From 2b81464a43485fcc8ce079fafdee7b7a171835f4 Mon Sep 17 00:00:00 2001 From: Bertrand Marc Date: Wed, 2 May 2012 21:43:37 +0200 Subject: Imported Upstream version 0.9.2 --- ABOUT-NLS | 1101 + AUTHORS | 100 + COPYING | 674 + ChangeLog | 1655 + INSTALL | 365 + Makefile.am | 29 + Makefile.in | 920 + NEWS | 1 + README | 253 + acinclude.m4 | 65 + aclocal.m4 | 1256 + compile | 143 + config.guess | 1501 + config.rpath | 614 + config.sub | 1705 ++ configure | 29880 +++++++++++++++++++ configure.ac | 971 + contrib/Makefile.am | 47 + contrib/Makefile.in | 687 + contrib/coverage.sh | 14 + contrib/gnunet-logo-color.png | Bin 0 -> 6851 bytes contrib/gnunet_janitor.py.in | 74 + contrib/gnunet_pyexpect.py.in | 83 + contrib/hostlist.cgi | 5 + contrib/hostlist.php | 35 + contrib/report.sh | 200 + contrib/test_gnunet_prefix.c | 65 + contrib/testing_hostkeys.dat | Bin 0 -> 3481426 bytes contrib/timeout_watchdog.c | 113 + depcomp | 630 + doc/Makefile.am | 3 + doc/Makefile.in | 662 + doc/README.mysql | 95 + doc/README.postgres | 49 + doc/man/Makefile.am | 17 + doc/man/Makefile.in | 557 + doc/man/gnunet-arm.1 | 45 + doc/man/gnunet-directory.1 | 35 + doc/man/gnunet-download-manager.1 | 24 + doc/man/gnunet-download.1 | 81 + doc/man/gnunet-fs.1 | 38 + doc/man/gnunet-nat-server.1 | 35 + doc/man/gnunet-peerinfo.1 | 43 + doc/man/gnunet-pseudonym.1 | 77 + doc/man/gnunet-publish.1 | 174 + doc/man/gnunet-search.1 | 93 + doc/man/gnunet-statistics.1 | 44 + doc/man/gnunet-transport.1 | 53 + doc/man/gnunet-unindex.1 | 37 + doc/man/gnunet-vpn.1 | 65 + gnunet_config.h | 802 + gnunet_config.h.in | 801 + install-sh | 520 + ltmain.sh | 8413 ++++++ m4/ChangeLog | 66 + m4/Makefile.am | 39 + m4/Makefile.in | 498 + m4/absolute-header.m4 | 77 + m4/align.m4 | 32 + m4/argz.m4 | 79 + m4/codeset.m4 | 21 + m4/freetype2.m4 | 178 + m4/gettext.m4 | 419 + m4/glib-2.0.m4 | 212 + m4/glib-gettext.m4 | 380 + m4/glibc2.m4 | 30 + m4/glibc21.m4 | 30 + m4/gnulib-cache.m4 | 35 + m4/gtk-2.0.m4 | 196 + m4/iconv.m4 | 101 + m4/intdiv0.m4 | 70 + m4/intl.m4 | 259 + m4/intldir.m4 | 19 + m4/intmax.m4 | 33 + m4/inttypes-pri.m4 | 36 + m4/inttypes.m4 | 27 + m4/inttypes_h.m4 | 26 + m4/isc-posix.m4 | 26 + m4/lcmessage.m4 | 30 + m4/lib-ld.m4 | 110 + m4/lib-link.m4 | 644 + m4/lib-prefix.m4 | 185 + m4/libcurl.m4 | 250 + m4/libgcrypt.m4 | 108 + m4/libtool.m4 | 7377 +++++ m4/libunistring.m4 | 150 + m4/libxml2.m4 | 188 + m4/lock.m4 | 311 + m4/longdouble.m4 | 31 + m4/longlong.m4 | 48 + m4/ltdl.m4 | 804 + m4/ltoptions.m4 | 368 + m4/ltsugar.m4 | 123 + m4/ltversion.m4 | 23 + m4/lt~obsolete.m4 | 92 + m4/nls.m4 | 31 + m4/pkg.m4 | 57 + m4/po.m4 | 428 + m4/printf-posix.m4 | 44 + m4/progtest.m4 | 92 + m4/signed.m4 | 19 + m4/size_max.m4 | 62 + m4/stdint_h.m4 | 26 + m4/uintmax_t.m4 | 30 + m4/ulonglong.m4 | 48 + m4/visibility.m4 | 52 + m4/wchar_t.m4 | 20 + m4/wint_t.m4 | 20 + m4/xsize.m4 | 13 + missing | 376 + pkgconfig/Makefile.am | 56 + pkgconfig/Makefile.in | 609 + pkgconfig/gnunetarm.pc.in | 12 + pkgconfig/gnunetblock.pc.in | 12 + pkgconfig/gnunetcore.pc.in | 12 + pkgconfig/gnunetdatacache.pc.in | 12 + pkgconfig/gnunetdatastore.pc.in | 12 + pkgconfig/gnunetdht.pc.in | 12 + pkgconfig/gnunetdhtlog.pc.in | 12 + pkgconfig/gnunetdv.pc.in | 12 + pkgconfig/gnunetfragmentation.pc.in | 12 + pkgconfig/gnunetfs.pc.in | 12 + pkgconfig/gnunethello.pc.in | 12 + pkgconfig/gnunetnat.pc.in | 12 + pkgconfig/gnunetnse.pc.in | 12 + pkgconfig/gnunetpeerinfo.pc.in | 12 + pkgconfig/gnunetstatistics.pc.in | 12 + pkgconfig/gnunettesting.pc.in | 12 + pkgconfig/gnunettransport.pc.in | 12 + pkgconfig/gnunetutil.pc.in | 12 + po/ChangeLog | 16 + po/LINGUAS | 2 + po/Makefile.in.in | 403 + po/Makevars | 41 + po/POTFILES.in | 226 + po/Rules-quot | 47 + po/boldquot.sed | 10 + po/de.gmo | Bin 0 -> 6870 bytes po/de.po | 9381 ++++++ po/en@boldquot.header | 25 + po/en@quot.header | 22 + po/es.gmo | Bin 0 -> 6270 bytes po/es.po | 8787 ++++++ po/gnunet.pot | 5480 ++++ po/insert-header.sin | 23 + po/quot.sed | 6 + po/remove-potcdate.sin | 19 + po/stamp-po | 1 + po/sv.gmo | Bin 0 -> 4058 bytes po/sv.po | 7275 +++++ po/vi.gmo | Bin 0 -> 14375 bytes po/vi.po | 9287 ++++++ po/zh_CN.gmo | Bin 0 -> 4364 bytes po/zh_CN.po | 6312 ++++ src/Makefile.am | 43 + src/Makefile.in | 701 + src/arm/Makefile.am | 91 + src/arm/Makefile.in | 960 + src/arm/arm.conf.in | 23 + src/arm/arm.h | 56 + src/arm/arm_api.c | 681 + src/arm/do_start_process.c | 104 + src/arm/gnunet-arm.c | 392 + src/arm/gnunet-service-arm.c | 1228 + src/arm/mockup-service.c | 105 + src/arm/test_arm_api.c | 173 + src/arm/test_arm_api_data.conf | 58 + src/arm/test_exponential_backoff.c | 459 + src/arm/test_gnunet_arm.sh | 65 + src/arm/test_gnunet_service_manager.c | 185 + src/ats/Makefile.am | 121 + src/ats/Makefile.in | 1015 + src/ats/ats.conf.in | 24 + src/ats/ats.h | 243 + src/ats/ats_api_performance.c | 645 + src/ats/ats_api_scheduling.c | 1177 + src/ats/gnunet-service-ats.c | 182 + src/ats/gnunet-service-ats.h | 38 + src/ats/gnunet-service-ats_addresses.c | 805 + src/ats/gnunet-service-ats_addresses.h | 151 + src/ats/gnunet-service-ats_addresses_mlp.c | 1736 ++ src/ats/gnunet-service-ats_addresses_mlp.h | 394 + src/ats/gnunet-service-ats_performance.c | 316 + src/ats/gnunet-service-ats_performance.h | 123 + src/ats/gnunet-service-ats_reservations.c | 157 + src/ats/gnunet-service-ats_reservations.h | 75 + src/ats/gnunet-service-ats_scheduling.c | 409 + src/ats/gnunet-service-ats_scheduling.h | 158 + src/ats/perf_ats_mlp.c | 138 + src/ats/test_ats_api.conf | 24 + src/ats/test_ats_api_scheduling.c | 264 + src/ats/test_ats_mlp.c | 199 + src/ats/test_ats_mlp_averaging.c | 182 + src/block/Makefile.am | 58 + src/block/Makefile.in | 768 + src/block/block.c | 308 + src/block/plugin_block_template.c | 113 + src/block/plugin_block_test.c | 147 + src/block/test_block.c | 77 + src/chat/Makefile.am | 128 + src/chat/Makefile.in | 1062 + src/chat/chat.c | 822 + src/chat/chat.conf.in | 22 + src/chat/chat.h | 485 + src/chat/gnunet-chat.c | 674 + src/chat/gnunet-service-chat.c | 1737 ++ src/chat/test_chat.c | 586 + src/chat/test_chat_data.conf | 56 + src/chat/test_chat_peer1.conf | 95 + src/chat/test_chat_peer2.conf | 97 + src/chat/test_chat_peer3.conf | 96 + src/chat/test_chat_private.c | 654 + src/core/Makefile.am | 137 + src/core/Makefile.in | 1081 + src/core/core.conf.in | 22 + src/core/core.h | 380 + src/core/core_api.c | 1493 + src/core/core_api_iterate_peers.c | 247 + src/core/gnunet-core-list-connections.c | 207 + src/core/gnunet-service-core.c | 120 + src/core/gnunet-service-core.h | 112 + src/core/gnunet-service-core_clients.c | 887 + src/core/gnunet-service-core_clients.h | 150 + src/core/gnunet-service-core_kx.c | 1579 + src/core/gnunet-service-core_kx.h | 137 + src/core/gnunet-service-core_neighbours.c | 528 + src/core/gnunet-service-core_neighbours.h | 63 + src/core/gnunet-service-core_sessions.c | 826 + src/core/gnunet-service-core_sessions.h | 192 + src/core/gnunet-service-core_typemap.c | 297 + src/core/gnunet-service-core_typemap.h | 129 + src/core/test_core_api.c | 412 + src/core/test_core_api_data.conf | 15 + src/core/test_core_api_peer1.conf | 30 + src/core/test_core_api_peer2.conf | 35 + src/core/test_core_api_reliability.c | 533 + src/core/test_core_api_send_to_self.c | 242 + src/core/test_core_api_send_to_self.conf | 32 + src/core/test_core_api_start_only.c | 262 + src/core/test_core_defaults.conf | 59 + ...t_core_quota_asymmetric_recv_limited_peer1.conf | 39 + ...t_core_quota_asymmetric_recv_limited_peer2.conf | 39 + ...est_core_quota_asymmetric_send_limit_peer1.conf | 38 + ...est_core_quota_asymmetric_send_limit_peer2.conf | 38 + src/core/test_core_quota_compliance.c | 750 + src/core/test_core_quota_peer1.conf | 40 + src/core/test_core_quota_peer2.conf | 38 + src/datacache/Makefile.am | 190 + src/datacache/Makefile.in | 1188 + src/datacache/datacache.c | 304 + src/datacache/datacache.conf | 10 + src/datacache/perf_datacache.c | 175 + src/datacache/perf_datacache_data_mysql.conf | 13 + src/datacache/perf_datacache_data_postgres.conf | 8 + src/datacache/perf_datacache_data_sqlite.conf | 4 + src/datacache/plugin_datacache_mysql.c | 1005 + src/datacache/plugin_datacache_postgres.c | 524 + src/datacache/plugin_datacache_sqlite.c | 490 + src/datacache/plugin_datacache_template.c | 145 + src/datacache/test_datacache.c | 162 + src/datacache/test_datacache_data_mysql.conf | 13 + src/datacache/test_datacache_data_postgres.conf | 8 + src/datacache/test_datacache_data_sqlite.conf | 5 + src/datacache/test_datacache_quota.c | 151 + src/datastore/Makefile.am | 234 + src/datastore/Makefile.in | 1384 + src/datastore/datastore.conf.in | 33 + src/datastore/datastore.h | 263 + src/datastore/datastore_api.c | 1505 + src/datastore/gnunet-service-datastore.c | 1693 ++ src/datastore/perf_datastore_api.c | 405 + src/datastore/perf_plugin_datastore.c | 521 + .../perf_plugin_datastore_data_mysql.conf | 11 + .../perf_plugin_datastore_data_postgres.conf | 11 + .../perf_plugin_datastore_data_sqlite.conf | 5 + src/datastore/plugin_datastore_mysql.c | 1612 + src/datastore/plugin_datastore_postgres.c | 1039 + src/datastore/plugin_datastore_sqlite.c | 1264 + src/datastore/plugin_datastore_template.c | 262 + src/datastore/test_datastore_api.c | 589 + src/datastore/test_datastore_api_data_mysql.conf | 28 + .../test_datastore_api_data_postgres.conf | 28 + src/datastore/test_datastore_api_data_sqlite.conf | 24 + src/datastore/test_datastore_api_management.c | 373 + src/datastore/test_defaults.conf | 30 + src/datastore/test_plugin_datastore.c | 421 + .../test_plugin_datastore_data_mysql.conf | 11 + .../test_plugin_datastore_data_postgres.conf | 11 + .../test_plugin_datastore_data_sqlite.conf | 5 + src/dht/Makefile.am | 204 + src/dht/Makefile.in | 1197 + src/dht/dht.conf.in | 39 + src/dht/dht.h | 261 + src/dht/dht_api.c | 997 + src/dht/gnunet-dht-get.c | 236 + src/dht/gnunet-dht-put.c | 207 + src/dht/gnunet-service-dht.c | 190 + src/dht/gnunet-service-dht.h | 60 + src/dht/gnunet-service-dht_clients.c | 1164 + src/dht/gnunet-service-dht_clients.h | 103 + src/dht/gnunet-service-dht_datacache.c | 309 + src/dht/gnunet-service-dht_datacache.h | 86 + src/dht/gnunet-service-dht_hello.c | 135 + src/dht/gnunet-service-dht_hello.h | 55 + src/dht/gnunet-service-dht_neighbours.c | 2029 ++ src/dht/gnunet-service-dht_neighbours.h | 138 + src/dht/gnunet-service-dht_nse.c | 101 + src/dht/gnunet-service-dht_nse.h | 52 + src/dht/gnunet-service-dht_routing.c | 383 + src/dht/gnunet-service-dht_routing.h | 96 + src/dht/multipeer_topo.dat | 31 + src/dht/plugin_block_dht.c | 181 + src/dht/test_dht_2dtorus.conf | 87 + src/dht/test_dht_api.c | 339 + src/dht/test_dht_api_data.conf | 85 + src/dht/test_dht_api_peer1.conf | 76 + src/dht/test_dht_line.conf | 87 + src/dht/test_dht_monitor.c | 624 + src/dht/test_dht_multipeer.c | 872 + src/dht/test_dht_multipeer_data.conf | 128 + src/dht/test_dht_tools.sh | 73 + src/dht/test_dht_topo.c | 662 + src/dht/test_dht_twopeer.c | 513 + src/dht/test_dht_twopeer_data.conf | 74 + src/dht/test_dht_twopeer_get_put.c | 605 + src/dht/test_dht_twopeer_path_tracking.c | 522 + src/dht/test_dht_twopeer_put_get.c | 512 + src/dns/Makefile.am | 111 + src/dns/Makefile.in | 1017 + src/dns/dns.conf.in | 44 + src/dns/dns.h | 101 + src/dns/dns_api.c | 522 + src/dns/dnsparser.c | 796 + src/dns/gnunet-dns-monitor.c | 353 + src/dns/gnunet-dns-redirector.c | 252 + src/dns/gnunet-helper-dns.c | 961 + src/dns/gnunet-service-dns.c | 1667 ++ src/dns/plugin_block_dns.c | 170 + src/dns/test_gnunet_dns.sh | 18 + src/dv/Makefile.am | 79 + src/dv/Makefile.in | 955 + src/dv/dv.conf.in | 18 + src/dv/dv.h | 275 + src/dv/dv_api.c | 628 + src/dv/gnunet-service-dv.c | 3335 +++ src/dv/plugin_transport_dv.c | 452 + src/dv/test_transport_api_dv.c | 1247 + src/dv/test_transport_dv_data.conf | 79 + src/exit/Makefile.am | 43 + src/exit/Makefile.in | 714 + src/exit/exit.conf | 47 + src/exit/exit.h | 313 + src/exit/gnunet-daemon-exit.c | 3240 ++ src/exit/gnunet-helper-exit.c | 767 + src/fragmentation/Makefile.am | 36 + src/fragmentation/Makefile.in | 785 + src/fragmentation/defragmentation.c | 547 + src/fragmentation/fragmentation.c | 405 + src/fragmentation/fragmentation.h | 89 + src/fragmentation/test_fragmentation.c | 261 + src/fragmentation/test_fragmentation_data.conf | 5 + src/fs/Makefile.am | 466 + src/fs/Makefile.in | 1788 ++ src/fs/fs.conf.in | 32 + src/fs/fs.h | 332 + src/fs/fs_api.c | 2824 ++ src/fs/fs_api.h | 1919 ++ src/fs/fs_directory.c | 644 + src/fs/fs_dirmetascan.c | 465 + src/fs/fs_download.c | 2260 ++ src/fs/fs_file_information.c | 453 + src/fs/fs_getopt.c | 197 + src/fs/fs_list_indexed.c | 184 + src/fs/fs_misc.c | 231 + src/fs/fs_namespace.c | 954 + src/fs/fs_namespace_advertise.c | 323 + src/fs/fs_publish.c | 1270 + src/fs/fs_publish_ksk.c | 342 + src/fs/fs_search.c | 1548 + src/fs/fs_sharetree.c | 452 + src/fs/fs_test_lib.c | 731 + src/fs/fs_test_lib.h | 183 + src/fs/fs_test_lib_data.conf | 11 + src/fs/fs_tree.c | 441 + src/fs/fs_tree.h | 207 + src/fs/fs_unindex.c | 524 + src/fs/fs_uri.c | 2084 ++ src/fs/gnunet-directory.c | 183 + src/fs/gnunet-download-manager.scm | 407 + src/fs/gnunet-download.c | 281 + src/fs/gnunet-fs.c | 128 + src/fs/gnunet-helper-fs-publish.c | 457 + src/fs/gnunet-pseudonym.c | 312 + src/fs/gnunet-publish.c | 740 + src/fs/gnunet-search.c | 312 + src/fs/gnunet-service-fs.c | 654 + src/fs/gnunet-service-fs.h | 286 + src/fs/gnunet-service-fs_cp.c | 1898 ++ src/fs/gnunet-service-fs_cp.h | 420 + src/fs/gnunet-service-fs_indexing.c | 623 + src/fs/gnunet-service-fs_indexing.h | 121 + src/fs/gnunet-service-fs_lc.c | 510 + src/fs/gnunet-service-fs_lc.h | 87 + src/fs/gnunet-service-fs_pe.c | 775 + src/fs/gnunet-service-fs_pe.h | 90 + src/fs/gnunet-service-fs_pr.c | 1644 + src/fs/gnunet-service-fs_pr.h | 403 + src/fs/gnunet-service-fs_push.c | 658 + src/fs/gnunet-service-fs_push.h | 66 + src/fs/gnunet-service-fs_put.c | 238 + src/fs/gnunet-service-fs_put.h | 46 + src/fs/gnunet-unindex.c | 180 + src/fs/perf_gnunet_service_fs_p2p.c | 337 + src/fs/perf_gnunet_service_fs_p2p_trust.c | 418 + src/fs/plugin_block_fs.c | 322 + src/fs/test_fs_data.conf | 8 + src/fs/test_fs_defaults.conf | 87 + src/fs/test_fs_directory.c | 179 + src/fs/test_fs_download.c | 353 + src/fs/test_fs_download_data.conf | 5 + src/fs/test_fs_download_indexed.c | 372 + src/fs/test_fs_download_persistence.c | 405 + src/fs/test_fs_file_information.c | 172 + src/fs/test_fs_file_information_data.conf | 8 + src/fs/test_fs_getopt.c | 40 + src/fs/test_fs_list_indexed.c | 338 + src/fs/test_fs_list_indexed_data.conf | 11 + src/fs/test_fs_namespace.c | 410 + src/fs/test_fs_namespace_data.conf | 8 + src/fs/test_fs_namespace_list_updateable.c | 244 + src/fs/test_fs_publish.c | 323 + src/fs/test_fs_publish_data.conf | 11 + src/fs/test_fs_publish_persistence.c | 384 + src/fs/test_fs_search.c | 280 + src/fs/test_fs_search_data.conf | 8 + src/fs/test_fs_search_persistence.c | 345 + src/fs/test_fs_start_stop.c | 135 + src/fs/test_fs_test_lib.c | 164 + src/fs/test_fs_unindex.c | 304 + src/fs/test_fs_unindex_data.conf | 8 + src/fs/test_fs_unindex_persistence.c | 367 + src/fs/test_fs_uri.c | 330 + src/fs/test_fs_uri_data.conf | 7 + src/fs/test_gnunet_fs_idx.py.in | 73 + src/fs/test_gnunet_fs_idx_data.conf | 8 + src/fs/test_gnunet_fs_ns.py.in | 80 + src/fs/test_gnunet_fs_ns_data.conf | 8 + src/fs/test_gnunet_fs_psd.py.in | 79 + src/fs/test_gnunet_fs_psd_data.conf | 8 + src/fs/test_gnunet_fs_rec.py.in | 109 + src/fs/test_gnunet_fs_rec_data.conf | 8 + src/fs/test_gnunet_fs_rec_data.tgz | Bin 0 -> 17822 bytes src/fs/test_gnunet_service_fs_migration.c | 221 + src/fs/test_gnunet_service_fs_migration_data.conf | 9 + src/fs/test_gnunet_service_fs_p2p.c | 176 + src/gns/Makefile.am | 113 + src/gns/Makefile.in | 998 + src/gns/gns.conf.in | 17 + src/gns/gns.h | 97 + src/gns/gns_api.c | 635 + src/gns/gnunet-service-gns.c | 1399 + src/gns/namestore_stub_api.c | 438 + src/gns/plugin_block_gns.c | 226 + src/gns/test_gns_twopeer.c | 463 + src/gns/test_gns_twopeer.conf | 80 + src/gns/test_gnunet_gns.sh | 22 + src/hello/Makefile.am | 34 + src/hello/Makefile.in | 779 + src/hello/address.c | 120 + src/hello/hello.c | 645 + src/hello/test_hello.c | 205 + src/hostlist/Makefile.am | 81 + src/hostlist/Makefile.in | 949 + src/hostlist/gnunet-daemon-hostlist.c | 347 + src/hostlist/gnunet-daemon-hostlist.h | 47 + src/hostlist/hostlist-client.c | 1568 + src/hostlist/hostlist-client.h | 108 + src/hostlist/hostlist-server.c | 700 + src/hostlist/hostlist-server.h | 58 + src/hostlist/hostlist.conf | 14 + src/hostlist/learning_data.conf | 14 + src/hostlist/test_gnunet_daemon_hostlist.c | 255 + src/hostlist/test_gnunet_daemon_hostlist_data.conf | 29 + .../test_gnunet_daemon_hostlist_learning.c | 533 + .../test_gnunet_daemon_hostlist_peer1.conf | 43 + .../test_gnunet_daemon_hostlist_peer2.conf | 43 + .../test_gnunet_daemon_hostlist_reconnect.c | 266 + src/hostlist/test_hostlist_defaults.conf | 62 + src/hostlist/test_learning_adv_peer.conf | 47 + src/hostlist/test_learning_learn_peer.conf | 46 + src/hostlist/test_learning_learn_peer2.conf | 39 + src/include/Makefile.am | 82 + src/include/Makefile.in | 840 + src/include/block_dns.h | 87 + src/include/block_fs.h | 167 + src/include/block_gns.h | 93 + src/include/gauger.h | 89 + src/include/gettext.h | 71 + src/include/gnunet_applications.h | 74 + src/include/gnunet_arm_service.h | 194 + src/include/gnunet_ats_service.h | 767 + src/include/gnunet_bandwidth_lib.h | 227 + src/include/gnunet_bio_lib.h | 303 + src/include/gnunet_block_lib.h | 260 + src/include/gnunet_block_plugin.h | 128 + src/include/gnunet_chat_service.h | 253 + src/include/gnunet_client_lib.h | 222 + src/include/gnunet_common.h | 840 + src/include/gnunet_configuration_lib.h | 442 + src/include/gnunet_connection_lib.h | 373 + src/include/gnunet_constants.h | 161 + src/include/gnunet_container_lib.h | 1240 + src/include/gnunet_core_service.h | 328 + src/include/gnunet_crypto_lib.h | 882 + src/include/gnunet_datacache_lib.h | 134 + src/include/gnunet_datacache_plugin.h | 154 + src/include/gnunet_datastore_plugin.h | 333 + src/include/gnunet_datastore_service.h | 393 + src/include/gnunet_dht_service.h | 290 + src/include/gnunet_directories.h.in | 33 + src/include/gnunet_disk_lib.h | 768 + src/include/gnunet_dns_service.h | 186 + src/include/gnunet_dnsparser_lib.h | 397 + src/include/gnunet_dv_service.h | 88 + src/include/gnunet_fragmentation_lib.h | 203 + src/include/gnunet_fs_service.h | 2843 ++ src/include/gnunet_getopt_lib.h | 349 + src/include/gnunet_gns_service.h | 163 + src/include/gnunet_hello_lib.h | 336 + src/include/gnunet_helper_lib.h | 96 + src/include/gnunet_load_lib.h | 119 + src/include/gnunet_mesh_service.h | 358 + src/include/gnunet_namestore_plugin.h | 152 + src/include/gnunet_namestore_service.h | 368 + src/include/gnunet_nat_lib.h | 256 + src/include/gnunet_network_lib.h | 464 + src/include/gnunet_nse_service.h | 109 + src/include/gnunet_os_lib.h | 434 + src/include/gnunet_peer_lib.h | 103 + src/include/gnunet_peerinfo_service.h | 190 + src/include/gnunet_plugin_lib.h | 137 + src/include/gnunet_program_lib.h | 86 + src/include/gnunet_protocols.h | 1289 + src/include/gnunet_pseudonym_lib.h | 140 + src/include/gnunet_resolver_service.h | 169 + src/include/gnunet_scheduler_lib.h | 555 + src/include/gnunet_server_lib.h | 715 + src/include/gnunet_service_lib.h | 164 + src/include/gnunet_signal_lib.h | 84 + src/include/gnunet_signatures.h | 127 + src/include/gnunet_statistics_service.h | 205 + src/include/gnunet_stream_lib.h | 297 + src/include/gnunet_strings_lib.h | 226 + src/include/gnunet_testing_lib.h | 1231 + src/include/gnunet_time_lib.h | 429 + src/include/gnunet_transport_plugin.h | 487 + src/include/gnunet_transport_service.h | 413 + src/include/gnunet_tun_lib.h | 420 + src/include/gnunet_util_lib.h | 71 + src/include/gnunet_vpn_service.h | 162 + src/include/platform.h | 258 + src/include/plibc.h | 864 + src/include/winproc.h | 234 + src/integration-tests/Makefile.am | 113 + src/integration-tests/Makefile.in | 715 + .../confs/c_bootstrap_server.conf | 355 + src/integration-tests/confs/c_nat_client.conf | 354 + src/integration-tests/confs/c_no_nat_client.conf | 356 + src/integration-tests/confs/c_no_nat_client_2.conf | 344 + src/integration-tests/gnunet_pyexpect.py.in | 83 + src/integration-tests/gnunet_testing.py.in | 232 + src/integration-tests/hostkeys/0000-hostkey | Bin 0 -> 914 bytes src/integration-tests/hostkeys/0001-hostkey | Bin 0 -> 914 bytes src/integration-tests/hostkeys/0002-hostkey | Bin 0 -> 914 bytes src/integration-tests/hostkeys/0003-hostkey | Bin 0 -> 914 bytes src/integration-tests/hostkeys/0004-hostkey | Bin 0 -> 914 bytes src/integration-tests/hostkeys/0005-hostkey | Bin 0 -> 914 bytes src/integration-tests/hostkeys/0006-hostkey | Bin 0 -> 914 bytes src/integration-tests/hostkeys/0007-hostkey | Bin 0 -> 914 bytes src/integration-tests/hostkeys/0008-hostkey | Bin 0 -> 914 bytes src/integration-tests/hostkeys/0009-hostkey | Bin 0 -> 914 bytes .../test_integration_bootstrap_and_connect.py.in | 135 + ...tion_bootstrap_and_connect_and_disconnect.py.in | 147 + ..._bootstrap_and_connect_and_disconnect_nat.py.in | 147 + .../test_integration_clique.py.in | 197 + .../test_integration_clique_nat.py.in | 197 + .../test_integration_disconnect.py.in | 156 + .../test_integration_restart.py.in | 171 + src/mesh/Makefile.am | 142 + src/mesh/Makefile.in | 1052 + src/mesh/gnunet-service-mesh.c | 4877 +++ src/mesh/mesh.conf.in | 13 + src/mesh/mesh.h | 263 + src/mesh/mesh_api.c | 1713 ++ src/mesh/mesh_protocol.h | 292 + src/mesh/mesh_tunnel_tree.c | 1075 + src/mesh/mesh_tunnel_tree.h | 345 + src/mesh/test_mesh.conf | 69 + src/mesh/test_mesh_2dtorus.c | 370 + src/mesh/test_mesh_2dtorus.conf | 87 + src/mesh/test_mesh_api.c | 192 + src/mesh/test_mesh_local_1.c | 357 + src/mesh/test_mesh_local_2.c | 349 + src/mesh/test_mesh_path.conf | 69 + src/mesh/test_mesh_small.c | 1020 + src/mesh/test_mesh_small.conf | 95 + src/mesh/test_mesh_tree_api.c | 378 + src/namestore/Makefile.am | 105 + src/namestore/Makefile.in | 918 + src/namestore/gnunet-service-namestore.c | 845 + src/namestore/hostkey | Bin 0 -> 913 bytes src/namestore/namestore.conf.in | 30 + src/namestore/namestore.h | 424 + src/namestore/namestore_api.c | 1194 + src/namestore/namestore_common.c | 159 + src/namestore/plugin_namestore_sqlite.c | 806 + src/namestore/test_namestore_api.c | 213 + src/namestore/test_namestore_api.conf | 34 + src/namestore/test_namestore_api_zone_iteration.c | 219 + .../test_namestore_record_serialization.c | 157 + src/namestore/test_plugin_namestore.c | 248 + src/namestore/test_plugin_namestore_sqlite.conf | 2 + src/nat/Makefile.am | 102 + src/nat/Makefile.in | 969 + src/nat/gnunet-helper-nat-client-windows.c | 507 + src/nat/gnunet-helper-nat-client.c | 498 + src/nat/gnunet-helper-nat-server-windows.c | 598 + src/nat/gnunet-helper-nat-server.c | 617 + src/nat/gnunet-nat-server.c | 335 + src/nat/nat.c | 1411 + src/nat/nat.conf | 54 + src/nat/nat.h | 68 + src/nat/nat_mini.c | 591 + src/nat/nat_test.c | 479 + src/nat/test_nat.c | 192 + src/nat/test_nat_data.conf | 141 + src/nat/test_nat_mini.c | 131 + src/nat/test_nat_test.c | 136 + src/nat/test_nat_test_data.conf | 48 + src/nse/Makefile.am | 90 + src/nse/Makefile.in | 939 + src/nse/gnunet-nse-profiler.c | 934 + src/nse/gnunet-service-nse.c | 1497 + src/nse/nse.conf.in | 25 + src/nse/nse.h | 78 + src/nse/nse_api.c | 298 + src/nse/nse_profiler_test.conf | 170 + src/nse/test_nse.conf | 77 + src/nse/test_nse_api.c | 187 + src/nse/test_nse_multipeer.c | 275 + src/peerinfo-tool/Makefile.am | 42 + src/peerinfo-tool/Makefile.in | 753 + src/peerinfo-tool/gnunet-peerinfo.c | 268 + src/peerinfo-tool/test_gnunet_peerinfo.py.in | 93 + src/peerinfo-tool/test_gnunet_peerinfo_data.conf | 32 + src/peerinfo/Makefile.am | 69 + src/peerinfo/Makefile.in | 917 + src/peerinfo/gnunet-service-peerinfo.c | 671 + src/peerinfo/peerinfo.conf.in | 24 + src/peerinfo/peerinfo.h | 88 + src/peerinfo/peerinfo_api.c | 661 + src/peerinfo/peerinfo_api_notify.c | 292 + src/peerinfo/perf_peerinfo_api.c | 217 + src/peerinfo/test_peerinfo_api.c | 220 + src/peerinfo/test_peerinfo_api_data.conf | 16 + src/pt/Makefile.am | 31 + src/pt/Makefile.in | 700 + src/pt/gnunet-daemon-pt.c | 978 + src/pt/pt.conf | 13 + src/statistics/Makefile.am | 85 + src/statistics/Makefile.in | 951 + src/statistics/gnunet-service-statistics.c | 737 + src/statistics/gnunet-statistics.c | 184 + src/statistics/statistics.conf.in | 22 + src/statistics/statistics.h | 135 + src/statistics/statistics_api.c | 1277 + src/statistics/test_gnunet_statistics.sh | 199 + src/statistics/test_statistics_api.c | 212 + src/statistics/test_statistics_api_data.conf | 43 + src/statistics/test_statistics_api_loop.c | 133 + src/statistics/test_statistics_api_watch.c | 164 + src/stream/Makefile.am | 43 + src/stream/Makefile.in | 789 + src/stream/README | 11 + src/stream/stream_api.c | 2180 ++ src/stream/stream_protocol.h | 197 + src/stream/test_stream_local.c | 386 + src/stream/test_stream_local.conf | 69 + src/template/Makefile.am | 44 + src/template/Makefile.in | 831 + src/template/gnunet-service-template.c | 81 + src/template/gnunet-template.c | 72 + src/template/template.conf | 21 + src/template/test_template_api.c | 45 + src/testing/Makefile.am | 279 + src/testing/Makefile.in | 1401 + src/testing/gnunet-testing.c | 291 + src/testing/helper.c | 75 + src/testing/test_testing.c | 126 + src/testing/test_testing_2dtorus.c | 372 + src/testing/test_testing_2dtorus.conf | 79 + src/testing/test_testing_connect.c | 197 + src/testing/test_testing_connect_peer1.conf | 37 + src/testing/test_testing_connect_peer2.conf | 37 + src/testing/test_testing_data.conf | 7 + src/testing/test_testing_data_remote.conf | 12 + .../test_testing_data_topology_2d_torus.conf | 8 + .../test_testing_data_topology_blacklist.conf | 13 + src/testing/test_testing_data_topology_churn.conf | 10 + src/testing/test_testing_data_topology_clique.conf | 10 + .../test_testing_data_topology_clique_dfs.conf | 13 + .../test_testing_data_topology_clique_minimum.conf | 10 + .../test_testing_data_topology_clique_random.conf | 16 + .../test_testing_data_topology_erdos_renyi.conf | 7 + .../test_testing_data_topology_internat.conf | 7 + src/testing/test_testing_data_topology_none.conf | 37 + src/testing/test_testing_data_topology_ring.conf | 7 + .../test_testing_data_topology_scale_free.conf | 11 + ...est_testing_data_topology_small_world_ring.conf | 8 + ...st_testing_data_topology_small_world_torus.conf | 7 + .../test_testing_data_topology_stability.conf | 9 + src/testing/test_testing_defaults.conf | 72 + src/testing/test_testing_group.c | 166 + src/testing/test_testing_group_remote.c | 263 + src/testing/test_testing_peergroup.c | 157 + src/testing/test_testing_peergroup_data.conf | 22 + src/testing/test_testing_reconnect.c | 249 + src/testing/test_testing_topology.c | 1263 + src/testing/test_testing_topology_blacklist.c | 595 + src/testing/test_testing_topology_churn.c | 350 + src/testing/testing.c | 2215 ++ src/testing/testing.conf | 11 + src/testing/testing_group.c | 7170 +++++ src/testing/testing_peergroup.c | 1007 + src/topology/Makefile.am | 43 + src/topology/Makefile.in | 828 + src/topology/gnunet-daemon-topology.c | 1328 + src/topology/test_gnunet_daemon_topology.c | 218 + src/topology/test_gnunet_daemon_topology_data.conf | 64 + src/topology/topology.conf | 10 + src/transport/Makefile.am | 811 + src/transport/Makefile.in | 2648 ++ src/transport/gnunet-helper-transport-wlan-dummy.c | 439 + src/transport/gnunet-helper-transport-wlan.c | 1758 ++ src/transport/gnunet-service-transport.c | 633 + src/transport/gnunet-service-transport.h | 72 + src/transport/gnunet-service-transport_blacklist.c | 822 + src/transport/gnunet-service-transport_blacklist.h | 127 + src/transport/gnunet-service-transport_clients.c | 1057 + src/transport/gnunet-service-transport_clients.h | 86 + src/transport/gnunet-service-transport_hello.c | 318 + src/transport/gnunet-service-transport_hello.h | 100 + .../gnunet-service-transport_neighbours.c | 2721 ++ .../gnunet-service-transport_neighbours.h | 314 + src/transport/gnunet-service-transport_plugins.c | 230 + src/transport/gnunet-service-transport_plugins.h | 82 + .../gnunet-service-transport_validation.c | 1276 + .../gnunet-service-transport_validation.h | 155 + .../gnunet-transport-certificate-creation | 148 + .../gnunet-transport-certificate-creation.c | 82 + src/transport/gnunet-transport-wlan-sender.c | 237 + src/transport/gnunet-transport.c | 619 + src/transport/plugin_transport_http.c | 1529 + src/transport/plugin_transport_http.h | 504 + src/transport/plugin_transport_http_client.c | 643 + src/transport/plugin_transport_http_server.c | 1223 + src/transport/plugin_transport_tcp.c | 2115 ++ src/transport/plugin_transport_template.c | 299 + src/transport/plugin_transport_udp.c | 2297 ++ src/transport/plugin_transport_udp.h | 291 + src/transport/plugin_transport_udp_broadcasting.c | 522 + src/transport/plugin_transport_unix.c | 1078 + src/transport/plugin_transport_wlan.c | 3201 ++ src/transport/plugin_transport_wlan.h | 152 + src/transport/template_cfg_peer1.conf | 50 + src/transport/template_cfg_peer2.conf | 50 + src/transport/test_plugin_transport_data.conf | 25 + src/transport/test_plugin_transport_data_udp.conf | 1 + src/transport/test_quota_compliance.c | 632 + src/transport/test_quota_compliance_data.conf | 25 + ...est_quota_compliance_http_asymmetric_peer1.conf | 30 + ...est_quota_compliance_http_asymmetric_peer2.conf | 30 + .../test_quota_compliance_http_peer1.conf | 30 + .../test_quota_compliance_http_peer2.conf | 30 + ...st_quota_compliance_https_asymmetric_peer1.conf | 32 + ...st_quota_compliance_https_asymmetric_peer2.conf | 32 + .../test_quota_compliance_https_peer1.conf | 32 + .../test_quota_compliance_https_peer2.conf | 32 + ...test_quota_compliance_tcp_asymmetric_peer1.conf | 32 + ...test_quota_compliance_tcp_asymmetric_peer2.conf | 30 + src/transport/test_quota_compliance_tcp_peer1.conf | 32 + src/transport/test_quota_compliance_tcp_peer2.conf | 30 + src/transport/test_quota_compliance_udp_peer1.conf | 30 + src/transport/test_quota_compliance_udp_peer2.conf | 31 + ...est_quota_compliance_unix_asymmetric_peer1.conf | 29 + ...est_quota_compliance_unix_asymmetric_peer2.conf | 29 + .../test_quota_compliance_unix_peer1.conf | 28 + .../test_quota_compliance_unix_peer2.conf | 32 + src/transport/test_transport_api.c | 442 + .../test_transport_api_bidirectional_connect.c | 415 + ..._transport_api_bidirectional_connect_peer1.conf | 31 + ..._transport_api_bidirectional_connect_peer2.conf | 30 + src/transport/test_transport_api_blacklisting.c | 480 + src/transport/test_transport_api_data.conf | 12 + src/transport/test_transport_api_disconnect.c | 436 + .../test_transport_api_disconnect_tcp_peer1.conf | 31 + .../test_transport_api_disconnect_tcp_peer2.conf | 30 + .../test_transport_api_http_nat_peer1.conf | 38 + .../test_transport_api_http_nat_peer2.conf | 31 + src/transport/test_transport_api_http_peer1.conf | 34 + src/transport/test_transport_api_http_peer2.conf | 31 + .../test_transport_api_https_nat_peer1.conf | 36 + .../test_transport_api_https_nat_peer2.conf | 33 + src/transport/test_transport_api_https_peer1.conf | 32 + src/transport/test_transport_api_https_peer2.conf | 33 + src/transport/test_transport_api_limited_sockets.c | 383 + ...st_transport_api_limited_sockets_tcp_peer1.conf | 31 + ...st_transport_api_limited_sockets_tcp_peer2.conf | 30 + src/transport/test_transport_api_multi_peer1.conf | 43 + src/transport/test_transport_api_multi_peer2.conf | 46 + src/transport/test_transport_api_reliability.c | 538 + ...t_transport_api_reliability_http_nat_peer1.conf | 38 + ...t_transport_api_reliability_http_nat_peer2.conf | 35 + .../test_transport_api_reliability_http_peer1.conf | 33 + .../test_transport_api_reliability_http_peer2.conf | 30 + ..._transport_api_reliability_https_nat_peer1.conf | 36 + ..._transport_api_reliability_https_nat_peer2.conf | 33 + ...test_transport_api_reliability_https_peer1.conf | 31 + ...test_transport_api_reliability_https_peer2.conf | 32 + ...st_transport_api_reliability_tcp_nat_peer1.conf | 36 + ...st_transport_api_reliability_tcp_nat_peer2.conf | 35 + .../test_transport_api_reliability_tcp_peer1.conf | 30 + .../test_transport_api_reliability_tcp_peer2.conf | 30 + .../test_transport_api_reliability_wlan_peer1.conf | 30 + .../test_transport_api_reliability_wlan_peer2.conf | 30 + src/transport/test_transport_api_restart_1peer.c | 491 + src/transport/test_transport_api_restart_2peers.c | 477 + .../test_transport_api_tcp_nat_peer1.conf | 36 + .../test_transport_api_tcp_nat_peer2.conf | 34 + src/transport/test_transport_api_tcp_peer1.conf | 31 + src/transport/test_transport_api_tcp_peer2.conf | 30 + src/transport/test_transport_api_timeout.c | 361 + .../test_transport_api_timeout_http_peer1.conf | 36 + .../test_transport_api_timeout_http_peer2.conf | 33 + .../test_transport_api_timeout_https_peer1.conf | 32 + .../test_transport_api_timeout_https_peer2.conf | 33 + .../test_transport_api_timeout_tcp_peer1.conf | 31 + .../test_transport_api_timeout_tcp_peer2.conf | 33 + .../test_transport_api_timeout_udp_peer1.conf | 34 + .../test_transport_api_timeout_udp_peer2.conf | 32 + .../test_transport_api_timeout_unix_peer1.conf | 29 + .../test_transport_api_timeout_unix_peer2.conf | 29 + .../test_transport_api_udp_nat_peer1.conf | 37 + .../test_transport_api_udp_nat_peer2.conf | 35 + src/transport/test_transport_api_udp_peer1.conf | 34 + src/transport/test_transport_api_udp_peer2.conf | 32 + src/transport/test_transport_api_unix_peer1.conf | 29 + src/transport/test_transport_api_unix_peer2.conf | 29 + src/transport/test_transport_api_unreliability.c | 585 + .../test_transport_api_unreliability_constant.c | 523 + ...sport_api_unreliability_constant_udp_peer1.conf | 31 + ...sport_api_unreliability_constant_udp_peer2.conf | 31 + ...test_transport_api_unreliability_udp_peer1.conf | 31 + ...test_transport_api_unreliability_udp_peer2.conf | 31 + ...est_transport_api_unreliability_unix_peer1.conf | 29 + ...est_transport_api_unreliability_unix_peer2.conf | 29 + ...est_transport_api_unreliability_wlan_peer1.conf | 30 + ...est_transport_api_unreliability_wlan_peer2.conf | 30 + src/transport/test_transport_api_wlan_peer1.conf | 38 + src/transport/test_transport_api_wlan_peer2.conf | 37 + src/transport/test_transport_defaults.conf | 54 + src/transport/test_transport_startonly.c | 189 + src/transport/test_transport_startonly.conf | 15 + src/transport/test_transport_testing.c | 227 + src/transport/transport-testing.c | 872 + src/transport/transport-testing.h | 275 + src/transport/transport.conf.in | 67 + src/transport/transport.h | 438 + src/transport/transport_api.c | 1337 + src/transport/transport_api_address_lookup.c | 369 + src/transport/transport_api_address_to_string.c | 192 + src/transport/transport_api_blacklist.c | 296 + src/tun/Makefile.am | 35 + src/tun/Makefile.in | 778 + src/tun/test_tun.c | 74 + src/tun/tun.c | 271 + src/util/Makefile.am | 440 + src/util/Makefile.in | 1945 ++ src/util/bandwidth.c | 328 + src/util/bio.c | 525 + src/util/client.c | 1216 + src/util/common_allocation.c | 359 + src/util/common_endian.c | 94 + src/util/common_logging.c | 1056 + src/util/configuration.c | 1287 + src/util/connection.c | 1626 + src/util/container_bloomfilter.c | 858 + src/util/container_heap.c | 550 + src/util/container_meta_data.c | 1180 + src/util/container_multihashmap.c | 493 + src/util/container_slist.c | 387 + src/util/crypto_aes.c | 185 + src/util/crypto_crc.c | 171 + src/util/crypto_hash.c | 647 + src/util/crypto_hkdf.c | 299 + src/util/crypto_kdf.c | 89 + src/util/crypto_ksk.c | 769 + src/util/crypto_random.c | 334 + src/util/crypto_rsa.c | 967 + src/util/disk.c | 2505 ++ src/util/disk.h | 44 + src/util/getopt.c | 1050 + src/util/getopt_helpers.c | 290 + src/util/gnunet-config-diff.c | 23 + src/util/gnunet-resolver.c | 158 + src/util/gnunet-service-resolver.c | 584 + src/util/helper.c | 506 + src/util/load.c | 260 + src/util/network.c | 1662 ++ src/util/os_installation.c | 538 + src/util/os_network.c | 270 + src/util/os_priority.c | 1826 ++ src/util/peer.c | 241 + src/util/perf_crypto_hash.c | 70 + src/util/plugin.c | 361 + src/util/program.c | 261 + src/util/pseudonym.c | 602 + src/util/resolver.conf.in | 22 + src/util/resolver.h | 69 + src/util/resolver_api.c | 972 + src/util/scheduler.c | 1696 ++ src/util/server.c | 1415 + src/util/server_mst.c | 321 + src/util/server_nc.c | 450 + src/util/server_tc.c | 247 + src/util/service.c | 1840 ++ src/util/signal.c | 98 + src/util/strings.c | 633 + src/util/test_bio.c | 417 + src/util/test_client.c | 210 + src/util/test_common_allocation.c | 112 + src/util/test_common_endian.c | 42 + src/util/test_common_logging.c | 99 + src/util/test_common_logging_dummy.c | 98 + src/util/test_common_logging_runtime_loglevels.c | 384 + src/util/test_configuration.c | 553 + src/util/test_configuration_data.conf | 30 + src/util/test_connection.c | 208 + src/util/test_connection_addressing.c | 208 + src/util/test_connection_receive_cancel.c | 158 + src/util/test_connection_timeout.c | 154 + src/util/test_connection_timeout_no_connect.c | 101 + src/util/test_connection_transmit_cancel.c | 101 + src/util/test_container_bloomfilter.c | 244 + src/util/test_container_heap.c | 290 + src/util/test_container_meta_data.c | 347 + src/util/test_container_multihashmap.c | 105 + src/util/test_container_slist.c | 160 + src/util/test_crypto_aes.c | 175 + src/util/test_crypto_aes_weak.c | 202 + src/util/test_crypto_crc.c | 221 + src/util/test_crypto_hash.c | 166 + src/util/test_crypto_hkdf.c | 351 + src/util/test_crypto_ksk.c | 260 + src/util/test_crypto_random.c | 71 + src/util/test_crypto_rsa.c | 334 + src/util/test_disk.c | 283 + src/util/test_getopt.c | 216 + src/util/test_os_network.c | 86 + src/util/test_os_priority.c | 69 + src/util/test_os_start_process.c | 194 + src/util/test_peer.c | 139 + src/util/test_plugin.c | 79 + src/util/test_plugin_plug.c | 42 + src/util/test_program.c | 121 + src/util/test_program_data.conf | 0 src/util/test_pseudonym.c | 191 + src/util/test_pseudonym_data.conf | 7 + src/util/test_resolver_api.c | 437 + src/util/test_resolver_api_data.conf | 8 + src/util/test_scheduler.c | 266 + src/util/test_scheduler_delay.c | 103 + src/util/test_server.c | 222 + src/util/test_server_disconnect.c | 180 + src/util/test_server_with_client.c | 224 + src/util/test_server_with_client_unix.c | 212 + src/util/test_service.c | 287 + src/util/test_service_data.conf | 29 + src/util/test_strings.c | 117 + src/util/test_time.c | 244 + src/util/time.c | 521 + src/util/util.conf | 16 + src/util/win.cc | 1266 + src/util/winproc.c | 338 + src/vpn/Makefile.am | 110 + src/vpn/Makefile.in | 1018 + src/vpn/gnunet-helper-vpn.c | 616 + src/vpn/gnunet-service-vpn.c | 3202 ++ src/vpn/gnunet-vpn.c | 334 + src/vpn/test_gnunet_vpn.c | 605 + src/vpn/test_gnunet_vpn.conf | 37 + src/vpn/vpn.conf.in | 21 + src/vpn/vpn.h | 159 + src/vpn/vpn_api.c | 605 + 1004 files changed, 442707 insertions(+) create mode 100644 ABOUT-NLS create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 NEWS create mode 100644 README create mode 100644 acinclude.m4 create mode 100644 aclocal.m4 create mode 100755 compile create mode 100755 config.guess create mode 100755 config.rpath create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.ac create mode 100644 contrib/Makefile.am create mode 100644 contrib/Makefile.in create mode 100755 contrib/coverage.sh create mode 100644 contrib/gnunet-logo-color.png create mode 100644 contrib/gnunet_janitor.py.in create mode 100644 contrib/gnunet_pyexpect.py.in create mode 100644 contrib/hostlist.cgi create mode 100644 contrib/hostlist.php create mode 100755 contrib/report.sh create mode 100644 contrib/test_gnunet_prefix.c create mode 100644 contrib/testing_hostkeys.dat create mode 100644 contrib/timeout_watchdog.c create mode 100755 depcomp create mode 100644 doc/Makefile.am create mode 100644 doc/Makefile.in create mode 100644 doc/README.mysql create mode 100644 doc/README.postgres create mode 100644 doc/man/Makefile.am create mode 100644 doc/man/Makefile.in create mode 100644 doc/man/gnunet-arm.1 create mode 100644 doc/man/gnunet-directory.1 create mode 100644 doc/man/gnunet-download-manager.1 create mode 100644 doc/man/gnunet-download.1 create mode 100644 doc/man/gnunet-fs.1 create mode 100644 doc/man/gnunet-nat-server.1 create mode 100644 doc/man/gnunet-peerinfo.1 create mode 100644 doc/man/gnunet-pseudonym.1 create mode 100644 doc/man/gnunet-publish.1 create mode 100644 doc/man/gnunet-search.1 create mode 100644 doc/man/gnunet-statistics.1 create mode 100644 doc/man/gnunet-transport.1 create mode 100644 doc/man/gnunet-unindex.1 create mode 100644 doc/man/gnunet-vpn.1 create mode 100644 gnunet_config.h create mode 100644 gnunet_config.h.in create mode 100755 install-sh create mode 100755 ltmain.sh create mode 100644 m4/ChangeLog create mode 100644 m4/Makefile.am create mode 100644 m4/Makefile.in create mode 100644 m4/absolute-header.m4 create mode 100644 m4/align.m4 create mode 100644 m4/argz.m4 create mode 100644 m4/codeset.m4 create mode 100644 m4/freetype2.m4 create mode 100644 m4/gettext.m4 create mode 100644 m4/glib-2.0.m4 create mode 100644 m4/glib-gettext.m4 create mode 100644 m4/glibc2.m4 create mode 100644 m4/glibc21.m4 create mode 100644 m4/gnulib-cache.m4 create mode 100644 m4/gtk-2.0.m4 create mode 100644 m4/iconv.m4 create mode 100644 m4/intdiv0.m4 create mode 100644 m4/intl.m4 create mode 100644 m4/intldir.m4 create mode 100644 m4/intmax.m4 create mode 100644 m4/inttypes-pri.m4 create mode 100644 m4/inttypes.m4 create mode 100644 m4/inttypes_h.m4 create mode 100644 m4/isc-posix.m4 create mode 100644 m4/lcmessage.m4 create mode 100644 m4/lib-ld.m4 create mode 100644 m4/lib-link.m4 create mode 100644 m4/lib-prefix.m4 create mode 100644 m4/libcurl.m4 create mode 100644 m4/libgcrypt.m4 create mode 100644 m4/libtool.m4 create mode 100644 m4/libunistring.m4 create mode 100644 m4/libxml2.m4 create mode 100644 m4/lock.m4 create mode 100644 m4/longdouble.m4 create mode 100644 m4/longlong.m4 create mode 100644 m4/ltdl.m4 create mode 100644 m4/ltoptions.m4 create mode 100644 m4/ltsugar.m4 create mode 100644 m4/ltversion.m4 create mode 100644 m4/lt~obsolete.m4 create mode 100644 m4/nls.m4 create mode 100644 m4/pkg.m4 create mode 100644 m4/po.m4 create mode 100644 m4/printf-posix.m4 create mode 100644 m4/progtest.m4 create mode 100644 m4/signed.m4 create mode 100644 m4/size_max.m4 create mode 100644 m4/stdint_h.m4 create mode 100644 m4/uintmax_t.m4 create mode 100644 m4/ulonglong.m4 create mode 100644 m4/visibility.m4 create mode 100644 m4/wchar_t.m4 create mode 100644 m4/wint_t.m4 create mode 100644 m4/xsize.m4 create mode 100755 missing create mode 100644 pkgconfig/Makefile.am create mode 100644 pkgconfig/Makefile.in create mode 100644 pkgconfig/gnunetarm.pc.in create mode 100644 pkgconfig/gnunetblock.pc.in create mode 100644 pkgconfig/gnunetcore.pc.in create mode 100644 pkgconfig/gnunetdatacache.pc.in create mode 100644 pkgconfig/gnunetdatastore.pc.in create mode 100644 pkgconfig/gnunetdht.pc.in create mode 100644 pkgconfig/gnunetdhtlog.pc.in create mode 100644 pkgconfig/gnunetdv.pc.in create mode 100644 pkgconfig/gnunetfragmentation.pc.in create mode 100644 pkgconfig/gnunetfs.pc.in create mode 100644 pkgconfig/gnunethello.pc.in create mode 100644 pkgconfig/gnunetnat.pc.in create mode 100644 pkgconfig/gnunetnse.pc.in create mode 100644 pkgconfig/gnunetpeerinfo.pc.in create mode 100644 pkgconfig/gnunetstatistics.pc.in create mode 100644 pkgconfig/gnunettesting.pc.in create mode 100644 pkgconfig/gnunettransport.pc.in create mode 100644 pkgconfig/gnunetutil.pc.in create mode 100644 po/ChangeLog create mode 100644 po/LINGUAS create mode 100644 po/Makefile.in.in create mode 100644 po/Makevars create mode 100644 po/POTFILES.in create mode 100644 po/Rules-quot create mode 100644 po/boldquot.sed create mode 100644 po/de.gmo create mode 100644 po/de.po create mode 100644 po/en@boldquot.header create mode 100644 po/en@quot.header create mode 100644 po/es.gmo create mode 100644 po/es.po create mode 100644 po/gnunet.pot create mode 100644 po/insert-header.sin create mode 100644 po/quot.sed create mode 100644 po/remove-potcdate.sin create mode 100644 po/stamp-po create mode 100644 po/sv.gmo create mode 100644 po/sv.po create mode 100644 po/vi.gmo create mode 100644 po/vi.po create mode 100644 po/zh_CN.gmo create mode 100644 po/zh_CN.po create mode 100644 src/Makefile.am create mode 100644 src/Makefile.in create mode 100644 src/arm/Makefile.am create mode 100644 src/arm/Makefile.in create mode 100644 src/arm/arm.conf.in create mode 100644 src/arm/arm.h create mode 100644 src/arm/arm_api.c create mode 100644 src/arm/do_start_process.c create mode 100644 src/arm/gnunet-arm.c create mode 100644 src/arm/gnunet-service-arm.c create mode 100644 src/arm/mockup-service.c create mode 100644 src/arm/test_arm_api.c create mode 100644 src/arm/test_arm_api_data.conf create mode 100644 src/arm/test_exponential_backoff.c create mode 100755 src/arm/test_gnunet_arm.sh create mode 100644 src/arm/test_gnunet_service_manager.c create mode 100644 src/ats/Makefile.am create mode 100644 src/ats/Makefile.in create mode 100644 src/ats/ats.conf.in create mode 100644 src/ats/ats.h create mode 100644 src/ats/ats_api_performance.c create mode 100644 src/ats/ats_api_scheduling.c create mode 100644 src/ats/gnunet-service-ats.c create mode 100644 src/ats/gnunet-service-ats.h create mode 100644 src/ats/gnunet-service-ats_addresses.c create mode 100644 src/ats/gnunet-service-ats_addresses.h create mode 100644 src/ats/gnunet-service-ats_addresses_mlp.c create mode 100644 src/ats/gnunet-service-ats_addresses_mlp.h create mode 100644 src/ats/gnunet-service-ats_performance.c create mode 100644 src/ats/gnunet-service-ats_performance.h create mode 100644 src/ats/gnunet-service-ats_reservations.c create mode 100644 src/ats/gnunet-service-ats_reservations.h create mode 100644 src/ats/gnunet-service-ats_scheduling.c create mode 100644 src/ats/gnunet-service-ats_scheduling.h create mode 100644 src/ats/perf_ats_mlp.c create mode 100644 src/ats/test_ats_api.conf create mode 100644 src/ats/test_ats_api_scheduling.c create mode 100644 src/ats/test_ats_mlp.c create mode 100644 src/ats/test_ats_mlp_averaging.c create mode 100644 src/block/Makefile.am create mode 100644 src/block/Makefile.in create mode 100644 src/block/block.c create mode 100644 src/block/plugin_block_template.c create mode 100644 src/block/plugin_block_test.c create mode 100644 src/block/test_block.c create mode 100644 src/chat/Makefile.am create mode 100644 src/chat/Makefile.in create mode 100644 src/chat/chat.c create mode 100644 src/chat/chat.conf.in create mode 100644 src/chat/chat.h create mode 100644 src/chat/gnunet-chat.c create mode 100644 src/chat/gnunet-service-chat.c create mode 100644 src/chat/test_chat.c create mode 100644 src/chat/test_chat_data.conf create mode 100644 src/chat/test_chat_peer1.conf create mode 100644 src/chat/test_chat_peer2.conf create mode 100644 src/chat/test_chat_peer3.conf create mode 100644 src/chat/test_chat_private.c create mode 100644 src/core/Makefile.am create mode 100644 src/core/Makefile.in create mode 100644 src/core/core.conf.in create mode 100644 src/core/core.h create mode 100644 src/core/core_api.c create mode 100644 src/core/core_api_iterate_peers.c create mode 100644 src/core/gnunet-core-list-connections.c create mode 100644 src/core/gnunet-service-core.c create mode 100644 src/core/gnunet-service-core.h create mode 100644 src/core/gnunet-service-core_clients.c create mode 100644 src/core/gnunet-service-core_clients.h create mode 100644 src/core/gnunet-service-core_kx.c create mode 100644 src/core/gnunet-service-core_kx.h create mode 100644 src/core/gnunet-service-core_neighbours.c create mode 100644 src/core/gnunet-service-core_neighbours.h create mode 100644 src/core/gnunet-service-core_sessions.c create mode 100644 src/core/gnunet-service-core_sessions.h create mode 100644 src/core/gnunet-service-core_typemap.c create mode 100644 src/core/gnunet-service-core_typemap.h create mode 100644 src/core/test_core_api.c create mode 100644 src/core/test_core_api_data.conf create mode 100644 src/core/test_core_api_peer1.conf create mode 100644 src/core/test_core_api_peer2.conf create mode 100644 src/core/test_core_api_reliability.c create mode 100644 src/core/test_core_api_send_to_self.c create mode 100644 src/core/test_core_api_send_to_self.conf create mode 100644 src/core/test_core_api_start_only.c create mode 100644 src/core/test_core_defaults.conf create mode 100644 src/core/test_core_quota_asymmetric_recv_limited_peer1.conf create mode 100644 src/core/test_core_quota_asymmetric_recv_limited_peer2.conf create mode 100644 src/core/test_core_quota_asymmetric_send_limit_peer1.conf create mode 100644 src/core/test_core_quota_asymmetric_send_limit_peer2.conf create mode 100644 src/core/test_core_quota_compliance.c create mode 100644 src/core/test_core_quota_peer1.conf create mode 100644 src/core/test_core_quota_peer2.conf create mode 100644 src/datacache/Makefile.am create mode 100644 src/datacache/Makefile.in create mode 100644 src/datacache/datacache.c create mode 100644 src/datacache/datacache.conf create mode 100644 src/datacache/perf_datacache.c create mode 100644 src/datacache/perf_datacache_data_mysql.conf create mode 100644 src/datacache/perf_datacache_data_postgres.conf create mode 100644 src/datacache/perf_datacache_data_sqlite.conf create mode 100644 src/datacache/plugin_datacache_mysql.c create mode 100644 src/datacache/plugin_datacache_postgres.c create mode 100644 src/datacache/plugin_datacache_sqlite.c create mode 100644 src/datacache/plugin_datacache_template.c create mode 100644 src/datacache/test_datacache.c create mode 100644 src/datacache/test_datacache_data_mysql.conf create mode 100644 src/datacache/test_datacache_data_postgres.conf create mode 100644 src/datacache/test_datacache_data_sqlite.conf create mode 100644 src/datacache/test_datacache_quota.c create mode 100644 src/datastore/Makefile.am create mode 100644 src/datastore/Makefile.in create mode 100644 src/datastore/datastore.conf.in create mode 100644 src/datastore/datastore.h create mode 100644 src/datastore/datastore_api.c create mode 100644 src/datastore/gnunet-service-datastore.c create mode 100644 src/datastore/perf_datastore_api.c create mode 100644 src/datastore/perf_plugin_datastore.c create mode 100644 src/datastore/perf_plugin_datastore_data_mysql.conf create mode 100644 src/datastore/perf_plugin_datastore_data_postgres.conf create mode 100644 src/datastore/perf_plugin_datastore_data_sqlite.conf create mode 100644 src/datastore/plugin_datastore_mysql.c create mode 100644 src/datastore/plugin_datastore_postgres.c create mode 100644 src/datastore/plugin_datastore_sqlite.c create mode 100644 src/datastore/plugin_datastore_template.c create mode 100644 src/datastore/test_datastore_api.c create mode 100644 src/datastore/test_datastore_api_data_mysql.conf create mode 100644 src/datastore/test_datastore_api_data_postgres.conf create mode 100644 src/datastore/test_datastore_api_data_sqlite.conf create mode 100644 src/datastore/test_datastore_api_management.c create mode 100644 src/datastore/test_defaults.conf create mode 100644 src/datastore/test_plugin_datastore.c create mode 100644 src/datastore/test_plugin_datastore_data_mysql.conf create mode 100644 src/datastore/test_plugin_datastore_data_postgres.conf create mode 100644 src/datastore/test_plugin_datastore_data_sqlite.conf create mode 100644 src/dht/Makefile.am create mode 100644 src/dht/Makefile.in create mode 100644 src/dht/dht.conf.in create mode 100644 src/dht/dht.h create mode 100644 src/dht/dht_api.c create mode 100644 src/dht/gnunet-dht-get.c create mode 100644 src/dht/gnunet-dht-put.c create mode 100644 src/dht/gnunet-service-dht.c create mode 100644 src/dht/gnunet-service-dht.h create mode 100644 src/dht/gnunet-service-dht_clients.c create mode 100644 src/dht/gnunet-service-dht_clients.h create mode 100644 src/dht/gnunet-service-dht_datacache.c create mode 100644 src/dht/gnunet-service-dht_datacache.h create mode 100644 src/dht/gnunet-service-dht_hello.c create mode 100644 src/dht/gnunet-service-dht_hello.h create mode 100644 src/dht/gnunet-service-dht_neighbours.c create mode 100644 src/dht/gnunet-service-dht_neighbours.h create mode 100644 src/dht/gnunet-service-dht_nse.c create mode 100644 src/dht/gnunet-service-dht_nse.h create mode 100644 src/dht/gnunet-service-dht_routing.c create mode 100644 src/dht/gnunet-service-dht_routing.h create mode 100644 src/dht/multipeer_topo.dat create mode 100644 src/dht/plugin_block_dht.c create mode 100644 src/dht/test_dht_2dtorus.conf create mode 100644 src/dht/test_dht_api.c create mode 100644 src/dht/test_dht_api_data.conf create mode 100644 src/dht/test_dht_api_peer1.conf create mode 100644 src/dht/test_dht_line.conf create mode 100644 src/dht/test_dht_monitor.c create mode 100644 src/dht/test_dht_multipeer.c create mode 100644 src/dht/test_dht_multipeer_data.conf create mode 100755 src/dht/test_dht_tools.sh create mode 100644 src/dht/test_dht_topo.c create mode 100644 src/dht/test_dht_twopeer.c create mode 100644 src/dht/test_dht_twopeer_data.conf create mode 100644 src/dht/test_dht_twopeer_get_put.c create mode 100644 src/dht/test_dht_twopeer_path_tracking.c create mode 100644 src/dht/test_dht_twopeer_put_get.c create mode 100644 src/dns/Makefile.am create mode 100644 src/dns/Makefile.in create mode 100644 src/dns/dns.conf.in create mode 100644 src/dns/dns.h create mode 100644 src/dns/dns_api.c create mode 100644 src/dns/dnsparser.c create mode 100644 src/dns/gnunet-dns-monitor.c create mode 100644 src/dns/gnunet-dns-redirector.c create mode 100644 src/dns/gnunet-helper-dns.c create mode 100644 src/dns/gnunet-service-dns.c create mode 100644 src/dns/plugin_block_dns.c create mode 100755 src/dns/test_gnunet_dns.sh create mode 100644 src/dv/Makefile.am create mode 100644 src/dv/Makefile.in create mode 100644 src/dv/dv.conf.in create mode 100644 src/dv/dv.h create mode 100644 src/dv/dv_api.c create mode 100644 src/dv/gnunet-service-dv.c create mode 100644 src/dv/plugin_transport_dv.c create mode 100644 src/dv/test_transport_api_dv.c create mode 100644 src/dv/test_transport_dv_data.conf create mode 100644 src/exit/Makefile.am create mode 100644 src/exit/Makefile.in create mode 100644 src/exit/exit.conf create mode 100644 src/exit/exit.h create mode 100644 src/exit/gnunet-daemon-exit.c create mode 100644 src/exit/gnunet-helper-exit.c create mode 100644 src/fragmentation/Makefile.am create mode 100644 src/fragmentation/Makefile.in create mode 100644 src/fragmentation/defragmentation.c create mode 100644 src/fragmentation/fragmentation.c create mode 100644 src/fragmentation/fragmentation.h create mode 100644 src/fragmentation/test_fragmentation.c create mode 100644 src/fragmentation/test_fragmentation_data.conf create mode 100644 src/fs/Makefile.am create mode 100644 src/fs/Makefile.in create mode 100644 src/fs/fs.conf.in create mode 100644 src/fs/fs.h create mode 100644 src/fs/fs_api.c create mode 100644 src/fs/fs_api.h create mode 100644 src/fs/fs_directory.c create mode 100644 src/fs/fs_dirmetascan.c create mode 100644 src/fs/fs_download.c create mode 100644 src/fs/fs_file_information.c create mode 100644 src/fs/fs_getopt.c create mode 100644 src/fs/fs_list_indexed.c create mode 100644 src/fs/fs_misc.c create mode 100644 src/fs/fs_namespace.c create mode 100644 src/fs/fs_namespace_advertise.c create mode 100644 src/fs/fs_publish.c create mode 100644 src/fs/fs_publish_ksk.c create mode 100644 src/fs/fs_search.c create mode 100644 src/fs/fs_sharetree.c create mode 100644 src/fs/fs_test_lib.c create mode 100644 src/fs/fs_test_lib.h create mode 100644 src/fs/fs_test_lib_data.conf create mode 100644 src/fs/fs_tree.c create mode 100644 src/fs/fs_tree.h create mode 100644 src/fs/fs_unindex.c create mode 100644 src/fs/fs_uri.c create mode 100644 src/fs/gnunet-directory.c create mode 100755 src/fs/gnunet-download-manager.scm create mode 100644 src/fs/gnunet-download.c create mode 100644 src/fs/gnunet-fs.c create mode 100644 src/fs/gnunet-helper-fs-publish.c create mode 100644 src/fs/gnunet-pseudonym.c create mode 100644 src/fs/gnunet-publish.c create mode 100644 src/fs/gnunet-search.c create mode 100644 src/fs/gnunet-service-fs.c create mode 100644 src/fs/gnunet-service-fs.h create mode 100644 src/fs/gnunet-service-fs_cp.c create mode 100644 src/fs/gnunet-service-fs_cp.h create mode 100644 src/fs/gnunet-service-fs_indexing.c create mode 100644 src/fs/gnunet-service-fs_indexing.h create mode 100644 src/fs/gnunet-service-fs_lc.c create mode 100644 src/fs/gnunet-service-fs_lc.h create mode 100644 src/fs/gnunet-service-fs_pe.c create mode 100644 src/fs/gnunet-service-fs_pe.h create mode 100644 src/fs/gnunet-service-fs_pr.c create mode 100644 src/fs/gnunet-service-fs_pr.h create mode 100644 src/fs/gnunet-service-fs_push.c create mode 100644 src/fs/gnunet-service-fs_push.h create mode 100644 src/fs/gnunet-service-fs_put.c create mode 100644 src/fs/gnunet-service-fs_put.h create mode 100644 src/fs/gnunet-unindex.c create mode 100644 src/fs/perf_gnunet_service_fs_p2p.c create mode 100644 src/fs/perf_gnunet_service_fs_p2p_trust.c create mode 100644 src/fs/plugin_block_fs.c create mode 100644 src/fs/test_fs_data.conf create mode 100644 src/fs/test_fs_defaults.conf create mode 100644 src/fs/test_fs_directory.c create mode 100644 src/fs/test_fs_download.c create mode 100644 src/fs/test_fs_download_data.conf create mode 100644 src/fs/test_fs_download_indexed.c create mode 100644 src/fs/test_fs_download_persistence.c create mode 100644 src/fs/test_fs_file_information.c create mode 100644 src/fs/test_fs_file_information_data.conf create mode 100644 src/fs/test_fs_getopt.c create mode 100644 src/fs/test_fs_list_indexed.c create mode 100644 src/fs/test_fs_list_indexed_data.conf create mode 100644 src/fs/test_fs_namespace.c create mode 100644 src/fs/test_fs_namespace_data.conf create mode 100644 src/fs/test_fs_namespace_list_updateable.c create mode 100644 src/fs/test_fs_publish.c create mode 100644 src/fs/test_fs_publish_data.conf create mode 100644 src/fs/test_fs_publish_persistence.c create mode 100644 src/fs/test_fs_search.c create mode 100644 src/fs/test_fs_search_data.conf create mode 100644 src/fs/test_fs_search_persistence.c create mode 100644 src/fs/test_fs_start_stop.c create mode 100644 src/fs/test_fs_test_lib.c create mode 100644 src/fs/test_fs_unindex.c create mode 100644 src/fs/test_fs_unindex_data.conf create mode 100644 src/fs/test_fs_unindex_persistence.c create mode 100644 src/fs/test_fs_uri.c create mode 100644 src/fs/test_fs_uri_data.conf create mode 100755 src/fs/test_gnunet_fs_idx.py.in create mode 100644 src/fs/test_gnunet_fs_idx_data.conf create mode 100755 src/fs/test_gnunet_fs_ns.py.in create mode 100644 src/fs/test_gnunet_fs_ns_data.conf create mode 100755 src/fs/test_gnunet_fs_psd.py.in create mode 100644 src/fs/test_gnunet_fs_psd_data.conf create mode 100755 src/fs/test_gnunet_fs_rec.py.in create mode 100644 src/fs/test_gnunet_fs_rec_data.conf create mode 100644 src/fs/test_gnunet_fs_rec_data.tgz create mode 100644 src/fs/test_gnunet_service_fs_migration.c create mode 100644 src/fs/test_gnunet_service_fs_migration_data.conf create mode 100644 src/fs/test_gnunet_service_fs_p2p.c create mode 100644 src/gns/Makefile.am create mode 100644 src/gns/Makefile.in create mode 100644 src/gns/gns.conf.in create mode 100644 src/gns/gns.h create mode 100644 src/gns/gns_api.c create mode 100644 src/gns/gnunet-service-gns.c create mode 100644 src/gns/namestore_stub_api.c create mode 100644 src/gns/plugin_block_gns.c create mode 100644 src/gns/test_gns_twopeer.c create mode 100644 src/gns/test_gns_twopeer.conf create mode 100755 src/gns/test_gnunet_gns.sh create mode 100644 src/hello/Makefile.am create mode 100644 src/hello/Makefile.in create mode 100644 src/hello/address.c create mode 100644 src/hello/hello.c create mode 100644 src/hello/test_hello.c create mode 100644 src/hostlist/Makefile.am create mode 100644 src/hostlist/Makefile.in create mode 100644 src/hostlist/gnunet-daemon-hostlist.c create mode 100644 src/hostlist/gnunet-daemon-hostlist.h create mode 100644 src/hostlist/hostlist-client.c create mode 100644 src/hostlist/hostlist-client.h create mode 100644 src/hostlist/hostlist-server.c create mode 100644 src/hostlist/hostlist-server.h create mode 100644 src/hostlist/hostlist.conf create mode 100644 src/hostlist/learning_data.conf create mode 100644 src/hostlist/test_gnunet_daemon_hostlist.c create mode 100644 src/hostlist/test_gnunet_daemon_hostlist_data.conf create mode 100644 src/hostlist/test_gnunet_daemon_hostlist_learning.c create mode 100644 src/hostlist/test_gnunet_daemon_hostlist_peer1.conf create mode 100644 src/hostlist/test_gnunet_daemon_hostlist_peer2.conf create mode 100644 src/hostlist/test_gnunet_daemon_hostlist_reconnect.c create mode 100644 src/hostlist/test_hostlist_defaults.conf create mode 100644 src/hostlist/test_learning_adv_peer.conf create mode 100644 src/hostlist/test_learning_learn_peer.conf create mode 100644 src/hostlist/test_learning_learn_peer2.conf create mode 100644 src/include/Makefile.am create mode 100644 src/include/Makefile.in create mode 100644 src/include/block_dns.h create mode 100644 src/include/block_fs.h create mode 100644 src/include/block_gns.h create mode 100644 src/include/gauger.h create mode 100644 src/include/gettext.h create mode 100644 src/include/gnunet_applications.h create mode 100644 src/include/gnunet_arm_service.h create mode 100644 src/include/gnunet_ats_service.h create mode 100644 src/include/gnunet_bandwidth_lib.h create mode 100644 src/include/gnunet_bio_lib.h create mode 100644 src/include/gnunet_block_lib.h create mode 100644 src/include/gnunet_block_plugin.h create mode 100644 src/include/gnunet_chat_service.h create mode 100644 src/include/gnunet_client_lib.h create mode 100644 src/include/gnunet_common.h create mode 100644 src/include/gnunet_configuration_lib.h create mode 100644 src/include/gnunet_connection_lib.h create mode 100644 src/include/gnunet_constants.h create mode 100644 src/include/gnunet_container_lib.h create mode 100644 src/include/gnunet_core_service.h create mode 100644 src/include/gnunet_crypto_lib.h create mode 100644 src/include/gnunet_datacache_lib.h create mode 100644 src/include/gnunet_datacache_plugin.h create mode 100644 src/include/gnunet_datastore_plugin.h create mode 100644 src/include/gnunet_datastore_service.h create mode 100644 src/include/gnunet_dht_service.h create mode 100644 src/include/gnunet_directories.h.in create mode 100644 src/include/gnunet_disk_lib.h create mode 100644 src/include/gnunet_dns_service.h create mode 100644 src/include/gnunet_dnsparser_lib.h create mode 100644 src/include/gnunet_dv_service.h create mode 100644 src/include/gnunet_fragmentation_lib.h create mode 100644 src/include/gnunet_fs_service.h create mode 100644 src/include/gnunet_getopt_lib.h create mode 100644 src/include/gnunet_gns_service.h create mode 100644 src/include/gnunet_hello_lib.h create mode 100644 src/include/gnunet_helper_lib.h create mode 100644 src/include/gnunet_load_lib.h create mode 100644 src/include/gnunet_mesh_service.h create mode 100644 src/include/gnunet_namestore_plugin.h create mode 100644 src/include/gnunet_namestore_service.h create mode 100644 src/include/gnunet_nat_lib.h create mode 100644 src/include/gnunet_network_lib.h create mode 100644 src/include/gnunet_nse_service.h create mode 100644 src/include/gnunet_os_lib.h create mode 100644 src/include/gnunet_peer_lib.h create mode 100644 src/include/gnunet_peerinfo_service.h create mode 100644 src/include/gnunet_plugin_lib.h create mode 100644 src/include/gnunet_program_lib.h create mode 100644 src/include/gnunet_protocols.h create mode 100644 src/include/gnunet_pseudonym_lib.h create mode 100644 src/include/gnunet_resolver_service.h create mode 100644 src/include/gnunet_scheduler_lib.h create mode 100644 src/include/gnunet_server_lib.h create mode 100644 src/include/gnunet_service_lib.h create mode 100644 src/include/gnunet_signal_lib.h create mode 100644 src/include/gnunet_signatures.h create mode 100644 src/include/gnunet_statistics_service.h create mode 100644 src/include/gnunet_stream_lib.h create mode 100644 src/include/gnunet_strings_lib.h create mode 100644 src/include/gnunet_testing_lib.h create mode 100644 src/include/gnunet_time_lib.h create mode 100644 src/include/gnunet_transport_plugin.h create mode 100644 src/include/gnunet_transport_service.h create mode 100644 src/include/gnunet_tun_lib.h create mode 100644 src/include/gnunet_util_lib.h create mode 100644 src/include/gnunet_vpn_service.h create mode 100644 src/include/platform.h create mode 100644 src/include/plibc.h create mode 100644 src/include/winproc.h create mode 100644 src/integration-tests/Makefile.am create mode 100644 src/integration-tests/Makefile.in create mode 100644 src/integration-tests/confs/c_bootstrap_server.conf create mode 100644 src/integration-tests/confs/c_nat_client.conf create mode 100644 src/integration-tests/confs/c_no_nat_client.conf create mode 100644 src/integration-tests/confs/c_no_nat_client_2.conf create mode 100644 src/integration-tests/gnunet_pyexpect.py.in create mode 100644 src/integration-tests/gnunet_testing.py.in create mode 100644 src/integration-tests/hostkeys/0000-hostkey create mode 100644 src/integration-tests/hostkeys/0001-hostkey create mode 100644 src/integration-tests/hostkeys/0002-hostkey create mode 100644 src/integration-tests/hostkeys/0003-hostkey create mode 100644 src/integration-tests/hostkeys/0004-hostkey create mode 100644 src/integration-tests/hostkeys/0005-hostkey create mode 100644 src/integration-tests/hostkeys/0006-hostkey create mode 100644 src/integration-tests/hostkeys/0007-hostkey create mode 100644 src/integration-tests/hostkeys/0008-hostkey create mode 100644 src/integration-tests/hostkeys/0009-hostkey create mode 100755 src/integration-tests/test_integration_bootstrap_and_connect.py.in create mode 100755 src/integration-tests/test_integration_bootstrap_and_connect_and_disconnect.py.in create mode 100755 src/integration-tests/test_integration_bootstrap_and_connect_and_disconnect_nat.py.in create mode 100755 src/integration-tests/test_integration_clique.py.in create mode 100755 src/integration-tests/test_integration_clique_nat.py.in create mode 100755 src/integration-tests/test_integration_disconnect.py.in create mode 100755 src/integration-tests/test_integration_restart.py.in create mode 100644 src/mesh/Makefile.am create mode 100644 src/mesh/Makefile.in create mode 100644 src/mesh/gnunet-service-mesh.c create mode 100644 src/mesh/mesh.conf.in create mode 100644 src/mesh/mesh.h create mode 100644 src/mesh/mesh_api.c create mode 100644 src/mesh/mesh_protocol.h create mode 100644 src/mesh/mesh_tunnel_tree.c create mode 100644 src/mesh/mesh_tunnel_tree.h create mode 100644 src/mesh/test_mesh.conf create mode 100644 src/mesh/test_mesh_2dtorus.c create mode 100644 src/mesh/test_mesh_2dtorus.conf create mode 100644 src/mesh/test_mesh_api.c create mode 100644 src/mesh/test_mesh_local_1.c create mode 100644 src/mesh/test_mesh_local_2.c create mode 100644 src/mesh/test_mesh_path.conf create mode 100644 src/mesh/test_mesh_small.c create mode 100644 src/mesh/test_mesh_small.conf create mode 100644 src/mesh/test_mesh_tree_api.c create mode 100644 src/namestore/Makefile.am create mode 100644 src/namestore/Makefile.in create mode 100644 src/namestore/gnunet-service-namestore.c create mode 100644 src/namestore/hostkey create mode 100644 src/namestore/namestore.conf.in create mode 100644 src/namestore/namestore.h create mode 100644 src/namestore/namestore_api.c create mode 100644 src/namestore/namestore_common.c create mode 100644 src/namestore/plugin_namestore_sqlite.c create mode 100644 src/namestore/test_namestore_api.c create mode 100644 src/namestore/test_namestore_api.conf create mode 100644 src/namestore/test_namestore_api_zone_iteration.c create mode 100644 src/namestore/test_namestore_record_serialization.c create mode 100644 src/namestore/test_plugin_namestore.c create mode 100644 src/namestore/test_plugin_namestore_sqlite.conf create mode 100644 src/nat/Makefile.am create mode 100644 src/nat/Makefile.in create mode 100644 src/nat/gnunet-helper-nat-client-windows.c create mode 100644 src/nat/gnunet-helper-nat-client.c create mode 100644 src/nat/gnunet-helper-nat-server-windows.c create mode 100644 src/nat/gnunet-helper-nat-server.c create mode 100644 src/nat/gnunet-nat-server.c create mode 100644 src/nat/nat.c create mode 100644 src/nat/nat.conf create mode 100644 src/nat/nat.h create mode 100644 src/nat/nat_mini.c create mode 100644 src/nat/nat_test.c create mode 100644 src/nat/test_nat.c create mode 100644 src/nat/test_nat_data.conf create mode 100644 src/nat/test_nat_mini.c create mode 100644 src/nat/test_nat_test.c create mode 100644 src/nat/test_nat_test_data.conf create mode 100644 src/nse/Makefile.am create mode 100644 src/nse/Makefile.in create mode 100644 src/nse/gnunet-nse-profiler.c create mode 100644 src/nse/gnunet-service-nse.c create mode 100644 src/nse/nse.conf.in create mode 100644 src/nse/nse.h create mode 100644 src/nse/nse_api.c create mode 100644 src/nse/nse_profiler_test.conf create mode 100644 src/nse/test_nse.conf create mode 100644 src/nse/test_nse_api.c create mode 100644 src/nse/test_nse_multipeer.c create mode 100644 src/peerinfo-tool/Makefile.am create mode 100644 src/peerinfo-tool/Makefile.in create mode 100644 src/peerinfo-tool/gnunet-peerinfo.c create mode 100755 src/peerinfo-tool/test_gnunet_peerinfo.py.in create mode 100644 src/peerinfo-tool/test_gnunet_peerinfo_data.conf create mode 100644 src/peerinfo/Makefile.am create mode 100644 src/peerinfo/Makefile.in create mode 100644 src/peerinfo/gnunet-service-peerinfo.c create mode 100644 src/peerinfo/peerinfo.conf.in create mode 100644 src/peerinfo/peerinfo.h create mode 100644 src/peerinfo/peerinfo_api.c create mode 100644 src/peerinfo/peerinfo_api_notify.c create mode 100755 src/peerinfo/perf_peerinfo_api.c create mode 100644 src/peerinfo/test_peerinfo_api.c create mode 100644 src/peerinfo/test_peerinfo_api_data.conf create mode 100644 src/pt/Makefile.am create mode 100644 src/pt/Makefile.in create mode 100644 src/pt/gnunet-daemon-pt.c create mode 100644 src/pt/pt.conf create mode 100644 src/statistics/Makefile.am create mode 100644 src/statistics/Makefile.in create mode 100644 src/statistics/gnunet-service-statistics.c create mode 100644 src/statistics/gnunet-statistics.c create mode 100644 src/statistics/statistics.conf.in create mode 100644 src/statistics/statistics.h create mode 100644 src/statistics/statistics_api.c create mode 100755 src/statistics/test_gnunet_statistics.sh create mode 100644 src/statistics/test_statistics_api.c create mode 100644 src/statistics/test_statistics_api_data.conf create mode 100644 src/statistics/test_statistics_api_loop.c create mode 100644 src/statistics/test_statistics_api_watch.c create mode 100644 src/stream/Makefile.am create mode 100644 src/stream/Makefile.in create mode 100644 src/stream/README create mode 100644 src/stream/stream_api.c create mode 100644 src/stream/stream_protocol.h create mode 100644 src/stream/test_stream_local.c create mode 100644 src/stream/test_stream_local.conf create mode 100644 src/template/Makefile.am create mode 100644 src/template/Makefile.in create mode 100644 src/template/gnunet-service-template.c create mode 100644 src/template/gnunet-template.c create mode 100644 src/template/template.conf create mode 100644 src/template/test_template_api.c create mode 100644 src/testing/Makefile.am create mode 100644 src/testing/Makefile.in create mode 100644 src/testing/gnunet-testing.c create mode 100644 src/testing/helper.c create mode 100644 src/testing/test_testing.c create mode 100644 src/testing/test_testing_2dtorus.c create mode 100644 src/testing/test_testing_2dtorus.conf create mode 100644 src/testing/test_testing_connect.c create mode 100644 src/testing/test_testing_connect_peer1.conf create mode 100644 src/testing/test_testing_connect_peer2.conf create mode 100644 src/testing/test_testing_data.conf create mode 100644 src/testing/test_testing_data_remote.conf create mode 100644 src/testing/test_testing_data_topology_2d_torus.conf create mode 100644 src/testing/test_testing_data_topology_blacklist.conf create mode 100644 src/testing/test_testing_data_topology_churn.conf create mode 100644 src/testing/test_testing_data_topology_clique.conf create mode 100644 src/testing/test_testing_data_topology_clique_dfs.conf create mode 100644 src/testing/test_testing_data_topology_clique_minimum.conf create mode 100644 src/testing/test_testing_data_topology_clique_random.conf create mode 100644 src/testing/test_testing_data_topology_erdos_renyi.conf create mode 100644 src/testing/test_testing_data_topology_internat.conf create mode 100644 src/testing/test_testing_data_topology_none.conf create mode 100644 src/testing/test_testing_data_topology_ring.conf create mode 100644 src/testing/test_testing_data_topology_scale_free.conf create mode 100644 src/testing/test_testing_data_topology_small_world_ring.conf create mode 100644 src/testing/test_testing_data_topology_small_world_torus.conf create mode 100644 src/testing/test_testing_data_topology_stability.conf create mode 100644 src/testing/test_testing_defaults.conf create mode 100644 src/testing/test_testing_group.c create mode 100644 src/testing/test_testing_group_remote.c create mode 100644 src/testing/test_testing_peergroup.c create mode 100644 src/testing/test_testing_peergroup_data.conf create mode 100644 src/testing/test_testing_reconnect.c create mode 100644 src/testing/test_testing_topology.c create mode 100644 src/testing/test_testing_topology_blacklist.c create mode 100644 src/testing/test_testing_topology_churn.c create mode 100644 src/testing/testing.c create mode 100644 src/testing/testing.conf create mode 100644 src/testing/testing_group.c create mode 100644 src/testing/testing_peergroup.c create mode 100644 src/topology/Makefile.am create mode 100644 src/topology/Makefile.in create mode 100644 src/topology/gnunet-daemon-topology.c create mode 100644 src/topology/test_gnunet_daemon_topology.c create mode 100644 src/topology/test_gnunet_daemon_topology_data.conf create mode 100644 src/topology/topology.conf create mode 100644 src/transport/Makefile.am create mode 100644 src/transport/Makefile.in create mode 100644 src/transport/gnunet-helper-transport-wlan-dummy.c create mode 100644 src/transport/gnunet-helper-transport-wlan.c create mode 100644 src/transport/gnunet-service-transport.c create mode 100644 src/transport/gnunet-service-transport.h create mode 100644 src/transport/gnunet-service-transport_blacklist.c create mode 100644 src/transport/gnunet-service-transport_blacklist.h create mode 100644 src/transport/gnunet-service-transport_clients.c create mode 100644 src/transport/gnunet-service-transport_clients.h create mode 100644 src/transport/gnunet-service-transport_hello.c create mode 100644 src/transport/gnunet-service-transport_hello.h create mode 100644 src/transport/gnunet-service-transport_neighbours.c create mode 100644 src/transport/gnunet-service-transport_neighbours.h create mode 100644 src/transport/gnunet-service-transport_plugins.c create mode 100644 src/transport/gnunet-service-transport_plugins.h create mode 100644 src/transport/gnunet-service-transport_validation.c create mode 100644 src/transport/gnunet-service-transport_validation.h create mode 100755 src/transport/gnunet-transport-certificate-creation create mode 100644 src/transport/gnunet-transport-certificate-creation.c create mode 100644 src/transport/gnunet-transport-wlan-sender.c create mode 100644 src/transport/gnunet-transport.c create mode 100644 src/transport/plugin_transport_http.c create mode 100644 src/transport/plugin_transport_http.h create mode 100644 src/transport/plugin_transport_http_client.c create mode 100644 src/transport/plugin_transport_http_server.c create mode 100644 src/transport/plugin_transport_tcp.c create mode 100644 src/transport/plugin_transport_template.c create mode 100644 src/transport/plugin_transport_udp.c create mode 100644 src/transport/plugin_transport_udp.h create mode 100644 src/transport/plugin_transport_udp_broadcasting.c create mode 100644 src/transport/plugin_transport_unix.c create mode 100644 src/transport/plugin_transport_wlan.c create mode 100644 src/transport/plugin_transport_wlan.h create mode 100644 src/transport/template_cfg_peer1.conf create mode 100644 src/transport/template_cfg_peer2.conf create mode 100644 src/transport/test_plugin_transport_data.conf create mode 100644 src/transport/test_plugin_transport_data_udp.conf create mode 100644 src/transport/test_quota_compliance.c create mode 100644 src/transport/test_quota_compliance_data.conf create mode 100644 src/transport/test_quota_compliance_http_asymmetric_peer1.conf create mode 100644 src/transport/test_quota_compliance_http_asymmetric_peer2.conf create mode 100644 src/transport/test_quota_compliance_http_peer1.conf create mode 100644 src/transport/test_quota_compliance_http_peer2.conf create mode 100644 src/transport/test_quota_compliance_https_asymmetric_peer1.conf create mode 100644 src/transport/test_quota_compliance_https_asymmetric_peer2.conf create mode 100644 src/transport/test_quota_compliance_https_peer1.conf create mode 100644 src/transport/test_quota_compliance_https_peer2.conf create mode 100644 src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf create mode 100644 src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf create mode 100644 src/transport/test_quota_compliance_tcp_peer1.conf create mode 100644 src/transport/test_quota_compliance_tcp_peer2.conf create mode 100644 src/transport/test_quota_compliance_udp_peer1.conf create mode 100644 src/transport/test_quota_compliance_udp_peer2.conf create mode 100644 src/transport/test_quota_compliance_unix_asymmetric_peer1.conf create mode 100644 src/transport/test_quota_compliance_unix_asymmetric_peer2.conf create mode 100644 src/transport/test_quota_compliance_unix_peer1.conf create mode 100644 src/transport/test_quota_compliance_unix_peer2.conf create mode 100644 src/transport/test_transport_api.c create mode 100644 src/transport/test_transport_api_bidirectional_connect.c create mode 100644 src/transport/test_transport_api_bidirectional_connect_peer1.conf create mode 100644 src/transport/test_transport_api_bidirectional_connect_peer2.conf create mode 100644 src/transport/test_transport_api_blacklisting.c create mode 100644 src/transport/test_transport_api_data.conf create mode 100644 src/transport/test_transport_api_disconnect.c create mode 100644 src/transport/test_transport_api_disconnect_tcp_peer1.conf create mode 100644 src/transport/test_transport_api_disconnect_tcp_peer2.conf create mode 100644 src/transport/test_transport_api_http_nat_peer1.conf create mode 100644 src/transport/test_transport_api_http_nat_peer2.conf create mode 100644 src/transport/test_transport_api_http_peer1.conf create mode 100644 src/transport/test_transport_api_http_peer2.conf create mode 100644 src/transport/test_transport_api_https_nat_peer1.conf create mode 100644 src/transport/test_transport_api_https_nat_peer2.conf create mode 100644 src/transport/test_transport_api_https_peer1.conf create mode 100644 src/transport/test_transport_api_https_peer2.conf create mode 100644 src/transport/test_transport_api_limited_sockets.c create mode 100644 src/transport/test_transport_api_limited_sockets_tcp_peer1.conf create mode 100644 src/transport/test_transport_api_limited_sockets_tcp_peer2.conf create mode 100644 src/transport/test_transport_api_multi_peer1.conf create mode 100644 src/transport/test_transport_api_multi_peer2.conf create mode 100644 src/transport/test_transport_api_reliability.c create mode 100644 src/transport/test_transport_api_reliability_http_nat_peer1.conf create mode 100644 src/transport/test_transport_api_reliability_http_nat_peer2.conf create mode 100644 src/transport/test_transport_api_reliability_http_peer1.conf create mode 100644 src/transport/test_transport_api_reliability_http_peer2.conf create mode 100644 src/transport/test_transport_api_reliability_https_nat_peer1.conf create mode 100644 src/transport/test_transport_api_reliability_https_nat_peer2.conf create mode 100644 src/transport/test_transport_api_reliability_https_peer1.conf create mode 100644 src/transport/test_transport_api_reliability_https_peer2.conf create mode 100644 src/transport/test_transport_api_reliability_tcp_nat_peer1.conf create mode 100644 src/transport/test_transport_api_reliability_tcp_nat_peer2.conf create mode 100644 src/transport/test_transport_api_reliability_tcp_peer1.conf create mode 100644 src/transport/test_transport_api_reliability_tcp_peer2.conf create mode 100644 src/transport/test_transport_api_reliability_wlan_peer1.conf create mode 100644 src/transport/test_transport_api_reliability_wlan_peer2.conf create mode 100644 src/transport/test_transport_api_restart_1peer.c create mode 100644 src/transport/test_transport_api_restart_2peers.c create mode 100644 src/transport/test_transport_api_tcp_nat_peer1.conf create mode 100644 src/transport/test_transport_api_tcp_nat_peer2.conf create mode 100644 src/transport/test_transport_api_tcp_peer1.conf create mode 100644 src/transport/test_transport_api_tcp_peer2.conf create mode 100644 src/transport/test_transport_api_timeout.c create mode 100644 src/transport/test_transport_api_timeout_http_peer1.conf create mode 100644 src/transport/test_transport_api_timeout_http_peer2.conf create mode 100644 src/transport/test_transport_api_timeout_https_peer1.conf create mode 100644 src/transport/test_transport_api_timeout_https_peer2.conf create mode 100644 src/transport/test_transport_api_timeout_tcp_peer1.conf create mode 100644 src/transport/test_transport_api_timeout_tcp_peer2.conf create mode 100644 src/transport/test_transport_api_timeout_udp_peer1.conf create mode 100644 src/transport/test_transport_api_timeout_udp_peer2.conf create mode 100644 src/transport/test_transport_api_timeout_unix_peer1.conf create mode 100644 src/transport/test_transport_api_timeout_unix_peer2.conf create mode 100644 src/transport/test_transport_api_udp_nat_peer1.conf create mode 100644 src/transport/test_transport_api_udp_nat_peer2.conf create mode 100644 src/transport/test_transport_api_udp_peer1.conf create mode 100644 src/transport/test_transport_api_udp_peer2.conf create mode 100644 src/transport/test_transport_api_unix_peer1.conf create mode 100644 src/transport/test_transport_api_unix_peer2.conf create mode 100644 src/transport/test_transport_api_unreliability.c create mode 100644 src/transport/test_transport_api_unreliability_constant.c create mode 100644 src/transport/test_transport_api_unreliability_constant_udp_peer1.conf create mode 100644 src/transport/test_transport_api_unreliability_constant_udp_peer2.conf create mode 100644 src/transport/test_transport_api_unreliability_udp_peer1.conf create mode 100644 src/transport/test_transport_api_unreliability_udp_peer2.conf create mode 100644 src/transport/test_transport_api_unreliability_unix_peer1.conf create mode 100644 src/transport/test_transport_api_unreliability_unix_peer2.conf create mode 100644 src/transport/test_transport_api_unreliability_wlan_peer1.conf create mode 100644 src/transport/test_transport_api_unreliability_wlan_peer2.conf create mode 100644 src/transport/test_transport_api_wlan_peer1.conf create mode 100644 src/transport/test_transport_api_wlan_peer2.conf create mode 100644 src/transport/test_transport_defaults.conf create mode 100644 src/transport/test_transport_startonly.c create mode 100644 src/transport/test_transport_startonly.conf create mode 100644 src/transport/test_transport_testing.c create mode 100644 src/transport/transport-testing.c create mode 100644 src/transport/transport-testing.h create mode 100644 src/transport/transport.conf.in create mode 100644 src/transport/transport.h create mode 100644 src/transport/transport_api.c create mode 100644 src/transport/transport_api_address_lookup.c create mode 100644 src/transport/transport_api_address_to_string.c create mode 100644 src/transport/transport_api_blacklist.c create mode 100644 src/tun/Makefile.am create mode 100644 src/tun/Makefile.in create mode 100644 src/tun/test_tun.c create mode 100644 src/tun/tun.c create mode 100644 src/util/Makefile.am create mode 100644 src/util/Makefile.in create mode 100644 src/util/bandwidth.c create mode 100644 src/util/bio.c create mode 100644 src/util/client.c create mode 100644 src/util/common_allocation.c create mode 100644 src/util/common_endian.c create mode 100644 src/util/common_logging.c create mode 100644 src/util/configuration.c create mode 100644 src/util/connection.c create mode 100644 src/util/container_bloomfilter.c create mode 100644 src/util/container_heap.c create mode 100644 src/util/container_meta_data.c create mode 100644 src/util/container_multihashmap.c create mode 100644 src/util/container_slist.c create mode 100644 src/util/crypto_aes.c create mode 100644 src/util/crypto_crc.c create mode 100644 src/util/crypto_hash.c create mode 100644 src/util/crypto_hkdf.c create mode 100644 src/util/crypto_kdf.c create mode 100644 src/util/crypto_ksk.c create mode 100644 src/util/crypto_random.c create mode 100644 src/util/crypto_rsa.c create mode 100644 src/util/disk.c create mode 100644 src/util/disk.h create mode 100644 src/util/getopt.c create mode 100644 src/util/getopt_helpers.c create mode 100644 src/util/gnunet-config-diff.c create mode 100644 src/util/gnunet-resolver.c create mode 100644 src/util/gnunet-service-resolver.c create mode 100644 src/util/helper.c create mode 100644 src/util/load.c create mode 100644 src/util/network.c create mode 100644 src/util/os_installation.c create mode 100644 src/util/os_network.c create mode 100644 src/util/os_priority.c create mode 100644 src/util/peer.c create mode 100644 src/util/perf_crypto_hash.c create mode 100644 src/util/plugin.c create mode 100644 src/util/program.c create mode 100644 src/util/pseudonym.c create mode 100644 src/util/resolver.conf.in create mode 100644 src/util/resolver.h create mode 100644 src/util/resolver_api.c create mode 100644 src/util/scheduler.c create mode 100644 src/util/server.c create mode 100644 src/util/server_mst.c create mode 100644 src/util/server_nc.c create mode 100644 src/util/server_tc.c create mode 100644 src/util/service.c create mode 100644 src/util/signal.c create mode 100644 src/util/strings.c create mode 100644 src/util/test_bio.c create mode 100644 src/util/test_client.c create mode 100644 src/util/test_common_allocation.c create mode 100644 src/util/test_common_endian.c create mode 100644 src/util/test_common_logging.c create mode 100644 src/util/test_common_logging_dummy.c create mode 100644 src/util/test_common_logging_runtime_loglevels.c create mode 100644 src/util/test_configuration.c create mode 100644 src/util/test_configuration_data.conf create mode 100644 src/util/test_connection.c create mode 100644 src/util/test_connection_addressing.c create mode 100644 src/util/test_connection_receive_cancel.c create mode 100644 src/util/test_connection_timeout.c create mode 100644 src/util/test_connection_timeout_no_connect.c create mode 100644 src/util/test_connection_transmit_cancel.c create mode 100644 src/util/test_container_bloomfilter.c create mode 100644 src/util/test_container_heap.c create mode 100644 src/util/test_container_meta_data.c create mode 100644 src/util/test_container_multihashmap.c create mode 100644 src/util/test_container_slist.c create mode 100644 src/util/test_crypto_aes.c create mode 100644 src/util/test_crypto_aes_weak.c create mode 100644 src/util/test_crypto_crc.c create mode 100644 src/util/test_crypto_hash.c create mode 100644 src/util/test_crypto_hkdf.c create mode 100644 src/util/test_crypto_ksk.c create mode 100644 src/util/test_crypto_random.c create mode 100644 src/util/test_crypto_rsa.c create mode 100644 src/util/test_disk.c create mode 100644 src/util/test_getopt.c create mode 100644 src/util/test_os_network.c create mode 100644 src/util/test_os_priority.c create mode 100644 src/util/test_os_start_process.c create mode 100644 src/util/test_peer.c create mode 100644 src/util/test_plugin.c create mode 100644 src/util/test_plugin_plug.c create mode 100644 src/util/test_program.c create mode 100644 src/util/test_program_data.conf create mode 100644 src/util/test_pseudonym.c create mode 100644 src/util/test_pseudonym_data.conf create mode 100644 src/util/test_resolver_api.c create mode 100644 src/util/test_resolver_api_data.conf create mode 100644 src/util/test_scheduler.c create mode 100644 src/util/test_scheduler_delay.c create mode 100644 src/util/test_server.c create mode 100644 src/util/test_server_disconnect.c create mode 100644 src/util/test_server_with_client.c create mode 100644 src/util/test_server_with_client_unix.c create mode 100644 src/util/test_service.c create mode 100644 src/util/test_service_data.conf create mode 100644 src/util/test_strings.c create mode 100644 src/util/test_time.c create mode 100644 src/util/time.c create mode 100644 src/util/util.conf create mode 100644 src/util/win.cc create mode 100644 src/util/winproc.c create mode 100644 src/vpn/Makefile.am create mode 100644 src/vpn/Makefile.in create mode 100644 src/vpn/gnunet-helper-vpn.c create mode 100644 src/vpn/gnunet-service-vpn.c create mode 100644 src/vpn/gnunet-vpn.c create mode 100644 src/vpn/test_gnunet_vpn.c create mode 100644 src/vpn/test_gnunet_vpn.conf create mode 100644 src/vpn/vpn.conf.in create mode 100644 src/vpn/vpn.h create mode 100644 src/vpn/vpn_api.c diff --git a/ABOUT-NLS b/ABOUT-NLS new file mode 100644 index 0000000..ec20977 --- /dev/null +++ b/ABOUT-NLS @@ -0,0 +1,1101 @@ +1 Notes on the Free Translation Project +*************************************** + +Free software is going international! The Free Translation Project is +a way to get maintainers of free software, translators, and users all +together, so that free software will gradually become able to speak many +languages. A few packages already provide translations for their +messages. + + If you found this `ABOUT-NLS' file inside a distribution, you may +assume that the distributed package does use GNU `gettext' internally, +itself available at your nearest GNU archive site. But you do _not_ +need to install GNU `gettext' prior to configuring, installing or using +this package with messages translated. + + Installers will find here some useful hints. These notes also +explain how users should proceed for getting the programs to use the +available translations. They tell how people wanting to contribute and +work on translations can contact the appropriate team. + + When reporting bugs in the `intl/' directory or bugs which may be +related to internationalization, you should tell about the version of +`gettext' which is used. The information can be found in the +`intl/VERSION' file, in internationalized packages. + +1.1 Quick configuration advice +============================== + +If you want to exploit the full power of internationalization, you +should configure it using + + ./configure --with-included-gettext + +to force usage of internationalizing routines provided within this +package, despite the existence of internationalizing capabilities in the +operating system where this package is being installed. So far, only +the `gettext' implementation in the GNU C library version 2 provides as +many features (such as locale alias, message inheritance, automatic +charset conversion or plural form handling) as the implementation here. +It is also not possible to offer this additional functionality on top +of a `catgets' implementation. Future versions of GNU `gettext' will +very likely convey even more functionality. So it might be a good idea +to change to GNU `gettext' as soon as possible. + + So you need _not_ provide this option if you are using GNU libc 2 or +you have installed a recent copy of the GNU gettext package with the +included `libintl'. + +1.2 INSTALL Matters +=================== + +Some packages are "localizable" when properly installed; the programs +they contain can be made to speak your own native language. Most such +packages use GNU `gettext'. Other packages have their own ways to +internationalization, predating GNU `gettext'. + + By default, this package will be installed to allow translation of +messages. It will automatically detect whether the system already +provides the GNU `gettext' functions. If not, the included GNU +`gettext' library will be used. This library is wholly contained +within this package, usually in the `intl/' subdirectory, so prior +installation of the GNU `gettext' package is _not_ required. +Installers may use special options at configuration time for changing +the default behaviour. The commands: + + ./configure --with-included-gettext + ./configure --disable-nls + +will, respectively, bypass any pre-existing `gettext' to use the +internationalizing routines provided within this package, or else, +_totally_ disable translation of messages. + + When you already have GNU `gettext' installed on your system and run +configure without an option for your new package, `configure' will +probably detect the previously built and installed `libintl.a' file and +will decide to use this. This might not be desirable. You should use +the more recent version of the GNU `gettext' library. I.e. if the file +`intl/VERSION' shows that the library which comes with this package is +more recent, you should use + + ./configure --with-included-gettext + +to prevent auto-detection. + + The configuration process will not test for the `catgets' function +and therefore it will not be used. The reason is that even an +emulation of `gettext' on top of `catgets' could not provide all the +extensions of the GNU `gettext' library. + + Internationalized packages usually have many `po/LL.po' files, where +LL gives an ISO 639 two-letter code identifying the language. Unless +translations have been forbidden at `configure' time by using the +`--disable-nls' switch, all available translations are installed +together with the package. However, the environment variable `LINGUAS' +may be set, prior to configuration, to limit the installed set. +`LINGUAS' should then contain a space separated list of two-letter +codes, stating which languages are allowed. + +1.3 Using This Package +====================== + +As a user, if your language has been installed for this package, you +only have to set the `LANG' environment variable to the appropriate +`LL_CC' combination. Here `LL' is an ISO 639 two-letter language code, +and `CC' is an ISO 3166 two-letter country code. For example, let's +suppose that you speak German and live in Germany. At the shell +prompt, merely execute `setenv LANG de_DE' (in `csh'), +`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). +This can be done from your `.login' or `.profile' file, once and for +all. + + You might think that the country code specification is redundant. +But in fact, some languages have dialects in different countries. For +example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The +country code serves to distinguish the dialects. + + The locale naming convention of `LL_CC', with `LL' denoting the +language and `CC' denoting the country, is the one use on systems based +on GNU libc. On other systems, some variations of this scheme are +used, such as `LL' or `LL_CC.ENCODING'. You can get the list of +locales supported by your system for your language by running the +command `locale -a | grep '^LL''. + + Not all programs have translations for all languages. By default, an +English message is shown in place of a nonexistent translation. If you +understand other languages, you can set up a priority list of languages. +This is done through a different environment variable, called +`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' +for the purpose of message handling, but you still need to have `LANG' +set to the primary language; this is required by other parts of the +system libraries. For example, some Swedish users who would rather +read translations in German than English for when Swedish is not +available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. + + Special advice for Norwegian users: The language code for Norwegian +bokma*l changed from `no' to `nb' recently (in 2003). During the +transition period, while some message catalogs for this language are +installed under `nb' and some older ones under `no', it's recommended +for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and +older translations are used. + + In the `LANGUAGE' environment variable, but not in the `LANG' +environment variable, `LL_CC' combinations can be abbreviated as `LL' +to denote the language's main dialect. For example, `de' is equivalent +to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' +(Portuguese as spoken in Portugal) in this context. + +1.4 Translating Teams +===================== + +For the Free Translation Project to be a success, we need interested +people who like their own language and write it well, and who are also +able to synergize with other translators speaking the same language. +Each translation team has its own mailing list. The up-to-date list of +teams can be found at the Free Translation Project's homepage, +`http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams" +area. + + If you'd like to volunteer to _work_ at translating messages, you +should become a member of the translating team for your own language. +The subscribing address is _not_ the same as the list itself, it has +`-request' appended. For example, speakers of Swedish can send a +message to `sv-request@li.org', having this message body: + + subscribe + + Keep in mind that team members are expected to participate +_actively_ in translations, or at solving translational difficulties, +rather than merely lurking around. If your team does not exist yet and +you want to start one, or if you are unsure about what to do or how to +get started, please write to `translation@iro.umontreal.ca' to reach the +coordinator for all translator teams. + + The English team is special. It works at improving and uniformizing +the terminology in use. Proven linguistic skills are praised more than +programming skills, here. + +1.5 Available Packages +====================== + +Languages are not equally supported in all packages. The following +matrix shows the current state of internationalization, as of October +2006. The matrix shows, in regard of each package, for which languages +PO files have been submitted to translation coordination, with a +translation percentage of at least 50%. + + Ready PO files af am ar az be bg bs ca cs cy da de el en en_GB eo + +----------------------------------------------------+ + GNUnet | [] | + a2ps | [] [] [] [] [] | + aegis | () | + ant-phone | () | + anubis | [] | + ap-utils | | + aspell | [] [] [] [] [] | + bash | [] [] [] | + batchelor | [] | + bfd | | + bibshelf | [] | + binutils | [] | + bison | [] [] | + bison-runtime | | + bluez-pin | [] [] [] [] [] | + cflow | [] | + clisp | [] [] | + console-tools | [] [] | + coreutils | [] [] [] | + cpio | | + cpplib | [] [] [] | + cryptonit | [] | + darkstat | [] () [] | + dialog | [] [] [] [] [] [] | + diffutils | [] [] [] [] [] [] | + doodle | [] | + e2fsprogs | [] [] | + enscript | [] [] [] [] | + error | [] [] [] [] | + fetchmail | [] [] () [] | + fileutils | [] [] | + findutils | [] [] [] | + flex | [] [] [] | + fslint | [] | + gas | | + gawk | [] [] [] | + gbiff | [] | + gcal | [] | + gcc | [] | + gettext-examples | [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] | + gettext-tools | [] [] | + gimp-print | [] [] [] [] | + gip | [] | + gliv | [] | + glunarclock | [] | + gmult | [] [] | + gnubiff | () | + gnucash | () () [] | + gnucash-glossary | [] () | + gnuedu | | + gnulib | [] [] [] [] [] [] | + gnunet-gtk | | + gnutls | | + gpe-aerial | [] [] | + gpe-beam | [] [] | + gpe-calendar | | + gpe-clock | [] [] | + gpe-conf | [] [] | + gpe-contacts | | + gpe-edit | [] | + gpe-filemanager | | + gpe-go | [] | + gpe-login | [] [] | + gpe-ownerinfo | [] [] | + gpe-package | | + gpe-sketchbook | [] [] | + gpe-su | [] [] | + gpe-taskmanager | [] [] | + gpe-timesheet | [] | + gpe-today | [] [] | + gpe-todo | | + gphoto2 | [] [] [] [] | + gprof | [] [] | + gpsdrive | () () | + gramadoir | [] [] | + grep | [] [] [] [] [] [] | + gretl | | + gsasl | | + gss | | + gst-plugins | [] [] [] [] | + gst-plugins-base | [] [] [] | + gst-plugins-good | [] [] [] [] [] [] [] | + gstreamer | [] [] [] [] [] [] [] | + gtick | () | + gtkam | [] [] [] | + gtkorphan | [] [] | + gtkspell | [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] | + id-utils | [] [] | + impost | | + indent | [] [] [] | + iso_3166 | [] [] | + iso_3166_2 | | + iso_4217 | [] | + iso_639 | [] [] | + jpilot | [] | + jtag | | + jwhois | | + kbd | [] [] [] [] | + keytouch | | + keytouch-editor | | + keytouch-keyboa... | | + latrine | () | + ld | [] | + leafpad | [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | [] | + libgpewidget | [] [] [] | + libgpg-error | [] | + libgphoto2 | [] [] | + libgphoto2_port | [] [] | + libgsasl | | + libiconv | [] [] | + libidn | [] [] | + lifelines | [] () | + lilypond | [] | + lingoteach | | + lynx | [] [] [] [] | + m4 | [] [] [] [] | + mailutils | [] | + make | [] [] | + man-db | [] () [] [] | + minicom | [] [] [] | + mysecretdiary | [] [] | + nano | [] [] [] | + nano_1_0 | [] () [] [] | + opcodes | [] | + parted | | + pilot-qof | [] | + psmisc | [] | + pwdutils | | + python | | + qof | | + radius | [] | + recode | [] [] [] [] [] [] | + rpm | [] [] | + screem | | + scrollkeeper | [] [] [] [] [] [] [] [] | + sed | [] [] [] | + sh-utils | [] [] | + shared-mime-info | [] [] [] [] | + sharutils | [] [] [] [] [] [] | + shishi | | + silky | | + skencil | [] () | + sketch | [] () | + solfege | | + soundtracker | [] [] | + sp | [] | + stardict | [] | + system-tools-ba... | [] [] [] [] [] [] [] [] [] | + tar | [] | + texinfo | [] [] [] | + textutils | [] [] [] | + tin | () () | + tp-robot | [] | + tuxpaint | [] [] [] [] [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] [] [] | + vorbis-tools | [] [] [] [] | + wastesedge | () | + wdiff | [] [] [] [] | + wget | [] [] | + xchat | [] [] [] [] [] [] | + xkeyboard-config | | + xpad | [] [] | + +----------------------------------------------------+ + af am ar az be bg bs ca cs cy da de el en en_GB eo + 10 0 1 2 9 22 1 42 41 2 60 95 16 1 17 16 + + es et eu fa fi fr ga gl gu he hi hr hu id is it + +--------------------------------------------------+ + GNUnet | | + a2ps | [] [] [] () | + aegis | | + ant-phone | [] | + anubis | [] | + ap-utils | [] [] | + aspell | [] [] [] | + bash | [] [] [] | + batchelor | [] [] | + bfd | [] | + bibshelf | [] [] [] | + binutils | [] [] [] | + bison | [] [] [] [] [] [] | + bison-runtime | [] [] [] [] [] | + bluez-pin | [] [] [] [] [] | + cflow | [] | + clisp | [] [] | + console-tools | | + coreutils | [] [] [] [] [] [] | + cpio | [] [] [] | + cpplib | [] [] | + cryptonit | [] | + darkstat | [] () [] [] [] | + dialog | [] [] [] [] [] [] [] [] | + diffutils | [] [] [] [] [] [] [] [] [] | + doodle | [] [] | + e2fsprogs | [] [] [] | + enscript | [] [] [] | + error | [] [] [] [] [] | + fetchmail | [] | + fileutils | [] [] [] [] [] [] | + findutils | [] [] [] [] | + flex | [] [] [] | + fslint | [] | + gas | [] [] | + gawk | [] [] [] [] | + gbiff | [] | + gcal | [] [] | + gcc | [] | + gettext-examples | [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] | + gettext-tools | [] [] [] | + gimp-print | [] [] | + gip | [] [] [] | + gliv | () | + glunarclock | [] [] [] | + gmult | [] [] [] | + gnubiff | () () | + gnucash | () () () | + gnucash-glossary | [] [] | + gnuedu | [] | + gnulib | [] [] [] [] [] [] [] [] | + gnunet-gtk | | + gnutls | | + gpe-aerial | [] [] | + gpe-beam | [] [] | + gpe-calendar | | + gpe-clock | [] [] [] [] | + gpe-conf | [] | + gpe-contacts | [] [] | + gpe-edit | [] [] [] [] | + gpe-filemanager | [] | + gpe-go | [] [] [] | + gpe-login | [] [] [] | + gpe-ownerinfo | [] [] [] [] [] | + gpe-package | [] | + gpe-sketchbook | [] [] | + gpe-su | [] [] [] [] | + gpe-taskmanager | [] [] [] | + gpe-timesheet | [] [] [] [] | + gpe-today | [] [] [] [] | + gpe-todo | [] | + gphoto2 | [] [] [] [] [] | + gprof | [] [] [] [] | + gpsdrive | () () [] () | + gramadoir | [] [] | + grep | [] [] [] [] [] [] [] [] [] [] [] [] | + gretl | [] [] [] | + gsasl | [] [] | + gss | [] | + gst-plugins | [] [] [] | + gst-plugins-base | [] [] | + gst-plugins-good | [] [] [] | + gstreamer | [] [] [] | + gtick | [] | + gtkam | [] [] [] [] | + gtkorphan | [] [] | + gtkspell | [] [] [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] [] [] [] [] [] [] [] [] | + id-utils | [] [] [] [] [] | + impost | [] [] | + indent | [] [] [] [] [] [] [] [] [] [] | + iso_3166 | [] [] [] | + iso_3166_2 | [] | + iso_4217 | [] [] [] [] | + iso_639 | [] [] [] [] [] | + jpilot | [] [] | + jtag | [] | + jwhois | [] [] [] [] [] | + kbd | [] [] | + keytouch | [] | + keytouch-editor | [] | + keytouch-keyboa... | [] | + latrine | [] [] [] | + ld | [] [] | + leafpad | [] [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | [] | + libgpewidget | [] [] [] [] [] | + libgpg-error | | + libgphoto2 | [] [] [] | + libgphoto2_port | [] [] | + libgsasl | [] [] | + libiconv | [] [] | + libidn | [] [] | + lifelines | () | + lilypond | [] | + lingoteach | [] [] [] | + lynx | [] [] [] | + m4 | [] [] [] [] | + mailutils | [] [] | + make | [] [] [] [] [] [] [] [] | + man-db | () | + minicom | [] [] [] [] | + mysecretdiary | [] [] [] | + nano | [] [] [] [] [] [] | + nano_1_0 | [] [] [] [] [] | + opcodes | [] [] [] [] | + parted | [] [] [] [] | + pilot-qof | | + psmisc | [] [] [] | + pwdutils | | + python | | + qof | [] | + radius | [] [] | + recode | [] [] [] [] [] [] [] [] | + rpm | [] [] | + screem | | + scrollkeeper | [] [] [] | + sed | [] [] [] [] [] | + sh-utils | [] [] [] [] [] [] [] | + shared-mime-info | [] [] [] [] [] [] | + sharutils | [] [] [] [] [] [] [] [] | + shishi | | + silky | [] | + skencil | [] [] | + sketch | [] [] | + solfege | [] | + soundtracker | [] [] [] | + sp | [] | + stardict | [] | + system-tools-ba... | [] [] [] [] [] [] [] [] | + tar | [] [] [] [] [] [] [] | + texinfo | [] [] | + textutils | [] [] [] [] [] | + tin | [] () | + tp-robot | [] [] [] [] | + tuxpaint | [] [] | + unicode-han-tra... | | + unicode-transla... | [] [] | + util-linux | [] [] [] [] [] [] [] | + vorbis-tools | [] [] | + wastesedge | () | + wdiff | [] [] [] [] [] [] [] [] | + wget | [] [] [] [] [] [] [] [] | + xchat | [] [] [] [] [] [] [] [] | + xkeyboard-config | [] [] [] [] | + xpad | [] [] [] | + +--------------------------------------------------+ + es et eu fa fi fr ga gl gu he hi hr hu id is it + 88 22 14 2 40 115 61 14 1 8 1 6 59 31 0 52 + + ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no + +-------------------------------------------------+ + GNUnet | | + a2ps | () [] [] () | + aegis | () | + ant-phone | [] | + anubis | [] [] [] | + ap-utils | [] | + aspell | [] [] | + bash | [] | + batchelor | [] [] | + bfd | | + bibshelf | [] | + binutils | | + bison | [] [] [] | + bison-runtime | [] [] [] | + bluez-pin | [] [] [] | + cflow | | + clisp | [] | + console-tools | | + coreutils | [] | + cpio | | + cpplib | [] | + cryptonit | [] | + darkstat | [] [] | + dialog | [] [] | + diffutils | [] [] [] | + doodle | | + e2fsprogs | [] | + enscript | [] | + error | [] | + fetchmail | [] [] | + fileutils | [] [] | + findutils | [] | + flex | [] [] | + fslint | [] [] | + gas | | + gawk | [] [] | + gbiff | [] | + gcal | | + gcc | | + gettext-examples | [] [] | + gettext-runtime | [] [] [] | + gettext-tools | [] [] | + gimp-print | [] [] | + gip | [] [] | + gliv | [] | + glunarclock | [] [] | + gmult | [] [] | + gnubiff | | + gnucash | () () | + gnucash-glossary | [] | + gnuedu | | + gnulib | [] [] [] [] | + gnunet-gtk | | + gnutls | | + gpe-aerial | [] | + gpe-beam | [] | + gpe-calendar | [] | + gpe-clock | [] [] [] | + gpe-conf | [] [] | + gpe-contacts | [] | + gpe-edit | [] [] [] | + gpe-filemanager | [] [] | + gpe-go | [] [] [] | + gpe-login | [] [] [] | + gpe-ownerinfo | [] [] | + gpe-package | [] [] | + gpe-sketchbook | [] [] | + gpe-su | [] [] [] | + gpe-taskmanager | [] [] [] [] | + gpe-timesheet | [] | + gpe-today | [] [] | + gpe-todo | [] | + gphoto2 | [] [] | + gprof | | + gpsdrive | () () () | + gramadoir | () | + grep | [] [] [] [] | + gretl | | + gsasl | [] | + gss | | + gst-plugins | [] | + gst-plugins-base | | + gst-plugins-good | [] | + gstreamer | [] | + gtick | | + gtkam | [] | + gtkorphan | [] | + gtkspell | [] [] | + gutenprint | | + hello | [] [] [] [] [] [] | + id-utils | [] | + impost | | + indent | [] [] | + iso_3166 | [] | + iso_3166_2 | [] | + iso_4217 | [] [] [] | + iso_639 | [] [] | + jpilot | () () () | + jtag | | + jwhois | [] | + kbd | [] | + keytouch | [] | + keytouch-editor | | + keytouch-keyboa... | | + latrine | [] | + ld | | + leafpad | [] [] | + libc | [] [] [] [] [] | + libexif | | + libextractor | | + libgpewidget | [] | + libgpg-error | | + libgphoto2 | [] | + libgphoto2_port | [] | + libgsasl | [] | + libiconv | | + libidn | [] [] | + lifelines | [] | + lilypond | | + lingoteach | [] | + lynx | [] [] | + m4 | [] [] | + mailutils | | + make | [] [] [] | + man-db | () | + minicom | [] | + mysecretdiary | [] | + nano | [] [] [] | + nano_1_0 | [] [] [] | + opcodes | [] | + parted | [] [] | + pilot-qof | | + psmisc | [] [] [] | + pwdutils | | + python | | + qof | | + radius | | + recode | [] | + rpm | [] [] | + screem | [] | + scrollkeeper | [] [] [] [] | + sed | [] [] | + sh-utils | [] [] | + shared-mime-info | [] [] [] [] [] | + sharutils | [] [] | + shishi | | + silky | [] | + skencil | | + sketch | | + solfege | | + soundtracker | | + sp | () | + stardict | [] [] | + system-tools-ba... | [] [] [] [] | + tar | [] [] [] | + texinfo | [] [] [] | + textutils | [] [] [] | + tin | | + tp-robot | [] | + tuxpaint | [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] | + vorbis-tools | [] | + wastesedge | [] | + wdiff | [] [] | + wget | [] [] | + xchat | [] [] [] [] | + xkeyboard-config | [] | + xpad | [] [] [] | + +-------------------------------------------------+ + ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no + 52 24 2 2 1 3 0 2 3 21 0 15 1 97 5 1 + + nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta + +------------------------------------------------------+ + GNUnet | | + a2ps | () [] [] [] [] [] [] | + aegis | () () | + ant-phone | [] [] | + anubis | [] [] [] | + ap-utils | () | + aspell | [] [] | + bash | [] [] [] | + batchelor | [] [] | + bfd | | + bibshelf | [] | + binutils | [] [] | + bison | [] [] [] [] [] | + bison-runtime | [] [] [] [] | + bluez-pin | [] [] [] [] [] [] [] [] [] | + cflow | [] | + clisp | [] | + console-tools | [] | + coreutils | [] [] [] [] | + cpio | [] [] [] | + cpplib | [] | + cryptonit | [] [] | + darkstat | [] [] [] [] [] [] | + dialog | [] [] [] [] [] [] [] [] [] | + diffutils | [] [] [] [] [] [] | + doodle | [] [] | + e2fsprogs | [] [] | + enscript | [] [] [] [] [] | + error | [] [] [] [] | + fetchmail | [] [] [] | + fileutils | [] [] [] [] [] | + findutils | [] [] [] [] [] [] | + flex | [] [] [] [] [] | + fslint | [] [] [] [] | + gas | | + gawk | [] [] [] [] | + gbiff | [] | + gcal | [] | + gcc | [] | + gettext-examples | [] [] [] [] [] [] [] [] | + gettext-runtime | [] [] [] [] [] [] [] [] | + gettext-tools | [] [] [] [] [] [] [] | + gimp-print | [] [] | + gip | [] [] [] [] | + gliv | [] [] [] [] | + glunarclock | [] [] [] [] [] [] | + gmult | [] [] [] [] | + gnubiff | () | + gnucash | () [] | + gnucash-glossary | [] [] [] | + gnuedu | | + gnulib | [] [] [] [] [] | + gnunet-gtk | [] | + gnutls | [] [] | + gpe-aerial | [] [] [] [] [] [] [] | + gpe-beam | [] [] [] [] [] [] [] | + gpe-calendar | [] | + gpe-clock | [] [] [] [] [] [] [] [] | + gpe-conf | [] [] [] [] [] [] [] | + gpe-contacts | [] [] [] [] [] | + gpe-edit | [] [] [] [] [] [] [] [] | + gpe-filemanager | [] [] | + gpe-go | [] [] [] [] [] [] | + gpe-login | [] [] [] [] [] [] [] [] | + gpe-ownerinfo | [] [] [] [] [] [] [] [] | + gpe-package | [] [] | + gpe-sketchbook | [] [] [] [] [] [] [] [] | + gpe-su | [] [] [] [] [] [] [] [] | + gpe-taskmanager | [] [] [] [] [] [] [] [] | + gpe-timesheet | [] [] [] [] [] [] [] [] | + gpe-today | [] [] [] [] [] [] [] [] | + gpe-todo | [] [] [] [] | + gphoto2 | [] [] [] [] [] | + gprof | [] [] [] | + gpsdrive | [] [] [] | + gramadoir | [] [] | + grep | [] [] [] [] [] [] [] [] | + gretl | [] | + gsasl | [] [] [] | + gss | [] [] [] | + gst-plugins | [] [] [] [] | + gst-plugins-base | [] | + gst-plugins-good | [] [] [] [] | + gstreamer | [] [] [] | + gtick | [] | + gtkam | [] [] [] [] | + gtkorphan | [] | + gtkspell | [] [] [] [] [] [] [] [] | + gutenprint | [] | + hello | [] [] [] [] [] [] [] [] | + id-utils | [] [] [] [] | + impost | [] | + indent | [] [] [] [] [] [] | + iso_3166 | [] [] [] [] [] [] | + iso_3166_2 | | + iso_4217 | [] [] [] [] | + iso_639 | [] [] [] [] | + jpilot | | + jtag | [] | + jwhois | [] [] [] [] | + kbd | [] [] [] | + keytouch | [] | + keytouch-editor | [] | + keytouch-keyboa... | [] | + latrine | [] [] | + ld | [] | + leafpad | [] [] [] [] [] [] | + libc | [] [] [] [] [] | + libexif | [] | + libextractor | [] [] | + libgpewidget | [] [] [] [] [] [] [] | + libgpg-error | [] [] | + libgphoto2 | [] | + libgphoto2_port | [] [] [] | + libgsasl | [] [] [] [] | + libiconv | [] [] | + libidn | [] [] () | + lifelines | [] [] | + lilypond | | + lingoteach | [] | + lynx | [] [] [] | + m4 | [] [] [] [] [] | + mailutils | [] [] [] [] | + make | [] [] [] [] | + man-db | [] [] | + minicom | [] [] [] [] [] | + mysecretdiary | [] [] [] [] | + nano | [] [] [] | + nano_1_0 | [] [] [] [] | + opcodes | [] [] | + parted | [] | + pilot-qof | [] | + psmisc | [] [] | + pwdutils | [] [] | + python | | + qof | [] [] | + radius | [] [] | + recode | [] [] [] [] [] [] [] | + rpm | [] [] [] [] | + screem | | + scrollkeeper | [] [] [] [] [] [] [] | + sed | [] [] [] [] [] [] [] [] [] | + sh-utils | [] [] [] | + shared-mime-info | [] [] [] [] [] | + sharutils | [] [] [] [] | + shishi | [] | + silky | [] | + skencil | [] [] [] | + sketch | [] [] [] | + solfege | [] | + soundtracker | [] [] | + sp | | + stardict | [] [] [] | + system-tools-ba... | [] [] [] [] [] [] [] [] [] | + tar | [] [] [] [] [] | + texinfo | [] [] [] [] | + textutils | [] [] [] | + tin | () | + tp-robot | [] | + tuxpaint | [] [] [] [] [] | + unicode-han-tra... | | + unicode-transla... | | + util-linux | [] [] [] [] | + vorbis-tools | [] [] | + wastesedge | | + wdiff | [] [] [] [] [] [] | + wget | [] [] [] [] | + xchat | [] [] [] [] [] [] [] | + xkeyboard-config | [] [] | + xpad | [] [] [] | + +------------------------------------------------------+ + nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta + 0 2 3 58 30 54 5 73 72 4 40 46 11 50 128 2 + + tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu + +---------------------------------------------------+ + GNUnet | [] | 2 + a2ps | [] [] [] | 19 + aegis | | 0 + ant-phone | [] [] | 6 + anubis | [] [] [] | 11 + ap-utils | () [] | 4 + aspell | [] [] [] | 15 + bash | [] | 11 + batchelor | [] [] | 9 + bfd | | 1 + bibshelf | [] | 7 + binutils | [] [] [] | 9 + bison | [] [] [] | 19 + bison-runtime | [] [] [] | 15 + bluez-pin | [] [] [] [] [] [] | 28 + cflow | [] [] | 5 + clisp | | 6 + console-tools | [] [] | 5 + coreutils | [] [] | 16 + cpio | [] [] [] | 9 + cpplib | [] [] [] [] | 11 + cryptonit | | 5 + darkstat | [] () () | 15 + dialog | [] [] [] [] [] | 30 + diffutils | [] [] [] [] | 28 + doodle | [] | 6 + e2fsprogs | [] [] | 10 + enscript | [] [] [] | 16 + error | [] [] [] [] | 18 + fetchmail | [] [] | 12 + fileutils | [] [] [] | 18 + findutils | [] [] [] | 17 + flex | [] [] | 15 + fslint | [] | 9 + gas | [] | 3 + gawk | [] [] | 15 + gbiff | [] | 5 + gcal | [] | 5 + gcc | [] [] [] | 6 + gettext-examples | [] [] [] [] [] [] | 27 + gettext-runtime | [] [] [] [] [] [] | 28 + gettext-tools | [] [] [] [] [] | 19 + gimp-print | [] [] | 12 + gip | [] [] | 12 + gliv | [] [] | 8 + glunarclock | [] [] [] | 15 + gmult | [] [] [] [] | 15 + gnubiff | [] | 1 + gnucash | () | 2 + gnucash-glossary | [] [] | 9 + gnuedu | [] | 2 + gnulib | [] [] [] [] [] | 28 + gnunet-gtk | | 1 + gnutls | | 2 + gpe-aerial | [] [] | 14 + gpe-beam | [] [] | 14 + gpe-calendar | [] | 3 + gpe-clock | [] [] [] [] | 21 + gpe-conf | [] [] | 14 + gpe-contacts | [] [] | 10 + gpe-edit | [] [] [] [] | 20 + gpe-filemanager | [] | 6 + gpe-go | [] [] | 15 + gpe-login | [] [] [] [] [] | 21 + gpe-ownerinfo | [] [] [] [] | 21 + gpe-package | [] | 6 + gpe-sketchbook | [] [] | 16 + gpe-su | [] [] [] | 20 + gpe-taskmanager | [] [] [] | 20 + gpe-timesheet | [] [] [] [] | 18 + gpe-today | [] [] [] [] [] | 21 + gpe-todo | [] | 7 + gphoto2 | [] [] [] [] | 20 + gprof | [] [] | 11 + gpsdrive | | 4 + gramadoir | [] | 7 + grep | [] [] [] [] | 34 + gretl | | 4 + gsasl | [] [] | 8 + gss | [] | 5 + gst-plugins | [] [] [] | 15 + gst-plugins-base | [] [] [] | 9 + gst-plugins-good | [] [] [] [] [] | 20 + gstreamer | [] [] [] | 17 + gtick | [] | 3 + gtkam | [] | 13 + gtkorphan | [] | 7 + gtkspell | [] [] [] [] [] [] | 26 + gutenprint | | 3 + hello | [] [] [] [] [] | 37 + id-utils | [] [] | 14 + impost | [] | 4 + indent | [] [] [] [] | 25 + iso_3166 | [] [] [] [] | 16 + iso_3166_2 | | 2 + iso_4217 | [] [] | 14 + iso_639 | [] | 14 + jpilot | [] [] [] [] | 7 + jtag | [] | 3 + jwhois | [] [] [] | 13 + kbd | [] [] | 12 + keytouch | [] | 4 + keytouch-editor | | 2 + keytouch-keyboa... | [] | 3 + latrine | [] [] | 8 + ld | [] [] [] [] | 8 + leafpad | [] [] [] [] | 23 + libc | [] [] [] | 23 + libexif | [] | 4 + libextractor | [] | 5 + libgpewidget | [] [] [] | 19 + libgpg-error | [] | 4 + libgphoto2 | [] | 8 + libgphoto2_port | [] [] [] | 11 + libgsasl | [] | 8 + libiconv | [] | 7 + libidn | [] [] | 10 + lifelines | | 4 + lilypond | | 2 + lingoteach | [] | 6 + lynx | [] [] [] | 15 + m4 | [] [] [] | 18 + mailutils | [] | 8 + make | [] [] [] | 20 + man-db | [] | 6 + minicom | [] | 14 + mysecretdiary | [] [] | 12 + nano | [] [] | 17 + nano_1_0 | [] [] [] | 18 + opcodes | [] [] | 10 + parted | [] [] [] | 10 + pilot-qof | [] | 3 + psmisc | [] | 10 + pwdutils | [] | 3 + python | | 0 + qof | [] | 4 + radius | [] | 6 + recode | [] [] [] | 25 + rpm | [] [] [] [] | 14 + screem | [] | 2 + scrollkeeper | [] [] [] [] | 26 + sed | [] [] [] | 22 + sh-utils | [] | 15 + shared-mime-info | [] [] [] [] | 24 + sharutils | [] [] [] | 23 + shishi | | 1 + silky | [] | 4 + skencil | [] | 7 + sketch | | 6 + solfege | | 2 + soundtracker | [] [] | 9 + sp | [] | 3 + stardict | [] [] [] [] | 11 + system-tools-ba... | [] [] [] [] [] [] [] | 37 + tar | [] [] [] [] | 20 + texinfo | [] [] [] | 15 + textutils | [] [] [] | 17 + tin | | 1 + tp-robot | [] [] [] | 10 + tuxpaint | [] [] [] | 16 + unicode-han-tra... | | 0 + unicode-transla... | | 2 + util-linux | [] [] [] | 20 + vorbis-tools | [] [] | 11 + wastesedge | | 1 + wdiff | [] [] | 22 + wget | [] [] [] | 19 + xchat | [] [] [] [] | 29 + xkeyboard-config | [] [] [] [] | 11 + xpad | [] [] [] | 14 + +---------------------------------------------------+ + 77 teams tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu + 170 domains 0 1 1 77 39 0 136 10 1 48 5 54 0 2028 + + Some counters in the preceding matrix are higher than the number of +visible blocks let us expect. This is because a few extra PO files are +used for implementing regional variants of languages, or language +dialects. + + For a PO file in the matrix above to be effective, the package to +which it applies should also have been internationalized and +distributed as such by its maintainer. There might be an observable +lag between the mere existence a PO file and its wide availability in a +distribution. + + If October 2006 seems to be old, you may fetch a more recent copy of +this `ABOUT-NLS' file on most GNU archive sites. The most up-to-date +matrix with full percentage details can be found at +`http://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'. + +1.6 Using `gettext' in new packages +=================================== + +If you are writing a freely available program and want to +internationalize it you are welcome to use GNU `gettext' in your +package. Of course you have to respect the GNU Library General Public +License which covers the use of the GNU `gettext' library. This means +in particular that even non-free programs can use `libintl' as a shared +library, whereas only free software can use `libintl' as a static +library or use modified versions of `libintl'. + + Once the sources are changed appropriately and the setup can handle +the use of `gettext' the only thing missing are the translations. The +Free Translation Project is also available for packages which are not +developed inside the GNU project. Therefore the information given above +applies also for every other Free Software Project. Contact +`translation@iro.umontreal.ca' to make the `.pot' files available to +the translation teams. + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..61de3fa --- /dev/null +++ b/AUTHORS @@ -0,0 +1,100 @@ +Program: GNUnet +Homepage: https://gnunet.org/ +Maintainer: Christian Grothoff +Bug reports: https://gnunet.org/bugs/ +Security related bug reports: security@gnunet.org +License: some GPLv2+, mostly GPLv3+ + +Primary developers (0.9.x series): +Bart Polot +Christian Grothoff +David Brodski +Heikki Lindholm +LRN +Matthias Wachs +Milan Bouchet-Valat +Nathan Evans +Nils Durner +Safey Allah Mohammed +Philipp Tölke , +Vitaly Minko + +Code contributions also came from: +Adam Warrington [ UPnP ] +Alex Harper [ OS X CPU load ] +Andrew McDonald [ SHA-512] +Antti Salonen +Blake Matheny +Clytie Siddall +David Kuehling +Enrico Scholz +Eric Haumant +Eric Noack +Felix von Leitner [ diet libc snprintf for win32 ] +Gabor Adam Toth +Gerd Knorr +Glenn McGrath +Hendrik Pagenhardt +Heikki Lindholm +Igor Wronsky +Ioana Patrascu + +Jacob Appelbaum +Jake Dust +James Blackwell +Jean-Luc Cooke [ SHA-512] +Jussi Eloranta +Jürgen Appel +Kevin Vandersloot [original code of gnome-system-monitor] +Krista Bennett Grothoff +Kyle McMartin [ SHA-512] +Larry Waldo +Ludovic Courtès +Marko Räihä +Michael John Wensley +Paul Ruth +Renaldo Ferreira +Risto Saarelma +Roman Zippel +Romain Lievin +sheda +Simo Viitanen +Tiberius Stef +Tomi Tukiainen +Tuomas Toivonen +Tzvetan Horozov +Uli Luckas +Vasil Dimov +Werner Koch [original code of libgcrypt] + +Translations (webpage, documentation, as far as known): +Chinese : Di Ma +Danish : Jens Palsberg +Deutsch : Christian Grothoff , + Nils Durner +French : Mathieu , + Eric Haumant + Milan +Japanese : Hiroshi Yamauchi +Polish : Adam Welc +Romaneste : Bogdan Carbunar +Kinyarwanda: Steven Michael Murphy +Vietnamese : Phan Vinh Thinh and Clytie Siddall +Swedish : Daniel Nylander +Spanish : Miguel Angel Arruga Vivas +Turkish : Nilgün Belma Bugüner + +Logos: +GNU in Net : Christian Muellner +GNU with Net : Christian Muellner +AFS Face : Alex Jones +new GNU in Net: Nicklas Larsson + +Maintainers: +FreeBSD : Kirill Ponomarew +Debian GNU/Linux: Daniel Baumann +OS X : Jussi Eloranta + + +If you have contributed and are not listed here, please +notify one of the maintainers in order to be added. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..d238cfa --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1655 @@ +2012-02-28 17:29 grothoff + + * [r20121] src/util/os_priority.c: LRN: Apparently cleanup is not + for W32 + +2012-02-28 17:28 grothoff + + * [r20120] po/de.po, po/es.po, po/sv.po, po/vi.po, po/zh_CN.po, + src/util/os_priority.c: LRN: W32 pipe name generation needs + random + +2012-02-28 10:54 grothoff + + * [r20112] po/de.po, po/es.po, po/sv.po, po/vi.po, po/zh_CN.po: + releasing GNUnet 0.9.2 + +2012-02-28 09:32 grothoff + + * [r20097] configure.ac, src/Makefile.am: add gns + +2012-02-28 09:08 schanzen + + * [r20093] src/gns/plugin_block_gns.c: -fix + +2012-02-27 20:00 wachs + + * [r20087] configure.ac: enabling libglpk detection + +2012-02-27 11:00 grothoff + + * [r20060] src/arm/arm_api.c, src/arm/do_start_process.c, + src/arm/gnunet-service-arm.c, + src/ats/test_ats_api_bandwidth_consumption.c, + src/ats/test_ats_api_scheduling.c, src/chat/test_chat.c, + src/chat/test_chat_private.c, src/core/test_core_api.c, + src/core/test_core_api_reliability.c, + src/core/test_core_api_send_to_self.c, + src/core/test_core_api_start_only.c, + src/core/test_core_defaults.conf, + src/core/test_core_quota_compliance.c, + src/datastore/perf_datastore_api.c, + src/datastore/test_datastore_api.c, + src/datastore/test_datastore_api_management.c, + src/datastore/test_defaults.conf, src/dht/test_dht_api.c, + src/fs/test_fs_defaults.conf, src/fs/test_fs_download.c, + src/fs/test_fs_download_indexed.c, + src/fs/test_fs_download_persistence.c, + src/fs/test_fs_list_indexed.c, src/fs/test_fs_namespace.c, + src/fs/test_fs_namespace_list_updateable.c, + src/fs/test_fs_publish.c, src/fs/test_fs_publish_persistence.c, + src/fs/test_fs_search.c, src/fs/test_fs_search_persistence.c, + src/fs/test_fs_start_stop.c, src/fs/test_fs_unindex.c, + src/fs/test_fs_unindex_persistence.c, + src/hostlist/test_gnunet_daemon_hostlist.c, + src/hostlist/test_gnunet_daemon_hostlist_learning.c, + src/hostlist/test_gnunet_daemon_hostlist_reconnect.c, + src/hostlist/test_hostlist_defaults.conf, + src/include/gnunet_disk_lib.h, src/include/gnunet_os_lib.h, + src/include/platform.h, src/mesh/test_mesh_api.c, + src/mesh/test_mesh_local_1.c, src/mesh/test_mesh_local_2.c, + src/namestore/test_namestore_api.c, src/nat/nat.c, + src/nat/nat_mini.c, src/nat/test_nat_test.c, + src/nse/test_nse_api.c, src/peerinfo/test_peerinfo_api.c, + src/statistics/test_statistics_api.c, + src/statistics/test_statistics_api_loop.c, + src/statistics/test_statistics_api_watch.c, + src/stream/test_stream_local.c, + src/stream/test_stream_local_halfclose.c, + src/testing/test_testing_defaults.conf, src/testing/testing.c, + src/testing/testing_group.c, + src/transport/gnunet-transport-certificate-creation.c, + src/transport/gnunet-transport-connect-running-peers.c, + src/transport/gnunet-transport.c, + src/transport/plugin_transport_http_server.c, + src/transport/plugin_transport_wlan.c, + src/transport/transport-testing.c, src/util/crypto_random.c, + src/util/disk.c, src/util/helper.c, src/util/os_priority.c, + src/util/scheduler.c, + src/util/test_common_logging_runtime_loglevels.c, + src/util/test_os_start_process.c, src/util/test_resolver_api.c, + src/util/test_strings.c, src/vpn/test_gnunet_vpn.c: enabling use + of pipes for signal communication also on UNIX to enable future + integration with Java services + +2012-02-27 10:54 wachs + + * [r20059] src/transport/test_transport_api.c: adding error + messages + +2012-02-25 19:08 grothoff + + * [r20026] doc/man/gnunet-directory.1, doc/man/gnunet-download.1, + doc/man/gnunet-nat-server.1, doc/man/gnunet-pseudonym.1, + doc/man/gnunet-publish.1, doc/man/gnunet-search.1, + doc/man/gnunet-vpn.1: Igor/CG: various minor updates to man pages + +2012-02-24 06:54 grothoff + + * [r19998] src/include/winproc.h, src/util/os_network.c: + bratao/LRN: Use-bigger-buffer-for-EnumNICs3_results + +2012-02-23 18:09 wachs + + * [r19993] src/transport/gnunet-service-transport_validation.c: not + an error: plugin can return NULL (e.g. for IPv6 address when does + not support IPv6) + +2012-02-23 18:08 wachs + + * [r19992] src/transport/plugin_transport_unix.c: improved + rescheduling + improved recv error handling + +2012-02-23 17:35 wachs + + * [r19983] src/transport/plugin_transport_udp.c, + src/transport/plugin_transport_udp.h: splitted ipv4 and ipv6 + socket select scheduling + removed looping for write select + improved ipv4/v6 en/disabling + session management + +2012-02-23 16:41 grothoff + + * [r19979] AUTHORS, src/include/gnunet_common.h, + src/include/gnunet_crypto_lib.h, src/include/gnunet_server_lib.h, + src/util/common_logging.c, src/util/crypto_hash.c, + src/util/server.c: TG: attached are the following patches for + GNUnet: + + - 1: added GNUNET_i2s_full - full variant of GNUNET_i2s + - 2: GNUNET_CRYPTO_hash_from_string2 with additional length + parameter, + useful to prevent an additional strlen call when the caller + already knows + the length + - 3: custom mst callbacks for the server, enables using the + server with a + custom parser + - 4: added GNUNET_SERVER_client_set_finish_pending_write - + enables changing the + server behavior to finish pending writes when closing the + connection + + Best regards, + Gabor Adam Toth + +2012-02-23 16:01 wachs + + * [r19975] src/transport/plugin_transport_unix.c: fix to the 100% + CPU load problem + +2012-02-23 15:34 wachs + + * [r19974] src/transport/gnunet-service-transport_neighbours.c: + fix: ats suggested address for unknown plugin + +2012-02-23 14:40 wachs + + * [r19968] src/ats/Makefile.am, + src/ats/gnunet-service-ats_addresses_mlp.c, + src/ats/gnunet-service-ats_addresses_mlp.h, + src/ats/test_ats_api.conf, src/ats/test_ats_mlp.c: averaging fast + changing quality values + +2012-02-23 10:28 wachs + + * [r19962] src/transport/plugin_transport_udp.c: fix for mantis bug + 0002154: + change order of calls: + - discard unsend messages + - call transmit send continuation + - call session_end + +2012-02-23 10:18 wachs + + * [r19961] src/transport/plugin_transport_udp.c: fix to use correct + queue + +2012-02-22 18:34 grothoff + + * [r19949] src/fs/fs_api.c, src/fs/fs_dirmetascan.c, + src/fs/fs_file_information.c, src/fs/fs_publish.c, + src/fs/fs_sharetree.c, src/fs/gnunet-helper-fs-publish.c, + src/fs/gnunet-publish.c: LRN: two directory patches change the + way "is_directory" is evaluated. + Now it must be GNUNET_YES for the execution flow to switch to a + branch + where something is considered to be a directory. + The reason for that is that some functions might return + GNUNET_SYSERR + when asked whether something is a directory or not. Checking this + value as "!= GNUNET_NO" will produce positive result, even though + it's + not a directory. + +2012-02-22 12:43 wachs + + * [r19932] src/transport/gnunet-service-transport_validation.c: fix + coverity 10138 + +2012-02-22 10:10 harsha + + * [r19915] src/stream/stream_api.c: added ack sending + +2012-02-21 19:08 grothoff + + * [r19906] src/util/os_priority.c: LRN: + Escape-trailing-slash-when-spawning-W32-process: + +2012-02-21 10:12 schanzen + + * [r19881] src/gns/gnunet-service-gns.c, + src/gns/namestore_stub_api.c: Better logging + modified ns stub + +2012-02-20 14:28 schanzen + + * [r19868] src/gns/Makefile.am, src/gns/gns_api.c, + src/gns/gnunet-service-gns.c, src/gns/namestore_stub_api.c, + src/include/gnunet_gns_service.h, + src/include/gnunet_namestore_service.h: namestore stub api added + fixes to namestore api + +2012-02-20 12:08 grothoff + + * [r19864] src/fs/gnunet-helper-fs-publish.c: LRN: + Do-partial-serialization-in-fs-publish-helper: + +2012-02-20 09:09 grothoff + + * [r19859] src/fs/fs_sharetree.c: LRN: + Iterate-over-a-copy-of-ksk-when-removing-items + +2012-02-20 09:09 grothoff + + * [r19858] src/fs/gnunet-service-fs_put.c: LRN: check for tc being + NULL + +2012-02-18 19:03 grothoff + + * [r19844] src/fs/Makefile.am, src/fs/fs_api.h, + src/fs/fs_list_indexed.c, src/fs/fs_namespace.c, + src/fs/fs_namespace_advertise.c, src/fs/fs_publish.c, + src/fs/fs_publish_ksk.c, src/fs/fs_tree.c, src/fs/gnunet-fs.c, + src/fs/gnunet-publish.c, src/include/gnunet_fs_service.h: make + all (?) asynchronously operating FS operations actually + cancel-able + +2012-02-18 15:16 grothoff + + * [r19837] src/fs/fs_namespace.c, src/include/gnunet_fs_service.h: + add GNUNET_FS_namespace_dup API call + +2012-02-18 13:50 grothoff + + * [r19836] src/util/disk.c: LRN: don't free memory on the stack + +2012-02-16 14:29 wachs + + * [r19820] src/transport/gnunet-service-transport_neighbours.c: fix + for fast reconnect: send ack after fast reconnect even when we + are already connected since other peer waits for it + +2012-02-16 14:28 wachs + + * [r19819] src/transport/test_transport_api_restart_1peer.c: fix + test for peer restart + +2012-02-16 12:58 grothoff + + * [r19817] src/fs/gnunet-helper-fs-publish.c: LRN: Use binary mode + on W32 (lol -CG) + +2012-02-15 13:39 schanzen + + * [r19812] src/gns/gns_api.c, src/gns/gnunet-gns-add.c, + src/gns/gnunet-gns-lookup.c, src/gns/gnunet-service-gns.c, + src/include/gnunet_gns_service.h: Added preliminary API and stubs + for GNS + +2012-02-15 09:49 wachs + + * [r19811] src/transport/gnunet-service-transport_neighbours.c: fix + for Assertion failed at gnunet-service-ats_addresses.c:587 + +2012-02-13 16:36 wachs + + * [r19795] src/include/gnunet_transport_plugin.h: changes in + includes + +2012-02-13 16:02 wachs + + * [r19791] src/transport/gnunet-service-transport_neighbours.c, + src/transport/gnunet-service-transport_validation.c, + src/transport/plugin_transport_http.c, + src/transport/plugin_transport_tcp.c, + src/transport/plugin_transport_template.c, + src/transport/plugin_transport_udp.c, + src/transport/plugin_transport_unix.c, + src/transport/plugin_transport_wlan.c: removing legacy send + functions from plugins and renaming new send function + +2012-02-13 15:38 wachs + + * [r19790] src/transport/gnunet-service-transport_validation.c, + src/transport/plugin_transport_http.h: new sending in validation + +2012-02-13 13:27 wachs + + * [r19777] src/transport/plugin_transport_tcp.c: fix access before + null check + +2012-02-13 12:22 wachs + + * [r19775] src/transport/gnunet-service-transport_neighbours.c: + removing old send code from neighbours + +2012-02-13 11:57 wachs + + * [r19771] src/transport/Makefile.am, + src/transport/gnunet-service-transport_neighbours.c, + src/transport/plugin_transport_udp.c, + src/transport/plugin_transport_udp.h, + src/transport/plugin_transport_udp_broadcasting.c, + src/transport/plugin_transport_udp_new.h, + src/transport/plugin_transport_udp_new_broadcasting.c: adding + rewritten udp plugin + +2012-02-13 10:58 wachs + + * [r19770] src/ats/gnunet-service-ats_math.c, + src/ats/gnunet-service-ats_math.h: removing backup ATS code + +2012-02-08 15:23 bartpolot + + * [r19733] src/mesh/gnunet-service-mesh.c, src/mesh/mesh_api.c, + src/mesh/test_mesh_small.c: Attemp to fix ctrl-c crashes - + disconnect from services before calling daemons_stop, since the + cfg is free'd in the latter. + +2012-02-06 09:34 grothoff + + * [r19707] doc/man/gnunet-transport.1, + src/transport/gnunet-transport.c: adding -m option to + gnunet-transport to enable monitor mode (see #1972) + +2012-02-01 17:37 bartpolot + + * [r19608] src/include/gnunet_common.h: Let the compiler not + include debug strings in binary when make is not configured with + verbose + +2012-02-01 17:08 wachs + + * [r19603] src/transport/Makefile.am, + src/transport/gnunet-service-transport_blacklist.c, + src/transport/test_transport_api_blacklisting.c, + src/transport/transport_api_blacklist.c: fixing and testing + blacklisting api and service + +2012-02-01 15:00 wachs + + * [r19598] src/transport/test_transport_api_blacklisting.c: + improved blacklisting test + +2012-02-01 14:59 wachs + + * [r19597] src/transport/transport_api_blacklist.c: fix 2 crashes + in blacklisting api + - client transmit handle was not sent to NULL after sending + - BlacklistMessage was not checked for NULL + +2012-02-01 13:26 wachs + + * [r19596] src/transport/transport_api_blacklist.c: fix segfault: + api never saved callback and callback_cls + +2012-02-01 09:04 wachs + + * [r19591] src/transport/gnunet-service-transport_blacklist.c: + added assertion (which is successfully failing ;-) ) + +2012-01-31 13:46 wachs + + * [r19571] src/transport/plugin_transport_wlan.c: session based + sending for wlan + +2012-01-31 13:12 wachs + + * [r19568] src/util/os_network.c: ifconfig parsing + Shum's patch + bugs fixed in patch: + - IPv4 loopback address was not included: added line 179 + - stack allocated strings were not zeroed out, so last value was + used if value was not included in current line + - IPv4 netmask was passed as broadcast address (patch line 81) + - IPv4 netmask was passed as IPv6 netmask, caused invalid address + conversion (patch line 113) + + +2012-01-31 13:04 wachs + + * [r19567] src/util/test_os_network.c: adding verbose message + +2012-01-31 08:25 wachs + + * [r19563] src/ats/ats_api_scheduling.c, src/hello/address.c, + src/include/gnunet_ats_service.h: fixing const api and add check + to address + +2012-01-31 08:19 wachs + + * [r19562] src/transport/test_transport_api.c: fix assertion + +2012-01-30 16:38 wachs + + * [r19543] src/transport/test_transport_api.c: variable message + size + +2012-01-27 15:51 wachs + + * [r19486] src/transport/plugin_transport_unix.c: implemented + sessions + +2012-01-27 14:30 wachs + + * [r19485] src/transport/plugin_transport_unix.c: removing retry + code + removing unused structs + removing UDP Address structs + fixed PrettyPrinter (printed UDP addresses???) + +2012-01-27 13:48 wachs + + * [r19484] src/transport/plugin_transport_unix.c: complete select + write implementation + +2012-01-27 13:21 wachs + + * [r19483] src/transport/test_transport_api.c: fix memory leaks + +2012-01-26 14:53 wachs + + * [r19440] src/transport/gnunet-service-transport_neighbours.c: + fixing mantis 2101 + +2012-01-26 14:09 wachs + + * [r19437] src/transport/gnunet-service-transport_neighbours.c, + src/transport/plugin_transport_http.c, + src/transport/plugin_transport_http_server.c: implemented session + based sending in transport service (coexisting with old code) + +2012-01-26 14:01 bartpolot + + * [r19436] src/mesh/gnunet-service-mesh.c: Workaround for #2104, + initialize local tid when local type destination connects after + tunnel connect request by origin + +2012-01-26 13:23 wachs + + * [r19435] src/ats/ats_api.c, + src/ats/gnunet-service-ats_addresses_mlp.c: cppcheck + +2012-01-25 14:22 wachs + + * [r19389] src/ats/gnunet-service-ats_scheduling.c: clang: mem + access if plugin_name_length == 0 + +2012-01-25 13:56 wachs + + * [r19387] src/transport/plugin_transport_tcp.c: coverity 10054 + +2012-01-25 13:55 wachs + + * [r19386] src/transport/plugin_transport_http_client.c: coverity + 10048 + +2012-01-24 20:28 grothoff + + * [r19359] src/vpn: ign + +2012-01-24 01:32 bartpolot + + * [r19334] src/mesh/gnunet-service-mesh.c: Changed incoming tunnel + notification to delay until relvant traffic is received from + remote peer. Allowed several remote clients for each tunnel. + +2012-01-23 15:45 wachs + + * [r19331] src/ats/gnunet-service-ats_addresses.c: fixing mantis + 2098: + ats did not lookup addresses correctly + ats overwrote existing session when updating addresses + +2012-01-23 15:43 wachs + + * [r19330] src/transport/gnunet-service-transport_neighbours.c: + fixing: mantis 0002098: transport did not propagate session to + ats + +2012-01-23 14:54 grothoff + + * [r19329] src/include/gnunet_common.h: use noreturn macro for + GNUNET_abort to help gcc and others + +2012-01-23 09:14 grothoff + + * [r19322] src/util/win.cc: It-might-be-NULL + +2012-01-20 15:41 bartpolot + + * [r19283] src/include/gnunet_mesh_service.h: Reflected changes in + r19282. + +2012-01-20 15:40 bartpolot + + * [r19282] src/mesh/mesh_api.c: Don't call cleaner on tunnels + explicity destroyed. Updated and improved documentation. + +2012-01-20 12:49 bartpolot + + * [r19280] src/mesh/gnunet-service-mesh.c: Fixed bug with remote + tunnel traffic reception + +2012-01-20 12:48 bartpolot + + * [r19279] src/mesh/mesh_api.c: Added more debug info + +2012-01-19 23:17 bartpolot + + * [r19274] src/mesh/gnunet-service-mesh.c: Added TTL and MID + initialization to tunnel refresh packets. + +2012-01-19 23:00 bartpolot + + * [r19273] src/mesh/gnunet-service-mesh.c: Fixed #2088, don't call + receive_done on traffic not generated by client. Improved debug + output. + +2012-01-19 22:39 bartpolot + + * [r19272] src/mesh/gnunet-service-mesh.c: Fixed #2087, wrong local + tunnel number sent when multiple clients are subscribed to one + type message on same peer and one clientis owner of the tunnel + and the other is target + +2012-01-19 22:13 bartpolot + + * [r19271] src/mesh/mesh_api.c: Fixed a memory leak on disconnect, + double peer_rc decrease on tunnel destroy, adjusted backoff, + completed doxygen + +2012-01-19 15:20 bartpolot + + * [r19260] src/mesh/gnunet-service-mesh.c: Fixed client disconnect + bug, delimited debug messages. + +2012-01-19 14:33 bartpolot + + * [r19258] src/mesh/mesh_api.c: Fixed a peer_rc bug. + +2012-01-19 11:06 bartpolot + + * [r19253] src/mesh/gnunet-service-mesh.c: Fixed an assert error + when a client disconnects with open tunnels and without doing + MESH_disconnect + +2012-01-19 10:58 bartpolot + + * [r19252] src/mesh/mesh_api.c: Improved debug message + +2012-01-18 19:28 grothoff + + * [r19248] src/include/gnunet_testing_lib.h, + src/testing/Makefile.am, src/testing/helper.c: implementing + GNUNET_TESTING_get_peer_identity (addressing #2083) + +2012-01-18 15:10 bartpolot + + * [r19244] src/mesh/gnunet-service-mesh.c: Fixed client shutdown + case, various minor fixes + +2012-01-18 12:47 bartpolot + + * [r19233] src/mesh/gnunet-service-mesh.c: Implemented workaround + for #2071 + +2012-01-18 11:27 bartpolot + + * [r19228] src/mesh/gnunet-service-mesh.c: Allowed client to send + again + +2012-01-18 11:17 bartpolot + + * [r19227] src/mesh/gnunet-service-mesh.c: Fixed a bug when a + multicast packet is delivered exclusively to local clients + +2012-01-17 19:45 bartpolot + + * [r19217] src/mesh/mesh_api.c: Added debug info for #2071 + +2012-01-17 17:29 bartpolot + + * [r19208] src/mesh/gnunet-service-mesh.c: Fixed #2070 and + simplified data transmission unicast/multicast handling + +2012-01-17 16:17 bartpolot + + * [r19206] src/mesh/gnunet-service-mesh.c: Temporal workaround for + #2070 + +2012-01-17 16:13 bartpolot + + * [r19204] src/mesh/gnunet-service-mesh.c: Temporl workaround for + #2070 + +2012-01-17 15:36 bartpolot + + * [r19196] src/mesh/mesh_api.c: Fixed queue bug + +2012-01-16 21:11 grothoff + + * [r19181] src/pt/gnunet-daemon-pt.c: implemented new protocol + translation daemon (#2063) + +2012-01-16 17:17 harsha + + * [r19176] src/stream/test_stream_local.c, + src/stream/test_stream_local_halfclose.c: refined test cases + +2012-01-15 23:40 grothoff + + * [r19169] doc/man/Makefile.am, doc/man/gnunet-download-manager.1, + src/fs/Makefile.am, src/fs/gnunet-download-manager.scm: adding + Ludo's gnunet-download-manager.scm back to SVN HEAD + +2012-01-14 23:18 grothoff + + * [r19146] src/arm/gnunet-service-arm.c, src/fs/fs_dirmetascan.c, + src/include/gnunet_disk_lib.h, src/nat/nat.c, src/nat/nat_mini.c, + src/testing/testing.c, src/transport/plugin_transport_wlan.c, + src/util/disk.c, src/util/helper.c, src/util/os_priority.c, + src/util/scheduler.c, + src/util/test_common_logging_runtime_loglevels.c, + src/util/test_os_start_process.c, src/util/test_scheduler.c: LRN: + enable more fine-grained control over blocking/non-blocking pipe + operation + +2012-01-14 20:58 grothoff + + * [r19141] src/exit/exit.conf, src/exit/gnunet-daemon-exit.c, + src/exit/gnunet-helper-exit.c: changing exit helper code to + automatically do the network configuration for an exit node (by + running sysctl/iptables commands as necessary) + +2012-01-14 15:24 grothoff + + * [r19135] src/fs/Makefile.am, src/include/gnunet_fs_service.h: + LRN: new threaded directory metadata scanner + +2012-01-14 15:20 grothoff + + * [r19134] src/fs/fs_uri.c: LRN: skip short keywords when + generating keywords automatically from metadata + +2012-01-14 15:20 grothoff + + * [r19133] src/include/gnunet_disk_lib.h, src/util/disk.c: LRN: new + pipe creation function GNUNET_DISK_pipe_from_fd to wrap existing + file descriptor pair + +2012-01-14 15:17 grothoff + + * [r19131] src/include/gnunet_strings_lib.h, src/util/strings.c: + LRN: add function GNUNET_STRINGS_get_short_name to get basename + +2012-01-13 22:14 harsha + + * [r19130] src/stream/test_stream_local.c: added half-closed + shutdown test + +2012-01-13 22:10 grothoff + + * [r19129] configure.ac, src/dht/dht.conf.in, src/dns/Makefile.am, + src/dns/dns.conf.in, src/dv/dv.conf.in, + src/transport/transport.conf.in, src/util/service.c, + src/vpn/vpn.conf.in: improving code and build system to be in + line with gnunet access control model for services as described + at https://gnunet.org/gnunet-access-control-model + +2012-01-13 21:33 harsha + + * [r19128] src/stream/test_stream_local.c: added shutdown call in + testcase + +2012-01-13 21:33 harsha + + * [r19127] src/include/gnunet_stream_lib.h: removed ambigious + description + +2012-01-13 18:10 harsha + + * [r19126] src/stream/stream_protocol.h, + src/stream/test_stream_local.c, + src/stream/test_stream_local.conf: test case for stream API + +2012-01-13 17:41 harsha + + * [r19125] src/include/gnunet_stream_lib.h: generic type for read + data + +2012-01-13 17:04 grothoff + + * [r19123] configure.ac, src/arm/Makefile.am, src/arm/arm.conf, + src/arm/arm.conf.in, src/ats/Makefile.am, src/ats/ats.conf, + src/ats/ats.conf.in, src/chat/Makefile.am, src/chat/chat.conf, + src/chat/chat.conf.in, src/core/Makefile.am, src/core/core.conf, + src/core/core.conf.in, src/datastore/Makefile.am, + src/datastore/datastore.conf, src/datastore/datastore.conf.in, + src/dht/Makefile.am, src/dht/dht.conf, src/dht/dht.conf.in, + src/dns/Makefile.am, src/dns/dns.conf, src/dns/dns.conf.in, + src/dv/Makefile.am, src/dv/dv.conf, src/dv/dv.conf.in, + src/exit/exit.conf, src/fs/Makefile.am, src/fs/fs.conf, + src/fs/fs.conf.in, src/mesh/Makefile.am, src/mesh/mesh.conf, + src/mesh/mesh.conf.in, src/nse/Makefile.am, src/nse/nse.conf, + src/nse/nse.conf.in, src/peerinfo/Makefile.am, + src/peerinfo/peerinfo.conf, src/peerinfo/peerinfo.conf.in, + src/statistics/Makefile.am, src/statistics/statistics.conf, + src/statistics/statistics.conf.in, src/transport/Makefile.am, + src/transport/transport.conf, src/transport/transport.conf.in, + src/util/Makefile.am, src/util/client.c, src/util/resolver.conf, + src/util/resolver.conf.in, src/vpn/Makefile.am, src/vpn/vpn.conf, + src/vpn/vpn.conf.in: change default configurations on systems + with UNIX domain sockets to NOT specify any port for TCP-based + IPC (and interpret that as no TCP-based IPC desired), as we can + and want to use UNIX domain sockets in this case by default + +2012-01-12 09:26 wachs + + * [r19101] src/vpn/gnunet-service-vpn.c: fix compile errors + +2012-01-11 21:11 grothoff + + * [r19093] src/fs/fs_api.c, src/fs/fs_api.h, src/fs/fs_publish.c: + fixing bug to ensure that we properly descend into deep + directories for the various publish start/stop/suspend/resume + event callbacks + +2012-01-11 13:18 wachs + + * [r19085] src/ats/ats.conf, + src/ats/gnunet-service-ats_addresses.c: mlp configuration + +2012-01-11 12:41 wachs + + * [r19084] src/ats/Makefile.am: adding glpk to the makefile + +2012-01-10 23:18 harsha + + * [r19082] src/stream/stream_protocol.h: stream P2P protocol + message specification + +2012-01-10 16:06 wachs + + * [r19078] src/vpn/vpn.conf: fix: wrong binary and duplicate unix + path + +2012-01-10 15:54 wachs + + * [r19077] src/integration-tests/confs/c_bootstrap_server.conf, + src/integration-tests/confs/c_nat_client.conf, + src/integration-tests/confs/c_no_nat_client.conf: added section + to solve vpn conflicts + +2012-01-09 16:38 grothoff + + * [r19069] src/include/gnunet_disk_lib.h, src/util/disk.c: LRN: + make disk iterator start return GNUNET_SYSERR if run on empty + directory + +2012-01-05 21:04 grothoff + + * [r19023] src/exit/Makefile.am: fix + +2012-01-05 20:58 bartpolot + + * [r19021] src/dht, src/dht/Makefile.am, src/dht/dht_api.c, + src/dht/test_dht_monitor.c: Added testcase for DHT monitoring. + +2012-01-05 20:18 grothoff + + * [r19017] src/include/gnunet_crypto_lib.h, src/util/crypto_crc.c: + fix crc16 prototypes + +2012-01-04 20:00 bartpolot + + * [r18989] src/dht/dht.h, src/dht/dht_api.c, + src/dht/gnunet-service-dht_clients.c, + src/dht/gnunet-service-dht_clients.h, + src/dht/gnunet-service-dht_neighbours.c, + src/include/gnunet_dht_service.h, src/include/gnunet_protocols.h: + New DHT-monitor functionality + +2012-01-04 15:48 grothoff + + * [r18988] doc/man/Makefile.am, doc/man/gnunet-monkey.1: move + monkey man page to monkey + +2012-01-04 14:20 grothoff + + * [r18982] src/dns/dnsparser.c, src/dns/gnunet-dns-monitor.c, + src/dns/gnunet-service-dns_new.c: adding missing file + +2012-01-02 12:23 grothoff + + * [r18937] src/dns/Makefile.am, src/dns/gnunet-helper-dns.c: DNS + helper for DNS redesign + +2012-01-02 10:22 grothoff + + * [r18929] src/include/gnunet_crypto_lib.h, src/util/crypto_crc.c: + adding crc16 to gnunet_crypto_lib.h + +2012-01-02 09:26 grothoff + + * [r18924] src/include/Makefile.am, + src/include/gnunet_helper_lib.h, src/util/Makefile.am, + src/util/helper.c: adding new GNUNET_HELPER_ API for + communication with (SUID) helper binaries via stdin/stdout using + standard GNUNET messages + +2012-01-02 08:24 grothoff + + * [r18923] src/include/gnunet_os_lib.h, src/util/os_priority.c: + adding GNUNET_OS_start_process_vap function + +2012-01-02 03:51 grothoff + + * [r18912] src/dns/gnunet-helper-hijack-dns.c: dns hijacker code + review + +2012-01-01 23:39 grothoff + + * [r18908] src/dns/Makefile.am, src/dns/dns_api.c, + src/include/gnunet_dns_service.h, src/vpn/Makefile.am, + src/vpn/gnunet-daemon-vpn-dns.c, src/vpn/gnunet-daemon-vpn-dns.h, + src/vpn/gnunet-daemon-vpn-helper.c, src/vpn/gnunet-daemon-vpn.c, + src/vpn/gnunet-daemon-vpn.h: first quick hack to extract an + initial DNS service API + +2012-01-01 21:12 grothoff + + * [r18889] src/arm/gnunet-service-arm.c, src/chat/gnunet-chat.c, + src/datastore/gnunet-service-datastore.c, src/fs/fs_api.c, + src/fs/gnunet-service-fs_cp.c, + src/include/gnunet_scheduler_lib.h, src/nse/gnunet-service-nse.c, + src/peerinfo/gnunet-service-peerinfo.c, src/util/crypto_hash.c, + src/util/scheduler.c: changing scheduler priorities to revert to + DEFAULT instead of inheriting parent-task priority unless + something else is explicitly specified + +2011-12-30 22:25 grothoff + + * [r18853] src/fs/Makefile.am, src/fs/fs_uri.c: LRN: normalize + keywords (decapitalize, split) using libunistring - #2052 + +2011-12-26 19:31 grothoff + + * [r18828] src/fs/fs_misc.c, src/include/gnunet_fs_service.h, + src/util/os_network.c: adding GNUNET_FS_time_to_year function to + FS API + +2011-12-25 20:45 grothoff + + * [r18815] src/fs/gnunet-service-fs_cp.h, + src/fs/gnunet-service-fs_pr.c: fixing migration stop delay + calculation, largely by first calculating datastore load + correctly and then by better distinguishing between datastore + full, datastore timeout and success and finally by adding + per-peer tracking of the current block interval to adjust to + repeated undesireable behavior. See #2029. + +2011-12-23 20:13 wachs + + * [r18794] src/ats/Makefile.am: missing file + +2011-12-22 14:15 wachs + + * [r18756] src/transport/gnunet-transport.c: include plugin in + gnunet-transport output + +2011-12-21 18:03 bartpolot + + * [r18754] src/nse/gnunet-nse-profiler.c, + src/nse/gnunet-service-nse.c: Added statistic reading to NSE, + fixed some minor bugs + +2011-12-21 16:39 wachs + + * [r18751] src/vpn/gnunet-helper-vpn.c: fix compile error + +2011-12-21 14:33 wachs + + * [r18742] src/transport/plugin_transport_http.c: fixed assertion + in gnunet-service resolver + improved address printing for IPv6 addresses, especially if + reverse lookup is not successful + +2011-12-21 12:39 wachs + + * [r18735] src/transport/plugin_transport_udp.c: fixed assertion: + wrong return value + +2011-12-21 09:56 grothoff + + * [r18732] contrib/report.sh: add version reporting for MHD to + report.sh + +2011-12-21 09:40 grothoff + + * [r18730] src/arm/arm.h, + src/ats-test/test_transport_ats_multiple_peers.c, src/ats/ats.h, + src/chat/chat.h, src/core/core.h, + src/core/gnunet-service-core_kx.c, src/datastore/datastore.h, + src/dht/dht.h, src/dht/gnunet-service-dht_neighbours.c, + src/dv/dv.h, src/dv/test_transport_api_dv.c, + src/fragmentation/fragmentation.h, src/fs/fs.h, + src/fs/gnunet-service-fs.h, src/hello/hello.c, + src/hostlist/gnunet-daemon-hostlist.c, src/include/block_dns.h, + src/include/block_fs.h, src/include/gnunet_ats_service.h, + src/include/gnunet_bandwidth_lib.h, src/include/gnunet_common.h, + src/include/gnunet_crypto_lib.h, src/include/gnunet_time_lib.h, + src/mesh/mesh.h, src/mesh/mesh_protocol.h, src/nat/nat.h, + src/nse/gnunet-service-nse.c, src/nse/nse.h, + src/peerinfo/peerinfo.h, src/statistics/statistics.h, + src/testing/test_testing_large_topology.c, + src/testing/test_testing_topology.c, + src/testing/test_testing_topology_blacklist.c, + src/testing/test_testing_topology_churn.c, + src/transport/gnunet-helper-transport-wlan.c, + src/transport/gnunet-service-transport_neighbours.c, + src/transport/gnunet-service-transport_validation.c, + src/transport/gnunet-transport-wlan-sender.c, + src/transport/plugin_transport_http.h, + src/transport/plugin_transport_smtp.c, + src/transport/plugin_transport_tcp.c, + src/transport/plugin_transport_udp.c, + src/transport/plugin_transport_udp_new.c, + src/transport/plugin_transport_unix.c, + src/transport/plugin_transport_wlan.c, + src/transport/plugin_transport_wlan.h, + src/transport/test_quota_compliance.c, + src/transport/test_transport_api_reliability.c, + src/transport/test_transport_api_unreliability.c, + src/transport/test_transport_api_unreliability_constant.c, + src/transport/transport.h, src/util/crypto_ksk.c, + src/util/crypto_rsa.c, src/util/resolver.h, + src/vpn/gnunet-service-dns-p.h, src/vpn/gnunet-service-dns.c, + src/vpn/gnunet-vpn-packet.h: fixing 2012: network structure + alignment now forced to be correct even on W32 using #pragma pack + from gcc 4.x + +2011-12-20 16:41 wachs + + * [r18726] src/transport/gnunet-service-transport_neighbours.c: fix + for mantis 1959 + compare addresses and only mark address when addresses match + +2011-12-20 16:01 wachs + + * [r18723] src/transport/gnunet-service-transport_clients.c: fix + for mantis #2008 + +2011-12-20 15:48 wachs + + * [r18722] src/transport/transport_api.c: Improvement in reconnect: + first disconnect, then destroy neighbours + +2011-12-20 12:58 wachs + + * [r18719] src/include/gnunet_transport_plugin.h, + src/transport/plugin_transport_tcp.c: first changes for new + plugin api + +2011-12-20 09:20 grothoff + + * [r18714] AUTHORS, configure.ac, src/dht/test_dht_2dtorus.conf: + Adding optional compiler and linker hardening options as per + suggestion from Jacob + +2011-12-19 23:24 grothoff + + * [r18710] src/dht/test_dht_2dtorus.conf: do not run with full on + NSE during testing + +2011-12-19 21:26 grothoff + + * [r18704] src/include/gnunet_statistics_service.h, + src/statistics/statistics_api.c: implement watch_cancel function + +2011-12-19 17:15 grothoff + + * [r18698] src/fs/fs_api.c, src/fs/fs_api.h, src/fs/fs_search.c: + improving results seen communication to consider which exact + keywords a particular result has been seen for so far + +2011-12-19 17:10 wachs + + * [r18697] src/integration-tests/Makefile.am, + src/integration-tests/gnunet_testing.py.in, + src/integration-tests/test_integration_disconnect.py.in: a new + nat disconnect test + +2011-12-19 16:31 grothoff + + * [r18696] src/transport/gnunet-service-transport_neighbours.c: + fixing #2014 + +2011-12-19 15:59 grothoff + + * [r18693] src/fs/gnunet-service-fs_pr.c: limit lifetime of + migrated content to at most 1 year + +2011-12-19 15:52 grothoff + + * [r18692] src/fs/gnunet-service-fs_cp.c, + src/fs/gnunet-service-fs_cp.h, src/fs/gnunet-service-fs_pr.c: + block data migration based on lowest discarded expiration of + content in the datastore to avoid wasting bandwidth on migrating + content that is just instantly discarded again anyway + +2011-12-19 15:02 wachs + + * [r18691] src/integration-tests/test_integration_clique.py.in, + src/integration-tests/test_integration_disconnect.py.in, + src/integration-tests/test_integration_restart.py.in: fixing some + timeouts + +2011-12-19 14:26 wachs + + * [r18690] src/ats/ats_api_scheduling.c: + +2011-12-19 14:25 wachs + + * [r18689] src/ats/ats_api_scheduling.c, + src/transport/gnunet-service-transport_neighbours.c: fixes for + mantis #1988 + and cleanup + +2011-12-19 14:10 grothoff + + * [r18688] src/fs/gnunet-service-fs_cp.c, + src/fs/gnunet-service-fs_pr.c, src/fs/gnunet-service-fs_pr.h: + actually limit FS memory consumption by limiting how many + requests we track from other peers (respective GSF-option had not + been set; new code also inverts the meaning of the bit, so it + does not have to be set for peers but rather is now set for + clients to excempt them from the limitation) + +2011-12-19 13:54 grothoff + + * [r18686] src/datastore/datastore.h, + src/datastore/datastore_api.c, + src/datastore/perf_datastore_api.c, + src/datastore/test_datastore_api.c, + src/datastore/test_datastore_api_management.c, + src/fs/fs_namespace.c, src/fs/fs_publish.c, src/fs/fs_unindex.c, + src/fs/gnunet-service-fs_indexing.c, + src/fs/gnunet-service-fs_pr.c, + src/include/gnunet_datastore_service.h: adding min_expiration + argument to GNUNET_DATASTORE_ContinuationWithStatus callback to + communicate which content has a chance of being stored in the + medium term + +2011-12-19 13:08 wachs + + * [r18684] src/hostlist/test_gnunet_daemon_hostlist.c: added LRN's + patch from mantis bug 1998 + +2011-12-19 12:12 wachs + + * [r18682] src/include/gnunet_ats_service.h, + src/transport/plugin_transport_wlan.c: additional network type + for WLAN + +2011-12-19 12:08 wachs + + * [r18681] src/ats/ats_api_scheduling.c: checked mantis #0002016 + and added additional assertion + +2011-12-19 10:59 grothoff + + * [r18680] src/nat/gnunet-helper-nat-server.c: Jacob Appelbaum + reviewed gnunet-helper-nat-server and affirms that the code + 'seems fine' + +2011-12-19 09:32 grothoff + + * [r18678] src/datastore/gnunet-service-datastore.c: fixing + calculation of Bloom filter size that was too large by 1024x + because it was not adjusted when the unit for the quota was + changed from kb to bytes + +2011-12-17 18:32 grothoff + + * [r18662] contrib/apparmor, + contrib/apparmor/usr.bin.gnunet-helper-nat-server: adding + apparmor profile for gnunet-helper-nat-server from Jacob + +2011-12-16 22:42 grothoff + + * [r18653] src/datastore/plugin_datastore_sqlite.c: implementing + get_keys API for sqlite datastore plugin (#2013) + +2011-12-16 22:19 grothoff + + * [r18652] src/statistics/statistics_api.c, + src/statistics/test_statistics_api_watch.c: code cleanup, also + trying to fix #2011 + +2011-12-16 22:13 grothoff + + * [r18650] src/nat/gnunet-helper-nat-client.c: really minimizing + gnunet-helper-nat-client code running with root rights + +2011-12-16 22:04 grothoff + + * [r18649] src/nat/gnunet-helper-nat-server-windows.c, + src/nat/gnunet-helper-nat-server.c: really minimizing code + running with root rights + +2011-12-16 21:19 grothoff + + * [r18647] src/util/container_bloomfilter.c: cleaning up + bloomfilter code and disk file size tests + +2011-12-16 17:15 wachs + + * [r18635] src/integration-tests/confs/c_nat_client.conf, + src/integration-tests/gnunet_testing.py.in, + src/integration-tests/test_integration_clique_nat.py.in: + +2011-12-16 16:27 wachs + + * [r18634] src/integration-tests/gnunet_testing.py.in, + src/integration-tests/test_integration_clique_nat.py.in: + improvements and fixes + +2011-12-16 16:12 wachs + + * [r18633] src/integration-tests/confs/c_nat_client.conf, + src/integration-tests/gnunet_testing.py.in, + src/integration-tests/test_integration_clique_nat.py.in: fix + +2011-12-16 14:49 wachs + + * [r18632] src/integration-tests/Makefile.am, + src/integration-tests/confs/c_nat_client.conf, + src/integration-tests/test_integration_clique_nat.py.in: adding + nat clique test + +2011-12-16 14:03 wachs + + * [r18631] src/integration-tests/gnunet_testing.py.in: improved + statisc output + +2011-12-16 13:43 wachs + + * [r18630] src/integration-tests/test_integration_restart.py.in: + new test: connect after peer restart? + +2011-12-16 13:43 wachs + + * [r18629] src/integration-tests/Makefile.am, + src/integration-tests/test_integration_bootstrap_and_connect.py.in, + src/integration-tests/test_integration_clique.py.in, + src/integration-tests/test_integration_disconnect.py.in: + +2011-12-16 12:25 wachs + + * [r18627] src/integration-tests/gnunet_testing.py.in, + src/integration-tests/test_integration_bootstrap_and_connect.py.in, + src/integration-tests/test_integration_clique.py.in, + src/integration-tests/test_integration_disconnect.py.in: added + support for interupting a test + +2011-12-16 11:19 grothoff + + * [r18625] src/nat/gnunet-helper-nat-client.c, + src/nat/gnunet-helper-nat-server.c: additional stylistic changes + to gnunet-helper-nat-client anticipating next round of + suggestions from Jacob Applebaum + +2011-12-16 11:16 grothoff + + * [r18624] configure.ac, src/nat/gnunet-helper-nat-server.c: some + very minor stylistic changes to gnunet-helper-nat-server based on + suggestions from Jacob Applebaum + +2011-12-15 17:03 wachs + + * [r18620] src/integration-tests/gnunet_testing.py.in, + src/integration-tests/test_integration_bootstrap_and_connect.py.in, + src/integration-tests/test_integration_clique.py.in, + src/integration-tests/test_integration_disconnect.py.in: improved + tests + +2011-12-15 15:56 wachs + + * [r18617] src/integration-tests/Makefile.am, + src/integration-tests/gnunet_testing.py.in, + src/integration-tests/test_integration_bootstrap_and_connect.py.in, + src/integration-tests/test_integration_clique.py.in: improved + test framework + +2011-12-15 15:20 wachs + + * [r18615] src/integration-tests/gnunet_testing.py.in: added + improved check management + +2011-12-15 14:56 grothoff + + * [r18614] src/fs/gnunet-service-fs_cp.c, + src/fs/gnunet-service-fs_pr.c: use better heuristic to deal with + datastore put failures; log migration stop message transmissions + +2011-12-15 14:55 grothoff + + * [r18613] src/datastore/gnunet-service-datastore.c, + src/include/gnunet_datastore_plugin.h: adding support for + detection quota changes / missing bloomfilter files and + reconstruction/recovery code + +2011-12-15 14:21 wachs + + * [r18603] src/integration-tests/gnunet_testing.py.in: peer get + automatically stopped + +2011-12-15 14:09 wachs + + * [r18602] src/integration-tests/gnunet_testing.py.in: improved + peer management + +2011-12-15 12:44 grothoff + + * [r18601] src/util/container_bloomfilter.c: only try to read bf + from disk if we didn't just create the file + +2011-12-15 12:41 grothoff + + * [r18600] src/datastore/datastore.conf: store Bloomfilter with + rest of datastore data + +2011-12-15 12:40 grothoff + + * [r18599] src/include/gnunet_disk_lib.h, + src/util/container_bloomfilter.c, src/util/disk.c: extra error + checking in Bloom filter to check that the size of the file on + disk corresponds to the expected size for the given filter + +2011-12-15 09:51 wachs + + * [r18597] README: added python remark to hacking This line, and + those below, will be ignored + -- + + M README + +2011-12-15 09:46 wachs + + * [r18596] configure.ac: Python version required to run tests is >= + 2.6 + +2011-12-14 13:32 wachs + + * [r18590] src/include/gnunet_ats_service.h, + src/transport/gnunet-service-transport.c, + src/transport/plugin_transport_http.c, + src/transport/plugin_transport_udp.c, + src/transport/plugin_transport_unix.c: wan/lan detection in + plugins + +2011-12-14 13:31 wachs + + * [r18589] src/ats/ats_api_scheduling.c: adding detection for + AF_UNIX + +2011-12-14 10:25 wachs + + * [r18588] src/transport/plugin_transport_http.c, + src/transport/plugin_transport_http.h, + src/transport/plugin_transport_http_server.c, + src/transport/plugin_transport_tcp.c: WAN/LAN for HTTP/S + +2011-12-14 08:53 wachs + + * [r18587] src/include/gnunet_transport_plugin.h, + src/transport/gnunet-service-transport.c, + src/transport/gnunet-service-transport_plugins.c, + src/transport/gnunet-service-transport_plugins.h, + src/transport/plugin_transport_tcp.c: removing ats functions from + plugins, instead provide callback function + +2011-12-14 08:52 wachs + + * [r18586] src/ats/ats_api_scheduling.c: + +2011-12-13 16:26 wachs + + * [r18578] src/include/gnunet_transport_plugin.h: missing + +2011-12-13 16:20 wachs + + * [r18577] src/transport/gnunet-service-transport.c, + src/transport/gnunet-service-transport_plugins.c, + src/transport/plugin_transport_tcp.c: changes: + changed order of startup since ats is now required for plugins + transport provides ATS handles for plugins + network detection for tcp + +2011-12-13 15:19 wachs + + * [r18576] src/transport/plugin_transport_wlan.c: address type in + WLAN + +2011-12-13 15:15 wachs + + * [r18575] src/transport/plugin_transport_unix.c: added ATS + addresstype information to unix + +2011-12-13 15:13 wachs + + * [r18574] src/ats/ats_api_scheduling.c, + src/ats/gnunet-service-ats_addresses.c: fixing crash 0002007 + adding network information to addresses + +2011-12-13 15:02 wachs + + * [r18573] src/util/os_network.c: LRN's patch argument order + +2011-12-13 14:36 grothoff + + * [r18572] src/fs/gnunet-service-fs.c, + src/fs/gnunet-service-fs_lc.c, src/fs/gnunet-service-fs_pr.h: + trying to fix #2000 + +2011-12-13 12:31 wachs + + * [r18566] src/ats/Makefile.am, src/ats/ats_api_scheduling.c, + src/ats/gnunet-service-ats_addresses.c, + src/ats/gnunet-service-ats_addresses.h, + src/include/gnunet_ats_service.h: move code from service to api + fix bug + add test + +2011-12-12 17:11 wachs + + * [r18562] src/ats/gnunet-service-ats_addresses.c, + src/include/gnunet_ats_service.h: WAN/LAN detection + Mantis 1991 + +2011-12-12 13:58 wachs + + * [r18560] src/ats/gnunet-service-ats_addresses.c, + src/ats/gnunet-service-ats_addresses.h: IPv4 check implemented + TODO: IPv6 + +2011-12-12 12:52 wachs + + * [r18559] src/ats/gnunet-service-ats_addresses.c, + src/ats/gnunet-service-ats_addresses.h: WAN/LAN detection + +2011-12-12 12:05 wachs + + * [r18558] src/Makefile.am, + src/integration-tests/test_integration_clique.py.in: including + integration tests in checks + +2011-12-11 15:39 grothoff + + * [r18556] src/transport, src/transport/Makefile.am, + src/transport/gnunet-helper-transport-wlan-dummy.c, + src/transport/gnunet-helper-transport-wlan.c, + src/transport/gnunet-transport-wlan-helper-dummy.c, + src/transport/gnunet-transport-wlan-helper.c, + src/transport/gnunet-transport-wlan-sender.c, + src/transport/plugin_transport_wlan.c: renaming WLAN helper + process to gnunet-helper-transport-wlan in order to satisfy + naming conventions + +2011-12-10 13:49 harsha + + * [r18543] src/include/gnunet_stream_lib.h: syntax + +2011-12-09 17:31 wachs + + * [r18541] src/integration-tests/Makefile.am, + src/integration-tests/confs/c_no_nat_client_2.conf, + src/integration-tests/hostkeys/0002-hostkey, + src/integration-tests/hostkeys/0003-hostkey, + src/integration-tests/hostkeys/0004-hostkey, + src/integration-tests/hostkeys/0005-hostkey, + src/integration-tests/hostkeys/0006-hostkey, + src/integration-tests/hostkeys/0007-hostkey, + src/integration-tests/hostkeys/0008-hostkey, + src/integration-tests/hostkeys/0009-hostkey, + src/integration-tests/test_integration_clique.py.in, + src/integration-tests/test_integration_disconnect.py.in: clique + +2011-12-09 16:18 wachs + + * [r18534] src/integration-tests/Makefile.am, + src/integration-tests/test_integration_bootstrap_and_connect.py.in, + src/integration-tests/test_integration_disconnect.py.in: + disconnect test + +2011-12-09 16:09 grothoff + + * [r18533] src/statistics/statistics_api.c: fix crash + +2011-12-09 15:57 harsha + + * [r18532] src/include/gnunet_stream_lib.h: fixed missing doc + comment + +2011-12-09 15:55 harsha + + * [r18531] src/include/gnunet_stream_lib.h, src/stream, + src/stream/README: added API definitions for stream library + +2011-12-09 15:19 wachs + + * [r18530] + src/integration-tests/test_integration_bootstrap_and_connect.py.in: + added core sessions + +2011-12-09 14:48 wachs + + * [r18528] src/integration-tests/confs/c_bootstrap_server.conf, + src/integration-tests/confs/c_no_nat_client.conf, + src/integration-tests/test_integration_bootstrap_and_connect.py.in: + first test ready + +2011-12-09 12:41 wachs + + * [r18526] + src/integration-tests/test_integration_bootstrap_and_connect.py.in: + test now checks if boths transports are connecting + +2011-12-09 10:40 wachs + + * [r18525] src/statistics/gnunet-statistics.c: added quiet mode + just printing the value + +2011-12-08 16:16 wachs + + * [r18517] src/integration-tests/Makefile.am, + src/integration-tests/confs, + src/integration-tests/confs/c_bootstrap_server.conf, + src/integration-tests/confs/c_nat_client.conf, + src/integration-tests/confs/c_no_nat_client.conf, + src/integration-tests/test_integration_bootstrap_and_connect.py.in, + src/integration-tests/test_integration_clique.py.in: step by step + +2011-12-08 15:45 grothoff + + * [r18515] doc/man/gnunet-arm.1, po/POTFILES.in, + src/arm/Makefile.am, src/arm/arm.h, src/arm/arm_api.c, + src/arm/do_start_process.c, src/arm/gnunet-arm.c, + src/arm/gnunet-service-arm.c, src/arm/mockup-service.c, + src/arm/test_arm_api.c, src/arm/test_exponential_backoff.c, + src/arm/test_gnunet_arm.sh, + src/arm/test_gnunet_service_manager.c, + src/include/gnunet_arm_service.h, src/include/gnunet_protocols.h: + major rewrite of ARM service and a bit of the ARM IPC to take + advantage of the simplifications possible now that we no longer + intercept traffic; the new code in particular is better at + communicating what exactly ARM was doing in response to requests. + A major change is that gnunet-arm -i/-k now only impacts if a + service is running by-default, on-demand starting is no longer + impacted, option -t from gnunet-arm was removed + +2011-12-08 15:32 wachs + + * [r18512] src/testing/gnunet-testing.c: modified to create cfg + with default without template + +2011-12-08 13:43 wachs + + * [r18511] src/testing/gnunet-testing.c: added option to specify + hostkey file + +2011-12-08 13:16 wachs + + * [r18510] configure.ac, src/integration-tests, + src/integration-tests/Makefile.am, + src/integration-tests/test_integration_clique.py.in: basics for + integration tests + +2011-12-08 13:04 wachs + + * [r18509] src/testing/Makefile.am: space after backslash + +2011-12-08 12:42 grothoff + + * [r18506] src/nse/gnunet-service-nse.c: add statistic to track + estimated network diameter + +2011-12-08 12:38 grothoff + + * [r18505] src/nse/gnunet-service-nse.c: fixing issue with sending + back size estimate messages to peers that already have good + estimate information + +2011-12-07 17:02 wachs + + * [r18497] src/testing/gnunet-testing.c: added hostkey generation + functionality + +2011-12-07 15:34 wachs + + * [r18496] src/include/gnunet_testing_lib.h, + src/testing/gnunet-testing.c, src/testing/testing_group.c: + +2011-12-07 15:33 bartpolot + + * [r18495] src/nse/nse_api.c: Made sure that NSE never returns + invalid standard deviation values + +2011-12-07 13:23 wachs + + * [r18492] src/testing/gnunet-testing.c: + +2011-12-07 12:42 wachs + + * [r18491] src/include/gnunet_getopt_lib.h, + src/util/getopt_helpers.c: fixed docu + +2011-12-07 12:28 wachs + + * [r18490] src/testing/Makefile.am, src/testing/gnunet-testing.c: + testing cmd line tool + +2011-12-06 20:20 grothoff + + * [r18484] src/arm/gnunet-service-arm_interceptor.c: removing ARM + interceptor connection forwarding post-accept code, now using + lsocks everywhere + +2011-12-06 20:07 grothoff + + * [r18479] src/include/gnunet_common.h, + src/include/gnunet_network_lib.h, + src/include/gnunet_server_lib.h, src/transport/Makefile.am, + src/transport/gnunet-transport-wlan-helper.c, + src/util/pseudonym.c: eliminating last dependency on util code + from wlan helper by inlining + +2011-12-06 19:06 grothoff + + * [r18476] src/util/common_logging.c: LRN: correct behaviour when + logfile does not exist + +2011-12-06 18:06 grothoff + + * [r18475] src/arm/gnunet-service-arm_interceptor.c: fix compile + +2011-12-06 18:06 grothoff + + * [r18474] src/util/common_logging.c: LRN: Ensure that GTK can then + do the internal call write(2, message, strlen + (message)); successfully by default. + +2011-12-06 17:58 grothoff + + * [r18473] src/arm/do_start_process.c, + src/arm/gnunet-service-arm.c, src/arm/gnunet-service-arm.h, + src/arm/gnunet-service-arm_interceptor.c, + src/include/gnunet_network_lib.h, src/include/gnunet_os_lib.h, + src/include/platform.h, src/util/network.c, + src/util/os_priority.c, src/util/service.c: Implement passing + sockets in IPC on W32 (#1975) + +2011-12-06 14:55 wachs + + * [r18463] src/include/gnunet_common.h, + src/transport/gnunet-transport-wlan-helper.c, + src/transport/gnunet_wlan_sender.c, + src/transport/plugin_transport_wlan.c: adding GNUnet endian + operations + +2011-12-06 14:19 wachs + + * [r18461] src/transport/gnunet_wlan_sender.c: timestamp not + supported on fedora core 8 + +2011-12-06 14:13 grothoff + + * [r18460] src/datastore/gnunet-service-datastore.c, + src/util/common_allocation.c, src/util/container_bloomfilter.c: + Fixing #1976 by allowing allocations between INT_MAX and SIZE_MAX + and at the same time limiting BF size for datastore to 2 GB. Also + fixing infinite loop when creating BFs of sizes between 2-4 GB + +2011-12-06 13:54 grothoff + + * [r18456] src/arm/gnunet-service-arm_interceptor.c, + src/include/gnunet_common.h, src/util/common_endian.c: use + uint64_t instead of long long for GNUNET_ntohll/GNUNET_htonll + +2011-12-06 13:35 bartpolot + + * [r18451] src/include/platform.h: Removed legacy code + +2011-12-06 12:49 grothoff + + * [r18445] src/include/platform.h, src/include/winproc.h, + src/nat/gnunet-helper-nat-client-windows.c, + src/nat/gnunet-helper-nat-server-windows.c: LRN: Fixing Mantis + #1974: On W32 winsock2.h defines FD_SETSIZE (if it was not + defined before inclusion of the header) to 64, which means that + it's not possible to select on more than 64 sockets at once. This + might work during the tests, but in the wild people might want to + have more than 60 connections, at least in the transport service. + The patch attached should increase the limit to 1024. + +2011-12-06 09:44 grothoff + + * [r18432] README: fix + +2011-12-06 01:56 grothoff + + * [r18431] contrib/Makefile.am: distfix + +2011-12-01 09:17 grothoff + + * [r18412] src/datastore/perf_plugin_datastore.c, + src/util/winproc.c: LRN: Adding vectored exception handling for + W32 (#1965) + + Whenever an exception occurs, and the process is not being + debugged, it will run a debugger specified by GNUNET_DEBUGGER + environment variable, and wait for it to attach. + The net effect is the same as using JIT debugging (AeDebug), but + without the stack being broken by SEH (because VEH has a priority + over SEH), which allows for fuller backtraces for any exception, + not just for GNUNET_abort() calls. + +2011-11-30 15:21 grothoff + + * [r18410] Makefile.am, configure.ac, po/de.po, po/es.po, po/sv.po, + po/vi.po, po/zh_CN.po: releasing GNUnet 0.9.0 + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..7d1c323 --- /dev/null +++ b/INSTALL @@ -0,0 +1,365 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008, 2009 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..1c804cb --- /dev/null +++ b/Makefile.am @@ -0,0 +1,29 @@ +INCLUDES = -I$(top_srcdir)/src/include +SUBDIRS = contrib doc m4 src po pkgconfig + +EXTRA_DIST = \ + ABOUT-NLS \ + config.rpath \ + install-sh \ + acinclude.m4 + +gnunetincludedir = $(includedir)/gnunet +gnunetinclude_HEADERS = gnunet_config.h + +docdir = $(datadir)/doc/gnunet/ +doc_DATA = COPYING + +ACLOCAL_AMFLAGS = -I m4 + +ChangeLog: + if test -f $(top_srcdir)/.svn/entries; then \ + svn log -v --xml -r HEAD:18409 | \ + xsltproc --stringparam ignore-message-starting "-" \ + --stringparam strip-prefix "gnunet" \ + --stringparam include-rev "yes" $(top_srcdir)/contrib/svn2cl.xsl - > $@; \ + fi + +dist: ChangeLog + +.PHONY: ChangeLog + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..b1af2c5 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,920 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = . +DIST_COMMON = README $(am__configure_deps) $(gnunetinclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/gnunet_config.h.in $(top_srcdir)/configure ABOUT-NLS \ + AUTHORS COPYING ChangeLog INSTALL NEWS compile config.guess \ + config.rpath config.sub depcomp install-sh ltmain.sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(docdir)" \ + "$(DESTDIR)$(gnunetincludedir)" +DATA = $(doc_DATA) +HEADERS = $(gnunetinclude_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = $(datadir)/doc/gnunet/ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +SUBDIRS = contrib doc m4 src po pkgconfig +EXTRA_DIST = \ + ABOUT-NLS \ + config.rpath \ + install-sh \ + acinclude.m4 + +gnunetincludedir = $(includedir)/gnunet +gnunetinclude_HEADERS = gnunet_config.h +doc_DATA = COPYING +ACLOCAL_AMFLAGS = -I m4 +all: gnunet_config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +gnunet_config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/gnunet_config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status gnunet_config.h +$(srcdir)/gnunet_config.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f gnunet_config.h stamp-h1 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +install-docDATA: $(doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)" + @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ + done + +uninstall-docDATA: + @$(NORMAL_UNINSTALL) + @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(docdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(docdir)" && rm -f $$files +install-gnunetincludeHEADERS: $(gnunetinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(gnunetincludedir)" || $(MKDIR_P) "$(DESTDIR)$(gnunetincludedir)" + @list='$(gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(gnunetincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(gnunetincludedir)" || exit $$?; \ + done + +uninstall-gnunetincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(gnunetincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(gnunetincludedir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) gnunet_config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) gnunet_config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) gnunet_config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) gnunet_config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) $(HEADERS) gnunet_config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(gnunetincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-docDATA install-gnunetincludeHEADERS + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-docDATA uninstall-gnunetincludeHEADERS + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ + dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \ + distcheck distclean distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-docDATA install-dvi install-dvi-am install-exec \ + install-exec-am install-gnunetincludeHEADERS install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-recursive uninstall uninstall-am \ + uninstall-docDATA uninstall-gnunetincludeHEADERS + + +ChangeLog: + if test -f $(top_srcdir)/.svn/entries; then \ + svn log -v --xml -r HEAD:18409 | \ + xsltproc --stringparam ignore-message-starting "-" \ + --stringparam strip-prefix "gnunet" \ + --stringparam include-rev "yes" $(top_srcdir)/contrib/svn2cl.xsl - > $@; \ + fi + +dist: ChangeLog + +.PHONY: ChangeLog + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..898a3da --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ +See ChangeLog. diff --git a/README b/README new file mode 100644 index 0000000..b2b7233 --- /dev/null +++ b/README @@ -0,0 +1,253 @@ + Welcome to GNUnet + + +What is GNUnet? +=============== + +GNUnet is peer-to-peer framework focusing on security. The first and +primary application for GNUnet is anonymous file-sharing. GNUnet is +currently developed by a worldwide group of independent free software +developers. GNUnet is a GNU package (http://www.gnu.org/). + +This is an ALPHA release. There are known and significant bugs as +well as many missing features in this release. + +Additional documentation about GNUnet can be found at +https://gnunet.org/. + + +Dependencies: +============= + +Please note that for many of its dependencies GNUnet requires very +recent versions of the libraries which are often NOT to be found in +stable distributions in 2011. While using older packages may in some +cases on some operating systems may seem to work in some limited +fashion, we are in many cases aware of serious problems with older +packages. Hence please make sure to use the versions listed below. + +These are the direct dependencies for running GNUnet: + +- libextractor >= 0.6.1 +- libmicrohttpd >= 0.9.18 +- libgcrypt >= 1.2 +- libcurl >= 7.21.0 +- libunistring >= 0.9.2 +- libltdl >= 2.2 (part of GNU libtool) +- sqlite >= 3.0 (default database) +- mysql >= 5.1 (alternative to sqLite) +- postgres >= 8.3 (alternative to sqLite) + +Recommended autotools for compiling the SVN version are: +- autoconf >= 2.59 +- automake >= 1.11.1 +- libtool >= 2.2 + + +How to install? +=============== + +The fastest way is to use a binary package if it is available for your +system. For a more detailed description, read the installation +instructions on the webpage at https://gnunet.org/installation. + +Note that some functions of GNUnet require "root" access. GNUnet will +install (tiny) SUID binaries for those functions is you run "make +install" as root. If you do not, GNUnet will still work, but some +functionality will not be available (including certain forms of NAT +traversal). + +GNUnet requires the GNU MP library (http://www.gnu.org/software/gmp/) +and libgcrypt (http://www.gnupg.org/). You can specify the path to +libgcrypt by passing "--with-gcrypt=PATH" to configure. You will also +need either sqlite (http://www.sqlite.org/), MySQL +(http://www.mysql.org/) or PostGres (http://www.postgres.org/). + +If you install from source, you need to install GNU libextractor first +(download from http://www.gnu.org/software/libextractor/). We also +recommend installing GNU libmicrohttpd (download from +http://www.gnu.org/software/libmicrohttpd/). Then you can start the +actual GNUnet compilation and installation process with: + +$ export GNUNET_PREFIX=/usr/local # or other directory of your choice +$ addgroup gnunetdns +$ adduser gnunet gnunet +$ ./configure --prefix=$GNUNET_PREFIX --with-extractor=$LE_PREFIX +$ make +# make install +# sudo -u gnunet mkdir ~/.gnunet/ +# sudo -u gnunet touch ~/.gnunet/gnunet.conf +# sudo -u gnunet gnunet-arm -s + +This will create the users and groups needed for running GNUnet +securely and then compile and install GNUnet to $GNUNET_PREFIX/bin/, +$GNUNET_PREFIX/lib/ and $GNUNET_PREFIX/share/ and start the system +with the default configuration. It is strongly recommended that you +add a user "gnunet" to run "gnunet-arm". You can then still run the +end-user applications as another user. + +If you create a system user "gnunet", it is recommended that you edit +the configuration file slightly so that data can be stored in the +system user home directory at "/var/lib/gnunet"; you may also want to +use "/etc/gnunet.conf" for the location of the configuration file in +this case. + +You can avoid running 'make install' as root if you run configure +with the "--with-sudo=yes" option and have extensive sudo rights +(can run "chmod +s" and "chown" via 'sudo'). If you run 'make install' +as a normal user without sudo rights (or the configure option), +certain binaries that require additional priviledges will not be +installed properly (and autonomous NAT traversal, WLAN, DNS/GNS and +the VPN will then not work). + +Note that additional, per-user configuration files +(~/.gnunet/gnunet.conf) need to be created by each user (for example, +by running gnunet-setup). Note that gnunet-setup is a separate +download and requires recent versions of GTK+ and Glade; you can also +edit the configuration file by hand, but this is not recommended. For +more general information about the GNU build process read the INSTALL +file. + +If you are compiling the code from subversion, you have to run +". bootstrap" before ./configure. If you receive an error during the +running of ". bootstrap" that looks like "macro `AM_PATH_GTK' not +found in library", you may need to run aclocal by hand with the -I +option, pointing to your aclocal m4 macros, i.e. + +$ aclocal -I /usr/local/share/aclocal + + +Configuration +============= + +GNUnet uses two types of configuration files, one that specifies the +system-wide defaults (typically located in +$GNUNET_PREFIX/share/gnunet/config.d/) and a second one that overrides +default values with user-specific preferences. The user-specific +configuration file should be located in "~/.gnunet/gnunet.conf" or its +location can be specified by giving the "-c" option to the respective +GNUnet application. + +The defaults that are shipped with the installation are usually ok, +you may want to adjust the limitations (space consumption, bandwidth, +etc.) though. The configuration files are human-readable. Note that +you MUST create "~/.gnunet/gnunet.conf" explicitly before starting +GNUnet. You can either run gnunet-setup (available as part of the +gnunet-gtk source package) or simply create an empty file. + + +Usage +===== + +First, you must obtain an initial list of GNUnet hosts. Knowing a +single peer is sufficient since after that GNUnet propagates +information about other peers. Note that the default "gnunet.conf" +contains URLs from where GNUnet downloads an initial hostlist +whenever it is started. If you want to create an alternative URL for +others to use, the file can be generated on any machine running +GNUnet by periodically executing + +$ cat $SERVICEHOME/data/hosts/* > the_file + +and offering 'the_file' via your web server. Alternatively, you can +run the build-in web server by adding '-p' to the OPTIONS value +in the "hostlist" section of gnunet.conf and opening the respective +HTTPPORT to the public. + +If the solution with the hostlist URL is not feasible for your +situation, you can also add hosts manually. Simply copy the hostkeys +to "$SERVICEHOME/data/hosts/" (where $SERVICEHOME is the directory +specified in the gnunet.conf configuration file). + +Now start the local node using "gnunet-arm -s". GNUnet should run 24/7 if +you want to maximize your anonymity. + +You should then be able to access GNUnet using the shell: + +$ gnunet-search KEYWORD + +This will display a list of results to the console. Then use + +$ gnunet-download -o FILENAME GNUNET_URI + +to retrieve a file. The GNUNET_URI is printed by gnunet-search +together with a description. To publish files on GNUnet, use the +"gnunet-publish" command. + + +The GTK user interface is shipped separately. After downloading and +installing gnunet-gtk, you can invoke the setup tool and the +file-sharing GUI with: + +$ gnunet-setup +$ gnunet-fs-gtk + +For further documentation, see our webpage. + + +Hacking GNUnet +============== + +Contributions are welcome, please submit bugs to +https://gnunet.org/bugs/. Please make sure to run contrib/report.sh +and include the output with your bug reports. More about how to +report bugs can be found in the GNUnet FAQ on the webpage. Submit +patches via E-Mail to gnunet-developers@gnu.org. + +In order to run the unit tests with "make check", you need to +set an environment variable ("GNUNET_PREFIX") to the directory +where GNUnet is installed (usually, GNUnet will use OS specific +tricks in order to try to figure out the PREFIX, but since the +testcase binaries are not installed, that trick does not work +for them). Also, before running any testcases, you must +complete the installation first. Quick summary: + +$ ./configure --prefix=$SOMEWHERE +$ make +$ make install +$ export GNUNET_PREFIX=$SOMEWHERE +$ make check + +Some of the testcases require python >= 2.6 and pexpect to be +installed. If any testcases fail to pass on your system, run +"contrib/report.sh" and report the output together with +information about the failing testcase to the Mantis bugtracking +system at https://gnunet.org/bugs/. + + +Running http on port 80 and https on port 443 +============================================= + +In order to hide GNUnet's HTTP/HTTPS traffic perfectly, you might +consider running GNUnet's HTTP/HTTPS transport on port 80/443. +However, we do not recommend running GNUnet as root. Instead, forward +port 80 to say 8080 with this command (as root, in your startup +scripts): + +# iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080 + +or for HTTPS + +# iptables -t nat -A PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 4433 + +Then set in the HTTP section of gnunet.conf the "ADVERTISED-PORT" to +"80" and "PORT" to 8080 and similarly in the HTTPS section the +"ADVERTISED-PORT" to "443" and "PORT" to 4433. + +You can do the same trick for the TCP and UDP transports if you want +to map them to a priviledged port (from the point of view of the +network). However, we are not aware of this providing any advantages +at this point. + + +Stay tuned +========== + +* https://gnunet.org/ +* https://gnunet.org/bugs/ +* https://gnunet.org/svn/ +* http://www.gnu.org/software/gnunet/ +* http://mail.gnu.org/mailman/listinfo/gnunet-developers +* http://mail.gnu.org/mailman/listinfo/help-gnunet +* http://mail.gnu.org/mailman/listinfo/info-gnunet +* http://mail.gnu.org/mailman/listinfo/gnunet-svn diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..d17f1c5 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,65 @@ +# See: http://gcc.gnu.org/ml/gcc/2000-05/msg01141.html +AC_DEFUN([CHECK_PTHREAD], +[ + AC_CHECK_LIB(pthread,pthread_create, + [ + PTHREAD_CPPFLAGS= + PTHREAD_LDFLAGS= + PTHREAD_LIBS=-lpthread + ],[ + AC_MSG_CHECKING(if compiler supports -pthread) + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -pthread" + AC_TRY_LINK( + [ + #include + ],[ + pthread_create(0,0,0,0); + ],[ + AC_MSG_RESULT(yes) + PTHREAD_CPPFLAGS=-pthread + PTHREAD_LDFLAGS=-pthread + PTHREAD_LIBS= + ],[ + AC_MSG_RESULT(no) + AC_MSG_CHECKING(if compiler supports -pthreads) + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$save_CPPFLAGS -pthreads" + AC_TRY_LINK( + [ + #include + ],[ + pthread_create(0,0,0,0); + ],[ + AC_MSG_RESULT(yes) + PTHREAD_CPPFLAGS=-pthreads + PTHREAD_LDFLAGS=-pthreads + PTHREAD_LIBS= + ],[ + AC_MSG_RESULT(no) + AC_MSG_CHECKING(if compiler supports -threads) + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$save_CPPFLAGS -threads" + AC_TRY_LINK( + [ + #include + ],[ + pthread_create(0,0,0,0); + ],[ + AC_MSG_RESULT(yes) + PTHREAD_CPPFLAGS=-threads + PTHREAD_LDFLAGS=-threads + PTHREAD_LIBS= + ],[ + AC_MSG_ERROR([Your system is not supporting pthreads!]) + ]) + ]) + ]) + CPPFLAGS="$save_CPPFLAGS" + ]) +]) + +dnl Checks for all prerequisites of the intl subdirectory, +dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, +dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. + AC_DEFUN([AM_INTL_SUBDIR], []) \ No newline at end of file diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..f7689c9 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1256 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.67],, +[m4_warning([this file was generated for autoconf 2.67. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_PROG_CC_C_O +# -------------- +# Like AC_PROG_CC_C_O, but changed for automake. +AC_DEFUN([AM_PROG_CC_C_O], +[AC_REQUIRE([AC_PROG_CC_C_O])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +dnl Make sure AC_PROG_CC is never called again, or it will override our +dnl setting of CC. +m4_define([AC_PROG_CC], + [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# --------------------------------------------------------------------------- +# Adds support for distributing Python modules and packages. To +# install modules, copy them to $(pythondir), using the python_PYTHON +# automake variable. To install a package with the same name as the +# automake package, install to $(pkgpythondir), or use the +# pkgpython_PYTHON automake variable. +# +# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as +# locations to install python extension modules (shared libraries). +# Another macro is required to find the appropriate flags to compile +# extension modules. +# +# If your package is configured with a different prefix to python, +# users will have to add the install directory to the PYTHONPATH +# environment variable, or create a .pth file (see the python +# documentation for details). +# +# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will +# cause an error if the version of python installed on the system +# doesn't meet the requirement. MINIMUM-VERSION should consist of +# numbers and dots only. +AC_DEFUN([AM_PATH_PYTHON], + [ + dnl Find a Python interpreter. Python versions prior to 2.0 are not + dnl supported. (2.0 was released on October 16, 2000). + m4_define_default([_AM_PYTHON_INTERPRETER_LIST], + [python python2 python3 python3.0 python2.5 python2.4 python2.3 python2.2 dnl +python2.1 python2.0]) + + m4_if([$1],[],[ + dnl No version check is needed. + # Find any Python interpreter. + if test -z "$PYTHON"; then + AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) + fi + am_display_PYTHON=python + ], [ + dnl A version check is needed. + if test -n "$PYTHON"; then + # If the user set $PYTHON, use it and don't search something else. + AC_MSG_CHECKING([whether $PYTHON version >= $1]) + AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], + [AC_MSG_RESULT(yes)], + [AC_MSG_ERROR(too old)]) + am_display_PYTHON=$PYTHON + else + # Otherwise, try each interpreter until we find one that satisfies + # VERSION. + AC_CACHE_CHECK([for a Python interpreter with version >= $1], + [am_cv_pathless_PYTHON],[ + for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do + test "$am_cv_pathless_PYTHON" = none && break + AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) + done]) + # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. + if test "$am_cv_pathless_PYTHON" = none; then + PYTHON=: + else + AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) + fi + am_display_PYTHON=$am_cv_pathless_PYTHON + fi + ]) + + if test "$PYTHON" = :; then + dnl Run any user-specified action, or abort. + m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) + else + + dnl Query Python for its version number. Getting [:3] seems to be + dnl the best way to do this; it's what "site.py" does in the standard + dnl library. + + AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], + [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) + AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) + + dnl Use the values of $prefix and $exec_prefix for the corresponding + dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made + dnl distinct variables so they can be overridden if need be. However, + dnl general consensus is that you shouldn't need this ability. + + AC_SUBST([PYTHON_PREFIX], ['${prefix}']) + AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) + + dnl At times (like when building shared libraries) you may want + dnl to know which OS platform Python thinks this is. + + AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], + [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) + AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) + + + dnl Set up 4 directories: + + dnl pythondir -- where to install python scripts. This is the + dnl site-packages directory, not the python standard library + dnl directory like in previous automake betas. This behavior + dnl is more consistent with lispdir.m4 for example. + dnl Query distutils for this directory. distutils does not exist in + dnl Python 1.5, so we fall back to the hardcoded directory if it + dnl doesn't work. + AC_CACHE_CHECK([for $am_display_PYTHON script directory], + [am_cv_python_pythondir], + [if test "x$prefix" = xNONE + then + am_py_prefix=$ac_default_prefix + else + am_py_prefix=$prefix + fi + am_cv_python_pythondir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(0,0,prefix='$am_py_prefix'))" 2>/dev/null || + echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"` + case $am_cv_python_pythondir in + $am_py_prefix*) + am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` + am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` + ;; + *) + case $am_py_prefix in + /usr|/System*) ;; + *) + am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages + ;; + esac + ;; + esac + ]) + AC_SUBST([pythondir], [$am_cv_python_pythondir]) + + dnl pkgpythondir -- $PACKAGE directory under pythondir. Was + dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is + dnl more consistent with the rest of automake. + + AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) + + dnl pyexecdir -- directory for installing python extension modules + dnl (shared libraries) + dnl Query distutils for this directory. distutils does not exist in + dnl Python 1.5, so we fall back to the hardcoded directory if it + dnl doesn't work. + AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], + [am_cv_python_pyexecdir], + [if test "x$exec_prefix" = xNONE + then + am_py_exec_prefix=$am_py_prefix + else + am_py_exec_prefix=$exec_prefix + fi + am_cv_python_pyexecdir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(1,0,prefix='$am_py_exec_prefix'))" 2>/dev/null || + echo "$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages"` + case $am_cv_python_pyexecdir in + $am_py_exec_prefix*) + am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` + am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` + ;; + *) + case $am_py_exec_prefix in + /usr|/System*) ;; + *) + am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages + ;; + esac + ;; + esac + ]) + AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) + + dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) + + AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) + + dnl Run any user-specified action. + $2 + fi + +]) + + +# AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# --------------------------------------------------------------------------- +# Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. +# Run ACTION-IF-FALSE otherwise. +# This test uses sys.hexversion instead of the string equivalent (first +# word of sys.version), in order to cope with versions such as 2.2c1. +# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). +AC_DEFUN([AM_PYTHON_CHECK_VERSION], + [prog="import sys +# split strings by '.' and convert to numeric. Append some zeros +# because we need at least 4 digits for the hex conversion. +# map returns an iterator in Python 3.0 and a list in 2.x +minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] +minverhex = 0 +# xrange is not present in Python 3.0 and range returns an iterator +for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] +sys.exit(sys.hexversion < minverhex)" + AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# (`yes' being less verbose, `no' or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], +[ --enable-silent-rules less verbose build output (undo: `make V=1') + --disable-silent-rules verbose build output (undo: `make V=0')]) +case $enable_silent_rules in +yes) AM_DEFAULT_VERBOSITY=0;; +no) AM_DEFAULT_VERBOSITY=1;; +*) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([m4/absolute-header.m4]) +m4_include([m4/align.m4]) +m4_include([m4/argz.m4]) +m4_include([m4/gettext.m4]) +m4_include([m4/iconv.m4]) +m4_include([m4/lib-ld.m4]) +m4_include([m4/lib-link.m4]) +m4_include([m4/lib-prefix.m4]) +m4_include([m4/libcurl.m4]) +m4_include([m4/libgcrypt.m4]) +m4_include([m4/libtool.m4]) +m4_include([m4/libunistring.m4]) +m4_include([m4/ltdl.m4]) +m4_include([m4/ltoptions.m4]) +m4_include([m4/ltsugar.m4]) +m4_include([m4/ltversion.m4]) +m4_include([m4/lt~obsolete.m4]) +m4_include([m4/nls.m4]) +m4_include([m4/po.m4]) +m4_include([m4/progtest.m4]) +m4_include([acinclude.m4]) diff --git a/compile b/compile new file mode 100755 index 0000000..c0096a7 --- /dev/null +++ b/compile @@ -0,0 +1,143 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2009-10-06.20; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009 Free Software +# Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..dc84c68 --- /dev/null +++ b/config.guess @@ -0,0 +1,1501 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.rpath b/config.rpath new file mode 100755 index 0000000..c492a93 --- /dev/null +++ b/config.rpath @@ -0,0 +1,614 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2006 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit , 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + darwin*) + case $cc_basename in + xlc*) + wl='-Wl,' + ;; + esac + ;; + mingw* | pw32* | os2*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + newsos6) + ;; + linux*) + case $cc_basename in + icc* | ecc*) + wl='-Wl,' + ;; + pgcc | pgf77 | pgf90) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + sco3.2v5*) + ;; + solaris*) + wl='-Wl,' + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we cannot use + # them. + ld_shlibs=no + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + interix3*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if test "$GCC" = yes ; then + : + else + case $cc_basename in + xlc*) + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd1*) + ld_shlibs=no + ;; + freebsd2.2*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + freebsd2*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + openbsd*) + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER. +libname_spec='lib$name' +case "$host_os" in + aix3*) + ;; + aix4* | aix5*) + ;; + amigaos*) + ;; + beos*) + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32*) + shrext=.dll + ;; + darwin* | rhapsody*) + shrext=.dylib + ;; + dgux*) + ;; + freebsd1*) + ;; + kfreebsd*-gnu) + ;; + freebsd* | dragonfly*) + ;; + gnu*) + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + ;; + interix3*) + ;; + irix5* | irix6* | nonstopux*) + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux*) + ;; + knetbsd*-gnu) + ;; + netbsd*) + ;; + newsos6) + ;; + nto-qnx*) + ;; + openbsd*) + ;; + os2*) + libname_spec='$name' + shrext=.dll + ;; + osf3* | osf4* | osf5*) + ;; + solaris*) + ;; + sunos4*) + ;; + sysv4 | sysv4.3*) + ;; + sysv4*MP*) + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + ;; + uts4*) + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <. Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000..102c357 --- /dev/null +++ b/configure @@ -0,0 +1,29880 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.67 for gnunet 0.9.2. +# +# Report bugs to . +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and bug-gnunet@gnu.org +$0: about your system, including any error possibly output +$0: before this message. Then install a modern shell, or +$0: manually run the script under such a shell if you do +$0: have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +$* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + + +lt_ltdl_dir='libltdl' + +lt_dlopen_dir="$lt_ltdl_dir" + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='gnunet' +PACKAGE_TARNAME='gnunet' +PACKAGE_VERSION='0.9.2' +PACKAGE_STRING='gnunet 0.9.2' +PACKAGE_BUGREPORT='bug-gnunet@gnu.org' +PACKAGE_URL='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +enable_option_checking=no +gt_needs= +ac_subst_vars='ltdl_LTLIBOBJS +ltdl_LIBOBJS +am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +USE_COVERAGE_FALSE +USE_COVERAGE_TRUE +HAVE_EXPERIMENTAL_FALSE +HAVE_EXPERIMENTAL_TRUE +HAVE_BENCHMARKS_FALSE +HAVE_BENCHMARKS_TRUE +HAVE_EXPENSIVE_TESTS_FALSE +HAVE_EXPENSIVE_TESTS_TRUE +ENABLE_TEST_RUN_FALSE +ENABLE_TEST_RUN_TRUE +GNUNETDNS_GROUP +SUDO_BINARY +DLLDIR +LIBPREFIX +EXT_LIBS +EXT_LIB_PATH +GN_LIBINTL +GN_INTLINCL +GN_PLUGIN_LDFLAGS +GN_LIB_LDFLAGS +WANT_FRAMEWORK_FALSE +WANT_FRAMEWORK_TRUE +GN_DAEMON_CONFIG_DIR +GN_DAEMON_HOME_DIR +GN_USER_HOME_DIR +LIBOBJS +POSUB +LTLIBINTL +LIBINTL +INTLLIBS +INTL_MACOSX_LIBS +MSGMERGE +XGETTEXT_015 +XGETTEXT +GMSGFMT_015 +MSGFMT_015 +GMSGFMT +MSGFMT +USE_NLS +HAVE_PYTHON_PEXPECT_FALSE +HAVE_PYTHON_PEXPECT_TRUE +HAVE_PYTHON_FALSE +HAVE_PYTHON_TRUE +pkgpyexecdir +pyexecdir +pkgpythondir +pythondir +PYTHON_PLATFORM +PYTHON_EXEC_PREFIX +PYTHON_PREFIX +PYTHON_VERSION +PYTHON +HAVE_MHD_FALSE +HAVE_MHD_TRUE +HAVE_MYSQLE_FALSE +HAVE_MYSQLE_TRUE +HAVE_MYSQL_FALSE +HAVE_MYSQL_TRUE +MYSQL_CPPFLAGS +MYSQL_LDFLAGS +HAVE_ZLIB_FALSE +HAVE_ZLIB_TRUE +POSTGRES_LDFLAGS +POSTGRES_CPPFLAGS +HAVE_POSTGRES_FALSE +HAVE_POSTGRES_TRUE +SQLITE_LDFLAGS +SQLITE_CPPFLAGS +HAVE_SQLITE_FALSE +HAVE_SQLITE_TRUE +LTLIBUNISTRING +LIBUNISTRING +HAVE_LIBUNISTRING +LTLIBICONV +LIBICONV +HAVE_LIBGLPK_FALSE +HAVE_LIBGLPK_TRUE +LIBCURL +LIBCURL_CPPFLAGS +_libcurl_config +LIBGCRYPT_LIBS +LIBGCRYPT_CFLAGS +LIBGCRYPT_CONFIG +build_target +LINUX_FALSE +LINUX_TRUE +OPENBSD_FALSE +OPENBSD_TRUE +XFREEBSD_FALSE +XFREEBSD_TRUE +SOLARIS_FALSE +SOLARIS_TRUE +MINGW_FALSE +MINGW_TRUE +CYGWIN_FALSE +CYGWIN_TRUE +DARWIN_FALSE +DARWIN_TRUE +UNIXONLY +DEFAULT_INTERFACE +X_EXTRA_LIBS +X_LIBS +X_PRE_LIBS +X_CFLAGS +XMKMF +LTDLOPEN +LT_CONFIG_H +subdirs +CONVENIENCE_LTDL_FALSE +CONVENIENCE_LTDL_TRUE +INSTALL_LTDL_FALSE +INSTALL_LTDL_TRUE +ARGZ_H +sys_symbol_underscore +LIBADD_DL +LT_DLPREOPEN +LIBADD_DLD_LINK +LIBADD_SHL_LOAD +LIBADD_DLOPEN +LT_DLLOADERS +INCLTDL +LTDLINCL +LTDLDEPS +LIBLTDL +CXXCPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +lt_ECHO +RANLIB +AR +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +LIBTOOL +OBJDUMP +DLLTOOL +AS +LN_S +am__fastdepOBJC_FALSE +am__fastdepOBJC_TRUE +OBJCDEPMODE +ac_ct_OBJC +OBJCFLAGS +OBJC +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +CPP +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_dependency_tracking +enable_static +enable_shared +with_pic +enable_fast_install +with_gnu_ld +enable_libtool_lock +with_included_ltdl +with_ltdl_include +with_ltdl_lib +enable_ltdl_install +enable_largefile +with_x +with_libgcrypt_prefix +enable_gcc_hardening +enable_linker_hardening +enable_logging +with_libcurl +with_extractor +enable_rpath +with_libiconv_prefix +with_libunistring_prefix +with_sqlite +with_postgres +with_mysql +enable_mysql_version_check +with_microhttpd +enable_nls +with_libintl_prefix +with_user_home_dir +with_daemon_home_dir +with_daemon_config_dir +enable_framework +with_sudo +with_gnunetdns +enable_testruns +enable_expensivetests +enable_benchmarks +enable_experimental +enable_windows_workarounds +enable_coverage +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +CXX +CXXFLAGS +CCC +OBJC +OBJCFLAGS +CXXCPP +XMKMF' +ac_subdirs_all='libltdl' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures gnunet 0.9.2 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/gnunet] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +X features: + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of gnunet 0.9.2:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: `make V=1') + --disable-silent-rules verbose build output (undo: `make V=0') + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-static[=PKGS] build static libraries [default=no] + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-ltdl-install install libltdl + --disable-largefile omit support for large files + --enable-gcc-hardening enable compiler security checks + --enable-linker-hardening + enable linker security fixups + --enable-logging[=value] + Enable logging calls. Possible values: + yes,no,verbose,veryverbose ('yes' is the default) + --disable-rpath do not hardcode runtime library paths + --disable-mysql-version-check do not check MySQL version + --disable-nls do not use Native Language Support + --enable-framework enable Mac OS X framework build helpers + --disable-testruns disable running tests on make check (default is YES) + --enable-expensive-tests + enable running expensive testcases + --enable-benchmarks enable running benchmarks during make check + --enable-experimental enable compiling experimental code + --enable-windows_workarounds + enable workarounds used on Windows (only useful for + test cases) + --enable-coverage compile the library with code coverage support + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-included-ltdl use the GNU ltdl sources included here + --with-ltdl-include=DIR use the ltdl headers installed in DIR + --with-ltdl-lib=DIR use the libltdl.la installed in DIR + --with-x use the X Window System + --with-libgcrypt-prefix=PFX + prefix where LIBGCRYPT is installed (optional) + --with-libcurl=PREFIX look for the curl library in PREFIX/lib and headers + in PREFIX/include + --with-extractor=PFX base of libextractor installation + --with-gnu-ld assume the C compiler uses GNU ld default=no + --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib + --without-libiconv-prefix don't search for libiconv in includedir and libdir + --with-libunistring-prefix[=DIR] search for libunistring in DIR/include and DIR/lib + --without-libunistring-prefix don't search for libunistring in includedir and libdir + --with-sqlite=PFX base of SQLite installation + --with-postgres=PFX base of postgres installation + --with-mysql=PFX base of MySQL installation + --with-microhttpd=PFX base of libmicrohttpd installation + --with-libintl-prefix[=DIR] search for libintl in DIR/include and DIR/lib + --without-libintl-prefix don't search for libintl in includedir and libdir + --with-user-home-dir=DIR + default user home directory (~/.gnunet) + --with-daemon-home-dir=DIR + default daemon home directory (/var/lib/gnunet) + --with-daemon-config-dir=DIR + default daemon config directory (/etc) + --with-sudo=PATH path to sudo binary (or just yes) + --with-gnunetdns=GRPNAME name for gnunetdns group + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + OBJC Objective C compiler command + OBJCFLAGS Objective C compiler flags + CXXCPP C++ preprocessor + XMKMF Path to xmkmf, Makefile generator for X Window System + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +gnunet configure 0.9.2 +generated by GNU Autoconf 2.67 + +Copyright (C) 2010 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_objc_try_compile LINENO +# ----------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_objc_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_objc_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_objc_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_decl + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_type + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval "test \"\${$3+set}\"" = set; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## --------------------------------- ## +## Report this to bug-gnunet@gnu.org ## +## --------------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval "test \"\${$4+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$4 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_member + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by gnunet $as_me 0.9.2, which was +generated by GNU Autoconf 2.67. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5 ; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +gt_needs="$gt_needs " +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if test "${ac_cv_target+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5 ;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5 ;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5 ;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=gnunet + VERSION=0.9.2 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in +yes) AM_DEFAULT_VERBOSITY=0;; +no) AM_DEFAULT_VERBOSITY=1;; +*) AM_DEFAULT_VERBOSITY=0;; +esac +AM_BACKSLASH='\' + +ac_config_headers="$ac_config_headers gnunet_config.h" + + + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5 ; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5 ; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5 ; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5 ; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5 ; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5 ; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +ac_ext=m +ac_cpp='$OBJCPP $CPPFLAGS' +ac_compile='$OBJC -c $OBJCFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$OBJC -o conftest$ac_exeext $OBJCFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_objc_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in gcc objcc objc cc CC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OBJC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJC"; then + ac_cv_prog_OBJC="$OBJC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJC=$ac_cv_prog_OBJC +if test -n "$OBJC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJC" >&5 +$as_echo "$OBJC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$OBJC" && break + done +fi +if test -z "$OBJC"; then + ac_ct_OBJC=$OBJC + for ac_prog in gcc objcc objc cc CC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OBJC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJC"; then + ac_cv_prog_ac_ct_OBJC="$ac_ct_OBJC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJC=$ac_cv_prog_ac_ct_OBJC +if test -n "$ac_ct_OBJC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJC" >&5 +$as_echo "$ac_ct_OBJC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_OBJC" && break +done + + if test "x$ac_ct_OBJC" = x; then + OBJC="gcc" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJC=$ac_ct_OBJC + fi +fi + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for Objective C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU Objective C compiler" >&5 +$as_echo_n "checking whether we are using the GNU Objective C compiler... " >&6; } +if test "${ac_cv_objc_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_objc_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_objc_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objc_compiler_gnu" >&5 +$as_echo "$ac_cv_objc_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GOBJC=yes +else + GOBJC= +fi +ac_test_OBJCFLAGS=${OBJCFLAGS+set} +ac_save_OBJCFLAGS=$OBJCFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $OBJC accepts -g" >&5 +$as_echo_n "checking whether $OBJC accepts -g... " >&6; } +if test "${ac_cv_prog_objc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_objc_werror_flag=$ac_objc_werror_flag + ac_objc_werror_flag=yes + ac_cv_prog_objc_g=no + OBJCFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_objc_try_compile "$LINENO"; then : + ac_cv_prog_objc_g=yes +else + OBJCFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_objc_try_compile "$LINENO"; then : + +else + ac_objc_werror_flag=$ac_save_objc_werror_flag + OBJCFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_objc_try_compile "$LINENO"; then : + ac_cv_prog_objc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_objc_werror_flag=$ac_save_objc_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_objc_g" >&5 +$as_echo "$ac_cv_prog_objc_g" >&6; } +if test "$ac_test_OBJCFLAGS" = set; then + OBJCFLAGS=$ac_save_OBJCFLAGS +elif test $ac_cv_prog_objc_g = yes; then + if test "$GOBJC" = yes; then + OBJCFLAGS="-g -O2" + else + OBJCFLAGS="-g" + fi +else + if test "$GOBJC" = yes; then + OBJCFLAGS="-O2" + else + OBJCFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$OBJC" am_compiler_list='gcc3 gcc' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_OBJC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_OBJC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_OBJC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_OBJC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_OBJC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_OBJC_dependencies_compiler_type" >&6; } +OBJCDEPMODE=depmode=$am_cv_OBJC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_OBJC_dependencies_compiler_type" = gcc3; then + am__fastdepOBJC_TRUE= + am__fastdepOBJC_FALSE='#' +else + am__fastdepOBJC_TRUE='#' + am__fastdepOBJC_FALSE= +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +if test "x$CC" != xcc; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 +$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5 +$as_echo_n "checking whether cc understands -c and -o together... " >&6; } +fi +set dummy $CC; ac_cc=`$as_echo "$2" | + sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +if eval "test \"\${ac_cv_prog_cc_${ac_cc}_c_o+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' +rm -f conftest2.* +if { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && + test -f conftest2.$ac_objext && { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if { ac_try='cc -c conftest.$ac_ext >&5' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' + rm -f conftest2.* + if { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && + test -f conftest2.$ac_objext && { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f core conftest* + +fi +if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +$as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h + +fi + +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.2.6b' +macro_revision='1.3017' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if test "${ac_cv_path_SED+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if test "${ac_cv_path_FGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if test "${lt_cv_path_NM+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$ac_tool_prefix"; then + for ac_prog in "dumpbin -symbols" "link -dump -symbols" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in "dumpbin -symbols" "link -dump -symbols" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if test "${lt_cv_nm_interface+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:6386: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:6389: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:6392: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if test "${lt_cv_sys_max_cmd_len+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if test "${lt_cv_ld_reload_flag+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if test "${lt_cv_deplibs_check_method+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + + + + + + + + + + + + + + + + + + + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 7584 "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if test "${lt_cv_cc_needs_belf+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if test "${lt_cv_apple_cc_single_mod+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if test "${lt_cv_ld_exported_symbols_list+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +_lt_caught_CXX_error=yes; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + + + + + +# Set options +# Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=no +fi + + + + + + + +enable_dlopen=yes +enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. +set dummy ${ac_tool_prefix}as; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AS+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AS="${ac_tool_prefix}as" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AS=$ac_cv_prog_AS +if test -n "$AS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 +$as_echo "$AS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AS"; then + ac_ct_AS=$AS + # Extract the first word of "as", so it can be a program name with args. +set dummy as; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_AS+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AS"; then + ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AS="as" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AS=$ac_cv_prog_ac_ct_AS +if test -n "$ac_ct_AS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 +$as_echo "$ac_ct_AS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AS" = x; then + AS="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AS=$ac_ct_AS + fi +else + AS="$ac_cv_prog_AS" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DLLTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DLLTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + + ;; +esac + +test -z "$AS" && AS=as + + + + + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if test "${lt_cv_objdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + + + + + + + + + + + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:9799: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:9803: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 +$as_echo "$lt_prog_compiler_pic" >&6; } + + + + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:10138: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:10142: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:10243: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:10247: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:10298: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:10302: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + link_all_deplibs=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + whole_archive_flag_spec='' + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo(void) {} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 +$as_echo "$archive_cmds_need_lc" >&6; } + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 12682 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self_static+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 12778 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec_CXX='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + whole_archive_flag_spec_CXX='' + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + gnu*) + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5]* | *pgcpp\ [1-5]*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_prog_compiler_pic_CXX" >&6; } + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14734: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:14738: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14833: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:14837: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14885: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:14889: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + linux* | k*bsd*-gnu) + link_all_deplibs_CXX=no + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + archive_cmds_need_lc_CXX=no + else + archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_CXX" >&5 +$as_echo "$archive_cmds_need_lc_CXX" >&6; } + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which extension is used for runtime loadable modules" >&5 +$as_echo_n "checking which extension is used for runtime loadable modules... " >&6; } +if test "${libltdl_cv_shlibext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + +module=yes +eval libltdl_cv_shlibext=$shrext_cmds + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_shlibext" >&5 +$as_echo "$libltdl_cv_shlibext" >&6; } +if test -n "$libltdl_cv_shlibext"; then + +cat >>confdefs.h <<_ACEOF +#define LT_MODULE_EXT "$libltdl_cv_shlibext" +_ACEOF + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which variable specifies run-time module search path" >&5 +$as_echo_n "checking which variable specifies run-time module search path... " >&6; } +if test "${lt_cv_module_path_var+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_module_path_var="$shlibpath_var" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_module_path_var" >&5 +$as_echo "$lt_cv_module_path_var" >&6; } +if test -n "$lt_cv_module_path_var"; then + +cat >>confdefs.h <<_ACEOF +#define LT_MODULE_PATH_VAR "$lt_cv_module_path_var" +_ACEOF + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the default library search path" >&5 +$as_echo_n "checking for the default library search path... " >&6; } +if test "${lt_cv_sys_dlsearch_path+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sys_dlsearch_path="$sys_lib_dlsearch_path_spec" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_dlsearch_path" >&5 +$as_echo "$lt_cv_sys_dlsearch_path" >&6; } +if test -n "$lt_cv_sys_dlsearch_path"; then + sys_dlsearch_path= + for dir in $lt_cv_sys_dlsearch_path; do + if test -z "$sys_dlsearch_path"; then + sys_dlsearch_path="$dir" + else + sys_dlsearch_path="$sys_dlsearch_path$PATH_SEPARATOR$dir" + fi + done + +cat >>confdefs.h <<_ACEOF +#define LT_DLSEARCH_PATH "$sys_dlsearch_path" +_ACEOF + +fi + + +LT_DLLOADERS= + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +LIBADD_DLOPEN= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 +$as_echo_n "checking for library containing dlopen... " >&6; } +if test "${ac_cv_search_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dl; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_dlopen=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_dlopen+set}" = set; then : + break +fi +done +if test "${ac_cv_search_dlopen+set}" = set; then : + +else + ac_cv_search_dlopen=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 +$as_echo "$ac_cv_search_dlopen" >&6; } +ac_res=$ac_cv_search_dlopen +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +$as_echo "#define HAVE_LIBDL 1" >>confdefs.h + + if test "$ac_cv_search_dlopen" != "none required" ; then + LIBADD_DLOPEN="-ldl" + fi + libltdl_cv_lib_dl_dlopen="yes" + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if HAVE_DLFCN_H +# include +#endif + +int +main () +{ +dlopen(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +$as_echo "#define HAVE_LIBDL 1" >>confdefs.h + + libltdl_cv_func_dlopen="yes" + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : + +$as_echo "#define HAVE_LIBDL 1" >>confdefs.h + + LIBADD_DLOPEN="-lsvld" libltdl_cv_func_dlopen="yes" + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la" +fi + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes +then + lt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DLOPEN" + for ac_func in dlerror +do : + ac_fn_c_check_func "$LINENO" "dlerror" "ac_cv_func_dlerror" +if test "x$ac_cv_func_dlerror" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLERROR 1 +_ACEOF + +fi +done + + LIBS="$lt_save_LIBS" +fi + + +LIBADD_SHL_LOAD= +ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = x""yes; then : + +$as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h + + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : + +$as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h + + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" + LIBADD_SHL_LOAD="-ldld" +fi + +fi + + + +case $host_os in +darwin[1567].*) +# We only want this for pre-Mac OS X 10.4. + ac_fn_c_check_func "$LINENO" "_dyld_func_lookup" "ac_cv_func__dyld_func_lookup" +if test "x$ac_cv_func__dyld_func_lookup" = x""yes; then : + +$as_echo "#define HAVE_DYLD 1" >>confdefs.h + + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la" +fi + + ;; +beos*) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" + ;; +cygwin* | mingw* | os2* | pw32*) + ac_fn_c_check_decl "$LINENO" "cygwin_conv_path" "ac_cv_have_decl_cygwin_conv_path" "#include +" +if test "x$ac_cv_have_decl_cygwin_conv_path" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_CYGWIN_CONV_PATH $ac_have_decl +_ACEOF + + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : + +$as_echo "#define HAVE_DLD 1" >>confdefs.h + + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la" +fi + + + + +LT_DLPREOPEN= +if test -n "$LT_DLLOADERS" +then + for lt_loader in $LT_DLLOADERS; do + LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " + done + +$as_echo "#define HAVE_LIBDLLOADER 1" >>confdefs.h + +fi + + +LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ prefix in compiled symbols" >&5 +$as_echo_n "checking for _ prefix in compiled symbols... " >&6; } +if test "${lt_cv_sys_symbol_underscore+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext <<_LT_EOF +void nm_test_func(){} +int main(){nm_test_func;return 0;} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + ac_nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + lt_cv_sys_symbol_underscore=yes + else + if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&5 + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "configure: failed program was:" >&5 + cat conftest.c >&5 + fi + rm -rf conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_symbol_underscore" >&5 +$as_echo "$lt_cv_sys_symbol_underscore" >&6; } + sys_symbol_underscore=$lt_cv_sys_symbol_underscore + + +if test x"$lt_cv_sys_symbol_underscore" = xyes; then + if test x"$libltdl_cv_func_dlopen" = xyes || + test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have to add an underscore for dlsym" >&5 +$as_echo_n "checking whether we have to add an underscore for dlsym... " >&6; } +if test "${libltdl_cv_need_uscore+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + libltdl_cv_need_uscore=unknown + save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DLOPEN" + if test "$cross_compiling" = yes; then : + libltdl_cv_need_uscore=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 16297 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) libltdl_cv_need_uscore=no ;; + x$lt_dlneed_uscore) libltdl_cv_need_uscore=yes ;; + x$lt_dlunknown|x*) ;; + esac + else : + # compilation failed + + fi +fi +rm -fr conftest* + + LIBS="$save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_need_uscore" >&5 +$as_echo "$libltdl_cv_need_uscore" >&6; } + fi +fi + +if test x"$libltdl_cv_need_uscore" = xyes; then + +$as_echo "#define NEED_USCORE 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether deplibs are loaded by dlopen" >&5 +$as_echo_n "checking whether deplibs are loaded by dlopen... " >&6; } +if test "${lt_cv_sys_dlopen_deplibs+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # PORTME does your system automatically load deplibs for dlopen? + # or its logical equivalent (e.g. shl_load for HP-UX < 11) + # For now, we just catch OSes we know something about -- in the + # future, we'll try test this programmatically. + lt_cv_sys_dlopen_deplibs=unknown + case $host_os in + aix3*|aix4.1.*|aix4.2.*) + # Unknown whether this is true for these versions of AIX, but + # we want this `case' here to explicitly catch those versions. + lt_cv_sys_dlopen_deplibs=unknown + ;; + aix[4-9]*) + lt_cv_sys_dlopen_deplibs=yes + ;; + amigaos*) + case $host_cpu in + powerpc) + lt_cv_sys_dlopen_deplibs=no + ;; + esac + ;; + darwin*) + # Assuming the user has installed a libdl from somewhere, this is true + # If you are looking for one http://www.opendarwin.org/projects/dlcompat + lt_cv_sys_dlopen_deplibs=yes + ;; + freebsd* | dragonfly*) + lt_cv_sys_dlopen_deplibs=yes + ;; + gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) + # GNU and its variants, using gnu ld.so (Glibc) + lt_cv_sys_dlopen_deplibs=yes + ;; + hpux10*|hpux11*) + lt_cv_sys_dlopen_deplibs=yes + ;; + interix*) + lt_cv_sys_dlopen_deplibs=yes + ;; + irix[12345]*|irix6.[01]*) + # Catch all versions of IRIX before 6.2, and indicate that we don't + # know how it worked for any of those versions. + lt_cv_sys_dlopen_deplibs=unknown + ;; + irix*) + # The case above catches anything before 6.2, and it's known that + # at 6.2 and later dlopen does load deplibs. + lt_cv_sys_dlopen_deplibs=yes + ;; + netbsd* | netbsdelf*-gnu) + lt_cv_sys_dlopen_deplibs=yes + ;; + openbsd*) + lt_cv_sys_dlopen_deplibs=yes + ;; + osf[1234]*) + # dlopen did load deplibs (at least at 4.x), but until the 5.x series, + # it did *not* use an RPATH in a shared library to find objects the + # library depends on, so we explicitly say `no'. + lt_cv_sys_dlopen_deplibs=no + ;; + osf5.0|osf5.0a|osf5.1) + # dlopen *does* load deplibs and with the right loader patch applied + # it even uses RPATH in a shared library to search for shared objects + # that the library depends on, but there's no easy way to know if that + # patch is installed. Since this is the case, all we can really + # say is unknown -- it depends on the patch being installed. If + # it is, this changes to `yes'. Without it, it would be `no'. + lt_cv_sys_dlopen_deplibs=unknown + ;; + osf*) + # the two cases above should catch all versions of osf <= 5.1. Read + # the comments above for what we know about them. + # At > 5.1, deplibs are loaded *and* any RPATH in a shared library + # is used to find them so we can finally say `yes'. + lt_cv_sys_dlopen_deplibs=yes + ;; + qnx*) + lt_cv_sys_dlopen_deplibs=yes + ;; + solaris*) + lt_cv_sys_dlopen_deplibs=yes + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_dlopen_deplibs" >&5 +$as_echo "$lt_cv_sys_dlopen_deplibs" >&6; } +if test "$lt_cv_sys_dlopen_deplibs" != yes; then + +$as_echo "#define LTDL_DLOPEN_DEPLIBS 1" >>confdefs.h + +fi + +: + +for ac_header in argz.h +do : + ac_fn_c_check_header_compile "$LINENO" "argz.h" "ac_cv_header_argz_h" "$ac_includes_default +" +if test "x$ac_cv_header_argz_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ARGZ_H 1 +_ACEOF + +fi + +done + + +ac_fn_c_check_type "$LINENO" "error_t" "ac_cv_type_error_t" "#if defined(HAVE_ARGZ_H) +# include +#endif +" +if test "x$ac_cv_type_error_t" = x""yes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_ERROR_T 1 +_ACEOF + + +else + +$as_echo "#define error_t int" >>confdefs.h + + +$as_echo "#define __error_t_defined 1" >>confdefs.h + +fi + + +ARGZ_H= +for ac_func in argz_add argz_append argz_count argz_create_sep argz_insert \ + argz_next argz_stringify +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + ARGZ_H=argz.h; + + _LT_LIBOBJS="$_LT_LIBOBJS argz.$ac_objext" + +fi +done + + +if test -z "$ARGZ_H"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if argz actually works" >&5 +$as_echo_n "checking if argz actually works... " >&6; } +if test "${lt_cv_sys_argz_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $host_os in #( + *cygwin*) + lt_cv_sys_argz_works=no + if test "$cross_compiling" != no; then + lt_cv_sys_argz_works="guessing no" + else + lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' + save_IFS=$IFS + IFS=-. + set x `uname -r | sed -e "$lt_sed_extract_leading_digits"` + IFS=$save_IFS + lt_os_major=${2-0} + lt_os_minor=${3-0} + lt_os_micro=${4-0} + if test "$lt_os_major" -gt 1 \ + || { test "$lt_os_major" -eq 1 \ + && { test "$lt_os_minor" -gt 5 \ + || { test "$lt_os_minor" -eq 5 \ + && test "$lt_os_micro" -gt 24; }; }; }; then + lt_cv_sys_argz_works=yes + fi + fi + ;; #( + *) lt_cv_sys_argz_works=yes ;; + esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_argz_works" >&5 +$as_echo "$lt_cv_sys_argz_works" >&6; } + if test $lt_cv_sys_argz_works = yes; then : + +$as_echo "#define HAVE_WORKING_ARGZ 1" >>confdefs.h + +else + ARGZ_H=argz.h + + + _LT_LIBOBJS="$_LT_LIBOBJS argz.$ac_objext" + +fi +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libtool supports -dlopen/-dlpreopen" >&5 +$as_echo_n "checking whether libtool supports -dlopen/-dlpreopen... " >&6; } +if test "${libltdl_cv_preloaded_symbols+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$lt_cv_sys_global_symbol_pipe"; then + libltdl_cv_preloaded_symbols=yes + else + libltdl_cv_preloaded_symbols=no + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_preloaded_symbols" >&5 +$as_echo "$libltdl_cv_preloaded_symbols" >&6; } +if test x"$libltdl_cv_preloaded_symbols" = xyes; then + +$as_echo "#define HAVE_PRELOADED_SYMBOLS 1" >>confdefs.h + +fi + + + +# Set options + + + + + + + + + + + + +# Check whether --with-included_ltdl was given. +if test "${with_included_ltdl+set}" = set; then : + withval=$with_included_ltdl; +fi + + +if test "x$with_included_ltdl" != xyes; then + # We are not being forced to use the included libltdl sources, so + # decide whether there is a useful installed version we can use. + ac_fn_c_check_header_compile "$LINENO" "ltdl.h" "ac_cv_header_ltdl_h" "$ac_includes_default + +" +if test "x$ac_cv_header_ltdl_h" = x""yes; then : + ac_fn_c_check_decl "$LINENO" "lt_dlinterface_register" "ac_cv_have_decl_lt_dlinterface_register" "$ac_includes_default + #include +" +if test "x$ac_cv_have_decl_lt_dlinterface_register" = x""yes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lt_dladvise_preload in -lltdl" >&5 +$as_echo_n "checking for lt_dladvise_preload in -lltdl... " >&6; } +if test "${ac_cv_lib_ltdl_lt_dladvise_preload+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lltdl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char lt_dladvise_preload (); +int +main () +{ +return lt_dladvise_preload (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ltdl_lt_dladvise_preload=yes +else + ac_cv_lib_ltdl_lt_dladvise_preload=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ltdl_lt_dladvise_preload" >&5 +$as_echo "$ac_cv_lib_ltdl_lt_dladvise_preload" >&6; } +if test "x$ac_cv_lib_ltdl_lt_dladvise_preload" = x""yes; then : + with_included_ltdl=no +else + with_included_ltdl=yes +fi + +else + with_included_ltdl=yes +fi + +else + with_included_ltdl=yes +fi + + +fi + + + + + + + + + +# Check whether --with-ltdl_include was given. +if test "${with_ltdl_include+set}" = set; then : + withval=$with_ltdl_include; +fi + + +if test -n "$with_ltdl_include"; then + if test -f "$with_ltdl_include/ltdl.h"; then : + else + as_fn_error $? "invalid ltdl include directory: \`$with_ltdl_include'" "$LINENO" 5 + fi +else + with_ltdl_include=no +fi + + +# Check whether --with-ltdl_lib was given. +if test "${with_ltdl_lib+set}" = set; then : + withval=$with_ltdl_lib; +fi + + +if test -n "$with_ltdl_lib"; then + if test -f "$with_ltdl_lib/libltdl.la"; then : + else + as_fn_error $? "invalid ltdl library directory: \`$with_ltdl_lib'" "$LINENO" 5 + fi +else + with_ltdl_lib=no +fi + +case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in + ,yes,no,no,) + case $enable_ltdl_convenience in + no) as_fn_error $? "this package needs a convenience libltdl" "$LINENO" 5 ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; +esac +LIBLTDL='${top_build_prefix}'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdlc.la" +LTDLDEPS=$LIBLTDL +LTDLINCL='-I${top_srcdir}'"${lt_ltdl_dir+/$lt_ltdl_dir}" + + + + + +# For backwards non-gettext consistent compatibility... +INCLTDL="$LTDLINCL" + + + ;; + ,no,no,no,) + # If the included ltdl is not to be used, then use the + # preinstalled libltdl we found. + +$as_echo "#define HAVE_LTDL 1" >>confdefs.h + + LIBLTDL=-lltdl + LTDLDEPS= + LTDLINCL= + ;; + ,no*,no,*) + as_fn_error $? "\`--with-ltdl-include' and \`--with-ltdl-lib' options must be used together" "$LINENO" 5 + ;; + *) with_included_ltdl=no + LIBLTDL="-L$with_ltdl_lib -lltdl" + LTDLDEPS= + LTDLINCL="-I$with_ltdl_include" + ;; +esac +INCLTDL="$LTDLINCL" + +# Report our decision... +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find libltdl headers" >&5 +$as_echo_n "checking where to find libltdl headers... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LTDLINCL" >&5 +$as_echo "$LTDLINCL" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find libltdl library" >&5 +$as_echo_n "checking where to find libltdl library... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBLTDL" >&5 +$as_echo "$LIBLTDL" >&6; } + + + +# Check whether --enable-ltdl-install was given. +if test "${enable_ltdl_install+set}" = set; then : + enableval=$enable_ltdl_install; +fi + + +case ,${enable_ltdl_install},${enable_ltdl_convenience} in + *yes*) ;; + *) enable_ltdl_convenience=yes ;; +esac + + if test x"${enable_ltdl_install-no}" != xno; then + INSTALL_LTDL_TRUE= + INSTALL_LTDL_FALSE='#' +else + INSTALL_LTDL_TRUE='#' + INSTALL_LTDL_FALSE= +fi + + if test x"${enable_ltdl_convenience-no}" != xno; then + CONVENIENCE_LTDL_TRUE= + CONVENIENCE_LTDL_FALSE='#' +else + CONVENIENCE_LTDL_TRUE='#' + CONVENIENCE_LTDL_FALSE= +fi + + + + subdirs="$subdirs libltdl" + + + + + +# In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS +# the user used. This is so that ltdl.h can pick up the parent projects +# config.h file, The first file in AC_CONFIG_HEADERS must contain the +# definitions required by ltdl.c. +# FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). + + + +for ac_header in unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_func in closedir opendir readdir +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + + + _LT_LIBOBJS="$_LT_LIBOBJS lt__dirent.$ac_objext" + +fi +done + +for ac_func in strlcat strlcpy +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + + + _LT_LIBOBJS="$_LT_LIBOBJS lt__strl.$ac_objext" + +fi +done + + + +cat >>confdefs.h <<_ACEOF +#define LT_LIBEXT "$libext" +_ACEOF + + +name=ltdl +LTDLOPEN=`eval "\\$ECHO \"$libname_spec\""` + + + + + + + + +# Only expand once: + + + + + + +# large file support +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if test "${ac_cv_sys_largefile_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if test "${ac_cv_sys_file_offset_bits+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if test "${ac_cv_sys_large_files+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 +$as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } +if test "${ac_cv_sys_largefile_source+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include /* for off_t */ + #include +int +main () +{ +int (*fp) (FILE *, off_t, int) = fseeko; + return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_sys_largefile_source=no; break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGEFILE_SOURCE 1 +#include /* for off_t */ + #include +int +main () +{ +int (*fp) (FILE *, off_t, int) = fseeko; + return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_sys_largefile_source=1; break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_cv_sys_largefile_source=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 +$as_echo "$ac_cv_sys_largefile_source" >&6; } +case $ac_cv_sys_largefile_source in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source +_ACEOF +;; +esac +rm -rf conftest* + +# We used to try defining _XOPEN_SOURCE=500 too, to work around a bug +# in glibc 2.1.3, but that breaks too many other things. +# If you want fseeko and ftello with glibc, upgrade to a fixed glibc. +if test $ac_cv_sys_largefile_source != unknown; then + +$as_echo "#define HAVE_FSEEKO 1" >>confdefs.h + +fi + + + +if test "$enable_shared" = "no" +then + as_fn_error $? "GNUnet only works with shared libraries. Sorry." "$LINENO" 5 +fi + +CFLAGS="-Wall $CFLAGS" +# use '-fno-strict-aliasing', but only if the compiler can take it +if gcc -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; +then + CFLAGS="-fno-strict-aliasing $CFLAGS" +fi + +# Use Linux interface name unless the OS has a different preference +DEFAULT_INTERFACE="\"eth0\"" + +# Check system type +case "$host_os" in +*darwin* | *rhapsody* | *macosx*) + +cat >>confdefs.h <<_ACEOF +#define DARWIN 1 +_ACEOF + + CPPFLAGS="-D_APPLE_C_SOURCE $CPPFLAGS" + CFLAGS="-no-cpp-precomp -fno-common $CFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: The VPN application cannot be compiled on your OS" >&5 +$as_echo "$as_me: WARNING: The VPN application cannot be compiled on your OS" >&2;} + build_target="darwin" + DEFAULT_INTERFACE="\"en0\"" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +linux*) + +cat >>confdefs.h <<_ACEOF +#define LINUX 1 +_ACEOF + + build_target="linux" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 +$as_echo_n "checking for X... " >&6; } + + +# Check whether --with-x was given. +if test "${with_x+set}" = set; then : + withval=$with_x; +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + case $x_includes,$x_libraries in #( + *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5 ;; #( + *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=no ac_x_libraries=no +rm -f -r conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + cat >Imakefile <<'_ACEOF' +incroot: + @echo incroot='${INCROOT}' +usrlibdir: + @echo usrlibdir='${USRLIBDIR}' +libdir: + @echo libdir='${LIBDIR}' +_ACEOF + if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. + for ac_var in incroot usrlibdir libdir; do + eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" + done + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl dylib la dll; do + if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && + test -f "$ac_im_libdir/libX11.$ac_extension"; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case $ac_im_incroot in + /usr/include) ac_x_includes= ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /usr/lib64 | /lib | /lib64) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -f -r conftest.dir +fi + +# Standard set of common directories for X headers. +# Check X11 before X11Rn because it is often a symlink to the current release. +ac_x_header_dirs=' +/usr/X11/include +/usr/X11R7/include +/usr/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R7 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R7/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/usr/local/include/X11R7 +/usr/local/include/X11R6 +/usr/local/include/X11R5 +/usr/local/include/X11R4 + +/usr/X386/include +/usr/x386/include +/usr/XFree86/include/X11 + +/usr/include +/usr/local/include +/usr/unsupported/include +/usr/athena/include +/usr/local/x11r5/include +/usr/lpp/Xamples/include + +/usr/openwin/include +/usr/openwin/share/include' + +if test "$ac_x_includes" = no; then + # Guess where to find include files, by looking for Xlib.h. + # First, try using that file with no special directory specified. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # We can compile using X headers with no special include directory. +ac_x_includes= +else + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Xlib.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi +rm -f conftest.err conftest.i conftest.$ac_ext +fi # $ac_x_includes = no + +if test "$ac_x_libraries" = no; then + # Check for the libraries. + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS=$LIBS + LIBS="-lX11 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +XrmInitialize () + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + LIBS=$ac_save_LIBS +for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +do + # Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl dylib la dll; do + if test -r "$ac_dir/libX11.$ac_extension"; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +case $ac_x_includes,$ac_x_libraries in #( + no,* | *,no | *\'*) + # Didn't find X, or a directory has "'" in its name. + ac_cv_have_x="have_x=no";; #( + *) + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$ac_x_includes'\ + ac_x_libraries='$ac_x_libraries'" +esac +fi +;; #( + *) have_x=yes;; + esac + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 +$as_echo "$have_x" >&6; } + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$x_includes'\ + ac_x_libraries='$x_libraries'" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 +$as_echo "libraries $x_libraries, headers $x_includes" >&6; } +fi + +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + +$as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h + + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 +$as_echo_n "checking whether -R must be followed by a space... " >&6; } + ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" + ac_xsave_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + X_LIBS="$X_LIBS -R$x_libraries" +else + LIBS="$ac_xsave_LIBS -R $x_libraries" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + X_LIBS="$X_LIBS -R $x_libraries" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 +$as_echo "neither works" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_c_werror_flag=$ac_xsave_c_werror_flag + LIBS=$ac_xsave_LIBS + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn Johnson says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And Karl Berry says + # the Alpha needs dnet_stub (dnet does not exist). + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XOpenDisplay (); +int +main () +{ +return XOpenDisplay (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } +if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dnet_dnet_ntoa=yes +else + ac_cv_lib_dnet_dnet_ntoa=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_dnet_ntoa" = x""yes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" +fi + + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } +if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet_stub $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dnet_stub_dnet_ntoa=yes +else + ac_cv_lib_dnet_stub_dnet_ntoa=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = x""yes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" +fi + + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_xsave_LIBS" + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to T.E. Dickey. + # The functions gethostbyname, getservbyname, and inet_addr are + # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. + ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" +if test "x$ac_cv_func_gethostbyname" = x""yes; then : + +fi + + if test $ac_cv_func_gethostbyname = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nsl_gethostbyname=yes +else + ac_cv_lib_nsl_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" +fi + + if test $ac_cv_lib_nsl_gethostbyname = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 +$as_echo_n "checking for gethostbyname in -lbsd... " >&6; } +if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_bsd_gethostbyname=yes +else + ac_cv_lib_bsd_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 +$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } +if test "x$ac_cv_lib_bsd_gethostbyname" = x""yes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" +fi + + fi + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says Simon Leinen: it contains gethostby* + # variants that don't use the name server (or something). -lsocket + # must be given before -lnsl if both are needed. We assume that + # if connect needs -lnsl, so does gethostbyname. + ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" +if test "x$ac_cv_func_connect" = x""yes; then : + +fi + + if test $ac_cv_func_connect = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 +$as_echo_n "checking for connect in -lsocket... " >&6; } +if test "${ac_cv_lib_socket_connect+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char connect (); +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_connect=yes +else + ac_cv_lib_socket_connect=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 +$as_echo "$ac_cv_lib_socket_connect" >&6; } +if test "x$ac_cv_lib_socket_connect" = x""yes; then : + X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" +fi + + fi + + # Guillermo Gomez says -lposix is necessary on A/UX. + ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" +if test "x$ac_cv_func_remove" = x""yes; then : + +fi + + if test $ac_cv_func_remove = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 +$as_echo_n "checking for remove in -lposix... " >&6; } +if test "${ac_cv_lib_posix_remove+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lposix $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char remove (); +int +main () +{ +return remove (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_posix_remove=yes +else + ac_cv_lib_posix_remove=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 +$as_echo "$ac_cv_lib_posix_remove" >&6; } +if test "x$ac_cv_lib_posix_remove" = x""yes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" +fi + + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" +if test "x$ac_cv_func_shmat" = x""yes; then : + +fi + + if test $ac_cv_func_shmat = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 +$as_echo_n "checking for shmat in -lipc... " >&6; } +if test "${ac_cv_lib_ipc_shmat+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lipc $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shmat (); +int +main () +{ +return shmat (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ipc_shmat=yes +else + ac_cv_lib_ipc_shmat=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 +$as_echo "$ac_cv_lib_ipc_shmat" >&6; } +if test "x$ac_cv_lib_ipc_shmat" = x""yes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" +fi + + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS=$LDFLAGS + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # John Interrante, Karl Berry + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 +$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } +if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char IceConnectionNumber (); +int +main () +{ +return IceConnectionNumber (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ICE_IceConnectionNumber=yes +else + ac_cv_lib_ICE_IceConnectionNumber=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 +$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } +if test "x$ac_cv_lib_ICE_IceConnectionNumber" = x""yes; then : + X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" +fi + + LDFLAGS=$ac_save_LDFLAGS + +fi + + ;; +freebsd*) + +cat >>confdefs.h <<_ACEOF +#define SOMEBSD 1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define FREEBSD 1 +_ACEOF + + CFLAGS="-D_THREAD_SAFE $CFLAGS" + build_target="freebsd" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +openbsd*) + +cat >>confdefs.h <<_ACEOF +#define SOMEBSD 1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define OPENBSD 1 +_ACEOF + + LIBS=`echo $LIBS | sed -e "s/-ldl//"` + build_target="openbsd" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +netbsd*) + +cat >>confdefs.h <<_ACEOF +#define SOMEBSD 1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define NETBSD 1 +_ACEOF + + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +*solaris*) + +cat >>confdefs.h <<_ACEOF +#define SOLARIS 1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define _REENTRANT 1 +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for res_init in -lresolv" >&5 +$as_echo_n "checking for res_init in -lresolv... " >&6; } +if test "${ac_cv_lib_resolv_res_init+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresolv $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char res_init (); +int +main () +{ +return res_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_resolv_res_init=yes +else + ac_cv_lib_resolv_res_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_res_init" >&5 +$as_echo "$ac_cv_lib_resolv_res_init" >&6; } +if test "x$ac_cv_lib_resolv_res_init" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBRESOLV 1 +_ACEOF + + LIBS="-lresolv $LIBS" + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lrt" >&5 +$as_echo_n "checking for nanosleep in -lrt... " >&6; } +if test "${ac_cv_lib_rt_nanosleep+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char nanosleep (); +int +main () +{ +return nanosleep (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_nanosleep=yes +else + ac_cv_lib_rt_nanosleep=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_nanosleep" >&5 +$as_echo "$ac_cv_lib_rt_nanosleep" >&6; } +if test "x$ac_cv_lib_rt_nanosleep" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBRT 1 +_ACEOF + + LIBS="-lrt $LIBS" + +fi + + build_target="solaris" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +*arm-linux*) + +cat >>confdefs.h <<_ACEOF +#define LINUX 1 +_ACEOF + + CFLAGS="-D_REENTRANT -fPIC -pipe $CFLAGS" + build_target="linux" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +*cygwin*) + +cat >>confdefs.h <<_ACEOF +#define CYGWIN 1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define WINDOWS 1 +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettext in -lintl" >&5 +$as_echo_n "checking for gettext in -lintl... " >&6; } +if test "${ac_cv_lib_intl_gettext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lintl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gettext (); +int +main () +{ +return gettext (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_intl_gettext=yes +else + ac_cv_lib_intl_gettext=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_gettext" >&5 +$as_echo "$ac_cv_lib_intl_gettext" >&6; } +if test "x$ac_cv_lib_intl_gettext" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBINTL 1 +_ACEOF + + LIBS="-lintl $LIBS" + +fi + + LDFLAGS="$LDFLAGS -no-undefined" + CFLAGS="-mms-bitfields $CFLAGS" + build_target="cygwin" + LIBPREFIX=lib + DLLDIR=bin + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + UNIXONLY="" + ;; +*mingw*) + +cat >>confdefs.h <<_ACEOF +#define MINGW 1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define WINDOWS 1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define _WIN32 1 +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettext in -lintl" >&5 +$as_echo_n "checking for gettext in -lintl... " >&6; } +if test "${ac_cv_lib_intl_gettext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lintl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gettext (); +int +main () +{ +return gettext (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_intl_gettext=yes +else + ac_cv_lib_intl_gettext=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_gettext" >&5 +$as_echo "$ac_cv_lib_intl_gettext" >&6; } +if test "x$ac_cv_lib_intl_gettext" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBINTL 1 +_ACEOF + + LIBS="-lintl $LIBS" + +fi + + LDFLAGS="$LDFLAGS -Wl,-no-undefined -Wl,--export-all-symbols" + LIBS="$LIBS -lws2_32 -lplibc -lgnurx -lole32" + CFLAGS="-mms-bitfields $CFLAGS" + CPPFLAGS="-D_WIN32_WINNT=0x0501 $CPPFLAGS" + build_target="mingw" + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + LIBPREFIX=lib + DLLDIR=bin + UNIXONLY="" + ;; +*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Unrecognised OS $host_os" >&5 +$as_echo "Unrecognised OS $host_os" >&6; } + +cat >>confdefs.h <<_ACEOF +#define OTHEROS 1 +_ACEOF + + UNIXONLY="" +;; +esac + +cat >>confdefs.h <<_ACEOF +#define GNUNET_DEFAULT_INTERFACE $DEFAULT_INTERFACE +_ACEOF + + + +# Disable TCP-based IPC on systems that support UNIX domain +# sockets in default configuratin: + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for build target" >&5 +$as_echo_n "checking for build target... " >&6; } + if test "$build_target" = "darwin"; then + DARWIN_TRUE= + DARWIN_FALSE='#' +else + DARWIN_TRUE='#' + DARWIN_FALSE= +fi + + if test "$build_target" = "cygwin"; then + CYGWIN_TRUE= + CYGWIN_FALSE='#' +else + CYGWIN_TRUE='#' + CYGWIN_FALSE= +fi + + if test "$build_target" = "mingw"; then + MINGW_TRUE= + MINGW_FALSE='#' +else + MINGW_TRUE='#' + MINGW_FALSE= +fi + + if test "$build_target" = "solaris"; then + SOLARIS_TRUE= + SOLARIS_FALSE='#' +else + SOLARIS_TRUE='#' + SOLARIS_FALSE= +fi + + if test "$build_target" = "freebsd"; then + XFREEBSD_TRUE= + XFREEBSD_FALSE='#' +else + XFREEBSD_TRUE='#' + XFREEBSD_FALSE= +fi + + if test "$build_target" = "openbsd"; then + OPENBSD_TRUE= + OPENBSD_FALSE='#' +else + OPENBSD_TRUE='#' + OPENBSD_FALSE= +fi + + if test "$build_target" = "linux"; then + LINUX_TRUE= + LINUX_FALSE='#' +else + LINUX_TRUE='#' + LINUX_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $build_target" >&5 +$as_echo "$build_target" >&6; } + + if false; then + am__fastdepOBJC_TRUE= + am__fastdepOBJC_FALSE='#' +else + am__fastdepOBJC_TRUE='#' + am__fastdepOBJC_FALSE= +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether unaligned 64-bit access works" >&5 +$as_echo_n "checking whether unaligned 64-bit access works... " >&6; } +if test "${ac_cv_unaligned_64_access+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + ac_cv_unaligned_64_access=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +struct S { int a,b,c;}; +int +main () +{ +struct S s = {0,0,0}; long long * p = (long long *) &s.b; + void *bp = malloc (50); + long long x = *p; + long long *be = (long long*) &bp1; + long long y = *be; + return (int) x*y; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_unaligned_64_access=yes +else + ac_cv_unaligned_64_access=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_unaligned_64_access" >&5 +$as_echo "$ac_cv_unaligned_64_access" >&6; } + case "$ac_cv_unaligned_64_access" in + *yes) value=1;; + *) value=0;; + esac + +cat >>confdefs.h <<_ACEOF +#define HAVE_UNALIGNED_64_ACCESS $value +_ACEOF + + + +# some other checks for standard libs +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5 +$as_echo_n "checking for library containing gethostbyname... " >&6; } +if test "${ac_cv_search_gethostbyname+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +for ac_lib in '' nsl ws2_32; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_gethostbyname=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_gethostbyname+set}" = set; then : + break +fi +done +if test "${ac_cv_search_gethostbyname+set}" = set; then : + +else + ac_cv_search_gethostbyname=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5 +$as_echo "$ac_cv_search_gethostbyname" >&6; } +ac_res=$ac_cv_search_gethostbyname +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 +$as_echo_n "checking for socket in -lsocket... " >&6; } +if test "${ac_cv_lib_socket_socket+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char socket (); +int +main () +{ +return socket (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_socket=yes +else + ac_cv_lib_socket_socket=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 +$as_echo "$ac_cv_lib_socket_socket" >&6; } +if test "x$ac_cv_lib_socket_socket" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for log in -lm" >&5 +$as_echo_n "checking for log in -lm... " >&6; } +if test "${ac_cv_lib_m_log+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char log (); +int +main () +{ +return log (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_log=yes +else + ac_cv_lib_m_log=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_log" >&5 +$as_echo "$ac_cv_lib_m_log" >&6; } +if test "x$ac_cv_lib_m_log" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBM 1 +_ACEOF + + LIBS="-lm $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getloadavg in -lc" >&5 +$as_echo_n "checking for getloadavg in -lc... " >&6; } +if test "${ac_cv_lib_c_getloadavg+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char getloadavg (); +int +main () +{ +return getloadavg (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_c_getloadavg=yes +else + ac_cv_lib_c_getloadavg=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_getloadavg" >&5 +$as_echo "$ac_cv_lib_c_getloadavg" >&6; } +if test "x$ac_cv_lib_c_getloadavg" = x""yes; then : + +$as_echo "#define HAVE_GETLOADAVG 1" >>confdefs.h + +fi + + +# 'save' libs; only those libs found so far will be +# linked against _everywhere_. For the others, we +# will be more selective! +SAVE_LIBS=$LIBS + +# libgnurx (regex library for W32) +gnurx=0 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for regexec in -lgnurx" >&5 +$as_echo_n "checking for regexec in -lgnurx... " >&6; } +if test "${ac_cv_lib_gnurx_regexec+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgnurx $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char regexec (); +int +main () +{ +return regexec (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_gnurx_regexec=yes +else + ac_cv_lib_gnurx_regexec=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnurx_regexec" >&5 +$as_echo "$ac_cv_lib_gnurx_regexec" >&6; } +if test "x$ac_cv_lib_gnurx_regexec" = x""yes; then : + gnurx=1 +fi + +if test "x$gnurx" = "x0" -a "x$build_target" = "xmingw" +then + as_fn_error $? "on W32 GNUnet needs libgnurx" "$LINENO" 5 +fi + +# libgcrypt +gcrypt=0 + +# Check whether --with-libgcrypt-prefix was given. +if test "${with_libgcrypt_prefix+set}" = set; then : + withval=$with_libgcrypt_prefix; libgcrypt_config_prefix="$withval" +else + libgcrypt_config_prefix="" +fi + + if test x$libgcrypt_config_prefix != x ; then + if test x${LIBGCRYPT_CONFIG+set} != xset ; then + LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config + fi + fi + + # Extract the first word of "libgcrypt-config", so it can be a program name with args. +set dummy libgcrypt-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_LIBGCRYPT_CONFIG+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $LIBGCRYPT_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_LIBGCRYPT_CONFIG="$LIBGCRYPT_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_LIBGCRYPT_CONFIG" && ac_cv_path_LIBGCRYPT_CONFIG="no" + ;; +esac +fi +LIBGCRYPT_CONFIG=$ac_cv_path_LIBGCRYPT_CONFIG +if test -n "$LIBGCRYPT_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGCRYPT_CONFIG" >&5 +$as_echo "$LIBGCRYPT_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + tmp=1.2.0 + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_libgcrypt_api=0 + min_libgcrypt_version="$tmp" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBGCRYPT - version >= $min_libgcrypt_version" >&5 +$as_echo_n "checking for LIBGCRYPT - version >= $min_libgcrypt_version... " >&6; } + ok=no + if test "$LIBGCRYPT_CONFIG" != "no" ; then + req_major=`echo $min_libgcrypt_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + req_minor=`echo $min_libgcrypt_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + req_micro=`echo $min_libgcrypt_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version` + major=`echo $libgcrypt_config_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1/'` + minor=`echo $libgcrypt_config_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\2/'` + micro=`echo $libgcrypt_config_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\3/'` + if test "$major" -gt "$req_major"; then + ok=yes + else + if test "$major" -eq "$req_major"; then + if test "$minor" -gt "$req_minor"; then + ok=yes + else + if test "$minor" -eq "$req_minor"; then + if test "$micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + if test $ok = yes; then + # If we have a recent libgcrypt, we should also check that the + # API is compatible + if test "$req_libgcrypt_api" -gt 0 ; then + tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking LIBGCRYPT API version" >&5 +$as_echo_n "checking LIBGCRYPT API version... " >&6; } + if test "$req_libgcrypt_api" -eq "$tmp" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: okay" >&5 +$as_echo "okay" >&6; } + else + ok=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: does not match (want=$req_libgcrypt_api got=$tmp)" >&5 +$as_echo "does not match (want=$req_libgcrypt_api got=$tmp)" >&6; } + fi + fi + fi + fi + if test $ok = yes; then + LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags` + LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs` + gcrypt=1 + else + LIBGCRYPT_CFLAGS="" + LIBGCRYPT_LIBS="" + : + fi + + + +ac_fn_c_check_decl "$LINENO" "gcry_mpi_lshift" "ac_cv_have_decl_gcry_mpi_lshift" "#include +" +if test "x$ac_cv_have_decl_gcry_mpi_lshift" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_GCRY_MPI_LSHIFT $ac_have_decl +_ACEOF + + +if test $gcrypt = 0 +then + as_fn_error $? "GNUnet needs libgcrypt" "$LINENO" 5 +fi + +# Adam shostack suggests the following for Windows: +# -D_FORTIFY_SOURCE=2 -fstack-protector-all +# Check whether --enable-gcc-hardening was given. +if test "${enable_gcc_hardening+set}" = set; then : + enableval=$enable_gcc_hardening; if test x$enableval = xyes; then + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector-all" + CFLAGS="$CFLAGS -fwrapv -fPIE -Wstack-protector" + CFLAGS="$CFLAGS --param ssp-buffer-size=1" + LDFLAGS="$LDFLAGS -pie" +fi +fi + + + +# Linker hardening options +# Currently these options are ELF specific - you can't use this with MacOSX +# Check whether --enable-linker-hardening was given. +if test "${enable_linker_hardening+set}" = set; then : + enableval=$enable_linker_hardening; if test x$enableval = xyes; then + LDFLAGS="$LDFLAGS -z relro -z now" +fi +fi + + + +extra_logging=GNUNET_NO +# Check whether --enable-logging was given. +if test "${enable_logging+set}" = set; then : + enableval=$enable_logging; if test "x$enableval" = "xyes"; then : + +elif test "x$enableval" = "xno"; then : + +$as_echo "#define GNUNET_CULL_LOGGING /**/" >>confdefs.h + +elif test "x$enableval" = "xverbose"; then : + extra_logging=GNUNET_YES + test "x$enableval" = "xveryverbose" +else + extra_logging=\(GNUNET_YES+1\) +fi + +fi + + +cat >>confdefs.h <<_ACEOF +#define GNUNET_EXTRA_LOGGING $extra_logging +_ACEOF + + +if test $build = $target +then +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working HMAC" >&5 +$as_echo_n "checking for working HMAC... " >&6; } +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +LIBS="$LIBS $LIBGCRYPT_LIBS" +CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS" +if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5 ; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include +int +main () +{ + + gcry_md_hd_t mac; + + unsigned char data[] = { 0xbf, 0x16, 0x6e, 0x46, 0x3a, 0x6c, 0xf3, 0x93, 0xa7, 0x72, + 0x11, 0xa1, 0xdc, 0x0b, 0x07, 0xdb, 0x1a, 0x5e, 0xd9, 0xb9, 0x81, 0xbe, + 0xea, 0xe4, 0x31, 0x5f, 0x24, 0xff, 0xfe, 0x50, 0x8a, 0xde }; + unsigned char key[] = { 0xfc, 0x62, 0x76, 0x35 }; + unsigned char result[] = {0xa2, 0xb, 0x1, 0xd9, 0xc0, 0x8b, 0x5a, 0x12, 0x80, + 0xd5, 0x50, 0x12, 0x8e, 0xd0, 0x5b, 0xb6, 0x5c, 0x87, 0x24, 0xe2, 0xd0, + 0xd2, 0xaf, 0x63, 0xae, 0xd1, 0xd6, 0x64, 0x14, 0xe3, 0x6e, 0x61, 0x5b, + 0xd, 0xba, 0x17, 0x7d, 0xd3, 0x10, 0xb1, 0x37, 0x41, 0x91, 0x7d, 0xeb, + 0x1, 0x4d, 0x71, 0xe8, 0x59, 0x71, 0x42, 0x8e, 0xd6, 0xf3, 0x29, 0x3b, + 0x90, 0xf2, 0xd1, 0xaf, 0x65, 0x1e, 0xb3}; + + if (!gcry_check_version (GCRYPT_VERSION)) + { + fprintf (stderr, "Version mismatch %s <-> %s \n", gcry_check_version (NULL), GCRYPT_VERSION); + return 1; + } + + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + + if (gcry_md_open(&mac, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR) + { + fprintf (stderr, "gcry_md_open error\n"); + return 2; + } + + gcry_md_setkey (mac, key, sizeof (key)); + gcry_md_write (mac, data, sizeof (data)); + + if (memcmp(gcry_md_read (mac, 0), result, gcry_md_get_algo_dlen (gcry_md_get_algo (mac))) != 0) + { + fprintf (stderr, "memcmp error\n"); + return 3; + } + + gcry_md_close (mac); + + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + + RESULT=$? + if test $RESULT = 3 + then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "HMAC test vector does not match. This is a known problem with libgcrypt 1.2.2 on Windows and fixed in 1.4.6. +See \`config.log' for more details" "$LINENO" 5 ; } + fi + if test $RESULT = 2 + then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "HMAC test failed +See \`config.log' for more details" "$LINENO" 5 ; } + fi + if test $RESULT = 1 + then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "libgcrypt header version does not match library version +See \`config.log' for more details" "$LINENO" 5 ; } + fi + +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi # $build = $target + +# libcurl + + + + + + + + + + + + + + + + + + + + + + + + + +# Check whether --with-libcurl was given. +if test "${with_libcurl+set}" = set; then : + withval=$with_libcurl; _libcurl_with=$withval +else + _libcurl_with=yes +fi + + + if test "$_libcurl_with" != "no" ; then + + for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + + + _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[1]+256*A[2]+A[3]; print X;}'" + + _libcurl_try_link=yes + + if test -d "$_libcurl_with" ; then + LIBCURL_CPPFLAGS="-I$withval/include" + _libcurl_ldflags="-L$withval/lib" + # Extract the first word of "curl-config", so it can be a program name with args. +set dummy curl-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path__libcurl_config+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $_libcurl_config in + [\\/]* | ?:[\\/]*) + ac_cv_path__libcurl_config="$_libcurl_config" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in "$withval/bin" +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path__libcurl_config="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +_libcurl_config=$ac_cv_path__libcurl_config +if test -n "$_libcurl_config"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_libcurl_config" >&5 +$as_echo "$_libcurl_config" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + # Extract the first word of "curl-config", so it can be a program name with args. +set dummy curl-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path__libcurl_config+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $_libcurl_config in + [\\/]* | ?:[\\/]*) + ac_cv_path__libcurl_config="$_libcurl_config" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path__libcurl_config="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +_libcurl_config=$ac_cv_path__libcurl_config +if test -n "$_libcurl_config"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_libcurl_config" >&5 +$as_echo "$_libcurl_config" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + + if test x$_libcurl_config != "x" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the version of libcurl" >&5 +$as_echo_n "checking for the version of libcurl... " >&6; } +if test "${libcurl_cv_lib_curl_version+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $2}'` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_curl_version" >&5 +$as_echo "$libcurl_cv_lib_curl_version" >&6; } + + _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse` + _libcurl_wanted=`echo 7.20.1 | $_libcurl_version_parse` + + if test $_libcurl_wanted -gt 0 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcurl >= version 7.20.1" >&5 +$as_echo_n "checking for libcurl >= version 7.20.1... " >&6; } +if test "${libcurl_cv_lib_version_ok+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + if test $_libcurl_version -ge $_libcurl_wanted ; then + libcurl_cv_lib_version_ok=yes + else + libcurl_cv_lib_version_ok=no + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_version_ok" >&5 +$as_echo "$libcurl_cv_lib_version_ok" >&6; } + fi + + if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then + if test x"$LIBCURL_CPPFLAGS" = "x" ; then + LIBCURL_CPPFLAGS=`$_libcurl_config --cflags` + fi + if test x"$LIBCURL" = "x" ; then + LIBCURL=`$_libcurl_config --libs` + + # This is so silly, but Apple actually has a bug in their + # curl-config script. Fixed in Tiger, but there are still + # lots of Panther installs around. + case "${host}" in + powerpc-apple-darwin7*) + LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'` + ;; + esac + fi + + # All curl-config scripts support --feature + _libcurl_features=`$_libcurl_config --feature` + + # Is it modern enough to have --protocols? (7.12.4) + if test $_libcurl_version -ge 461828 ; then + _libcurl_protocols=`$_libcurl_config --protocols` + fi + else + _libcurl_try_link=no + fi + + unset _libcurl_wanted + fi + + if test $_libcurl_try_link = yes ; then + + # we didn't find curl-config, so let's see if the user-supplied + # link line (or failing that, "-lcurl") is enough. + LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libcurl is usable" >&5 +$as_echo_n "checking whether libcurl is usable... " >&6; } +if test "${libcurl_cv_lib_curl_usable+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBCURL $LIBS" + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + +/* Try and use a few common options to force a failure if we are + missing symbols or can't link. */ +int x; +curl_easy_setopt(NULL,CURLOPT_URL,NULL); +x=CURL_ERROR_SIZE; +x=CURLOPT_WRITEFUNCTION; +x=CURLOPT_FILE; +x=CURLOPT_ERRORBUFFER; +x=CURLOPT_STDERR; +x=CURLOPT_VERBOSE; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + libcurl_cv_lib_curl_usable=yes +else + libcurl_cv_lib_curl_usable=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_curl_usable" >&5 +$as_echo "$libcurl_cv_lib_curl_usable" >&6; } + + if test $libcurl_cv_lib_curl_usable = yes ; then + + # Does curl_free() exist in this version of libcurl? + # If not, fake it with free() + + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBS $LIBCURL" + + ac_fn_c_check_func "$LINENO" "curl_free" "ac_cv_func_curl_free" +if test "x$ac_cv_func_curl_free" = x""yes; then : + +else + +$as_echo "#define curl_free free" >>confdefs.h + +fi + + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + + +$as_echo "#define HAVE_LIBCURL 1" >>confdefs.h + + + + + for _libcurl_feature in $_libcurl_features ; do + cat >>confdefs.h <<_ACEOF +#define `$as_echo "libcurl_feature_$_libcurl_feature" | $as_tr_cpp` 1 +_ACEOF + + eval `$as_echo "libcurl_feature_$_libcurl_feature" | $as_tr_sh`=yes + done + + if test "x$_libcurl_protocols" = "x" ; then + + # We don't have --protocols, so just assume that all + # protocols are available + _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" + + if test x$libcurl_feature_SSL = xyes ; then + _libcurl_protocols="$_libcurl_protocols HTTPS" + + # FTPS wasn't standards-compliant until version + # 7.11.0 (0x070b00 == 461568) + if test $_libcurl_version -ge 461568; then + _libcurl_protocols="$_libcurl_protocols FTPS" + fi + fi + + # RTSP, IMAP, POP3 and SMTP were added in + # 7.20.0 (0x071400 == 463872) + if test $_libcurl_version -ge 463872; then + _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" + fi + fi + + for _libcurl_protocol in $_libcurl_protocols ; do + cat >>confdefs.h <<_ACEOF +#define `$as_echo "libcurl_protocol_$_libcurl_protocol" | $as_tr_cpp` 1 +_ACEOF + + eval `$as_echo "libcurl_protocol_$_libcurl_protocol" | $as_tr_sh`=yes + done + else + unset LIBCURL + unset LIBCURL_CPPFLAGS + fi + fi + + unset _libcurl_try_link + unset _libcurl_version_parse + unset _libcurl_config + unset _libcurl_feature + unset _libcurl_features + unset _libcurl_protocol + unset _libcurl_protocols + unset _libcurl_version + unset _libcurl_ldflags + fi + + if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then + # This is the IF-NO path + as_fn_error $? "GNUnet requires libcurl >= 7.20.1" "$LINENO" 5 + else + # This is the IF-YES path + : + fi + + unset _libcurl_with + +# restore LIBS +LIBS=$SAVE_LIBS + + +for ac_header in glpk.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "glpk.h" "ac_cv_header_glpk_h" "$ac_includes_default" +if test "x$ac_cv_header_glpk_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GLPK_H 1 +_ACEOF + glpk=true +else + gplk=false +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for glp_create_prob in -lglpk" >&5 +$as_echo_n "checking for glp_create_prob in -lglpk... " >&6; } +if test "${ac_cv_lib_glpk_glp_create_prob+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lglpk $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char glp_create_prob (); +int +main () +{ +return glp_create_prob (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_glpk_glp_create_prob=yes +else + ac_cv_lib_glpk_glp_create_prob=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_glpk_glp_create_prob" >&5 +$as_echo "$ac_cv_lib_glpk_glp_create_prob" >&6; } +if test "x$ac_cv_lib_glpk_glp_create_prob" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBGLPK 1 +_ACEOF + + LIBS="-lglpk $LIBS" + +else + gplk=false +fi + +# GLPK must support atm MLP presolving, version >= 4.32 +ac_fn_c_check_member "$LINENO" "glp_iocp" "presolve" "ac_cv_member_glp_iocp_presolve" "#include +" +if test "x$ac_cv_member_glp_iocp_presolve" = x""yes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_GLP_IOCP_PRESOLVE 1 +_ACEOF + + +else + gplk=false +fi + +if test x$gplk = xfalse +then + if false; then + HAVE_LIBGLPK_TRUE= + HAVE_LIBGLPK_FALSE='#' +else + HAVE_LIBGLPK_TRUE='#' + HAVE_LIBGLPK_FALSE= +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GNUnet requires GLPK >= 4.32" >&5 +$as_echo "$as_me: WARNING: GNUnet requires GLPK >= 4.32" >&2;} +else + if true; then + HAVE_LIBGLPK_TRUE= + HAVE_LIBGLPK_FALSE='#' +else + HAVE_LIBGLPK_TRUE='#' + HAVE_LIBGLPK_FALSE= +fi + + +$as_echo "#define HAVE_LIBGLPK 1" >>confdefs.h + +fi + + +# test for kvm and kstat (for CPU stats under BSD/Solaris) +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for kvm_open in -lkvm" >&5 +$as_echo_n "checking for kvm_open in -lkvm... " >&6; } +if test "${ac_cv_lib_kvm_kvm_open+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lkvm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char kvm_open (); +int +main () +{ +return kvm_open (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_kvm_kvm_open=yes +else + ac_cv_lib_kvm_kvm_open=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kvm_kvm_open" >&5 +$as_echo "$ac_cv_lib_kvm_kvm_open" >&6; } +if test "x$ac_cv_lib_kvm_kvm_open" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBKVM 1 +_ACEOF + + LIBS="-lkvm $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for kstat_open in -lkstat" >&5 +$as_echo_n "checking for kstat_open in -lkstat... " >&6; } +if test "${ac_cv_lib_kstat_kstat_open+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lkstat $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char kstat_open (); +int +main () +{ +return kstat_open (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_kstat_kstat_open=yes +else + ac_cv_lib_kstat_kstat_open=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kstat_kstat_open" >&5 +$as_echo "$ac_cv_lib_kstat_kstat_open" >&6; } +if test "x$ac_cv_lib_kstat_kstat_open" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBKSTAT 1 +_ACEOF + + LIBS="-lkstat $LIBS" + +fi + + +# test for libextractor +extractor=0 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libextractor" >&5 +$as_echo_n "checking for libextractor... " >&6; } + +# Check whether --with-extractor was given. +if test "${with_extractor+set}" = set; then : + withval=$with_extractor; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_extractor" >&5 +$as_echo "$with_extractor" >&6; } + case $with_extractor in + no) + ;; + yes) + for ac_header in extractor.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "extractor.h" "ac_cv_header_extractor_h" "$ac_includes_default" +if test "x$ac_cv_header_extractor_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXTRACTOR_H 1 +_ACEOF + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EXTRACTOR_plugin_add_defaults in -lextractor" >&5 +$as_echo_n "checking for EXTRACTOR_plugin_add_defaults in -lextractor... " >&6; } +if test "${ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lextractor $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char EXTRACTOR_plugin_add_defaults (); +int +main () +{ +return EXTRACTOR_plugin_add_defaults (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=yes +else + ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&5 +$as_echo "$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&6; } +if test "x$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" = x""yes; then : + extractor=1 +fi + +fi + +done + + ;; + *) + LDFLAGS="-L$with_extractor/lib $LDFLAGS" + CPPFLAGS="-I$with_extractor/include $CPPFLAGS" + for ac_header in extractor.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "extractor.h" "ac_cv_header_extractor_h" "$ac_includes_default" +if test "x$ac_cv_header_extractor_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXTRACTOR_H 1 +_ACEOF + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EXTRACTOR_plugin_add_defaults in -lextractor" >&5 +$as_echo_n "checking for EXTRACTOR_plugin_add_defaults in -lextractor... " >&6; } +if test "${ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lextractor $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char EXTRACTOR_plugin_add_defaults (); +int +main () +{ +return EXTRACTOR_plugin_add_defaults (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=yes +else + ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&5 +$as_echo "$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&6; } +if test "x$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" = x""yes; then : + EXT_LIB_PATH="-L$with_extractor/lib $EXT_LIB_PATH" + extractor=1 +fi + +fi + +done + + ;; + esac + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: --with-extractor not specified" >&5 +$as_echo "--with-extractor not specified" >&6; } + for ac_header in extractor.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "extractor.h" "ac_cv_header_extractor_h" "$ac_includes_default" +if test "x$ac_cv_header_extractor_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXTRACTOR_H 1 +_ACEOF + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EXTRACTOR_plugin_add_defaults in -lextractor" >&5 +$as_echo_n "checking for EXTRACTOR_plugin_add_defaults in -lextractor... " >&6; } +if test "${ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lextractor $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char EXTRACTOR_plugin_add_defaults (); +int +main () +{ +return EXTRACTOR_plugin_add_defaults (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=yes +else + ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&5 +$as_echo "$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&6; } +if test "x$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" = x""yes; then : + extractor=1 +fi + +fi + +done + +fi + +if test "$extractor" != 1 +then + as_fn_error $? "GNUnet requires libextractor" "$LINENO" 5 +fi +# restore LIBS +LIBS=$SAVE_LIBS + +# test for libunistring + + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by GCC" >&5 +$as_echo_n "checking for ld used by GCC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${acl_cv_path_LD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break ;; + *) + test "$with_gnu_ld" != yes && break ;; + esac + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$acl_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${acl_cv_prog_gnu_ld+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$acl_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$acl_cv_prog_gnu_ld + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 +$as_echo_n "checking for shared library run path origin... " >&6; } +if test "${acl_cv_rpath+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 +$as_echo "$acl_cv_rpath" >&6; } + wl="$acl_cv_wl" + libext="$acl_cv_libext" + shlibext="$acl_cv_shlibext" + hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + hardcode_direct="$acl_cv_hardcode_direct" + hardcode_minus_L="$acl_cv_hardcode_minus_L" + # Check whether --enable-rpath was given. +if test "${enable_rpath+set}" = set; then : + enableval=$enable_rpath; : +else + enable_rpath=yes +fi + + + + acl_libdirstem=lib + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libiconv-prefix was given. +if test "${with_libiconv_prefix+set}" = set; then : + withval=$with_libiconv_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi + +fi + + LIBICONV= + LTLIBICONV= + INCICONV= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='iconv ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" \ + && { test -f "$additional_libdir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$additional_libdir/lib$name.dll.a"; }; }; then + found_dir="$additional_libdir" + if test -f "$additional_libdir/lib$name.$shlibext"; then + found_so="$additional_libdir/lib$name.$shlibext" + else + found_so="$additional_libdir/lib$name.dll.a" + fi + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" \ + && { test -f "$dir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$dir/lib$name.dll.a"; }; }; then + found_dir="$dir" + if test -f "$dir/lib$name.$shlibext"; then + found_so="$dir/lib$name.$shlibext" + else + found_so="$dir/lib$name.dll.a" + fi + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$hardcode_direct" = yes; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBICONV="${LIBICONV}${LIBICONV:+ }$dep" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep" + ;; + esac + done + fi + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir" + done + fi + + + + + + + + am_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCICONV; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 +$as_echo_n "checking for iconv... " >&6; } +if test "${am_cv_func_iconv+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$am_save_LIBS" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +$as_echo "$am_cv_func_iconv" >&6; } + if test "$am_cv_func_iconv" = yes; then + +$as_echo "#define HAVE_ICONV 1" >>confdefs.h + + fi + if test "$am_cv_lib_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 +$as_echo_n "checking how to link with libiconv... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 +$as_echo "$LIBICONV" >&6; } + else + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + + + + if test "$am_cv_func_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 +$as_echo_n "checking for iconv declaration... " >&6; } + if test "${am_cv_proto_iconv+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + am_cv_proto_iconv_arg1="" +else + am_cv_proto_iconv_arg1="const" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" +fi + + am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- + }$am_cv_proto_iconv" >&5 +$as_echo "${ac_t:- + }$am_cv_proto_iconv" >&6; } + +cat >>confdefs.h <<_ACEOF +#define ICONV_CONST $am_cv_proto_iconv_arg1 +_ACEOF + + fi + + + + + + + + + if test -n "$LIBICONV"; then + + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libunistring-prefix was given. +if test "${with_libunistring_prefix+set}" = set; then : + withval=$with_libunistring_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi + +fi + + LIBUNISTRING= + LTLIBUNISTRING= + INCUNISTRING= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='unistring ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" \ + && { test -f "$additional_libdir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$additional_libdir/lib$name.dll.a"; }; }; then + found_dir="$additional_libdir" + if test -f "$additional_libdir/lib$name.$shlibext"; then + found_so="$additional_libdir/lib$name.$shlibext" + else + found_so="$additional_libdir/lib$name.dll.a" + fi + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" \ + && { test -f "$dir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$dir/lib$name.dll.a"; }; }; then + found_dir="$dir" + if test -f "$dir/lib$name.$shlibext"; then + found_so="$dir/lib$name.$shlibext" + else + found_so="$dir/lib$name.dll.a" + fi + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$hardcode_direct" = yes; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + else + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_a" + else + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCUNISTRING="${INCUNISTRING}${INCUNISTRING:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$dep" + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$dep" + ;; + esac + done + fi + else + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-R$found_dir" + done + fi + + + ac_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCUNISTRING; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libunistring" >&5 +$as_echo_n "checking for libunistring... " >&6; } +if test "${ac_cv_libunistring+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIBUNISTRING" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +u8_strconv_from_locale((char*)0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_libunistring=yes +else + ac_cv_libunistring=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libunistring" >&5 +$as_echo "$ac_cv_libunistring" >&6; } + if test "$ac_cv_libunistring" = yes; then + HAVE_LIBUNISTRING=yes + +$as_echo "#define HAVE_LIBUNISTRING 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libunistring" >&5 +$as_echo_n "checking how to link with libunistring... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBUNISTRING" >&5 +$as_echo "$LIBUNISTRING" >&6; } + else + HAVE_LIBUNISTRING=no + CPPFLAGS="$ac_save_CPPFLAGS" + LIBUNISTRING= + LTLIBUNISTRING= + fi + + + + + + + if test "$ac_cv_libunistring" != yes; then + unset ac_cv_libunistring + glus_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libunistring-prefix was given. +if test "${with_libunistring_prefix+set}" = set; then : + withval=$with_libunistring_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi + +fi + + LIBUNISTRING= + LTLIBUNISTRING= + INCUNISTRING= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='unistring ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" \ + && { test -f "$additional_libdir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$additional_libdir/lib$name.dll.a"; }; }; then + found_dir="$additional_libdir" + if test -f "$additional_libdir/lib$name.$shlibext"; then + found_so="$additional_libdir/lib$name.$shlibext" + else + found_so="$additional_libdir/lib$name.dll.a" + fi + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" \ + && { test -f "$dir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$dir/lib$name.dll.a"; }; }; then + found_dir="$dir" + if test -f "$dir/lib$name.$shlibext"; then + found_so="$dir/lib$name.$shlibext" + else + found_so="$dir/lib$name.dll.a" + fi + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$hardcode_direct" = yes; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + else + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_a" + else + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCUNISTRING="${INCUNISTRING}${INCUNISTRING:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$dep" + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$dep" + ;; + esac + done + fi + else + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-R$found_dir" + done + fi + + + ac_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCUNISTRING; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libunistring" >&5 +$as_echo_n "checking for libunistring... " >&6; } +if test "${ac_cv_libunistring+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIBUNISTRING" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +u8_strconv_from_locale((char*)0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_libunistring=yes +else + ac_cv_libunistring=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libunistring" >&5 +$as_echo "$ac_cv_libunistring" >&6; } + if test "$ac_cv_libunistring" = yes; then + HAVE_LIBUNISTRING=yes + +$as_echo "#define HAVE_LIBUNISTRING 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libunistring" >&5 +$as_echo_n "checking how to link with libunistring... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBUNISTRING" >&5 +$as_echo "$LIBUNISTRING" >&6; } + else + HAVE_LIBUNISTRING=no + CPPFLAGS="$ac_save_CPPFLAGS" + LIBUNISTRING= + LTLIBUNISTRING= + fi + + + + + + + if test -n "$LIBUNISTRING"; then + LIBUNISTRING="$LIBUNISTRING $LIBICONV" + LTLIBUNISTRING="$LTLIBUNISTRING $LTLIBICONV" + fi + LIBS="$glus_save_LIBS" + fi + else + + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libunistring-prefix was given. +if test "${with_libunistring_prefix+set}" = set; then : + withval=$with_libunistring_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi + +fi + + LIBUNISTRING= + LTLIBUNISTRING= + INCUNISTRING= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='unistring ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" \ + && { test -f "$additional_libdir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$additional_libdir/lib$name.dll.a"; }; }; then + found_dir="$additional_libdir" + if test -f "$additional_libdir/lib$name.$shlibext"; then + found_so="$additional_libdir/lib$name.$shlibext" + else + found_so="$additional_libdir/lib$name.dll.a" + fi + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" \ + && { test -f "$dir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$dir/lib$name.dll.a"; }; }; then + found_dir="$dir" + if test -f "$dir/lib$name.$shlibext"; then + found_so="$dir/lib$name.$shlibext" + else + found_so="$dir/lib$name.dll.a" + fi + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$hardcode_direct" = yes; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" + else + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_a" + else + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCUNISTRING="${INCUNISTRING}${INCUNISTRING:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBUNISTRING; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$dep" + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$dep" + ;; + esac + done + fi + else + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-R$found_dir" + done + fi + + + ac_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCUNISTRING; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libunistring" >&5 +$as_echo_n "checking for libunistring... " >&6; } +if test "${ac_cv_libunistring+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIBUNISTRING" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +u8_strconv_from_locale((char*)0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_libunistring=yes +else + ac_cv_libunistring=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libunistring" >&5 +$as_echo "$ac_cv_libunistring" >&6; } + if test "$ac_cv_libunistring" = yes; then + HAVE_LIBUNISTRING=yes + +$as_echo "#define HAVE_LIBUNISTRING 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libunistring" >&5 +$as_echo_n "checking how to link with libunistring... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBUNISTRING" >&5 +$as_echo "$LIBUNISTRING" >&6; } + else + HAVE_LIBUNISTRING=no + CPPFLAGS="$ac_save_CPPFLAGS" + LIBUNISTRING= + LTLIBUNISTRING= + fi + + + + + + + fi + if test $HAVE_LIBUNISTRING = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libunistring version" >&5 +$as_echo_n "checking for libunistring version... " >&6; } +if test "${gl_cv_libunistring_version+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "_LIBUNISTRING_VERSION" "gl_libunistring_hexversion" "#include "; then : + +fi + + if test $gl_libunistring_hexversion = 9; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_libunistring_version092=true +else + gl_cv_libunistring_version092=false +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if $gl_cv_libunistring_version092; then + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF + case "$host_os" in + aix*) gl_absname_cpp="$ac_cpp -C" ;; + *) gl_absname_cpp="$ac_cpp" ;; + esac + gl_cv_absolute_unistr_h=`(eval "$gl_absname_cpp conftest.$ac_ext") 2>&5 | +sed -n '\#/unistr.h#{ + s#.*"\(.*/unistr.h\)".*#\1# + s#^/[^/]#//&# + p + q +}'` + + if test -n "$gl_cv_absolute_unistr_h" \ + && grep 'Copy no more than N units of SRC to DEST. Return a pointer' $gl_cv_absolute_unistr_h > /dev/null; then + gl_libunistring_hexversion=2307 + else + gl_libunistring_hexversion=2306 + fi + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + casing_suffix_context_t ct; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gl_cv_libunistring_version091=true +else + gl_cv_libunistring_version091=false +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if $gl_cv_libunistring_version091; then + gl_libunistring_hexversion=2305 + else + gl_libunistring_hexversion=2304 + fi + fi + fi + gl_libunistring_major=`expr $gl_libunistring_hexversion / 65536` + gl_libunistring_minor=`expr $gl_libunistring_hexversion / 256 % 256` + gl_libunistring_subminor=`expr $gl_libunistring_hexversion % 256` + gl_cv_libunistring_version="$gl_libunistring_major.$gl_libunistring_minor.$gl_libunistring_subminor" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_libunistring_version" >&5 +$as_echo "$gl_cv_libunistring_version" >&6; } + LIBUNISTRING_VERSION="$gl_cv_libunistring_version" + fi + + +if test $HAVE_LIBUNISTRING != yes; then + as_fn_error $? "GNUnet requires libunistring" "$LINENO" 5 +fi +if test $gl_libunistring_hexversion -le 2305; then + as_fn_error $? "GNUnet requires libunistring >= 0.9.1.1" "$LINENO" 5 +fi +# restore LIBS +LIBS=$SAVE_LIBS + + + +# Checks for standard header files. +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 +$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } +if eval "test \"\${$as_ac_Header+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include <$ac_hdr> + +int +main () +{ +if ((DIR *) 0) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$as_ac_Header=yes" +else + eval "$as_ac_Header=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$as_ac_Header + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 +_ACEOF + +ac_header_dirent=$ac_hdr; break +fi + +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 +$as_echo_n "checking for library containing opendir... " >&6; } +if test "${ac_cv_search_opendir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char opendir (); +int +main () +{ +return opendir (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dir; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_opendir=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_opendir+set}" = set; then : + break +fi +done +if test "${ac_cv_search_opendir+set}" = set; then : + +else + ac_cv_search_opendir=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 +$as_echo "$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 +$as_echo_n "checking for library containing opendir... " >&6; } +if test "${ac_cv_search_opendir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char opendir (); +int +main () +{ +return opendir (); + ; + return 0; +} +_ACEOF +for ac_lib in '' x; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_opendir=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_opendir+set}" = set; then : + break +fi +done +if test "${ac_cv_search_opendir+set}" = set; then : + +else + ac_cv_search_opendir=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 +$as_echo "$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + + +# Check for headers that are ALWAYS required +for ac_header in fcntl.h math.h errno.h ctype.h limits.h stdio.h stdlib.h string.h unistd.h stdarg.h signal.h locale.h sys/stat.h sys/types.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +else + as_fn_error $? "Compiling GNUnet requires standard UNIX headers files" "$LINENO" 5 +fi + +done + + +# Checks for headers that are only required on some systems or opional (and where we do NOT abort if they are not there) +for ac_header in langinfo.h sys/param.h sys/mount.h sys/statvfs.h sys/select.h sockLib.h sys/mman.h sys/msg.h sys/vfs.h arpa/inet.h fcntl.h libintl.h netdb.h netinet/in.h netinet/in_systm.h sys/ioctl.h sys/socket.h sys/time.h unistd.h kstat.h sys/sysinfo.h kvm.h sys/file.h sys/resource.h ifaddrs.h mach/mach.h stddef.h sys/timeb.h terminos.h argz.h ucred.h endian.h sys/endian.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +SAVE_LDFLAGS=$LDFLAGS +SAVE_CPPFLAGS=$CPPFLAGS + +# test for sqlite +sqlite=false +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SQLite" >&5 +$as_echo_n "checking for SQLite... " >&6; } + +# Check whether --with-sqlite was given. +if test "${with_sqlite+set}" = set; then : + withval=$with_sqlite; { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_sqlite\"" >&5 +$as_echo "\"$with_sqlite\"" >&6; } + case $with_sqlite in + no) + ;; + yes) + for ac_header in sqlite3.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" +if test "x$ac_cv_header_sqlite3_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQLITE3_H 1 +_ACEOF + sqlite=true +fi + +done + + ;; + *) + LDFLAGS="-L$with_sqlite/lib $LDFLAGS" + CPPFLAGS="-I$with_sqlite/include $CPPFLAGS" + for ac_header in sqlite3.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" +if test "x$ac_cv_header_sqlite3_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQLITE3_H 1 +_ACEOF + EXT_LIB_PATH="-L$with_sqlite/lib $EXT_LIB_PATH" + SQLITE_LDFLAGS="-L$with_sqlite/lib" + SQLITE_CPPFLAGS="-I$with_sqlite/include" + sqlite=true +fi + +done + + LDFLAGS=$SAVE_LDFLAGS + CPPFLAGS=$SAVE_CPPFLAGS + ;; + esac + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: --with-sqlite not specified" >&5 +$as_echo "--with-sqlite not specified" >&6; } + for ac_header in sqlite3.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" +if test "x$ac_cv_header_sqlite3_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SQLITE3_H 1 +_ACEOF + sqlite=true +fi + +done + +fi + + if test x$sqlite = xtrue; then + HAVE_SQLITE_TRUE= + HAVE_SQLITE_FALSE='#' +else + HAVE_SQLITE_TRUE='#' + HAVE_SQLITE_FALSE= +fi + + + + +# test for postgres +postgres=false +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for postgres" >&5 +$as_echo_n "checking for postgres... " >&6; } + +# Check whether --with-postgres was given. +if test "${with_postgres+set}" = set; then : + withval=$with_postgres; { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_postgres\"" >&5 +$as_echo "\"$with_postgres\"" >&6; } + case $with_postgres in + no) + ;; + yes) + for ac_header in postgresql/libpq-fe.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "postgresql/libpq-fe.h" "ac_cv_header_postgresql_libpq_fe_h" "$ac_includes_default" +if test "x$ac_cv_header_postgresql_libpq_fe_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POSTGRESQL_LIBPQ_FE_H 1 +_ACEOF + postgres=true +fi + +done + + ;; + *) + LDFLAGS="-L$with_postgres/lib $LDFLAGS" + CPPFLAGS="-I$with_postgres/include $CPPFLAGS" + for ac_header in postgresql/libpq-fe.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "postgresql/libpq-fe.h" "ac_cv_header_postgresql_libpq_fe_h" "$ac_includes_default" +if test "x$ac_cv_header_postgresql_libpq_fe_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POSTGRESQL_LIBPQ_FE_H 1 +_ACEOF + EXT_LIB_PATH="-L$with_postgres/lib $EXT_LIB_PATH" + POSTGRES_LDFLAGS="-L$with_postgres/lib" + POSTGRES_CPPFLAGS="-I$with_postgres/include" + postgres=true +fi + +done + + LDFLAGS=$SAVE_LDFLAGS + CPPFLAGS=$SAVE_CPPFLAGS + ;; + esac + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: --with-postgres not specified" >&5 +$as_echo "--with-postgres not specified" >&6; } + for ac_header in postgresql/libpq-fe.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "postgresql/libpq-fe.h" "ac_cv_header_postgresql_libpq_fe_h" "$ac_includes_default" +if test "x$ac_cv_header_postgresql_libpq_fe_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_POSTGRESQL_LIBPQ_FE_H 1 +_ACEOF + postgres=true +fi + +done + +fi + + if test x$postgres = xtrue; then + HAVE_POSTGRES_TRUE= + HAVE_POSTGRES_FALSE='#' +else + HAVE_POSTGRES_TRUE='#' + HAVE_POSTGRES_FALSE= +fi + + + + +# test for libz (maybe required for linking mysql) +zlib=1 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compress in -lz" >&5 +$as_echo_n "checking for compress in -lz... " >&6; } +if test "${ac_cv_lib_z_compress+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char compress (); +int +main () +{ +return compress (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_z_compress=yes +else + ac_cv_lib_z_compress=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_compress" >&5 +$as_echo "$ac_cv_lib_z_compress" >&6; } +if test "x$ac_cv_lib_z_compress" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBZ 1 +_ACEOF + + LIBS="-lz $LIBS" + +else + zlib=0 +fi + + if test x$zlib = x1; then + HAVE_ZLIB_TRUE= + HAVE_ZLIB_FALSE='#' +else + HAVE_ZLIB_TRUE='#' + HAVE_ZLIB_FALSE= +fi + +if test "$zlib" != 1 +then + as_fn_error $? "GNUnet requires zlib" "$LINENO" 5 +fi + +# mysql & windows +ac_fn_c_check_type "$LINENO" "sigset_t" "ac_cv_type_sigset_t" "#include +" +if test "x$ac_cv_type_sigset_t" = x""yes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_SIGSET_T 1 +_ACEOF + + +fi +ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "#include +" +if test "x$ac_cv_type_off_t" = x""yes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_OFF_T 1 +_ACEOF + + +fi + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "#include +" +if test "x$ac_cv_type_size_t" = x""yes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_SIZE_T 1 +_ACEOF + + +fi + + +if test "$build_target" = "mingw" +then + CYGWIN_MYSQL_MAGIC="#include " +fi + +# test for mysql +mysql=false +mysqlfail=false +SAVE_LDFLAGS=$LDFLAGS +SAVE_CPPFLAGS=$CPPFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql" >&5 +$as_echo_n "checking for mysql... " >&6; } + +# Check whether --with-mysql was given. +if test "${with_mysql+set}" = set; then : + withval=$with_mysql; { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_mysql\"" >&5 +$as_echo "\"$with_mysql\"" >&6; } + if test "$with_mysql" != "no" + then + if test "$with_mysql" != "yes" + then + LDFLAGS="-L$with_mysql/lib -L$with_mysql/lib/mysql $LDFLAGS $ZLIBS" + CPPFLAGS="-I$with_mysql/include $CPPFLAGS" + fi + for ac_header in mysql/mysql.h +do : + ac_fn_c_check_header_compile "$LINENO" "mysql/mysql.h" "ac_cv_header_mysql_mysql_h" "$CYGWIN_MYSQL_MAGIC +" +if test "x$ac_cv_header_mysql_mysql_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MYSQL_MYSQL_H 1 +_ACEOF + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient" >&5 +$as_echo_n "checking for mysql_init in -lmysqlclient... " >&6; } +if test "${ac_cv_lib_mysqlclient_mysql_init+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmysqlclient $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char mysql_init (); +int +main () +{ +return mysql_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_mysqlclient_mysql_init=yes +else + ac_cv_lib_mysqlclient_mysql_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mysqlclient_mysql_init" >&5 +$as_echo "$ac_cv_lib_mysqlclient_mysql_init" >&6; } +if test "x$ac_cv_lib_mysqlclient_mysql_init" = x""yes; then : + MYSQL_LDFLAGS="-L$with_mysql/lib -L$with_mysql/lib/mysql" + MYSQL_CPPFLAGS="-I$with_mysql/include" + + mysql=true +fi + +fi + +done + + fi + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: --with-mysql not specified" >&5 +$as_echo "--with-mysql not specified" >&6; } + LDFLAGS="-L/usr/lib/mysql $LDFLAGS $ZLIBS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient" >&5 +$as_echo_n "checking for mysql_init in -lmysqlclient... " >&6; } +if test "${ac_cv_lib_mysqlclient_mysql_init+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmysqlclient $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char mysql_init (); +int +main () +{ +return mysql_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_mysqlclient_mysql_init=yes +else + ac_cv_lib_mysqlclient_mysql_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mysqlclient_mysql_init" >&5 +$as_echo "$ac_cv_lib_mysqlclient_mysql_init" >&6; } +if test "x$ac_cv_lib_mysqlclient_mysql_init" = x""yes; then : + for ac_header in mysql/mysql.h +do : + ac_fn_c_check_header_compile "$LINENO" "mysql/mysql.h" "ac_cv_header_mysql_mysql_h" "$CYGWIN_MYSQL_MAGIC +" +if test "x$ac_cv_header_mysql_mysql_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MYSQL_MYSQL_H 1 +_ACEOF + MYSQL_LDFLAGS="-L/usr/lib/mysql" + mysql=true + + +fi + +done + +fi + + +fi + + + + + +# additional version check for mysql +# Check whether --enable-mysql-version-check was given. +if test "${enable_mysql_version_check+set}" = set; then : + enableval=$enable_mysql_version_check; +else + enable_mysql_version_check=yes +fi + +if test "$mysql" = "true" -a "x$enable_mysql_version_check" = "xyes" +then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking mysql version" >&5 +$as_echo_n "checking mysql version... " >&6; } + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5 ; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$CYGWIN_MYSQL_MAGIC + #include +int +main () +{ +if (MYSQL_VERSION_ID < 40100) + return(-1); + else + return(0); + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + mysql=true +else + mysql=false +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + if test "$mysql" = "false" + then + mysqlfail=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: fail, >= 4.1 required" >&5 +$as_echo "fail, >= 4.1 required" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } + fi +fi + if test x$mysql = xtrue; then + HAVE_MYSQL_TRUE= + HAVE_MYSQL_FALSE='#' +else + HAVE_MYSQL_TRUE='#' + HAVE_MYSQL_FALSE= +fi + + if test "0" = "1"; then + HAVE_MYSQLE_TRUE= + HAVE_MYSQLE_FALSE='#' +else + HAVE_MYSQLE_TRUE='#' + HAVE_MYSQLE_FALSE= +fi + +# restore LIBS +LIBS=$SAVE_LIBS +LDFLAGS=$SAVE_LDFLAGS +CPPFLAGS=$SAVE_CPPFLAGS + +if test "$sqlite" = 0 -a "$mysql" = 0 +then + as_fn_error $? "GNUnet requires SQLite or MySQL" "$LINENO" 5 +fi + +# libmicrohttpd +lmhd=0 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libmicrohttpd" >&5 +$as_echo_n "checking for libmicrohttpd... " >&6; } + +# Check whether --with-microhttpd was given. +if test "${with_microhttpd+set}" = set; then : + withval=$with_microhttpd; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_microhttpd" >&5 +$as_echo "$with_microhttpd" >&6; } + case $with_microhttpd in + no) + ;; + yes) + for ac_header in microhttpd.h +do : + ac_fn_c_check_header_compile "$LINENO" "microhttpd.h" "ac_cv_header_microhttpd_h" "#include \"src/include/platform.h\" +" +if test "x$ac_cv_header_microhttpd_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MICROHTTPD_H 1 +_ACEOF + ac_fn_c_check_decl "$LINENO" "MHD_OPTION_PER_IP_CONNECTION_LIMIT" "ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" "#include \"src/include/platform.h\" + #include +" +if test "x$ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" = x""yes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MHD_start_daemon in -lmicrohttpd" >&5 +$as_echo_n "checking for MHD_start_daemon in -lmicrohttpd... " >&6; } +if test "${ac_cv_lib_microhttpd_MHD_start_daemon+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmicrohttpd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char MHD_start_daemon (); +int +main () +{ +return MHD_start_daemon (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_microhttpd_MHD_start_daemon=yes +else + ac_cv_lib_microhttpd_MHD_start_daemon=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_microhttpd_MHD_start_daemon" >&5 +$as_echo "$ac_cv_lib_microhttpd_MHD_start_daemon" >&6; } +if test "x$ac_cv_lib_microhttpd_MHD_start_daemon" = x""yes; then : + lmhd=1 +fi + +fi + +fi + +done + + ;; + *) + LDFLAGS="-L$with_microhttpd/lib $LDFLAGS" + CPPFLAGS="-I$with_microhttpd/include $CPPFLAGS" + for ac_header in microhttpd.h +do : + ac_fn_c_check_header_compile "$LINENO" "microhttpd.h" "ac_cv_header_microhttpd_h" "#include \"src/include/platform.h\" +" +if test "x$ac_cv_header_microhttpd_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MICROHTTPD_H 1 +_ACEOF + ac_fn_c_check_decl "$LINENO" "MHD_OPTION_PER_IP_CONNECTION_LIMIT" "ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" "#include \"src/include/platform.h\" + #include +" +if test "x$ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" = x""yes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MHD_start_daemon in -lmicrohttpd" >&5 +$as_echo_n "checking for MHD_start_daemon in -lmicrohttpd... " >&6; } +if test "${ac_cv_lib_microhttpd_MHD_start_daemon+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmicrohttpd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char MHD_start_daemon (); +int +main () +{ +return MHD_start_daemon (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_microhttpd_MHD_start_daemon=yes +else + ac_cv_lib_microhttpd_MHD_start_daemon=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_microhttpd_MHD_start_daemon" >&5 +$as_echo "$ac_cv_lib_microhttpd_MHD_start_daemon" >&6; } +if test "x$ac_cv_lib_microhttpd_MHD_start_daemon" = x""yes; then : + EXT_LIB_PATH="-L$with_microhttpd/lib $EXT_LIB_PATH" + lmhd=1 +fi + +fi + +fi + +done + + ;; + esac + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: --with-microhttpd not specified" >&5 +$as_echo "--with-microhttpd not specified" >&6; } + for ac_header in microhttpd.h +do : + ac_fn_c_check_header_compile "$LINENO" "microhttpd.h" "ac_cv_header_microhttpd_h" "#include \"src/include/platform.h\" +" +if test "x$ac_cv_header_microhttpd_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MICROHTTPD_H 1 +_ACEOF + ac_fn_c_check_decl "$LINENO" "MHD_OPTION_PER_IP_CONNECTION_LIMIT" "ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" "#include \"src/include/platform.h\" + #include +" +if test "x$ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" = x""yes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MHD_start_daemon in -lmicrohttpd" >&5 +$as_echo_n "checking for MHD_start_daemon in -lmicrohttpd... " >&6; } +if test "${ac_cv_lib_microhttpd_MHD_start_daemon+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmicrohttpd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char MHD_start_daemon (); +int +main () +{ +return MHD_start_daemon (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_microhttpd_MHD_start_daemon=yes +else + ac_cv_lib_microhttpd_MHD_start_daemon=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_microhttpd_MHD_start_daemon" >&5 +$as_echo "$ac_cv_lib_microhttpd_MHD_start_daemon" >&6; } +if test "x$ac_cv_lib_microhttpd_MHD_start_daemon" = x""yes; then : + lmhd=1 +fi + +fi + +fi + +done + +fi + + if test x$lmhd = x1; then + HAVE_MHD_TRUE= + HAVE_MHD_FALSE='#' +else + HAVE_MHD_TRUE='#' + HAVE_MHD_FALSE= +fi + + +cat >>confdefs.h <<_ACEOF +#define HAVE_MHD $lmhd +_ACEOF + + + +# restore LIBS +LIBS=$SAVE_LIBS + +# check for python & pexpect (used for some testcases only) + + + + + if test -n "$PYTHON"; then + # If the user set $PYTHON, use it and don't search something else. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version >= 2.6" >&5 +$as_echo_n "checking whether $PYTHON version >= 2.6... " >&6; } + prog="import sys +# split strings by '.' and convert to numeric. Append some zeros +# because we need at least 4 digits for the hex conversion. +# map returns an iterator in Python 3.0 and a list in 2.x +minver = list(map(int, '2.6'.split('.'))) + [0, 0, 0] +minverhex = 0 +# xrange is not present in Python 3.0 and range returns an iterator +for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] +sys.exit(sys.hexversion < minverhex)" + if { echo "$as_me:$LINENO: $PYTHON -c "$prog"" >&5 + ($PYTHON -c "$prog") >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + as_fn_error $? "too old" "$LINENO" 5 +fi + am_display_PYTHON=$PYTHON + else + # Otherwise, try each interpreter until we find one that satisfies + # VERSION. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a Python interpreter with version >= 2.6" >&5 +$as_echo_n "checking for a Python interpreter with version >= 2.6... " >&6; } +if test "${am_cv_pathless_PYTHON+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + for am_cv_pathless_PYTHON in python python2 python3 python3.0 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do + test "$am_cv_pathless_PYTHON" = none && break + prog="import sys +# split strings by '.' and convert to numeric. Append some zeros +# because we need at least 4 digits for the hex conversion. +# map returns an iterator in Python 3.0 and a list in 2.x +minver = list(map(int, '2.6'.split('.'))) + [0, 0, 0] +minverhex = 0 +# xrange is not present in Python 3.0 and range returns an iterator +for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] +sys.exit(sys.hexversion < minverhex)" + if { echo "$as_me:$LINENO: $am_cv_pathless_PYTHON -c "$prog"" >&5 + ($am_cv_pathless_PYTHON -c "$prog") >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then : + break +fi + done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_pathless_PYTHON" >&5 +$as_echo "$am_cv_pathless_PYTHON" >&6; } + # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. + if test "$am_cv_pathless_PYTHON" = none; then + PYTHON=: + else + # Extract the first word of "$am_cv_pathless_PYTHON", so it can be a program name with args. +set dummy $am_cv_pathless_PYTHON; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_PYTHON+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $PYTHON in + [\\/]* | ?:[\\/]*) + ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PYTHON=$ac_cv_path_PYTHON +if test -n "$PYTHON"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 +$as_echo "$PYTHON" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + am_display_PYTHON=$am_cv_pathless_PYTHON + fi + + + if test "$PYTHON" = :; then + : + else + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5 +$as_echo_n "checking for $am_display_PYTHON version... " >&6; } +if test "${am_cv_python_version+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[:3])"` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5 +$as_echo "$am_cv_python_version" >&6; } + PYTHON_VERSION=$am_cv_python_version + + + + PYTHON_PREFIX='${prefix}' + + PYTHON_EXEC_PREFIX='${exec_prefix}' + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5 +$as_echo_n "checking for $am_display_PYTHON platform... " >&6; } +if test "${am_cv_python_platform+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5 +$as_echo "$am_cv_python_platform" >&6; } + PYTHON_PLATFORM=$am_cv_python_platform + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory" >&5 +$as_echo_n "checking for $am_display_PYTHON script directory... " >&6; } +if test "${am_cv_python_pythondir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$prefix" = xNONE + then + am_py_prefix=$ac_default_prefix + else + am_py_prefix=$prefix + fi + am_cv_python_pythondir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(0,0,prefix='$am_py_prefix'))" 2>/dev/null || + echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"` + case $am_cv_python_pythondir in + $am_py_prefix*) + am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` + am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` + ;; + *) + case $am_py_prefix in + /usr|/System*) ;; + *) + am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages + ;; + esac + ;; + esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5 +$as_echo "$am_cv_python_pythondir" >&6; } + pythondir=$am_cv_python_pythondir + + + + pkgpythondir=\${pythondir}/$PACKAGE + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory" >&5 +$as_echo_n "checking for $am_display_PYTHON extension module directory... " >&6; } +if test "${am_cv_python_pyexecdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$exec_prefix" = xNONE + then + am_py_exec_prefix=$am_py_prefix + else + am_py_exec_prefix=$exec_prefix + fi + am_cv_python_pyexecdir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(1,0,prefix='$am_py_exec_prefix'))" 2>/dev/null || + echo "$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages"` + case $am_cv_python_pyexecdir in + $am_py_exec_prefix*) + am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` + am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` + ;; + *) + case $am_py_exec_prefix in + /usr|/System*) ;; + *) + am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages + ;; + esac + ;; + esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5 +$as_echo "$am_cv_python_pyexecdir" >&6; } + pyexecdir=$am_cv_python_pyexecdir + + + + pkgpyexecdir=\${pyexecdir}/$PACKAGE + + + + fi + + + if test "$PYTHON" != :; then + HAVE_PYTHON_TRUE= + HAVE_PYTHON_FALSE='#' +else + HAVE_PYTHON_TRUE='#' + HAVE_PYTHON_FALSE= +fi + + +if test "$PYTHON" != : +then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pexpect" >&5 +$as_echo_n "checking for pexpect... " >&6; } + $PYTHON -c "import pexpect" > /dev/null 2> /dev/null + PYEX=$? + if test $PYEX -eq 0; then + HAVE_PYTHON_PEXPECT_TRUE= + HAVE_PYTHON_PEXPECT_FALSE='#' +else + HAVE_PYTHON_PEXPECT_TRUE='#' + HAVE_PYTHON_PEXPECT_FALSE= +fi + + if test $PYEX -eq 0 + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + fi +else + if 0; then + HAVE_PYTHON_PEXPECT_TRUE= + HAVE_PYTHON_PEXPECT_FALSE='#' +else + HAVE_PYTHON_PEXPECT_TRUE='#' + HAVE_PYTHON_PEXPECT_FALSE= +fi + +fi + + +# check for gettext + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 +$as_echo_n "checking whether NLS is requested... " >&6; } + # Check whether --enable-nls was given. +if test "${enable_nls+set}" = set; then : + enableval=$enable_nls; USE_NLS=$enableval +else + USE_NLS=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 +$as_echo "$USE_NLS" >&6; } + + + + + + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "msgfmt", so it can be a program name with args. +set dummy msgfmt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_MSGFMT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case "$MSGFMT" in + [\\/]* | ?:[\\/]*) + ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&5 + if $ac_dir/$ac_word --statistics /dev/null >&5 2>&1 && + (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + ac_cv_path_MSGFMT="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":" + ;; +esac +fi +MSGFMT="$ac_cv_path_MSGFMT" +if test "$MSGFMT" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 +$as_echo "$MSGFMT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + # Extract the first word of "gmsgfmt", so it can be a program name with args. +set dummy gmsgfmt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_GMSGFMT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $GMSGFMT in + [\\/]* | ?:[\\/]*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_GMSGFMT="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" + ;; +esac +fi +GMSGFMT=$ac_cv_path_GMSGFMT +if test -n "$GMSGFMT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GMSGFMT" >&5 +$as_echo "$GMSGFMT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; + *) MSGFMT_015=$MSGFMT ;; + esac + + case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; + *) GMSGFMT_015=$GMSGFMT ;; + esac + + + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "xgettext", so it can be a program name with args. +set dummy xgettext; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_XGETTEXT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case "$XGETTEXT" in + [\\/]* | ?:[\\/]*) + ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&5 + if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&5 2>&1 && + (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + ac_cv_path_XGETTEXT="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" + ;; +esac +fi +XGETTEXT="$ac_cv_path_XGETTEXT" +if test "$XGETTEXT" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 +$as_echo "$XGETTEXT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + rm -f messages.po + + case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; + *) XGETTEXT_015=$XGETTEXT ;; + esac + + + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "msgmerge", so it can be a program name with args. +set dummy msgmerge; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_MSGMERGE+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case "$MSGMERGE" in + [\\/]* | ?:[\\/]*) + ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&5 + if $ac_dir/$ac_word --update -q /dev/null /dev/null >&5 2>&1; then + ac_cv_path_MSGMERGE="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_MSGMERGE" && ac_cv_path_MSGMERGE=":" + ;; +esac +fi +MSGMERGE="$ac_cv_path_MSGMERGE" +if test "$MSGMERGE" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGMERGE" >&5 +$as_echo "$MSGMERGE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$localedir" || localedir='${datadir}/locale' + + + ac_config_commands="$ac_config_commands po-directories" + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 +$as_echo_n "checking for CFPreferencesCopyAppValue... " >&6; } +if test "${gt_cv_func_CFPreferencesCopyAppValue+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +CFPreferencesCopyAppValue(NULL, NULL) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gt_cv_func_CFPreferencesCopyAppValue=yes +else + gt_cv_func_CFPreferencesCopyAppValue=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$gt_save_LIBS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5 +$as_echo "$gt_cv_func_CFPreferencesCopyAppValue" >&6; } + if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then + +$as_echo "#define HAVE_CFPREFERENCESCOPYAPPVALUE 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyCurrent" >&5 +$as_echo_n "checking for CFLocaleCopyCurrent... " >&6; } +if test "${gt_cv_func_CFLocaleCopyCurrent+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +CFLocaleCopyCurrent(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gt_cv_func_CFLocaleCopyCurrent=yes +else + gt_cv_func_CFLocaleCopyCurrent=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$gt_save_LIBS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyCurrent" >&5 +$as_echo "$gt_cv_func_CFLocaleCopyCurrent" >&6; } + if test $gt_cv_func_CFLocaleCopyCurrent = yes; then + +$as_echo "#define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h + + fi + INTL_MACOSX_LIBS= + if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then + INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" + fi + + + + + + + LIBINTL= + LTLIBINTL= + POSUB= + + case " $gt_needs " in + *" need-formatstring-macros "*) gt_api_version=3 ;; + *" need-ngettext "*) gt_api_version=2 ;; + *) gt_api_version=1 ;; + esac + gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" + gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" + + if test "$USE_NLS" = "yes"; then + gt_use_preinstalled_gnugettext=no + + + if test $gt_api_version -ge 3; then + gt_revision_test_code=' +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +' + else + gt_revision_test_code= + fi + if test $gt_api_version -ge 2; then + gt_expression_test_code=' + * ngettext ("", "", 0)' + else + gt_expression_test_code= + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libc" >&5 +$as_echo_n "checking for GNU gettext in libc... " >&6; } +if eval "test \"\${$gt_func_gnugettext_libc+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern int *_nl_domain_bindings; +int +main () +{ +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$gt_func_gnugettext_libc=yes" +else + eval "$gt_func_gnugettext_libc=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$gt_func_gnugettext_libc + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + + + + + + am_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCICONV; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 +$as_echo_n "checking for iconv... " >&6; } +if test "${am_cv_func_iconv+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$am_save_LIBS" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +$as_echo "$am_cv_func_iconv" >&6; } + if test "$am_cv_func_iconv" = yes; then + +$as_echo "#define HAVE_ICONV 1" >>confdefs.h + + fi + if test "$am_cv_lib_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 +$as_echo_n "checking how to link with libiconv... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 +$as_echo "$LIBICONV" >&6; } + else + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libintl-prefix was given. +if test "${with_libintl_prefix+set}" = set; then : + withval=$with_libintl_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi + +fi + + LIBINTL= + LTLIBINTL= + INCINTL= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='intl ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBINTL="${LIBINTL}${LIBINTL:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" \ + && { test -f "$additional_libdir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$additional_libdir/lib$name.dll.a"; }; }; then + found_dir="$additional_libdir" + if test -f "$additional_libdir/lib$name.$shlibext"; then + found_so="$additional_libdir/lib$name.$shlibext" + else + found_so="$additional_libdir/lib$name.dll.a" + fi + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" \ + && { test -f "$dir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$dir/lib$name.dll.a"; }; }; then + found_dir="$dir" + if test -f "$dir/lib$name.$shlibext"; then + found_so="$dir/lib$name.$shlibext" + else + found_so="$dir/lib$name.dll.a" + fi + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$hardcode_direct" = yes; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + else + LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_a" + else + LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCINTL="${INCINTL}${INCINTL:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBINTL="${LIBINTL}${LIBINTL:+ }$dep" + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$dep" + ;; + esac + done + fi + else + LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-R$found_dir" + done + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libintl" >&5 +$as_echo_n "checking for GNU gettext in libintl... " >&6; } +if eval "test \"\${$gt_func_gnugettext_libintl+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + gt_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCINTL" + gt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBINTL" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *); +int +main () +{ +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$gt_func_gnugettext_libintl=yes" +else + eval "$gt_func_gnugettext_libintl=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then + LIBS="$LIBS $LIBICONV" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *); +int +main () +{ +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + LIBINTL="$LIBINTL $LIBICONV" + LTLIBINTL="$LTLIBINTL $LTLIBICONV" + eval "$gt_func_gnugettext_libintl=yes" + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + fi + CPPFLAGS="$gt_save_CPPFLAGS" + LIBS="$gt_save_LIBS" +fi +eval ac_res=\$$gt_func_gnugettext_libintl + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + fi + + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ + || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ + && test "$PACKAGE" != gettext-runtime \ + && test "$PACKAGE" != gettext-tools; }; then + gt_use_preinstalled_gnugettext=yes + else + LIBINTL= + LTLIBINTL= + INCINTL= + fi + + + + if test -n "$INTL_MACOSX_LIBS"; then + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" + LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" + fi + fi + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + +$as_echo "#define ENABLE_NLS 1" >>confdefs.h + + else + USE_NLS=no + fi + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use NLS" >&5 +$as_echo_n "checking whether to use NLS... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 +$as_echo "$USE_NLS" >&6; } + if test "$USE_NLS" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking where the gettext function comes from" >&5 +$as_echo_n "checking where the gettext function comes from... " >&6; } + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + gt_source="external libintl" + else + gt_source="libc" + fi + else + gt_source="included intl directory" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_source" >&5 +$as_echo "$gt_source" >&6; } + fi + + if test "$USE_NLS" = "yes"; then + + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libintl" >&5 +$as_echo_n "checking how to link with libintl... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBINTL" >&5 +$as_echo "$LIBINTL" >&6; } + + for element in $INCINTL; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + fi + + +$as_echo "#define HAVE_GETTEXT 1" >>confdefs.h + + +$as_echo "#define HAVE_DCGETTEXT 1" >>confdefs.h + + fi + + POSUB=po + fi + + + + INTLLIBS="$LIBINTL" + + + + + + + + +# check for iconv + + + + + + am_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCICONV; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 +$as_echo_n "checking for iconv... " >&6; } +if test "${am_cv_func_iconv+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$am_save_LIBS" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +$as_echo "$am_cv_func_iconv" >&6; } + if test "$am_cv_func_iconv" = yes; then + +$as_echo "#define HAVE_ICONV 1" >>confdefs.h + + fi + if test "$am_cv_lib_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 +$as_echo_n "checking how to link with libiconv... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 +$as_echo "$LIBICONV" >&6; } + else + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + + + + if test "$am_cv_func_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 +$as_echo_n "checking for iconv declaration... " >&6; } + if test "${am_cv_proto_iconv+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + am_cv_proto_iconv_arg1="" +else + am_cv_proto_iconv_arg1="const" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" +fi + + am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- + }$am_cv_proto_iconv" >&5 +$as_echo "${ac_t:- + }$am_cv_proto_iconv" >&6; } + +cat >>confdefs.h <<_ACEOF +#define ICONV_CONST $am_cv_proto_iconv_arg1 +_ACEOF + + fi + + +# Checks for standard typedefs, structures, and compiler characteristics. +ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" +if test "x$ac_cv_type_pid_t" = x""yes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = x""yes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" +if test "x$ac_cv_type_mode_t" = x""yes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define mode_t int +_ACEOF + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 +$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } +if test "${ac_cv_header_time+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_time=yes +else + ac_cv_header_time=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 +$as_echo "$ac_cv_header_time" >&6; } +if test $ac_cv_header_time = yes; then + +$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat file-mode macros are broken" >&5 +$as_echo_n "checking whether stat file-mode macros are broken... " >&6; } +if test "${ac_cv_header_stat_broken+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include + +#if defined S_ISBLK && defined S_IFDIR +extern char c1[S_ISBLK (S_IFDIR) ? -1 : 1]; +#endif + +#if defined S_ISBLK && defined S_IFCHR +extern char c2[S_ISBLK (S_IFCHR) ? -1 : 1]; +#endif + +#if defined S_ISLNK && defined S_IFREG +extern char c3[S_ISLNK (S_IFREG) ? -1 : 1]; +#endif + +#if defined S_ISSOCK && defined S_IFREG +extern char c4[S_ISSOCK (S_IFREG) ? -1 : 1]; +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stat_broken=no +else + ac_cv_header_stat_broken=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stat_broken" >&5 +$as_echo "$ac_cv_header_stat_broken" >&6; } +if test $ac_cv_header_stat_broken = yes; then + +$as_echo "#define STAT_MACROS_BROKEN 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 +$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } +if test "${ac_cv_header_stdbool_h+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifndef bool + "error: bool is not defined" +#endif +#ifndef false + "error: false is not defined" +#endif +#if false + "error: false is not 0" +#endif +#ifndef true + "error: true is not defined" +#endif +#if true != 1 + "error: true is not 1" +#endif +#ifndef __bool_true_false_are_defined + "error: __bool_true_false_are_defined is not defined" +#endif + + struct s { _Bool s: 1; _Bool t; } s; + + char a[true == 1 ? 1 : -1]; + char b[false == 0 ? 1 : -1]; + char c[__bool_true_false_are_defined == 1 ? 1 : -1]; + char d[(bool) 0.5 == true ? 1 : -1]; + bool e = &s; + char f[(_Bool) 0.0 == false ? 1 : -1]; + char g[true]; + char h[sizeof (_Bool)]; + char i[sizeof s.t]; + enum { j = false, k = true, l = false * true, m = true * 256 }; + /* The following fails for + HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ + _Bool n[m]; + char o[sizeof n == m * sizeof n[0] ? 1 : -1]; + char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; +# if defined __xlc__ || defined __GNUC__ + /* Catch a bug in IBM AIX xlc compiler version 6.0.0.0 + reported by James Lemley on 2005-10-05; see + http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html + This test is not quite right, since xlc is allowed to + reject this program, as the initializer for xlcbug is + not one of the forms that C requires support for. + However, doing the test right would require a runtime + test, and that would make cross-compilation harder. + Let us hope that IBM fixes the xlc bug, and also adds + support for this kind of constant expression. In the + meantime, this test will reject xlc, which is OK, since + our stdbool.h substitute should suffice. We also test + this with GCC, where it should work, to detect more + quickly whether someone messes up the test in the + future. */ + char digs[] = "0123456789"; + int xlcbug = 1 / (&(digs + 5)[-2 + (bool) 1] == &digs[4] ? 1 : -1); +# endif + /* Catch a bug in an HP-UX C compiler. See + http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html + http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html + */ + _Bool q = true; + _Bool *pq = &q; + +int +main () +{ + + *pq |= q; + *pq |= ! q; + /* Refer to every declared value, to avoid compiler optimizations. */ + return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + + !m + !n + !o + !p + !q + !pq); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdbool_h=yes +else + ac_cv_header_stdbool_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 +$as_echo "$ac_cv_header_stdbool_h" >&6; } +ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" +if test "x$ac_cv_type__Bool" = x""yes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE__BOOL 1 +_ACEOF + + +fi + +if test $ac_cv_header_stdbool_h = yes; then + +$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 +$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } +if test "${ac_cv_struct_tm+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include + +int +main () +{ +struct tm tm; + int *p = &tm.tm_sec; + return !p; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_struct_tm=time.h +else + ac_cv_struct_tm=sys/time.h +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 +$as_echo "$ac_cv_struct_tm" >&6; } +if test $ac_cv_struct_tm = sys/time.h; then + +$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h + +fi + + +ac_fn_c_check_member "$LINENO" "struct sockaddr_in" "sin_len" "ac_cv_member_struct_sockaddr_in_sin_len" " + #include + #include + #include + +" +if test "x$ac_cv_member_struct_sockaddr_in_sin_len" = x""yes; then : + +$as_echo "#define HAVE_SOCKADDR_IN_SIN_LEN 1" >>confdefs.h + + +fi + + + + +# Checks for library functions. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether closedir returns void" >&5 +$as_echo_n "checking whether closedir returns void... " >&6; } +if test "${ac_cv_func_closedir_void+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_closedir_void=yes +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header_dirent> +#ifndef __cplusplus +int closedir (); +#endif + +int +main () +{ +return closedir (opendir (".")) != 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_closedir_void=no +else + ac_cv_func_closedir_void=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_closedir_void" >&5 +$as_echo "$ac_cv_func_closedir_void" >&6; } +if test $ac_cv_func_closedir_void = yes; then + +$as_echo "#define CLOSEDIR_VOID 1" >>confdefs.h + +fi + +for ac_header in vfork.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" +if test "x$ac_cv_header_vfork_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_VFORK_H 1 +_ACEOF + +fi + +done + +for ac_func in fork vfork +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +if test "x$ac_cv_func_fork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 +$as_echo_n "checking for working fork... " >&6; } +if test "${ac_cv_func_fork_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_fork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* By Ruediger Kuhlmann. */ + return fork () < 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_fork_works=yes +else + ac_cv_func_fork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 +$as_echo "$ac_cv_func_fork_works" >&6; } + +else + ac_cv_func_fork_works=$ac_cv_func_fork +fi +if test "x$ac_cv_func_fork_works" = xcross; then + case $host in + *-*-amigaos* | *-*-msdosdjgpp*) + # Override, as these systems have only a dummy fork() stub + ac_cv_func_fork_works=no + ;; + *) + ac_cv_func_fork_works=yes + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} +fi +ac_cv_func_vfork_works=$ac_cv_func_vfork +if test "x$ac_cv_func_vfork" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 +$as_echo_n "checking for working vfork... " >&6; } +if test "${ac_cv_func_vfork_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_vfork_works=cross +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Thanks to Paul Eggert for this test. */ +$ac_includes_default +#include +#ifdef HAVE_VFORK_H +# include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. The compiler + is told about this with #include , but some compilers + (e.g. gcc -O) don't grok . Test for this by using a + static variable whose address is put into a register that is + clobbered by the vfork. */ +static void +#ifdef __cplusplus +sparc_address_test (int arg) +# else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} + +int +main () +{ + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (0); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. This + test uses lots of local variables, at least as many local + variables as main has allocated so far including compiler + temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris + 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should + reuse the register of parent for one of the local variables, + since it will think that parent can't possibly be used any more + in this routine. Assigning to the local variable will thus + munge parent in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent + from child file descriptors. If the child closes a descriptor + before it execs or exits, this munges the parent's descriptor + as well. Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + return ( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_vfork_works=yes +else + ac_cv_func_vfork_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 +$as_echo "$ac_cv_func_vfork_works" >&6; } + +fi; +if test "x$ac_cv_func_fork_works" = xcross; then + ac_cv_func_vfork_works=$ac_cv_func_vfork + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 +$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} +fi + +if test "x$ac_cv_func_vfork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h + +else + +$as_echo "#define vfork fork" >>confdefs.h + +fi +if test "x$ac_cv_func_fork_works" = xyes; then + +$as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h + +fi + +if test $ac_cv_c_compiler_gnu = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 +$as_echo_n "checking whether $CC needs -traditional... " >&6; } +if test "${ac_cv_prog_gcc_traditional+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_pattern="Autoconf.*'x'" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +Autoconf TIOCGETP +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +else + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +Autoconf TCGETA +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 +$as_echo "$ac_cv_prog_gcc_traditional" >&6; } + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5 +$as_echo_n "checking for working memcmp... " >&6; } +if test "${ac_cv_func_memcmp_working+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_memcmp_working=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Some versions of memcmp are not 8-bit clean. */ + char c0 = '\100', c1 = '\200', c2 = '\201'; + if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) + return 1; + + /* The Next x86 OpenStep bug shows up only when comparing 16 bytes + or more and with at least one buffer not starting on a 4-byte boundary. + William Lewis provided this test program. */ + { + char foo[21]; + char bar[21]; + int i; + for (i = 0; i < 4; i++) + { + char *a = foo + i; + char *b = bar + i; + strcpy (a, "--------01111111"); + strcpy (b, "--------10000000"); + if (memcmp (a, b, 16) >= 0) + return 1; + } + return 0; + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_memcmp_working=yes +else + ac_cv_func_memcmp_working=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5 +$as_echo "$ac_cv_func_memcmp_working" >&6; } +test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in + *" memcmp.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" + ;; +esac + + +for ac_header in sys/select.h sys/socket.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5 +$as_echo_n "checking types of arguments for select... " >&6; } +if test "${ac_cv_func_select_args+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + for ac_arg234 in 'fd_set *' 'int *' 'void *'; do + for ac_arg1 in 'int' 'size_t' 'unsigned long int' 'unsigned int'; do + for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#ifdef HAVE_SYS_SELECT_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +int +main () +{ +extern int select ($ac_arg1, + $ac_arg234, $ac_arg234, $ac_arg234, + $ac_arg5); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done + done +done +# Provide a safe default value. +: ${ac_cv_func_select_args='int,int *,struct timeval *'} + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5 +$as_echo "$ac_cv_func_select_args" >&6; } +ac_save_IFS=$IFS; IFS=',' +set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'` +IFS=$ac_save_IFS +shift + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG1 $1 +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG234 ($2) +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define SELECT_TYPE_ARG5 ($3) +_ACEOF + +rm -f conftest* + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 +$as_echo_n "checking for uid_t in sys/types.h... " >&6; } +if test "${ac_cv_type_uid_t+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "uid_t" >/dev/null 2>&1; then : + ac_cv_type_uid_t=yes +else + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 +$as_echo "$ac_cv_type_uid_t" >&6; } +if test $ac_cv_type_uid_t = no; then + +$as_echo "#define uid_t int" >>confdefs.h + + +$as_echo "#define gid_t int" >>confdefs.h + +fi + +for ac_header in unistd.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" +if test "x$ac_cv_header_unistd_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_UNISTD_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5 +$as_echo_n "checking for working chown... " >&6; } +if test "${ac_cv_func_chown_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_chown_works=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#include + +int +main () +{ + char *f = "conftest.chown"; + struct stat before, after; + + if (creat (f, 0600) < 0) + return 1; + if (stat (f, &before) < 0) + return 1; + if (chown (f, (uid_t) -1, (gid_t) -1) == -1) + return 1; + if (stat (f, &after) < 0) + return 1; + return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_chown_works=yes +else + ac_cv_func_chown_works=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +rm -f conftest.chown + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chown_works" >&5 +$as_echo "$ac_cv_func_chown_works" >&6; } +if test $ac_cv_func_chown_works = yes; then + +$as_echo "#define HAVE_CHOWN 1" >>confdefs.h + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 +$as_echo_n "checking return type of signal handlers... " >&6; } +if test "${ac_cv_type_signal+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include + +int +main () +{ +return *(signal (0, 0)) (0) == 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_type_signal=int +else + ac_cv_type_signal=void +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 +$as_echo "$ac_cv_type_signal" >&6; } + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 +$as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; } +if test "${ac_cv_func_lstat_dereferences_slashed_symlink+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + rm -f conftest.sym conftest.file +echo >conftest.file +if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then + if test "$cross_compiling" = yes; then : + ac_cv_func_lstat_dereferences_slashed_symlink=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +struct stat sbuf; + /* Linux will dereference the symlink and fail, as required by POSIX. + That is better in the sense that it means we will not + have to compile and use the lstat wrapper. */ + return lstat ("conftest.sym/", &sbuf) == 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_lstat_dereferences_slashed_symlink=yes +else + ac_cv_func_lstat_dereferences_slashed_symlink=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +else + # If the `ln -s' command failed, then we probably don't even + # have an lstat function. + ac_cv_func_lstat_dereferences_slashed_symlink=no +fi +rm -f conftest.sym conftest.file + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 +$as_echo "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } + +test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && + +cat >>confdefs.h <<_ACEOF +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +_ACEOF + + +if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then + case " $LIBOBJS " in + *" lstat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS lstat.$ac_objext" + ;; +esac + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat accepts an empty string" >&5 +$as_echo_n "checking whether stat accepts an empty string... " >&6; } +if test "${ac_cv_func_stat_empty_string_bug+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_stat_empty_string_bug=yes +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +struct stat sbuf; + return stat ("", &sbuf) == 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_stat_empty_string_bug=no +else + ac_cv_func_stat_empty_string_bug=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_stat_empty_string_bug" >&5 +$as_echo "$ac_cv_func_stat_empty_string_bug" >&6; } +if test $ac_cv_func_stat_empty_string_bug = yes; then + case " $LIBOBJS " in + *" stat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS stat.$ac_objext" + ;; +esac + + +cat >>confdefs.h <<_ACEOF +#define HAVE_STAT_EMPTY_STRING_BUG 1 +_ACEOF + +fi + +for ac_func in strftime +do : + ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime" +if test "x$ac_cv_func_strftime" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRFTIME 1 +_ACEOF + +else + # strftime is in -lintl on SCO UNIX. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strftime in -lintl" >&5 +$as_echo_n "checking for strftime in -lintl... " >&6; } +if test "${ac_cv_lib_intl_strftime+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lintl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char strftime (); +int +main () +{ +return strftime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_intl_strftime=yes +else + ac_cv_lib_intl_strftime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_strftime" >&5 +$as_echo "$ac_cv_lib_intl_strftime" >&6; } +if test "x$ac_cv_lib_intl_strftime" = x""yes; then : + $as_echo "#define HAVE_STRFTIME 1" >>confdefs.h + +LIBS="-lintl $LIBS" +fi + +fi +done + +for ac_func in vprintf +do : + ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" +if test "x$ac_cv_func_vprintf" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_VPRINTF 1 +_ACEOF + +ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" +if test "x$ac_cv_func__doprnt" = x""yes; then : + +$as_echo "#define HAVE_DOPRNT 1" >>confdefs.h + +fi + +fi +done + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 +$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } +if test "${ac_cv_header_sys_wait_h+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +int +main () +{ + int s; + wait (&s); + s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_sys_wait_h=yes +else + ac_cv_header_sys_wait_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 +$as_echo "$ac_cv_header_sys_wait_h" >&6; } +if test $ac_cv_header_sys_wait_h = yes; then + +$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" +if test "x$ac_cv_type_off_t" = x""yes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define off_t long int +_ACEOF + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 +$as_echo_n "checking for uid_t in sys/types.h... " >&6; } +if test "${ac_cv_type_uid_t+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "uid_t" >/dev/null 2>&1; then : + ac_cv_type_uid_t=yes +else + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 +$as_echo "$ac_cv_type_uid_t" >&6; } +if test $ac_cv_type_uid_t = no; then + +$as_echo "#define uid_t int" >>confdefs.h + + +$as_echo "#define gid_t int" >>confdefs.h + +fi + +for ac_func in floor gethostname memmove rmdir strncasecmp strrchr strtol atoll dup2 fdatasync ftruncate gettimeofday memset mkdir mkfifo select socket strcasecmp strchr strdup strerror strstr clock_gettime getrusage rand uname setlocale getcwd mktime gmtime_r gmtime strlcpy strlcat ftruncate stat64 sbrk mmap mremap setrlimit sysconf gethostbyaddr initgroups getifaddrs freeifaddrs getnameinfo getaddrinfo inet_ntoa localtime_r nl_langinfo putenv realpath strndup gethostbyname2 gethostbyname getpeerucred getpeereid setresuid +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +# restore LIBS +LIBS=$SAVE_LIBS + +gn_user_home_dir="~/.gnunet" + +# Check whether --with-user-home-dir was given. +if test "${with_user_home_dir+set}" = set; then : + withval=$with_user_home_dir; gn_user_home_dir=$withval +fi + +GN_USER_HOME_DIR=$gn_user_home_dir + +gn_daemon_home_dir="/var/lib/gnunet" + +# Check whether --with-daemon-home-dir was given. +if test "${with_daemon_home_dir+set}" = set; then : + withval=$with_daemon_home_dir; gn_daemon_home_dir=$withval +fi + +GN_DAEMON_HOME_DIR=$gn_daemon_home_dir + +gn_daemon_config_dir="/etc" + +# Check whether --with-daemon-config-dir was given. +if test "${with_daemon_config_dir+set}" = set; then : + withval=$with_daemon_config_dir; gn_daemon_config_dir=$withval +fi + +GN_DAEMON_CONFIG_DIR=$gn_daemon_config_dir + + +GN_INTLINCL="" +GN_LIBINTL="$LTLIBINTL" +# Check whether --enable-framework was given. +if test "${enable_framework+set}" = set; then : + enableval=$enable_framework; enable_framework_build=$enableval +fi + + if test x$enable_framework_build = xyes; then + WANT_FRAMEWORK_TRUE= + WANT_FRAMEWORK_FALSE='#' +else + WANT_FRAMEWORK_TRUE='#' + WANT_FRAMEWORK_FALSE= +fi + +if test x$enable_framework_build = xyes +then + +$as_echo "#define FRAMEWORK_BUILD 1" >>confdefs.h + + GN_INTLINCL='-I$(top_srcdir)/src/intlemu' + GN_LIBINTL='$(top_builddir)/src/intlemu/libintlemu.la -framework CoreFoundation' + + for element in $GN_INTLINCL; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + +fi + +GN_LIB_LDFLAGS="-export-dynamic -no-undefined" +GN_PLUGIN_LDFLAGS="-export-dynamic -avoid-version -module -no-undefined" + + + + + + + + + + + + + + + + + +# test for sudo +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sudo" >&5 +$as_echo_n "checking for sudo... " >&6; } + +# Check whether --with-sudo was given. +if test "${with_sudo+set}" = set; then : + withval=$with_sudo; { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_sudo\"" >&5 +$as_echo "\"$with_sudo\"" >&6; } + case $with_sudo in + no) + SUDO_BINARY= + ;; + yes) + SUDO_BINARY=sudo + ;; + *) + SUDO_BINARY=$with_sudo + ;; + esac + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + +# test for gnunetdns group name +GNUNETDNS_GROUP=gnunetdns +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnunetdns group name" >&5 +$as_echo_n "checking for gnunetdns group name... " >&6; } + +# Check whether --with-gnunetdns was given. +if test "${with_gnunetdns+set}" = set; then : + withval=$with_gnunetdns; { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_gnunetdns\"" >&5 +$as_echo "\"$with_gnunetdns\"" >&6; } + case $with_gnunetdns in + no) + GNUNETDNS_GROUP=gnunet + ;; + yes) + GNUNETDNS_GROUP=gnunetdns + ;; + *) + GNUNETDNS_GROUP=$with_gnunetdns + ;; + esac + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gnunetdns" >&5 +$as_echo "gnunetdns" >&6; } +fi + + + + +# should 'make check' run tests? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to run tests" >&5 +$as_echo_n "checking whether to run tests... " >&6; } +# Check whether --enable-testruns was given. +if test "${enable_testruns+set}" = set; then : + enableval=$enable_testruns; enable_tests_run=${enableval} +else + enable_tests_run=yes +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_test_run" >&5 +$as_echo "$enable_test_run" >&6; } + if test "x$enable_tests_run" = "xyes"; then + ENABLE_TEST_RUN_TRUE= + ENABLE_TEST_RUN_FALSE='#' +else + ENABLE_TEST_RUN_TRUE='#' + ENABLE_TEST_RUN_FALSE= +fi + + +# should expensive tests be run? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to run expensive tests" >&5 +$as_echo_n "checking whether to run expensive tests... " >&6; } +# Check whether --enable-expensivetests was given. +if test "${enable_expensivetests+set}" = set; then : + enableval=$enable_expensivetests; enable_expensive=${enableval} +else + enable_expensive=no +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_expensive" >&5 +$as_echo "$enable_expensive" >&6; } + if test "x$enable_expensive" = "xyes"; then + HAVE_EXPENSIVE_TESTS_TRUE= + HAVE_EXPENSIVE_TESTS_FALSE='#' +else + HAVE_EXPENSIVE_TESTS_TRUE='#' + HAVE_EXPENSIVE_TESTS_FALSE= +fi + + +# should benchmarks be run? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to run benchmarks during make check" >&5 +$as_echo_n "checking whether to run benchmarks during make check... " >&6; } +# Check whether --enable-benchmarks was given. +if test "${enable_benchmarks+set}" = set; then : + enableval=$enable_benchmarks; enable_benchmarks=${enableval} +else + enable_benchmarks=no +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_benchmarks" >&5 +$as_echo "$enable_benchmarks" >&6; } + if test "x$enable_benchmarks" = "xyes"; then + HAVE_BENCHMARKS_TRUE= + HAVE_BENCHMARKS_FALSE='#' +else + HAVE_BENCHMARKS_TRUE='#' + HAVE_BENCHMARKS_FALSE= +fi + + +# should experimental code be compiled (code that may not yet compile)? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile experimental code" >&5 +$as_echo_n "checking whether to compile experimental code... " >&6; } +# Check whether --enable-experimental was given. +if test "${enable_experimental+set}" = set; then : + enableval=$enable_experimental; enable_experimental=${enableval} +else + enable_experimental=no +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_experimental" >&5 +$as_echo "$enable_experimental" >&6; } + if test "x$enable_experimental" = "xyes"; then + HAVE_EXPERIMENTAL_TRUE= + HAVE_EXPERIMENTAL_FALSE='#' +else + HAVE_EXPERIMENTAL_TRUE='#' + HAVE_EXPERIMENTAL_FALSE= +fi + + +# should code be enabled that works around missing OS functionality on Windows? +# used for test cases +if test $build_target = "mingw" +then + workarounds=1 +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable windows workarounds" >&5 +$as_echo_n "checking whether to enable windows workarounds... " >&6; } + # Check whether --enable-windows_workarounds was given. +if test "${enable_windows_workarounds+set}" = set; then : + enableval=$enable_windows_workarounds; enable_workarounds=${enableval} +else + enable_workarounds=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_workarounds" >&5 +$as_echo "$enable_workarounds" >&6; } + if test x$enable_windows_workarounds = "xyes" + then + workarounds=1 + else + workarounds=0 + fi +fi + +cat >>confdefs.h <<_ACEOF +#define ENABLE_WINDOWS_WORKAROUNDS $workarounds +_ACEOF + + +# gcov compilation +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with support for code coverage analysis" >&5 +$as_echo_n "checking whether to compile with support for code coverage analysis... " >&6; } +# Check whether --enable-coverage was given. +if test "${enable_coverage+set}" = set; then : + enableval=$enable_coverage; use_gcov=${enableval} +else + use_gcov=no +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_gcov" >&5 +$as_echo "$use_gcov" >&6; } + if test "x$use_gcov" = "xyes"; then + USE_COVERAGE_TRUE= + USE_COVERAGE_FALSE='#' +else + USE_COVERAGE_TRUE='#' + USE_COVERAGE_FALSE= +fi + + + +ac_config_files="$ac_config_files Makefile contrib/Makefile doc/Makefile doc/man/Makefile m4/Makefile po/Makefile.in src/Makefile src/arm/Makefile src/arm/arm.conf src/ats/Makefile src/ats/ats.conf src/block/Makefile src/chat/Makefile src/chat/chat.conf src/core/Makefile src/core/core.conf src/datacache/Makefile src/datastore/Makefile src/datastore/datastore.conf src/dht/Makefile src/dht/dht.conf src/dns/Makefile src/dns/dns.conf src/dv/Makefile src/dv/dv.conf src/exit/Makefile src/fragmentation/Makefile src/fs/Makefile src/fs/fs.conf src/gns/Makefile src/gns/gns.conf src/hello/Makefile src/include/Makefile src/include/gnunet_directories.h src/hostlist/Makefile src/mesh/Makefile src/mesh/mesh.conf src/namestore/Makefile src/namestore/namestore.conf src/nat/Makefile src/nse/Makefile src/nse/nse.conf src/peerinfo/Makefile src/peerinfo/peerinfo.conf src/peerinfo-tool/Makefile src/pt/Makefile src/statistics/Makefile src/statistics/statistics.conf src/stream/Makefile src/template/Makefile src/testing/Makefile src/topology/Makefile src/transport/Makefile src/transport/transport.conf src/tun/Makefile src/util/Makefile src/util/resolver.conf src/vpn/Makefile src/vpn/vpn.conf src/integration-tests/Makefile pkgconfig/Makefile pkgconfig/gnunetarm.pc pkgconfig/gnunetblock.pc pkgconfig/gnunetcore.pc pkgconfig/gnunetdatacache.pc pkgconfig/gnunetdatastore.pc pkgconfig/gnunetdht.pc pkgconfig/gnunetdhtlog.pc pkgconfig/gnunetdv.pc pkgconfig/gnunetfragmentation.pc pkgconfig/gnunetfs.pc pkgconfig/gnunethello.pc pkgconfig/gnunetnat.pc pkgconfig/gnunetnse.pc pkgconfig/gnunetpeerinfo.pc pkgconfig/gnunetstatistics.pc pkgconfig/gnunettesting.pc pkgconfig/gnunettransport.pc pkgconfig/gnunetutil.pc" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepOBJC_TRUE}" && test -z "${am__fastdepOBJC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepOBJC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${INSTALL_LTDL_TRUE}" && test -z "${INSTALL_LTDL_FALSE}"; then + as_fn_error $? "conditional \"INSTALL_LTDL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CONVENIENCE_LTDL_TRUE}" && test -z "${CONVENIENCE_LTDL_FALSE}"; then + as_fn_error $? "conditional \"CONVENIENCE_LTDL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +LT_CONFIG_H=gnunet_config.h + + _ltdl_libobjs= + _ltdl_ltlibobjs= + if test -n "$_LT_LIBOBJS"; then + # Remove the extension. + _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' + for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | sed "$_lt_sed_drop_objext" | sort -u`; do + _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" + _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" + done + fi + ltdl_LIBOBJS=$_ltdl_libobjs + + ltdl_LTLIBOBJS=$_ltdl_ltlibobjs + + +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DARWIN_TRUE}" && test -z "${DARWIN_FALSE}"; then + as_fn_error $? "conditional \"DARWIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CYGWIN_TRUE}" && test -z "${CYGWIN_FALSE}"; then + as_fn_error $? "conditional \"CYGWIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MINGW_TRUE}" && test -z "${MINGW_FALSE}"; then + as_fn_error $? "conditional \"MINGW\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${SOLARIS_TRUE}" && test -z "${SOLARIS_FALSE}"; then + as_fn_error $? "conditional \"SOLARIS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${XFREEBSD_TRUE}" && test -z "${XFREEBSD_FALSE}"; then + as_fn_error $? "conditional \"XFREEBSD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${OPENBSD_TRUE}" && test -z "${OPENBSD_FALSE}"; then + as_fn_error $? "conditional \"OPENBSD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LINUX_TRUE}" && test -z "${LINUX_FALSE}"; then + as_fn_error $? "conditional \"LINUX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepOBJC_TRUE}" && test -z "${am__fastdepOBJC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepOBJC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_LIBGLPK_TRUE}" && test -z "${HAVE_LIBGLPK_FALSE}"; then + as_fn_error $? "conditional \"HAVE_LIBGLPK\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_LIBGLPK_TRUE}" && test -z "${HAVE_LIBGLPK_FALSE}"; then + as_fn_error $? "conditional \"HAVE_LIBGLPK\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_SQLITE_TRUE}" && test -z "${HAVE_SQLITE_FALSE}"; then + as_fn_error $? "conditional \"HAVE_SQLITE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_POSTGRES_TRUE}" && test -z "${HAVE_POSTGRES_FALSE}"; then + as_fn_error $? "conditional \"HAVE_POSTGRES\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_ZLIB_TRUE}" && test -z "${HAVE_ZLIB_FALSE}"; then + as_fn_error $? "conditional \"HAVE_ZLIB\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_MYSQL_TRUE}" && test -z "${HAVE_MYSQL_FALSE}"; then + as_fn_error $? "conditional \"HAVE_MYSQL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_MYSQLE_TRUE}" && test -z "${HAVE_MYSQLE_FALSE}"; then + as_fn_error $? "conditional \"HAVE_MYSQLE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_MHD_TRUE}" && test -z "${HAVE_MHD_FALSE}"; then + as_fn_error $? "conditional \"HAVE_MHD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_PYTHON_TRUE}" && test -z "${HAVE_PYTHON_FALSE}"; then + as_fn_error $? "conditional \"HAVE_PYTHON\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_PYTHON_PEXPECT_TRUE}" && test -z "${HAVE_PYTHON_PEXPECT_FALSE}"; then + as_fn_error $? "conditional \"HAVE_PYTHON_PEXPECT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_PYTHON_PEXPECT_TRUE}" && test -z "${HAVE_PYTHON_PEXPECT_FALSE}"; then + as_fn_error $? "conditional \"HAVE_PYTHON_PEXPECT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${WANT_FRAMEWORK_TRUE}" && test -z "${WANT_FRAMEWORK_FALSE}"; then + as_fn_error $? "conditional \"WANT_FRAMEWORK\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_TEST_RUN_TRUE}" && test -z "${ENABLE_TEST_RUN_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_TEST_RUN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_EXPENSIVE_TESTS_TRUE}" && test -z "${HAVE_EXPENSIVE_TESTS_FALSE}"; then + as_fn_error $? "conditional \"HAVE_EXPENSIVE_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_BENCHMARKS_TRUE}" && test -z "${HAVE_BENCHMARKS_FALSE}"; then + as_fn_error $? "conditional \"HAVE_BENCHMARKS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_EXPERIMENTAL_TRUE}" && test -z "${HAVE_EXPERIMENTAL_FALSE}"; then + as_fn_error $? "conditional \"HAVE_EXPERIMENTAL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_COVERAGE_TRUE}" && test -z "${USE_COVERAGE_FALSE}"; then + as_fn_error $? "conditional \"USE_COVERAGE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by gnunet $as_me 0.9.2, which was +generated by GNU Autoconf 2.67. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +gnunet config.status 0.9.2 +configured by $0, generated by GNU Autoconf 2.67, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`' +macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`' +enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`' +AS='`$ECHO "X$AS" | $Xsed -e "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "X$DLLTOOL" | $Xsed -e "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`' +pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`' +host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`' +host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`' +host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`' +build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`' +build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`' +build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`' +SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`' +Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`' +GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`' +EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`' +FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`' +LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`' +NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`' +LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`' +ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`' +exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`' +lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`' +reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`' +AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`' +STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`' +RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`' +compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`' +GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`' +SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`' +ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`' +need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`' +LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`' +libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`' +fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`' +version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`' +runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`' +libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`' +soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`' +old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`' +striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "X$compiler_lib_search_dirs" | $Xsed -e "$delay_single_quote_subst"`' +predep_objects='`$ECHO "X$predep_objects" | $Xsed -e "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "X$postdep_objects" | $Xsed -e "$delay_single_quote_subst"`' +predeps='`$ECHO "X$predeps" | $Xsed -e "$delay_single_quote_subst"`' +postdeps='`$ECHO "X$postdeps" | $Xsed -e "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "X$compiler_lib_search_path" | $Xsed -e "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "X$LD_CXX" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "X$old_archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "X$compiler_CXX" | $Xsed -e "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "X$GCC_CXX" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "X$lt_prog_compiler_no_builtin_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "X$lt_prog_compiler_wl_CXX" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "X$lt_prog_compiler_pic_CXX" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "X$lt_prog_compiler_static_CXX" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "X$lt_cv_prog_compiler_c_o_CXX" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "X$archive_cmds_need_lc_CXX" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "X$enable_shared_with_static_runtimes_CXX" | $Xsed -e "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "X$export_dynamic_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "X$whole_archive_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "X$compiler_needs_object_CXX" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "X$old_archive_from_new_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "X$old_archive_from_expsyms_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "X$archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "X$archive_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "X$module_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "X$module_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "X$with_gnu_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "X$allow_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "X$no_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "X$hardcode_libdir_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld_CXX='`$ECHO "X$hardcode_libdir_flag_spec_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "X$hardcode_libdir_separator_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "X$hardcode_direct_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "X$hardcode_direct_absolute_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "X$hardcode_minus_L_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "X$hardcode_shlibpath_var_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "X$hardcode_automatic_CXX" | $Xsed -e "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "X$inherit_rpath_CXX" | $Xsed -e "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "X$link_all_deplibs_CXX" | $Xsed -e "$delay_single_quote_subst"`' +fix_srcfile_path_CXX='`$ECHO "X$fix_srcfile_path_CXX" | $Xsed -e "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "X$always_export_symbols_CXX" | $Xsed -e "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "X$export_symbols_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "X$exclude_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "X$include_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "X$prelink_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "X$file_list_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "X$hardcode_action_CXX" | $Xsed -e "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "X$compiler_lib_search_dirs_CXX" | $Xsed -e "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "X$predep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "X$postdep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "X$predeps_CXX" | $Xsed -e "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "X$postdeps_CXX" | $Xsed -e "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "X$compiler_lib_search_path_CXX" | $Xsed -e "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +deplibs_check_method \ +file_magic_cmd \ +AR \ +AR_FLAGS \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +SHELL \ +ECHO \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_wl \ +lt_prog_compiler_pic \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ +hardcode_libdir_separator \ +fix_srcfile_path \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_flag_spec_ld_CXX \ +hardcode_libdir_separator_CXX \ +fix_srcfile_path_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\` + ;; +esac + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + + +# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it + # from automake < 1.5. + eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "gnunet_config.h") CONFIG_HEADERS="$CONFIG_HEADERS gnunet_config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "po-directories") CONFIG_COMMANDS="$CONFIG_COMMANDS po-directories" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "contrib/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/Makefile" ;; + "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "doc/man/Makefile") CONFIG_FILES="$CONFIG_FILES doc/man/Makefile" ;; + "m4/Makefile") CONFIG_FILES="$CONFIG_FILES m4/Makefile" ;; + "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "src/arm/Makefile") CONFIG_FILES="$CONFIG_FILES src/arm/Makefile" ;; + "src/arm/arm.conf") CONFIG_FILES="$CONFIG_FILES src/arm/arm.conf" ;; + "src/ats/Makefile") CONFIG_FILES="$CONFIG_FILES src/ats/Makefile" ;; + "src/ats/ats.conf") CONFIG_FILES="$CONFIG_FILES src/ats/ats.conf" ;; + "src/block/Makefile") CONFIG_FILES="$CONFIG_FILES src/block/Makefile" ;; + "src/chat/Makefile") CONFIG_FILES="$CONFIG_FILES src/chat/Makefile" ;; + "src/chat/chat.conf") CONFIG_FILES="$CONFIG_FILES src/chat/chat.conf" ;; + "src/core/Makefile") CONFIG_FILES="$CONFIG_FILES src/core/Makefile" ;; + "src/core/core.conf") CONFIG_FILES="$CONFIG_FILES src/core/core.conf" ;; + "src/datacache/Makefile") CONFIG_FILES="$CONFIG_FILES src/datacache/Makefile" ;; + "src/datastore/Makefile") CONFIG_FILES="$CONFIG_FILES src/datastore/Makefile" ;; + "src/datastore/datastore.conf") CONFIG_FILES="$CONFIG_FILES src/datastore/datastore.conf" ;; + "src/dht/Makefile") CONFIG_FILES="$CONFIG_FILES src/dht/Makefile" ;; + "src/dht/dht.conf") CONFIG_FILES="$CONFIG_FILES src/dht/dht.conf" ;; + "src/dns/Makefile") CONFIG_FILES="$CONFIG_FILES src/dns/Makefile" ;; + "src/dns/dns.conf") CONFIG_FILES="$CONFIG_FILES src/dns/dns.conf" ;; + "src/dv/Makefile") CONFIG_FILES="$CONFIG_FILES src/dv/Makefile" ;; + "src/dv/dv.conf") CONFIG_FILES="$CONFIG_FILES src/dv/dv.conf" ;; + "src/exit/Makefile") CONFIG_FILES="$CONFIG_FILES src/exit/Makefile" ;; + "src/fragmentation/Makefile") CONFIG_FILES="$CONFIG_FILES src/fragmentation/Makefile" ;; + "src/fs/Makefile") CONFIG_FILES="$CONFIG_FILES src/fs/Makefile" ;; + "src/fs/fs.conf") CONFIG_FILES="$CONFIG_FILES src/fs/fs.conf" ;; + "src/gns/Makefile") CONFIG_FILES="$CONFIG_FILES src/gns/Makefile" ;; + "src/gns/gns.conf") CONFIG_FILES="$CONFIG_FILES src/gns/gns.conf" ;; + "src/hello/Makefile") CONFIG_FILES="$CONFIG_FILES src/hello/Makefile" ;; + "src/include/Makefile") CONFIG_FILES="$CONFIG_FILES src/include/Makefile" ;; + "src/include/gnunet_directories.h") CONFIG_FILES="$CONFIG_FILES src/include/gnunet_directories.h" ;; + "src/hostlist/Makefile") CONFIG_FILES="$CONFIG_FILES src/hostlist/Makefile" ;; + "src/mesh/Makefile") CONFIG_FILES="$CONFIG_FILES src/mesh/Makefile" ;; + "src/mesh/mesh.conf") CONFIG_FILES="$CONFIG_FILES src/mesh/mesh.conf" ;; + "src/namestore/Makefile") CONFIG_FILES="$CONFIG_FILES src/namestore/Makefile" ;; + "src/namestore/namestore.conf") CONFIG_FILES="$CONFIG_FILES src/namestore/namestore.conf" ;; + "src/nat/Makefile") CONFIG_FILES="$CONFIG_FILES src/nat/Makefile" ;; + "src/nse/Makefile") CONFIG_FILES="$CONFIG_FILES src/nse/Makefile" ;; + "src/nse/nse.conf") CONFIG_FILES="$CONFIG_FILES src/nse/nse.conf" ;; + "src/peerinfo/Makefile") CONFIG_FILES="$CONFIG_FILES src/peerinfo/Makefile" ;; + "src/peerinfo/peerinfo.conf") CONFIG_FILES="$CONFIG_FILES src/peerinfo/peerinfo.conf" ;; + "src/peerinfo-tool/Makefile") CONFIG_FILES="$CONFIG_FILES src/peerinfo-tool/Makefile" ;; + "src/pt/Makefile") CONFIG_FILES="$CONFIG_FILES src/pt/Makefile" ;; + "src/statistics/Makefile") CONFIG_FILES="$CONFIG_FILES src/statistics/Makefile" ;; + "src/statistics/statistics.conf") CONFIG_FILES="$CONFIG_FILES src/statistics/statistics.conf" ;; + "src/stream/Makefile") CONFIG_FILES="$CONFIG_FILES src/stream/Makefile" ;; + "src/template/Makefile") CONFIG_FILES="$CONFIG_FILES src/template/Makefile" ;; + "src/testing/Makefile") CONFIG_FILES="$CONFIG_FILES src/testing/Makefile" ;; + "src/topology/Makefile") CONFIG_FILES="$CONFIG_FILES src/topology/Makefile" ;; + "src/transport/Makefile") CONFIG_FILES="$CONFIG_FILES src/transport/Makefile" ;; + "src/transport/transport.conf") CONFIG_FILES="$CONFIG_FILES src/transport/transport.conf" ;; + "src/tun/Makefile") CONFIG_FILES="$CONFIG_FILES src/tun/Makefile" ;; + "src/util/Makefile") CONFIG_FILES="$CONFIG_FILES src/util/Makefile" ;; + "src/util/resolver.conf") CONFIG_FILES="$CONFIG_FILES src/util/resolver.conf" ;; + "src/vpn/Makefile") CONFIG_FILES="$CONFIG_FILES src/vpn/Makefile" ;; + "src/vpn/vpn.conf") CONFIG_FILES="$CONFIG_FILES src/vpn/vpn.conf" ;; + "src/integration-tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/integration-tests/Makefile" ;; + "pkgconfig/Makefile") CONFIG_FILES="$CONFIG_FILES pkgconfig/Makefile" ;; + "pkgconfig/gnunetarm.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetarm.pc" ;; + "pkgconfig/gnunetblock.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetblock.pc" ;; + "pkgconfig/gnunetcore.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetcore.pc" ;; + "pkgconfig/gnunetdatacache.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetdatacache.pc" ;; + "pkgconfig/gnunetdatastore.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetdatastore.pc" ;; + "pkgconfig/gnunetdht.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetdht.pc" ;; + "pkgconfig/gnunetdhtlog.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetdhtlog.pc" ;; + "pkgconfig/gnunetdv.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetdv.pc" ;; + "pkgconfig/gnunetfragmentation.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetfragmentation.pc" ;; + "pkgconfig/gnunetfs.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetfs.pc" ;; + "pkgconfig/gnunethello.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunethello.pc" ;; + "pkgconfig/gnunetnat.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetnat.pc" ;; + "pkgconfig/gnunetnse.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetnse.pc" ;; + "pkgconfig/gnunetpeerinfo.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetpeerinfo.pc" ;; + "pkgconfig/gnunetstatistics.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetstatistics.pc" ;; + "pkgconfig/gnunettesting.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunettesting.pc" ;; + "pkgconfig/gnunettransport.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunettransport.pc" ;; + "pkgconfig/gnunetutil.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetutil.pc" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="CXX " + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Assembler program. +AS=$AS + +# DLL creation program. +DLLTOOL=$DLLTOOL + +# Object dumper program. +OBJDUMP=$OBJDUMP + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that does not interpret backslashes. +ECHO=$lt_ECHO + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $* )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[^=]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$@"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1+=\$2" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1=\$$1\$2" +} + +_LT_EOF + ;; + esac + + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + "po-directories":C) + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + # Treat a directory as a PO directory if and only if it has a + # POTFILES.in file. This allows packages to have multiple PO + # directories under different names or in different locations. + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + POMAKEFILEDEPS="POTFILES.in" + # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assigment from automake < 1.5. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # The set of available languages was given in configure.in. + # Hide the ALL_LINGUAS assigment from automake < 1.5. + eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' + fi + # Compute POFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) + # Compute UPDATEPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) + # Compute DUMMYPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) + # Compute GMOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + UPDATEPOFILES= + DUMMYPOFILES= + GMOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi + +# +# CONFIG_SUBDIRS section. +# +if test "$no_recursion" != yes; then + + # Remove --cache-file, --srcdir, and --disable-option-checking arguments + # so they do not pile up. + ac_sub_configure_args= + ac_prev= + eval "set x $ac_configure_args" + shift + for ac_arg + do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case $ac_arg in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ + | --c=*) + ;; + --config-cache | -C) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + ;; + --disable-option-checking) + ;; + *) + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_sub_configure_args " '$ac_arg'" ;; + esac + done + + # Always prepend --prefix to ensure using the same prefix + # in subdir configurations. + ac_arg="--prefix=$prefix" + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" + + # Pass --silent + if test "$silent" = yes; then + ac_sub_configure_args="--silent $ac_sub_configure_args" + fi + + # Always prepend --disable-option-checking to silence warnings, since + # different subdirs can have different --enable and --with options. + ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" + + ac_popdir=`pwd` + for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + test -d "$srcdir/$ac_dir" || continue + + ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" + $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 + $as_echo "$ac_msg" >&6 + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + cd "$ac_dir" + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f "$ac_srcdir/configure.gnu"; then + ac_sub_configure=$ac_srcdir/configure.gnu + elif test -f "$ac_srcdir/configure"; then + ac_sub_configure=$ac_srcdir/configure + elif test -f "$ac_srcdir/configure.in"; then + # This should be Cygnus configure. + ac_sub_configure=$ac_aux_dir/configure + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 +$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + # Make the cache file name correct relative to the subdirectory. + case $cache_file in + [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; + *) # Relative name. + ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 +$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} + # The eval makes quoting arguments work. + eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ + --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || + as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 + fi + + cd "$ac_popdir" + done +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +# Finally: summary! + +# warn user if mysql found but not used due to version +if test "$mysqlfail" = "true" +then + { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: MySQL found, but too old. MySQL support will not be compiled." >&5 +$as_echo "$as_me: NOTICE: MySQL found, but too old. MySQL support will not be compiled." >&6;} +fi + +# sqlite +if test "x$sqlite" = "x0" +then + { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: sqlite not found. sqLite support will not be compiled." >&5 +$as_echo "$as_me: NOTICE: sqlite not found. sqLite support will not be compiled." >&6;} +fi + +if test "x$lmhd" != "x1" +then + { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: libmicrohttpd not found, http transport will not be installed." >&5 +$as_echo "$as_me: NOTICE: libmicrohttpd not found, http transport will not be installed." >&6;} +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: Database support is set to MySQL: $mysql, SQLite: $sqlite, Postgres: $postgres" >&5 +$as_echo "$as_me: NOTICE: Database support is set to MySQL: $mysql, SQLite: $sqlite, Postgres: $postgres" >&6;} + +if test "$enable_framework_build" = "yes" +then + { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: Mac OS X framework build enabled." >&5 +$as_echo "$as_me: NOTICE: Mac OS X framework build enabled." >&6;} +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: ******************************************** +You can compile GNUnet with + make +now. After that, run (if necessary as 'root') + make install +to install everything. You may want to create a new user account +to run the GNUnet service: + adduser gnunet +You also need to create an configuration file that should +specify the path where GNUnet should store data. For example, +you could store in \"/etc/gnunet.conf\" the following lines: + +[PATHS] +SERVICEHOME = /var/lib/gnunet +DEFAULTCONFIG = /etc/gnunet.conf + +Now, in order to start your peer, run as the 'gnunet' user + gnunet-arm -s + +Each GNUnet user should also create an (at least initially) empty +configuration file: + mkdir $HOME/.gnunet/ + touch $HOME/.gnunet/gnunet.conf + +Optionally, download and compile: +- gnunet-gtk to get a GUI for file-sharing and configuration. +********************************************" >&5 +$as_echo "$as_me: ******************************************** +You can compile GNUnet with + make +now. After that, run (if necessary as 'root') + make install +to install everything. You may want to create a new user account +to run the GNUnet service: + adduser gnunet +You also need to create an configuration file that should +specify the path where GNUnet should store data. For example, +you could store in \"/etc/gnunet.conf\" the following lines: + +[PATHS] +SERVICEHOME = /var/lib/gnunet +DEFAULTCONFIG = /etc/gnunet.conf + +Now, in order to start your peer, run as the 'gnunet' user + gnunet-arm -s + +Each GNUnet user should also create an (at least initially) empty +configuration file: + mkdir $HOME/.gnunet/ + touch $HOME/.gnunet/gnunet.conf + +Optionally, download and compile: +- gnunet-gtk to get a GUI for file-sharing and configuration. +********************************************" >&6;} diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..a558ffd --- /dev/null +++ b/configure.ac @@ -0,0 +1,971 @@ +# This file is part of GNUnet. +# (C) 2001--2012 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# +# Process this file with autoconf to produce a configure script. +# +# +AC_PREREQ(2.61) +# Checks for programs. +AC_INIT([gnunet], [0.9.2],[bug-gnunet@gnu.org]) + +AC_CANONICAL_TARGET +AC_CANONICAL_HOST +AC_CANONICAL_SYSTEM + +AM_INIT_AUTOMAKE([gnunet], [0.9.2]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) +AC_CONFIG_HEADERS([gnunet_config.h]) +AH_TOP([#define _GNU_SOURCE 1]) + +AC_PROG_AWK +AC_PROG_CC +AC_PROG_CPP +AC_PROG_CXX +AC_PROG_OBJC +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AM_PROG_CC_C_O +LT_INIT([disable-static dlopen win32-dll]) +LTDL_INIT +AC_SUBST(LTDLINCL) +AC_SUBST(LIBLTDL) +AC_SUBST(MKDIR_P) + +# large file support +AC_SYS_LARGEFILE +AC_FUNC_FSEEKO + + +if test "$enable_shared" = "no" +then + AC_MSG_ERROR([GNUnet only works with shared libraries. Sorry.]) +fi + +CFLAGS="-Wall $CFLAGS" +# use '-fno-strict-aliasing', but only if the compiler can take it +if gcc -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; +then + CFLAGS="-fno-strict-aliasing $CFLAGS" +fi + +# Use Linux interface name unless the OS has a different preference +DEFAULT_INTERFACE="\"eth0\"" + +# Check system type +case "$host_os" in +*darwin* | *rhapsody* | *macosx*) + AC_DEFINE_UNQUOTED(DARWIN,1,[This is an Apple Darwin system]) + CPPFLAGS="-D_APPLE_C_SOURCE $CPPFLAGS" + CFLAGS="-no-cpp-precomp -fno-common $CFLAGS" + AC_MSG_WARN([The VPN application cannot be compiled on your OS]) + build_target="darwin" + DEFAULT_INTERFACE="\"en0\"" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +linux*) + AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux system]) + build_target="linux" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + AC_PATH_XTRA + ;; +freebsd*) + AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system]) + AC_DEFINE_UNQUOTED(FREEBSD,1,[This is a FreeBSD system]) + CFLAGS="-D_THREAD_SAFE $CFLAGS" + build_target="freebsd" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +openbsd*) + AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system]) + AC_DEFINE_UNQUOTED(OPENBSD,1,[This is an OpenBSD system]) + LIBS=`echo $LIBS | sed -e "s/-ldl//"` + build_target="openbsd" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +netbsd*) + AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system]) + AC_DEFINE_UNQUOTED(NETBSD,1,[This is a NetBSD system]) + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +*solaris*) + AC_DEFINE_UNQUOTED(SOLARIS,1,[This is a Solaris system]) + AC_DEFINE_UNQUOTED(_REENTRANT,1,[Need with solaris or errno doesnt work]) + AC_CHECK_LIB(resolv, res_init) + AC_CHECK_LIB(rt, nanosleep) + build_target="solaris" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +*arm-linux*) + AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux system]) + CFLAGS="-D_REENTRANT -fPIC -pipe $CFLAGS" + build_target="linux" + LIBPREFIX= + DLLDIR=lib + UNIXONLY="#" + ;; +*cygwin*) + AC_DEFINE_UNQUOTED(CYGWIN,1,[This is a Cygwin system]) + AC_DEFINE_UNQUOTED(WINDOWS,1,[This is a Windows system]) + AC_CHECK_LIB(intl, gettext) + LDFLAGS="$LDFLAGS -no-undefined" + CFLAGS="-mms-bitfields $CFLAGS" + build_target="cygwin" + LIBPREFIX=lib + DLLDIR=bin + AC_PROG_CXX + UNIXONLY="" + ;; +*mingw*) + AC_DEFINE_UNQUOTED(MINGW,1,[This is a MinGW system]) + AC_DEFINE_UNQUOTED(WINDOWS,1,[This is a Windows system]) + AC_DEFINE_UNQUOTED(_WIN32,1,[This is a Windows system]) + AC_CHECK_LIB(intl, gettext) + LDFLAGS="$LDFLAGS -Wl,-no-undefined -Wl,--export-all-symbols" + LIBS="$LIBS -lws2_32 -lplibc -lgnurx -lole32" + CFLAGS="-mms-bitfields $CFLAGS" + CPPFLAGS="-D_WIN32_WINNT=0x0501 $CPPFLAGS" + build_target="mingw" + AC_PROG_CXX + LIBPREFIX=lib + DLLDIR=bin + UNIXONLY="" + ;; +*) + AC_MSG_RESULT(Unrecognised OS $host_os) + AC_DEFINE_UNQUOTED(OTHEROS,1,[Some strange OS]) + UNIXONLY="" +;; +esac +AC_DEFINE_UNQUOTED([GNUNET_DEFAULT_INTERFACE], $DEFAULT_INTERFACE, [This should be the default choice for the name of the first network interface]) +AC_SUBST(DEFAULT_INTERFACE) + +# Disable TCP-based IPC on systems that support UNIX domain +# sockets in default configuratin: +AC_SUBST(UNIXONLY) + +AC_MSG_CHECKING([for build target]) +AM_CONDITIONAL(DARWIN, test "$build_target" = "darwin") +AM_CONDITIONAL(CYGWIN, test "$build_target" = "cygwin") +AM_CONDITIONAL(MINGW, test "$build_target" = "mingw") +AM_CONDITIONAL(SOLARIS, test "$build_target" = "solaris") +AM_CONDITIONAL(XFREEBSD, test "$build_target" = "freebsd") +AM_CONDITIONAL(OPENBSD, test "$build_target" = "openbsd") +AM_CONDITIONAL(LINUX, test "$build_target" = "linux") + +AC_MSG_RESULT([$build_target]) +AC_SUBST(build_target) +AM_CONDITIONAL([am__fastdepOBJC], false) +AC_UNALIGNED_64_ACCESS + +# some other checks for standard libs +AC_SEARCH_LIBS([gethostbyname], [nsl ws2_32]) +AC_CHECK_LIB(socket, socket) +AC_CHECK_LIB(m, log) +AC_CHECK_LIB(c, getloadavg, AC_DEFINE(HAVE_GETLOADAVG,1,[getloadavg supported])) + +# 'save' libs; only those libs found so far will be +# linked against _everywhere_. For the others, we +# will be more selective! +SAVE_LIBS=$LIBS + +# libgnurx (regex library for W32) +gnurx=0 +AC_CHECK_LIB(gnurx, regexec, gnurx=1) +if test "x$gnurx" = "x0" -a "x$build_target" = "xmingw" +then + AC_MSG_ERROR([on W32 GNUnet needs libgnurx]) +fi + +# libgcrypt +gcrypt=0 +AM_PATH_LIBGCRYPT(1.2.0, gcrypt=1) +AC_CHECK_DECLS([gcry_mpi_lshift], [], [], [[#include ]]) + +if test $gcrypt = 0 +then + AC_MSG_ERROR([GNUnet needs libgcrypt]) +fi + +# Adam shostack suggests the following for Windows: +# -D_FORTIFY_SOURCE=2 -fstack-protector-all +AC_ARG_ENABLE(gcc-hardening, + AS_HELP_STRING(--enable-gcc-hardening, enable compiler security checks), +[if test x$enableval = xyes; then + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector-all" + CFLAGS="$CFLAGS -fwrapv -fPIE -Wstack-protector" + CFLAGS="$CFLAGS --param ssp-buffer-size=1" + LDFLAGS="$LDFLAGS -pie" +fi]) + + +# Linker hardening options +# Currently these options are ELF specific - you can't use this with MacOSX +AC_ARG_ENABLE(linker-hardening, + AS_HELP_STRING(--enable-linker-hardening, enable linker security fixups), +[if test x$enableval = xyes; then + LDFLAGS="$LDFLAGS -z relro -z now" +fi]) + + +extra_logging=GNUNET_NO +AC_ARG_ENABLE([logging], + AS_HELP_STRING([--enable-logging@<:@=value@:>@],[Enable logging calls. Possible values: yes,no,verbose,veryverbose ('yes' is the default)]), + [AS_IF([test "x$enableval" = "xyes"], [], + [test "x$enableval" = "xno"], [AC_DEFINE([GNUNET_CULL_LOGGING],[],[Define to cull all logging calls])], + [test "x$enableval" = "xverbose"], [extra_logging=GNUNET_YES] + [test "x$enableval" = "xveryverbose"], [extra_logging=\(GNUNET_YES+1\)]) + ], []) +AC_DEFINE_UNQUOTED([GNUNET_EXTRA_LOGGING],[$extra_logging],[1 if extra logging is enabled, 2 for very verbose extra logging, 0 otherwise]) + +if test $build = $target +then +AC_MSG_CHECKING([for working HMAC]) +AC_LANG_PUSH(C) +LIBS="$LIBS $LIBGCRYPT_LIBS" +CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS" +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([#include + #include ], [[ + gcry_md_hd_t mac; + + unsigned char data[] = { 0xbf, 0x16, 0x6e, 0x46, 0x3a, 0x6c, 0xf3, 0x93, 0xa7, 0x72, + 0x11, 0xa1, 0xdc, 0x0b, 0x07, 0xdb, 0x1a, 0x5e, 0xd9, 0xb9, 0x81, 0xbe, + 0xea, 0xe4, 0x31, 0x5f, 0x24, 0xff, 0xfe, 0x50, 0x8a, 0xde }; + unsigned char key[] = { 0xfc, 0x62, 0x76, 0x35 }; + unsigned char result[] = {0xa2, 0xb, 0x1, 0xd9, 0xc0, 0x8b, 0x5a, 0x12, 0x80, + 0xd5, 0x50, 0x12, 0x8e, 0xd0, 0x5b, 0xb6, 0x5c, 0x87, 0x24, 0xe2, 0xd0, + 0xd2, 0xaf, 0x63, 0xae, 0xd1, 0xd6, 0x64, 0x14, 0xe3, 0x6e, 0x61, 0x5b, + 0xd, 0xba, 0x17, 0x7d, 0xd3, 0x10, 0xb1, 0x37, 0x41, 0x91, 0x7d, 0xeb, + 0x1, 0x4d, 0x71, 0xe8, 0x59, 0x71, 0x42, 0x8e, 0xd6, 0xf3, 0x29, 0x3b, + 0x90, 0xf2, 0xd1, 0xaf, 0x65, 0x1e, 0xb3}; + + if (!gcry_check_version (GCRYPT_VERSION)) + { + fprintf (stderr, "Version mismatch %s <-> %s \n", gcry_check_version (NULL), GCRYPT_VERSION); + return 1; + } + + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + + if (gcry_md_open(&mac, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR) + { + fprintf (stderr, "gcry_md_open error\n"); + return 2; + } + + gcry_md_setkey (mac, key, sizeof (key)); + gcry_md_write (mac, data, sizeof (data)); + + if (memcmp(gcry_md_read (mac, 0), result, gcry_md_get_algo_dlen (gcry_md_get_algo (mac))) != 0) + { + fprintf (stderr, "memcmp error\n"); + return 3; + } + + gcry_md_close (mac); + + return 0; + ]])], + [AC_MSG_RESULT([yes])], + [ + RESULT=$? + if test $RESULT = 3 + then + AC_MSG_FAILURE([HMAC test vector does not match. This is a known problem with libgcrypt 1.2.2 on Windows and fixed in 1.4.6.]) + fi + if test $RESULT = 2 + then + AC_MSG_FAILURE([HMAC test failed]) + fi + if test $RESULT = 1 + then + AC_MSG_FAILURE([libgcrypt header version does not match library version]) + fi + ]) +AC_LANG_POP(C) +fi # $build = $target + +# libcurl +LIBCURL_CHECK_CONFIG(,7.20.1,,AC_MSG_ERROR([GNUnet requires libcurl >= 7.20.1])) +# restore LIBS +LIBS=$SAVE_LIBS + + +AC_CHECK_HEADERS([glpk.h],[glpk=true],[gplk=false]) +AC_CHECK_LIB([glpk],[glp_create_prob],,[gplk=false]) +# GLPK must support atm MLP presolving, version >= 4.32 +AC_CHECK_MEMBERS(glp_iocp.presolve,,[gplk=false],[[#include ]]) +if test x$gplk = xfalse +then + AM_CONDITIONAL(HAVE_LIBGLPK, false) + AC_MSG_WARN([GNUnet requires GLPK >= 4.32]) +else + AM_CONDITIONAL(HAVE_LIBGLPK, true) + AC_DEFINE([HAVE_LIBGLPK],[1],[Have GLPK]) +fi + + +# test for kvm and kstat (for CPU stats under BSD/Solaris) +AC_CHECK_LIB([kvm],[kvm_open]) +AC_CHECK_LIB([kstat],[kstat_open]) + +# test for libextractor +extractor=0 +AC_MSG_CHECKING(for libextractor) +AC_ARG_WITH(extractor, + [ --with-extractor=PFX base of libextractor installation], + [AC_MSG_RESULT([$with_extractor]) + case $with_extractor in + no) + ;; + yes) + AC_CHECK_HEADERS(extractor.h, + AC_CHECK_LIB([extractor], [EXTRACTOR_plugin_add_defaults], + extractor=1)) + ;; + *) + LDFLAGS="-L$with_extractor/lib $LDFLAGS" + CPPFLAGS="-I$with_extractor/include $CPPFLAGS" + AC_CHECK_HEADERS(extractor.h, + AC_CHECK_LIB([extractor], [EXTRACTOR_plugin_add_defaults], + EXT_LIB_PATH="-L$with_extractor/lib $EXT_LIB_PATH" + extractor=1)) + ;; + esac + ], + [AC_MSG_RESULT([--with-extractor not specified]) + AC_CHECK_HEADERS(extractor.h, + AC_CHECK_LIB([extractor], [EXTRACTOR_plugin_add_defaults], + extractor=1))]) +if test "$extractor" != 1 +then + AC_MSG_ERROR([GNUnet requires libextractor]) +fi +# restore LIBS +LIBS=$SAVE_LIBS + +# test for libunistring +gl_LIBUNISTRING +if test $HAVE_LIBUNISTRING != yes; then + AC_MSG_ERROR([GNUnet requires libunistring]) +fi +if test $gl_libunistring_hexversion -le 2305; then + AC_MSG_ERROR([GNUnet requires libunistring >= 0.9.1.1]) +fi +# restore LIBS +LIBS=$SAVE_LIBS + + + +# Checks for standard header files. +AC_HEADER_DIRENT +AC_HEADER_STDC + +# Check for headers that are ALWAYS required +AC_CHECK_HEADERS([fcntl.h math.h errno.h ctype.h limits.h stdio.h stdlib.h string.h unistd.h stdarg.h signal.h locale.h sys/stat.h sys/types.h],,AC_MSG_ERROR([Compiling GNUnet requires standard UNIX headers files])) + +# Checks for headers that are only required on some systems or opional (and where we do NOT abort if they are not there) +AC_CHECK_HEADERS([langinfo.h sys/param.h sys/mount.h sys/statvfs.h sys/select.h sockLib.h sys/mman.h sys/msg.h sys/vfs.h arpa/inet.h fcntl.h libintl.h netdb.h netinet/in.h netinet/in_systm.h sys/ioctl.h sys/socket.h sys/time.h unistd.h kstat.h sys/sysinfo.h kvm.h sys/file.h sys/resource.h ifaddrs.h mach/mach.h stddef.h sys/timeb.h terminos.h argz.h ucred.h endian.h sys/endian.h]) + +SAVE_LDFLAGS=$LDFLAGS +SAVE_CPPFLAGS=$CPPFLAGS + +# test for sqlite +sqlite=false +AC_MSG_CHECKING(for SQLite) +AC_ARG_WITH(sqlite, + [ --with-sqlite=PFX base of SQLite installation], + [AC_MSG_RESULT("$with_sqlite") + case $with_sqlite in + no) + ;; + yes) + AC_CHECK_HEADERS(sqlite3.h, + sqlite=true) + ;; + *) + LDFLAGS="-L$with_sqlite/lib $LDFLAGS" + CPPFLAGS="-I$with_sqlite/include $CPPFLAGS" + AC_CHECK_HEADERS(sqlite3.h, + EXT_LIB_PATH="-L$with_sqlite/lib $EXT_LIB_PATH" + SQLITE_LDFLAGS="-L$with_sqlite/lib" + SQLITE_CPPFLAGS="-I$with_sqlite/include" + sqlite=true) + LDFLAGS=$SAVE_LDFLAGS + CPPFLAGS=$SAVE_CPPFLAGS + ;; + esac + ], + [AC_MSG_RESULT([--with-sqlite not specified]) + AC_CHECK_HEADERS(sqlite3.h, sqlite=true)]) +AM_CONDITIONAL(HAVE_SQLITE, test x$sqlite = xtrue) +AC_SUBST(SQLITE_CPPFLAGS) +AC_SUBST(SQLITE_LDFLAGS) + +# test for postgres +postgres=false +AC_MSG_CHECKING(for postgres) +AC_ARG_WITH(postgres, + [ --with-postgres=PFX base of postgres installation], + [AC_MSG_RESULT("$with_postgres") + case $with_postgres in + no) + ;; + yes) + AC_CHECK_HEADERS(postgresql/libpq-fe.h, + postgres=true) + ;; + *) + LDFLAGS="-L$with_postgres/lib $LDFLAGS" + CPPFLAGS="-I$with_postgres/include $CPPFLAGS" + AC_CHECK_HEADERS(postgresql/libpq-fe.h, + EXT_LIB_PATH="-L$with_postgres/lib $EXT_LIB_PATH" + POSTGRES_LDFLAGS="-L$with_postgres/lib" + POSTGRES_CPPFLAGS="-I$with_postgres/include" + postgres=true) + LDFLAGS=$SAVE_LDFLAGS + CPPFLAGS=$SAVE_CPPFLAGS + ;; + esac + ], + [AC_MSG_RESULT([--with-postgres not specified]) + AC_CHECK_HEADERS(postgresql/libpq-fe.h, postgres=true)]) +AM_CONDITIONAL(HAVE_POSTGRES, test x$postgres = xtrue) +AC_SUBST(POSTGRES_CPPFLAGS) +AC_SUBST(POSTGRES_LDFLAGS) + +# test for libz (maybe required for linking mysql) +zlib=1 +AC_CHECK_LIB(z, compress,,zlib=0) +AM_CONDITIONAL(HAVE_ZLIB, test x$zlib = x1) +if test "$zlib" != 1 +then + AC_MSG_ERROR([GNUnet requires zlib]) +fi + +# mysql & windows +AC_CHECK_TYPES([sigset_t, off_t], [], [], [#include ]) +AC_CHECK_TYPES([size_t], [], [], [#include ]) + +if test "$build_target" = "mingw" +then + CYGWIN_MYSQL_MAGIC="#include " +fi + +# test for mysql +mysql=false +mysqlfail=false +SAVE_LDFLAGS=$LDFLAGS +SAVE_CPPFLAGS=$CPPFLAGS +AC_MSG_CHECKING(for mysql) +AC_ARG_WITH(mysql, + [ --with-mysql=PFX base of MySQL installation], + [AC_MSG_RESULT("$with_mysql") + if test "$with_mysql" != "no" + then + if test "$with_mysql" != "yes" + then + LDFLAGS="-L$with_mysql/lib -L$with_mysql/lib/mysql $LDFLAGS $ZLIBS" + CPPFLAGS="-I$with_mysql/include $CPPFLAGS" + fi + AC_CHECK_HEADERS(mysql/mysql.h, + AC_CHECK_LIB(mysqlclient, mysql_init, + MYSQL_LDFLAGS="-L$with_mysql/lib -L$with_mysql/lib/mysql" + MYSQL_CPPFLAGS="-I$with_mysql/include" + + mysql=true), [], [$CYGWIN_MYSQL_MAGIC]) + fi + ], + [AC_MSG_RESULT([--with-mysql not specified]) + LDFLAGS="-L/usr/lib/mysql $LDFLAGS $ZLIBS" + AC_CHECK_LIB(mysqlclient, mysql_init, + [AC_CHECK_HEADERS(mysql/mysql.h, + MYSQL_LDFLAGS="-L/usr/lib/mysql" + mysql=true + + , [], [$CYGWIN_MYSQL_MAGIC])]) + ]) + +AC_SUBST(MYSQL_LDFLAGS) +AC_SUBST(MYSQL_CPPFLAGS) + +# additional version check for mysql +AC_ARG_ENABLE(mysql-version-check, [ --disable-mysql-version-check do not check MySQL version],, enable_mysql_version_check=yes) +if test "$mysql" = "true" -a "x$enable_mysql_version_check" = "xyes" +then + AC_MSG_CHECKING(mysql version) + AC_RUN_IFELSE([AC_LANG_PROGRAM( + [[$CYGWIN_MYSQL_MAGIC + #include ]], + [[if (MYSQL_VERSION_ID < 40100) + return(-1); + else + return(0); + ]]) + ],mysql=true,mysql=false) + if test "$mysql" = "false" + then + mysqlfail=true + AC_MSG_RESULT([fail, >= 4.1 required]) + else + AC_MSG_RESULT(ok) + fi +fi +AM_CONDITIONAL(HAVE_MYSQL, test x$mysql = xtrue) +AM_CONDITIONAL(HAVE_MYSQLE, test "0" = "1") +# restore LIBS +LIBS=$SAVE_LIBS +LDFLAGS=$SAVE_LDFLAGS +CPPFLAGS=$SAVE_CPPFLAGS + +if test "$sqlite" = 0 -a "$mysql" = 0 +then + AC_MSG_ERROR([GNUnet requires SQLite or MySQL]) +fi + +# libmicrohttpd +lmhd=0 +AC_MSG_CHECKING([for libmicrohttpd]) +AC_ARG_WITH(microhttpd, + [ --with-microhttpd=PFX base of libmicrohttpd installation], + [AC_MSG_RESULT([$with_microhttpd]) + case $with_microhttpd in + no) + ;; + yes) + AC_CHECK_HEADERS([microhttpd.h], + AC_CHECK_DECL(MHD_OPTION_PER_IP_CONNECTION_LIMIT, + AC_CHECK_LIB([microhttpd], [MHD_start_daemon], + lmhd=1), + [],[#include "src/include/platform.h" + #include ]),, + [#include "src/include/platform.h"]) + ;; + *) + LDFLAGS="-L$with_microhttpd/lib $LDFLAGS" + CPPFLAGS="-I$with_microhttpd/include $CPPFLAGS" + AC_CHECK_HEADERS(microhttpd.h, + AC_CHECK_DECL(MHD_OPTION_PER_IP_CONNECTION_LIMIT, + AC_CHECK_LIB([microhttpd], [MHD_start_daemon], + EXT_LIB_PATH="-L$with_microhttpd/lib $EXT_LIB_PATH" + lmhd=1), + [],[#include "src/include/platform.h" + #include ]),, + [#include "src/include/platform.h"]) + ;; + esac + ], + [AC_MSG_RESULT([--with-microhttpd not specified]) + AC_CHECK_HEADERS([microhttpd.h], + AC_CHECK_DECL(MHD_OPTION_PER_IP_CONNECTION_LIMIT, + AC_CHECK_LIB([microhttpd], [MHD_start_daemon], + lmhd=1), + [],[#include "src/include/platform.h" + #include ]),, + [#include "src/include/platform.h"])]) +AM_CONDITIONAL(HAVE_MHD, test x$lmhd = x1) +AC_DEFINE_UNQUOTED([HAVE_MHD], $lmhd, [We have libmicrohttpd]) + + +# restore LIBS +LIBS=$SAVE_LIBS + +# check for python & pexpect (used for some testcases only) +AM_PATH_PYTHON([2.6],, [:]) +AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != :]) + +if test "$PYTHON" != : +then + AC_MSG_CHECKING([for pexpect]) + $PYTHON -c "import pexpect" > /dev/null 2> /dev/null + PYEX=$? + AM_CONDITIONAL(HAVE_PYTHON_PEXPECT, test $PYEX -eq 0) + if test $PYEX -eq 0 + then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([not found]) + fi +else + AM_CONDITIONAL(HAVE_PYTHON_PEXPECT, 0) +fi + + +# check for gettext +AM_GNU_GETTEXT([external]) +AM_GNU_GETTEXT_VERSION([0.16.1]) + +# check for iconv +AM_ICONV + +# Checks for standard typedefs, structures, and compiler characteristics. +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_MODE_T +AC_HEADER_TIME +AC_HEADER_STAT +AC_HEADER_STDBOOL +AC_STRUCT_TM + +AC_CHECK_MEMBER([struct sockaddr_in.sin_len], + [ AC_DEFINE(HAVE_SOCKADDR_IN_SIN_LEN, 1, [Do we have sockaddr_in.sin_len?]) + ], + [], + [ + #include + #include + #include + ]) + + + +# Checks for library functions. +AC_FUNC_CLOSEDIR_VOID +AC_FUNC_FORK +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MEMCMP +AC_FUNC_SELECT_ARGTYPES +AC_FUNC_CHOWN + +AC_TYPE_SIGNAL +AC_FUNC_STAT +AC_FUNC_STRFTIME +AC_FUNC_VPRINTF +AC_HEADER_SYS_WAIT +AC_TYPE_OFF_T +AC_TYPE_UID_T +AC_CHECK_FUNCS([floor gethostname memmove rmdir strncasecmp strrchr strtol atoll dup2 fdatasync ftruncate gettimeofday memset mkdir mkfifo select socket strcasecmp strchr strdup strerror strstr clock_gettime getrusage rand uname setlocale getcwd mktime gmtime_r gmtime strlcpy strlcat ftruncate stat64 sbrk mmap mremap setrlimit sysconf gethostbyaddr initgroups getifaddrs freeifaddrs getnameinfo getaddrinfo inet_ntoa localtime_r nl_langinfo putenv realpath strndup gethostbyname2 gethostbyname getpeerucred getpeereid setresuid]) + +# restore LIBS +LIBS=$SAVE_LIBS + +gn_user_home_dir="~/.gnunet" +AC_ARG_WITH(user-home-dir, + AC_HELP_STRING( + [--with-user-home-dir=DIR], + [default user home directory (~/.gnunet)]), + [gn_user_home_dir=$withval]) +AC_SUBST(GN_USER_HOME_DIR, $gn_user_home_dir) +gn_daemon_home_dir="/var/lib/gnunet" +AC_ARG_WITH(daemon-home-dir, + AC_HELP_STRING( + [--with-daemon-home-dir=DIR], + [default daemon home directory (/var/lib/gnunet)]), + [gn_daemon_home_dir=$withval]) +AC_SUBST(GN_DAEMON_HOME_DIR, $gn_daemon_home_dir) +gn_daemon_config_dir="/etc" +AC_ARG_WITH(daemon-config-dir, + AC_HELP_STRING( + [--with-daemon-config-dir=DIR], + [default daemon config directory (/etc)]), + [gn_daemon_config_dir=$withval]) +AC_SUBST(GN_DAEMON_CONFIG_DIR, $gn_daemon_config_dir) + +GN_INTLINCL="" +GN_LIBINTL="$LTLIBINTL" +AC_ARG_ENABLE(framework, [ --enable-framework enable Mac OS X framework build helpers],enable_framework_build=$enableval) +AM_CONDITIONAL(WANT_FRAMEWORK, test x$enable_framework_build = xyes) +if test x$enable_framework_build = xyes +then + AC_DEFINE([FRAMEWORK_BUILD], 1, [Build a Mac OS X Framework]) + GN_INTLINCL='-I$(top_srcdir)/src/intlemu' + GN_LIBINTL='$(top_builddir)/src/intlemu/libintlemu.la -framework CoreFoundation' + AC_LIB_APPENDTOVAR([CPPFLAGS], [$GN_INTLINCL]) +fi + +GN_LIB_LDFLAGS="-export-dynamic -no-undefined" +GN_PLUGIN_LDFLAGS="-export-dynamic -avoid-version -module -no-undefined" + +AC_SUBST(GN_LIB_LDFLAGS) +AC_SUBST(GN_PLUGIN_LDFLAGS) +AC_SUBST(GN_INTLINCL) +AC_SUBST(GN_LIBINTL) + +AC_SUBST(CPPFLAGS) +AC_SUBST(LIBS) +AC_SUBST(LDFLAGS) +AC_SUBST(EXT_LIB_PATH) +AC_SUBST(EXT_LIBS) + +AC_SUBST(LIBPREFIX) +AC_SUBST(DLLDIR) +AC_SUBST(EXT_LIB_PATH) + + +# test for sudo +AC_MSG_CHECKING(for sudo) +AC_ARG_WITH(sudo, + [ --with-sudo=PATH path to sudo binary (or just yes)], + [AC_MSG_RESULT("$with_sudo") + case $with_sudo in + no) + SUDO_BINARY= + ;; + yes) + SUDO_BINARY=sudo + ;; + *) + SUDO_BINARY=$with_sudo + ;; + esac + ], + [AC_MSG_RESULT([no])]) +AC_SUBST(SUDO_BINARY) + + +# test for gnunetdns group name +GNUNETDNS_GROUP=gnunetdns +AC_MSG_CHECKING(for gnunetdns group name) +AC_ARG_WITH(gnunetdns, + [ --with-gnunetdns=GRPNAME name for gnunetdns group], + [AC_MSG_RESULT("$with_gnunetdns") + case $with_gnunetdns in + no) + GNUNETDNS_GROUP=gnunet + ;; + yes) + GNUNETDNS_GROUP=gnunetdns + ;; + *) + GNUNETDNS_GROUP=$with_gnunetdns + ;; + esac + ], + [AC_MSG_RESULT([gnunetdns])]) +AC_SUBST(GNUNETDNS_GROUP) + + +# should 'make check' run tests? +AC_MSG_CHECKING(whether to run tests) +AC_ARG_ENABLE([testruns], + [AS_HELP_STRING([--disable-testruns], [disable running tests on make check (default is YES)])], + [enable_tests_run=${enableval}], + [enable_tests_run=yes]) +AC_MSG_RESULT($enable_test_run) +AM_CONDITIONAL([ENABLE_TEST_RUN], [test "x$enable_tests_run" = "xyes"]) + +# should expensive tests be run? +AC_MSG_CHECKING(whether to run expensive tests) +AC_ARG_ENABLE([expensivetests], + [AS_HELP_STRING([--enable-expensive-tests], [enable running expensive testcases])], + [enable_expensive=${enableval}], + [enable_expensive=no]) +AC_MSG_RESULT($enable_expensive) +AM_CONDITIONAL([HAVE_EXPENSIVE_TESTS], [test "x$enable_expensive" = "xyes"]) + +# should benchmarks be run? +AC_MSG_CHECKING(whether to run benchmarks during make check) +AC_ARG_ENABLE([benchmarks], + [AS_HELP_STRING([--enable-benchmarks], [enable running benchmarks during make check])], + [enable_benchmarks=${enableval}], + [enable_benchmarks=no]) +AC_MSG_RESULT($enable_benchmarks) +AM_CONDITIONAL([HAVE_BENCHMARKS], [test "x$enable_benchmarks" = "xyes"]) + +# should experimental code be compiled (code that may not yet compile)? +AC_MSG_CHECKING(whether to compile experimental code) +AC_ARG_ENABLE([experimental], + [AS_HELP_STRING([--enable-experimental], [enable compiling experimental code])], + [enable_experimental=${enableval}], + [enable_experimental=no]) +AC_MSG_RESULT($enable_experimental) +AM_CONDITIONAL([HAVE_EXPERIMENTAL], [test "x$enable_experimental" = "xyes"]) + +# should code be enabled that works around missing OS functionality on Windows? +# used for test cases +if test $build_target = "mingw" +then + workarounds=1 +else + AC_MSG_CHECKING(whether to enable windows workarounds) + AC_ARG_ENABLE([windows_workarounds], + [AS_HELP_STRING([--enable-windows_workarounds], [enable workarounds used on Windows (only useful for test cases)])], + [enable_workarounds=${enableval}], + [enable_workarounds=no]) + AC_MSG_RESULT($enable_workarounds) + if test x$enable_windows_workarounds = "xyes" + then + workarounds=1 + else + workarounds=0 + fi +fi +AC_DEFINE_UNQUOTED([ENABLE_WINDOWS_WORKAROUNDS], $workarounds, [enable workarounds used on Windows (only useful for test cases)]) + +# gcov compilation +AC_MSG_CHECKING(whether to compile with support for code coverage analysis) +AC_ARG_ENABLE([coverage], + AS_HELP_STRING([--enable-coverage], + [compile the library with code coverage support]), + [use_gcov=${enableval}], + [use_gcov=no]) +AC_MSG_RESULT($use_gcov) +AM_CONDITIONAL([USE_COVERAGE], [test "x$use_gcov" = "xyes"]) + + +AC_CONFIG_FILES([ +Makefile +contrib/Makefile +doc/Makefile +doc/man/Makefile +m4/Makefile +po/Makefile.in +src/Makefile +src/arm/Makefile +src/arm/arm.conf +src/ats/Makefile +src/ats/ats.conf +src/block/Makefile +src/chat/Makefile +src/chat/chat.conf +src/core/Makefile +src/core/core.conf +src/datacache/Makefile +src/datastore/Makefile +src/datastore/datastore.conf +src/dht/Makefile +src/dht/dht.conf +src/dns/Makefile +src/dns/dns.conf +src/dv/Makefile +src/dv/dv.conf +src/exit/Makefile +src/fragmentation/Makefile +src/fs/Makefile +src/fs/fs.conf +src/gns/Makefile +src/gns/gns.conf +src/hello/Makefile +src/include/Makefile +src/include/gnunet_directories.h +src/hostlist/Makefile +src/mesh/Makefile +src/mesh/mesh.conf +src/namestore/Makefile +src/namestore/namestore.conf +src/nat/Makefile +src/nse/Makefile +src/nse/nse.conf +src/peerinfo/Makefile +src/peerinfo/peerinfo.conf +src/peerinfo-tool/Makefile +src/pt/Makefile +src/statistics/Makefile +src/statistics/statistics.conf +src/stream/Makefile +src/template/Makefile +src/testing/Makefile +src/topology/Makefile +src/transport/Makefile +src/transport/transport.conf +src/tun/Makefile +src/util/Makefile +src/util/resolver.conf +src/vpn/Makefile +src/vpn/vpn.conf +src/integration-tests/Makefile +pkgconfig/Makefile +pkgconfig/gnunetarm.pc +pkgconfig/gnunetblock.pc +pkgconfig/gnunetcore.pc +pkgconfig/gnunetdatacache.pc +pkgconfig/gnunetdatastore.pc +pkgconfig/gnunetdht.pc +pkgconfig/gnunetdhtlog.pc +pkgconfig/gnunetdv.pc +pkgconfig/gnunetfragmentation.pc +pkgconfig/gnunetfs.pc +pkgconfig/gnunethello.pc +pkgconfig/gnunetnat.pc +pkgconfig/gnunetnse.pc +pkgconfig/gnunetpeerinfo.pc +pkgconfig/gnunetstatistics.pc +pkgconfig/gnunettesting.pc +pkgconfig/gnunettransport.pc +pkgconfig/gnunetutil.pc +]) +AC_OUTPUT + +# Finally: summary! + +# warn user if mysql found but not used due to version +if test "$mysqlfail" = "true" +then + AC_MSG_NOTICE([NOTICE: MySQL found, but too old. MySQL support will not be compiled.]) +fi + +# sqlite +if test "x$sqlite" = "x0" +then + AC_MSG_NOTICE([NOTICE: sqlite not found. sqLite support will not be compiled.]) +fi + +if test "x$lmhd" != "x1" +then + AC_MSG_NOTICE([NOTICE: libmicrohttpd not found, http transport will not be installed.]) +fi + +AC_MSG_NOTICE([NOTICE: Database support is set to MySQL: $mysql, SQLite: $sqlite, Postgres: $postgres]) + +if test "$enable_framework_build" = "yes" +then + AC_MSG_NOTICE([NOTICE: Mac OS X framework build enabled.]) +fi + +AC_MSG_NOTICE([******************************************** +You can compile GNUnet with + make +now. After that, run (if necessary as 'root') + make install +to install everything. You may want to create a new user account +to run the GNUnet service: + adduser gnunet +You also need to create an configuration file that should +specify the path where GNUnet should store data. For example, +you could store in "/etc/gnunet.conf" the following lines: + +[[PATHS]] +SERVICEHOME = /var/lib/gnunet +DEFAULTCONFIG = /etc/gnunet.conf + +Now, in order to start your peer, run as the 'gnunet' user + gnunet-arm -s + +Each GNUnet user should also create an (at least initially) empty +configuration file: + mkdir $HOME/.gnunet/ + touch $HOME/.gnunet/gnunet.conf + +Optionally, download and compile: +- gnunet-gtk to get a GUI for file-sharing and configuration. +********************************************]) diff --git a/contrib/Makefile.am b/contrib/Makefile.am new file mode 100644 index 0000000..df6bdc2 --- /dev/null +++ b/contrib/Makefile.am @@ -0,0 +1,47 @@ +INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include + + +if !MINGW +noinst_PROGRAMS = \ + timeout_watchdog + +timeout_watchdog_SOURCES = \ + timeout_watchdog.c +endif + +noinst_SCRIPTS = \ + gnunet_pyexpect.py \ + gnunet_janitor.py + +dist_pkgdata_DATA = \ + gnunet-logo-color.png + +EXTRA_DIST = \ + coverage.sh \ + hostlist.cgi \ + hostlist.php \ + report.sh \ + testing_hostkeys.dat \ + gnunet_pyexpect.py.in \ + gnunet_janitor.py.in + +do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' + +%.py: %.py.in Makefile + $(do_subst) < $< > $@ + chmod +x $@ + +# init_gnunet_redhat \ +# init_gnunet_ubuntu \ +# visualize_stats.sh \ +# gnmessage.sh \ +# junkinsert.sh \ +# junklookup.sh \ +# namespacehelper.sh + + +check_PROGRAMS = \ + test_gnunet_prefix + +test_gnunet_prefix_SOURCES = \ + test_gnunet_prefix.c diff --git a/contrib/Makefile.in b/contrib/Makefile.in new file mode 100644 index 0000000..04a23bf --- /dev/null +++ b/contrib/Makefile.in @@ -0,0 +1,687 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +@MINGW_FALSE@noinst_PROGRAMS = timeout_watchdog$(EXEEXT) +check_PROGRAMS = test_gnunet_prefix$(EXEEXT) +subdir = contrib +DIST_COMMON = $(dist_pkgdata_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am_test_gnunet_prefix_OBJECTS = test_gnunet_prefix.$(OBJEXT) +test_gnunet_prefix_OBJECTS = $(am_test_gnunet_prefix_OBJECTS) +test_gnunet_prefix_LDADD = $(LDADD) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am__timeout_watchdog_SOURCES_DIST = timeout_watchdog.c +@MINGW_FALSE@am_timeout_watchdog_OBJECTS = timeout_watchdog.$(OBJEXT) +timeout_watchdog_OBJECTS = $(am_timeout_watchdog_OBJECTS) +timeout_watchdog_LDADD = $(LDADD) +SCRIPTS = $(noinst_SCRIPTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(test_gnunet_prefix_SOURCES) $(timeout_watchdog_SOURCES) +DIST_SOURCES = $(test_gnunet_prefix_SOURCES) \ + $(am__timeout_watchdog_SOURCES_DIST) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkgdatadir)" +DATA = $(dist_pkgdata_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include +@MINGW_FALSE@timeout_watchdog_SOURCES = \ +@MINGW_FALSE@ timeout_watchdog.c + +noinst_SCRIPTS = \ + gnunet_pyexpect.py \ + gnunet_janitor.py + +dist_pkgdata_DATA = \ + gnunet-logo-color.png + +EXTRA_DIST = \ + coverage.sh \ + hostlist.cgi \ + hostlist.php \ + report.sh \ + testing_hostkeys.dat \ + gnunet_pyexpect.py.in \ + gnunet_janitor.py.in + +do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' +test_gnunet_prefix_SOURCES = \ + test_gnunet_prefix.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu contrib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +test_gnunet_prefix$(EXEEXT): $(test_gnunet_prefix_OBJECTS) $(test_gnunet_prefix_DEPENDENCIES) + @rm -f test_gnunet_prefix$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_prefix_OBJECTS) $(test_gnunet_prefix_LDADD) $(LIBS) +timeout_watchdog$(EXEEXT): $(timeout_watchdog_OBJECTS) $(timeout_watchdog_DEPENDENCIES) + @rm -f timeout_watchdog$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(timeout_watchdog_OBJECTS) $(timeout_watchdog_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_prefix.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timeout_watchdog.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_pkgdataDATA: $(dist_pkgdata_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgdatadir)" || $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" + @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \ + done + +uninstall-dist_pkgdataDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgdatadir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgdatadir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-am +all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(pkgdatadir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_pkgdataDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_pkgdataDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool \ + clean-noinstPROGRAMS ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dist_pkgdataDATA \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-dist_pkgdataDATA + + +%.py: %.py.in Makefile + $(do_subst) < $< > $@ + chmod +x $@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/coverage.sh b/contrib/coverage.sh new file mode 100755 index 0000000..b53a382 --- /dev/null +++ b/contrib/coverage.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# make sure configure was run with coverage enabled... +lcov --directory . --zerocounters +make check +rm `find * -name "test_*.gc??"` +for n in `find * -name "*.gc??" | grep libs` +do + cd `dirname $n` + mv `basename $n` .. + cd - +done +lcov --directory . --capture --output-file app.info +mkdir -p doc/coverage +genhtml -o doc/coverage app.info diff --git a/contrib/gnunet-logo-color.png b/contrib/gnunet-logo-color.png new file mode 100644 index 0000000..326822e Binary files /dev/null and b/contrib/gnunet-logo-color.png differ diff --git a/contrib/gnunet_janitor.py.in b/contrib/gnunet_janitor.py.in new file mode 100644 index 0000000..c11ff4f --- /dev/null +++ b/contrib/gnunet_janitor.py.in @@ -0,0 +1,74 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2011 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Finds any gnunet processes still running in the system and kills them +# +# gnunet janitor can be used by invoking `make' like this: +# TESTS_ENVIRONMENT='${top_srcdir}/contrib/gnunet_janitor.py &&' make check + +from __future__ import print_function +import os +import re +import subprocess +import sys +import shutil +import time +import signal + +if os.name == 'nt': + from win32com.client import GetObject + WMI = GetObject('winmgmts:') + +def get_process_list (): + result = [] + if os.name == 'nt': + processes = WMI.InstancesOf('Win32_Process') + for p in processes: + result.append ((p.Properties_('ProcessId').Value, re.sub (r'(.+)\.exe', r'\1', p.Properties_('Name').Value))) + else: + pids = [pid for pid in os.listdir('/proc') if pid.isdigit ()] + for pid in pids: + result.append ((pid, open (os.path.join ('/proc', pid, 'comm'), 'rb').read ())) + return result + +def main (): + procs = get_process_list () + gnunet_procs = [] + for p in procs: + if re.match (r'gnunet-.+', p[1]): + gnunet_procs.append (p) + for p in gnunet_procs: + if re.match (r'gnunet-service-arm', p[1]): + print ("killing arm process {0:5} {1}".format (p[0], p[1])) + try: + os.kill (p[0], signal.SIGTERM) + except OSError as e: + print ("failed: {0}".format (e)) + pass + for p in gnunet_procs: + if not re.match (r'gnunet-service-arm', p[1]): + print ("killing non-arm process {0:5} {1}".format (p[0], p[1])) + try: + os.kill (p[0], signal.SIGTERM) + except OSError as e: + print ("failed: {0}".format (e)) + pass + +if __name__ == '__main__': + sys.exit (main ()) diff --git a/contrib/gnunet_pyexpect.py.in b/contrib/gnunet_pyexpect.py.in new file mode 100644 index 0000000..9e5c83f --- /dev/null +++ b/contrib/gnunet_pyexpect.py.in @@ -0,0 +1,83 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Testcase for gnunet-peerinfo +from __future__ import print_function +import os +import re +import subprocess +import sys +import shutil +import time + +class pexpect (object): + def __init__ (self): + super (pexpect, self).__init__ () + + def spawn (self, stdin, arglist, *pargs, **kwargs): + env = kwargs.pop ('env', None) + if env is None: + env = os.environ.copy () + # This messes up some testcases, disable log redirection + env.pop ('GNUNET_FORCE_LOGFILE', None) + self.proc = subprocess.Popen (arglist, *pargs, env=env, **kwargs) + if self.proc is None: + print ("Failed to spawn a process {0}".format (arglist)) + sys.exit (1) + if stdin is not None: + self.stdo, self.stde = self.proc.communicate (stdin) + else: + self.stdo, self.stde = self.proc.communicate () + return self.proc + + def expect (self, s, r, flags=0): + stream = self.stdo if s == 'stdout' else self.stde + if isinstance (r, str): + if r == "EOF": + if len (stream) == 0: + return True + else: + print ("Failed to find `{1}' in {0}, which is `{2}' ({3})".format (s, r, stream, len (stream))) + sys.exit (2) + raise ValueError ("Argument `r' should be an instance of re.RegexObject or a special string, but is `{0}'".format (r)) + m = r.search (stream, flags) + if not m: + print ("Failed to find `{1}' in {0}, which is is `{2}'".format (s, r.pattern, stream)) + sys.exit (2) + stream = stream[m.end ():] + if s == 'stdout': + self.stdo = stream + else: + self.stde = stream + return m + + def read (self, s, size=-1): + stream = self.stdo if s == 'stdout' else self.stde + result = "" + if size < 0: + result = stream + new_stream = "" + else: + result = stream[0:size] + new_stream = stream[size:] + if s == 'stdout': + self.stdo = new_stream + else: + self.stde = new_stream + return result diff --git a/contrib/hostlist.cgi b/contrib/hostlist.cgi new file mode 100644 index 0000000..f04246e --- /dev/null +++ b/contrib/hostlist.cgi @@ -0,0 +1,5 @@ +#!/bin/sh +# This is a CGI script to generate the host list on-demand. +# by Michael Wensley, with minor improvements by Christian Grothoff +echo -ne "Content-Type: application/octet-stream\r\n\r\n" +cat /var/lib/gnunet/data/hosts/*.{2,3,4,5,6,8,12,17,23,25} diff --git a/contrib/hostlist.php b/contrib/hostlist.php new file mode 100644 index 0000000..1585615 --- /dev/null +++ b/contrib/hostlist.php @@ -0,0 +1,35 @@ += 4.3.0 +// Author: "Krasko Oleksandr" <0m3r.mail@gmail.com> +// Minor improvements by Christian Grothoff +header("Content-Type: application/octet-stream\r\n\r\n"); +$extmas = array(); +$pv=$_GET['p']; +if (isset($pv)) + { + for ($ii=0;$ii<64;$ii++) + if (0 != ($pv & (1 << $ii))) + $extmas[] = $ii; + } +else + { + $extmas = array('2','3','4','5','6','8','12','17','23','25'); + } +$path = '/var/lib/gnunet/data/hosts/'; // adjust as necessary +$dir = opendir($path); +if (! $dir) + die("Cannot open directory $path.\n"); +$mas = array(); +while ($fname = readdir($dir)) { + $fn = $path . '/' . $fname; + if (is_file($fn)) { + $dpo = strpos($fname, '.') + 1; + $len = strlen($fname); + if (in_array(substr($fname, $dpo - $len), $extmas)) + $mas[] = $fn; + } +} +shuffle($mas); // randomize order +foreach ($mas as $val) + echo file_get_contents($val); +?> diff --git a/contrib/report.sh b/contrib/report.sh new file mode 100755 index 0000000..37a1c41 --- /dev/null +++ b/contrib/report.sh @@ -0,0 +1,200 @@ +#!/bin/sh + +TEST=`type type|grep not` +if test -n "$TEST"; then + WHICH=which +else + WHICH=type +fi + +echo "Please submit the following information with your bug report: " +echo "--------------------------------------------------------------" +OS=`uname -s 2>/dev/null` +echo "OS : $OS" +REL=`uname -r 2>/dev/null` +echo "OS RELEASE : $REL" +HW=`uname -m 2>/dev/null` +echo "HARDWARE : $HW" + +TEST=`$WHICH gcc 2>/dev/null` +if test -n "$TEST"; then + VERS=`gcc --version 2>/dev/null | head -n 1` + echo "gcc : $VERS" +else + echo "gcc : Not Found"; +fi + +TEST=`$WHICH gmake 2>/dev/null` +if test -n "$TEST" ; then + gmake --version 2>/dev/null |\ + awk -F, '{print $1}' |\ + awk '/GNU Make/{print "GNU gmake :",$NF}' +else + TEST=`make --version 2>/dev/null` + if test -n "$TEST"; then + make --version 2>/dev/null |\ + awk -F, '{print $1}' |\ + awk '/GNU Make/{print "make :",$NF}' + else + echo "make : Not Found" + fi +fi + +TEST=`$WHICH autoconf 2>/dev/null` +if test -n "$TEST"; then + autoconf --version |\ + head -n 1 |\ + awk '{\ + if (length($4) == 0) {\ + print "autoconf : "$3\ + } else {\ + print "autoconf : "$4\ + }}' +else + echo "autoconf : Not Found" +fi + +TEST=`$WHICH automake 2>/dev/null` +if test -n "$TEST"; then + automake --version 2>/dev/null |\ + head -n 1 |\ + awk '{print "automake : "$4}' +else + echo "automake : Not Found" +fi + +TEST=`$WHICH libtool 2>/dev/null` +if test -n "$TEST"; then + libtool --version 2>/dev/null |\ + head -n 1 |\ + awk '{print "libtool : "$4}' +else + echo "libtool : Not Found" +fi + +TEST=`$WHICH extract 2>/dev/null` +if test -n "$TEST"; then + extract -v 2>/dev/null |\ + head -n 1 |\ + awk '{print "libextractor : "$2}' +else + echo "libextractor : Not Found" +fi + +if test -x gnunetd; then + gnunetd -v | sed -e "s/v//" 2>/dev/null |\ + awk '{print "GNUnet 0.8 : "$2 (may conflict!)}' +else + echo "GNUnet 0.8 : Not Found (good)" +fi + +TEST=`$WHICH gnunet-arm 2>/dev/null` +if test -n "$TEST"; then + gnunet-arm -v | sed -e "s/v//" 2>/dev/null |\ + awk '{print "GNUnet 0.9 : "$2}' +else + echo "GNUnet 0.9 : Not Found" +fi + +TEST=`$WHICH libgcrypt-config 2> /dev/null` +if test -n "$TEST"; then + libgcrypt-config --version 2> /dev/null | \ + awk '{print "libgcrypt : "$1}' +else + echo "libgcrypt : Not Found" +fi + +TEST=`$WHICH mysql_config 2> /dev/null` +if test -n "$TEST"; then + mysql_config --version 2> /dev/null | \ + awk '{print "mysql : "$1}' +else + echo "mysql : Not Found" +fi + +TEST=`$WHICH pkg-config 2> /dev/null` +if test -n "$TEST"; then + pkg-config --version 2> /dev/null | \ + awk '{print "pkg-config : "$1}' +else + echo "pkg-config : Not Found" +fi + +TEST=`$WHICH pkg-config 2> /dev/null` +if test -n "$TEST"; then + pkg-config --modversion glib-2.0 2> /dev/null | \ + awk '{print "glib2 : "$1}' +else + echo "glib2 : Not Found" +fi + +TEST=`$WHICH pkg-config 2> /dev/null` +if test -n "$TEST"; then + pkg-config --modversion gtk+-2.0 2> /dev/null | \ + awk '{print "gtk2+ : "$1}' +else + echo "gtk2+ : Not Found" +fi + +TEST=`$WHICH dpkg 2> /dev/null` +if test -n "$TEST"; then + LINES=`dpkg -s libgmp3-dev | grep Version | wc -l` + if test "$LINES" = "1" + then + VERSION=`dpkg -s libgmp3-dev | grep Version | awk '{print $2}'` + echo "GMP : libgmp3-dev-$VERSION.deb" + else + echo "GMP : dpkg: libgmp3-dev not installed" + fi +else + TEST=`$WHICH rpm 2> /dev/null` + if test -n "$TEST"; then + rpm -q gmp | sed -e "s/gmp-//" 2> /dev/null | \ + awk '{print "GMP : "$1.rpm}' + else + echo "GMP : Test not available" + fi +fi + +TEST=`$WHICH gettext 2> /dev/null` +if test -n "$TEST"; then + gettext --version | head -n1 2> /dev/null | \ + awk '{print "GNU gettext : "$4}' +else + echo "GNU gettext : Not found" +fi + + +TEST=`$WHICH curl-config 2> /dev/null` +if test -n "$TEST"; then + curl-config --version | head -n1 2> /dev/null | \ + awk '{print "libcurl : "$2}' +else + echo "libcurl : Not found" +fi + + +TEST=`which qmake 2> /dev/null` +if test -x "$TEST"; then + qmake --version | tail -n 1 | awk '{print "Qt : "$4}' +else + echo "Qt : Not found" +fi + +echo -n "MHD : " +TMPFILE=`mktemp /tmp/mhd-version-testXXXXXX` +cat - >$TMPFILE.c < +#include +int main() +{ + fprintf (stdout, "%X\n", MHD_VERSION); + return 0; +} +EOF + +gcc -o $TMPFILE $TMPFILE.c 2> /dev/null && $TMPFILE || echo "Not found" +rm -f $TMPFILE $TMPFILE.bin + + +echo "--------------------------------------------------------------" diff --git a/contrib/test_gnunet_prefix.c b/contrib/test_gnunet_prefix.c new file mode 100644 index 0000000..732e8eb --- /dev/null +++ b/contrib/test_gnunet_prefix.c @@ -0,0 +1,65 @@ +/* + This file is part of GNUnet + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +/** + * @file contrib/test_gnunet_prefix.c + * @brief test if environment variable GNUNET_PREFIX is set so that + * we have a chance to run tests + * @author Christian Grothoff + */ +#include "platform.h" + + +int +main (int argc, + char **argv) +{ + const char *basename; + const char *dirname; + + basename = getenv ("GNUNET_PREFIX"); + if (NULL == basename) + { + fprintf (stderr, + _("Environment variable GNUNET_PREFIX not set\n")); + fprintf (stderr, + _("Testcases will not work!\n")); + return 1; + } + dirname = DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR "config.d"; + { + char tmp[strlen (basename) + strlen (dirname) + 1]; + sprintf (tmp, "%s%s", basename, dirname); + if (0 != access (tmp, R_OK)) + { + fprintf (stderr, + _("Failed to access `%s': %s\n"), + tmp, + STRERROR (errno)); + fprintf (stderr, + _("Check that you did run `make install' and that GNUNET_PREFIX='%s' is the correct prefix.\n"), + basename); + fprintf (stderr, + _("Testcases will not work!\n")); + return 2; + } + } + return 0; +} diff --git a/contrib/testing_hostkeys.dat b/contrib/testing_hostkeys.dat new file mode 100644 index 0000000..d355fcb Binary files /dev/null and b/contrib/testing_hostkeys.dat differ diff --git a/contrib/timeout_watchdog.c b/contrib/timeout_watchdog.c new file mode 100644 index 0000000..a33f67a --- /dev/null +++ b/contrib/timeout_watchdog.c @@ -0,0 +1,113 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file contrib/timeout_watchdog.c + * @brief small tool starting a child process, waiting that it terminates or killing it after a given timeout period + * @author Matthias Wachs + */ + +#include +#include +#include +#include +#include +#include + +static pid_t child; + +static void +sigchld_handler (int val) +{ + int status = 0; + int ret = 0; + + waitpid (child, &status, 0); + if (WIFEXITED (status) != 0) + { + ret = WEXITSTATUS (status); + printf ("Test process exited with result %u\n", ret); + } + if (WIFSIGNALED (status) != 0) + { + ret = WTERMSIG (status); + printf ("Test process was signaled %u\n", ret); + } + exit (ret); +} + +static void +sigint_handler (int val) +{ + kill (0, val); + exit (val); +} + +int +main (int argc, char *argv[]) +{ + int timeout = 0; + pid_t gpid = 0; + + if (argc < 3) + { + printf + ("arg 1: timeout in sec., arg 2: executable, arg arguments\n"); + exit (1); + } + + timeout = atoi (argv[1]); + + if (timeout == 0) + timeout = 600; + +/* with getpgid() it does not compile, but getpgrp is the BSD version and working */ + gpid = getpgrp (); + + signal (SIGCHLD, sigchld_handler); + signal (SIGABRT, sigint_handler); + signal (SIGFPE, sigint_handler); + signal (SIGILL, sigint_handler); + signal (SIGINT, sigint_handler); + signal (SIGSEGV, sigint_handler); + signal (SIGTERM, sigint_handler); + + child = fork (); + if (child == 0) + { + /* int setpgrp(pid_t pid, pid_t pgid); is not working on this machine */ + //setpgrp (0, pid_t gpid); + if (-1 != gpid) + setpgid (0, gpid); + execvp (argv[2], &argv[2]); + exit (1); + } + if (child > 0) + { + sleep (timeout); + printf ("Child processes were killed after timeout of %u seconds\n", + timeout); + kill (0, SIGTERM); + exit (1); + } + exit (1); +} + +/* end of timeout_watchdog.c */ diff --git a/depcomp b/depcomp new file mode 100755 index 0000000..df8eea7 --- /dev/null +++ b/depcomp @@ -0,0 +1,630 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free +# Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u="sed s,\\\\\\\\,/,g" + depmode=msvisualcpp +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> "$depfile" + echo >> "$depfile" + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..738d970 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = man + +EXTRA_DIST = README.mysql README.postgres diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 0000000..601e718 --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,662 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = doc +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = man +EXTRA_DIST = README.mysql README.postgres +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu doc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/doc/README.mysql b/doc/README.mysql new file mode 100644 index 0000000..84aeb24 --- /dev/null +++ b/doc/README.mysql @@ -0,0 +1,95 @@ +How to setup the MySQL database for GNUnet. + +NOTE: This db module does NOT work with mysql before 4.1 since we need +prepared statements. We are generally testing the code against MySQL +5.0 at this point. + +HIGHLIGHTS + +Pros + + On up-to-date hardware where mysql can be used comfortably, this + module will have better performance than the other db choices + (according to our tests). + + Its often possible to recover the mysql database from internal + inconsistencies. The other db choices do not support repair + (gnunet-check cannot fix problems internal to the dbmgr!). + For example, we have seen several cases where power failure + has ruined a gdbm database beyond repair. + + much faster (for one of the key benchmarks -- content migration + -- we have measure mysql taking 2s for an operation where + sqlite takes 150s). +Cons + - Memory usage (Comment: "I have 1G and it never caused me trouble") + - Manual setup + +MANUAL SETUP INSTRUCTIONS + + 1) in /etc/gnunet.conf, set + DATABASE = mysql + + 2) Then access mysql as root, + $ mysql -u root -p + and do the following. [You should replace $USER with the username + that will be running the gnunetd process]. + + CREATE DATABASE gnunet; + GRANT select,insert,update,delete,create,alter,drop,create temporary tables + ON gnunet.* TO $USER@localhost; + SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like'); + FLUSH PRIVILEGES; + + 3) In the $HOME directory of $USER, create a ".my.cnf" file + with the following lines + + [client] + user=$USER + password=$the_password_you_like + + Thats it. Note that .my.cnf file is a security risk unless its on + a safe partition etc. The $HOME/.my.cnf can of course be a symbolic + link. Even greater security risk can be achieved by setting no + password for $USER. Luckily $USER has only priviledges to mess + up GNUnet's tables, nothing else (unless you give him more, + of course). + + 4) Still, perhaps you should briefly try if the DB connection + works. First, login as $USER. Then use, + + $ mysql -u $USER + mysql> use gnunet; + + If you get the message "Database changed" it probably works. + + [If you get "ERROR 2002: Can't connect to local MySQL server + through socket '/tmp/mysql.sock' (2)" it may be resolvable by + "ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock" + so there may be some additional trouble depending on your mysql setup.] + + 5) If you want to run the testcases, you must create a second + database "gnunetcheck" with the same username and password. + This database will then be used for testing ("make check"). + + +REPAIRING TABLES + +- Its probably healthy to check your tables for inconsistencies + every now and then, especially after system crashes. +- If you get odd SEGVs on gnunetd startup, it might be that the mysql + databases have been corrupted. +- The tables can be verified/fixed in two ways; + 1) by shutting down mysqld (mandatory!) and running + # myisamchk -r *.MYI + in /var/lib/mysql/gnunet/ (or wherever the tables are stored). + Another repair command is "mysqlcheck". The usable command + may depend on your mysql build/version. Or, + 2) by executing + mysql> REPAIR TABLE gn090; + + +PROBLEMS? + +If you have problems related to the mysql module, your best friend is +probably the mysql manual. The first thing to check is that mysql is +basically operational, that you can connect to it, create tables, +issue queries etc. + diff --git a/doc/README.postgres b/doc/README.postgres new file mode 100644 index 0000000..2c96716 --- /dev/null +++ b/doc/README.postgres @@ -0,0 +1,49 @@ +How to setup the Postgres database for GNUnet. + +NOTE: This db module was developed for Postgres 8.3. I have no +idea what the minimum version that we require is exactly. + +HIGHLIGHTS + +Pros + + Easier to setup than MySQL + + Real database +Cons + - Quite slow + - Still some setup + +MANUAL SETUP INSTRUCTIONS + + 1) in /etc/gnunet.conf, set + DATABASE = postgres + + 2) Then access postgres to create a user; I had to do this to get + access and create a user: + # su - postgres + $ createuser + At this point, use the name of the user running gnunet + for the role, do not set it to superuser, allow the creation + of databases. + + 3) As that user, create a database (or two): + $ createdb gnunet + $ createdb gnunetcheck # this way you can run "make check" + + Thats it. + + 4) Still, perhaps you should briefly try if the DB connection + works. First, login as the user who will run gnunetd. Then use, + + $ psql gnunet # or gnunetcheck + gnunet=> \dt + + If, after you have started gnunetd at least once, you get a + gn090 table here, it probably works. + +PROBLEMS? + +If you have problems related to the postgres module, your best friend +is probably the postgres manual. The first thing to check is that +postgres is basically operational, that you can connect to it, create +tables, issue queries etc. (see step 4 above for details). + diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am new file mode 100644 index 0000000..6d98ffa --- /dev/null +++ b/doc/man/Makefile.am @@ -0,0 +1,17 @@ +man_MANS = \ + gnunet-arm.1 \ + gnunet-directory.1 \ + gnunet-download.1 \ + gnunet-download-manager.1 \ + gnunet-fs.1 \ + gnunet-nat-server.1 \ + gnunet-peerinfo.1 \ + gnunet-pseudonym.1 \ + gnunet-publish.1 \ + gnunet-search.1 \ + gnunet-statistics.1 \ + gnunet-transport.1 \ + gnunet-unindex.1 \ + gnunet-vpn.1 + +EXTRA_DIST = ${man_MANS} diff --git a/doc/man/Makefile.in b/doc/man/Makefile.in new file mode 100644 index 0000000..f9c665d --- /dev/null +++ b/doc/man/Makefile.in @@ -0,0 +1,557 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = doc/man +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +man1dir = $(mandir)/man1 +am__installdirs = "$(DESTDIR)$(man1dir)" +NROFF = nroff +MANS = $(man_MANS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +man_MANS = \ + gnunet-arm.1 \ + gnunet-directory.1 \ + gnunet-download.1 \ + gnunet-download-manager.1 \ + gnunet-fs.1 \ + gnunet-nat-server.1 \ + gnunet-peerinfo.1 \ + gnunet-pseudonym.1 \ + gnunet-publish.1 \ + gnunet-search.1 \ + gnunet-statistics.1 \ + gnunet-transport.1 \ + gnunet-unindex.1 \ + gnunet-vpn.1 + +EXTRA_DIST = ${man_MANS} +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/man/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu doc/man/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man1: $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" + @list=''; test -n "$(man1dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(MANS) +installdirs: + for dir in "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man1 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-man + +uninstall-man: uninstall-man1 + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-man1 \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + uninstall uninstall-am uninstall-man uninstall-man1 + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/doc/man/gnunet-arm.1 b/doc/man/gnunet-arm.1 new file mode 100644 index 0000000..1bd4467 --- /dev/null +++ b/doc/man/gnunet-arm.1 @@ -0,0 +1,45 @@ +.TH GNUNET\-ARM 1 "Jan 4, 2012" "GNUnet" + +.SH NAME +gnunet\-arm \- control GNUnet services + +.SH SYNOPSIS +.B gnunet\-arm +.RI [ options ] +.br + +.SH DESCRIPTION +\fBgnunet\-arm\fP can be used to start or stop GNUnet services, including the ARM service itself. The ARM service is a supervisor for GNUnet's service processes. ARM starts services on-demand or as configured and re-starts them if they crash. + +.SH OPTIONS +.B +.IP "\-c FILENAME, \-\-config=FILENAME" +Use the configuration file FILENAME. +.B +.IP "\-e, \-\-end" +Shutdown all GNUnet services (including ARM itself). Running "gnunet-arm -e" is the usual way to shutdown a GNUnet peer. +.B +.IP "\-h, \-\-help" +Print short help on options. +.B +.IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL" +Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR. +.B +.IP "\-i SERVICE, \-\-init=SERVICE" +Starts the specified SERVICE if it is not already running. More specifically, this makes the service behave as if it were in the default services list. +.B +.IP "\-k SERVICE, \-\-kill=SERVICE" +Stop the specified SERVICE if it is running. While this will kill the service right now, the service may be restarted immediately if other services depend on it (service is then started 'on-demand'). If the service used to be a 'default' service, its default-service status will be revoked. If the service was not a default service, it will just be (temporarily) stopped, but could be re-started on-demand at any time. +.B +.IP "\-s, \-\-start" +Start all GNUnet default services on this system (and also ARM). Naturally, if a service is demanded by a default service, it will then also be started. Running "gnunet-arm -s" is the usual way to start a GNUnet peer. +.B +.IP "\-v, \-\-version" +Print GNUnet version number. + + +.SH BUGS +Report bugs by using Mantis or by sending electronic mail to + +.SH SEE ALSO +gnunet\-service\-arm(1) diff --git a/doc/man/gnunet-directory.1 b/doc/man/gnunet-directory.1 new file mode 100644 index 0000000..373e171 --- /dev/null +++ b/doc/man/gnunet-directory.1 @@ -0,0 +1,35 @@ +.TH gnunet-directory "1" "25 Feb 2012" "GNUnet" +.SH NAME +gnunet\-directory \- display directories + +.SH SYNOPSIS +.B gnunet\-directory +[\fIOPTIONS\fR] (FILENAME)* +.SH DESCRIPTION +.PP +gnunet\-directory lists the contents of one or more GNUnet directories. A GNUnet directory is a binary file that contains a list of GNUnet file\-sharing URIs and meta data. The names of the directory files must be passed as command\-line arguments to gnunet\-directory. +.TP +\fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR +configuration file to use (useless option since gnunet\-directory does not really depend on any configuration options) +.TP +\fB\-h\fR, \fB\-\-help\fR +print help page +.TP +\fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR +Change the loglevel. Possible values for LOGLEVEL are ERROR, WARNING, INFO and DEBUG. +.TP +\fB\-v\fR, \fB\-\-version\fR +print the version number +.SH NOTES +A GNUnet directory is a file containing a list of GNUnet URIs and meta data. The keys can point to files, other directories or files in namespaces. In other words, a GNUnet directory is similar to UNIX directories. The difference to tar and zip is that GNUnet directory does not contain the actual files (except if they are really small, in which case they may be inlined), just symbolic (links), similar to directories with symbolic links in UNIX filesystems. The benefit is that the individual files can be retrieved separately (if desired) and if some of the files are inserted to another node in GNUnet, this just increases their availability but does not produce useless duplicates (for example, it is a better idea to publish a collection of pictures or compressed sound files using a GNUnet directory instead of processing them with archivers such as tar or zip first). Directories can contain arbitrary meta data for each file. + +If a directory has missing blocks (for example, some blocks failed to download), GNUnet is typically able to retrieve information about other files in the directory. Files in a GNUnet directory have no particular order; the GNUnet code that generates a directory can reorder the entries in order to better fit the information about files into blocks of 32k. Respecting 32k boundaries where possible makes it easier for gnunet\-directory (and other tools) to recover information from partially downloaded directory files. + +At the moment, directories can be created by \fBgnunet\-fs\-gtk\fP and \fBgnunet\-publish\fP. Just like ordinary files, a directory can be published in a namespace. + +GNUnet directories use the (unregistered) mimetype \fBapplication/gnunet\-directory\fP. They can show up among normal search results. The directory file can be downloaded to disk by \fBgnunet\-download\fP(1) for later processing or be handled more directly by \fBgnunet\-fs\-gtk\fP(1). + +.SH "REPORTING BUGS" +Report bugs by using mantis or by sending electronic mail to +.SH "SEE ALSO" +\fBgnunet\-fs\-gtk\fP(1), \fBgnunet\-publish\fP(1), \fBgnunet\-search\fP(1), \fBgnunet\-download\fP(1) diff --git a/doc/man/gnunet-download-manager.1 b/doc/man/gnunet-download-manager.1 new file mode 100644 index 0000000..844f810 --- /dev/null +++ b/doc/man/gnunet-download-manager.1 @@ -0,0 +1,24 @@ +.TH GNUNET-DOWNLOAD-MANAGER 1 "15 Jan, 2011" "GNUnet" + +.SH NAME +gnunet-download-manager \- manage downloads across sessions + +.SH SYNOPSIS +.B gnunet\-download\-manager +.RI [ options ] +.br + +.SH DESCRIPTION +\fBgnunet\-download\-manager\fP is a script that can be used to track download sessions. It makes the process of resuming downloads after a system reboot easier. A typical use is to define an alias (depending on your shell) of the form + +$ alias gnunet\-download='gnunet\-download\-manager.scm download' + +Other commands for the download manager include resume (resumes all downloads), status (show status of pending downloads), killall (abort all downloads), settings (for configuration) and help (print help text). + +gnunet\-download\-manager is a scheme script and will only work if guile is available. + +.SH BUGS +Report bugs by using mantis or by sending electronic mail to + +.SH SEE ALSO +gnunet\-download(1) diff --git a/doc/man/gnunet-download.1 b/doc/man/gnunet-download.1 new file mode 100644 index 0000000..9754cb0 --- /dev/null +++ b/doc/man/gnunet-download.1 @@ -0,0 +1,81 @@ +.TH GNUNET-DOWNLOAD "1" "25 Feb 2012" "GNUnet" +.SH NAME +gnunet\-download \- a command line interface for downloading files from GNUnet +.SH SYNOPSIS +.B gnunet\-download +[\fIOPTIONS\fR] \-\- GNUNET_URI +.SH DESCRIPTION +.PP +Download files from GNUnet. + +.TP +\fB\-a \fILEVEL\fR, \fB\-\-anonymity=LEVEL\fR +set desired level of receiver anonymity. Default is 1. + +.TP +\fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR +use config file (defaults: ~/.gnunet/gnunet.conf) + +.TP +\fB\-D, \fB\-\-delete\-incomplete\fR +causes gnunet\-download to delete incomplete downloads when aborted with CTRL\-C. Note that complete files that are part of an incomplete recursive download will not be deleted even with this option. Without this option, terminating gnunet\-download with a signal will cause incomplete downloads to stay on disk. If gnunet\-download runs to (normal) completion finishing the download, this option has no effect. + +.TP +\fB\-h\fR, \fB\-\-help\fR +print help page + +.TP +\fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR +Change the loglevel. Possible values for LOGLEVEL are +ERROR, WARNING, INFO and DEBUG. + +.TP +\fB\-n\fR, \fB\-\-no-network\fR +Only search locally, do not forward requests to other peers. + +.TP +\fB\-o \fIFILENAME\fR, \fB\-\-output=FILENAME\fR +write the file to FILENAME. Hint: when recursively downloading a directory, append a '/' to the end of the FILENAME to create a directory of that name. If no FILENAME is specified, gnunet\-download constructs a temporary ID from the URI of the file. The final filename is constructed based on meta\-data extracted using libextractor (if available). + +.TP +\fB\-p \fIDOWNLOADS\fR, \fB\-\-parallelism=DOWNLOADS\fR +set the maximum number of parallel downloads that is allowed. More parallel downloads can, to some extent, improve the overall time to download content. However, parallel downloads also take more memory (see also option \-r which can be used to limit memory utilization) and more sockets. This option is used to limit the number of files that are downloaded in parallel (\-r can be used to limit the number of blocks that are concurrently requested). As a result, the value only matters for recursive downloads. The default value is 32. + +.TP +\fB\-r \fIREQUESTS\fR, \fB\-\-request-parallelism=REQUESTS\fR +set the maximum number of parallel requests that is allowed. If multiple files are downloaded, gnunet\-download will not run them in parallel if this would cause the number of pending requests to possibly exceed the given value. This is useful since, for example, downloading dozens of multi\-gigabyte files in parallel could exhaust memory resources and would hardly improve performance. Note that the limit only applies to this specific process and that other download activities by other processes are not included in this limit. Consider raising this limit for large recursive downloads with many large files if memory and network bandwidth are not fully utilized and if the parallelism limit (\-p option) is not reached. This option also only matters for recursive downloads. The default value is 4092. + +.TP +\fB\-R\fR, \fB\-\-recursive\fR +download directories recursively (and in parallel); note that the URI must belong to a GNUnet directory and that the filename given must end with a '/' \-\- otherwise, only the file corresponding to the URI will be downloaded. Note that in addition to using '-R', you must also specify a filename ending in '.gnd' so that the code realizes that the top-level file is a directory (since we have no meta data). + +.TP +\fB\-v\fR, \fB\-\-version\fR +print the version number + +.TP +\fB\-V\fR, \fB\-\-verbose\fR +print progress information + +.SH NOTES +The GNUNET_URI is typically obtained from gnunet\-search. gnunet\-fs\-gtk can also be used instead of gnunet\-download. +If you ever have to abort a download, you can at any time continue it by re\-issuing gnunet\-download with the same filename. In that case GNUnet will not download blocks again that are already present. GNUnet's file\-encoding will ensure file integrity, even if the existing file was not downloaded from GNUnet in the first place. Temporary information will be appended to the target file until the download is completed. + +.SH SETTING ANONYMITY LEVEL + +The \fB\-a\fR option can be used to specify additional anonymity constraints. If set to 0, GNUnet will try to download the file as fast as possible, including using non-anonymous methods. If you set it to 1 (default), you use the standard anonymous routing algorithm (which does not explicitly leak your identity). However, a powerful adversary may still be able to perform traffic analysis (statistics) to over time infer data about your identity. You can gain better privacy by specifying a higher level of anonymity, which increases the amount of cover traffic your own traffic will get, at the expense of performance. Note that your download performance is not only determined by your own anonymity level, but also by the anonymity level of the peers publishing the file. So even if you download with anonymity level 0, the peers publishing the data might be sharing with a higher anonymity level, which in this case will determine performance. Also, peers that cache content in the network always use anonymity level 1. + +This option can be used to limit requests further than that. In particular, you can require GNUnet to receive certain amounts of traffic from other peers before sending your queries. This way, you can gain very high levels of anonymity \- at the expense of much more traffic and much higher latency. So set it only if you really believe you need it. + +The definition of ANONYMITY\-RECEIVE is the following. 0 means no anonymity is required. Otherwise a value of 'v' means that 1 out of v bytes of "anonymous" traffic can be from the local user, leaving 'v-1' bytes of cover traffic per byte on the wire. Thus, if GNUnet routes n bytes of messages from foreign peers (using anonymous routing), it may originate n/(v-1) bytes of queries in the same time\-period. The time\-period is twice the average delay that GNUnet defers forwarded queries. + +The default is 1 and this should be fine for most users. Also notice that if you choose very large values, you may end up having no throughput at all, especially if many of your fellow GNUnet\-peers all do the same. + +.SH FILES +.TP +~/.gnunet/gnunet.conf +GNUnet configuration file +.SH "REPORTING BUGS" +Report bugs to or by sending electronic mail to +.SH "SEE ALSO" +\fBgnunet\-fs\-gtk\fP(1), \fBgnunet\-publish\fP(1), \fBgnunet\-search\fP(1), \fBgnunet.conf\fP(5), \fBgnunet\-service\-fs\fP(1) diff --git a/doc/man/gnunet-fs.1 b/doc/man/gnunet-fs.1 new file mode 100644 index 0000000..fcf0663 --- /dev/null +++ b/doc/man/gnunet-fs.1 @@ -0,0 +1,38 @@ +.TH gnunet\-fs "1" "2 Nov 2011" "GNUnet" +.SH NAME +gnunet\-fs \- measure and control the fs subsystem + +.SH SYNOPSIS +.B gnunet\-fs +[\fIOPTIONS\fR] +.SH DESCRIPTION +.PP + +gnunet\-fs is a tool to access various functions of GNUnet's fs subsystem from the command\-line. Most of these are not expected to be useful for end-users. gnunet\-fs can currently only be used to obtain a list of indexed files. Other functions should be added in the near future. + +.TP +\fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR +configuration file to use +.TP +\fB\-h\fR, \fB\-\-help\fR +print help page +.TP +\fB\-i\fR, \fB\-\-list-indexed\fR +print information about files that are currently indexed by file-sharing +.TP +\fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR +Change the loglevel. Possible values for LOGLEVEL are ERROR, WARNING, INFO and DEBUG. +.TP +\fB\-v\fR, \fB\-\-version\fR +print the version number +.TP +\fB\-V\fR, \fB\-\-verbose\fR +be verbose + +.SH NOTES + + +.SH "REPORTING BUGS" +Report bugs by using mantis or by sending electronic mail to +.SH "SEE ALSO" +\fBgnunet\-publish\fP(1) diff --git a/doc/man/gnunet-nat-server.1 b/doc/man/gnunet-nat-server.1 new file mode 100644 index 0000000..dcf856e --- /dev/null +++ b/doc/man/gnunet-nat-server.1 @@ -0,0 +1,35 @@ +.TH GNUNET\-NAT\-SERVER 1 "25 Feb 2012" "GNUnet" + +.SH NAME +gnunet\-nat\-server \- help GNUnet setup test network setup with NAT + +.SH SYNOPSIS +.B gnunet\-nat\-server +.RI [ options ] +.RI PORT +.br + +.SH DESCRIPTION + +Normal GNUnet end-users should not concern themselves with gnunet\-nat\-server. In fact, distributions are encouraged to consider not shipping it at all. Running gnunet\-nat\-server's is similar to running hostlist servers: it is a special service to the community with special requirements and no benefit to those running the service. + +This program will listen on the specified PORT for incoming requests to test a peer's network connectivity. Incoming requests can ask it to connect to a given IPv4 address (and port) using TCP or UDP and to send a 2-byte test message using the specified address. The program can also be asked to send a "fake" ICMP response message to a given IPv4 address (for autonomous NAT traversal \-\-\- see the description in the respective research paper). + +The idea is that gnunet\-nat\-server will be run on some trusted hosts with unrestricted connectivity to allow GNUnet users to test their network configuration. As written, the code allows any user on the Internet to cause the gnunet\-nat\-server to send 2-bytes of arbitrary data to any TCP or UDP port at any address. We believe that this is generally harmless. + +When running gnunet\-nat\-server, make sure to use a configuration that disables most NAT options but enables 'enable_nat_client' and sets 'internal_address' to the global IP address of your local host. Also, the gnunet\-helper\-nat\-client should be installed locally and run with root privileges (SUID), otherwise the gnunet\-nat\-server will not work properly. + +Note that gnunet\-nat\-server could be run via gnunet\-arm but typically is not. Also, the name of the host and port that gnunet\-nat\-server is run on should be specified in the NATSERVER option in the [setup] section of the configuration file of hosts that are supposed to autoconfigure with this server. + + +.SH OPTIONS +.B +.IP "\-c FILENAME, \-\-config=FILENAME" +Use the configuration file FILENAME. + +.SH BUGS +Report bugs by using Mantis or by sending electronic mail to + +.SH SEE ALSO +gnunet\-transport(1) + diff --git a/doc/man/gnunet-peerinfo.1 b/doc/man/gnunet-peerinfo.1 new file mode 100644 index 0000000..e2691b1 --- /dev/null +++ b/doc/man/gnunet-peerinfo.1 @@ -0,0 +1,43 @@ +.TH GNUNET\-PEERINFO 1 "Mar 15, 2009" "GNUnet" + +.SH NAME +gnunet\-peerinfo \- Display information about other peers. + +.SH SYNOPSIS +.B gnunet\-peerinfo +.RI [ options ] +.br + +.SH DESCRIPTION +.PP +\fBgnunet\-peerinfo\fP display the known addresses and trust of known peers. + +.SH OPTIONS +.B +.IP "\-c FILENAME, \-\-config=FILENAME" +Load config file (default: ~/.gnunet/gnunet.conf) +.B +.IP "\-h, \-\-help" +Print help page +.B +.IP "\-n, \-\-numeric" +Disable resolution of IPs to hostnames +.B +.IP "\-q, \-\-quiet" +Do not print anything but the peer identities +.B +.IP "\-s, \-\-self" +Print only our own identity (together with "\-q", this is the exact line that other peers would have to put in to their friends file in order to consider this peer one of their friends in F2F mode). +.B +.IP "\-v, \-\-version" +Print the version number +.B +.IP "\-L LOGLEVEL, \-\-loglelvel=LOGLEVEL" +Set the loglevel + + +.SH BUGS +Report bugs by using mantis or by sending electronic mail to + +.SH SEE ALSO +gnunet.conf(5) diff --git a/doc/man/gnunet-pseudonym.1 b/doc/man/gnunet-pseudonym.1 new file mode 100644 index 0000000..1e6de87 --- /dev/null +++ b/doc/man/gnunet-pseudonym.1 @@ -0,0 +1,77 @@ +.TH GNUNET-PSEUDONYM "1" "25 Feb 2012" "GNUnet" +.SH NAME +gnunet\-pseudonym \- create, delete or list pseudonyms +.SH SYNOPSIS +.B gnunet\-pseudonym +[options] +.SH DESCRIPTION +.PP +gnunet\-pseudonym is a tool for managing pseudonyms and namespaces. A pseudonym is the persona that controls a namespace. As such, it is identical to a public\-private RSA key pair. A namespace is a collection of files that have been signed by the corresponding private RSA key. A namespace is typically associated with a nickname and other metadata. + +Namespaces are an important tool for providing assurances about content integrity and authenticity in GNUnet. Since all of the content in the namespace must have been provided by the same entity, users can form an opinion about that entity and learn to search (or avoid) certain namespaces. + +gnunet\-pseudonym can be used to list all of the pseudonyms that were created locally, to create new pseudonyms, to delete existing pseudonyms (the namespace will continue to exist, but it will be impossible to add additional data to it) and to list all of the namespaces (with their meta-data) known to the local user. By default, gnunet\-pseudonym lists all pseudonyms that were discovered so far. + +Creating a new pseudonym requires using the \-C option together with a nickname that is to be used for the namespace. Nicknames must be unique for each user, global uniqueness is desirable but not necessary. If two namespaces in GNUnet use the same nickname all GNUnet tools will display the nickname together with a number which ensures that the name becomes locally unique to avoid ambiguity. Additional options can be passed together with the \-C option to provide additional meta\-data that describes the namespace. Possible meta\-data includes the 'realname' of the person controlling the namespace, a description, the mime\-type for content in the namespace (useful if the namespace is dedicated to some specific type of content) and contact information. One important piece of meta\-data that can be specified is the identifier of a document root, that is the name of a file in the namespace that is a portal to the rest of the content. This is useful to help users find this root in the absence of conventions. Note that all of this meta\-data is optional and should never be trusted blindly. + +As mentioned before, by default, gnunet\-pseudonym simply lists the meta\-data available for other namespaces. Namespaces can be discovered whenever the peer obtains the namespace advertisement. Namespace advertisements can be found using ordinary keyword\-based searches (by default gnunet\-pseudonym publishes the namespace advertisement under the keyword 'namespace', but the \-k option can be used to specify other keywords) and under the 'empty' identifier of the respective namespace (using a namespace\-search if the namespace ID is already known). + +For more details about GNUnet namespaces and content encoding please read the 'Encoding for Censorship\-resistant Sharing' (ECRS) paper which can be found on the GNUnet webpage. + +.TP +\fB\-a \fILEVEL\fR, \fB\-\-anonymity=LEVEL\fR +set desired level of sender anonymity. Default is 1. + +.TP +\fB\-C NAME\fR, \fB\-\-create=NAME\fR +Creates a new pseudonym with the given NAME or creates a new advertisement for the pseudonym with the given NAME (if the pseudonym already exists). + +.TP +\fB\-D NAME\fR, \fB\-\-delete=NAME\fR +Delete the pseudonym with the given NAME. + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print help page. + +.TP +\fB\-k KEYWORD\fR, \fB\-\-keyword=KEYWORD\fR +Publish a namespace advertisement under the keyword 'KEYWORD'. Default is 'namespace' (use with \-C). You can specify \-k multiple times. In that case, the namespace will be published under each of those keywords. + +.TP +\fB\-m \fITYPE:VALUE\fR, \fB\-\-meta=\fITYPE:VALUE\fR +For the main file (or directory), set the metadata of the given TYPE to the given VALUE. Note that this will not add the respective VALUE to the set of keywords under which the file can be found. + +.TP +\fB\-o\fR, \fB\-\-only\-local\fR +display names of local namespaces (those that we can extend with content because we created them) + +.TP +\fB\-p \fIPRIORITY\fR, \fB\-\-prio=\fIPRIORITY\fR +Set the priority of the namespace advertisement (default: 365). If the local database is full, GNUnet will discard the content with the lowest ranking. Note that ranks change over time depending on popularity. The default should be high enough to preserve the locally inserted content in favor of content that migrates from other peers. + +.TP +\fB\-q\fR, \fB\-\-quiet\fR +Do not print the list of pseudonyms (only perform create or delete operation). + +.TP +\fB\-r \fILEVEL\fR, \fB\-\-replication=\fILEVEL\fR +Set the desired replication level. If CONTENT_PUSHING is set to YES, GNUnet will push each block (for the file) LEVEL times to other peers before doing nomral "random" replication of all content. This option can be used to push some content out into the network harder. Note that pushing content LEVEL times into the network does not guarantee that there will actually be LEVEL replicas. + +.TP +\fB\-R IDENTIFIER\fR, \fB\-\-root=IDENTIFIER\fR +Specify the identifier for the root of the namespace. Used in the namespace advertisement to tell users that find the namespace advertisement about an entry\-point into the namespace (use with \-C). Advertisements are only created if "\-C" and "\-r" are specified. + +.TP +\fB\-s ID:VALUE\fR, \fB\-\-set-rating=ID:VALUE\fR +Change the rating for the namespace identified by ID by VALUE. For example, "\-s test:-3" decrements the rating of the pseudonym "test" by 3. Note that ratings are purely local. Each user has his own independent rating of namespaces. The rating is merely a way for each user to keep track of his own experience with a given namespace. + +.SH FILES +.TP +~/.gnunet/data/pseudonyms/ +Directory where the pseudonyms are stored + +.SH "REPORTING BUGS" +Report bugs by using Mantis or by sending electronic mail to +.SH "SEE ALSO" +\fBgnunet\-publish\fP(1), \fBgnunet\-search\fP(1) diff --git a/doc/man/gnunet-publish.1 b/doc/man/gnunet-publish.1 new file mode 100644 index 0000000..a189c74 --- /dev/null +++ b/doc/man/gnunet-publish.1 @@ -0,0 +1,174 @@ +.TH GNUNET-PUBLISH "1" "25 Feb 2012" "GNUnet" +.SH NAME +gnunet\-publish \- a command line interface for publishing new content into GNUnet +.SH SYNOPSIS +.B gnunet\-publish +[\fIOPTIONS\fR] FILENAME +.SH DESCRIPTION +.PP +In order to share files with other GNUnet users, the files must first be made available to GNUnet. GNUnet does not automatically share all files from a certain directory. In fact, even files that are downloaded are not automatically shared. +.PP +In order to start sharing files, the files must be added either using gnunet\-publish or a graphical interface such as gnunet\-fs\-gtk. The command line tool gnunet\-publish is more useful if many files are supposed to be added. gnunet\-publish can automatically publish batches of files, recursively publish directories, create directories that can be browsed within GNUnet and publish file lists in a namespace. When run on a directory, gnunet\-publish will always recursively publish all of the files in the directory. +.PP +gnunet\-publish can automatically extract keywords from the files that are shared. Users that want to download files from GNUnet use keywords to search for the appropriate content. You can disable keyword extraction with the \-D option. You can manually add keywords using the \-k option. The keywords are case\-sensitive. +.PP +You can use automatic meta\-data extraction (based on libextractor) or the command\-line option \-m to specify meta-data. For the \-m option you need to use the form keyword\-type:value. For example, use "\-m os:Linux" to specify that the operating system is Linux. Common meta\-data types are "author name", "title" , "mimetype", "filename", "language", "subject" and "keywords". A full list can be obtained from the extract tool using the option \-\-list. The meta\-data is used to help users in searching for files on the network. +.PP +In addition to searching for files by keyword, GNUnet allows organizing files into directories. With directories, the user only needs to find the directory in order to be able to download any of the files listed in the directory. Directories can contain pointers to other directories. +.PP +With gnunet\-publish, it is easy to create new directories simultaneously when adding the files. Simply pass the name of a directory instead of a file. +.PP +Since keywords can be spammed (any user can add any content under any keyword), GNUnet supports namespaces. A namespace is a subset of the searchspace into which only the holder of a certain pseudonym can add content. Any GNUnet user can create any number of pseudonyms using \fBgnunet\-pseudonym\fR. Pseudonyms are stored in the user's GNUnet directory. While pseudonyms are locally identified with an arbitrary string that the user selects when the pseudonym is created, the namespace is globally known only under the hash of the public key of the pseudonym. Since only the owner of the pseudonym can add content to the namespace, it is impossible for other users to pollute the namespace. gnunet\-publish automatically publishes the top\-directory (or the only file if only one file is specified) into the namespace if a pseudonym is specified. +.PP +It is possible to update content in GNUnet if that content was placed and obtained from a particular namespace. Updates are only possible for content in namespaces since this is the only way to assure that a malicious party can not supply counterfeited updates. Note that an update with GNUnet does not make the old content unavailable, GNUnet merely allows the publisher to point users to more recent versions. You can use the \-N option to specify the future identifier of an update. When using this option, a GNUnet client that finds the current (\-t) identifier will automatically begin a search for the update (\-N) identifier. If you later publish an update under the (\-N) identifier, both results will be given to the user. +.PP +You can use automatic meta\-data extraction (based on libextractor) or the command\-line option \-m to specify meta-data. For the \-m option you need to use the form keyword\-type:value. For example, use "\-m os:Linux" to specify that the operating system is Linux. Common meta\-data types are "author", "title" , "mimetype", "filename", "language", "subject" and "keywords". A full list can be obtained from the extract tool using the option \-\-list. The meta\-data is used to help users in searching for files on the network. The keywords are case\-sensitive. +.PP +GNUnet supports two styles of publishing files on the network. Publishing a file means that a copy of the file is made in the local (!) database of the node. Indexing a file means that an index is added to the local (!) database with symbolic links to the file itself. The links will use the SHA-512 hash of the entire file as the filename. Indexing is generally significantly more efficient and the default choice. However, indexing only works if the indexed file can be read (using the same absolute path) by gnunet-service-fs. If this is not the case, indexing will fail (and gnunet\-publish will automatically revert to publishing instead). Regardless of which method is used to publish the file, the file will be slowly (depending on how often it is requested and on how much bandwidth is available) dispersed into the network. If you publish or index a file and then leave the network, it will almost always NOT be available anymore. + +\fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR +Use alternate config file (if this option is not specified, the default is ~/.gnunet/gnunet.conf). + +.TP +\fB\-D\fR, \fB\-\-disable\-extractor\fR +Disable use of GNU libextractor for finding additional keywords and metadata. + +.TP +\fB\-e\fR, \fB\-\-extract\fR +Print the list of keywords that will be used for each file given the current options. Do not perform any indexing or publishing. + +.TP +\fB\-h\fR, \fB\-\-help\fR +Print a brief help page with all the options. + +.TP +\fB\-k \fIKEYWORD\fR, \fB\-\-key=KEYWORD\fR +additional key to index the content with (to add multiple keys, specify multiple times). Each additional key is case\-sensitive. Can be specified multiple times. The keyword is only applied to the top\-level file or directory. + +.TP +\fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=\fILOGLEVEL\fR +Change the loglevel. Possible values for LOGLEVEL are +ERROR, WARNING, INFO and DEBUG. + +.TP +\fB\-m \fITYPE:VALUE\fR, \fB\-\-meta=\fITYPE:VALUE\fR +For the main file (or directory), set the metadata of the given TYPE to the given VALUE. Note that this will not add the respective VALUE to the set of keywords under which the file can be found. + +.TP +\fB\-n\fR, \fB\-\-noindex\fR +Executive summary: You probably don't need it. + +Do not index, full publishing. Note that directories, RBlocks, SBlocks and IBlocks are always published (even without this option). With this option, every block of the actual files is stored in encrypted form in the block database of the local peer. While this adds security if the local node is compromised (the adversary snags your machine), it is significantly less efficient compared to on\-demand encryption and is definitely not recommended for large files. + +.TP +\fB\-N \fIID\fR, \fB\-\-next=\fIID\fR +Specifies the next ID of a future version of the SBlock. This option is only valid together with the \-P option. This option can be used to specify what the identifier of an updated version will look like. Note that specifying \-i and \-N without \-t is not allowed. + +.TP +\fB\-p \fIPRIORITY\fR, \fB\-\-prio=\fIPRIORITY\fR +Executive summary: You probably don't need it. + +Set the priority of the published content (default: 365). If the local database is full, GNUnet will discard the content with the lowest ranking. Note that ranks change over time depending on popularity. The default should be high enough to preserve the locally published content in favor of content that migrates from other peers. + +.TP +\fB\-P \fINAME\fR, \fB\-\-pseudonym=\fINAME\fR +For the top\-level directory or file, create an SBlock that places the file into the namespace specified by the pseudonym NAME. + +.TP +\fB\-r \fILEVEL\fR, \fB\-\-replication=\fILEVEL\fR +Set the desired replication level. If CONTENT_PUSHING is set to YES, GNUnet will push each block (for the file) LEVEL times to other peers before doing normal "random" replication of all content. This option can be used to push some content out into the network harder. Note that pushing content LEVEL times into the network does not guarantee that there will actually be LEVEL replicas. + +.TP +\fB\-s\fR, \fB\-\-simulate-only\fR +When this option is used, gnunet\-publish will not actually publish the file but just simulate what would be done. This can be used to compute the GNUnet URI for a file without actually sharing it. + +.TP +\fB\-t \fIID\fR, \fB\-\-this=\fIID\fR +Specifies the ID of the SBlock. This option is only valid together with the\ \-s option. + +.TP +\fB\-u \fIURI\fR, \fB\-\-uri=\fIURI\fR +This option can be used to specify the URI of a file instead of a filename (this is the only case where the otherwise mandatory filename argument must be omitted). Instead of publishing a file or directory and using the corresponding URI, gnunet\-publish will use this URI and perform the selected namespace or keyword operations. This can be used to add additional keywords to a file that has already been shared or to add files to a namespace for which the URI is known but the content is not locally available. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version number. + +.TP +\fB\-V\fR, \fB\-\-verbose\fR +Be verbose. Using this option causes gnunet\-publish to print progress information and at the end the file identification that can be used to download the file from GNUnet. + + +.SH SETTING ANONYMITY LEVEL + +The \fB\-a\fR option can be used to specify additional anonymity constraints. If set to 0, GNUnet will publish the file non-anonymously and in fact sign the advertisement for the file using your peer's private key. This will allow other users to download the file as fast as possible, including using non-anonymous methods (DHT, direct transfer). If you set it to 1 (default), you use the standard anonymous routing algorithm (which does not explicitly leak your identity). However, a powerful adversary may still be able to perform traffic analysis (statistics) to over time infer data about your identity. You can gain better privacy by specifying a higher level of anonymity, which increases the amount of cover traffic your own traffic will get, at the expense of performance. Note that regardless of the anonymity level you choose, peers that cache content in the network always use anonymity level 1. + +The definition of the ANONYMITY LEVEL is the following. 0 means no anonymity is required. Otherwise a value of 'v' means that 1 out of v bytes of "anonymous" traffic can be from the local user, leaving 'v-1' bytes of cover traffic per byte on the wire. Thus, if GNUnet routes n bytes of messages from foreign peers (using anonymous routing), it may originate n/(v-1) bytes of data in the same time\-period. The time\-period is twice the average delay that GNUnet defers forwarded queries. + +The default is 1 and this should be fine for most users. Also notice that if you choose very large values, you may end up having no throughput at all, especially if many of your fellow GNUnet\-peers all do the same. + + +.SH EXAMPLES +.PP + +\fBBasic examples\fR + +Index a file COPYING: + + # gnunet\-publish COPYING + +Publish a file COPYING: + + # gnunet\-publish \-n COPYING + +Index a file COPYING with the keywords \fBgpl\fR and \fBtest\fR: + + # gnunet\-publish \-k gpl \-k test COPYING + +Index a file COPYING with description "GNU License", mime-type "text/plain" and keywords \fBgpl\fR and \fBtest\fR: + + # gnunet\-publish \-m "description:GNU License" \-k gpl \-k test -m "mimetype:text/plain" COPYING + +\fBUsing directories\fR + +Index the files COPYING and AUTHORS with keyword \fBtest\fR and build a directory containing the two files. Make the directory itself available under keyword \fBgnu\fR and disable keyword extraction using libextractor: + + # mkdir gnu + # mv COPYING AUTHORS gnu/ + # gnunet\-publish \-K test \-k gnu \-D gnu/ + +Neatly publish an image gallery in \fBkittendir/\fR and its subdirs with keyword \fBkittens\fR for the directory but no keywords for the individual files or subdirs (\-n). Force description for all files: + + # gnunet\-publish \-n \-m "description:Kitten collection" \-k kittens kittendir/ + +\fBSecure publishing with namespaces\fR + +Publish file COPYING with pseudonym RIAA-2 (\-P) and with identifier \fBgpl\fR (\-t) and no updates: + + # gnunet\-publish \-P RIAA-2 \-t gpl COPYING + +Recursively index /home/ogg and build a matching directory structure. Publish the top\-level directory into the namespace under the pseudonym RIAA-2 (\-P) under identifier 'MUSIC' (\-t) and promise to provide an update with identifier 'VIDEOS' (\-N): + + # gnunet\-publish \-P RIAA-2 \-t MUSIC \-N VIDEOS /home/ogg + +Recursively publish (\-n) /var/lib/mysql and build a matching directory structure, but disable the use of libextractor to extract keywords (\-n). Print the file identifiers (\-V) that can be used to retrieve the files. This will store a copy of the MySQL database in GNUnet but without adding any keywords to search for it. Thus only people that have been told the secret file identifiers printed with the \-V option can retrieve the (secret?) files: + + # gnunet\-publish \-nV /var/lib/mysql + +Create a namespace entry 'root' in namespace MPAA-1 and announce that the next update will be called 'next': + + # gnunet\-publish \-P MPAA-1 -t root \-N next noise.mp3 + +Update the previous entry, do not allow any future updates: + + # gnunet\-publish \-P MPAA-1 \-t next noise_updated.mp3 + + +.SH FILES +.TP +~/.gnunet/gnunet.conf +GNUnet configuration file +.SH "REPORTING BUGS" +Report bugs to or by sending electronic mail to +.SH "SEE ALSO" +\fBgnunet\-fs\-gtk\fP(1), \fBgnunet\-pseudonym\fP(1), \fBgnunet\-search\fP(1), \fBgnunet\-download\fP(1), \fBgnunet.conf\fP(5), \fBextract\fP(1) diff --git a/doc/man/gnunet-search.1 b/doc/man/gnunet-search.1 new file mode 100644 index 0000000..ccca75f --- /dev/null +++ b/doc/man/gnunet-search.1 @@ -0,0 +1,93 @@ +.TH GNUNET-SEARCH "1" "25 Feb 2012" "GNUnet" +.SH NAME +gnunet\-search \- a command line interface to search for content on GNUnet +.SH SYNOPSIS +.B gnunet\-search +[\fIOPTIONS\fR] [+]\fIKEYWORD\fR [[+]\fIKEYWORD\fR]* + +.B gnunet\-search +[\fIOPTIONS\fR] [+]\fIURI\fR +.SH DESCRIPTION +.PP +Search for content on GNUnet. The keywords are case\-sensitive. gnunet\-search can be used both for a search in the global namespace as well as for searching a private subspace. +.TP +\fB\-a \fILEVEL\fR, \fB\-\-anonymity=\fILEVEL\fR + +The \fB\-a\fR option can be used to specify additional anonymity constraints. If set to 0, GNUnet will try to download the file as fast as possible, including using non-anonymous methods. If you set it to 1 (default), you use the standard anonymous routing algorithm (which does not explicitly leak your identity). However, a powerful adversary may still be able to perform traffic analysis (statistics) to over time infer data about your identity. You can gain better privacy by specifying a higher level of anonymity, which increases the amount of cover traffic your own traffic will get, at the expense of performance. Note that your download performance is not only determined by your own anonymity level, but also by the anonymity level of the peers publishing the file. So even if you download with anonymity level 0, the peers publishing the data might be sharing with a higher anonymity level, which in this case will determine performance. Also, peers that cache content in the network always use anonymity level 1. + +This option can be used to limit requests further than that. In particular, you can require GNUnet to receive certain amounts of traffic from other peers before sending your queries. This way, you can gain very high levels of anonymity \- at the expense of much more traffic and much higher latency. So set it only if you really believe you need it. + +The definition of ANONYMITY\-RECEIVE is the following. 0 means no anonymity is required. Otherwise a value of 'v' means that 1 out of v bytes of "anonymous" traffic can be from the local user, leaving 'v-1' bytes of cover traffic per byte on the wire. Thus, if GNUnet routes n bytes of messages from foreign peers (using anonymous routing), it may originate n/(v-1) bytes of queries in the same time\-period. The time\-period is twice the average delay that GNUnet defers forwarded queries. + +The default is 1 and this should be fine for most users. Also notice that if you choose very large values, you may end up having no throughput at all, especially if many of your fellow GNUnet\-peers all do the same. + +.TP +\fB\-c \fIFILENAME\fR, \fB\-\-config=\fIFILENAME\fR +use config file (defaults: ~/.gnunet/gnunet.conf) + +.TP +\fB\-h\fR, \fB\-\-help\fR +print help page + +.TP +\fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=\fILOGLEVEL\fR +Change the loglevel. Possible values for LOGLEVEL are +ERROR, WARNING, INFO and DEBUG. + +.TP +\fB\-o \fIFILENAME\fR, \fB\-\-output=\fIFILENAME\fR +Writes a GNUnet directory containing all of the search results to FILENAME. + +.TP +\fB\-n\fR, \fB\-\-no-network\fR +Only search locally, do not forward requests to other peers. + +.TP +\fB\-N \fIVALUE\fR, \fB\-\-results=\fIVALUE\fR +automatically terminate the search after receiving VALUE results. + +.TP +\fB\-t \fIVALUE\fR, \fB\-\-timeout=\fIVALUE\fR +Automatically timeout search after VALUE ms. Otherwise the search runs until gnunet\-search is aborted with CTRL\-C. + +.TP +\fB\-v\fR, \fB\-\-version\fR +print the version number + +.TP +\fB\-V\fR, \fB\-\-verbose\fR +print meta data from search results as well +.SH NOTES + +You can run gnunet\-search with an URI instead of a keyword. The URI can have the format for a namespace search or for a keyword search. For a namespace search, the format is gnunet://fs/sks/NAMESPACE/IDENTIFIER. For a keyword search, use gnunet://fs/ksk/KEYWORD[+KEYWORD]*. If the format does not correspond to a GNUnet URI, GNUnet will automatically assume that keywords are supplied directly. + +If multiple keywords are passed, gnunet-search will look for content matching any of the keywords. The prefix "+" makes a keyword mandatory. + +# gnunet\-search "Das Kapital" + +searches for content matching the keyword "Das Kapital". Whereas + +# gnunet\-search +Das +Kapital + +Searches for content matching both mandatory keywords "Das" and "Kapital". + +Search results are printed by gnunet\-search like this: +.P +.ad l + gnunet\-download \-o "COPYING" gnunet://fs/chk/HASH1.HASH2.SIZE + + Description: The GNU Public License + + Mime-type: text/plain +.ad b + +The first line contains the command to run to download the file. The suggested filename in the example is COPYING. The GNUnet URI consists of the key and query hash of the file and finally the size of the file. After the command to download the file GNUnet will print meta\-data about the file as advertised in the search result, here "The GNU Public License" and the mime\-type (see the options for gnunet\-publish on how to supply meta-data by hand). + +.SH FILES +.TP +~/.gnunet/gnunet.conf +GNUnet configuration file; specifies the default value for the timeout +.SH "REPORTING BUGS" +Report bugs to or by sending electronic mail to +.SH "SEE ALSO" +\fBgnunet\-fs\-gtk\fP(1), \fBgnunet\-publish\fP(1), \fBgnunet\-download\fP(1), \fBgnunet\-pseudonym\fP(1), \fBgnunet.conf\fP(5), diff --git a/doc/man/gnunet-statistics.1 b/doc/man/gnunet-statistics.1 new file mode 100644 index 0000000..e6c744f --- /dev/null +++ b/doc/man/gnunet-statistics.1 @@ -0,0 +1,44 @@ +.TH GNUNET\-STATISTICS 1 "Jan 4, 2012" "GNUnet" + +.SH NAME +gnunet\-statistics \- Display statistics about your GNUnet system + +.SH SYNOPSIS +.B gnunet\-statistics +.RI [ options ] +.RI [ VALUE ] +.br + +.SH DESCRIPTION +\fBgnunet\-statistics\fP is used to display detailed information about various aspect of GNUnet's operation. This tool only works if the "statistics" service is available. +gnunet\-statistics can be used to set a value by giving the options \-n, \-s and also a VALUE. + +.SH OPTIONS +.B +.IP "\-c FILENAME, \-\-config=FILENAME" +Use the configuration file FILENAME. +.B +.IP "\-h, \-\-help" +Print short help on options. +.B +.IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL" +Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR. +.B +.IP "\-n NAME, \-\-name=NAME" +Each statistic has a name that is unique with in its subsystem. With this option, the output can be restricted to statistics that have a particular name. +.B +.IP "\-p, \-\-persistent" +When setting a value, make the value persistent. If the value used to be persistent and this flag is not given, it will be marked as non\-persistent. +.B +.IP "\-s SUBSYSTEM, \-\-subsystem=SUBSYSTEM" +Statistics are kept for various subsystems. With this option, the output can be restricted to a particular subsystem only. +.B +.IP "\-v, \-\-version" +Print GNUnet version number. + + +.SH BUGS +Report bugs by using Mantis or by sending electronic mail to + +.SH SEE ALSO +gnunet\-service\-statistics(1) diff --git a/doc/man/gnunet-transport.1 b/doc/man/gnunet-transport.1 new file mode 100644 index 0000000..cc1a022 --- /dev/null +++ b/doc/man/gnunet-transport.1 @@ -0,0 +1,53 @@ +.TH gnunet\-transport "1" "26 Oct 2011" "GNUnet" +.SH NAME +gnunet\-transport \- measure and control the transport subsystem + +.SH SYNOPSIS +.B gnunet\-transport +[\fIOPTIONS\fR] +.SH DESCRIPTION +.PP + +gnunet\-transport is a tool to access various functions of GNUnet's transport subsystem from the command\-line. Most of these are not expected to be useful for end-users. gnunet\-transport can be used to evaluate the performance of the transports, force a peer to connect to another peer (if possible). Other functions should be added in the near future. + +.TP +\fB\-b\fR, \fB\-\-benchmark\fR +measure how fast we are receiving data (from all connections). On exit, the data rate will be reported. Runs until aborted with CTRL-C. +.TP +\fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR +configuration file to use +.TP +\fB\-C \fIPEER\fR, \fB\-\-connect=PEER\fR +peer to connect to (and to use for sending if used in conjunction with \-s) +.TP +\fB\-h\fR, \fB\-\-help\fR +print help page +.TP +\fB\-i\fR, \fB\-\-information\fR +print information about our current connections (once) +.TP +\fB\-m\fR, \fB\-\-monitor\fR +print information about our current connections (continuously) +.TP +\fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR +Change the loglevel. Possible values for LOGLEVEL are ERROR, WARNING, INFO and DEBUG. +.TP +\fB\-s\fR, \fB\-\-send\fR +transmit (dummy) traffic as quickly as possible to the peer specified with the \-C option. The rate will still be limited by the quota(s) determined by the peers (ATS subsystem). Will run until CTRL\-C is pressed or until the connection to the other peer is disrupted. +.TP +\fB\-t\fR, \fB\-\-test\fR +test transport configuration. With this flag, the tool will check if each of the configured transport plugins has a working address. Plugins that do not have a listen port configured will be ignored. The test is performed with the help of an external server (by default running on gnunet.org) which tries to contact the local machine. The test can only work if the local GNUnet peer is not yet running. +.TP +\fB\-v\fR, \fB\-\-version\fR +print the version number +.TP +\fB\-V\fR, \fB\-\-verbose\fR +be verbose + +.SH NOTES + + +.SH "REPORTING BUGS" +Report bugs by using mantis or by sending electronic mail to +.SH "SEE ALSO" +\fBgnunet\-arm\fP(1) diff --git a/doc/man/gnunet-unindex.1 b/doc/man/gnunet-unindex.1 new file mode 100644 index 0000000..9cbb7aa --- /dev/null +++ b/doc/man/gnunet-unindex.1 @@ -0,0 +1,37 @@ +.TH GNUNET-UNINDEX "1" "6 Sep 2009" "GNUnet" +.SH NAME +gnunet\-unindex \- a command line interface for deleting indexed files from GNUnet +.SH SYNOPSIS +.B gnunet\-unindex +[\fIOPTIONS\fR] FILENAME +.SH DESCRIPTION +.PP +gnunet\-unindex is used for deleting indexed files from GNUnet. +.TP +\fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR +use config file (defaults: ~/.gnunet/gnunet.conf) +.TP +\fB\-h\fR, \fB\-\-help\fR +print help page +.TP +\fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR +Change the loglevel. Possible values for LOGLEVEL are NOTHING, +ERROR, WARNING, INFO and DEBUG. + +.TP +\fB\-v\fR, \fB\-\-version\fR +print the version number +.TP +\fB\-V\fR, \fB\-\-verbose\fR +be verbose +.SH NOTES +You can only unindex files that you indexed and that you still have available locally in full. You should use gnunet\-unindex on files that you indexed (not inserted) and that you are going to delete or move locally. +.TP +.SH FILES +.TP +~/.gnunet/gnunet.conf +GNUnet configuration file +.SH "REPORTING BUGS" +Report bugs to or by sending electronic mail to +.SH "SEE ALSO" +\fBgnunet\-fs\-gtk\fP(1), \fBgnunet\-publish\fP(1), \fBgnunet\-search\fP(1), \fBgnunet\-download\fP(1), \fBgnunet.conf\fP(5) diff --git a/doc/man/gnunet-vpn.1 b/doc/man/gnunet-vpn.1 new file mode 100644 index 0000000..ad5b9db --- /dev/null +++ b/doc/man/gnunet-vpn.1 @@ -0,0 +1,65 @@ +.TH GNUNET\-VPN 1 "25 Feb 2012" "GNUnet" + +.SH NAME +gnunet\-vpn \- manually setup a GNUnet VPN tunnel + +.SH SYNOPSIS +.B gnunet\-vpn +.RI [ options ] +.br + +.SH DESCRIPTION +\fBgnunet\-vpn\fP can be used to manually setup a VPN tunnel via the GNUnet network. There are two main types of tunnels. Tunnels to an exit node which routes the traffic to the global Internet, and tunnels to a node that runs a service only within GNUnet. Depending on the type of tunnel, gnunet\-vpn takes different options. The "\-i" option is required for tunnels to an exit node, whereas the "\-p" and "\-s" options in conjunction with either "\-u" or "\-t" are required for tunnels to services. For exit tunnels, both UDP and TCP traffic will be redirected. For service tunnels, either UDP ("\-u") or TCP ("\-t") traffic will be redirected. + +The tool will display the IP address for this end of the tunnel. The address can be displayed as soon as it has been allocated, or only after ("\-a") the tunnel has been created. + +.SH OPTIONS +.B +.IP "\-4, \-\-ipv4" +Desired IP address on this end of the tunnel should be an IPv4 address. +.B +.IP "\-6, \-\-ipv6" +Desired IP address on this end of the tunnel should be an IPv6 address. +.B +.IP "\-a, \-\-after\-connect" +Display IP address only after the tunnel is fully connected. +.B +.IP "\-c FILENAME, \-\-config=FILENAME" +Use the configuration file FILENAME. +.B +.IP "\-d SEC, \-\-duration SEC" +The mapping should be established for SEC seconds. Default is 5 minutes. +.B +.IP "\-h, \-\-help" +Print short help on options. +.B +.IP "\-i IP, \-\-ip IP" +Tunnel should be to an exit node and connect to the given IPv4 or IPv6 IP address. Note that you can specify an IPv6 address as the target here, even in combination with "\-4" (4to6) and similarly you can specify an IPv4 address in combination with "\-6" (6to4). +.B +.IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL" +Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR. +.B +.IP "\-p PEERID, \-\-peer=PEERID" +Name of the peer offering the service to connect to. Cannot be used in conjunction with "\-i", requires "\-s". +.B +.IP "\-s NAME, \-\-service=NAME" +Name of the service running on the target peer. Cannot be used in conjunction with "\-i", requires "\-p". +.B +.IP "\-t, \-\-tcp" +Service runs TCP. Either "\-t" or "\-u" must be specified when using "\-s". +.B +.IP "\-u, \-\-udp" +Service runs UDP. Either "\-t" or "\-u" must be specified when using "\-s". +.B +.IP "\-V, \-\-verbose" +Be verbose. +.B +.IP "\-v, \-\-version" +Print GNUnet version number. + + +.SH BUGS +Report bugs by using Mantis or by sending electronic mail to + +.SH SEE ALSO +gnunet\-setup(1) diff --git a/gnunet_config.h b/gnunet_config.h new file mode 100644 index 0000000..3d50b1a --- /dev/null +++ b/gnunet_config.h @@ -0,0 +1,802 @@ +/* gnunet_config.h. Generated from gnunet_config.h.in by configure. */ +/* gnunet_config.h.in. Generated from configure.ac by autoheader. */ + +#define _GNU_SOURCE 1 + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* #undef CLOSEDIR_VOID */ + +/* This is a Cygwin system */ +/* #undef CYGWIN */ + +/* This is an Apple Darwin system */ +/* #undef DARWIN */ + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#define ENABLE_NLS 1 + +/* enable workarounds used on Windows (only useful for test cases) */ +#define ENABLE_WINDOWS_WORKAROUNDS 0 + +/* Build a Mac OS X Framework */ +/* #undef FRAMEWORK_BUILD */ + +/* This is a FreeBSD system */ +/* #undef FREEBSD */ + +/* Define to cull all logging calls */ +/* #undef GNUNET_CULL_LOGGING */ + +/* This should be the default choice for the name of the first network + interface */ +#define GNUNET_DEFAULT_INTERFACE "eth0" + +/* 1 if extra logging is enabled, 2 for very verbose extra logging, 0 + otherwise */ +#define GNUNET_EXTRA_LOGGING GNUNET_YES + +/* Define to 1 if you have the `argz_add' function. */ +#define HAVE_ARGZ_ADD 1 + +/* Define to 1 if you have the `argz_append' function. */ +#define HAVE_ARGZ_APPEND 1 + +/* Define to 1 if you have the `argz_count' function. */ +#define HAVE_ARGZ_COUNT 1 + +/* Define to 1 if you have the `argz_create_sep' function. */ +#define HAVE_ARGZ_CREATE_SEP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARGZ_H 1 + +/* Define to 1 if you have the `argz_insert' function. */ +#define HAVE_ARGZ_INSERT 1 + +/* Define to 1 if you have the `argz_next' function. */ +#define HAVE_ARGZ_NEXT 1 + +/* Define to 1 if you have the `argz_stringify' function. */ +#define HAVE_ARGZ_STRINGIFY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the `atoll' function. */ +#define HAVE_ATOLL 1 + +/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the + CoreFoundation framework. */ +/* #undef HAVE_CFLOCALECOPYCURRENT */ + +/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in + the CoreFoundation framework. */ +/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */ + +/* Define to 1 if your system has a working `chown' function. */ +#define HAVE_CHOWN 1 + +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Define to 1 if you have the `closedir' function. */ +#define HAVE_CLOSEDIR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_CTYPE_H 1 + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +#define HAVE_DCGETTEXT 1 + +/* Define to 1 if you have the declaration of `cygwin_conv_path', and to 0 if + you don't. */ +/* #undef HAVE_DECL_CYGWIN_CONV_PATH */ + +/* Define to 1 if you have the declaration of `gcry_mpi_lshift', and to 0 if + you don't. */ +#define HAVE_DECL_GCRY_MPI_LSHIFT 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the GNU dld library. */ +/* #undef HAVE_DLD */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLD_H */ + +/* Define to 1 if you have the `dlerror' function. */ +#define HAVE_DLERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DL_H */ + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define if you have the _dyld_func_lookup function. */ +/* #undef HAVE_DYLD */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ENDIAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if the system has the type `error_t'. */ +#define HAVE_ERROR_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_EXTRACTOR_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdatasync' function. */ +#define HAVE_FDATASYNC 1 + +/* Define to 1 if you have the `floor' function. */ +/* #undef HAVE_FLOOR */ + +/* Define to 1 if you have the `fork' function. */ +/* #undef HAVE_FORK */ + +/* Define to 1 if you have the `freeifaddrs' function. */ +#define HAVE_FREEIFADDRS 1 + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `getaddrinfo' function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `gethostbyaddr' function. */ +#define HAVE_GETHOSTBYADDR 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the `gethostbyname2' function. */ +#define HAVE_GETHOSTBYNAME2 1 + +/* Define to 1 if you have the `gethostname' function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have the `getifaddrs' function. */ +#define HAVE_GETIFADDRS 1 + +/* getloadavg supported */ +#define HAVE_GETLOADAVG 1 + +/* Define to 1 if you have the `getnameinfo' function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the `getpeereid' function. */ +/* #undef HAVE_GETPEEREID */ + +/* Define to 1 if you have the `getpeerucred' function. */ +/* #undef HAVE_GETPEERUCRED */ + +/* Define to 1 if you have the `getrusage' function. */ +#define HAVE_GETRUSAGE 1 + +/* Define if the GNU gettext() function is already present or preinstalled. */ +#define HAVE_GETTEXT 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_GLPK_H */ + +/* Define to 1 if `presolve' is a member of `glp_iocp'. */ +/* #undef HAVE_GLP_IOCP_PRESOLVE */ + +/* Define to 1 if you have the `gmtime' function. */ +#define HAVE_GMTIME 1 + +/* Define to 1 if you have the `gmtime_r' function. */ +#define HAVE_GMTIME_R 1 + +/* Define if you have the iconv() function. */ +#define HAVE_ICONV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IFADDRS_H 1 + +/* Define to 1 if you have the `inet_ntoa' function. */ +#define HAVE_INET_NTOA 1 + +/* Define to 1 if you have the `initgroups' function. */ +#define HAVE_INITGROUPS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_KSTAT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_KVM_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LANGINFO_H 1 + +/* Define to 1 if you have a functional curl library. */ +#define HAVE_LIBCURL 1 + +/* Define if you have the libdl library or equivalent. */ +#define HAVE_LIBDL 1 + +/* Define if libdlloader will be built on this platform */ +#define HAVE_LIBDLLOADER 1 + +/* Have GLPK */ +/* #undef HAVE_LIBGLPK */ + +/* Define to 1 if you have the `intl' library (-lintl). */ +/* #undef HAVE_LIBINTL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIBINTL_H 1 + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the `kvm' library (-lkvm). */ +/* #undef HAVE_LIBKVM */ + +/* Define to 1 if you have the `m' library (-lm). */ +/* #undef HAVE_LIBM */ + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +/* #undef HAVE_LIBRESOLV */ + +/* Define to 1 if you have the `rt' library (-lrt). */ +/* #undef HAVE_LIBRT */ + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define if you have the unistring library. */ +#define HAVE_LIBUNISTRING 1 + +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#define HAVE_LOCALTIME_R 1 + +/* Define this if a modern libltdl is already installed */ +#define HAVE_LTDL 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_O_DYLD_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MATH_H 1 + +/* Define to 1 if you have the `memmove' function. */ +/* #undef HAVE_MEMMOVE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +/* #undef HAVE_MEMSET */ + +/* We have libmicrohttpd */ +#define HAVE_MHD 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MICROHTTPD_H 1 + +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have the `mkfifo' function. */ +#define HAVE_MKFIFO 1 + +/* Define to 1 if you have the `mktime' function. */ +#define HAVE_MKTIME 1 + +/* Define to 1 if you have the `mmap' function. */ +#define HAVE_MMAP 1 + +/* Define to 1 if you have the `mremap' function. */ +#define HAVE_MREMAP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MYSQL_MYSQL_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_SYSTM_H 1 + +/* Define to 1 if you have the `nl_langinfo' function. */ +#define HAVE_NL_LANGINFO 1 + +/* Define to 1 if the system has the type `off_t'. */ +#define HAVE_OFF_T 1 + +/* Define to 1 if you have the `opendir' function. */ +#define HAVE_OPENDIR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_POSTGRESQL_LIBPQ_FE_H 1 + +/* Define if libtool can extract symbol lists from object files. */ +#define HAVE_PRELOADED_SYMBOLS 1 + +/* Define to 1 if you have the `putenv' function. */ +#define HAVE_PUTENV 1 + +/* Define to 1 if you have the `rand' function. */ +#define HAVE_RAND 1 + +/* Define to 1 if you have the `readdir' function. */ +#define HAVE_READDIR 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if you have the `rmdir' function. */ +#define HAVE_RMDIR 1 + +/* Define to 1 if you have the `sbrk' function. */ +#define HAVE_SBRK 1 + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `setresuid' function. */ +#define HAVE_SETRESUID 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#define HAVE_SETRLIMIT 1 + +/* Define if you have the shl_load function. */ +/* #undef HAVE_SHL_LOAD */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if the system has the type `sigset_t'. */ +#define HAVE_SIGSET_T 1 + +/* Define to 1 if the system has the type `size_t'. */ +#define HAVE_SIZE_T 1 + +/* Do we have sockaddr_in.sin_len? */ +/* #undef HAVE_SOCKADDR_IN_SIN_LEN */ + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SOCKLIB_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SQLITE3_H 1 + +/* Define to 1 if you have the `stat64' function. */ +#define HAVE_STAT64 1 + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if stdbool.h conforms to C99. */ +/* #undef HAVE_STDBOOL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +/* #undef HAVE_STRCASECMP */ + +/* Define to 1 if you have the `strchr' function. */ +/* #undef HAVE_STRCHR */ + +/* Define to 1 if you have the `strdup' function. */ +/* #undef HAVE_STRDUP */ + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strftime' function. */ +/* #undef HAVE_STRFTIME */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcat' function. */ +/* #undef HAVE_STRLCAT */ + +/* Define to 1 if you have the `strlcpy' function. */ +/* #undef HAVE_STRLCPY */ + +/* Define to 1 if you have the `strncasecmp' function. */ +/* #undef HAVE_STRNCASECMP */ + +/* Define to 1 if you have the `strndup' function. */ +/* #undef HAVE_STRNDUP */ + +/* Define to 1 if you have the `strrchr' function. */ +/* #undef HAVE_STRRCHR */ + +/* Define to 1 if you have the `strstr' function. */ +/* #undef HAVE_STRSTR */ + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `sysconf' function. */ +#define HAVE_SYSCONF 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_FILE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MSG_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SYSINFO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_VFS_H 1 + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_TERMINOS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UCRED_H */ + +/* We can access-64 bit values that are only 32-bit aligned */ +#define HAVE_UNALIGNED_64_ACCESS 0 + +/* Define to 1 if you have the `uname' function. */ +#define HAVE_UNAME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if you have the `vprintf' function. */ +/* #undef HAVE_VPRINTF */ + +/* This value is set to 1 to indicate that the system argz facility works */ +#define HAVE_WORKING_ARGZ 1 + +/* Define to 1 if `fork' works. */ +/* #undef HAVE_WORKING_FORK */ + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK 1 + +/* Define to 1 if the system has the type `_Bool'. */ +#define HAVE__BOOL 1 + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Defined if libcurl supports AsynchDNS */ +/* #undef LIBCURL_FEATURE_ASYNCHDNS */ + +/* Defined if libcurl supports IDN */ +#define LIBCURL_FEATURE_IDN 1 + +/* Defined if libcurl supports IPv6 */ +#define LIBCURL_FEATURE_IPV6 1 + +/* Defined if libcurl supports KRB4 */ +/* #undef LIBCURL_FEATURE_KRB4 */ + +/* Defined if libcurl supports libz */ +#define LIBCURL_FEATURE_LIBZ 1 + +/* Defined if libcurl supports NTLM */ +#define LIBCURL_FEATURE_NTLM 1 + +/* Defined if libcurl supports SSL */ +#define LIBCURL_FEATURE_SSL 1 + +/* Defined if libcurl supports SSPI */ +/* #undef LIBCURL_FEATURE_SSPI */ + +/* Defined if libcurl supports DICT */ +#define LIBCURL_PROTOCOL_DICT 1 + +/* Defined if libcurl supports FILE */ +#define LIBCURL_PROTOCOL_FILE 1 + +/* Defined if libcurl supports FTP */ +#define LIBCURL_PROTOCOL_FTP 1 + +/* Defined if libcurl supports FTPS */ +#define LIBCURL_PROTOCOL_FTPS 1 + +/* Defined if libcurl supports HTTP */ +#define LIBCURL_PROTOCOL_HTTP 1 + +/* Defined if libcurl supports HTTPS */ +#define LIBCURL_PROTOCOL_HTTPS 1 + +/* Defined if libcurl supports IMAP */ +#define LIBCURL_PROTOCOL_IMAP 1 + +/* Defined if libcurl supports LDAP */ +#define LIBCURL_PROTOCOL_LDAP 1 + +/* Defined if libcurl supports POP3 */ +#define LIBCURL_PROTOCOL_POP3 1 + +/* Defined if libcurl supports RTSP */ +#define LIBCURL_PROTOCOL_RTSP 1 + +/* Defined if libcurl supports SMTP */ +#define LIBCURL_PROTOCOL_SMTP 1 + +/* Defined if libcurl supports TELNET */ +#define LIBCURL_PROTOCOL_TELNET 1 + +/* Defined if libcurl supports TFTP */ +#define LIBCURL_PROTOCOL_TFTP 1 + +/* This is a Linux system */ +#define LINUX 1 + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 + +/* Define if the OS needs help to load dependent libraries for dlopen(). */ +/* #undef LTDL_DLOPEN_DEPLIBS */ + +/* Define to the system default library search path. */ +#define LT_DLSEARCH_PATH "/lib:/usr/lib:/usr/local/lib:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu" + +/* The archive extension */ +#define LT_LIBEXT "a" + +/* Define to the extension used for runtime loadable modules, say, ".so". */ +#define LT_MODULE_EXT ".so" + +/* Define to the name of the environment variable that determines the run-time + module search path. */ +#define LT_MODULE_PATH_VAR "LD_LIBRARY_PATH" + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* This is a MinGW system */ +/* #undef MINGW */ + +/* Define if dlsym() requires a leading underscore in symbol names. */ +/* #undef NEED_USCORE */ + +/* This is a NetBSD system */ +/* #undef NETBSD */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* This is an OpenBSD system */ +/* #undef OPENBSD */ + +/* Some strange OS */ +/* #undef OTHEROS */ + +/* Name of package */ +#define PACKAGE "gnunet" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-gnunet@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "gnunet" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "gnunet 0.9.2" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "gnunet" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.9.2" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the type of arg 1 for `select'. */ +#define SELECT_TYPE_ARG1 int + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#define SELECT_TYPE_ARG234 (fd_set *) + +/* Define to the type of arg 5 for `select'. */ +#define SELECT_TYPE_ARG5 (struct timeval *) + +/* This is a Solaris system */ +/* #undef SOLARIS */ + +/* This is a BSD system */ +/* #undef SOMEBSD */ + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 if your declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Version number of package */ +#define VERSION "0.9.2" + +/* This is a Windows system */ +/* #undef WINDOWS */ + +/* Define to 1 if the X Window System is missing or not being used. */ +/* #undef X_DISPLAY_MISSING */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +/* #undef _LARGEFILE_SOURCE */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Need with solaris or errno doesnt work */ +/* #undef _REENTRANT */ + +/* This is a Windows system */ +/* #undef _WIN32 */ + +/* Define so that glibc/gnulib argp.h does not typedef error_t. */ +/* #undef __error_t_defined */ + +/* Define curl_free() as free() if our version of curl lacks curl_free. */ +/* #undef curl_free */ + +/* Define to a type to use for `error_t' if it is not otherwise available. */ +/* #undef error_t */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `int' if does not define. */ +/* #undef mode_t */ + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ diff --git a/gnunet_config.h.in b/gnunet_config.h.in new file mode 100644 index 0000000..f1b691d --- /dev/null +++ b/gnunet_config.h.in @@ -0,0 +1,801 @@ +/* gnunet_config.h.in. Generated from configure.ac by autoheader. */ + +#define _GNU_SOURCE 1 + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +#undef CLOSEDIR_VOID + +/* This is a Cygwin system */ +#undef CYGWIN + +/* This is an Apple Darwin system */ +#undef DARWIN + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#undef ENABLE_NLS + +/* enable workarounds used on Windows (only useful for test cases) */ +#undef ENABLE_WINDOWS_WORKAROUNDS + +/* Build a Mac OS X Framework */ +#undef FRAMEWORK_BUILD + +/* This is a FreeBSD system */ +#undef FREEBSD + +/* Define to cull all logging calls */ +#undef GNUNET_CULL_LOGGING + +/* This should be the default choice for the name of the first network + interface */ +#undef GNUNET_DEFAULT_INTERFACE + +/* 1 if extra logging is enabled, 2 for very verbose extra logging, 0 + otherwise */ +#undef GNUNET_EXTRA_LOGGING + +/* Define to 1 if you have the `argz_add' function. */ +#undef HAVE_ARGZ_ADD + +/* Define to 1 if you have the `argz_append' function. */ +#undef HAVE_ARGZ_APPEND + +/* Define to 1 if you have the `argz_count' function. */ +#undef HAVE_ARGZ_COUNT + +/* Define to 1 if you have the `argz_create_sep' function. */ +#undef HAVE_ARGZ_CREATE_SEP + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARGZ_H + +/* Define to 1 if you have the `argz_insert' function. */ +#undef HAVE_ARGZ_INSERT + +/* Define to 1 if you have the `argz_next' function. */ +#undef HAVE_ARGZ_NEXT + +/* Define to 1 if you have the `argz_stringify' function. */ +#undef HAVE_ARGZ_STRINGIFY + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the `atoll' function. */ +#undef HAVE_ATOLL + +/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the + CoreFoundation framework. */ +#undef HAVE_CFLOCALECOPYCURRENT + +/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in + the CoreFoundation framework. */ +#undef HAVE_CFPREFERENCESCOPYAPPVALUE + +/* Define to 1 if your system has a working `chown' function. */ +#undef HAVE_CHOWN + +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if you have the `closedir' function. */ +#undef HAVE_CLOSEDIR + +/* Define to 1 if you have the header file. */ +#undef HAVE_CTYPE_H + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +#undef HAVE_DCGETTEXT + +/* Define to 1 if you have the declaration of `cygwin_conv_path', and to 0 if + you don't. */ +#undef HAVE_DECL_CYGWIN_CONV_PATH + +/* Define to 1 if you have the declaration of `gcry_mpi_lshift', and to 0 if + you don't. */ +#undef HAVE_DECL_GCRY_MPI_LSHIFT + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_DIRENT_H + +/* Define if you have the GNU dld library. */ +#undef HAVE_DLD + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLD_H + +/* Define to 1 if you have the `dlerror' function. */ +#undef HAVE_DLERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DL_H + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the `dup2' function. */ +#undef HAVE_DUP2 + +/* Define if you have the _dyld_func_lookup function. */ +#undef HAVE_DYLD + +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if the system has the type `error_t'. */ +#undef HAVE_ERROR_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXTRACTOR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fdatasync' function. */ +#undef HAVE_FDATASYNC + +/* Define to 1 if you have the `floor' function. */ +#undef HAVE_FLOOR + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define to 1 if you have the `freeifaddrs' function. */ +#undef HAVE_FREEIFADDRS + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#undef HAVE_FSEEKO + +/* Define to 1 if you have the `ftruncate' function. */ +#undef HAVE_FTRUNCATE + +/* Define to 1 if you have the `getaddrinfo' function. */ +#undef HAVE_GETADDRINFO + +/* Define to 1 if you have the `getcwd' function. */ +#undef HAVE_GETCWD + +/* Define to 1 if you have the `gethostbyaddr' function. */ +#undef HAVE_GETHOSTBYADDR + +/* Define to 1 if you have the `gethostbyname' function. */ +#undef HAVE_GETHOSTBYNAME + +/* Define to 1 if you have the `gethostbyname2' function. */ +#undef HAVE_GETHOSTBYNAME2 + +/* Define to 1 if you have the `gethostname' function. */ +#undef HAVE_GETHOSTNAME + +/* Define to 1 if you have the `getifaddrs' function. */ +#undef HAVE_GETIFADDRS + +/* getloadavg supported */ +#undef HAVE_GETLOADAVG + +/* Define to 1 if you have the `getnameinfo' function. */ +#undef HAVE_GETNAMEINFO + +/* Define to 1 if you have the `getpeereid' function. */ +#undef HAVE_GETPEEREID + +/* Define to 1 if you have the `getpeerucred' function. */ +#undef HAVE_GETPEERUCRED + +/* Define to 1 if you have the `getrusage' function. */ +#undef HAVE_GETRUSAGE + +/* Define if the GNU gettext() function is already present or preinstalled. */ +#undef HAVE_GETTEXT + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the header file. */ +#undef HAVE_GLPK_H + +/* Define to 1 if `presolve' is a member of `glp_iocp'. */ +#undef HAVE_GLP_IOCP_PRESOLVE + +/* Define to 1 if you have the `gmtime' function. */ +#undef HAVE_GMTIME + +/* Define to 1 if you have the `gmtime_r' function. */ +#undef HAVE_GMTIME_R + +/* Define if you have the iconv() function. */ +#undef HAVE_ICONV + +/* Define to 1 if you have the header file. */ +#undef HAVE_IFADDRS_H + +/* Define to 1 if you have the `inet_ntoa' function. */ +#undef HAVE_INET_NTOA + +/* Define to 1 if you have the `initgroups' function. */ +#undef HAVE_INITGROUPS + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_KSTAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_KVM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LANGINFO_H + +/* Define to 1 if you have a functional curl library. */ +#undef HAVE_LIBCURL + +/* Define if you have the libdl library or equivalent. */ +#undef HAVE_LIBDL + +/* Define if libdlloader will be built on this platform */ +#undef HAVE_LIBDLLOADER + +/* Have GLPK */ +#undef HAVE_LIBGLPK + +/* Define to 1 if you have the `intl' library (-lintl). */ +#undef HAVE_LIBINTL + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBINTL_H + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +#undef HAVE_LIBKSTAT + +/* Define to 1 if you have the `kvm' library (-lkvm). */ +#undef HAVE_LIBKVM + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have the `rt' library (-lrt). */ +#undef HAVE_LIBRT + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define if you have the unistring library. */ +#undef HAVE_LIBUNISTRING + +/* Define to 1 if you have the `z' library (-lz). */ +#undef HAVE_LIBZ + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the `localtime_r' function. */ +#undef HAVE_LOCALTIME_R + +/* Define this if a modern libltdl is already installed */ +#undef HAVE_LTDL + +/* Define to 1 if you have the header file. */ +#undef HAVE_MACH_MACH_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MACH_O_DYLD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MATH_H + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* We have libmicrohttpd */ +#undef HAVE_MHD + +/* Define to 1 if you have the header file. */ +#undef HAVE_MICROHTTPD_H + +/* Define to 1 if you have the `mkdir' function. */ +#undef HAVE_MKDIR + +/* Define to 1 if you have the `mkfifo' function. */ +#undef HAVE_MKFIFO + +/* Define to 1 if you have the `mktime' function. */ +#undef HAVE_MKTIME + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the `mremap' function. */ +#undef HAVE_MREMAP + +/* Define to 1 if you have the header file. */ +#undef HAVE_MYSQL_MYSQL_H + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +#undef HAVE_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_SYSTM_H + +/* Define to 1 if you have the `nl_langinfo' function. */ +#undef HAVE_NL_LANGINFO + +/* Define to 1 if the system has the type `off_t'. */ +#undef HAVE_OFF_T + +/* Define to 1 if you have the `opendir' function. */ +#undef HAVE_OPENDIR + +/* Define to 1 if you have the header file. */ +#undef HAVE_POSTGRESQL_LIBPQ_FE_H + +/* Define if libtool can extract symbol lists from object files. */ +#undef HAVE_PRELOADED_SYMBOLS + +/* Define to 1 if you have the `putenv' function. */ +#undef HAVE_PUTENV + +/* Define to 1 if you have the `rand' function. */ +#undef HAVE_RAND + +/* Define to 1 if you have the `readdir' function. */ +#undef HAVE_READDIR + +/* Define to 1 if you have the `realpath' function. */ +#undef HAVE_REALPATH + +/* Define to 1 if you have the `rmdir' function. */ +#undef HAVE_RMDIR + +/* Define to 1 if you have the `sbrk' function. */ +#undef HAVE_SBRK + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `setresuid' function. */ +#undef HAVE_SETRESUID + +/* Define to 1 if you have the `setrlimit' function. */ +#undef HAVE_SETRLIMIT + +/* Define if you have the shl_load function. */ +#undef HAVE_SHL_LOAD + +/* Define to 1 if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define to 1 if the system has the type `sigset_t'. */ +#undef HAVE_SIGSET_T + +/* Define to 1 if the system has the type `size_t'. */ +#undef HAVE_SIZE_T + +/* Do we have sockaddr_in.sin_len? */ +#undef HAVE_SOCKADDR_IN_SIN_LEN + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the header file. */ +#undef HAVE_SOCKLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SQLITE3_H + +/* Define to 1 if you have the `stat64' function. */ +#undef HAVE_STAT64 + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +#undef HAVE_STAT_EMPTY_STRING_BUG + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the `strftime' function. */ +#undef HAVE_STRFTIME + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the `strndup' function. */ +#undef HAVE_STRNDUP + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the `strstr' function. */ +#undef HAVE_STRSTR + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the `sysconf' function. */ +#undef HAVE_SYSCONF + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_DIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MMAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MOUNT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MSG_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STATVFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSINFO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIMEB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_VFS_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMINOS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UCRED_H + +/* We can access-64 bit values that are only 32-bit aligned */ +#undef HAVE_UNALIGNED_64_ACCESS + +/* Define to 1 if you have the `uname' function. */ +#undef HAVE_UNAME + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* This value is set to 1 to indicate that the system argz facility works */ +#undef HAVE_WORKING_ARGZ + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Define as const if the declaration of iconv() needs const. */ +#undef ICONV_CONST + +/* Defined if libcurl supports AsynchDNS */ +#undef LIBCURL_FEATURE_ASYNCHDNS + +/* Defined if libcurl supports IDN */ +#undef LIBCURL_FEATURE_IDN + +/* Defined if libcurl supports IPv6 */ +#undef LIBCURL_FEATURE_IPV6 + +/* Defined if libcurl supports KRB4 */ +#undef LIBCURL_FEATURE_KRB4 + +/* Defined if libcurl supports libz */ +#undef LIBCURL_FEATURE_LIBZ + +/* Defined if libcurl supports NTLM */ +#undef LIBCURL_FEATURE_NTLM + +/* Defined if libcurl supports SSL */ +#undef LIBCURL_FEATURE_SSL + +/* Defined if libcurl supports SSPI */ +#undef LIBCURL_FEATURE_SSPI + +/* Defined if libcurl supports DICT */ +#undef LIBCURL_PROTOCOL_DICT + +/* Defined if libcurl supports FILE */ +#undef LIBCURL_PROTOCOL_FILE + +/* Defined if libcurl supports FTP */ +#undef LIBCURL_PROTOCOL_FTP + +/* Defined if libcurl supports FTPS */ +#undef LIBCURL_PROTOCOL_FTPS + +/* Defined if libcurl supports HTTP */ +#undef LIBCURL_PROTOCOL_HTTP + +/* Defined if libcurl supports HTTPS */ +#undef LIBCURL_PROTOCOL_HTTPS + +/* Defined if libcurl supports IMAP */ +#undef LIBCURL_PROTOCOL_IMAP + +/* Defined if libcurl supports LDAP */ +#undef LIBCURL_PROTOCOL_LDAP + +/* Defined if libcurl supports POP3 */ +#undef LIBCURL_PROTOCOL_POP3 + +/* Defined if libcurl supports RTSP */ +#undef LIBCURL_PROTOCOL_RTSP + +/* Defined if libcurl supports SMTP */ +#undef LIBCURL_PROTOCOL_SMTP + +/* Defined if libcurl supports TELNET */ +#undef LIBCURL_PROTOCOL_TELNET + +/* Defined if libcurl supports TFTP */ +#undef LIBCURL_PROTOCOL_TFTP + +/* This is a Linux system */ +#undef LINUX + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#undef LSTAT_FOLLOWS_SLASHED_SYMLINK + +/* Define if the OS needs help to load dependent libraries for dlopen(). */ +#undef LTDL_DLOPEN_DEPLIBS + +/* Define to the system default library search path. */ +#undef LT_DLSEARCH_PATH + +/* The archive extension */ +#undef LT_LIBEXT + +/* Define to the extension used for runtime loadable modules, say, ".so". */ +#undef LT_MODULE_EXT + +/* Define to the name of the environment variable that determines the run-time + module search path. */ +#undef LT_MODULE_PATH_VAR + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* This is a MinGW system */ +#undef MINGW + +/* Define if dlsym() requires a leading underscore in symbol names. */ +#undef NEED_USCORE + +/* This is a NetBSD system */ +#undef NETBSD + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* This is an OpenBSD system */ +#undef OPENBSD + +/* Some strange OS */ +#undef OTHEROS + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to the type of arg 1 for `select'. */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg 5 for `select'. */ +#undef SELECT_TYPE_ARG5 + +/* This is a Solaris system */ +#undef SOLARIS + +/* This is a BSD system */ +#undef SOMEBSD + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +#undef STAT_MACROS_BROKEN + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define to 1 if your declares `struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* This is a Windows system */ +#undef WINDOWS + +/* Define to 1 if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +#undef _LARGEFILE_SOURCE + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Need with solaris or errno doesnt work */ +#undef _REENTRANT + +/* This is a Windows system */ +#undef _WIN32 + +/* Define so that glibc/gnulib argp.h does not typedef error_t. */ +#undef __error_t_defined + +/* Define curl_free() as free() if our version of curl lacks curl_free. */ +#undef curl_free + +/* Define to a type to use for `error_t' if it is not otherwise available. */ +#undef error_t + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define to `int' if does not define. */ +#undef mode_t + +/* Define to `long int' if does not define. */ +#undef off_t + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..6781b98 --- /dev/null +++ b/install-sh @@ -0,0 +1,520 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2009-04-28.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/ltmain.sh b/ltmain.sh new file mode 100755 index 0000000..d88da2c --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,8413 @@ +# Generated from ltmain.m4sh. + +# ltmain.sh (GNU libtool) 2.2.6b +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print informational messages (default) +# --version print version information +# -h, --help print short or long help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.2.6b Debian-2.2.6b-2 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION="2.2.6b Debian-2.2.6b-2" +TIMESTAMP="" +package_revision=1.3017 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# NLS nuisances: We save the old values to restore during execute mode. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done + +$lt_unset CDPATH + + + + + +: ${CP="cp -f"} +: ${ECHO="echo"} +: ${EGREP="/bin/grep -E"} +: ${FGREP="/bin/grep -F"} +: ${GREP="/bin/grep"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SED="/bin/sed"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +# Generated shell functions inserted here. + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +# In the unlikely event $progname began with a '-', it would play havoc with +# func_echo (imagine progname=-n), so we prepend ./ in that case: +func_dirname_and_basename "$progpath" +progname=$func_basename_result +case $progname in + -*) progname=./$progname ;; +esac + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=: + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname${mode+: }$mode: $*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` + done + my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "X$my_tmpdir" | $Xsed +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "X$1" | $Xsed \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + + + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $SED -n '/^# Usage:/,/# -h/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + $ECHO + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help +# Echo long help message to standard output and exit. +func_help () +{ + $SED -n '/^# Usage:/,/# Report bugs to/ { + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + p + }' < "$progpath" + exit $? +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + func_error "missing argument for $1" + exit_cmd=exit +} + +exit_cmd=: + + + + + +# Check that we have a working $ECHO. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell, and then maybe $ECHO will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# Parse options once, thoroughly. This comes as soon as possible in +# the script to make things like `libtool --version' happen quickly. +{ + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Parse non-mode specific arguments: + while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --config) func_config ;; + + --debug) preserve_args="$preserve_args $opt" + func_echo "enabling shell trace mode" + opt_debug='set -x' + $opt_debug + ;; + + -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break + execute_dlfiles="$execute_dlfiles $1" + shift + ;; + + --dry-run | -n) opt_dry_run=: ;; + --features) func_features ;; + --finish) mode="finish" ;; + + --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break + case $1 in + # Valid mode arguments: + clean) ;; + compile) ;; + execute) ;; + finish) ;; + install) ;; + link) ;; + relink) ;; + uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; + esac + + mode="$1" + shift + ;; + + --preserve-dup-deps) + opt_duplicate_deps=: ;; + + --quiet|--silent) preserve_args="$preserve_args $opt" + opt_silent=: + ;; + + --verbose| -v) preserve_args="$preserve_args $opt" + opt_silent=false + ;; + + --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break + preserve_args="$preserve_args $opt $1" + func_enable_tag "$1" # tagname is set here + shift + ;; + + # Separate optargs to long options: + -dlopen=*|--mode=*|--tag=*) + func_opt_split "$opt" + set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} + shift + ;; + + -\?|-h) func_usage ;; + --help) opt_help=: ;; + --version) func_version ;; + + -*) func_fatal_help "unrecognized option \`$opt'" ;; + + *) nonopt="$opt" + break + ;; + esac + done + + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_duplicate_deps + ;; + esac + + # Having warned about all mis-specified options, bail out if + # anything was wrong. + $exit_cmd $EXIT_FAILURE +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +## ----------- ## +## Main. ## +## ----------- ## + +$opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + test -z "$mode" && func_fatal_error "error: you must specify a MODE." + + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." +} + + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_ltwrapper_scriptname_result="" + if func_ltwrapper_executable_p "$1"; then + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" + fi +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case "$@ " in + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + removelist="$removelist $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + removelist="$removelist $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { +test "$mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$mode'" + ;; + esac + + $ECHO + $ECHO "Try \`$progname --help' for more information about other modes." + + exit $? +} + + # Now that we've collected a possible --mode arg, show help if necessary + $opt_help && func_mode_help + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_quote_for_eval "$file" + args="$args $func_quote_for_eval_result" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + $ECHO "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + $ECHO "X----------------------------------------------------------------------" | $Xsed + $ECHO "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + $ECHO + $ECHO "If you ever happen to want to link against installed libraries" + $ECHO "in a given directory, LIBDIR, you must either use libtool, and" + $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" + $ECHO "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" + $ECHO " during execution" + fi + if test -n "$runpath_var"; then + $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" + $ECHO " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $ECHO + + $ECHO "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" + $ECHO "pages." + ;; + *) + $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + $ECHO "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS +} + +test "$mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $ECHO "X$nonopt" | $GREP shtool >/dev/null; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + install_prog="$install_prog$func_quote_for_eval_result" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + install_prog="$install_prog $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_verbose "extracting global C symbols from \`$progfile'" + $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + $ECHO >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +" + case $host in + *cygwin* | *mingw* | *cegcc* ) + $ECHO >> "$output_objdir/$my_dlsyms" "\ +/* DATA imports from DLLs on WIN32 con't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs. */" + lt_dlsym_const= ;; + *osf5*) + echo >> "$output_objdir/$my_dlsyms" "\ +/* This system does not cope well with relocations in const data */" + lt_dlsym_const= ;; + *) + lt_dlsym_const=const ;; + esac + + $ECHO >> "$output_objdir/$my_dlsyms" "\ +extern $lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +$lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + $ECHO >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) symtab_cflags="$symtab_cflags $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + + +# func_emit_wrapper_part1 [arg=no] +# +# Emit the first part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part1 () +{ + func_emit_wrapper_part1_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part1_arg1=$1 + fi + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + ECHO=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$ECHO works! + : + else + # Restart under the correct shell, and then maybe \$ECHO will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $ECHO "\ + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done +" +} +# end: func_emit_wrapper_part1 + +# func_emit_wrapper_part2 [arg=no] +# +# Emit the second part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part2 () +{ + func_emit_wrapper_part2_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part2_arg1=$1 + fi + + $ECHO "\ + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} +# end: func_emit_wrapper_part2 + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=no + if test -n "$1" ; then + func_emit_wrapper_arg1=$1 + fi + + # split this up so that func_emit_cwrapperexe_src + # can call each part independently. + func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" + func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" +} + + +# func_to_host_path arg +# +# Convert paths to host format when used with build tools. +# Intended for use with "native" mingw (where libtool itself +# is running under the msys shell), or in the following cross- +# build environments: +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# where wine is equipped with the `winepath' executable. +# In the native mingw case, the (msys) shell automatically +# converts paths for any non-msys applications it launches, +# but that facility isn't available from inside the cwrapper. +# Similar accommodations are necessary for $host mingw and +# $build cygwin. Calling this function does no harm for other +# $host/$build combinations not listed above. +# +# ARG is the path (on $build) that should be converted to +# the proper representation for $host. The result is stored +# in $func_to_host_path_result. +func_to_host_path () +{ + func_to_host_path_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + case $build in + *mingw* ) # actually, msys + # awkward: cmd appends spaces to result + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_path_tmp1=`( cmd //c echo "$1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_path_tmp1=`cygpath -w "$1"` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # Unfortunately, winepath does not exit with a non-zero + # error code, so we are forced to check the contents of + # stdout. On the other hand, if the command is not + # found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both + # error code of zero AND non-empty stdout, which explains + # the odd construction: + func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + else + # Allow warning below. + func_to_host_path_result="" + fi + ;; + esac + if test -z "$func_to_host_path_result" ; then + func_error "Could not determine host path corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_path_result="$1" + fi + ;; + esac + fi +} +# end: func_to_host_path + +# func_to_host_pathlist arg +# +# Convert pathlists to host format when used with build tools. +# See func_to_host_path(), above. This function supports the +# following $build/$host combinations (but does no harm for +# combinations not listed here): +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# +# Path separators are also converted from $build format to +# $host format. If ARG begins or ends with a path separator +# character, it is preserved (but converted to $host format) +# on output. +# +# ARG is a pathlist (on $build) that should be converted to +# the proper representation on $host. The result is stored +# in $func_to_host_pathlist_result. +func_to_host_pathlist () +{ + func_to_host_pathlist_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_to_host_pathlist_tmp2="$1" + # Once set for this call, this variable should not be + # reassigned. It is used in tha fallback case. + func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e 's|^:*||' -e 's|:*$||'` + case $build in + *mingw* ) # Actually, msys. + # Awkward: cmd appends spaces to result. + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # unfortunately, winepath doesn't convert pathlists + func_to_host_pathlist_result="" + func_to_host_pathlist_oldIFS=$IFS + IFS=: + for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do + IFS=$func_to_host_pathlist_oldIFS + if test -n "$func_to_host_pathlist_f" ; then + func_to_host_path "$func_to_host_pathlist_f" + if test -n "$func_to_host_path_result" ; then + if test -z "$func_to_host_pathlist_result" ; then + func_to_host_pathlist_result="$func_to_host_path_result" + else + func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" + fi + fi + fi + IFS=: + done + IFS=$func_to_host_pathlist_oldIFS + ;; + esac + if test -z "$func_to_host_pathlist_result" ; then + func_error "Could not determine the host path(s) corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This may break if $1 contains DOS-style drive + # specifications. The fix is not to complicate the expression + # below, but for the user to provide a working wine installation + # with winepath so that path translation in the cross-to-mingw + # case works properly. + lt_replace_pathsep_nix_to_dos="s|:|;|g" + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_replace_pathsep_nix_to_dos"` + fi + # Now, add the leading and trailing path separators back + case "$1" in + :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" + ;; + esac + case "$1" in + *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" + ;; + esac + ;; + esac + fi +} +# end: func_to_host_pathlist + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +# define setmode _setmode +#else +# include +# include +# ifdef __CYGWIN__ +# include +# define HAVE_SETENV +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +#ifdef _MSC_VER +# define S_IXUSR _S_IEXEC +# define stat _stat +# ifndef _INTPTR_T_DEFINED +# define intptr_t int +# endif +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifdef __CYGWIN__ +# define FOPEN_WB "wb" +#endif + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#undef LTWRAPPER_DEBUGPRINTF +#if defined DEBUGWRAPPER +# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args +static void +ltwrapper_debugprintf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); +} +#else +# define LTWRAPPER_DEBUGPRINTF(args) +#endif + +const char *program_name = NULL; + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_fatal (const char *message, ...); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_opt_process_env_set (const char *arg); +void lt_opt_process_env_prepend (const char *arg); +void lt_opt_process_env_append (const char *arg); +int lt_split_name_value (const char *arg, char** name, char** value); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); + +static const char *script_text_part1 = +EOF + + func_emit_wrapper_part1 yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ "/' -e 's/$/\\n"/' + echo ";" + cat <"))); + for (i = 0; i < newargc; i++) + { + LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); + } + +EOF + + case $host_os in + mingw*) + cat <<"EOF" + /* execv doesn't actually work on mingw as expected on unix */ + rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); + if (rval == -1) + { + /* failed to start process */ + LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); + return 127; + } + return rval; +EOF + ;; + *) + cat <<"EOF" + execv (lt_argv_zero, newargz); + return rval; /* =127, but avoids unused variable warning */ +EOF + ;; + esac + + cat <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void *p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), + string) : NULL; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char) name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable (const char *path) +{ + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", + wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", + tmp_pathspec)); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + char *errstr = strerror (errno); + lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal ("Could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} + +void +lt_setenv (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", + (name ? name : ""), + (value ? value : ""))); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +int +lt_split_name_value (const char *arg, char** name, char** value) +{ + const char *p; + int len; + if (!arg || !*arg) + return 1; + + p = strchr (arg, (int)'='); + + if (!p) + return 1; + + *value = xstrdup (++p); + + len = strlen (arg) - strlen (*value); + *name = XMALLOC (char, len); + strncpy (*name, arg, len-1); + (*name)[len - 1] = '\0'; + + return 0; +} + +void +lt_opt_process_env_set (const char *arg) +{ + char *name = NULL; + char *value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); + } + + lt_setenv (name, value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_prepend (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_append (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 1); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + + +EOF +} +# end: func_emit_cwrapperexe_src + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) deplibs="$deplibs $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + weak_libs="$weak_libs $arg" + prev= + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname '-L' '' "$arg" + dir=$func_stripname_result + if test -z "$dir"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" + linker_flags="$linker_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_duplicate_deps ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + case $lib in + *.la) func_source "$lib" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` + case " $weak_libs " in + *" $deplib_base "*) ;; + *) deplibs="$deplibs $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + dir=$func_stripname_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $ECHO + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because the file extensions .$libext of this argument makes me believe" + $ECHO "*** that it is just a static archive that I should not use here." + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) temp_rpath="$temp_rpath$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + notinst_deplibs="$notinst_deplibs $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + $ECHO + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $ECHO + $ECHO "*** And there doesn't seem to be a static archive available" + $ECHO "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $ECHO + $ECHO "*** Warning: This system can not link to static lib archive $lib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $ECHO "*** But as you try to build a module library, libtool will still create " + $ECHO "*** a static module, that should work as long as the dlopening application" + $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_dirname "$deplib" "" "." + dir="$func_dirname_result" + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type \`$version_type'" + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + libobjs="$libobjs $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` + # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` + # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ + -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` + done + fi + if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | + $GREP . >/dev/null; then + $ECHO + if test "X$deplibs_check_method" = "Xnone"; then + $ECHO "*** Warning: inter-library dependencies are not supported in this platform." + else + $ECHO "*** Warning: inter-library dependencies are not known to be supported." + fi + $ECHO "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $ECHO + $ECHO "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + $ECHO "*** a static module, that should work as long as the dlopening" + $ECHO "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $ECHO "*** The inter-library dependencies that have been dropped here will be" + $ECHO "*** automatically added whenever a program is linked with this library" + $ECHO "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $ECHO + $ECHO "*** Since this library must not contain undefined symbols," + $ECHO "*** because either the platform does not support them or" + $ECHO "*** it was explicitly requested with -no-undefined," + $ECHO "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + delfiles="$delfiles $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + func_len " $cmd" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$ECHO "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + $ECHO 'INPUT (' > $output + for obj in $save_libobjs + do + $ECHO "$obj" >> $output + done + $ECHO ')' >> $output + delfiles="$delfiles $output" + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + $ECHO "$obj" >> $output + done + delfiles="$delfiles $output" + output=$firstobj\"$file_list_spec$output\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + delfiles="$delfiles $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *cegcc) + # Disable wrappers for cegcc, we are cross compiling anyway. + wrappers_required=no + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $ECHO for shipping. + if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + oldobjs="$oldobjs $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $ECHO "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlfiles="$newdlfiles $libdir/$name" + ;; + *) newdlfiles="$newdlfiles $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlprefiles="$newdlprefiles $libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$mode" = link || test "$mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) RM="$RM $arg"; rmforce=yes ;; + -*) RM="$RM $arg" ;; + *) files="$files $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + rmfiles="$rmfiles $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$mode" = uninstall || test "$mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/m4/ChangeLog b/m4/ChangeLog new file mode 100644 index 0000000..e76f4b0 --- /dev/null +++ b/m4/ChangeLog @@ -0,0 +1,66 @@ +2007-02-08 gettextize + + * gettext.m4: Upgrade to gettext-0.16.1. + * iconv.m4: Upgrade to gettext-0.16.1. + * lib-ld.m4: Upgrade to gettext-0.16.1. + * lib-link.m4: Upgrade to gettext-0.16.1. + * lib-prefix.m4: Upgrade to gettext-0.16.1. + * nls.m4: Upgrade to gettext-0.16.1. + * po.m4: Upgrade to gettext-0.16.1. + * progtest.m4: Upgrade to gettext-0.16.1. + * codeset.m4: Upgrade to gettext-0.16.1. + * glibc2.m4: New file, from gettext-0.16.1. + * glibc21.m4: Upgrade to gettext-0.16.1. + * intdiv0.m4: Upgrade to gettext-0.16.1. + * intl.m4: New file, from gettext-0.16.1. + * intldir.m4: New file, from gettext-0.16.1. + * intmax.m4: Upgrade to gettext-0.16.1. + * inttypes_h.m4: Upgrade to gettext-0.16.1. + * inttypes-pri.m4: Upgrade to gettext-0.16.1. + * lcmessage.m4: Upgrade to gettext-0.16.1. + * lock.m4: New file, from gettext-0.16.1. + * longdouble.m4: Upgrade to gettext-0.16.1. + * longlong.m4: Upgrade to gettext-0.16.1. + * printf-posix.m4: Upgrade to gettext-0.16.1. + * size_max.m4: Upgrade to gettext-0.16.1. + * stdint_h.m4: Upgrade to gettext-0.16.1. + * uintmax_t.m4: Upgrade to gettext-0.16.1. + * ulonglong.m4: Upgrade to gettext-0.16.1. + * visibility.m4: New file, from gettext-0.16.1. + * wchar_t.m4: Upgrade to gettext-0.16.1. + * wint_t.m4: Upgrade to gettext-0.16.1. + * xsize.m4: Upgrade to gettext-0.16.1. + * Makefile.am (EXTRA_DIST): Add the new files. + +2004-08-21 gettextize + + * codeset.m4: New file, from gettext-0.14. + * gettext.m4: New file, from gettext-0.14. + * glibc21.m4: New file, from gettext-0.14. + * iconv.m4: New file, from gettext-0.14. + * intdiv0.m4: New file, from gettext-0.14. + * intmax.m4: New file, from gettext-0.14. + * inttypes.m4: New file, from gettext-0.14. + * inttypes_h.m4: New file, from gettext-0.14. + * inttypes-pri.m4: New file, from gettext-0.14. + * isc-posix.m4: New file, from gettext-0.14. + * lcmessage.m4: New file, from gettext-0.14. + * lib-ld.m4: New file, from gettext-0.14. + * lib-link.m4: New file, from gettext-0.14. + * lib-prefix.m4: New file, from gettext-0.14. + * longdouble.m4: New file, from gettext-0.14. + * longlong.m4: New file, from gettext-0.14. + * nls.m4: New file, from gettext-0.14. + * po.m4: New file, from gettext-0.14. + * printf-posix.m4: New file, from gettext-0.14. + * progtest.m4: New file, from gettext-0.14. + * signed.m4: New file, from gettext-0.14. + * size_max.m4: New file, from gettext-0.14. + * stdint_h.m4: New file, from gettext-0.14. + * uintmax_t.m4: New file, from gettext-0.14. + * ulonglong.m4: New file, from gettext-0.14. + * wchar_t.m4: New file, from gettext-0.14. + * wint_t.m4: New file, from gettext-0.14. + * xsize.m4: New file, from gettext-0.14. + * Makefile.am: New file. + diff --git a/m4/Makefile.am b/m4/Makefile.am new file mode 100644 index 0000000..0e8179e --- /dev/null +++ b/m4/Makefile.am @@ -0,0 +1,39 @@ +EXTRA_DIST = glibc2.m4 intl.m4 intldir.m4 lock.m4 visibility.m4 \ +absolute-header.m4 \ +libunistring.m4 \ +codeset.m4 \ +freetype2.m4\ +gettext.m4\ +glib-2.0.m4\ +glibc21.m4\ +glib-gettext.m4\ +gnulib-cache.m4\ +gtk-2.0.m4\ +iconv.m4\ +intdiv0.m4\ +intmax.m4\ +inttypes_h.m4\ +inttypes.m4\ +inttypes-pri.m4\ +isc-posix.m4\ +lcmessage.m4\ +libgcrypt.m4\ +lib-ld.m4\ +lib-link.m4\ +lib-prefix.m4\ +libxml2.m4\ +longdouble.m4\ +longlong.m4\ +nls.m4\ +pkg.m4\ +po.m4\ +printf-posix.m4\ +progtest.m4\ +signed.m4\ +size_max.m4\ +stdint_h.m4\ +uintmax_t.m4\ +ulonglong.m4\ +wchar_t.m4\ +wint_t.m4\ +xsize.m4 diff --git a/m4/Makefile.in b/m4/Makefile.in new file mode 100644 index 0000000..43507ec --- /dev/null +++ b/m4/Makefile.in @@ -0,0 +1,498 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = m4 +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = glibc2.m4 intl.m4 intldir.m4 lock.m4 visibility.m4 \ +absolute-header.m4 \ +libunistring.m4 \ +codeset.m4 \ +freetype2.m4\ +gettext.m4\ +glib-2.0.m4\ +glibc21.m4\ +glib-gettext.m4\ +gnulib-cache.m4\ +gtk-2.0.m4\ +iconv.m4\ +intdiv0.m4\ +intmax.m4\ +inttypes_h.m4\ +inttypes.m4\ +inttypes-pri.m4\ +isc-posix.m4\ +lcmessage.m4\ +libgcrypt.m4\ +lib-ld.m4\ +lib-link.m4\ +lib-prefix.m4\ +libxml2.m4\ +longdouble.m4\ +longlong.m4\ +nls.m4\ +pkg.m4\ +po.m4\ +printf-posix.m4\ +progtest.m4\ +signed.m4\ +size_max.m4\ +stdint_h.m4\ +uintmax_t.m4\ +ulonglong.m4\ +wchar_t.m4\ +wint_t.m4\ +xsize.m4 + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu m4/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu m4/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/m4/absolute-header.m4 b/m4/absolute-header.m4 new file mode 100644 index 0000000..f576d34 --- /dev/null +++ b/m4/absolute-header.m4 @@ -0,0 +1,77 @@ +# absolute-header.m4 serial 12 +dnl Copyright (C) 2006-2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Derek Price. + +# gl_ABSOLUTE_HEADER(HEADER1 HEADER2 ...) +# --------------------------------------- +# Find the absolute name of a header file, testing first if the header exists. +# If the header were sys/inttypes.h, this macro would define +# ABSOLUTE_SYS_INTTYPES_H to the `""' quoted absolute name of sys/inttypes.h +# in config.h +# (e.g. `#define ABSOLUTE_SYS_INTTYPES_H "///usr/include/sys/inttypes.h"'). +# The three "///" are to pacify Sun C 5.8, which otherwise would say +# "warning: #include of /usr/include/... may be non-portable". +# Use `""', not `<>', so that the /// cannot be confused with a C99 comment. +# Note: This macro assumes that the header file is not empty after +# preprocessing, i.e. it does not only define preprocessor macros but also +# provides some type/enum definitions or function/variable declarations. +AC_DEFUN([gl_ABSOLUTE_HEADER], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_PREPROC_REQUIRE()dnl +m4_foreach_w([gl_HEADER_NAME], [$1], + [AS_VAR_PUSHDEF([gl_absolute_header], + [gl_cv_absolute_]m4_defn([gl_HEADER_NAME]))dnl + AC_CACHE_CHECK([absolute name of <]m4_defn([gl_HEADER_NAME])[>], + m4_defn([gl_absolute_header]), + [AS_VAR_PUSHDEF([ac_header_exists], + [ac_cv_header_]m4_defn([gl_HEADER_NAME]))dnl + AC_CHECK_HEADERS_ONCE(m4_defn([gl_HEADER_NAME]))dnl + if test AS_VAR_GET(ac_header_exists) = yes; then + gl_ABSOLUTE_HEADER_ONE(m4_defn([gl_HEADER_NAME])) + fi + AS_VAR_POPDEF([ac_header_exists])dnl + ])dnl + AC_DEFINE_UNQUOTED(AS_TR_CPP([ABSOLUTE_]m4_defn([gl_HEADER_NAME])), + ["AS_VAR_GET(gl_absolute_header)"], + [Define this to an absolute name of <]m4_defn([gl_HEADER_NAME])[>.]) + AS_VAR_POPDEF([gl_absolute_header])dnl +])dnl +])# gl_ABSOLUTE_HEADER + +# gl_ABSOLUTE_HEADER_ONE(HEADER) +# ------------------------------ +# Like gl_ABSOLUTE_HEADER, except that: +# - it assumes that the header exists, +# - it uses the current CPPFLAGS, +# - it does not cache the result, +# - it is silent. +AC_DEFUN([gl_ABSOLUTE_HEADER_ONE], +[ + AC_LANG_CONFTEST([AC_LANG_SOURCE([[#include <]]m4_dquote([$1])[[>]])]) + dnl AIX "xlc -E" and "cc -E" omit #line directives for header files + dnl that contain only a #include of other header files and no + dnl non-comment tokens of their own. This leads to a failure to + dnl detect the absolute name of , , + dnl and others. The workaround is to force preservation of comments + dnl through option -C. This ensures all necessary #line directives + dnl are present. GCC supports option -C as well. + case "$host_os" in + aix*) gl_absname_cpp="$ac_cpp -C" ;; + *) gl_absname_cpp="$ac_cpp" ;; + esac + dnl eval is necessary to expand gl_absname_cpp. + dnl Ultrix and Pyramid sh refuse to redirect output of eval, + dnl so use subshell. + AS_VAR_SET([gl_cv_absolute_]AS_TR_SH([[$1]]), +[`(eval "$gl_absname_cpp conftest.$ac_ext") 2>&AS_MESSAGE_LOG_FD | +sed -n '\#/$1#{ + s#.*"\(.*/$1\)".*#\1# + s#^/[^/]#//&# + p + q +}'`]) +]) diff --git a/m4/align.m4 b/m4/align.m4 new file mode 100644 index 0000000..733afa6 --- /dev/null +++ b/m4/align.m4 @@ -0,0 +1,32 @@ +# align.m4 +dnl Copyright (C) 2008 Christian Grothoff +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +# Define HAVE_UNALIGNED_64_ACCESS if reading a 64-bit value at a 32-bit aligned offset works +# Note that the program intentionally causes a SIGBUS (so you may +# see some message along those lines on the console). +AC_DEFUN([AC_UNALIGNED_64_ACCESS], +[AC_CACHE_CHECK([whether unaligned 64-bit access works], + ac_cv_unaligned_64_access, + [ + AC_RUN_IFELSE(AC_LANG_PROGRAM([[struct S { int a,b,c;};]], + [[struct S s = {0,0,0}; long long * p = (long long *) &s.b; + void *bp = malloc (50); + long long x = *p; + long long *be = (long long*) &bp[1]; + long long y = *be; + return (int) x*y;]]), + ac_cv_unaligned_64_access=yes, + ac_cv_unaligned_64_access=no, + ac_cv_unaligned_64_access=no) + ]) + case "$ac_cv_unaligned_64_access" in + *yes) value=1;; + *) value=0;; + esac + AC_DEFINE_UNQUOTED([HAVE_UNALIGNED_64_ACCESS], $value, [We can access-64 bit values that are only 32-bit aligned]) +]) diff --git a/m4/argz.m4 b/m4/argz.m4 new file mode 100644 index 0000000..37c1b11 --- /dev/null +++ b/m4/argz.m4 @@ -0,0 +1,79 @@ +# Portability macros for glibc argz. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +# Written by Gary V. Vaughan +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 argz.m4 + +AC_DEFUN([gl_FUNC_ARGZ], +[gl_PREREQ_ARGZ + +AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT]) + +AC_CHECK_TYPES([error_t], + [], + [AC_DEFINE([error_t], [int], + [Define to a type to use for `error_t' if it is not otherwise available.]) + AC_DEFINE([__error_t_defined], [1], [Define so that glibc/gnulib argp.h + does not typedef error_t.])], + [#if defined(HAVE_ARGZ_H) +# include +#endif]) + +ARGZ_H= +AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \ + argz_next argz_stringify], [], [ARGZ_H=argz.h; AC_LIBOBJ([argz])]) + +dnl if have system argz functions, allow forced use of +dnl libltdl-supplied implementation (and default to do so +dnl on "known bad" systems). Could use a runtime check, but +dnl (a) detecting malloc issues is notoriously unreliable +dnl (b) only known system that declares argz functions, +dnl provides them, yet they are broken, is cygwin +dnl releases prior to 16-Mar-2007 (1.5.24 and earlier) +dnl So, it's more straightforward simply to special case +dnl this for known bad systems. +AS_IF([test -z "$ARGZ_H"], + [AC_CACHE_CHECK( + [if argz actually works], + [lt_cv_sys_argz_works], + [[case $host_os in #( + *cygwin*) + lt_cv_sys_argz_works=no + if test "$cross_compiling" != no; then + lt_cv_sys_argz_works="guessing no" + else + lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' + save_IFS=$IFS + IFS=-. + set x `uname -r | sed -e "$lt_sed_extract_leading_digits"` + IFS=$save_IFS + lt_os_major=${2-0} + lt_os_minor=${3-0} + lt_os_micro=${4-0} + if test "$lt_os_major" -gt 1 \ + || { test "$lt_os_major" -eq 1 \ + && { test "$lt_os_minor" -gt 5 \ + || { test "$lt_os_minor" -eq 5 \ + && test "$lt_os_micro" -gt 24; }; }; }; then + lt_cv_sys_argz_works=yes + fi + fi + ;; #( + *) lt_cv_sys_argz_works=yes ;; + esac]]) + AS_IF([test $lt_cv_sys_argz_works = yes], + [AC_DEFINE([HAVE_WORKING_ARGZ], 1, + [This value is set to 1 to indicate that the system argz facility works])], + [ARGZ_H=argz.h + AC_LIBOBJ([argz])])]) + +AC_SUBST([ARGZ_H]) +]) + +# Prerequisites of lib/argz.c. +AC_DEFUN([gl_PREREQ_ARGZ], [:]) diff --git a/m4/codeset.m4 b/m4/codeset.m4 new file mode 100644 index 0000000..223955b --- /dev/null +++ b/m4/codeset.m4 @@ -0,0 +1,21 @@ +# codeset.m4 serial 2 (gettext-0.16) +dnl Copyright (C) 2000-2002, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_LANGINFO_CODESET], +[ + AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, + [AC_TRY_LINK([#include ], + [char* cs = nl_langinfo(CODESET); return !cs;], + am_cv_langinfo_codeset=yes, + am_cv_langinfo_codeset=no) + ]) + if test $am_cv_langinfo_codeset = yes; then + AC_DEFINE(HAVE_LANGINFO_CODESET, 1, + [Define if you have and nl_langinfo(CODESET).]) + fi +]) diff --git a/m4/freetype2.m4 b/m4/freetype2.m4 new file mode 100644 index 0000000..7424a32 --- /dev/null +++ b/m4/freetype2.m4 @@ -0,0 +1,178 @@ +# Configure paths for FreeType2 +# Marcelo Magallon 2001-10-26, based on gtk.m4 by Owen Taylor +# +# serial 2 + +# AC_CHECK_FT2([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +# Test for FreeType 2, and define FT2_CFLAGS and FT2_LIBS. +# MINIMUM-VERSION is what libtool reports; the default is `7.0.1' (this is +# FreeType 2.0.4). +# +AC_DEFUN([AC_CHECK_FT2], + [# Get the cflags and libraries from the freetype-config script + # + AC_ARG_WITH([ft-prefix], + dnl don't quote AS_HELP_STRING! + AS_HELP_STRING([--with-ft-prefix=PREFIX], + [Prefix where FreeType is installed (optional)]), + [ft_config_prefix="$withval"], + [ft_config_prefix=""]) + + AC_ARG_WITH([ft-exec-prefix], + dnl don't quote AS_HELP_STRING! + AS_HELP_STRING([--with-ft-exec-prefix=PREFIX], + [Exec prefix where FreeType is installed (optional)]), + [ft_config_exec_prefix="$withval"], + [ft_config_exec_prefix=""]) + + AC_ARG_ENABLE([freetypetest], + dnl don't quote AS_HELP_STRING! + AS_HELP_STRING([--disable-freetypetest], + [Do not try to compile and run a test FreeType program]), + [], + [enable_fttest=yes]) + + if test x$ft_config_exec_prefix != x ; then + ft_config_args="$ft_config_args --exec-prefix=$ft_config_exec_prefix" + if test x${FT2_CONFIG+set} != xset ; then + FT2_CONFIG=$ft_config_exec_prefix/bin/freetype-config + fi + fi + + if test x$ft_config_prefix != x ; then + ft_config_args="$ft_config_args --prefix=$ft_config_prefix" + if test x${FT2_CONFIG+set} != xset ; then + FT2_CONFIG=$ft_config_prefix/bin/freetype-config + fi + fi + + AC_PATH_PROG([FT2_CONFIG], [freetype-config], [no]) + + min_ft_version=m4_if([$1], [], [7.0.1], [$1]) + AC_MSG_CHECKING([for FreeType -- version >= $min_ft_version]) + no_ft="" + if test "$FT2_CONFIG" = "no" ; then + no_ft=yes + else + FT2_CFLAGS=`$FT2_CONFIG $ft_config_args --cflags` + FT2_LIBS=`$FT2_CONFIG $ft_config_args --libs` + ft_config_major_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + ft_config_minor_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + ft_config_micro_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + ft_min_major_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + ft_min_minor_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + ft_min_micro_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test x$enable_fttest = xyes ; then + ft_config_is_lt="" + if test $ft_config_major_version -lt $ft_min_major_version ; then + ft_config_is_lt=yes + else + if test $ft_config_major_version -eq $ft_min_major_version ; then + if test $ft_config_minor_version -lt $ft_min_minor_version ; then + ft_config_is_lt=yes + else + if test $ft_config_minor_version -eq $ft_min_minor_version ; then + if test $ft_config_micro_version -lt $ft_min_micro_version ; then + ft_config_is_lt=yes + fi + fi + fi + fi + fi + if test x$ft_config_is_lt = xyes ; then + no_ft=yes + else + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $FT2_CFLAGS" + LIBS="$FT2_LIBS $LIBS" + + # + # Sanity checks for the results of freetype-config to some extent. + # + AC_RUN_IFELSE([ + AC_LANG_SOURCE([[ + +#include +#include FT_FREETYPE_H +#include +#include + +int +main() +{ + FT_Library library; + FT_Error error; + + error = FT_Init_FreeType(&library); + + if (error) + return 1; + else + { + FT_Done_FreeType(library); + return 0; + } +} + + ]]) + ], + [], + [no_ft=yes], + [echo $ECHO_N "cross compiling; assuming OK... $ECHO_C"]) + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi # test $ft_config_version -lt $ft_min_version + fi # test x$enable_fttest = xyes + fi # test "$FT2_CONFIG" = "no" + + if test x$no_ft = x ; then + AC_MSG_RESULT([yes]) + m4_if([$2], [], [:], [$2]) + else + AC_MSG_RESULT([no]) + if test "$FT2_CONFIG" = "no" ; then + AC_MSG_WARN([ + + The freetype-config script installed by FreeType 2 could not be found. + If FreeType 2 was installed in PREFIX, make sure PREFIX/bin is in + your path, or set the FT2_CONFIG environment variable to the + full path to freetype-config. + ]) + else + if test x$ft_config_is_lt = xyes ; then + AC_MSG_WARN([ + + Your installed version of the FreeType 2 library is too old. + If you have different versions of FreeType 2, make sure that + correct values for --with-ft-prefix or --with-ft-exec-prefix + are used, or set the FT2_CONFIG environment variable to the + full path to freetype-config. + ]) + else + AC_MSG_WARN([ + + The FreeType test program failed to run. If your system uses + shared libraries and they are installed outside the normal + system library path, make sure the variable LD_LIBRARY_PATH + (or whatever is appropiate for your system) is correctly set. + ]) + fi + fi + + FT2_CFLAGS="" + FT2_LIBS="" + m4_if([$3], [], [:], [$3]) + fi + + AC_SUBST([FT2_CFLAGS]) + AC_SUBST([FT2_LIBS])]) + +# end of freetype2.m4 diff --git a/m4/gettext.m4 b/m4/gettext.m4 new file mode 100644 index 0000000..91c345e --- /dev/null +++ b/m4/gettext.m4 @@ -0,0 +1,419 @@ +# gettext.m4 serial 59 (gettext-0.16.1) +dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2006. + +dnl Macro to add for using GNU gettext. + +dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). +dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The +dnl default (if it is not specified or empty) is 'no-libtool'. +dnl INTLSYMBOL should be 'external' for packages with no intl directory, +dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. +dnl If INTLSYMBOL is 'use-libtool', then a libtool library +dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, +dnl depending on --{enable,disable}-{shared,static} and on the presence of +dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library +dnl $(top_builddir)/intl/libintl.a will be created. +dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext +dnl implementations (in libc or libintl) without the ngettext() function +dnl will be ignored. If NEEDSYMBOL is specified and is +dnl 'need-formatstring-macros', then GNU gettext implementations that don't +dnl support the ISO C 99 formatstring macros will be ignored. +dnl INTLDIR is used to find the intl libraries. If empty, +dnl the value `$(top_builddir)/intl/' is used. +dnl +dnl The result of the configuration is one of three cases: +dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled +dnl and used. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 2) GNU gettext has been found in the system's C library. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 3) No internationalization, always use English msgid. +dnl Catalog format: none +dnl Catalog extension: none +dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. +dnl The use of .gmo is historical (it was needed to avoid overwriting the +dnl GNU format catalogs when building on a platform with an X/Open gettext), +dnl but we keep it in order not to force irrelevant filename changes on the +dnl maintainers. +dnl +AC_DEFUN([AM_GNU_GETTEXT], +[ + dnl Argument checking. + ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , + [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT +])])])])]) + ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , + [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT +])])])]) + define([gt_included_intl], + ifelse([$1], [external], + ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), + [yes])) + define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) + gt_NEEDS_INIT + AM_GNU_GETTEXT_NEED([$2]) + + AC_REQUIRE([AM_PO_SUBDIRS])dnl + ifelse(gt_included_intl, yes, [ + AC_REQUIRE([AM_INTL_SUBDIR])dnl + ]) + + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Sometimes libintl requires libiconv, so first search for libiconv. + dnl Ideally we would do this search only after the + dnl if test "$USE_NLS" = "yes"; then + dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT + dnl the configure script would need to contain the same shell code + dnl again, outside any 'if'. There are two solutions: + dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. + dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. + dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not + dnl documented, we avoid it. + ifelse(gt_included_intl, yes, , [ + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + ]) + + dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation. + gt_INTL_MACOSX + + dnl Set USE_NLS. + AC_REQUIRE([AM_NLS]) + + ifelse(gt_included_intl, yes, [ + BUILD_INCLUDED_LIBINTL=no + USE_INCLUDED_LIBINTL=no + ]) + LIBINTL= + LTLIBINTL= + POSUB= + + dnl Add a version number to the cache macros. + case " $gt_needs " in + *" need-formatstring-macros "*) gt_api_version=3 ;; + *" need-ngettext "*) gt_api_version=2 ;; + *) gt_api_version=1 ;; + esac + gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" + gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" + + dnl If we use NLS figure out what method + if test "$USE_NLS" = "yes"; then + gt_use_preinstalled_gnugettext=no + ifelse(gt_included_intl, yes, [ + AC_MSG_CHECKING([whether included gettext is requested]) + AC_ARG_WITH(included-gettext, + [ --with-included-gettext use the GNU gettext library included here], + nls_cv_force_use_gnu_gettext=$withval, + nls_cv_force_use_gnu_gettext=no) + AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + ]) + dnl User does not insist on using GNU NLS library. Figure out what + dnl to use. If GNU gettext is available we use this. Else we have + dnl to fall back to GNU NLS library. + + if test $gt_api_version -ge 3; then + gt_revision_test_code=' +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +changequote(,)dnl +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +changequote([,])dnl +' + else + gt_revision_test_code= + fi + if test $gt_api_version -ge 2; then + gt_expression_test_code=' + * ngettext ("", "", 0)' + else + gt_expression_test_code= + fi + + AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], + [AC_TRY_LINK([#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern int *_nl_domain_bindings;], + [bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings], + [eval "$gt_func_gnugettext_libc=yes"], + [eval "$gt_func_gnugettext_libc=no"])]) + + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + dnl Sometimes libintl requires libiconv, so first search for libiconv. + ifelse(gt_included_intl, yes, , [ + AM_ICONV_LINK + ]) + dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL + dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) + dnl because that would add "-liconv" to LIBINTL and LTLIBINTL + dnl even if libiconv doesn't exist. + AC_LIB_LINKFLAGS_BODY([intl]) + AC_CACHE_CHECK([for GNU gettext in libintl], + [$gt_func_gnugettext_libintl], + [gt_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCINTL" + gt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBINTL" + dnl Now see whether libintl exists and does not depend on libiconv. + AC_TRY_LINK([#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *);], + [bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], + [eval "$gt_func_gnugettext_libintl=yes"], + [eval "$gt_func_gnugettext_libintl=no"]) + dnl Now see whether libintl exists and depends on libiconv. + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *);], + [bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], + [LIBINTL="$LIBINTL $LIBICONV" + LTLIBINTL="$LTLIBINTL $LTLIBICONV" + eval "$gt_func_gnugettext_libintl=yes" + ]) + fi + CPPFLAGS="$gt_save_CPPFLAGS" + LIBS="$gt_save_LIBS"]) + fi + + dnl If an already present or preinstalled GNU gettext() is found, + dnl use it. But if this macro is used in GNU gettext, and GNU + dnl gettext is already preinstalled in libintl, we update this + dnl libintl. (Cf. the install rule in intl/Makefile.in.) + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ + || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ + && test "$PACKAGE" != gettext-runtime \ + && test "$PACKAGE" != gettext-tools; }; then + gt_use_preinstalled_gnugettext=yes + else + dnl Reset the values set by searching for libintl. + LIBINTL= + LTLIBINTL= + INCINTL= + fi + + ifelse(gt_included_intl, yes, [ + if test "$gt_use_preinstalled_gnugettext" != "yes"; then + dnl GNU gettext is not found in the C library. + dnl Fall back on included GNU gettext library. + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions used to generate GNU NLS library. + BUILD_INCLUDED_LIBINTL=yes + USE_INCLUDED_LIBINTL=yes + LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" + LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" + LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` + fi + + CATOBJEXT= + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions to use GNU gettext tools. + CATOBJEXT=.gmo + fi + ]) + + if test -n "$INTL_MACOSX_LIBS"; then + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Some extra flags are needed during linking. + LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" + LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" + fi + fi + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + AC_DEFINE(ENABLE_NLS, 1, + [Define to 1 if translation of program messages to the user's native language + is requested.]) + else + USE_NLS=no + fi + fi + + AC_MSG_CHECKING([whether to use NLS]) + AC_MSG_RESULT([$USE_NLS]) + if test "$USE_NLS" = "yes"; then + AC_MSG_CHECKING([where the gettext function comes from]) + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + gt_source="external libintl" + else + gt_source="libc" + fi + else + gt_source="included intl directory" + fi + AC_MSG_RESULT([$gt_source]) + fi + + if test "$USE_NLS" = "yes"; then + + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + AC_MSG_CHECKING([how to link with libintl]) + AC_MSG_RESULT([$LIBINTL]) + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) + fi + + dnl For backward compatibility. Some packages may be using this. + AC_DEFINE(HAVE_GETTEXT, 1, + [Define if the GNU gettext() function is already present or preinstalled.]) + AC_DEFINE(HAVE_DCGETTEXT, 1, + [Define if the GNU dcgettext() function is already present or preinstalled.]) + fi + + dnl We need to process the po/ directory. + POSUB=po + fi + + ifelse(gt_included_intl, yes, [ + dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL + dnl to 'yes' because some of the testsuite requires it. + if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then + BUILD_INCLUDED_LIBINTL=yes + fi + + dnl Make all variables we use known to autoconf. + AC_SUBST(BUILD_INCLUDED_LIBINTL) + AC_SUBST(USE_INCLUDED_LIBINTL) + AC_SUBST(CATOBJEXT) + + dnl For backward compatibility. Some configure.ins may be using this. + nls_cv_header_intl= + nls_cv_header_libgt= + + dnl For backward compatibility. Some Makefiles may be using this. + DATADIRNAME=share + AC_SUBST(DATADIRNAME) + + dnl For backward compatibility. Some Makefiles may be using this. + INSTOBJEXT=.mo + AC_SUBST(INSTOBJEXT) + + dnl For backward compatibility. Some Makefiles may be using this. + GENCAT=gencat + AC_SUBST(GENCAT) + + dnl For backward compatibility. Some Makefiles may be using this. + INTLOBJS= + if test "$USE_INCLUDED_LIBINTL" = yes; then + INTLOBJS="\$(GETTOBJS)" + fi + AC_SUBST(INTLOBJS) + + dnl Enable libtool support if the surrounding package wishes it. + INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix + AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) + ]) + + dnl For backward compatibility. Some Makefiles may be using this. + INTLLIBS="$LIBINTL" + AC_SUBST(INTLLIBS) + + dnl Make all documented variables known to autoconf. + AC_SUBST(LIBINTL) + AC_SUBST(LTLIBINTL) + AC_SUBST(POSUB) +]) + + +dnl Checks for special options needed on MacOS X. +dnl Defines INTL_MACOSX_LIBS. +AC_DEFUN([gt_INTL_MACOSX], +[ + dnl Check for API introduced in MacOS X 10.2. + AC_CACHE_CHECK([for CFPreferencesCopyAppValue], + gt_cv_func_CFPreferencesCopyAppValue, + [gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + AC_TRY_LINK([#include ], + [CFPreferencesCopyAppValue(NULL, NULL)], + [gt_cv_func_CFPreferencesCopyAppValue=yes], + [gt_cv_func_CFPreferencesCopyAppValue=no]) + LIBS="$gt_save_LIBS"]) + if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then + AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], 1, + [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) + fi + dnl Check for API introduced in MacOS X 10.3. + AC_CACHE_CHECK([for CFLocaleCopyCurrent], gt_cv_func_CFLocaleCopyCurrent, + [gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + AC_TRY_LINK([#include ], [CFLocaleCopyCurrent();], + [gt_cv_func_CFLocaleCopyCurrent=yes], + [gt_cv_func_CFLocaleCopyCurrent=no]) + LIBS="$gt_save_LIBS"]) + if test $gt_cv_func_CFLocaleCopyCurrent = yes; then + AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], 1, + [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) + fi + INTL_MACOSX_LIBS= + if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then + INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" + fi + AC_SUBST([INTL_MACOSX_LIBS]) +]) + + +dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. +m4_define([gt_NEEDS_INIT], +[ + m4_divert_text([DEFAULTS], [gt_needs=]) + m4_define([gt_NEEDS_INIT], []) +]) + + +dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) +AC_DEFUN([AM_GNU_GETTEXT_NEED], +[ + m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) +]) + + +dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) +AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) diff --git a/m4/glib-2.0.m4 b/m4/glib-2.0.m4 new file mode 100644 index 0000000..13a3ce6 --- /dev/null +++ b/m4/glib-2.0.m4 @@ -0,0 +1,212 @@ +# Configure paths for GLIB +# Owen Taylor 1997-2001 + +dnl AM_PATH_GLIB_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) +dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if gmodule, gobject or +dnl gthread is specified in MODULES, pass to pkg-config +dnl +AC_DEFUN([AM_PATH_GLIB_2_0], +[dnl +dnl Get the cflags and libraries from pkg-config +dnl +AC_ARG_ENABLE(glibtest, [ --disable-glibtest do not try to compile and run a test GLIB program], + , enable_glibtest=yes) + + pkg_config_args=glib-2.0 + for module in . $4 + do + case "$module" in + gmodule) + pkg_config_args="$pkg_config_args gmodule-2.0" + ;; + gobject) + pkg_config_args="$pkg_config_args gobject-2.0" + ;; + gthread) + pkg_config_args="$pkg_config_args gthread-2.0" + ;; + esac + done + + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + + no_glib="" + + if test x$PKG_CONFIG != xno ; then + if $PKG_CONFIG --atleast-pkgconfig-version 0.7 ; then + : + else + echo *** pkg-config too old; version 0.7 or better required. + no_glib=yes + PKG_CONFIG=no + fi + else + no_glib=yes + fi + + min_glib_version=ifelse([$1], ,2.0.0,$1) + AC_MSG_CHECKING(for GLIB - version >= $min_glib_version) + + if test x$PKG_CONFIG != xno ; then + ## don't try to run the test against uninstalled libtool libs + if $PKG_CONFIG --uninstalled $pkg_config_args; then + echo "Will use uninstalled version of GLib found in PKG_CONFIG_PATH" + enable_glibtest=no + fi + + if $PKG_CONFIG --atleast-version $min_glib_version $pkg_config_args; then + : + else + no_glib=yes + fi + fi + + if test x"$no_glib" = x ; then + GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0` + GOBJECT_QUERY=`$PKG_CONFIG --variable=gobject_query glib-2.0` + GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0` + + GLIB_CFLAGS=`$PKG_CONFIG --cflags $pkg_config_args` + GLIB_LIBS=`$PKG_CONFIG --libs $pkg_config_args` + glib_config_major_version=`$PKG_CONFIG --modversion glib-2.0 | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + glib_config_minor_version=`$PKG_CONFIG --modversion glib-2.0 | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + glib_config_micro_version=`$PKG_CONFIG --modversion glib-2.0 | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_glibtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GLIB_CFLAGS" + LIBS="$GLIB_LIBS $LIBS" +dnl +dnl Now check if the installed GLIB is sufficiently new. (Also sanity +dnl checks the results of pkg-config to some extent) +dnl + rm -f conf.glibtest + AC_TRY_RUN([ +#include +#include +#include + +int +main () +{ + int major, minor, micro; + char *tmp_version; + + system ("touch conf.glibtest"); + + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = g_strdup("$min_glib_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_glib_version"); + exit(1); + } + + if ((glib_major_version != $glib_config_major_version) || + (glib_minor_version != $glib_config_minor_version) || + (glib_micro_version != $glib_config_micro_version)) + { + printf("\n*** 'pkg-config --modversion glib-2.0' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", + $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version, + glib_major_version, glib_minor_version, glib_micro_version); + printf ("*** was found! If pkg-config was correct, then it is best\n"); + printf ("*** to remove the old version of GLib. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); + printf("*** to point to the correct configuration files\n"); + } + else if ((glib_major_version != GLIB_MAJOR_VERSION) || + (glib_minor_version != GLIB_MINOR_VERSION) || + (glib_micro_version != GLIB_MICRO_VERSION)) + { + printf("*** GLIB header files (version %d.%d.%d) do not match\n", + GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); + printf("*** library (version %d.%d.%d)\n", + glib_major_version, glib_minor_version, glib_micro_version); + } + else + { + if ((glib_major_version > major) || + ((glib_major_version == major) && (glib_minor_version > minor)) || + ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GLIB (%d.%d.%d) was found.\n", + glib_major_version, glib_minor_version, glib_micro_version); + printf("*** You need a version of GLIB newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** GLIB is always available from ftp://ftp.gtk.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GLIB, but you can also set the PKG_CONFIG environment to point to the\n"); + printf("*** correct copy of pkg-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} +],, no_glib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_glib" = x ; then + AC_MSG_RESULT(yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$PKG_CONFIG" = "no" ; then + echo "*** A new enough version of pkg-config was not found." + echo "*** See http://www.freedesktop.org/software/pkgconfig/" + else + if test -f conf.glibtest ; then + : + else + echo "*** Could not run GLIB test program, checking why..." + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GLIB_CFLAGS" + LIBS="$LIBS $GLIB_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GLIB or finding the wrong" + echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means GLIB is incorrectly installed."]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GLIB_CFLAGS="" + GLIB_LIBS="" + GLIB_GENMARSHAL="" + GOBJECT_QUERY="" + GLIB_MKENUMS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GLIB_CFLAGS) + AC_SUBST(GLIB_LIBS) + AC_SUBST(GLIB_GENMARSHAL) + AC_SUBST(GOBJECT_QUERY) + AC_SUBST(GLIB_MKENUMS) + rm -f conf.glibtest +]) diff --git a/m4/glib-gettext.m4 b/m4/glib-gettext.m4 new file mode 100644 index 0000000..5a4ef28 --- /dev/null +++ b/m4/glib-gettext.m4 @@ -0,0 +1,380 @@ +# Copyright (C) 1995-2002 Free Software Foundation, Inc. +# Copyright (C) 2001-2003 Red Hat, Inc. +# +# This file is free software, distributed under the terms of the GNU +# General Public License. As a special exception to the GNU General +# Public License, this file may be distributed as part of a program +# that contains a configuration script generated by Autoconf, under +# the same distribution terms as the rest of that program. +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# +# Macro to add for using GNU gettext. +# Ulrich Drepper , 1995, 1996 +# +# Modified to never use included libintl. +# Owen Taylor , 12/15/1998 +# +# Major rework to remove unused code +# Owen Taylor , 12/11/2002 +# +# Added better handling of ALL_LINGUAS from GNU gettext version +# written by Bruno Haible, Owen Taylor 5/30/3002 + +# +# We need this here as well, since someone might use autoconf-2.5x +# to configure GLib then an older version to configure a package +# using AM_GLIB_GNU_GETTEXT +AC_PREREQ(2.53) + +dnl +dnl We go to great lengths to make sure that aclocal won't +dnl try to pull in the installed version of these macros +dnl when running aclocal in the glib directory. +dnl +m4_copy([AC_DEFUN],[glib_DEFUN]) +m4_copy([AC_REQUIRE],[glib_REQUIRE]) +dnl +dnl At the end, if we're not within glib, we'll define the public +dnl definitions in terms of our private definitions. +dnl + +# GLIB_LC_MESSAGES +#-------------------- +glib_DEFUN([GLIB_LC_MESSAGES], + [AC_CHECK_HEADERS([locale.h]) + if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, + [Define if your file defines LC_MESSAGES.]) + fi + fi]) + +# GLIB_PATH_PROG_WITH_TEST +#---------------------------- +dnl GLIB_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +glib_DEFUN([GLIB_PATH_PROG_WITH_TEST], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + +# GLIB_WITH_NLS +#----------------- +glib_DEFUN([GLIB_WITH_NLS], + dnl NLS is obligatory + [USE_NLS=yes + AC_SUBST(USE_NLS) + + gt_cv_have_gettext=no + + CATOBJEXT=NONE + XGETTEXT=: + INTLLIBS= + + AC_CHECK_HEADER(libintl.h, + [gt_cv_func_dgettext_libintl="no" + libintl_extra_libs="" + + # + # First check in libc + # + AC_CACHE_CHECK([for dgettext in libc], gt_cv_func_dgettext_libc, + [AC_TRY_LINK([ +#include +], + [return (int) dgettext ("","")], + gt_cv_func_dgettext_libc=yes, + gt_cv_func_dgettext_libc=no) + ]) + + if test "$gt_cv_func_dgettext_libc" = "yes" ; then + AC_CHECK_FUNCS(bind_textdomain_codeset) + fi + + # + # If we don't have everything we want, check in libintl + # + if test "$gt_cv_func_dgettext_libc" != "yes" \ + || test "$ac_cv_func_bind_textdomain_codeset" != "yes" ; then + + AC_CHECK_LIB(intl, bindtextdomain, + [AC_CHECK_LIB(intl, dgettext, + gt_cv_func_dgettext_libintl=yes)]) + + if test "$gt_cv_func_dgettext_libintl" != "yes" ; then + AC_MSG_CHECKING([if -liconv is needed to use gettext]) + AC_MSG_RESULT([]) + AC_CHECK_LIB(intl, dcgettext, + [gt_cv_func_dgettext_libintl=yes + libintl_extra_libs=-liconv], + :,-liconv) + fi + + # + # If we found libintl, then check in it for bind_textdomain_codeset(); + # we'll prefer libc if neither have bind_textdomain_codeset(), + # and both have dgettext + # + if test "$gt_cv_func_dgettext_libintl" = "yes" ; then + glib_save_LIBS="$LIBS" + LIBS="$LIBS -lintl $libintl_extra_libs" + unset ac_cv_func_bind_textdomain_codeset + AC_CHECK_FUNCS(bind_textdomain_codeset) + LIBS="$glib_save_LIBS" + + if test "$ac_cv_func_bind_textdomain_codeset" = "yes" ; then + gt_cv_func_dgettext_libc=no + else + if test "$gt_cv_func_dgettext_libc" = "yes"; then + gt_cv_func_dgettext_libintl=no + fi + fi + fi + fi + + if test "$gt_cv_func_dgettext_libc" = "yes" \ + || test "$gt_cv_func_dgettext_libintl" = "yes"; then + gt_cv_have_gettext=yes + fi + + if test "$gt_cv_func_dgettext_libintl" = "yes"; then + INTLLIBS="-lintl $libintl_extra_libs" + fi + + if test "$gt_cv_have_gettext" = "yes"; then + AC_DEFINE(HAVE_GETTEXT,1, + [Define if the GNU gettext() function is already present or preinstalled.]) + GLIB_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl + if test "$MSGFMT" != "no"; then + glib_save_LIBS="$LIBS" + LIBS="$LIBS $INTLLIBS" + AC_CHECK_FUNCS(dcgettext) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + GLIB_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; + return _nl_msg_cat_cntr], + [CATOBJEXT=.gmo + DATADIRNAME=share], + [case $host in + *-*-solaris*) + dnl On Solaris, if bind_textdomain_codeset is in libc, + dnl GNU format message catalog is always supported, + dnl since both are added to the libc all together. + dnl Hence, we'd like to go with DATADIRNAME=share and + dnl and CATOBJEXT=.gmo in this case. + AC_CHECK_FUNC(bind_textdomain_codeset, + [CATOBJEXT=.gmo + DATADIRNAME=share], + [CATOBJEXT=.mo + DATADIRNAME=lib]) + ;; + *) + CATOBJEXT=.mo + DATADIRNAME=lib + ;; + esac]) + LIBS="$glib_save_LIBS" + INSTOBJEXT=.mo + else + gt_cv_have_gettext=no + fi + fi + ]) + + if test "$gt_cv_have_gettext" = "yes" ; then + AC_DEFINE(ENABLE_NLS, 1, + [always defined to indicate that i18n is enabled]) + fi + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is not GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext program is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + + # We need to process the po/ directory. + POSUB=po + + AC_OUTPUT_COMMANDS( + [case "$CONFIG_FILES" in *po/Makefile.in*) + sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile + esac]) + + dnl These rules are solely for the distribution goal. While doing this + dnl we only have to keep exactly one list of the available catalogs + dnl in configure.in. + for lang in $ALL_LINGUAS; do + GMOFILES="$GMOFILES $lang.gmo" + POFILES="$POFILES $lang.po" + done + + dnl Make all variables we use known to autoconf. + AC_SUBST(CATALOGS) + AC_SUBST(CATOBJEXT) + AC_SUBST(DATADIRNAME) + AC_SUBST(GMOFILES) + AC_SUBST(INSTOBJEXT) + AC_SUBST(INTLLIBS) + AC_SUBST(PO_IN_DATADIR_TRUE) + AC_SUBST(PO_IN_DATADIR_FALSE) + AC_SUBST(POFILES) + AC_SUBST(POSUB) + ]) + +# AM_GLIB_GNU_GETTEXT +# ------------------- +# Do checks necessary for use of gettext. If a suitable implementation +# of gettext is found in either in libintl or in the C library, +# it will set INTLLIBS to the libraries needed for use of gettext +# and AC_DEFINE() HAVE_GETTEXT and ENABLE_NLS. (The shell variable +# gt_cv_have_gettext will be set to "yes".) It will also call AC_SUBST() +# on various variables needed by the Makefile.in.in installed by +# glib-gettextize. +dnl +glib_DEFUN([GLIB_GNU_GETTEXT], + [AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + + GLIB_LC_MESSAGES + GLIB_WITH_NLS + + if test "$gt_cv_have_gettext" = "yes"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "${LINGUAS-%UNSET%}"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + NEW_LINGUAS="$NEW_LINGUAS $presentlang" + fi + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly + dnl find the mkinstalldirs script in another subdir but ($top_srcdir). + dnl Try to locate is. + MKINSTALLDIRS= + if test -n "$ac_aux_dir"; then + MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" + fi + if test -z "$MKINSTALLDIRS"; then + MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" + fi + AC_SUBST(MKINSTALLDIRS) + + dnl Generate list of files to be processed by xgettext which will + dnl be included in po/Makefile. + test -d po || mkdir po + if test "x$srcdir" != "x."; then + if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then + posrcprefix="$srcdir/" + else + posrcprefix="../$srcdir/" + fi + else + posrcprefix="../" + fi + rm -f po/POTFILES + sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ + < $srcdir/po/POTFILES.in > po/POTFILES + ]) + +# AM_GLIB_DEFINE_LOCALEDIR(VARIABLE) +# ------------------------------- +# Define VARIABLE to the location where catalog files will +# be installed by po/Makefile. +glib_DEFUN([GLIB_DEFINE_LOCALEDIR], +[glib_REQUIRE([GLIB_GNU_GETTEXT])dnl +glib_save_prefix="$prefix" +glib_save_exec_prefix="$exec_prefix" +test "x$prefix" = xNONE && prefix=$ac_default_prefix +test "x$exec_prefix" = xNONE && exec_prefix=$prefix +if test "x$CATOBJEXT" = "x.mo" ; then + localedir=`eval echo "${libdir}/locale"` +else + localedir=`eval echo "${datadir}/locale"` +fi +prefix="$glib_save_prefix" +exec_prefix="$glib_save_exec_prefix" +AC_DEFINE_UNQUOTED($1, "$localedir", + [Define the location where the catalogs will be installed]) +]) + +dnl +dnl Now the definitions that aclocal will find +dnl +ifdef(glib_configure_in,[],[ +AC_DEFUN([AM_GLIB_GNU_GETTEXT],[GLIB_GNU_GETTEXT($@)]) +AC_DEFUN([AM_GLIB_DEFINE_LOCALEDIR],[GLIB_DEFINE_LOCALEDIR($@)]) +])dnl diff --git a/m4/glibc2.m4 b/m4/glibc2.m4 new file mode 100644 index 0000000..e8f5bfe --- /dev/null +++ b/m4/glibc2.m4 @@ -0,0 +1,30 @@ +# glibc2.m4 serial 1 +dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Test for the GNU C Library, version 2.0 or newer. +# From Bruno Haible. + +AC_DEFUN([gt_GLIBC2], + [ + AC_CACHE_CHECK(whether we are using the GNU C Library 2 or newer, + ac_cv_gnu_library_2, + [AC_EGREP_CPP([Lucky GNU user], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ >= 2) + Lucky GNU user + #endif +#endif + ], + ac_cv_gnu_library_2=yes, + ac_cv_gnu_library_2=no) + ] + ) + AC_SUBST(GLIBC2) + GLIBC2="$ac_cv_gnu_library_2" + ] +) diff --git a/m4/glibc21.m4 b/m4/glibc21.m4 new file mode 100644 index 0000000..d95fd98 --- /dev/null +++ b/m4/glibc21.m4 @@ -0,0 +1,30 @@ +# glibc21.m4 serial 3 +dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Test for the GNU C Library, version 2.1 or newer. +# From Bruno Haible. + +AC_DEFUN([gl_GLIBC21], + [ + AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, + ac_cv_gnu_library_2_1, + [AC_EGREP_CPP([Lucky GNU user], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) + Lucky GNU user + #endif +#endif + ], + ac_cv_gnu_library_2_1=yes, + ac_cv_gnu_library_2_1=no) + ] + ) + AC_SUBST(GLIBC21) + GLIBC21="$ac_cv_gnu_library_2_1" + ] +) diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4 new file mode 100644 index 0000000..a9ec8f3 --- /dev/null +++ b/m4/gnulib-cache.m4 @@ -0,0 +1,35 @@ +# Copyright (C) 2002-2011 Free Software Foundation, Inc. +# +# This file is free software, distributed under the terms of the GNU +# General Public License. As a special exception to the GNU General +# Public License, this file may be distributed as part of a program +# that contains a configuration script generated by Autoconf, under +# the same distribution terms as the rest of that program. +# +# Generated by gnulib-tool. +# +# This file represents the specification of how gnulib-tool is used. +# It acts as a cache: It is written and read by gnulib-tool. +# In projects that use version control, this file is meant to be put under +# version control, like the configure.ac and various Makefile.am files. + + +# Specification in the form of a command-line invocation: +# gnulib-tool --import --dir=/home/nils/workspace/gnunet --lib=libgnu --source-base=src/util/libgnu --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=. --libtool --macro-prefix=gl strtok_r + +# Specification in the form of a few gnulib-tool.m4 macro invocations: +gl_LOCAL_DIR([]) +gl_MODULES([ + strtok_r +]) +gl_AVOID([]) +gl_SOURCE_BASE([src/util/libgnu]) +gl_M4_BASE([m4]) +gl_PO_BASE([]) +gl_DOC_BASE([doc]) +gl_TESTS_BASE([tests]) +gl_LIB([libgnu]) +gl_MAKEFILE_NAME([]) +gl_LIBTOOL +gl_MACRO_PREFIX([gl]) +gl_PO_DOMAIN([]) diff --git a/m4/gtk-2.0.m4 b/m4/gtk-2.0.m4 new file mode 100644 index 0000000..3deba01 --- /dev/null +++ b/m4/gtk-2.0.m4 @@ -0,0 +1,196 @@ +# Configure paths for GTK+ +# Owen Taylor 1997-2001 + +dnl AM_PATH_GTK_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) +dnl Test for GTK+, and define GTK_CFLAGS and GTK_LIBS, if gthread is specified in MODULES, +dnl pass to pkg-config +dnl +AC_DEFUN([AM_PATH_GTK_2_0], +[dnl +dnl Get the cflags and libraries from pkg-config +dnl +AC_ARG_ENABLE(gtktest, [ --disable-gtktest do not try to compile and run a test GTK+ program], + , enable_gtktest=yes) + + pkg_config_args=gtk+-2.0 + for module in . $4 + do + case "$module" in + gthread) + pkg_config_args="$pkg_config_args gthread-2.0" + ;; + esac + done + + no_gtk="" + + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + + if test x$PKG_CONFIG != xno ; then + if pkg-config --atleast-pkgconfig-version 0.7 ; then + : + else + echo "*** pkg-config too old; version 0.7 or better required." + no_gtk=yes + PKG_CONFIG=no + fi + else + no_gtk=yes + fi + + min_gtk_version=ifelse([$1], ,2.0.0,$1) + AC_MSG_CHECKING(for GTK+ - version >= $min_gtk_version) + + if test x$PKG_CONFIG != xno ; then + ## don't try to run the test against uninstalled libtool libs + if $PKG_CONFIG --uninstalled $pkg_config_args; then + echo "Will use uninstalled version of GTK+ found in PKG_CONFIG_PATH" + enable_gtktest=no + fi + + if $PKG_CONFIG --atleast-version $min_gtk_version $pkg_config_args; then + : + else + no_gtk=yes + fi + fi + + if test x"$no_gtk" = x ; then + GTK_CFLAGS=`$PKG_CONFIG $pkg_config_args --cflags` + GTK_LIBS=`$PKG_CONFIG $pkg_config_args --libs` + gtk_config_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + gtk_config_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + gtk_config_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_gtktest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$GTK_LIBS $LIBS" +dnl +dnl Now check if the installed GTK+ is sufficiently new. (Also sanity +dnl checks the results of pkg-config to some extent) +dnl + rm -f conf.gtktest + AC_TRY_RUN([ +#include +#include +#include + +int +main () +{ + int major, minor, micro; + char *tmp_version; + + system ("touch conf.gtktest"); + + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = g_strdup("$min_gtk_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_gtk_version"); + exit(1); + } + + if ((gtk_major_version != $gtk_config_major_version) || + (gtk_minor_version != $gtk_config_minor_version) || + (gtk_micro_version != $gtk_config_micro_version)) + { + printf("\n*** 'pkg-config --modversion gtk+-2.0' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", + $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf ("*** was found! If pkg-config was correct, then it is best\n"); + printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); + printf("*** to point to the correct configuration files\n"); + } + else if ((gtk_major_version != GTK_MAJOR_VERSION) || + (gtk_minor_version != GTK_MINOR_VERSION) || + (gtk_micro_version != GTK_MICRO_VERSION)) + { + printf("*** GTK+ header files (version %d.%d.%d) do not match\n", + GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); + printf("*** library (version %d.%d.%d)\n", + gtk_major_version, gtk_minor_version, gtk_micro_version); + } + else + { + if ((gtk_major_version > major) || + ((gtk_major_version == major) && (gtk_minor_version > minor)) || + ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GTK+, but you can also set the PKG_CONFIG environment to point to the\n"); + printf("*** correct copy of pkg-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} +],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_gtk" = x ; then + AC_MSG_RESULT(yes (version $gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version)) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$PKG_CONFIG" = "no" ; then + echo "*** A new enough version of pkg-config was not found." + echo "*** See http://pkgconfig.sourceforge.net" + else + if test -f conf.gtktest ; then + : + else + echo "*** Could not run GTK+ test program, checking why..." + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GTK+ or finding the wrong" + echo "*** version of GTK+. If it is not finding GTK+, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means GTK+ is incorrectly installed."]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GTK_CFLAGS="" + GTK_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GTK_CFLAGS) + AC_SUBST(GTK_LIBS) + rm -f conf.gtktest +]) diff --git a/m4/iconv.m4 b/m4/iconv.m4 new file mode 100644 index 0000000..654c415 --- /dev/null +++ b/m4/iconv.m4 @@ -0,0 +1,101 @@ +# iconv.m4 serial AM4 (gettext-0.11.3) +dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], +[ + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([iconv]) +]) + +AC_DEFUN([AM_ICONV_LINK], +[ + dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and + dnl those with the standalone portable GNU libiconv installed). + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + + dnl Add $INCICONV to CPPFLAGS before performing the following checks, + dnl because if the user has installed libiconv and not disabled its use + dnl via --without-libiconv-prefix, he wants to use it. The first + dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. + am_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) + + AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + AC_TRY_LINK([#include +#include ], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + am_cv_func_iconv=yes) + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include +#include ], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + am_cv_lib_iconv=yes + am_cv_func_iconv=yes) + LIBS="$am_save_LIBS" + fi + ]) + if test "$am_cv_func_iconv" = yes; then + AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) + fi + if test "$am_cv_lib_iconv" = yes; then + AC_MSG_CHECKING([how to link with libiconv]) + AC_MSG_RESULT([$LIBICONV]) + else + dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV + dnl either. + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + AC_SUBST(LIBICONV) + AC_SUBST(LTLIBICONV) +]) + +AC_DEFUN([AM_ICONV], +[ + AM_ICONV_LINK + if test "$am_cv_func_iconv" = yes; then + AC_MSG_CHECKING([for iconv declaration]) + AC_CACHE_VAL(am_cv_proto_iconv, [ + AC_TRY_COMPILE([ +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif +], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) + am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + AC_MSG_RESULT([$]{ac_t:- + }[$]am_cv_proto_iconv) + AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, + [Define as const if the declaration of iconv() needs const.]) + fi +]) diff --git a/m4/intdiv0.m4 b/m4/intdiv0.m4 new file mode 100644 index 0000000..b8d7817 --- /dev/null +++ b/m4/intdiv0.m4 @@ -0,0 +1,70 @@ +# intdiv0.m4 serial 1 (gettext-0.11.3) +dnl Copyright (C) 2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([gt_INTDIV0], +[ + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_CANONICAL_HOST])dnl + + AC_CACHE_CHECK([whether integer division by zero raises SIGFPE], + gt_cv_int_divbyzero_sigfpe, + [ + AC_TRY_RUN([ +#include +#include + +static void +#ifdef __cplusplus +sigfpe_handler (int sig) +#else +sigfpe_handler (sig) int sig; +#endif +{ + /* Exit with code 0 if SIGFPE, with code 1 if any other signal. */ + exit (sig != SIGFPE); +} + +int x = 1; +int y = 0; +int z; +int nan; + +int main () +{ + signal (SIGFPE, sigfpe_handler); +/* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP. */ +#if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP) + signal (SIGTRAP, sigfpe_handler); +#endif +/* Linux/SPARC yields signal SIGILL. */ +#if defined (__sparc__) && defined (__linux__) + signal (SIGILL, sigfpe_handler); +#endif + + z = x / y; + nan = y / y; + exit (1); +} +], gt_cv_int_divbyzero_sigfpe=yes, gt_cv_int_divbyzero_sigfpe=no, + [ + # Guess based on the CPU. + case "$host_cpu" in + alpha* | i[34567]86 | m68k | s390*) + gt_cv_int_divbyzero_sigfpe="guessing yes";; + *) + gt_cv_int_divbyzero_sigfpe="guessing no";; + esac + ]) + ]) + case "$gt_cv_int_divbyzero_sigfpe" in + *yes) value=1;; + *) value=0;; + esac + AC_DEFINE_UNQUOTED(INTDIV0_RAISES_SIGFPE, $value, + [Define if integer division by zero raises signal SIGFPE.]) +]) diff --git a/m4/intl.m4 b/m4/intl.m4 new file mode 100644 index 0000000..dcefb11 --- /dev/null +++ b/m4/intl.m4 @@ -0,0 +1,259 @@ +# intl.m4 serial 3 (gettext-0.16) +dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2006. + +AC_PREREQ(2.52) + +dnl Checks for all prerequisites of the intl subdirectory, +dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, +dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. +AC_DEFUN([AM_INTL_SUBDIR], +[ + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_CANONICAL_HOST])dnl + AC_REQUIRE([gt_GLIBC2])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([gl_VISIBILITY])dnl + AC_REQUIRE([gt_INTL_SUBDIR_CORE])dnl + AC_REQUIRE([AC_TYPE_LONG_LONG_INT])dnl + AC_REQUIRE([gt_TYPE_LONGDOUBLE])dnl + AC_REQUIRE([gt_TYPE_WCHAR_T])dnl + AC_REQUIRE([gt_TYPE_WINT_T])dnl + AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) + AC_REQUIRE([gt_TYPE_INTMAX_T]) + AC_REQUIRE([gt_PRINTF_POSIX]) + AC_REQUIRE([gl_GLIBC21])dnl + AC_REQUIRE([gl_XSIZE])dnl + AC_REQUIRE([gt_INTL_MACOSX])dnl + + AC_CHECK_TYPE([ptrdiff_t], , + [AC_DEFINE([ptrdiff_t], [long], + [Define as the type of the result of subtracting two pointers, if the system doesn't define it.]) + ]) + AC_CHECK_HEADERS([stddef.h stdlib.h string.h]) + AC_CHECK_FUNCS([asprintf fwprintf putenv setenv setlocale snprintf wcslen]) + + dnl Use the _snprintf function only if it is declared (because on NetBSD it + dnl is defined as a weak alias of snprintf; we prefer to use the latter). + gt_CHECK_DECL(_snprintf, [#include ]) + gt_CHECK_DECL(_snwprintf, [#include ]) + + dnl Use the *_unlocked functions only if they are declared. + dnl (because some of them were defined without being declared in Solaris + dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built + dnl on Solaris 2.5.1 to run on Solaris 2.6). + dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. + gt_CHECK_DECL(getc_unlocked, [#include ]) + + case $gt_cv_func_printf_posix in + *yes) HAVE_POSIX_PRINTF=1 ;; + *) HAVE_POSIX_PRINTF=0 ;; + esac + AC_SUBST([HAVE_POSIX_PRINTF]) + if test "$ac_cv_func_asprintf" = yes; then + HAVE_ASPRINTF=1 + else + HAVE_ASPRINTF=0 + fi + AC_SUBST([HAVE_ASPRINTF]) + if test "$ac_cv_func_snprintf" = yes; then + HAVE_SNPRINTF=1 + else + HAVE_SNPRINTF=0 + fi + AC_SUBST([HAVE_SNPRINTF]) + if test "$ac_cv_func_wprintf" = yes; then + HAVE_WPRINTF=1 + else + HAVE_WPRINTF=0 + fi + AC_SUBST([HAVE_WPRINTF]) + + AM_LANGINFO_CODESET + gt_LC_MESSAGES + + dnl Compilation on mingw and Cygwin needs special Makefile rules, because + dnl 1. when we install a shared library, we must arrange to export + dnl auxiliary pointer variables for every exported variable, + dnl 2. when we install a shared library and a static library simultaneously, + dnl the include file specifies __declspec(dllimport) and therefore we + dnl must arrange to define the auxiliary pointer variables for the + dnl exported variables _also_ in the static library. + if test "$enable_shared" = yes; then + case "$host_os" in + cygwin*) is_woe32dll=yes ;; + *) is_woe32dll=no ;; + esac + else + is_woe32dll=no + fi + WOE32DLL=$is_woe32dll + AC_SUBST([WOE32DLL]) + + dnl Rename some macros and functions used for locking. + AH_BOTTOM([ +#define __libc_lock_t gl_lock_t +#define __libc_lock_define gl_lock_define +#define __libc_lock_define_initialized gl_lock_define_initialized +#define __libc_lock_init gl_lock_init +#define __libc_lock_lock gl_lock_lock +#define __libc_lock_unlock gl_lock_unlock +#define __libc_lock_recursive_t gl_recursive_lock_t +#define __libc_lock_define_recursive gl_recursive_lock_define +#define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized +#define __libc_lock_init_recursive gl_recursive_lock_init +#define __libc_lock_lock_recursive gl_recursive_lock_lock +#define __libc_lock_unlock_recursive gl_recursive_lock_unlock +#define glthread_in_use libintl_thread_in_use +#define glthread_lock_init libintl_lock_init +#define glthread_lock_lock libintl_lock_lock +#define glthread_lock_unlock libintl_lock_unlock +#define glthread_lock_destroy libintl_lock_destroy +#define glthread_rwlock_init libintl_rwlock_init +#define glthread_rwlock_rdlock libintl_rwlock_rdlock +#define glthread_rwlock_wrlock libintl_rwlock_wrlock +#define glthread_rwlock_unlock libintl_rwlock_unlock +#define glthread_rwlock_destroy libintl_rwlock_destroy +#define glthread_recursive_lock_init libintl_recursive_lock_init +#define glthread_recursive_lock_lock libintl_recursive_lock_lock +#define glthread_recursive_lock_unlock libintl_recursive_lock_unlock +#define glthread_recursive_lock_destroy libintl_recursive_lock_destroy +#define glthread_once libintl_once +#define glthread_once_call libintl_once_call +#define glthread_once_singlethreaded libintl_once_singlethreaded +]) +]) + + +dnl Checks for the core files of the intl subdirectory: +dnl dcigettext.c +dnl eval-plural.h +dnl explodename.c +dnl finddomain.c +dnl gettextP.h +dnl gmo.h +dnl hash-string.h hash-string.c +dnl l10nflist.c +dnl libgnuintl.h.in (except the *printf stuff) +dnl loadinfo.h +dnl loadmsgcat.c +dnl localealias.c +dnl log.c +dnl plural-exp.h plural-exp.c +dnl plural.y +dnl Used by libglocale. +AC_DEFUN([gt_INTL_SUBDIR_CORE], +[ + AC_REQUIRE([AC_C_INLINE])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([gl_AC_HEADER_STDINT_H]) + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + AC_REQUIRE([gt_INTDIV0])dnl + AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])dnl + AC_REQUIRE([gt_INTTYPES_PRI])dnl + AC_REQUIRE([gl_LOCK])dnl + + AC_TRY_LINK( + [int foo (int a) { a = __builtin_expect (a, 10); return a == 10 ? 0 : 1; }], + [], + [AC_DEFINE([HAVE_BUILTIN_EXPECT], 1, + [Define to 1 if the compiler understands __builtin_expect.])]) + + AC_CHECK_HEADERS([argz.h inttypes.h limits.h unistd.h sys/param.h]) + AC_CHECK_FUNCS([getcwd getegid geteuid getgid getuid mempcpy munmap \ + stpcpy strcasecmp strdup strtoul tsearch argz_count argz_stringify \ + argz_next __fsetlocking]) + + dnl Use the *_unlocked functions only if they are declared. + dnl (because some of them were defined without being declared in Solaris + dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built + dnl on Solaris 2.5.1 to run on Solaris 2.6). + dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. + gt_CHECK_DECL(feof_unlocked, [#include ]) + gt_CHECK_DECL(fgets_unlocked, [#include ]) + + AM_ICONV + + dnl glibc >= 2.4 has a NL_LOCALE_NAME macro when _GNU_SOURCE is defined, + dnl and a _NL_LOCALE_NAME macro always. + AC_CACHE_CHECK([for NL_LOCALE_NAME macro], gt_cv_nl_locale_name, + [AC_TRY_LINK([#include +#include ], + [char* cs = nl_langinfo(_NL_LOCALE_NAME(LC_MESSAGES));], + gt_cv_nl_locale_name=yes, + gt_cv_nl_locale_name=no) + ]) + if test $gt_cv_nl_locale_name = yes; then + AC_DEFINE(HAVE_NL_LOCALE_NAME, 1, + [Define if you have and it defines the NL_LOCALE_NAME macro if _GNU_SOURCE is defined.]) + fi + + dnl intl/plural.c is generated from intl/plural.y. It requires bison, + dnl because plural.y uses bison specific features. It requires at least + dnl bison-1.26 because earlier versions generate a plural.c that doesn't + dnl compile. + dnl bison is only needed for the maintainer (who touches plural.y). But in + dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put + dnl the rule in general Makefile. Now, some people carelessly touch the + dnl files or have a broken "make" program, hence the plural.c rule will + dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not + dnl present or too old. + AC_CHECK_PROGS([INTLBISON], [bison]) + if test -z "$INTLBISON"; then + ac_verc_fail=yes + else + dnl Found it, now check the version. + AC_MSG_CHECKING([version of bison]) +changequote(<<,>>)dnl + ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` + case $ac_prog_version in + '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; + 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) +changequote([,])dnl + ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; + *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; + esac + AC_MSG_RESULT([$ac_prog_version]) + fi + if test $ac_verc_fail = yes; then + INTLBISON=: + fi +]) + + +dnl gt_CHECK_DECL(FUNC, INCLUDES) +dnl Check whether a function is declared. +AC_DEFUN([gt_CHECK_DECL], +[ + AC_CACHE_CHECK([whether $1 is declared], ac_cv_have_decl_$1, + [AC_TRY_COMPILE([$2], [ +#ifndef $1 + char *p = (char *) $1; +#endif +], ac_cv_have_decl_$1=yes, ac_cv_have_decl_$1=no)]) + if test $ac_cv_have_decl_$1 = yes; then + gt_value=1 + else + gt_value=0 + fi + AC_DEFINE_UNQUOTED([HAVE_DECL_]translit($1, [a-z], [A-Z]), [$gt_value], + [Define to 1 if you have the declaration of `$1', and to 0 if you don't.]) +]) diff --git a/m4/intldir.m4 b/m4/intldir.m4 new file mode 100644 index 0000000..7a28843 --- /dev/null +++ b/m4/intldir.m4 @@ -0,0 +1,19 @@ +# intldir.m4 serial 1 (gettext-0.16) +dnl Copyright (C) 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +AC_PREREQ(2.52) + +dnl Tells the AM_GNU_GETTEXT macro to consider an intl/ directory. +AC_DEFUN([AM_GNU_GETTEXT_INTL_SUBDIR], []) diff --git a/m4/intmax.m4 b/m4/intmax.m4 new file mode 100644 index 0000000..ce7a8a4 --- /dev/null +++ b/m4/intmax.m4 @@ -0,0 +1,33 @@ +# intmax.m4 serial 3 (gettext-0.16) +dnl Copyright (C) 2002-2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether the system has the 'intmax_t' type, but don't attempt to +dnl find a replacement if it is lacking. + +AC_DEFUN([gt_TYPE_INTMAX_T], +[ + AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) + AC_REQUIRE([gl_AC_HEADER_STDINT_H]) + AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t, + [AC_TRY_COMPILE([ +#include +#include +#if HAVE_STDINT_H_WITH_UINTMAX +#include +#endif +#if HAVE_INTTYPES_H_WITH_UINTMAX +#include +#endif +], [intmax_t x = -1; + return !x;], + gt_cv_c_intmax_t=yes, + gt_cv_c_intmax_t=no)]) + if test $gt_cv_c_intmax_t = yes; then + AC_DEFINE(HAVE_INTMAX_T, 1, + [Define if you have the 'intmax_t' type in or .]) + fi +]) diff --git a/m4/inttypes-pri.m4 b/m4/inttypes-pri.m4 new file mode 100644 index 0000000..7c7f894 --- /dev/null +++ b/m4/inttypes-pri.m4 @@ -0,0 +1,36 @@ +# inttypes-pri.m4 serial 4 (gettext-0.16) +dnl Copyright (C) 1997-2002, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_PREREQ(2.52) + +# Define PRI_MACROS_BROKEN if exists and defines the PRI* +# macros to non-string values. This is the case on AIX 4.3.3. + +AC_DEFUN([gt_INTTYPES_PRI], +[ + AC_CHECK_HEADERS([inttypes.h]) + if test $ac_cv_header_inttypes_h = yes; then + AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken], + gt_cv_inttypes_pri_broken, + [ + AC_TRY_COMPILE([#include +#ifdef PRId32 +char *p = PRId32; +#endif +], [], gt_cv_inttypes_pri_broken=no, gt_cv_inttypes_pri_broken=yes) + ]) + fi + if test "$gt_cv_inttypes_pri_broken" = yes; then + AC_DEFINE_UNQUOTED(PRI_MACROS_BROKEN, 1, + [Define if exists and defines unusable PRI* macros.]) + PRI_MACROS_BROKEN=1 + else + PRI_MACROS_BROKEN=0 + fi + AC_SUBST([PRI_MACROS_BROKEN]) +]) diff --git a/m4/inttypes.m4 b/m4/inttypes.m4 new file mode 100644 index 0000000..ab370ff --- /dev/null +++ b/m4/inttypes.m4 @@ -0,0 +1,27 @@ +# inttypes.m4 serial 1 (gettext-0.11.4) +dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Paul Eggert. + +# Define HAVE_INTTYPES_H if exists and doesn't clash with +# . + +AC_DEFUN([gt_HEADER_INTTYPES_H], +[ + AC_CACHE_CHECK([for inttypes.h], gt_cv_header_inttypes_h, + [ + AC_TRY_COMPILE( + [#include +#include ], + [], gt_cv_header_inttypes_h=yes, gt_cv_header_inttypes_h=no) + ]) + if test $gt_cv_header_inttypes_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1, + [Define if exists and doesn't clash with .]) + fi +]) diff --git a/m4/inttypes_h.m4 b/m4/inttypes_h.m4 new file mode 100644 index 0000000..edc8ecb --- /dev/null +++ b/m4/inttypes_h.m4 @@ -0,0 +1,26 @@ +# inttypes_h.m4 serial 7 +dnl Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_INTTYPES_H_WITH_UINTMAX if exists, +# doesn't clash with , and declares uintmax_t. + +AC_DEFUN([gl_AC_HEADER_INTTYPES_H], +[ + AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h, + [AC_TRY_COMPILE( + [#include +#include ], + [uintmax_t i = (uintmax_t) -1; return !i;], + gl_cv_header_inttypes_h=yes, + gl_cv_header_inttypes_h=no)]) + if test $gl_cv_header_inttypes_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1, + [Define if exists, doesn't clash with , + and declares uintmax_t. ]) + fi +]) diff --git a/m4/isc-posix.m4 b/m4/isc-posix.m4 new file mode 100644 index 0000000..1319dd1 --- /dev/null +++ b/m4/isc-posix.m4 @@ -0,0 +1,26 @@ +# isc-posix.m4 serial 2 (gettext-0.11.2) +dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +# This file is not needed with autoconf-2.53 and newer. Remove it in 2005. + +# This test replaces the one in autoconf. +# Currently this macro should have the same name as the autoconf macro +# because gettext's gettext.m4 (distributed in the automake package) +# still uses it. Otherwise, the use in gettext.m4 makes autoheader +# give these diagnostics: +# configure.in:556: AC_TRY_COMPILE was called before AC_ISC_POSIX +# configure.in:556: AC_TRY_RUN was called before AC_ISC_POSIX + +undefine([AC_ISC_POSIX]) + +AC_DEFUN([AC_ISC_POSIX], + [ + dnl This test replaces the obsolescent AC_ISC_POSIX kludge. + AC_CHECK_LIB(cposix, strerror, [LIBS="$LIBS -lcposix"]) + ] +) diff --git a/m4/lcmessage.m4 b/m4/lcmessage.m4 new file mode 100644 index 0000000..19aa77e --- /dev/null +++ b/m4/lcmessage.m4 @@ -0,0 +1,30 @@ +# lcmessage.m4 serial 4 (gettext-0.14.2) +dnl Copyright (C) 1995-2002, 2004-2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995. + +# Check whether LC_MESSAGES is available in . + +AC_DEFUN([gt_LC_MESSAGES], +[ + AC_CACHE_CHECK([for LC_MESSAGES], gt_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + gt_cv_val_LC_MESSAGES=yes, gt_cv_val_LC_MESSAGES=no)]) + if test $gt_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, + [Define if your file defines LC_MESSAGES.]) + fi +]) diff --git a/m4/lib-ld.m4 b/m4/lib-ld.m4 new file mode 100644 index 0000000..96c4e2c --- /dev/null +++ b/m4/lib-ld.m4 @@ -0,0 +1,110 @@ +# lib-ld.m4 serial 3 (gettext-0.13) +dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Subroutines of libtool.m4, +dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision +dnl with libtool.m4. + +dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. +AC_DEFUN([AC_LIB_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +case `$LD -v 2>&1 conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + [re_direlt='/[^/][^/]*/\.\./'] + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(acl_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break ;; + *) + test "$with_gnu_ld" != yes && break ;; + esac + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$acl_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_LIB_PROG_LD_GNU +]) diff --git a/m4/lib-link.m4 b/m4/lib-link.m4 new file mode 100644 index 0000000..f95b7ba --- /dev/null +++ b/m4/lib-link.m4 @@ -0,0 +1,644 @@ +# lib-link.m4 serial 9 (gettext-0.16) +dnl Copyright (C) 2001-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_PREREQ(2.50) + +dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and +dnl augments the CPPFLAGS variable. +AC_DEFUN([AC_LIB_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + ac_cv_lib[]Name[]_libs="$LIB[]NAME" + ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" + ac_cv_lib[]Name[]_cppflags="$INC[]NAME" + ]) + LIB[]NAME="$ac_cv_lib[]Name[]_libs" + LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" + INC[]NAME="$ac_cv_lib[]Name[]_cppflags" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the + dnl results of this search when this library appears as a dependency. + HAVE_LIB[]NAME=yes + undefine([Name]) + undefine([NAME]) +]) + +dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) +dnl searches for libname and the libraries corresponding to explicit and +dnl implicit dependencies, together with the specified include files and +dnl the ability to compile and link the specified testcode. If found, it +dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and +dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and +dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs +dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. +AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + + dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + + dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, + dnl because if the user has installed lib[]Name and not disabled its use + dnl via --without-lib[]Name-prefix, he wants to use it. + ac_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + + AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIB[]NAME" + AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) + LIBS="$ac_save_LIBS" + ]) + if test "$ac_cv_lib[]Name" = yes; then + HAVE_LIB[]NAME=yes + AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) + AC_MSG_CHECKING([how to link with lib[]$1]) + AC_MSG_RESULT([$LIB[]NAME]) + else + HAVE_LIB[]NAME=no + dnl If $LIB[]NAME didn't lead to a usable library, we don't need + dnl $INC[]NAME either. + CPPFLAGS="$ac_save_CPPFLAGS" + LIB[]NAME= + LTLIB[]NAME= + fi + AC_SUBST([HAVE_LIB]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + undefine([Name]) + undefine([NAME]) +]) + +dnl Determine the platform dependent parameters needed to use rpath: +dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, +dnl hardcode_direct, hardcode_minus_L. +AC_DEFUN([AC_LIB_RPATH], +[ + dnl Tell automake >= 1.10 to complain if config.rpath is missing. + m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) + AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS + AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir + AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + ]) + wl="$acl_cv_wl" + libext="$acl_cv_libext" + shlibext="$acl_cv_shlibext" + hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + hardcode_direct="$acl_cv_hardcode_direct" + hardcode_minus_L="$acl_cv_hardcode_minus_L" + dnl Determine whether the user wants rpath handling at all. + AC_ARG_ENABLE(rpath, + [ --disable-rpath do not hardcode runtime library paths], + :, enable_rpath=yes) +]) + +dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. +AC_DEFUN([AC_LIB_LINKFLAGS_BODY], +[ + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib$1-prefix], +[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib + --without-lib$1-prefix don't search for lib$1 in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi +]) + dnl Search the library and its dependencies in $additional_libdir and + dnl $LDFLAGS. Using breadth-first-seach. + LIB[]NAME= + LTLIB[]NAME= + INC[]NAME= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='$1 $2' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + dnl See if it was already located by an earlier AC_LIB_LINKFLAGS + dnl or AC_LIB_HAVE_LINKFLAGS call. + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" + else + dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined + dnl that this library doesn't exist. So just drop it. + : + fi + else + dnl Search the library lib$name in $additional_libdir and $LDFLAGS + dnl and the already constructed $LIBNAME/$LTLIBNAME. + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" \ + && { test -f "$additional_libdir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$additional_libdir/lib$name.dll.a"; }; }; then + found_dir="$additional_libdir" + if test -f "$additional_libdir/lib$name.$shlibext"; then + found_so="$additional_libdir/lib$name.$shlibext" + else + found_so="$additional_libdir/lib$name.dll.a" + fi + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" \ + && { test -f "$dir/lib$name.$shlibext" \ + || { test "$shlibext" = dll \ + && test -f "$dir/lib$name.dll.a"; }; }; then + found_dir="$dir" + if test -f "$dir/lib$name.$shlibext"; then + found_so="$dir/lib$name.$shlibext" + else + found_so="$dir/lib$name.dll.a" + fi + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + dnl Found the library. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + dnl Linking with a shared library. We attempt to hardcode its + dnl directory into the executable's runpath, unless it's the + dnl standard /usr/lib. + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then + dnl No hardcoding is needed. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + dnl The hardcoding into $LIBNAME is system dependent. + if test "$hardcode_direct" = yes; then + dnl Using DIR/libNAME.so during linking hardcodes DIR into the + dnl resulting binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + dnl Rely on "-L$found_dir". + dnl But don't add it if it's already contained in the LDFLAGS + dnl or the already constructed $LIBNAME + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH + dnl here, because this doesn't fit in flags passed to the + dnl compiler. So give up. No hardcoding. This affects only + dnl very old systems. + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + dnl Linking with a static library. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" + else + dnl We shouldn't come here, but anyway it's good to have a + dnl fallback. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" + fi + fi + dnl Assume the include files are nearby. + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + dnl Potentially add $additional_includedir to $INCNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's /usr/local/include and we are using GCC on Linux, + dnl 3. if it's already present in $CPPFLAGS or the already + dnl constructed $INCNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INC[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $INCNAME. + INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + dnl Look for dependencies. + if test -n "$found_la"; then + dnl Read the .la file. It defines the variables + dnl dlname, library_names, old_library, dependency_libs, current, + dnl age, revision, installed, dlopen, dlpreopen, libdir. + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + dnl We use only dependency_libs. + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's /usr/local/lib and we are using GCC on Linux, + dnl 3. if it's already present in $LDFLAGS or the already + dnl constructed $LIBNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LIBNAME. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LTLIBNAME. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + dnl Handle this in the next round. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + dnl Handle this in the next round. Throw away the .la's + dnl directory; it is already contained in a preceding -L + dnl option. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + dnl Most likely an immediate library name. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" + ;; + esac + done + fi + else + dnl Didn't find the library; assume it is in the system directories + dnl known to the linker and runtime loader. (All the system + dnl directories known to the linker should also be known to the + dnl runtime loader, otherwise the system is severely misconfigured.) + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user must + dnl pass all path elements in one option. We can arrange that for a + dnl single library, but not when more than one $LIBNAMEs are used. + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + else + dnl The -rpath options are cumulative. + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + dnl When using libtool, the option that works for both libraries and + dnl executables is -R. The -R options are cumulative. + for found_dir in $ltrpathdirs; do + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" + done + fi +]) + +dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, +dnl unless already present in VAR. +dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes +dnl contains two or three consecutive elements that belong together. +AC_DEFUN([AC_LIB_APPENDTOVAR], +[ + for element in [$2]; do + haveit= + for x in $[$1]; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + [$1]="${[$1]}${[$1]:+ }$element" + fi + done +]) + +dnl For those cases where a variable contains several -L and -l options +dnl referring to unknown libraries and directories, this macro determines the +dnl necessary additional linker options for the runtime path. +dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) +dnl sets LDADDVAR to linker options needed together with LIBSVALUE. +dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, +dnl otherwise linking without libtool is assumed. +AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], +[ + AC_REQUIRE([AC_LIB_RPATH]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + $1= + if test "$enable_rpath" != no; then + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode directories into the resulting + dnl binary. + rpathdirs= + next= + for opt in $2; do + if test -n "$next"; then + dir="$next" + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem"; then + rpathdirs="$rpathdirs $dir" + fi + next= + else + case $opt in + -L) next=yes ;; + -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem"; then + rpathdirs="$rpathdirs $dir" + fi + next= ;; + *) next= ;; + esac + fi + done + if test "X$rpathdirs" != "X"; then + if test -n ""$3""; then + dnl libtool is used for linking. Use -R options. + for dir in $rpathdirs; do + $1="${$1}${$1:+ }-R$dir" + done + else + dnl The linker is used for linking directly. + if test -n "$hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user + dnl must pass all path elements in one option. + alldirs= + for dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="$flag" + else + dnl The -rpath options are cumulative. + for dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="${$1}${$1:+ }$flag" + done + fi + fi + fi + fi + fi + AC_SUBST([$1]) +]) diff --git a/m4/lib-prefix.m4 b/m4/lib-prefix.m4 new file mode 100644 index 0000000..a8684e1 --- /dev/null +++ b/m4/lib-prefix.m4 @@ -0,0 +1,185 @@ +# lib-prefix.m4 serial 5 (gettext-0.15) +dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and +dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't +dnl require excessive bracketing. +ifdef([AC_HELP_STRING], +[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], +[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) + +dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed +dnl to access previously installed libraries. The basic assumption is that +dnl a user will want packages to use other packages he previously installed +dnl with the same --prefix option. +dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate +dnl libraries, but is otherwise very convenient. +AC_DEFUN([AC_LIB_PREFIX], +[ + AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib-prefix], +[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib + --without-lib-prefix don't search for libraries in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi +]) + if test $use_additional = yes; then + dnl Potentially add $additional_includedir to $CPPFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's already present in $CPPFLAGS, + dnl 3. if it's /usr/local/include and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + for x in $CPPFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $CPPFLAGS. + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" + fi + fi + fi + fi + dnl Potentially add $additional_libdir to $LDFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's already present in $LDFLAGS, + dnl 3. if it's /usr/local/lib and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + for x in $LDFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LDFLAGS. + LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" + fi + fi + fi + fi + fi +]) + +dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, +dnl acl_final_exec_prefix, containing the values to which $prefix and +dnl $exec_prefix will expand at the end of the configure script. +AC_DEFUN([AC_LIB_PREPARE_PREFIX], +[ + dnl Unfortunately, prefix and exec_prefix get only finally determined + dnl at the end of configure. + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the +dnl variables prefix and exec_prefix bound to the values they will have +dnl at the end of the configure script. +AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], +[ + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + $1 + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing +dnl the basename of the libdir, either "lib" or "lib64". +AC_DEFUN([AC_LIB_PREPARE_MULTILIB], +[ + dnl There is no formal standard regarding lib and lib64. The current + dnl practice is that on a system supporting 32-bit and 64-bit instruction + dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit + dnl libraries go under $prefix/lib. We determine the compiler's default + dnl mode by looking at the compiler's library search path. If at least + dnl of its elements ends in /lib64 or points to a directory whose absolute + dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the + dnl default, namely "lib". + acl_libdirstem=lib + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi +]) diff --git a/m4/libcurl.m4 b/m4/libcurl.m4 new file mode 100644 index 0000000..01a0575 --- /dev/null +++ b/m4/libcurl.m4 @@ -0,0 +1,250 @@ +# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION], +# [ACTION-IF-YES], [ACTION-IF-NO]) +# ---------------------------------------------------------- +# David Shaw May-09-2006 +# +# Checks for libcurl. DEFAULT-ACTION is the string yes or no to +# specify whether to default to --with-libcurl or --without-libcurl. +# If not supplied, DEFAULT-ACTION is yes. MINIMUM-VERSION is the +# minimum version of libcurl to accept. Pass the version as a regular +# version number like 7.10.1. If not supplied, any version is +# accepted. ACTION-IF-YES is a list of shell commands to run if +# libcurl was successfully found and passed the various tests. +# ACTION-IF-NO is a list of shell commands that are run otherwise. +# Note that using --without-libcurl does run ACTION-IF-NO. +# +# This macro #defines HAVE_LIBCURL if a working libcurl setup is +# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary +# values. Other useful defines are LIBCURL_FEATURE_xxx where xxx are +# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy +# where yyy are the various protocols supported by libcurl. Both xxx +# and yyy are capitalized. See the list of AH_TEMPLATEs at the top of +# the macro for the complete list of possible defines. Shell +# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also +# defined to 'yes' for those features and protocols that were found. +# Note that xxx and yyy keep the same capitalization as in the +# curl-config list (e.g. it's "HTTP" and not "http"). +# +# Users may override the detected values by doing something like: +# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure +# +# For the sake of sanity, this macro assumes that any libcurl that is +# found is after version 7.7.2, the first version that included the +# curl-config script. Note that it is very important for people +# packaging binary versions of libcurl to include this script! +# Without curl-config, we can only guess what protocols are available, +# or use curl_version_info to figure it out at runtime. + +AC_DEFUN([LIBCURL_CHECK_CONFIG], +[ + AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL]) + AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4]) + AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6]) + AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz]) + AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS]) + AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN]) + AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI]) + AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM]) + + AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE]) + AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET]) + AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT]) + AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3]) + AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP]) + + AC_ARG_WITH(libcurl, + AC_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]), + [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])]) + + if test "$_libcurl_with" != "no" ; then + + AC_PROG_AWK + + _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'" + + _libcurl_try_link=yes + + if test -d "$_libcurl_with" ; then + LIBCURL_CPPFLAGS="-I$withval/include" + _libcurl_ldflags="-L$withval/lib" + AC_PATH_PROG([_libcurl_config],[curl-config],[], + ["$withval/bin"]) + else + AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH]) + fi + + if test x$_libcurl_config != "x" ; then + AC_CACHE_CHECK([for the version of libcurl], + [libcurl_cv_lib_curl_version], + [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`]) + + _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse` + _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse` + + if test $_libcurl_wanted -gt 0 ; then + AC_CACHE_CHECK([for libcurl >= version $2], + [libcurl_cv_lib_version_ok], + [ + if test $_libcurl_version -ge $_libcurl_wanted ; then + libcurl_cv_lib_version_ok=yes + else + libcurl_cv_lib_version_ok=no + fi + ]) + fi + + if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then + if test x"$LIBCURL_CPPFLAGS" = "x" ; then + LIBCURL_CPPFLAGS=`$_libcurl_config --cflags` + fi + if test x"$LIBCURL" = "x" ; then + LIBCURL=`$_libcurl_config --libs` + + # This is so silly, but Apple actually has a bug in their + # curl-config script. Fixed in Tiger, but there are still + # lots of Panther installs around. + case "${host}" in + powerpc-apple-darwin7*) + LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'` + ;; + esac + fi + + # All curl-config scripts support --feature + _libcurl_features=`$_libcurl_config --feature` + + # Is it modern enough to have --protocols? (7.12.4) + if test $_libcurl_version -ge 461828 ; then + _libcurl_protocols=`$_libcurl_config --protocols` + fi + else + _libcurl_try_link=no + fi + + unset _libcurl_wanted + fi + + if test $_libcurl_try_link = yes ; then + + # we didn't find curl-config, so let's see if the user-supplied + # link line (or failing that, "-lcurl") is enough. + LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} + + AC_CACHE_CHECK([whether libcurl is usable], + [libcurl_cv_lib_curl_usable], + [ + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBCURL $LIBS" + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ],[ +/* Try and use a few common options to force a failure if we are + missing symbols or can't link. */ +int x; +curl_easy_setopt(NULL,CURLOPT_URL,NULL); +x=CURL_ERROR_SIZE; +x=CURLOPT_WRITEFUNCTION; +x=CURLOPT_FILE; +x=CURLOPT_ERRORBUFFER; +x=CURLOPT_STDERR; +x=CURLOPT_VERBOSE; +])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + ]) + + if test $libcurl_cv_lib_curl_usable = yes ; then + + # Does curl_free() exist in this version of libcurl? + # If not, fake it with free() + + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBS $LIBCURL" + + AC_CHECK_FUNC(curl_free,, + AC_DEFINE(curl_free,free, + [Define curl_free() as free() if our version of curl lacks curl_free.])) + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + + AC_DEFINE(HAVE_LIBCURL,1, + [Define to 1 if you have a functional curl library.]) + AC_SUBST(LIBCURL_CPPFLAGS) + AC_SUBST(LIBCURL) + + for _libcurl_feature in $_libcurl_features ; do + AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1]) + eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes + done + + if test "x$_libcurl_protocols" = "x" ; then + + # We don't have --protocols, so just assume that all + # protocols are available + _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" + + if test x$libcurl_feature_SSL = xyes ; then + _libcurl_protocols="$_libcurl_protocols HTTPS" + + # FTPS wasn't standards-compliant until version + # 7.11.0 (0x070b00 == 461568) + if test $_libcurl_version -ge 461568; then + _libcurl_protocols="$_libcurl_protocols FTPS" + fi + fi + + # RTSP, IMAP, POP3 and SMTP were added in + # 7.20.0 (0x071400 == 463872) + if test $_libcurl_version -ge 463872; then + _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" + fi + fi + + for _libcurl_protocol in $_libcurl_protocols ; do + AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1]) + eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes + done + else + unset LIBCURL + unset LIBCURL_CPPFLAGS + fi + fi + + unset _libcurl_try_link + unset _libcurl_version_parse + unset _libcurl_config + unset _libcurl_feature + unset _libcurl_features + unset _libcurl_protocol + unset _libcurl_protocols + unset _libcurl_version + unset _libcurl_ldflags + fi + + if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then + # This is the IF-NO path + ifelse([$4],,:,[$4]) + else + # This is the IF-YES path + ifelse([$3],,:,[$3]) + fi + + unset _libcurl_with +])dnl diff --git a/m4/libgcrypt.m4 b/m4/libgcrypt.m4 new file mode 100644 index 0000000..20bd105 --- /dev/null +++ b/m4/libgcrypt.m4 @@ -0,0 +1,108 @@ +dnl Autoconf macros for libgcrypt +dnl Copyright (C) 2002, 2004 Free Software Foundation, Inc. +dnl +dnl This file is free software; as a special exception the author gives +dnl unlimited permission to copy and/or distribute it, with or without +dnl modifications, as long as this notice is preserved. +dnl +dnl This file is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + +dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS. +dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed +dnl with the API version to also check the API compatibility. Example: +dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed +dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using +dnl this features allows to prevent build against newer versions of libgcrypt +dnl with a changed API. +dnl +AC_DEFUN([AM_PATH_LIBGCRYPT], +[ AC_ARG_WITH(libgcrypt-prefix, + AC_HELP_STRING([--with-libgcrypt-prefix=PFX], + [prefix where LIBGCRYPT is installed (optional)]), + libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="") + if test x$libgcrypt_config_prefix != x ; then + if test x${LIBGCRYPT_CONFIG+set} != xset ; then + LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config + fi + fi + + AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config, no) + tmp=ifelse([$1], ,1:1.2.0,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_libgcrypt_api=0 + min_libgcrypt_version="$tmp" + fi + + AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version) + ok=no + if test "$LIBGCRYPT_CONFIG" != "no" ; then + req_major=`echo $min_libgcrypt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_libgcrypt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_libgcrypt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version` + major=`echo $libgcrypt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + minor=`echo $libgcrypt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` + micro=`echo $libgcrypt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'` + if test "$major" -gt "$req_major"; then + ok=yes + else + if test "$major" -eq "$req_major"; then + if test "$minor" -gt "$req_minor"; then + ok=yes + else + if test "$minor" -eq "$req_minor"; then + if test "$micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + if test $ok = yes; then + # If we have a recent libgcrypt, we should also check that the + # API is compatible + if test "$req_libgcrypt_api" -gt 0 ; then + tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + AC_MSG_CHECKING([LIBGCRYPT API version]) + if test "$req_libgcrypt_api" -eq "$tmp" ; then + AC_MSG_RESULT(okay) + else + ok=no + AC_MSG_RESULT([does not match (want=$req_libgcrypt_api got=$tmp)]) + fi + fi + fi + fi + if test $ok = yes; then + LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags` + LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs` + ifelse([$2], , :, [$2]) + else + LIBGCRYPT_CFLAGS="" + LIBGCRYPT_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(LIBGCRYPT_CFLAGS) + AC_SUBST(LIBGCRYPT_LIBS) +]) diff --git a/m4/libtool.m4 b/m4/libtool.m4 new file mode 100644 index 0000000..a3fee53 --- /dev/null +++ b/m4/libtool.m4 @@ -0,0 +1,7377 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 56 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl +_LT_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\[$]0 --fallback-echo"')dnl " + lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` + ;; +esac + +_LT_OUTPUT_LIBTOOL_INIT +]) + + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +cat >"$CONFIG_LT" <<_LTEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate a libtool stub with the current configuration. + +lt_cl_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AS_SHELL_SANITIZE +_AS_PREPARE + +exec AS_MESSAGE_FD>&1 +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +if test "$no_create" != yes; then + lt_cl_success=: + test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" + exec AS_MESSAGE_LOG_FD>/dev/null + $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false + exec AS_MESSAGE_LOG_FD>>config.log + $lt_cl_success || AS_EXIT(1) +fi +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_XSI_SHELLFNS + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES +# -------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX +# ----------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_SHELL_INIT + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[_LT_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +[$]* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(lt_ECHO) +]) +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], + [An echo program that does not interpret backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[AC_CHECK_TOOL(AR, ar, false) +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1]) + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method == "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac +AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE(int foo(void) {}, + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + ) + LDFLAGS="$save_LDFLAGS" + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], + [[If ld is used when linking, flag to hardcode $libdir into a binary + during linking. This must work even if $libdir does not exist]]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [fix_srcfile_path], [1], + [Fix the shell variable $srcfile for the compiler]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_PROG_CXX +# ------------ +# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ +# compiler, we have our own version here. +m4_defun([_LT_PROG_CXX], +[ +pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) +AC_PROG_CXX +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_CXX + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_CXX], []) + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[AC_REQUIRE([_LT_PROG_CXX])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +]) +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_PROG_F77 +# ------------ +# Since AC_PROG_F77 is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_F77], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) +AC_PROG_F77 +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_F77 + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_F77], []) + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_REQUIRE([_LT_PROG_F77])dnl +AC_LANG_PUSH(Fortran 77) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${F77-"f77"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_PROG_FC +# ----------- +# Since AC_PROG_FC is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_FC], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) +AC_PROG_FC +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_FC + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_FC], []) + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_REQUIRE([_LT_PROG_FC])dnl +AC_LANG_PUSH(Fortran) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${FC-"f95"} + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC="$lt_save_CC" +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC="$lt_save_CC" +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_XSI_SHELLFNS +# --------------------- +# Bourne and XSI compatible variants of some useful shell functions. +m4_defun([_LT_PROG_XSI_SHELLFNS], +[case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $[*] )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +dnl func_dirname_and_basename +dnl A portable version of this function is already defined in general.m4sh +dnl so there is no need for it here. + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[[^=]]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$[@]"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]+=\$[2]" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]=\$$[1]\$[2]" +} + +_LT_EOF + ;; + esac +]) diff --git a/m4/libunistring.m4 b/m4/libunistring.m4 new file mode 100644 index 0000000..c1bf4d5 --- /dev/null +++ b/m4/libunistring.m4 @@ -0,0 +1,150 @@ +# libunistring.m4 serial 11 +dnl Copyright (C) 2009-2012 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl gl_LIBUNISTRING +dnl Searches for an installed libunistring. +dnl If found, it sets and AC_SUBSTs HAVE_LIBUNISTRING=yes and the LIBUNISTRING +dnl and LTLIBUNISTRING variables, sets the LIBUNISTRING_VERSION variable, and +dnl augments the CPPFLAGS variable, and #defines HAVE_LIBUNISTRING to 1. +dnl Otherwise, it sets and AC_SUBSTs HAVE_LIBUNISTRING=no and LIBUNISTRING and +dnl LTLIBUNISTRING to empty. + +dnl Define gl_LIBUNISTRING using AC_DEFUN_ONCE for Autoconf >= 2.64, in order +dnl to avoid warnings like +dnl "warning: AC_REQUIRE: `gl_LIBUNISTRING' was expanded before it was required". +dnl This is tricky because of the way 'aclocal' is implemented: +dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. +dnl Otherwise aclocal's initial scan pass would miss the macro definition. +dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. +dnl Otherwise aclocal would emit many "Use of uninitialized value $1" +dnl warnings. +m4_define([gl_libunistring_AC_DEFUN], + m4_version_prereq([2.64], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [m4_ifdef([gl_00GNULIB], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [[AC_DEFUN( + [$1], [$2])]])])) +gl_libunistring_AC_DEFUN([gl_LIBUNISTRING], +[ + AC_BEFORE([$0], [gl_LIBUNISTRING_MODULE]) + AC_BEFORE([$0], [gl_LIBUNISTRING_LIBHEADER]) + AC_BEFORE([$0], [gl_LIBUNISTRING_LIB_PREPARE]) + + m4_ifdef([gl_LIBUNISTRING_OPTIONAL], + [ + AC_MSG_CHECKING([whether included libunistring is requested]) + AC_ARG_WITH([included-libunistring], + [ --with-included-libunistring use the libunistring parts included here], + [gl_libunistring_force_included=$withval], + [gl_libunistring_force_included=no]) + AC_MSG_RESULT([$gl_libunistring_force_included]) + gl_libunistring_use_included="$gl_libunistring_force_included" + if test "$gl_libunistring_use_included" = yes; then + dnl Assume that libunistring is not installed until some other macro + dnl explicitly invokes gl_LIBUNISTRING_CORE. + if test -z "$HAVE_LIBUNISTRING"; then + HAVE_LIBUNISTRING=no + fi + LIBUNISTRING= + LTLIBUNISTRING= + else + gl_LIBUNISTRING_CORE + if test $HAVE_LIBUNISTRING = no; then + gl_libunistring_use_included=yes + LIBUNISTRING= + LTLIBUNISTRING= + fi + fi + ], + [gl_LIBUNISTRING_CORE]) +]) + +AC_DEFUN([gl_LIBUNISTRING_CORE], +[ + AC_REQUIRE([AM_ICONV]) + if test -n "$LIBICONV"; then + dnl First, try to link without -liconv. libunistring often depends on + dnl libiconv, but we don't know (and often don't need to know) where + dnl libiconv is installed. + AC_LIB_HAVE_LINKFLAGS([unistring], [], + [#include ], [u8_strconv_from_locale((char*)0);], + [no, trying again together with libiconv]) + if test "$ac_cv_libunistring" != yes; then + dnl Second try, with -liconv. + dnl We have to erase the cached result of the first AC_LIB_HAVE_LINKFLAGS + dnl invocation, otherwise the second one will not be run. + unset ac_cv_libunistring + glus_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + AC_LIB_HAVE_LINKFLAGS([unistring], [], + [#include ], [u8_strconv_from_locale((char*)0);], + [no, consider installing GNU libunistring]) + if test -n "$LIBUNISTRING"; then + LIBUNISTRING="$LIBUNISTRING $LIBICONV" + LTLIBUNISTRING="$LTLIBUNISTRING $LTLIBICONV" + fi + LIBS="$glus_save_LIBS" + fi + else + AC_LIB_HAVE_LINKFLAGS([unistring], [], + [#include ], [u8_strconv_from_locale((char*)0);], + [no, consider installing GNU libunistring]) + fi + if test $HAVE_LIBUNISTRING = yes; then + dnl Determine the installed version. + AC_CACHE_CHECK([for libunistring version], [gl_cv_libunistring_version], + [AC_COMPUTE_INT([gl_libunistring_hexversion], + [_LIBUNISTRING_VERSION], + [#include ]) + dnl Versions <= 0.9.3 had a hexversion of 0x0009. + dnl Use other tests to distinguish them. + if test $gl_libunistring_hexversion = 9; then + dnl Version 0.9.2 introduced the header . + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include ]], [[]])], + [gl_cv_libunistring_version092=true], + [gl_cv_libunistring_version092=false]) + if $gl_cv_libunistring_version092; then + dnl Version 0.9.3 changed a comment in . + gl_ABSOLUTE_HEADER_ONE([unistr.h]) + if test -n "$gl_cv_absolute_unistr_h" \ + && grep 'Copy no more than N units of SRC to DEST. Return a pointer' $gl_cv_absolute_unistr_h > /dev/null; then + dnl Detected version 0.9.3. + gl_libunistring_hexversion=2307 + else + dnl Detected version 0.9.2. + gl_libunistring_hexversion=2306 + fi + else + dnl Version 0.9.1 introduced the type casing_suffix_context_t. + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + casing_suffix_context_t ct;]], + [[]])], + [gl_cv_libunistring_version091=true], + [gl_cv_libunistring_version091=false]) + if $gl_cv_libunistring_version091; then + dnl Detected version 0.9.1. + gl_libunistring_hexversion=2305 + else + dnl Detected version 0.9. + gl_libunistring_hexversion=2304 + fi + fi + fi + dnl Transform into the usual major.minor.subminor notation. + gl_libunistring_major=`expr $gl_libunistring_hexversion / 65536` + gl_libunistring_minor=`expr $gl_libunistring_hexversion / 256 % 256` + gl_libunistring_subminor=`expr $gl_libunistring_hexversion % 256` + gl_cv_libunistring_version="$gl_libunistring_major.$gl_libunistring_minor.$gl_libunistring_subminor" + ]) + LIBUNISTRING_VERSION="$gl_cv_libunistring_version" + fi +]) diff --git a/m4/libxml2.m4 b/m4/libxml2.m4 new file mode 100644 index 0000000..68cd824 --- /dev/null +++ b/m4/libxml2.m4 @@ -0,0 +1,188 @@ +# Configure paths for LIBXML2 +# Mike Hommey 2004-06-19 +# use CPPFLAGS instead of CFLAGS +# Toshio Kuratomi 2001-04-21 +# Adapted from: +# Configure paths for GLIB +# Owen Taylor 97-11-3 + +dnl AM_PATH_XML2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for XML, and define XML_CPPFLAGS and XML_LIBS +dnl +AC_DEFUN([AM_PATH_XML2],[ +AC_ARG_WITH(xml-prefix, + [ --with-xml-prefix=PFX Prefix where libxml is installed (optional)], + xml_config_prefix="$withval", xml_config_prefix="") +AC_ARG_WITH(xml-exec-prefix, + [ --with-xml-exec-prefix=PFX Exec prefix where libxml is installed (optional)], + xml_config_exec_prefix="$withval", xml_config_exec_prefix="") +AC_ARG_ENABLE(xmltest, + [ --disable-xmltest Do not try to compile and run a test LIBXML program],, + enable_xmltest=yes) + + if test x$xml_config_exec_prefix != x ; then + xml_config_args="$xml_config_args" + if test x${XML2_CONFIG+set} != xset ; then + XML2_CONFIG=$xml_config_exec_prefix/bin/xml2-config + fi + fi + if test x$xml_config_prefix != x ; then + xml_config_args="$xml_config_args --prefix=$xml_config_prefix" + if test x${XML2_CONFIG+set} != xset ; then + XML2_CONFIG=$xml_config_prefix/bin/xml2-config + fi + fi + + AC_PATH_PROG(XML2_CONFIG, xml2-config, no) + min_xml_version=ifelse([$1], ,2.0.0,[$1]) + AC_MSG_CHECKING(for libxml - version >= $min_xml_version) + no_xml="" + if test "$XML2_CONFIG" = "no" ; then + no_xml=yes + else + XML_CPPFLAGS=`$XML2_CONFIG $xml_config_args --cflags` + XML_LIBS=`$XML2_CONFIG $xml_config_args --libs` + xml_config_major_version=`$XML2_CONFIG $xml_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + xml_config_minor_version=`$XML2_CONFIG $xml_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + xml_config_micro_version=`$XML2_CONFIG $xml_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_xmltest" = "xyes" ; then + ac_save_CPPFLAGS="$CPPFLAGS" + ac_save_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $XML_CPPFLAGS" + LIBS="$XML_LIBS $LIBS" +dnl +dnl Now check if the installed libxml is sufficiently new. +dnl (Also sanity checks the results of xml2-config to some extent) +dnl + rm -f conf.xmltest + AC_TRY_RUN([ +#include +#include +#include +#include + +int +main() +{ + int xml_major_version, xml_minor_version, xml_micro_version; + int major, minor, micro; + char *tmp_version; + + system("touch conf.xmltest"); + + /* Capture xml2-config output via autoconf/configure variables */ + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = (char *)strdup("$min_xml_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string from xml2-config\n", "$min_xml_version"); + exit(1); + } + free(tmp_version); + + /* Capture the version information from the header files */ + tmp_version = (char *)strdup(LIBXML_DOTTED_VERSION); + if (sscanf(tmp_version, "%d.%d.%d", &xml_major_version, &xml_minor_version, &xml_micro_version) != 3) { + printf("%s, bad version string from libxml includes\n", "LIBXML_DOTTED_VERSION"); + exit(1); + } + free(tmp_version); + + /* Compare xml2-config output to the libxml headers */ + if ((xml_major_version != $xml_config_major_version) || + (xml_minor_version != $xml_config_minor_version) || + (xml_micro_version != $xml_config_micro_version)) + { + printf("*** libxml header files (version %d.%d.%d) do not match\n", + xml_major_version, xml_minor_version, xml_micro_version); + printf("*** xml2-config (version %d.%d.%d)\n", + $xml_config_major_version, $xml_config_minor_version, $xml_config_micro_version); + return 1; + } +/* Compare the headers to the library to make sure we match */ + /* Less than ideal -- doesn't provide us with return value feedback, + * only exits if there's a serious mismatch between header and library. + */ + LIBXML_TEST_VERSION; + + /* Test that the library is greater than our minimum version */ + if ((xml_major_version > major) || + ((xml_major_version == major) && (xml_minor_version > minor)) || + ((xml_major_version == major) && (xml_minor_version == minor) && + (xml_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of libxml (%d.%d.%d) was found.\n", + xml_major_version, xml_minor_version, xml_micro_version); + printf("*** You need a version of libxml newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** libxml is always available from ftp://ftp.xmlsoft.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the xml2-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of LIBXML, but you can also set the XML2_CONFIG environment to point to the\n"); + printf("*** correct copy of xml2-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + return 1; +} +],, no_xml=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CPPFLAGS="$ac_save_CPPFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + + if test "x$no_xml" = x ; then + AC_MSG_RESULT(yes (version $xml_config_major_version.$xml_config_minor_version.$xml_config_micro_version)) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$XML2_CONFIG" = "no" ; then + echo "*** The xml2-config script installed by LIBXML could not be found" + echo "*** If libxml was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the XML2_CONFIG environment variable to the" + echo "*** full path to xml2-config." + else + if test -f conf.xmltest ; then + : + else + echo "*** Could not run libxml test program, checking why..." + CPPFLAGS="$CPPFLAGS $XML_CPPFLAGS" + LIBS="$LIBS $XML_LIBS" + AC_TRY_LINK([ +#include +#include +], [ LIBXML_TEST_VERSION; return 0;], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding LIBXML or finding the wrong" + echo "*** version of LIBXML. If it is not finding LIBXML, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means LIBXML was incorrectly installed" + echo "*** or that you have moved LIBXML since it was installed. In the latter case, you" + echo "*** may want to edit the xml2-config script: $XML2_CONFIG" ]) + CPPFLAGS="$ac_save_CPPFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + + XML_CPPFLAGS="" + XML_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(XML_CPPFLAGS) + AC_SUBST(XML_LIBS) + rm -f conf.xmltest +]) diff --git a/m4/lock.m4 b/m4/lock.m4 new file mode 100644 index 0000000..0224f2f --- /dev/null +++ b/m4/lock.m4 @@ -0,0 +1,311 @@ +# lock.m4 serial 6 (gettext-0.16) +dnl Copyright (C) 2005-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl Tests for a multithreading library to be used. +dnl Defines at most one of the macros USE_POSIX_THREADS, USE_SOLARIS_THREADS, +dnl USE_PTH_THREADS, USE_WIN32_THREADS +dnl Sets the variables LIBTHREAD and LTLIBTHREAD to the linker options for use +dnl in a Makefile (LIBTHREAD for use without libtool, LTLIBTHREAD for use with +dnl libtool). +dnl Sets the variables LIBMULTITHREAD and LTLIBMULTITHREAD similarly, for +dnl programs that really need multithread functionality. The difference +dnl between LIBTHREAD and LIBMULTITHREAD is that on platforms supporting weak +dnl symbols, typically LIBTHREAD="" whereas LIBMULTITHREAD="-lpthread". +dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for +dnl multithread-safe programs. + +AC_DEFUN([gl_LOCK_EARLY], +[ + AC_REQUIRE([gl_LOCK_EARLY_BODY]) +]) + +dnl The guts of gl_LOCK_EARLY. Needs to be expanded only once. + +AC_DEFUN([gl_LOCK_EARLY_BODY], +[ + dnl Ordering constraints: This macro modifies CPPFLAGS in a way that + dnl influences the result of the autoconf tests that test for *_unlocked + dnl declarations, on AIX 5 at least. Therefore it must come early. + AC_BEFORE([$0], [gl_FUNC_GLIBC_UNLOCKED_IO])dnl + AC_BEFORE([$0], [gl_ARGP])dnl + + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_GNU_SOURCE]) dnl needed for pthread_rwlock_t on glibc systems + dnl Check for multithreading. + AC_ARG_ENABLE(threads, +AC_HELP_STRING([--enable-threads={posix|solaris|pth|win32}], [specify multithreading API]) +AC_HELP_STRING([--disable-threads], [build without multithread safety]), + [gl_use_threads=$enableval], + [case "$host_os" in + dnl Disable multithreading by default on OSF/1, because it interferes + dnl with fork()/exec(): When msgexec is linked with -lpthread, its child + dnl process gets an endless segmentation fault inside execvp(). + osf*) gl_use_threads=no ;; + *) gl_use_threads=yes ;; + esac + ]) + if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then + # For using : + case "$host_os" in + osf*) + # On OSF/1, the compiler needs the flag -D_REENTRANT so that it + # groks . cc also understands the flag -pthread, but + # we don't use it because 1. gcc-2.95 doesn't understand -pthread, + # 2. putting a flag into CPPFLAGS that has an effect on the linker + # causes the AC_TRY_LINK test below to succeed unexpectedly, + # leading to wrong values of LIBTHREAD and LTLIBTHREAD. + CPPFLAGS="$CPPFLAGS -D_REENTRANT" + ;; + esac + # Some systems optimize for single-threaded programs by default, and + # need special flags to disable these optimizations. For example, the + # definition of 'errno' in . + case "$host_os" in + aix* | freebsd*) CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" ;; + solaris*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;; + esac + fi +]) + +dnl The guts of gl_LOCK. Needs to be expanded only once. + +AC_DEFUN([gl_LOCK_BODY], +[ + AC_REQUIRE([gl_LOCK_EARLY_BODY]) + gl_threads_api=none + LIBTHREAD= + LTLIBTHREAD= + LIBMULTITHREAD= + LTLIBMULTITHREAD= + if test "$gl_use_threads" != no; then + dnl Check whether the compiler and linker support weak declarations. + AC_MSG_CHECKING([whether imported symbols can be declared weak]) + gl_have_weak=no + AC_TRY_LINK([extern void xyzzy (); +#pragma weak xyzzy], [xyzzy();], [gl_have_weak=yes]) + AC_MSG_RESULT([$gl_have_weak]) + if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then + # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that + # it groks . It's added above, in gl_LOCK_EARLY_BODY. + AC_CHECK_HEADER(pthread.h, gl_have_pthread_h=yes, gl_have_pthread_h=no) + if test "$gl_have_pthread_h" = yes; then + # Other possible tests: + # -lpthreads (FSU threads, PCthreads) + # -lgthreads + gl_have_pthread= + # Test whether both pthread_mutex_lock and pthread_mutexattr_init exist + # in libc. IRIX 6.5 has the first one in both libc and libpthread, but + # the second one only in libpthread, and lock.c needs it. + AC_TRY_LINK([#include ], + [pthread_mutex_lock((pthread_mutex_t*)0); + pthread_mutexattr_init((pthread_mutexattr_t*)0);], + [gl_have_pthread=yes]) + # Test for libpthread by looking for pthread_kill. (Not pthread_self, + # since it is defined as a macro on OSF/1.) + if test -n "$gl_have_pthread"; then + # The program links fine without libpthread. But it may actually + # need to link with libpthread in order to create multiple threads. + AC_CHECK_LIB(pthread, pthread_kill, + [LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread + # On Solaris and HP-UX, most pthread functions exist also in libc. + # Therefore pthread_in_use() needs to actually try to create a + # thread: pthread_create from libc will fail, whereas + # pthread_create will actually create a thread. + case "$host_os" in + solaris* | hpux*) + AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], 1, + [Define if the pthread_in_use() detection is hard.]) + esac + ]) + else + # Some library is needed. Try libpthread and libc_r. + AC_CHECK_LIB(pthread, pthread_kill, + [gl_have_pthread=yes + LIBTHREAD=-lpthread LTLIBTHREAD=-lpthread + LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread]) + if test -z "$gl_have_pthread"; then + # For FreeBSD 4. + AC_CHECK_LIB(c_r, pthread_kill, + [gl_have_pthread=yes + LIBTHREAD=-lc_r LTLIBTHREAD=-lc_r + LIBMULTITHREAD=-lc_r LTLIBMULTITHREAD=-lc_r]) + fi + fi + if test -n "$gl_have_pthread"; then + gl_threads_api=posix + AC_DEFINE([USE_POSIX_THREADS], 1, + [Define if the POSIX multithreading library can be used.]) + if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then + if test $gl_have_weak = yes; then + AC_DEFINE([USE_POSIX_THREADS_WEAK], 1, + [Define if references to the POSIX multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + # OSF/1 4.0 and MacOS X 10.1 lack the pthread_rwlock_t type and the + # pthread_rwlock_* functions. + AC_CHECK_TYPE([pthread_rwlock_t], + [AC_DEFINE([HAVE_PTHREAD_RWLOCK], 1, + [Define if the POSIX multithreading library has read/write locks.])], + [], + [#include ]) + # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro. + AC_TRY_COMPILE([#include ], + [#if __FreeBSD__ == 4 +error "No, in FreeBSD 4.0 recursive mutexes actually don't work." +#else +int x = (int)PTHREAD_MUTEX_RECURSIVE; +return !x; +#endif], + [AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE], 1, + [Define if the defines PTHREAD_MUTEX_RECURSIVE.])]) + fi + fi + fi + if test -z "$gl_have_pthread"; then + if test "$gl_use_threads" = yes || test "$gl_use_threads" = solaris; then + gl_have_solaristhread= + gl_save_LIBS="$LIBS" + LIBS="$LIBS -lthread" + AC_TRY_LINK([#include +#include ], + [thr_self();], + [gl_have_solaristhread=yes]) + LIBS="$gl_save_LIBS" + if test -n "$gl_have_solaristhread"; then + gl_threads_api=solaris + LIBTHREAD=-lthread + LTLIBTHREAD=-lthread + LIBMULTITHREAD="$LIBTHREAD" + LTLIBMULTITHREAD="$LTLIBTHREAD" + AC_DEFINE([USE_SOLARIS_THREADS], 1, + [Define if the old Solaris multithreading library can be used.]) + if test $gl_have_weak = yes; then + AC_DEFINE([USE_SOLARIS_THREADS_WEAK], 1, + [Define if references to the old Solaris multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + fi + fi + if test "$gl_use_threads" = pth; then + gl_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_LINKFLAGS(pth) + gl_have_pth= + gl_save_LIBS="$LIBS" + LIBS="$LIBS -lpth" + AC_TRY_LINK([#include ], [pth_self();], gl_have_pth=yes) + LIBS="$gl_save_LIBS" + if test -n "$gl_have_pth"; then + gl_threads_api=pth + LIBTHREAD="$LIBPTH" + LTLIBTHREAD="$LTLIBPTH" + LIBMULTITHREAD="$LIBTHREAD" + LTLIBMULTITHREAD="$LTLIBTHREAD" + AC_DEFINE([USE_PTH_THREADS], 1, + [Define if the GNU Pth multithreading library can be used.]) + if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then + if test $gl_have_weak = yes; then + AC_DEFINE([USE_PTH_THREADS_WEAK], 1, + [Define if references to the GNU Pth multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + else + CPPFLAGS="$gl_save_CPPFLAGS" + fi + fi + if test -z "$gl_have_pthread"; then + if test "$gl_use_threads" = yes || test "$gl_use_threads" = win32; then + if { case "$host_os" in + mingw*) true;; + *) false;; + esac + }; then + gl_threads_api=win32 + AC_DEFINE([USE_WIN32_THREADS], 1, + [Define if the Win32 multithreading API can be used.]) + fi + fi + fi + fi + AC_MSG_CHECKING([for multithread API to use]) + AC_MSG_RESULT([$gl_threads_api]) + AC_SUBST(LIBTHREAD) + AC_SUBST(LTLIBTHREAD) + AC_SUBST(LIBMULTITHREAD) + AC_SUBST(LTLIBMULTITHREAD) +]) + +AC_DEFUN([gl_LOCK], +[ + AC_REQUIRE([gl_LOCK_EARLY]) + AC_REQUIRE([gl_LOCK_BODY]) + gl_PREREQ_LOCK +]) + +# Prerequisites of lib/lock.c. +AC_DEFUN([gl_PREREQ_LOCK], [ + AC_REQUIRE([AC_C_INLINE]) +]) + +dnl Survey of platforms: +dnl +dnl Platform Available Compiler Supports test-lock +dnl flavours option weak result +dnl --------------- --------- --------- -------- --------- +dnl Linux 2.4/glibc posix -lpthread Y OK +dnl +dnl GNU Hurd/glibc posix +dnl +dnl FreeBSD 5.3 posix -lc_r Y +dnl posix -lkse ? Y +dnl posix -lpthread ? Y +dnl posix -lthr Y +dnl +dnl FreeBSD 5.2 posix -lc_r Y +dnl posix -lkse Y +dnl posix -lthr Y +dnl +dnl FreeBSD 4.0,4.10 posix -lc_r Y OK +dnl +dnl NetBSD 1.6 -- +dnl +dnl OpenBSD 3.4 posix -lpthread Y OK +dnl +dnl MacOS X 10.[123] posix -lpthread Y OK +dnl +dnl Solaris 7,8,9 posix -lpthread Y Sol 7,8: 0.0; Sol 9: OK +dnl solaris -lthread Y Sol 7,8: 0.0; Sol 9: OK +dnl +dnl HP-UX 11 posix -lpthread N (cc) OK +dnl Y (gcc) +dnl +dnl IRIX 6.5 posix -lpthread Y 0.5 +dnl +dnl AIX 4.3,5.1 posix -lpthread N AIX 4: 0.5; AIX 5: OK +dnl +dnl OSF/1 4.0,5.1 posix -pthread (cc) N OK +dnl -lpthread (gcc) Y +dnl +dnl Cygwin posix -lpthread Y OK +dnl +dnl Any of the above pth -lpth 0.0 +dnl +dnl Mingw win32 N OK +dnl +dnl BeOS 5 -- +dnl +dnl The test-lock result shows what happens if in test-lock.c EXPLICIT_YIELD is +dnl turned off: +dnl OK if all three tests terminate OK, +dnl 0.5 if the first test terminates OK but the second one loops endlessly, +dnl 0.0 if the first test already loops endlessly. diff --git a/m4/longdouble.m4 b/m4/longdouble.m4 new file mode 100644 index 0000000..25590f4 --- /dev/null +++ b/m4/longdouble.m4 @@ -0,0 +1,31 @@ +# longdouble.m4 serial 2 (gettext-0.15) +dnl Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether the compiler supports the 'long double' type. +dnl Prerequisite: AC_PROG_CC + +dnl This file is only needed in autoconf <= 2.59. Newer versions of autoconf +dnl have a macro AC_TYPE_LONG_DOUBLE with identical semantics. + +AC_DEFUN([gt_TYPE_LONGDOUBLE], +[ + AC_CACHE_CHECK([for long double], gt_cv_c_long_double, + [if test "$GCC" = yes; then + gt_cv_c_long_double=yes + else + AC_TRY_COMPILE([ + /* The Stardent Vistra knows sizeof(long double), but does not support it. */ + long double foo = 0.0; + /* On Ultrix 4.3 cc, long double is 4 and double is 8. */ + int array [2*(sizeof(long double) >= sizeof(double)) - 1]; + ], , + gt_cv_c_long_double=yes, gt_cv_c_long_double=no) + fi]) + if test $gt_cv_c_long_double = yes; then + AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.]) + fi +]) diff --git a/m4/longlong.m4 b/m4/longlong.m4 new file mode 100644 index 0000000..3716c09 --- /dev/null +++ b/m4/longlong.m4 @@ -0,0 +1,48 @@ +# longlong.m4 serial 8 +dnl Copyright (C) 1999-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_LONG_LONG_INT if 'long long int' works. +# This fixes a bug in Autoconf 2.60, but can be removed once we +# assume 2.61 everywhere. + +# Note: If the type 'long long int' exists but is only 32 bits large +# (as on some very old compilers), AC_TYPE_LONG_LONG_INT will not be +# defined. In this case you can treat 'long long int' like 'long int'. + +AC_DEFUN([AC_TYPE_LONG_LONG_INT], +[ + AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[long long int ll = 9223372036854775807ll; + long long int nll = -9223372036854775807LL; + typedef int a[((-9223372036854775807LL < 0 + && 0 < 9223372036854775807ll) + ? 1 : -1)]; + int i = 63;]], + [[long long int llmax = 9223372036854775807ll; + return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) + | (llmax / ll) | (llmax % ll));]])], + [ac_cv_type_long_long_int=yes], + [ac_cv_type_long_long_int=no])]) + if test $ac_cv_type_long_long_int = yes; then + AC_DEFINE([HAVE_LONG_LONG_INT], 1, + [Define to 1 if the system has the type `long long int'.]) + fi +]) + +# This macro is obsolescent and should go away soon. +AC_DEFUN([gl_AC_TYPE_LONG_LONG], +[ + AC_REQUIRE([AC_TYPE_LONG_LONG_INT]) + ac_cv_type_long_long=$ac_cv_type_long_long_int + if test $ac_cv_type_long_long = yes; then + AC_DEFINE(HAVE_LONG_LONG, 1, + [Define if you have the 'long long' type.]) + fi +]) diff --git a/m4/ltdl.m4 b/m4/ltdl.m4 new file mode 100644 index 0000000..aeae738 --- /dev/null +++ b/m4/ltdl.m4 @@ -0,0 +1,804 @@ +# ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- +# +# Copyright (C) 1999-2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Thomas Tanner, 1999 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 17 LTDL_INIT + +# LT_CONFIG_LTDL_DIR(DIRECTORY, [LTDL-MODE]) +# ------------------------------------------ +# DIRECTORY contains the libltdl sources. It is okay to call this +# function multiple times, as long as the same DIRECTORY is always given. +AC_DEFUN([LT_CONFIG_LTDL_DIR], +[AC_BEFORE([$0], [LTDL_INIT]) +_$0($*) +])# LT_CONFIG_LTDL_DIR + +# We break this out into a separate macro, so that we can call it safely +# internally without being caught accidentally by the sed scan in libtoolize. +m4_defun([_LT_CONFIG_LTDL_DIR], +[dnl remove trailing slashes +m4_pushdef([_ARG_DIR], m4_bpatsubst([$1], [/*$])) +m4_case(_LTDL_DIR, + [], [dnl only set lt_ltdl_dir if _ARG_DIR is not simply `.' + m4_if(_ARG_DIR, [.], + [], + [m4_define([_LTDL_DIR], _ARG_DIR) + _LT_SHELL_INIT([lt_ltdl_dir=']_ARG_DIR['])])], + [m4_if(_ARG_DIR, _LTDL_DIR, + [], + [m4_fatal([multiple libltdl directories: `]_LTDL_DIR[', `]_ARG_DIR['])])]) +m4_popdef([_ARG_DIR]) +])# _LT_CONFIG_LTDL_DIR + +# Initialise: +m4_define([_LTDL_DIR], []) + + +# _LT_BUILD_PREFIX +# ---------------- +# If Autoconf is new enough, expand to `${top_build_prefix}', otherwise +# to `${top_builddir}/'. +m4_define([_LT_BUILD_PREFIX], +[m4_ifdef([AC_AUTOCONF_VERSION], + [m4_if(m4_version_compare(m4_defn([AC_AUTOCONF_VERSION]), [2.62]), + [-1], [m4_ifdef([_AC_HAVE_TOP_BUILD_PREFIX], + [${top_build_prefix}], + [${top_builddir}/])], + [${top_build_prefix}])], + [${top_builddir}/])[]dnl +]) + + +# LTDL_CONVENIENCE +# ---------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. LIBLTDL will be prefixed with +# '${top_build_prefix}' if available, otherwise with '${top_builddir}/', +# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_build_prefix, top_builddir, and top_srcdir appropriately +# in your Makefiles. +AC_DEFUN([LTDL_CONVENIENCE], +[AC_BEFORE([$0], [LTDL_INIT])dnl +dnl Although the argument is deprecated and no longer documented, +dnl LTDL_CONVENIENCE used to take a DIRECTORY orgument, if we have one +dnl here make sure it is the same as any other declaration of libltdl's +dnl location! This also ensures lt_ltdl_dir is set when configure.ac is +dnl not yet using an explicit LT_CONFIG_LTDL_DIR. +m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl +_$0() +])# LTDL_CONVENIENCE + +# AC_LIBLTDL_CONVENIENCE accepted a directory argument in older libtools, +# now we have LT_CONFIG_LTDL_DIR: +AU_DEFUN([AC_LIBLTDL_CONVENIENCE], +[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) +_LTDL_CONVENIENCE]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBLTDL_CONVENIENCE], []) + + +# _LTDL_CONVENIENCE +# ----------------- +# Code shared by LTDL_CONVENIENCE and LTDL_INIT([convenience]). +m4_defun([_LTDL_CONVENIENCE], +[case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; +esac +LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdlc.la" +LTDLDEPS=$LIBLTDL +LTDLINCL='-I${top_srcdir}'"${lt_ltdl_dir+/$lt_ltdl_dir}" + +AC_SUBST([LIBLTDL]) +AC_SUBST([LTDLDEPS]) +AC_SUBST([LTDLINCL]) + +# For backwards non-gettext consistent compatibility... +INCLTDL="$LTDLINCL" +AC_SUBST([INCLTDL]) +])# _LTDL_CONVENIENCE + + +# LTDL_INSTALLABLE +# ---------------- +# sets LIBLTDL to the link flags for the libltdl installable library +# and LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called from here. If an installed libltdl +# is not found, LIBLTDL will be prefixed with '${top_build_prefix}' if +# available, otherwise with '${top_builddir}/', and LTDLINCL will be +# prefixed with '${top_srcdir}/' (note the single quotes!). If your +# package is not flat and you're not using automake, define top_build_prefix, +# top_builddir, and top_srcdir appropriately in your Makefiles. +# In the future, this macro may have to be called after LT_INIT. +AC_DEFUN([LTDL_INSTALLABLE], +[AC_BEFORE([$0], [LTDL_INIT])dnl +dnl Although the argument is deprecated and no longer documented, +dnl LTDL_INSTALLABLE used to take a DIRECTORY orgument, if we have one +dnl here make sure it is the same as any other declaration of libltdl's +dnl location! This also ensures lt_ltdl_dir is set when configure.ac is +dnl not yet using an explicit LT_CONFIG_LTDL_DIR. +m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl +_$0() +])# LTDL_INSTALLABLE + +# AC_LIBLTDL_INSTALLABLE accepted a directory argument in older libtools, +# now we have LT_CONFIG_LTDL_DIR: +AU_DEFUN([AC_LIBLTDL_INSTALLABLE], +[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) +_LTDL_INSTALLABLE]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBLTDL_INSTALLABLE], []) + + +# _LTDL_INSTALLABLE +# ----------------- +# Code shared by LTDL_INSTALLABLE and LTDL_INIT([installable]). +m4_defun([_LTDL_INSTALLABLE], +[if test -f $prefix/lib/libltdl.la; then + lt_save_LDFLAGS="$LDFLAGS" + LDFLAGS="-L$prefix/lib $LDFLAGS" + AC_CHECK_LIB([ltdl], [lt_dlinit], [lt_lib_ltdl=yes]) + LDFLAGS="$lt_save_LDFLAGS" + if test x"${lt_lib_ltdl-no}" = xyes; then + if test x"$enable_ltdl_install" != xyes; then + # Don't overwrite $prefix/lib/libltdl.la without --enable-ltdl-install + AC_MSG_WARN([not overwriting libltdl at $prefix, force with `--enable-ltdl-install']) + enable_ltdl_install=no + fi + elif test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + fi +fi + +# If configure.ac declared an installable ltdl, and the user didn't override +# with --disable-ltdl-install, we will install the shipped libltdl. +case $enable_ltdl_install in + no) ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLDEPS= + LTDLINCL= + ;; + *) enable_ltdl_install=yes + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdl.la" + LTDLDEPS=$LIBLTDL + LTDLINCL='-I${top_srcdir}'"${lt_ltdl_dir+/$lt_ltdl_dir}" + ;; +esac + +AC_SUBST([LIBLTDL]) +AC_SUBST([LTDLDEPS]) +AC_SUBST([LTDLINCL]) + +# For backwards non-gettext consistent compatibility... +INCLTDL="$LTDLINCL" +AC_SUBST([INCLTDL]) +])# LTDL_INSTALLABLE + + +# _LTDL_MODE_DISPATCH +# ------------------- +m4_define([_LTDL_MODE_DISPATCH], +[dnl If _LTDL_DIR is `.', then we are configuring libltdl itself: +m4_if(_LTDL_DIR, [], + [], + dnl if _LTDL_MODE was not set already, the default value is `subproject': + [m4_case(m4_default(_LTDL_MODE, [subproject]), + [subproject], [AC_CONFIG_SUBDIRS(_LTDL_DIR) + _LT_SHELL_INIT([lt_dlopen_dir="$lt_ltdl_dir"])], + [nonrecursive], [_LT_SHELL_INIT([lt_dlopen_dir="$lt_ltdl_dir"; lt_libobj_prefix="$lt_ltdl_dir/"])], + [recursive], [], + [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])])dnl +dnl Be careful not to expand twice: +m4_define([$0], []) +])# _LTDL_MODE_DISPATCH + + +# _LT_LIBOBJ(MODULE_NAME) +# ----------------------- +# Like AC_LIBOBJ, except that MODULE_NAME goes into _LT_LIBOBJS instead +# of into LIBOBJS. +AC_DEFUN([_LT_LIBOBJ], [ + m4_pattern_allow([^_LT_LIBOBJS$]) + _LT_LIBOBJS="$_LT_LIBOBJS $1.$ac_objext" +])# _LT_LIBOBJS + + +# LTDL_INIT([OPTIONS]) +# -------------------- +# Clients of libltdl can use this macro to allow the installer to +# choose between a shipped copy of the ltdl sources or a preinstalled +# version of the library. If the shipped ltdl sources are not in a +# subdirectory named libltdl, the directory name must be given by +# LT_CONFIG_LTDL_DIR. +AC_DEFUN([LTDL_INIT], +[dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +dnl We need to keep our own list of libobjs separate from our parent project, +dnl and the easiest way to do that is redefine the AC_LIBOBJs macro while +dnl we look for our own LIBOBJs. +m4_pushdef([AC_LIBOBJ], m4_defn([_LT_LIBOBJ])) +m4_pushdef([AC_LIBSOURCES]) + +dnl If not otherwise defined, default to the 1.5.x compatible subproject mode: +m4_if(_LTDL_MODE, [], + [m4_define([_LTDL_MODE], m4_default([$2], [subproject])) + m4_if([-1], [m4_bregexp(_LTDL_MODE, [\(subproject\|\(non\)?recursive\)])], + [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])]) + +AC_ARG_WITH([included_ltdl], + [AS_HELP_STRING([--with-included-ltdl], + [use the GNU ltdl sources included here])]) + +if test "x$with_included_ltdl" != xyes; then + # We are not being forced to use the included libltdl sources, so + # decide whether there is a useful installed version we can use. + AC_CHECK_HEADER([ltdl.h], + [AC_CHECK_DECL([lt_dlinterface_register], + [AC_CHECK_LIB([ltdl], [lt_dladvise_preload], + [with_included_ltdl=no], + [with_included_ltdl=yes])], + [with_included_ltdl=yes], + [AC_INCLUDES_DEFAULT + #include ])], + [with_included_ltdl=yes], + [AC_INCLUDES_DEFAULT] + ) +fi + +dnl If neither LT_CONFIG_LTDL_DIR, LTDL_CONVENIENCE nor LTDL_INSTALLABLE +dnl was called yet, then for old times' sake, we assume libltdl is in an +dnl eponymous directory: +AC_PROVIDE_IFELSE([LT_CONFIG_LTDL_DIR], [], [_LT_CONFIG_LTDL_DIR([libltdl])]) + +AC_ARG_WITH([ltdl_include], + [AS_HELP_STRING([--with-ltdl-include=DIR], + [use the ltdl headers installed in DIR])]) + +if test -n "$with_ltdl_include"; then + if test -f "$with_ltdl_include/ltdl.h"; then : + else + AC_MSG_ERROR([invalid ltdl include directory: `$with_ltdl_include']) + fi +else + with_ltdl_include=no +fi + +AC_ARG_WITH([ltdl_lib], + [AS_HELP_STRING([--with-ltdl-lib=DIR], + [use the libltdl.la installed in DIR])]) + +if test -n "$with_ltdl_lib"; then + if test -f "$with_ltdl_lib/libltdl.la"; then : + else + AC_MSG_ERROR([invalid ltdl library directory: `$with_ltdl_lib']) + fi +else + with_ltdl_lib=no +fi + +case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in + ,yes,no,no,) + m4_case(m4_default(_LTDL_TYPE, [convenience]), + [convenience], [_LTDL_CONVENIENCE], + [installable], [_LTDL_INSTALLABLE], + [m4_fatal([unknown libltdl build type: ]_LTDL_TYPE)]) + ;; + ,no,no,no,) + # If the included ltdl is not to be used, then use the + # preinstalled libltdl we found. + AC_DEFINE([HAVE_LTDL], [1], + [Define this if a modern libltdl is already installed]) + LIBLTDL=-lltdl + LTDLDEPS= + LTDLINCL= + ;; + ,no*,no,*) + AC_MSG_ERROR([`--with-ltdl-include' and `--with-ltdl-lib' options must be used together]) + ;; + *) with_included_ltdl=no + LIBLTDL="-L$with_ltdl_lib -lltdl" + LTDLDEPS= + LTDLINCL="-I$with_ltdl_include" + ;; +esac +INCLTDL="$LTDLINCL" + +# Report our decision... +AC_MSG_CHECKING([where to find libltdl headers]) +AC_MSG_RESULT([$LTDLINCL]) +AC_MSG_CHECKING([where to find libltdl library]) +AC_MSG_RESULT([$LIBLTDL]) + +_LTDL_SETUP + +dnl restore autoconf definition. +m4_popdef([AC_LIBOBJ]) +m4_popdef([AC_LIBSOURCES]) + +AC_CONFIG_COMMANDS_PRE([ + _ltdl_libobjs= + _ltdl_ltlibobjs= + if test -n "$_LT_LIBOBJS"; then + # Remove the extension. + _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' + for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | sed "$_lt_sed_drop_objext" | sort -u`; do + _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" + _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" + done + fi + AC_SUBST([ltdl_LIBOBJS], [$_ltdl_libobjs]) + AC_SUBST([ltdl_LTLIBOBJS], [$_ltdl_ltlibobjs]) +]) + +# Only expand once: +m4_define([LTDL_INIT]) +])# LTDL_INIT + +# Old names: +AU_DEFUN([AC_LIB_LTDL], [LTDL_INIT($@)]) +AU_DEFUN([AC_WITH_LTDL], [LTDL_INIT($@)]) +AU_DEFUN([LT_WITH_LTDL], [LTDL_INIT($@)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIB_LTDL], []) +dnl AC_DEFUN([AC_WITH_LTDL], []) +dnl AC_DEFUN([LT_WITH_LTDL], []) + + +# _LTDL_SETUP +# ----------- +# Perform all the checks necessary for compilation of the ltdl objects +# -- including compiler checks and header checks. This is a public +# interface mainly for the benefit of libltdl's own configure.ac, most +# other users should call LTDL_INIT instead. +AC_DEFUN([_LTDL_SETUP], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_SYS_MODULE_EXT])dnl +AC_REQUIRE([LT_SYS_MODULE_PATH])dnl +AC_REQUIRE([LT_SYS_DLSEARCH_PATH])dnl +AC_REQUIRE([LT_LIB_DLLOAD])dnl +AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl +AC_REQUIRE([LT_FUNC_DLSYM_USCORE])dnl +AC_REQUIRE([LT_SYS_DLOPEN_DEPLIBS])dnl +AC_REQUIRE([gl_FUNC_ARGZ])dnl + +m4_require([_LT_CHECK_OBJDIR])dnl +m4_require([_LT_HEADER_DLFCN])dnl +m4_require([_LT_CHECK_DLPREOPEN])dnl +m4_require([_LT_DECL_SED])dnl + +dnl Don't require this, or it will be expanded earlier than the code +dnl that sets the variables it relies on: +_LT_ENABLE_INSTALL + +dnl _LTDL_MODE specific code must be called at least once: +_LTDL_MODE_DISPATCH + +# In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS +# the user used. This is so that ltdl.h can pick up the parent projects +# config.h file, The first file in AC_CONFIG_HEADERS must contain the +# definitions required by ltdl.c. +# FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). +AC_CONFIG_COMMANDS_PRE([dnl +m4_pattern_allow([^LT_CONFIG_H$])dnl +m4_ifset([AH_HEADER], + [LT_CONFIG_H=AH_HEADER], + [m4_ifset([AC_LIST_HEADERS], + [LT_CONFIG_H=`echo "AC_LIST_HEADERS" | $SED 's,^[[ ]]*,,;s,[[ :]].*$,,'`], + [])])]) +AC_SUBST([LT_CONFIG_H]) + +AC_CHECK_HEADERS([unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h], + [], [], [AC_INCLUDES_DEFAULT]) + +AC_CHECK_FUNCS([closedir opendir readdir], [], [AC_LIBOBJ([lt__dirent])]) +AC_CHECK_FUNCS([strlcat strlcpy], [], [AC_LIBOBJ([lt__strl])]) + +AC_DEFINE_UNQUOTED([LT_LIBEXT],["$libext"],[The archive extension]) + +name=ltdl +LTDLOPEN=`eval "\\$ECHO \"$libname_spec\""` +AC_SUBST([LTDLOPEN]) +])# _LTDL_SETUP + + +# _LT_ENABLE_INSTALL +# ------------------ +m4_define([_LT_ENABLE_INSTALL], +[AC_ARG_ENABLE([ltdl-install], + [AS_HELP_STRING([--enable-ltdl-install], [install libltdl])]) + +case ,${enable_ltdl_install},${enable_ltdl_convenience} in + *yes*) ;; + *) enable_ltdl_convenience=yes ;; +esac + +m4_ifdef([AM_CONDITIONAL], +[AM_CONDITIONAL(INSTALL_LTDL, test x"${enable_ltdl_install-no}" != xno) + AM_CONDITIONAL(CONVENIENCE_LTDL, test x"${enable_ltdl_convenience-no}" != xno)]) +])# _LT_ENABLE_INSTALL + + +# LT_SYS_DLOPEN_DEPLIBS +# --------------------- +AC_DEFUN([LT_SYS_DLOPEN_DEPLIBS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_CACHE_CHECK([whether deplibs are loaded by dlopen], + [lt_cv_sys_dlopen_deplibs], + [# PORTME does your system automatically load deplibs for dlopen? + # or its logical equivalent (e.g. shl_load for HP-UX < 11) + # For now, we just catch OSes we know something about -- in the + # future, we'll try test this programmatically. + lt_cv_sys_dlopen_deplibs=unknown + case $host_os in + aix3*|aix4.1.*|aix4.2.*) + # Unknown whether this is true for these versions of AIX, but + # we want this `case' here to explicitly catch those versions. + lt_cv_sys_dlopen_deplibs=unknown + ;; + aix[[4-9]]*) + lt_cv_sys_dlopen_deplibs=yes + ;; + amigaos*) + case $host_cpu in + powerpc) + lt_cv_sys_dlopen_deplibs=no + ;; + esac + ;; + darwin*) + # Assuming the user has installed a libdl from somewhere, this is true + # If you are looking for one http://www.opendarwin.org/projects/dlcompat + lt_cv_sys_dlopen_deplibs=yes + ;; + freebsd* | dragonfly*) + lt_cv_sys_dlopen_deplibs=yes + ;; + gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) + # GNU and its variants, using gnu ld.so (Glibc) + lt_cv_sys_dlopen_deplibs=yes + ;; + hpux10*|hpux11*) + lt_cv_sys_dlopen_deplibs=yes + ;; + interix*) + lt_cv_sys_dlopen_deplibs=yes + ;; + irix[[12345]]*|irix6.[[01]]*) + # Catch all versions of IRIX before 6.2, and indicate that we don't + # know how it worked for any of those versions. + lt_cv_sys_dlopen_deplibs=unknown + ;; + irix*) + # The case above catches anything before 6.2, and it's known that + # at 6.2 and later dlopen does load deplibs. + lt_cv_sys_dlopen_deplibs=yes + ;; + netbsd* | netbsdelf*-gnu) + lt_cv_sys_dlopen_deplibs=yes + ;; + openbsd*) + lt_cv_sys_dlopen_deplibs=yes + ;; + osf[[1234]]*) + # dlopen did load deplibs (at least at 4.x), but until the 5.x series, + # it did *not* use an RPATH in a shared library to find objects the + # library depends on, so we explicitly say `no'. + lt_cv_sys_dlopen_deplibs=no + ;; + osf5.0|osf5.0a|osf5.1) + # dlopen *does* load deplibs and with the right loader patch applied + # it even uses RPATH in a shared library to search for shared objects + # that the library depends on, but there's no easy way to know if that + # patch is installed. Since this is the case, all we can really + # say is unknown -- it depends on the patch being installed. If + # it is, this changes to `yes'. Without it, it would be `no'. + lt_cv_sys_dlopen_deplibs=unknown + ;; + osf*) + # the two cases above should catch all versions of osf <= 5.1. Read + # the comments above for what we know about them. + # At > 5.1, deplibs are loaded *and* any RPATH in a shared library + # is used to find them so we can finally say `yes'. + lt_cv_sys_dlopen_deplibs=yes + ;; + qnx*) + lt_cv_sys_dlopen_deplibs=yes + ;; + solaris*) + lt_cv_sys_dlopen_deplibs=yes + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + esac + ]) +if test "$lt_cv_sys_dlopen_deplibs" != yes; then + AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], + [Define if the OS needs help to load dependent libraries for dlopen().]) +fi +])# LT_SYS_DLOPEN_DEPLIBS + +# Old name: +AU_ALIAS([AC_LTDL_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], []) + + +# LT_SYS_MODULE_EXT +# ----------------- +AC_DEFUN([LT_SYS_MODULE_EXT], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([which extension is used for runtime loadable modules], + [libltdl_cv_shlibext], +[ +module=yes +eval libltdl_cv_shlibext=$shrext_cmds + ]) +if test -n "$libltdl_cv_shlibext"; then + m4_pattern_allow([LT_MODULE_EXT])dnl + AC_DEFINE_UNQUOTED([LT_MODULE_EXT], ["$libltdl_cv_shlibext"], + [Define to the extension used for runtime loadable modules, say, ".so".]) +fi +])# LT_SYS_MODULE_EXT + +# Old name: +AU_ALIAS([AC_LTDL_SHLIBEXT], [LT_SYS_MODULE_EXT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SHLIBEXT], []) + + +# LT_SYS_MODULE_PATH +# ------------------ +AC_DEFUN([LT_SYS_MODULE_PATH], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([which variable specifies run-time module search path], + [lt_cv_module_path_var], [lt_cv_module_path_var="$shlibpath_var"]) +if test -n "$lt_cv_module_path_var"; then + m4_pattern_allow([LT_MODULE_PATH_VAR])dnl + AC_DEFINE_UNQUOTED([LT_MODULE_PATH_VAR], ["$lt_cv_module_path_var"], + [Define to the name of the environment variable that determines the run-time module search path.]) +fi +])# LT_SYS_MODULE_PATH + +# Old name: +AU_ALIAS([AC_LTDL_SHLIBPATH], [LT_SYS_MODULE_PATH]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SHLIBPATH], []) + + +# LT_SYS_DLSEARCH_PATH +# -------------------- +AC_DEFUN([LT_SYS_DLSEARCH_PATH], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([for the default library search path], + [lt_cv_sys_dlsearch_path], + [lt_cv_sys_dlsearch_path="$sys_lib_dlsearch_path_spec"]) +if test -n "$lt_cv_sys_dlsearch_path"; then + sys_dlsearch_path= + for dir in $lt_cv_sys_dlsearch_path; do + if test -z "$sys_dlsearch_path"; then + sys_dlsearch_path="$dir" + else + sys_dlsearch_path="$sys_dlsearch_path$PATH_SEPARATOR$dir" + fi + done + m4_pattern_allow([LT_DLSEARCH_PATH])dnl + AC_DEFINE_UNQUOTED([LT_DLSEARCH_PATH], ["$sys_dlsearch_path"], + [Define to the system default library search path.]) +fi +])# LT_SYS_DLSEARCH_PATH + +# Old name: +AU_ALIAS([AC_LTDL_SYSSEARCHPATH], [LT_SYS_DLSEARCH_PATH]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYSSEARCHPATH], []) + + +# _LT_CHECK_DLPREOPEN +# ------------------- +m4_defun([_LT_CHECK_DLPREOPEN], +[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], + [libltdl_cv_preloaded_symbols], + [if test -n "$lt_cv_sys_global_symbol_pipe"; then + libltdl_cv_preloaded_symbols=yes + else + libltdl_cv_preloaded_symbols=no + fi + ]) +if test x"$libltdl_cv_preloaded_symbols" = xyes; then + AC_DEFINE([HAVE_PRELOADED_SYMBOLS], [1], + [Define if libtool can extract symbol lists from object files.]) +fi +])# _LT_CHECK_DLPREOPEN + + +# LT_LIB_DLLOAD +# ------------- +AC_DEFUN([LT_LIB_DLLOAD], +[m4_pattern_allow([^LT_DLLOADERS$]) +LT_DLLOADERS= +AC_SUBST([LT_DLLOADERS]) + +AC_LANG_PUSH([C]) + +LIBADD_DLOPEN= +AC_SEARCH_LIBS([dlopen], [dl], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + if test "$ac_cv_search_dlopen" != "none required" ; then + LIBADD_DLOPEN="-ldl" + fi + libltdl_cv_lib_dl_dlopen="yes" + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_DLFCN_H +# include +#endif + ]], [[dlopen(0, 0);]])], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + libltdl_cv_func_dlopen="yes" + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], + [AC_CHECK_LIB([svld], [dlopen], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + LIBADD_DLOPEN="-lsvld" libltdl_cv_func_dlopen="yes" + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"])])]) +if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes +then + lt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DLOPEN" + AC_CHECK_FUNCS([dlerror]) + LIBS="$lt_save_LIBS" +fi +AC_SUBST([LIBADD_DLOPEN]) + +LIBADD_SHL_LOAD= +AC_CHECK_FUNC([shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la"], + [AC_CHECK_LIB([dld], [shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" + LIBADD_SHL_LOAD="-ldld"])]) +AC_SUBST([LIBADD_SHL_LOAD]) + +case $host_os in +darwin[[1567]].*) +# We only want this for pre-Mac OS X 10.4. + AC_CHECK_FUNC([_dyld_func_lookup], + [AC_DEFINE([HAVE_DYLD], [1], + [Define if you have the _dyld_func_lookup function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la"]) + ;; +beos*) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" + ;; +cygwin* | mingw* | os2* | pw32*) + AC_CHECK_DECLS([cygwin_conv_path], [], [], [[#include ]]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" + ;; +esac + +AC_CHECK_LIB([dld], [dld_link], + [AC_DEFINE([HAVE_DLD], [1], + [Define if you have the GNU dld library.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la"]) +AC_SUBST([LIBADD_DLD_LINK]) + +m4_pattern_allow([^LT_DLPREOPEN$]) +LT_DLPREOPEN= +if test -n "$LT_DLLOADERS" +then + for lt_loader in $LT_DLLOADERS; do + LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " + done + AC_DEFINE([HAVE_LIBDLLOADER], [1], + [Define if libdlloader will be built on this platform]) +fi +AC_SUBST([LT_DLPREOPEN]) + +dnl This isn't used anymore, but set it for backwards compatibility +LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" +AC_SUBST([LIBADD_DL]) + +AC_LANG_POP +])# LT_LIB_DLLOAD + +# Old name: +AU_ALIAS([AC_LTDL_DLLIB], [LT_LIB_DLLOAD]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_DLLIB], []) + + +# LT_SYS_SYMBOL_USCORE +# -------------------- +# does the compiler prefix global symbols with an underscore? +AC_DEFUN([LT_SYS_SYMBOL_USCORE], +[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +AC_CACHE_CHECK([for _ prefix in compiled symbols], + [lt_cv_sys_symbol_underscore], + [lt_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext <<_LT_EOF +void nm_test_func(){} +int main(){nm_test_func;return 0;} +_LT_EOF + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + ac_nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + lt_cv_sys_symbol_underscore=yes + else + if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.c >&AS_MESSAGE_LOG_FD + fi + rm -rf conftest* + ]) + sys_symbol_underscore=$lt_cv_sys_symbol_underscore + AC_SUBST([sys_symbol_underscore]) +])# LT_SYS_SYMBOL_USCORE + +# Old name: +AU_ALIAS([AC_LTDL_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYMBOL_USCORE], []) + + +# LT_FUNC_DLSYM_USCORE +# -------------------- +AC_DEFUN([LT_FUNC_DLSYM_USCORE], +[AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl +if test x"$lt_cv_sys_symbol_underscore" = xyes; then + if test x"$libltdl_cv_func_dlopen" = xyes || + test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then + AC_CACHE_CHECK([whether we have to add an underscore for dlsym], + [libltdl_cv_need_uscore], + [libltdl_cv_need_uscore=unknown + save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DLOPEN" + _LT_TRY_DLOPEN_SELF( + [libltdl_cv_need_uscore=no], [libltdl_cv_need_uscore=yes], + [], [libltdl_cv_need_uscore=cross]) + LIBS="$save_LIBS" + ]) + fi +fi + +if test x"$libltdl_cv_need_uscore" = xyes; then + AC_DEFINE([NEED_USCORE], [1], + [Define if dlsym() requires a leading underscore in symbol names.]) +fi +])# LT_FUNC_DLSYM_USCORE + +# Old name: +AU_ALIAS([AC_LTDL_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_DLSYM_USCORE], []) diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 new file mode 100644 index 0000000..34151a3 --- /dev/null +++ b/m4/ltoptions.m4 @@ -0,0 +1,368 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [0], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4 new file mode 100644 index 0000000..9000a05 --- /dev/null +++ b/m4/ltsugar.m4 @@ -0,0 +1,123 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/m4/ltversion.m4 b/m4/ltversion.m4 new file mode 100644 index 0000000..f3c5309 --- /dev/null +++ b/m4/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# Generated from ltversion.in. + +# serial 3017 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.2.6b]) +m4_define([LT_PACKAGE_REVISION], [1.3017]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.2.6b' +macro_revision='1.3017' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4 new file mode 100644 index 0000000..637bb20 --- /dev/null +++ b/m4/lt~obsolete.m4 @@ -0,0 +1,92 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 4 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) diff --git a/m4/nls.m4 b/m4/nls.m4 new file mode 100644 index 0000000..7967cc2 --- /dev/null +++ b/m4/nls.m4 @@ -0,0 +1,31 @@ +# nls.m4 serial 3 (gettext-0.15) +dnl Copyright (C) 1995-2003, 2005-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2003. + +AC_PREREQ(2.50) + +AC_DEFUN([AM_NLS], +[ + AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE(nls, + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT($USE_NLS) + AC_SUBST(USE_NLS) +]) diff --git a/m4/pkg.m4 b/m4/pkg.m4 new file mode 100644 index 0000000..f2bfc2d --- /dev/null +++ b/m4/pkg.m4 @@ -0,0 +1,57 @@ + +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +dnl also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN([PKG_CHECK_MODULES], [ + succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + $1_LIBS=`$PKG_CONFIG --libs "$2"` + AC_MSG_RESULT($$1_LIBS) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi +]) + + diff --git a/m4/po.m4 b/m4/po.m4 new file mode 100644 index 0000000..00133ef --- /dev/null +++ b/m4/po.m4 @@ -0,0 +1,428 @@ +# po.m4 serial 13 (gettext-0.15) +dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2003. + +AC_PREREQ(2.50) + +dnl Checks for all prerequisites of the po subdirectory. +AC_DEFUN([AM_PO_SUBDIRS], +[ + AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake + AC_REQUIRE([AM_NLS])dnl + + dnl Perform the following tests also if --disable-nls has been given, + dnl because they are needed for "make dist" to work. + + dnl Search for GNU msgfmt in the PATH. + dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. + dnl The second test excludes FreeBSD msgfmt. + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && + (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + + dnl Test whether it is GNU msgfmt >= 0.15. +changequote(,)dnl + case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; + *) MSGFMT_015=$MSGFMT ;; + esac +changequote([,])dnl + AC_SUBST([MSGFMT_015]) +changequote(,)dnl + case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; + *) GMSGFMT_015=$GMSGFMT ;; + esac +changequote([,])dnl + AC_SUBST([GMSGFMT_015]) + + dnl Search for GNU xgettext 0.12 or newer in the PATH. + dnl The first test excludes Solaris xgettext and early GNU xgettext versions. + dnl The second test excludes FreeBSD xgettext. + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && + (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + dnl Remove leftover from FreeBSD xgettext call. + rm -f messages.po + + dnl Test whether it is GNU xgettext >= 0.15. +changequote(,)dnl + case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; + *) XGETTEXT_015=$XGETTEXT ;; + esac +changequote([,])dnl + AC_SUBST([XGETTEXT_015]) + + dnl Search for GNU msgmerge 0.11 or newer in the PATH. + AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, + [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) + + dnl Installation directories. + dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we + dnl have to define it here, so that it can be used in po/Makefile. + test -n "$localedir" || localedir='${datadir}/locale' + AC_SUBST([localedir]) + + AC_CONFIG_COMMANDS([po-directories], [[ + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + # Treat a directory as a PO directory if and only if it has a + # POTFILES.in file. This allows packages to have multiple PO + # directories under different names or in different locations. + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + POMAKEFILEDEPS="POTFILES.in" + # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assigment from automake < 1.5. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # The set of available languages was given in configure.in. + # Hide the ALL_LINGUAS assigment from automake < 1.5. + eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' + fi + # Compute POFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) + # Compute UPDATEPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) + # Compute DUMMYPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) + # Compute GMOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + UPDATEPOFILES= + DUMMYPOFILES= + GMOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done]], + [# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it + # from automake < 1.5. + eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + ]) +]) + +dnl Postprocesses a Makefile in a directory containing PO files. +AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], +[ + # When this code is run, in config.status, two variables have already been + # set: + # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, + # - LINGUAS is the value of the environment variable LINGUAS at configure + # time. + +changequote(,)dnl + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + # Find a way to echo strings without interpreting backslash. + if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then + gt_echo='echo' + else + if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then + gt_echo='printf %s\n' + else + echo_func () { + cat < "$ac_file.tmp" + if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then + # Add dependencies that cannot be formulated as a simple suffix rule. + for lang in $ALL_LINGUAS; do + frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` + cat >> "$ac_file.tmp" < /dev/null; then + # Add dependencies that cannot be formulated as a simple suffix rule. + for lang in $ALL_LINGUAS; do + frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` + cat >> "$ac_file.tmp" <> "$ac_file.tmp" < +#include +/* The string "%2$d %1$d", with dollar characters protected from the shell's + dollar expansion (possibly an autoconf bug). */ +static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' }; +static char buf[100]; +int main () +{ + sprintf (buf, format, 33, 55); + return (strcmp (buf, "55 33") != 0); +}], gt_cv_func_printf_posix=yes, gt_cv_func_printf_posix=no, + [ + AC_EGREP_CPP(notposix, [ +#if defined __NetBSD__ || defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ + notposix +#endif + ], gt_cv_func_printf_posix="guessing no", + gt_cv_func_printf_posix="guessing yes") + ]) + ]) + case $gt_cv_func_printf_posix in + *yes) + AC_DEFINE(HAVE_POSIX_PRINTF, 1, + [Define if your printf() function supports format strings with positions.]) + ;; + esac +]) diff --git a/m4/progtest.m4 b/m4/progtest.m4 new file mode 100644 index 0000000..a56365c --- /dev/null +++ b/m4/progtest.m4 @@ -0,0 +1,92 @@ +# progtest.m4 serial 4 (gettext-0.14.2) +dnl Copyright (C) 1996-2003, 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1996. + +AC_PREREQ(2.50) + +# Search path for a program which passes the given test. + +dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST], +[ +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + [[\\/]]* | ?:[[\\/]]*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in ifelse([$5], , $PATH, [$5]); do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) diff --git a/m4/signed.m4 b/m4/signed.m4 new file mode 100644 index 0000000..dc1f54f --- /dev/null +++ b/m4/signed.m4 @@ -0,0 +1,19 @@ +# signed.m4 serial 1 (gettext-0.10.40) +dnl Copyright (C) 2001-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +AC_DEFUN([bh_C_SIGNED], +[ + AC_CACHE_CHECK([for signed], bh_cv_c_signed, + [AC_TRY_COMPILE(, [signed char x;], bh_cv_c_signed=yes, bh_cv_c_signed=no)]) + if test $bh_cv_c_signed = no; then + AC_DEFINE(signed, , + [Define to empty if the C compiler doesn't support this keyword.]) + fi +]) diff --git a/m4/size_max.m4 b/m4/size_max.m4 new file mode 100644 index 0000000..bfba811 --- /dev/null +++ b/m4/size_max.m4 @@ -0,0 +1,62 @@ +# size_max.m4 serial 5 +dnl Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([gl_SIZE_MAX], +[ + AC_CHECK_HEADERS(stdint.h) + dnl First test whether the system already has SIZE_MAX. + AC_MSG_CHECKING([for SIZE_MAX]) + AC_CACHE_VAL([gl_cv_size_max], [ + gl_cv_size_max= + AC_EGREP_CPP([Found it], [ +#include +#if HAVE_STDINT_H +#include +#endif +#ifdef SIZE_MAX +Found it +#endif +], gl_cv_size_max=yes) + if test -z "$gl_cv_size_max"; then + dnl Define it ourselves. Here we assume that the type 'size_t' is not wider + dnl than the type 'unsigned long'. Try hard to find a definition that can + dnl be used in a preprocessor #if, i.e. doesn't contain a cast. + _AC_COMPUTE_INT([sizeof (size_t) * CHAR_BIT - 1], size_t_bits_minus_1, + [#include +#include ], size_t_bits_minus_1=) + _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint, + [#include ], fits_in_uint=) + if test -n "$size_t_bits_minus_1" && test -n "$fits_in_uint"; then + if test $fits_in_uint = 1; then + dnl Even though SIZE_MAX fits in an unsigned int, it must be of type + dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'. + AC_TRY_COMPILE([#include + extern size_t foo; + extern unsigned long foo; + ], [], fits_in_uint=0) + fi + dnl We cannot use 'expr' to simplify this expression, because 'expr' + dnl works only with 'long' integers in the host environment, while we + dnl might be cross-compiling from a 32-bit platform to a 64-bit platform. + if test $fits_in_uint = 1; then + gl_cv_size_max="(((1U << $size_t_bits_minus_1) - 1) * 2 + 1)" + else + gl_cv_size_max="(((1UL << $size_t_bits_minus_1) - 1) * 2 + 1)" + fi + else + dnl Shouldn't happen, but who knows... + gl_cv_size_max='((size_t)~(size_t)0)' + fi + fi + ]) + AC_MSG_RESULT([$gl_cv_size_max]) + if test "$gl_cv_size_max" != yes; then + AC_DEFINE_UNQUOTED([SIZE_MAX], [$gl_cv_size_max], + [Define as the maximum value of type 'size_t', if the system doesn't define it.]) + fi +]) diff --git a/m4/stdint_h.m4 b/m4/stdint_h.m4 new file mode 100644 index 0000000..db9a8ac --- /dev/null +++ b/m4/stdint_h.m4 @@ -0,0 +1,26 @@ +# stdint_h.m4 serial 6 +dnl Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_STDINT_H_WITH_UINTMAX if exists, +# doesn't clash with , and declares uintmax_t. + +AC_DEFUN([gl_AC_HEADER_STDINT_H], +[ + AC_CACHE_CHECK([for stdint.h], gl_cv_header_stdint_h, + [AC_TRY_COMPILE( + [#include +#include ], + [uintmax_t i = (uintmax_t) -1; return !i;], + gl_cv_header_stdint_h=yes, + gl_cv_header_stdint_h=no)]) + if test $gl_cv_header_stdint_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1, + [Define if exists, doesn't clash with , + and declares uintmax_t. ]) + fi +]) diff --git a/m4/uintmax_t.m4 b/m4/uintmax_t.m4 new file mode 100644 index 0000000..bf83ed7 --- /dev/null +++ b/m4/uintmax_t.m4 @@ -0,0 +1,30 @@ +# uintmax_t.m4 serial 9 +dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +AC_PREREQ(2.13) + +# Define uintmax_t to 'unsigned long' or 'unsigned long long' +# if it is not already defined in or . + +AC_DEFUN([gl_AC_TYPE_UINTMAX_T], +[ + AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) + AC_REQUIRE([gl_AC_HEADER_STDINT_H]) + if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then + AC_REQUIRE([gl_AC_TYPE_UNSIGNED_LONG_LONG]) + test $ac_cv_type_unsigned_long_long = yes \ + && ac_type='unsigned long long' \ + || ac_type='unsigned long' + AC_DEFINE_UNQUOTED(uintmax_t, $ac_type, + [Define to unsigned long or unsigned long long + if and don't define.]) + else + AC_DEFINE(HAVE_UINTMAX_T, 1, + [Define if you have the 'uintmax_t' type in or .]) + fi +]) diff --git a/m4/ulonglong.m4 b/m4/ulonglong.m4 new file mode 100644 index 0000000..9fae98e --- /dev/null +++ b/m4/ulonglong.m4 @@ -0,0 +1,48 @@ +# ulonglong.m4 serial 6 +dnl Copyright (C) 1999-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works. +# This fixes a bug in Autoconf 2.60, but can be removed once we +# assume 2.61 everywhere. + +# Note: If the type 'unsigned long long int' exists but is only 32 bits +# large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT +# will not be defined. In this case you can treat 'unsigned long long int' +# like 'unsigned long int'. + +AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT], +[ + AC_CACHE_CHECK([for unsigned long long int], + [ac_cv_type_unsigned_long_long_int], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[unsigned long long int ull = 18446744073709551615ULL; + typedef int a[(18446744073709551615ULL <= (unsigned long long int) -1 + ? 1 : -1)]; + int i = 63;]], + [[unsigned long long int ullmax = 18446744073709551615ull; + return (ull << 63 | ull >> 63 | ull << i | ull >> i + | ullmax / ull | ullmax % ull);]])], + [ac_cv_type_unsigned_long_long_int=yes], + [ac_cv_type_unsigned_long_long_int=no])]) + if test $ac_cv_type_unsigned_long_long_int = yes; then + AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], 1, + [Define to 1 if the system has the type `unsigned long long int'.]) + fi +]) + +# This macro is obsolescent and should go away soon. +AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG], +[ + AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT]) + ac_cv_type_unsigned_long_long=$ac_cv_type_unsigned_long_long_int + if test $ac_cv_type_unsigned_long_long = yes; then + AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1, + [Define if you have the 'unsigned long long' type.]) + fi +]) diff --git a/m4/visibility.m4 b/m4/visibility.m4 new file mode 100644 index 0000000..2ff6330 --- /dev/null +++ b/m4/visibility.m4 @@ -0,0 +1,52 @@ +# visibility.m4 serial 1 (gettext-0.15) +dnl Copyright (C) 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl Tests whether the compiler supports the command-line option +dnl -fvisibility=hidden and the function and variable attributes +dnl __attribute__((__visibility__("hidden"))) and +dnl __attribute__((__visibility__("default"))). +dnl Does *not* test for __visibility__("protected") - which has tricky +dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on +dnl MacOS X. +dnl Does *not* test for __visibility__("internal") - which has processor +dnl dependent semantics. +dnl Does *not* test for #pragma GCC visibility push(hidden) - which is +dnl "really only recommended for legacy code". +dnl Set the variable CFLAG_VISIBILITY. +dnl Defines and sets the variable HAVE_VISIBILITY. + +AC_DEFUN([gl_VISIBILITY], +[ + AC_REQUIRE([AC_PROG_CC]) + CFLAG_VISIBILITY= + HAVE_VISIBILITY=0 + if test -n "$GCC"; then + AC_MSG_CHECKING([for simple visibility declarations]) + AC_CACHE_VAL(gl_cv_cc_visibility, [ + gl_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fvisibility=hidden" + AC_TRY_COMPILE( + [extern __attribute__((__visibility__("hidden"))) int hiddenvar; + extern __attribute__((__visibility__("default"))) int exportedvar; + extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void); + extern __attribute__((__visibility__("default"))) int exportedfunc (void);], + [], + gl_cv_cc_visibility=yes, + gl_cv_cc_visibility=no) + CFLAGS="$gl_save_CFLAGS"]) + AC_MSG_RESULT([$gl_cv_cc_visibility]) + if test $gl_cv_cc_visibility = yes; then + CFLAG_VISIBILITY="-fvisibility=hidden" + HAVE_VISIBILITY=1 + fi + fi + AC_SUBST([CFLAG_VISIBILITY]) + AC_SUBST([HAVE_VISIBILITY]) + AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY], + [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.]) +]) diff --git a/m4/wchar_t.m4 b/m4/wchar_t.m4 new file mode 100644 index 0000000..cde2129 --- /dev/null +++ b/m4/wchar_t.m4 @@ -0,0 +1,20 @@ +# wchar_t.m4 serial 1 (gettext-0.12) +dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether has the 'wchar_t' type. +dnl Prerequisite: AC_PROG_CC + +AC_DEFUN([gt_TYPE_WCHAR_T], +[ + AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t, + [AC_TRY_COMPILE([#include + wchar_t foo = (wchar_t)'\0';], , + gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)]) + if test $gt_cv_c_wchar_t = yes; then + AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.]) + fi +]) diff --git a/m4/wint_t.m4 b/m4/wint_t.m4 new file mode 100644 index 0000000..b8fff9c --- /dev/null +++ b/m4/wint_t.m4 @@ -0,0 +1,20 @@ +# wint_t.m4 serial 1 (gettext-0.12) +dnl Copyright (C) 2003 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether has the 'wint_t' type. +dnl Prerequisite: AC_PROG_CC + +AC_DEFUN([gt_TYPE_WINT_T], +[ + AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t, + [AC_TRY_COMPILE([#include + wint_t foo = (wchar_t)'\0';], , + gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)]) + if test $gt_cv_c_wint_t = yes; then + AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.]) + fi +]) diff --git a/m4/xsize.m4 b/m4/xsize.m4 new file mode 100644 index 0000000..85bb721 --- /dev/null +++ b/m4/xsize.m4 @@ -0,0 +1,13 @@ +# xsize.m4 serial 3 +dnl Copyright (C) 2003-2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_XSIZE], +[ + dnl Prerequisites of lib/xsize.h. + AC_REQUIRE([gl_SIZE_MAX]) + AC_REQUIRE([AC_C_INLINE]) + AC_CHECK_HEADERS(stdint.h) +]) diff --git a/missing b/missing new file mode 100755 index 0000000..28055d2 --- /dev/null +++ b/missing @@ -0,0 +1,376 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + tar*) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar*) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am new file mode 100644 index 0000000..5173f03 --- /dev/null +++ b/pkgconfig/Makefile.am @@ -0,0 +1,56 @@ +pcfiles = \ + gnunetarm.pc \ + gnunetblock.pc \ + gnunetcore.pc \ + gnunetdatacache.pc \ + gnunetdatastore.pc \ + gnunetdht.pc \ + gnunetdhtlog.pc \ + gnunetdv.pc \ + gnunetfragmentation.pc \ + gnunetfs.pc \ + gnunethello.pc \ + gnunetnse.pc \ + gnunetnat.pc \ + gnunetpeerinfo.pc \ + gnunetstatistics.pc \ + gnunettesting.pc \ + gnunettransport.pc \ + gnunetutil.pc + +all-local: $(pcfiles) + +cp_verbose = $(cp_verbose_$(V)) +cp_verbose_ = $(cp_verbose_$(AM_DEFAULT_VERBOSITY)) +cp_verbose_0 = @echo " CP $@"; + +%.pc: %.pc + $(cp_verbose_0)cp $< $@ + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = $(pcfiles) + +EXTRA_DIST = \ + gnunetarm.pc.in \ + gnunetblock.pc.in \ + gnunetcore.pc.in \ + gnunetdatacache.pc.in \ + gnunetdatastore.pc.in \ + gnunetdht.pc.in \ + gnunetdhtlog.pc.in \ + gnunetdv.pc.in \ + gnunetfragmentation.pc.in \ + gnunetfs.pc.in \ + gnunethello.pc.in \ + gnunetnat.pc.in \ + gnunetnse.pc.in \ + gnunetpeerinfo.pc.in \ + gnunetstatistics.pc.in \ + gnunettesting.pc.in \ + gnunettransport.pc.in \ + gnunetutil.pc.in + +CLEANFILES = $(pcfiles) +INCLUDES = -I$(top_srcdir)/src/include + + diff --git a/pkgconfig/Makefile.in b/pkgconfig/Makefile.in new file mode 100644 index 0000000..d487dcb --- /dev/null +++ b/pkgconfig/Makefile.in @@ -0,0 +1,609 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = pkgconfig +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/gnunetarm.pc.in $(srcdir)/gnunetblock.pc.in \ + $(srcdir)/gnunetcore.pc.in $(srcdir)/gnunetdatacache.pc.in \ + $(srcdir)/gnunetdatastore.pc.in $(srcdir)/gnunetdht.pc.in \ + $(srcdir)/gnunetdhtlog.pc.in $(srcdir)/gnunetdv.pc.in \ + $(srcdir)/gnunetfragmentation.pc.in $(srcdir)/gnunetfs.pc.in \ + $(srcdir)/gnunethello.pc.in $(srcdir)/gnunetnat.pc.in \ + $(srcdir)/gnunetnse.pc.in $(srcdir)/gnunetpeerinfo.pc.in \ + $(srcdir)/gnunetstatistics.pc.in $(srcdir)/gnunettesting.pc.in \ + $(srcdir)/gnunettransport.pc.in $(srcdir)/gnunetutil.pc.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = gnunetarm.pc gnunetblock.pc gnunetcore.pc \ + gnunetdatacache.pc gnunetdatastore.pc gnunetdht.pc \ + gnunetdhtlog.pc gnunetdv.pc gnunetfragmentation.pc gnunetfs.pc \ + gnunethello.pc gnunetnat.pc gnunetnse.pc gnunetpeerinfo.pc \ + gnunetstatistics.pc gnunettesting.pc gnunettransport.pc \ + gnunetutil.pc +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkgconfigdir)" +DATA = $(pkgconfig_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +pcfiles = \ + gnunetarm.pc \ + gnunetblock.pc \ + gnunetcore.pc \ + gnunetdatacache.pc \ + gnunetdatastore.pc \ + gnunetdht.pc \ + gnunetdhtlog.pc \ + gnunetdv.pc \ + gnunetfragmentation.pc \ + gnunetfs.pc \ + gnunethello.pc \ + gnunetnse.pc \ + gnunetnat.pc \ + gnunetpeerinfo.pc \ + gnunetstatistics.pc \ + gnunettesting.pc \ + gnunettransport.pc \ + gnunetutil.pc + +cp_verbose = $(cp_verbose_$(V)) +cp_verbose_ = $(cp_verbose_$(AM_DEFAULT_VERBOSITY)) +cp_verbose_0 = @echo " CP $@"; +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = $(pcfiles) +EXTRA_DIST = \ + gnunetarm.pc.in \ + gnunetblock.pc.in \ + gnunetcore.pc.in \ + gnunetdatacache.pc.in \ + gnunetdatastore.pc.in \ + gnunetdht.pc.in \ + gnunetdhtlog.pc.in \ + gnunetdv.pc.in \ + gnunetfragmentation.pc.in \ + gnunetfs.pc.in \ + gnunethello.pc.in \ + gnunetnat.pc.in \ + gnunetnse.pc.in \ + gnunetpeerinfo.pc.in \ + gnunetstatistics.pc.in \ + gnunettesting.pc.in \ + gnunettransport.pc.in \ + gnunetutil.pc.in + +CLEANFILES = $(pcfiles) +INCLUDES = -I$(top_srcdir)/src/include +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu pkgconfig/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu pkgconfig/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +gnunetarm.pc: $(top_builddir)/config.status $(srcdir)/gnunetarm.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetblock.pc: $(top_builddir)/config.status $(srcdir)/gnunetblock.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetcore.pc: $(top_builddir)/config.status $(srcdir)/gnunetcore.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetdatacache.pc: $(top_builddir)/config.status $(srcdir)/gnunetdatacache.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetdatastore.pc: $(top_builddir)/config.status $(srcdir)/gnunetdatastore.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetdht.pc: $(top_builddir)/config.status $(srcdir)/gnunetdht.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetdhtlog.pc: $(top_builddir)/config.status $(srcdir)/gnunetdhtlog.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetdv.pc: $(top_builddir)/config.status $(srcdir)/gnunetdv.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetfragmentation.pc: $(top_builddir)/config.status $(srcdir)/gnunetfragmentation.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetfs.pc: $(top_builddir)/config.status $(srcdir)/gnunetfs.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunethello.pc: $(top_builddir)/config.status $(srcdir)/gnunethello.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetnat.pc: $(top_builddir)/config.status $(srcdir)/gnunetnat.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetnse.pc: $(top_builddir)/config.status $(srcdir)/gnunetnse.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetpeerinfo.pc: $(top_builddir)/config.status $(srcdir)/gnunetpeerinfo.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetstatistics.pc: $(top_builddir)/config.status $(srcdir)/gnunetstatistics.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunettesting.pc: $(top_builddir)/config.status $(srcdir)/gnunettesting.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunettransport.pc: $(top_builddir)/config.status $(srcdir)/gnunettransport.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gnunetutil.pc: $(top_builddir)/config.status $(srcdir)/gnunetutil.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) all-local +installdirs: + for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgconfigDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkgconfigDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool distclean distclean-generic distclean-libtool \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkgconfigDATA install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am uninstall uninstall-am uninstall-pkgconfigDATA + + +all-local: $(pcfiles) + +%.pc: %.pc + $(cp_verbose_0)cp $< $@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/pkgconfig/gnunetarm.pc.in b/pkgconfig/gnunetarm.pc.in new file mode 100644 index 0000000..5f88e31 --- /dev/null +++ b/pkgconfig/gnunetarm.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet ARM +Description: Provides API for accessing the Automated Restart Manager service +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetarm +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetblock.pc.in b/pkgconfig/gnunetblock.pc.in new file mode 100644 index 0000000..75ec34c --- /dev/null +++ b/pkgconfig/gnunetblock.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet block +Description: Library for data block manipulation +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetblock +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetcore.pc.in b/pkgconfig/gnunetcore.pc.in new file mode 100644 index 0000000..66a469a --- /dev/null +++ b/pkgconfig/gnunetcore.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet core +Description: Provides API to access core service +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetcore +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetdatacache.pc.in b/pkgconfig/gnunetdatacache.pc.in new file mode 100644 index 0000000..e69875e --- /dev/null +++ b/pkgconfig/gnunetdatacache.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet datacache +Description: Provides datacache API implementation +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetdatacache +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetdatastore.pc.in b/pkgconfig/gnunetdatastore.pc.in new file mode 100644 index 0000000..9a0ddf8 --- /dev/null +++ b/pkgconfig/gnunetdatastore.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet datastore +Description: Management API for the datastore for files stored on a GNUnet node +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetdatastore +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetdht.pc.in b/pkgconfig/gnunetdht.pc.in new file mode 100644 index 0000000..4a2d12e --- /dev/null +++ b/pkgconfig/gnunetdht.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet DHT +Description: Library to access GNUnet DHT service +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetdht +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetdhtlog.pc.in b/pkgconfig/gnunetdhtlog.pc.in new file mode 100644 index 0000000..29fcef0 --- /dev/null +++ b/pkgconfig/gnunetdhtlog.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet dhtlog +Description: Library for logging DHT operations via plugins +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetdhtlog +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetdv.pc.in b/pkgconfig/gnunetdv.pc.in new file mode 100644 index 0000000..bd5bd42 --- /dev/null +++ b/pkgconfig/gnunetdv.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet dv +Description: Library to access GNUnet DV service +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetdv +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetfragmentation.pc.in b/pkgconfig/gnunetfragmentation.pc.in new file mode 100644 index 0000000..0971dc4 --- /dev/null +++ b/pkgconfig/gnunetfragmentation.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet fragmentation +Description: Provides API for sending and receiving messages that are larger than the MTU of the transport +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetfragmentation +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetfs.pc.in b/pkgconfig/gnunetfs.pc.in new file mode 100644 index 0000000..687b6a0 --- /dev/null +++ b/pkgconfig/gnunetfs.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet fs +Description: Provides API for GNUnet File-Sharing service +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetfs +Cflags: -I${includedir} diff --git a/pkgconfig/gnunethello.pc.in b/pkgconfig/gnunethello.pc.in new file mode 100644 index 0000000..2ef4aa3 --- /dev/null +++ b/pkgconfig/gnunethello.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet hello +Description: Helper library for handling GNUnet HELLO messages +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunethello +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetnat.pc.in b/pkgconfig/gnunetnat.pc.in new file mode 100644 index 0000000..58ba25a --- /dev/null +++ b/pkgconfig/gnunetnat.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet NAT +Description: library for NAT traversal +URL: https://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetnat +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetnse.pc.in b/pkgconfig/gnunetnse.pc.in new file mode 100644 index 0000000..fd34030 --- /dev/null +++ b/pkgconfig/gnunetnse.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet NSE +Description: library to access GNUnet network size estimate information +URL: https://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetnse +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetpeerinfo.pc.in b/pkgconfig/gnunetpeerinfo.pc.in new file mode 100644 index 0000000..226b4f2 --- /dev/null +++ b/pkgconfig/gnunetpeerinfo.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet peerinfo +Description: Provides API to access GNUnet peerinfo service +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetpeerinfo +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetstatistics.pc.in b/pkgconfig/gnunetstatistics.pc.in new file mode 100644 index 0000000..e01bcd5 --- /dev/null +++ b/pkgconfig/gnunetstatistics.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet statistics +Description: Provides API of GNUnet statistics service +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetstatistics +Cflags: -I${includedir} diff --git a/pkgconfig/gnunettesting.pc.in b/pkgconfig/gnunettesting.pc.in new file mode 100644 index 0000000..2998eb9 --- /dev/null +++ b/pkgconfig/gnunettesting.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet testing +Description: Provides convenience API for writing testcases for GNUnet +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunettesting +Cflags: -I${includedir} diff --git a/pkgconfig/gnunettransport.pc.in b/pkgconfig/gnunettransport.pc.in new file mode 100644 index 0000000..086be92 --- /dev/null +++ b/pkgconfig/gnunettransport.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet transport +Description: Library to access the low-level GNUnet P2P IO service +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunettransport +Cflags: -I${includedir} diff --git a/pkgconfig/gnunetutil.pc.in b/pkgconfig/gnunetutil.pc.in new file mode 100644 index 0000000..3273298 --- /dev/null +++ b/pkgconfig/gnunetutil.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: GNUnet util +Description: Provides miscellaneous utility functions and API for GNUnet +URL: http://gnunet.org +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lgnunetutil +Cflags: -I${includedir} diff --git a/po/ChangeLog b/po/ChangeLog new file mode 100644 index 0000000..7ff113c --- /dev/null +++ b/po/ChangeLog @@ -0,0 +1,16 @@ +2007-02-08 gettextize + + * Makefile.in.in: Upgrade to gettext-0.16.1. + * Rules-quot: Upgrade to gettext-0.16.1. + +2004-08-21 gettextize + + * Makefile.in.in: New file, from gettext-0.14. + * boldquot.sed: New file, from gettext-0.14. + * en@boldquot.header: New file, from gettext-0.14. + * en@quot.header: New file, from gettext-0.14. + * insert-header.sin: New file, from gettext-0.14. + * quot.sed: New file, from gettext-0.14. + * remove-potcdate.sin: New file, from gettext-0.14. + * Rules-quot: New file, from gettext-0.14. + diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..b8c70e1 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,2 @@ +# set of available languages +vi de sv es zh_CN diff --git a/po/Makefile.in.in b/po/Makefile.in.in new file mode 100644 index 0000000..5022b8b --- /dev/null +++ b/po/Makefile.in.in @@ -0,0 +1,403 @@ +# Makefile for PO directory in any package using GNU gettext. +# Copyright (C) 1995-1997, 2000-2006 by Ulrich Drepper +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU General Public +# License but which still want to provide support for the GNU gettext +# functionality. +# Please note that the actual code of GNU gettext is covered by the GNU +# General Public License and is *not* in the public domain. +# +# Origin: gettext-0.16 + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ + +SHELL = /bin/sh +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +datadir = @datadir@ +localedir = @localedir@ +gettextsrcdir = $(datadir)/gettext/po + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +# We use $(mkdir_p). +# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as +# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, +# @install_sh@ does not start with $(SHELL), so we add it. +# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined +# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake +# versions, $(mkinstalldirs) and $(install_sh) are unused. +mkinstalldirs = $(SHELL) @install_sh@ -d +install_sh = $(SHELL) @install_sh@ +MKDIR_P = @MKDIR_P@ +mkdir_p = @mkdir_p@ + +GMSGFMT_ = @GMSGFMT@ +GMSGFMT_no = @GMSGFMT@ +GMSGFMT_yes = @GMSGFMT_015@ +GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) +MSGFMT_ = @MSGFMT@ +MSGFMT_no = @MSGFMT@ +MSGFMT_yes = @MSGFMT_015@ +MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) +XGETTEXT_ = @XGETTEXT@ +XGETTEXT_no = @XGETTEXT@ +XGETTEXT_yes = @XGETTEXT_015@ +XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) +MSGMERGE = msgmerge +MSGMERGE_UPDATE = @MSGMERGE@ --update +MSGINIT = msginit +MSGCONV = msgconv +MSGFILTER = msgfilter + +POFILES = @POFILES@ +GMOFILES = @GMOFILES@ +UPDATEPOFILES = @UPDATEPOFILES@ +DUMMYPOFILES = @DUMMYPOFILES@ +DISTFILES.common = Makefile.in.in remove-potcdate.sin \ +$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) +DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \ +$(POFILES) $(GMOFILES) \ +$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) + +POTFILES = \ + +CATALOGS = @CATALOGS@ + +# Makevars gets inserted here. (Don't remove this line!) + +.SUFFIXES: +.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update + +.po.mo: + @echo "$(MSGFMT) -c -o $@ $<"; \ + $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ + +.po.gmo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ + cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo + +.sin.sed: + sed -e '/^#/d' $< > t-$@ + mv t-$@ $@ + + +all: all-@USE_NLS@ + +all-yes: stamp-po +all-no: + +# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no +# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because +# we don't want to bother translators with empty POT files). We assume that +# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. +# In this case, stamp-po is a nop (i.e. a phony target). + +# stamp-po is a timestamp denoting the last time at which the CATALOGS have +# been loosely updated. Its purpose is that when a developer or translator +# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, +# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent +# invocations of "make" will do nothing. This timestamp would not be necessary +# if updating the $(CATALOGS) would always touch them; however, the rule for +# $(POFILES) has been designed to not touch files that don't need to be +# changed. +stamp-po: $(srcdir)/$(DOMAIN).pot + test ! -f $(srcdir)/$(DOMAIN).pot || \ + test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) + @test ! -f $(srcdir)/$(DOMAIN).pot || { \ + echo "touch stamp-po" && \ + echo timestamp > stamp-poT && \ + mv stamp-poT stamp-po; \ + } + +# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', +# otherwise packages like GCC can not be built if only parts of the source +# have been downloaded. + +# This target rebuilds $(DOMAIN).pot; it is an expensive operation. +# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. +$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed + if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \ + msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \ + else \ + msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \ + fi; \ + $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ + --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ + --files-from=$(srcdir)/POTFILES.in \ + --copyright-holder='$(COPYRIGHT_HOLDER)' \ + --msgid-bugs-address="$$msgid_bugs_address" + test ! -f $(DOMAIN).po || { \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ + sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ + if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ + else \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + else \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + } + +# This rule has no dependencies: we don't need to update $(DOMAIN).pot at +# every "make" invocation, only create it when it is missing. +# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. +$(srcdir)/$(DOMAIN).pot: + $(MAKE) $(DOMAIN).pot-update + +# This target rebuilds a PO file if $(DOMAIN).pot has changed. +# Note that a PO file is not touched if it doesn't need to be changed. +$(POFILES): $(srcdir)/$(DOMAIN).pot + @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ + if test -f "$(srcdir)/$${lang}.po"; then \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ + cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot; \ + else \ + $(MAKE) $${lang}.po-create; \ + fi + + +install: install-exec install-data +install-exec: +install-data: install-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ + for file in $(DISTFILES.common) Makevars.template; do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + for file in Makevars; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +install-data-no: all +install-data-yes: all + $(mkdir_p) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $(DESTDIR)$$dir; \ + if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ + $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ + echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ + fi; \ + done; \ + done + +install-strip: install + +installdirs: installdirs-exec installdirs-data +installdirs-exec: +installdirs-data: installdirs-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi +installdirs-data-no: +installdirs-data-yes: + $(mkdir_p) $(DESTDIR)$(datadir) + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $(DESTDIR)$$dir; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + fi; \ + done; \ + done + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: uninstall-exec uninstall-data +uninstall-exec: +uninstall-data: uninstall-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + for file in $(DISTFILES.common) Makevars.template; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +uninstall-data-no: +uninstall-data-yes: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + done; \ + done + +check: all + +info dvi ps pdf html tags TAGS ctags CTAGS ID: + +mostlyclean: + rm -f remove-potcdate.sed + rm -f stamp-poT + rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f stamp-po $(GMOFILES) + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: + $(MAKE) update-po + @$(MAKE) dist2 +# This is a separate target because 'update-po' must be executed before. +dist2: stamp-po $(DISTFILES) + dists="$(DISTFILES)"; \ + if test "$(PACKAGE)" = "gettext-tools"; then \ + dists="$$dists Makevars.template"; \ + fi; \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + dists="$$dists $(DOMAIN).pot stamp-po"; \ + fi; \ + if test -f $(srcdir)/ChangeLog; then \ + dists="$$dists ChangeLog"; \ + fi; \ + for i in 0 1 2 3 4 5 6 7 8 9; do \ + if test -f $(srcdir)/ChangeLog.$$i; then \ + dists="$$dists ChangeLog.$$i"; \ + fi; \ + done; \ + if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ + for file in $$dists; do \ + if test -f $$file; then \ + cp -p $$file $(distdir) || exit 1; \ + else \ + cp -p $(srcdir)/$$file $(distdir) || exit 1; \ + fi; \ + done + +update-po: Makefile + $(MAKE) $(DOMAIN).pot-update + test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) + $(MAKE) update-gmo + +# General rule for creating PO files. + +.nop.po-create: + @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ + echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ + exit 1 + +# General rule for updating PO files. + +.nop.po-update: + @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ + if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ + cd $(srcdir); \ + if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +$(DUMMYPOFILES): + +update-gmo: Makefile $(GMOFILES) + @: + +Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ + cd $(top_builddir) \ + && $(SHELL) ./config.status $(subdir)/$@.in po-directories + +force: + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/po/Makevars b/po/Makevars new file mode 100644 index 0000000..0859571 --- /dev/null +++ b/po/Makevars @@ -0,0 +1,41 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = Christian Grothoff + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = gnunet-developers@mail.gnu.org + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..a116284 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,226 @@ +src/arm/arm_api.c +src/arm/do_start_process.c +src/arm/gnunet-arm.c +src/arm/gnunet-service-arm.c +src/arm/mockup-service.c +src/ats/ats_api.c +src/ats/ats_api_peer_change_preference.c +src/ats/ats_api_performance.c +src/ats/ats_api_scheduling.c +src/ats/gnunet-service-ats_addresses.c +src/ats/gnunet-service-ats_addresses_mlp.c +src/ats/gnunet-service-ats.c +src/ats/gnunet-service-ats_performance.c +src/ats/gnunet-service-ats_reservations.c +src/ats/gnunet-service-ats_scheduling.c +src/block/block.c +src/block/plugin_block_template.c +src/block/plugin_block_test.c +src/chat/chat.c +src/chat/gnunet-chat.c +src/chat/gnunet-service-chat.c +src/core/core_api.c +src/core/core_api_iterate_peers.c +src/core/gnunet-core-list-connections.c +src/core/gnunet-service-core.c +src/core/gnunet-service-core_clients.c +src/core/gnunet-service-core_kx.c +src/core/gnunet-service-core_neighbours.c +src/core/gnunet-service-core_sessions.c +src/core/gnunet-service-core_typemap.c +src/datacache/datacache.c +src/datacache/plugin_datacache_mysql.c +src/datacache/plugin_datacache_postgres.c +src/datacache/plugin_datacache_sqlite.c +src/datacache/plugin_datacache_template.c +src/datastore/datastore_api.c +src/datastore/gnunet-service-datastore.c +src/datastore/plugin_datastore_mysql.c +src/datastore/plugin_datastore_postgres.c +src/datastore/plugin_datastore_sqlite.c +src/datastore/plugin_datastore_template.c +src/dht/dht_api.c +src/dht/gnunet-dht-get.c +src/dht/gnunet-dht-put.c +src/dht/gnunet-service-dht.c +src/dht/gnunet-service-dht_clients.c +src/dht/gnunet-service-dht_datacache.c +src/dht/gnunet-service-dht_hello.c +src/dht/gnunet-service-dht_neighbours.c +src/dht/gnunet-service-dht_nse.c +src/dht/gnunet-service-dht_routing.c +src/dht/plugin_block_dht.c +src/dns/dns_api.c +src/dns/dnsparser.c +src/dns/gnunet-dns-monitor.c +src/dns/gnunet-dns-redirector.c +src/dns/gnunet-helper-dns.c +src/dns/gnunet-service-dns.c +src/dns/plugin_block_dns.c +src/dv/dv_api.c +src/dv/gnunet-service-dv.c +src/dv/plugin_transport_dv.c +src/exit/gnunet-daemon-exit.c +src/exit/gnunet-helper-exit.c +src/fragmentation/defragmentation.c +src/fragmentation/fragmentation.c +src/fs/fs_api.c +src/fs/fs_directory.c +src/fs/fs_dirmetascan.c +src/fs/fs_download.c +src/fs/fs_file_information.c +src/fs/fs_getopt.c +src/fs/fs_list_indexed.c +src/fs/fs_misc.c +src/fs/fs_namespace_advertise.c +src/fs/fs_namespace.c +src/fs/fs_publish.c +src/fs/fs_publish_ksk.c +src/fs/fs_search.c +src/fs/fs_sharetree.c +src/fs/fs_test_lib.c +src/fs/fs_tree.c +src/fs/fs_unindex.c +src/fs/fs_uri.c +src/fs/gnunet-directory.c +src/fs/gnunet-download.c +src/fs/gnunet-fs.c +src/fs/gnunet-helper-fs-publish.c +src/fs/gnunet-pseudonym.c +src/fs/gnunet-publish.c +src/fs/gnunet-search.c +src/fs/gnunet-service-fs.c +src/fs/gnunet-service-fs_cp.c +src/fs/gnunet-service-fs_indexing.c +src/fs/gnunet-service-fs_lc.c +src/fs/gnunet-service-fs_pe.c +src/fs/gnunet-service-fs_pr.c +src/fs/gnunet-service-fs_push.c +src/fs/gnunet-service-fs_put.c +src/fs/gnunet-unindex.c +src/fs/plugin_block_fs.c +src/gns/gns_api.c +src/gns/gnunet-gns-lookup.c +src/gns/gnunet-service-gns.c +src/gns/namestore_stub_api.c +src/hello/address.c +src/hello/hello.c +src/hostlist/gnunet-daemon-hostlist.c +src/hostlist/hostlist-client.c +src/hostlist/hostlist-server.c +src/mesh/gnunet-service-mesh.c +src/mesh/mesh_api.c +src/mesh/mesh_tunnel_tree.c +src/namestore/gnunet-service-namestore.c +src/namestore/namestore_api.c +src/namestore/plugin_namestore_sqlite.c +src/nat/gnunet-helper-nat-client.c +src/nat/gnunet-helper-nat-client-windows.c +src/nat/gnunet-helper-nat-server.c +src/nat/gnunet-helper-nat-server-windows.c +src/nat/gnunet-nat-server.c +src/nat/nat.c +src/nat/nat_mini.c +src/nat/nat_test.c +src/nse/gnunet-nse-profiler.c +src/nse/gnunet-service-nse.c +src/nse/nse_api.c +src/peerinfo/gnunet-service-peerinfo.c +src/peerinfo/peerinfo_api.c +src/peerinfo/peerinfo_api_notify.c +src/peerinfo-tool/gnunet-peerinfo.c +src/pt/gnunet-daemon-pt.c +src/statistics/gnunet-service-statistics.c +src/statistics/gnunet-statistics.c +src/statistics/statistics_api.c +src/stream/stream_api.c +src/template/gnunet-service-template.c +src/template/gnunet-template.c +src/testing/gnunet-testing.c +src/testing/helper.c +src/testing/testing.c +src/testing/testing_group.c +src/testing/testing_peergroup.c +src/topology/gnunet-daemon-topology.c +src/transport/gnunet-helper-transport-wlan.c +src/transport/gnunet-helper-transport-wlan-dummy.c +src/transport/gnunet-service-transport_blacklist.c +src/transport/gnunet-service-transport.c +src/transport/gnunet-service-transport_clients.c +src/transport/gnunet-service-transport_hello.c +src/transport/gnunet-service-transport_neighbours.c +src/transport/gnunet-service-transport_plugins.c +src/transport/gnunet-service-transport_validation.c +src/transport/gnunet-transport.c +src/transport/gnunet-transport-certificate-creation.c +src/transport/gnunet-transport-connect-running-peers.c +src/transport/gnunet-transport-wlan-sender.c +src/transport/plugin_transport_http.c +src/transport/plugin_transport_http_client.c +src/transport/plugin_transport_http_server.c +src/transport/plugin_transport_smtp.c +src/transport/plugin_transport_tcp.c +src/transport/plugin_transport_template.c +src/transport/plugin_transport_udp_broadcasting.c +src/transport/plugin_transport_udp.c +src/transport/plugin_transport_unix.c +src/transport/plugin_transport_wlan.c +src/transport/transport_api_address_lookup.c +src/transport/transport_api_address_to_string.c +src/transport/transport_api_blacklist.c +src/transport/transport_api.c +src/transport/transport-testing.c +src/tun/tun.c +src/util/bandwidth.c +src/util/bio.c +src/util/client.c +src/util/common_allocation.c +src/util/common_endian.c +src/util/common_logging.c +src/util/configuration.c +src/util/connection.c +src/util/container_bloomfilter.c +src/util/container_heap.c +src/util/container_meta_data.c +src/util/container_multihashmap.c +src/util/container_slist.c +src/util/crypto_aes.c +src/util/crypto_crc.c +src/util/crypto_hash.c +src/util/crypto_hkdf.c +src/util/crypto_kdf.c +src/util/crypto_ksk.c +src/util/crypto_random.c +src/util/crypto_rsa.c +src/util/disk.c +src/util/getopt.c +src/util/getopt_helpers.c +src/util/gnunet-config-diff.c +src/util/gnunet-resolver.c +src/util/gnunet-service-resolver.c +src/util/helper.c +src/util/load.c +src/util/network.c +src/util/os_installation.c +src/util/os_network.c +src/util/os_priority.c +src/util/peer.c +src/util/plugin.c +src/util/program.c +src/util/pseudonym.c +src/util/resolver_api.c +src/util/scheduler.c +src/util/server.c +src/util/server_mst.c +src/util/server_nc.c +src/util/server_tc.c +src/util/service.c +src/util/signal.c +src/util/strings.c +src/util/time.c +src/util/winproc.c +src/vpn/gnunet-helper-vpn.c +src/vpn/gnunet-service-vpn.c +src/vpn/gnunet-vpn.c +src/vpn/vpn_api.c +src/include/gnunet_common.h diff --git a/po/Rules-quot b/po/Rules-quot new file mode 100644 index 0000000..9c2a995 --- /dev/null +++ b/po/Rules-quot @@ -0,0 +1,47 @@ +# Special Makefile rules for English message catalogs with quotation marks. + +DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot + +.SUFFIXES: .insert-header .po-update-en + +en@quot.po-create: + $(MAKE) en@quot.po-update +en@boldquot.po-create: + $(MAKE) en@boldquot.po-update + +en@quot.po-update: en@quot.po-update-en +en@boldquot.po-update: en@boldquot.po-update-en + +.insert-header.po-update-en: + @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ + if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + ll=`echo $$lang | sed -e 's/@.*//'`; \ + LC_ALL=C; export LC_ALL; \ + cd $(srcdir); \ + if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "creation of $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +en@quot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header + +en@boldquot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header + +mostlyclean: mostlyclean-quot +mostlyclean-quot: + rm -f *.insert-header diff --git a/po/boldquot.sed b/po/boldquot.sed new file mode 100644 index 0000000..4b937aa --- /dev/null +++ b/po/boldquot.sed @@ -0,0 +1,10 @@ +s/"\([^"]*\)"/“\1â€/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“â€/""/g +s/“/“/g +s/â€/â€/g +s/‘/‘/g +s/’/’/g diff --git a/po/de.gmo b/po/de.gmo new file mode 100644 index 0000000..7a939b9 Binary files /dev/null and b/po/de.gmo differ diff --git a/po/de.po b/po/de.po new file mode 100644 index 0000000..1266419 --- /dev/null +++ b/po/de.po @@ -0,0 +1,9381 @@ +# German translations for GNUnet package +# German messages for GNUnet. +# Copyright (C) 2004, 2005 Christian Grothoff +# This file is distributed under the same license as the GNUnet package. +# Christian Grothoff , 2004, 2005. +msgid "" +msgstr "" +"Project-Id-Version: GNUnet 0.7.0b\n" +"Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" +"POT-Creation-Date: 2012-02-28 18:30+0100\n" +"PO-Revision-Date: 2006-03-17 21:37+0100\n" +"Last-Translator: Nils Durner \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/arm/arm_api.c:187 +#, fuzzy +msgid "Failed to transmit shutdown request to client.\n" +msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" + +#: src/arm/arm_api.c:378 +#, fuzzy, c-format +msgid "Configuration failes to specify option `%s' in section `%s'!\n" +msgstr "" +"Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein Verzeichnis " +"angeben, in dem FS Daten gespeichert werden.\n" + +#: src/arm/arm_api.c:392 +#, fuzzy, c-format +msgid "Configuration fails to specify option `%s' in section `%s'!\n" +msgstr "" +"Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein Verzeichnis " +"angeben, in dem FS Daten gespeichert werden.\n" + +#: src/arm/arm_api.c:467 +#, fuzzy, c-format +msgid "Error receiving response to `%s' request from ARM for service `%s'\n" +msgstr "Beschädigte Antwort auf `%s' von Knoten `%s' empfangen.\n" + +#: src/arm/arm_api.c:523 +#, c-format +msgid "Requesting start of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:524 +#, c-format +msgid "Requesting termination of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:546 +#, c-format +msgid "Error while trying to transmit request to start `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:548 +#, c-format +msgid "Error while trying to transmit request to stop `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:581 +#, fuzzy, c-format +msgid "Asked to start service `%s' within %llu ms\n" +msgstr "`%s': Nachricht wurde nicht innerhalb %llu ms empfangen.\n" + +#: src/arm/arm_api.c:654 +#, fuzzy, c-format +msgid "Stopping service `%s' within %llu ms\n" +msgstr "Keine Antwort innerhalb %llums erhalten.\n" + +#: src/arm/gnunet-arm.c:149 +#, fuzzy, c-format +msgid "Service `%s' is unknown to ARM.\n" +msgstr "Namespace `%s' hat das Rating %d.\n" + +#: src/arm/gnunet-arm.c:154 +#, fuzzy, c-format +msgid "Service `%s' has been stopped.\n" +msgstr "Dienst gelöscht.\n" + +#: src/arm/gnunet-arm.c:157 +#, fuzzy, c-format +msgid "Service `%s' was already running.\n" +msgstr "Diese Suche läuft bereits!\n" + +#: src/arm/gnunet-arm.c:162 +#, fuzzy, c-format +msgid "Service `%s' has been started.\n" +msgstr "Dienst gelöscht.\n" + +#: src/arm/gnunet-arm.c:165 +#, fuzzy, c-format +msgid "Service `%s' was already being stopped.\n" +msgstr "Dienst gelöscht.\n" + +#: src/arm/gnunet-arm.c:169 +#, fuzzy, c-format +msgid "Service `%s' was already not running.\n" +msgstr "Diese Suche läuft bereits!\n" + +#: src/arm/gnunet-arm.c:173 +#, fuzzy +msgid "Request ignored as ARM is shutting down.\n" +msgstr "`%s' fährt herunter.\n" + +#: src/arm/gnunet-arm.c:177 +#, fuzzy +msgid "Error communicating with ARM service.\n" +msgstr "Informationen über andere GNUnet Knoten ausgeben." + +#: src/arm/gnunet-arm.c:181 +#, fuzzy +msgid "Timeout communicating with ARM service.\n" +msgstr "Informationen über andere GNUnet Knoten ausgeben." + +#: src/arm/gnunet-arm.c:185 +#, fuzzy +msgid "Operation failed.\n" +msgstr "Absicherung fehlgeschlagen bei %s:%d.\n" + +#: src/arm/gnunet-arm.c:189 +msgid "Unknown response code from ARM.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:216 +#, fuzzy, c-format +msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" +msgstr "" +"Es muss eine Liste von Freunden in der Konfigurationsdatei unter `%s' in der " +"Sektion `%s' angegeben werden.\n" + +#: src/arm/gnunet-arm.c:224 src/arm/gnunet-arm.c:324 +msgid "Fatal error initializing ARM API.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:247 +#, fuzzy, c-format +msgid "Failed to remove configuration file %s\n" +msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" + +#: src/arm/gnunet-arm.c:253 +#, fuzzy, c-format +msgid "Failed to remove servicehome directory %s\n" +msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#: src/arm/gnunet-arm.c:355 +msgid "stop all GNUnet services" +msgstr "" + +#: src/arm/gnunet-arm.c:357 +msgid "start a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:359 +msgid "stop a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:361 +msgid "start all GNUnet default services" +msgstr "" + +#: src/arm/gnunet-arm.c:364 +msgid "stop and start all GNUnet default services" +msgstr "" + +#: src/arm/gnunet-arm.c:367 +msgid "delete config file and directory on exit" +msgstr "" + +#: src/arm/gnunet-arm.c:369 +msgid "don't print status messages" +msgstr "" + +#: src/arm/gnunet-arm.c:372 +#, fuzzy +msgid "timeout for completing current operation" +msgstr "Zeit, die gewartet wird, bis der Durchlauf fertiggestellt wird (in ms)" + +#: src/arm/gnunet-arm.c:383 +msgid "Control services and the Automated Restart Manager (ARM)" +msgstr "" + +#: src/arm/gnunet-service-arm.c:328 +#, fuzzy, c-format +msgid "Failed to start service `%s'\n" +msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" + +#: src/arm/gnunet-service-arm.c:331 +#, fuzzy, c-format +msgid "Starting service `%s'\n" +msgstr "Collection `%s' begonnen.\n" + +#: src/arm/gnunet-service-arm.c:357 +#, fuzzy +msgid "Could not send status result to client\n" +msgstr "Anfrage konnte nicht an gnunetd gesendet werden.\n" + +#: src/arm/gnunet-service-arm.c:484 +#, fuzzy, c-format +msgid "Unable to create socket for service `%s': %s\n" +msgstr "Fehler beim Anlegen des Benutzerkontos:" + +#: src/arm/gnunet-service-arm.c:506 +#, c-format +msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:520 +#, c-format +msgid "ARM now monitors connections to service `%s' at `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:628 +#, fuzzy, c-format +msgid "Preparing to stop `%s'\n" +msgstr "Collection `%s' begonnen.\n" + +#: src/arm/gnunet-service-arm.c:782 +#, fuzzy, c-format +msgid "Restarting service `%s'.\n" +msgstr "Collection `%s' begonnen.\n" + +#: src/arm/gnunet-service-arm.c:877 +msgid "exit" +msgstr "" + +#: src/arm/gnunet-service-arm.c:882 +msgid "signal" +msgstr "" + +#: src/arm/gnunet-service-arm.c:887 +#, fuzzy +msgid "unknown" +msgstr "Unbekannter Fehler" + +#: src/arm/gnunet-service-arm.c:921 +#, c-format +msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:967 src/arm/mockup-service.c:41 +#, fuzzy +msgid "Failed to transmit shutdown ACK.\n" +msgstr "Fehler beim Starten der Collection.\n" + +#: src/arm/gnunet-service-arm.c:1067 +#, fuzzy, c-format +msgid "Configuration file `%s' for service `%s' not valid: %s\n" +msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" + +#: src/arm/gnunet-service-arm.c:1069 +msgid "option missing" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1152 +#, fuzzy, c-format +msgid "Starting default services `%s'\n" +msgstr "Collection `%s' begonnen.\n" + +#: src/arm/gnunet-service-arm.c:1163 +#, c-format +msgid "Default service `%s' not configured correctly!\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1177 +msgid "" +"No default services configured, GNUnet will not really start right now.\n" +msgstr "" + +#: src/arm/mockup-service.c:46 +msgid "Transmitting shutdown ACK.\n" +msgstr "" + +#: src/arm/mockup-service.c:69 +msgid "Initiating shutdown as requested by client.\n" +msgstr "" + +#: src/block/block.c:105 +#, fuzzy, c-format +msgid "Loading block plugin `%s'\n" +msgstr "Teste Transport(e) %s\n" + +#: src/chat/chat.c:175 +#, fuzzy +msgid "Could not transmit confirmation receipt\n" +msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" + +#: src/chat/chat.c:283 +msgid "The current user must be the the first one joined\n" +msgstr "" + +#: src/chat/chat.c:412 +#, fuzzy, c-format +msgid "Unknown message type: '%u'\n" +msgstr "Unbekannte Operation `%s'\n" + +#: src/chat/chat.c:472 +#, fuzzy, c-format +msgid "Configuration option `%s' in section `%s' missing\n" +msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" + +#: src/chat/chat.c:480 +#, fuzzy, c-format +msgid "Failed to access chat home directory `%s'\n" +msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#: src/chat/chat.c:498 +#, fuzzy, c-format +msgid "Failed to create/open key in file `%s'\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/chat/chat.c:559 +#, fuzzy +msgid "Could not serialize metadata\n" +msgstr "Konnte libgnunetutil nicht initialisieren!\n" + +#: src/chat/chat.c:674 +#, fuzzy +msgid "Failed to connect to the chat service\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/chat/chat.c:680 +msgid "Undefined mandatory parameter: joinCallback\n" +msgstr "" + +#: src/chat/chat.c:686 +msgid "Undefined mandatory parameter: messageCallback\n" +msgstr "" + +#: src/chat/chat.c:692 +msgid "Undefined mandatory parameter: memberCallback\n" +msgstr "" + +#: src/chat/gnunet-chat.c:92 +msgid "Joined\n" +msgstr "" + +#: src/chat/gnunet-chat.c:124 +msgid "anonymous" +msgstr "" + +#: src/chat/gnunet-chat.c:130 +#, fuzzy, c-format +msgid "(%s) `%s' said: %s\n" +msgstr "`%s' %s schlug fehl: %s\n" + +#: src/chat/gnunet-chat.c:133 src/chat/gnunet-chat.c:136 +#, fuzzy, c-format +msgid "(%s) `%s' said to you: %s\n" +msgstr "`%s' %s schlug fehl: %s\n" + +#: src/chat/gnunet-chat.c:139 +#, fuzzy, c-format +msgid "(%s) `%s' said for sure: %s\n" +msgstr "`%s' fehlgeschlagen für Laufwerk %s: %u\n" + +#: src/chat/gnunet-chat.c:142 +#, fuzzy, c-format +msgid "(%s) `%s' said to you for sure: %s\n" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/chat/gnunet-chat.c:145 +#, fuzzy, c-format +msgid "(%s) `%s' was confirmed that you received: %s\n" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/chat/gnunet-chat.c:148 +#, fuzzy, c-format +msgid "(%s) `%s' was confirmed that you and only you received: %s\n" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/chat/gnunet-chat.c:151 +#, fuzzy, c-format +msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/chat/gnunet-chat.c:156 +#, fuzzy, c-format +msgid "" +"(%s) `%s' was confirmed that you and only you received from him or her: %s\n" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/chat/gnunet-chat.c:159 +#, fuzzy, c-format +msgid "(%s) `%s' said off the record: %s\n" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/chat/gnunet-chat.c:162 +#, c-format +msgid "(%s) <%s> said using an unknown message type: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:193 +#, c-format +msgid "'%s' acknowledged message #%d\n" +msgstr "" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' entered the room\n" +msgstr "" + +#: src/chat/gnunet-chat.c:224 +#, fuzzy, c-format +msgid "`%s' left the room\n" +msgstr "Fehler beim Binden an UDP Port %d.\n" + +#: src/chat/gnunet-chat.c:284 src/chat/gnunet-chat.c:316 +#, fuzzy +msgid "Could not change username\n" +msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" + +#: src/chat/gnunet-chat.c:288 src/chat/gnunet-chat.c:630 +#, fuzzy, c-format +msgid "Joining room `%s' as user `%s'...\n" +msgstr "Ungültige Antwort auf `%s' von Knoten `%s' empfangen.\n" + +#: src/chat/gnunet-chat.c:320 +#, fuzzy, c-format +msgid "Changed username to `%s'\n" +msgstr "Benutzer/Gruppe kann nicht zu `%s' gewechselt werden: %s\n" + +#: src/chat/gnunet-chat.c:333 +#, c-format +msgid "Users in room `%s': " +msgstr "" + +#: src/chat/gnunet-chat.c:371 +msgid "Syntax: /msg USERNAME MESSAGE" +msgstr "" + +#: src/chat/gnunet-chat.c:379 +#, fuzzy, c-format +msgid "Unknown user `%s'\n" +msgstr "Unbekannte Operation `%s'\n" + +#: src/chat/gnunet-chat.c:395 +#, c-format +msgid "User `%s' is currently not in the room!\n" +msgstr "" + +#: src/chat/gnunet-chat.c:448 +#, fuzzy, c-format +msgid "Unknown command `%s'\n" +msgstr "Unbekannte Operation `%s'\n" + +#: src/chat/gnunet-chat.c:459 +msgid "" +"Use `/join #roomname' to join a chat room. Joining a room will cause you to " +"leave the current room" +msgstr "" + +#: src/chat/gnunet-chat.c:463 +msgid "" +"Use `/nick nickname' to change your nickname. This will cause you to leave " +"the current room and immediately rejoin it with the new name." +msgstr "" + +#: src/chat/gnunet-chat.c:467 +msgid "" +"Use `/msg nickname message' to send a private message to the specified user" +msgstr "" + +#: src/chat/gnunet-chat.c:470 +msgid "The `/notice' command is an alias for `/msg'" +msgstr "" + +#: src/chat/gnunet-chat.c:472 +msgid "The `/query' command is an alias for `/msg'" +msgstr "" + +#: src/chat/gnunet-chat.c:474 +msgid "Use `/sig message' to send a signed public message" +msgstr "" + +#: src/chat/gnunet-chat.c:477 +msgid "Use `/ack message' to require signed acknowledgment of the message" +msgstr "" + +#: src/chat/gnunet-chat.c:480 +msgid "Use `/anonymous message' to send a public anonymous message" +msgstr "" + +#: src/chat/gnunet-chat.c:482 +msgid "The `/anon' command is an alias for `/anonymous'" +msgstr "" + +#: src/chat/gnunet-chat.c:484 +msgid "Use `/quit' to terminate gnunet-chat" +msgstr "" + +#: src/chat/gnunet-chat.c:486 +msgid "The `/leave' command is an alias for `/quit'" +msgstr "" + +#: src/chat/gnunet-chat.c:489 +msgid "Use `/names' to list all of the current members in the chat room" +msgstr "" + +#: src/chat/gnunet-chat.c:491 +msgid "Use `/help command' to get help for a specific command" +msgstr "" + +#: src/chat/gnunet-chat.c:606 +#, fuzzy +msgid "You must specify a nickname\n" +msgstr "Sie müssen einen Empfänger angeben!\n" + +#: src/chat/gnunet-chat.c:622 +#, fuzzy, c-format +msgid "Failed to join room `%s'\n" +msgstr "Fehler beim Binden an UDP Port %d.\n" + +#: src/chat/gnunet-chat.c:655 +msgid "set the nickname to use (required)" +msgstr "" + +#: src/chat/gnunet-chat.c:658 +msgid "set the chat room to join" +msgstr "" + +#: src/chat/gnunet-chat.c:670 +msgid "Join a chat on GNUnet." +msgstr "" + +#: src/chat/gnunet-service-chat.c:267 +#, fuzzy +msgid "Failed to queue a message notification\n" +msgstr "Fehler beim Speichern der Konfiguration!" + +#: src/chat/gnunet-service-chat.c:546 +#, fuzzy +msgid "Failed to queue a join notification\n" +msgstr "Fehler beim Abfragen der Netzwerkverkehrsbedingungen von gnunetd.\n" + +#: src/chat/gnunet-service-chat.c:729 +#, fuzzy +msgid "Failed to queue a confirmation receipt\n" +msgstr "Fehler beim Speichern der Konfiguration!" + +#: src/chat/gnunet-service-chat.c:907 +#, fuzzy +msgid "Failed to queue a leave notification\n" +msgstr "Fehler beim Speichern der Konfiguration!" + +#: src/core/core_api.c:798 +msgid "Client was disconnected from core service, trying to reconnect.\n" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:77 +#: src/peerinfo-tool/gnunet-peerinfo.c:60 +#, fuzzy, c-format +msgid "Peer `%s'\n" +msgstr "Ich bin Peer `%s'.\n" + +#: src/core/gnunet-core-list-connections.c:175 +#: src/peerinfo-tool/gnunet-peerinfo.c:194 +#, fuzzy, c-format +msgid "Invalid command line argument `%s'\n" +msgstr "Ungültige Kommandozeilen Parameter:\n" + +#: src/core/gnunet-core-list-connections.c:196 +#: src/peerinfo-tool/gnunet-peerinfo.c:252 +msgid "don't resolve host names" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:203 +#, fuzzy +msgid "Print information about connected peers." +msgstr "Informationen über andere GNUnet Knoten ausgeben." + +#: src/core/gnunet-service-core.c:99 +#, c-format +msgid "Core service of `%4s' ready.\n" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:360 +#, fuzzy +msgid "# send requests dropped (disconnected)" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/core/gnunet-service-core_clients.c:465 +#, fuzzy +msgid "# messages discarded (session disconnected)" +msgstr "# defragmentierter Nachrichten" + +#: src/core/gnunet-service-core_clients.c:801 +#, fuzzy, c-format +msgid "# bytes of messages of type %u received" +msgstr "# Bytes Rauschen empfangen" + +#: src/core/gnunet-service-core_kx.c:493 +msgid "# bytes encrypted" +msgstr "# Bytes verschlüsselt" + +#: src/core/gnunet-service-core_kx.c:543 +msgid "# bytes decrypted" +msgstr "# Bytes entschlüsselt" + +#: src/core/gnunet-service-core_kx.c:604 src/dv/gnunet-service-dv.c:3002 +#: src/hostlist/hostlist-server.c:436 src/peerinfo-tool/gnunet-peerinfo.c:151 +#, fuzzy +msgid "Error in communication with PEERINFO service\n" +msgstr "Informationen über andere GNUnet Knoten ausgeben." + +#: src/core/gnunet-service-core_kx.c:623 +msgid "# Delayed connecting due to lack of public key" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:673 +msgid "# key exchanges initiated" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:694 +msgid "# key exchanges stopped" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:746 +#, fuzzy +msgid "# session keys received" +msgstr "# Sitzungsschlüssel abgelehnt" + +#: src/core/gnunet-service-core_kx.c:765 +#, fuzzy, c-format +msgid "`%s' is for `%s', not for me. Ignoring.\n" +msgstr "Größe der `%s' Nachricht ist zu kurz. Nachricht wird ignoriert.\n" + +#: src/core/gnunet-service-core_kx.c:803 +#, fuzzy +msgid "# SET_KEY messages decrypted" +msgstr "# defragmentierter Nachrichten" + +#: src/core/gnunet-service-core_kx.c:883 +#: src/transport/gnunet-service-transport_validation.c:803 +#, fuzzy +msgid "# PING messages received" +msgstr "# PING Nachrichten erstellt" + +#: src/core/gnunet-service-core_kx.c:917 +#, c-format +msgid "" +"Received PING from `%s' for different identity: I am `%s', PONG identity: `" +"%s'\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:938 +#, fuzzy +msgid "# PONG messages created" +msgstr "# PING Nachrichten erstellt" + +#: src/core/gnunet-service-core_kx.c:1026 +#, fuzzy +msgid "# sessions terminated by timeout" +msgstr "# Bytes verworfen von TCP (ausgehend)" + +#: src/core/gnunet-service-core_kx.c:1037 +#, fuzzy +msgid "# keepalive messages sent" +msgstr "# Klartext PING Nachrichten gesendet" + +#: src/core/gnunet-service-core_kx.c:1095 +#: src/transport/gnunet-service-transport_validation.c:1026 +#, fuzzy +msgid "# PONG messages received" +msgstr "# verschlüsselter PONG Nachrichten empfangen" + +#: src/core/gnunet-service-core_kx.c:1125 +#, fuzzy +msgid "# PONG messages decrypted" +msgstr "# PING Nachrichten erstellt" + +#: src/core/gnunet-service-core_kx.c:1157 +#, fuzzy +msgid "# session keys confirmed via PONG" +msgstr "# Knotenankündigungen empfangen" + +#: src/core/gnunet-service-core_kx.c:1223 +#, fuzzy +msgid "# SET_KEY and PING messages created" +msgstr "# PING Nachrichten erstellt" + +#: src/core/gnunet-service-core_kx.c:1364 +msgid "# failed to decrypt message (no session key)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1406 +#: src/core/gnunet-service-core_kx.c:1431 +#, fuzzy +msgid "# bytes dropped (duplicates)" +msgstr "# Bytes verworfen von UDP (outgoing)" + +#: src/core/gnunet-service-core_kx.c:1418 +#, fuzzy +msgid "# bytes dropped (out of sequence)" +msgstr "# Bytes verworfen von UDP (outgoing)" + +#: src/core/gnunet-service-core_kx.c:1455 +#, fuzzy, c-format +msgid "Message received far too old (%llu ms). Content ignored.\n" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/core/gnunet-service-core_kx.c:1459 +#, fuzzy +msgid "# bytes dropped (ancient message)" +msgstr "# Bytes verworfen von UDP (outgoing)" + +#: src/core/gnunet-service-core_kx.c:1467 +#, fuzzy +msgid "# bytes of payload decrypted" +msgstr "# Bytes entschlüsselt" + +#: src/core/gnunet-service-core_kx.c:1528 +#, fuzzy +msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" +msgstr "GNUnet Konfiguration" + +#: src/core/gnunet-service-core_kx.c:1536 +msgid "Core service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1546 src/hostlist/hostlist-server.c:555 +#: src/peerinfo-tool/gnunet-peerinfo.c:202 +#: src/transport/gnunet-service-transport.c:595 +#, fuzzy +msgid "Could not access PEERINFO service. Exiting.\n" +msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" + +#: src/core/gnunet-service-core_neighbours.c:163 +#, fuzzy +msgid "# sessions terminated by transport disconnect" +msgstr "# Knotenankündigungen empfangen" + +#: src/core/gnunet-service-core_neighbours.c:180 +#: src/core/gnunet-service-core_neighbours.c:342 +msgid "# neighbour entries allocated" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:251 +msgid "# encrypted bytes given to transport" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:430 +#, fuzzy, c-format +msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" +msgstr "Ungültige Nachricht des Typs %u empfangen. Nachricht wird verworfen.\n" + +#: src/core/gnunet-service-core_sessions.c:208 +#: src/core/gnunet-service-core_sessions.c:273 +msgid "# entries in session map" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:238 +#, fuzzy +msgid "# type map refreshes sent" +msgstr "# p2p Trace-Antworten gesendet" + +#: src/core/gnunet-service-core_sessions.c:414 +msgid "# messages discarded (expired prior to transmission)" +msgstr "" + +#: src/core/gnunet-service-core_typemap.c:110 +#: src/core/gnunet-service-core_typemap.c:121 +#, fuzzy +msgid "# type maps received" +msgstr "# verschlüsselter PING Nachrichten empfangen" + +#: src/core/gnunet-service-core_typemap.c:151 +msgid "# updates to my type map" +msgstr "" + +#: src/datacache/datacache.c:118 src/datacache/datacache.c:255 +#: src/datastore/gnunet-service-datastore.c:854 +#, fuzzy +msgid "# bytes stored" +msgstr "# bytes in der Datenbank" + +#: src/datacache/datacache.c:144 src/datacache/datacache.c:151 +#: src/datastore/gnunet-service-datastore.c:1531 +#: src/datastore/gnunet-service-datastore.c:1542 +#, fuzzy, c-format +msgid "No `%s' specified for `%s' in configuration!\n" +msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" + +#: src/datacache/datacache.c:183 +#, c-format +msgid "Loading `%s' datacache plugin\n" +msgstr "" + +#: src/datacache/datacache.c:191 +#, fuzzy, c-format +msgid "Failed to load datacache plugin for `%s'\n" +msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" + +#: src/datacache/datacache.c:281 +#, fuzzy +msgid "# requests received" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/datacache/datacache.c:291 +msgid "# requests filtered by bloom filter" +msgstr "" + +#: src/datacache/plugin_datacache_mysql.c:103 +#: src/datacache/plugin_datacache_mysql.c:110 +#: src/datacache/plugin_datacache_mysql.c:517 +#: src/datacache/plugin_datacache_mysql.c:526 +#: src/datacache/plugin_datacache_mysql.c:598 +#: src/datacache/plugin_datacache_mysql.c:614 +#: src/datacache/plugin_datacache_sqlite.c:71 +#: src/datacache/plugin_datacache_sqlite.c:74 +#: src/datastore/plugin_datastore_mysql.c:139 +#: src/datastore/plugin_datastore_mysql.c:146 +#: src/datastore/plugin_datastore_mysql.c:613 +#: src/datastore/plugin_datastore_mysql.c:673 +#: src/datastore/plugin_datastore_mysql.c:685 +#: src/datastore/plugin_datastore_mysql.c:1362 +#: src/datastore/plugin_datastore_mysql.c:1376 +#: src/datastore/plugin_datastore_sqlite.c:61 +#: src/namestore/plugin_namestore_sqlite.c:49 src/util/crypto_ksk.c:49 +#: src/util/crypto_rsa.c:92 src/include/gnunet_common.h:507 +#: src/include/gnunet_common.h:514 +#, c-format +msgid "`%s' failed at %s:%d with error: %s\n" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/datacache/plugin_datacache_mysql.c:224 +#: src/datastore/plugin_datastore_mysql.c:316 +#, c-format +msgid "Trying to use file `%s' for MySQL configuration.\n" +msgstr "Versuche, Datei `%s' für MySQL Konfiguration zu verwenden.\n" + +#: src/datacache/plugin_datacache_mysql.c:230 +#: src/datastore/plugin_datastore_mysql.c:322 +#, fuzzy, c-format +msgid "Could not access file `%s': %s\n" +msgstr "`%s' konnte nicht aufgelöst werden: %s\n" + +#: src/datacache/plugin_datacache_mysql.c:979 +msgid "MySQL datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_postgres.c:79 +#: src/datastore/plugin_datastore_postgres.c:93 +#, fuzzy, c-format +msgid "`%s:%s' failed at %s:%d with error: %s" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/datacache/plugin_datacache_postgres.c:149 +#, fuzzy, c-format +msgid "Unable to initialize Postgres: %s" +msgstr "SQLite Datenbank konnte nicht initialisiert werden: %s.\n" + +#: src/datacache/plugin_datacache_postgres.c:499 +msgid "Postgres datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:424 +msgid "Sqlite datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:457 +#: src/datastore/plugin_datastore_sqlite.c:414 +#: src/namestore/plugin_namestore_sqlite.c:381 +msgid "Tried to close sqlite without finalizing all prepared statements.\n" +msgstr "" + +#: src/datacache/plugin_datacache_template.c:121 +msgid "Template datacache running\n" +msgstr "" + +#: src/datastore/datastore_api.c:289 +#, fuzzy +msgid "Failed to transmit request to drop database.\n" +msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" + +#: src/datastore/datastore_api.c:372 +msgid "# queue entry timeouts" +msgstr "" + +#: src/datastore/datastore_api.c:418 +msgid "# queue overflows" +msgstr "" + +#: src/datastore/datastore_api.c:445 +#, fuzzy +msgid "# queue entries created" +msgstr "# dht Anfragen weitergeleitet" + +#: src/datastore/datastore_api.c:465 +#, fuzzy +msgid "# Requests dropped from datastore queue" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/datastore/datastore_api.c:513 +msgid "# datastore connections (re)created" +msgstr "" + +#: src/datastore/datastore_api.c:540 +msgid "# reconnected to DATASTORE" +msgstr "" + +#: src/datastore/datastore_api.c:608 +#, fuzzy +msgid "# transmission request failures" +msgstr "# Klartext PONG Nachrichten empfangen" + +#: src/datastore/datastore_api.c:631 +#, fuzzy +msgid "# bytes sent to datastore" +msgstr "# bytes in der Datenbank" + +#: src/datastore/datastore_api.c:772 +#, fuzzy +msgid "Failed to receive status response from database." +msgstr "" +"\n" +"Fehler beim Empfangen der Antwort von gnunetd.\n" + +#: src/datastore/datastore_api.c:786 +msgid "Error reading response from datastore service" +msgstr "" + +#: src/datastore/datastore_api.c:798 src/datastore/datastore_api.c:804 +#, fuzzy +msgid "Invalid error message received from datastore service" +msgstr "Ungültige `%s' Nachricht von Knoten `%s' empfangen.\n" + +#: src/datastore/datastore_api.c:810 +#, fuzzy +msgid "# status messages received" +msgstr "# verschlüsselter PING Nachrichten empfangen" + +#: src/datastore/datastore_api.c:883 +#, fuzzy +msgid "# PUT requests executed" +msgstr "# dht Anfragen weitergeleitet" + +#: src/datastore/datastore_api.c:954 +#, fuzzy +msgid "# RESERVE requests executed" +msgstr "# dht Anfragen weitergeleitet" + +#: src/datastore/datastore_api.c:1019 +msgid "# RELEASE RESERVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1080 +#, fuzzy +msgid "# UPDATE requests executed" +msgstr "# dht Anfragen weitergeleitet" + +#: src/datastore/datastore_api.c:1148 +#, fuzzy +msgid "# REMOVE requests executed" +msgstr "# dht Anfragen weitergeleitet" + +#: src/datastore/datastore_api.c:1193 +#, fuzzy +msgid "Failed to receive response from database.\n" +msgstr "" +"\n" +"Fehler beim Empfangen der Antwort von gnunetd.\n" + +#: src/datastore/datastore_api.c:1253 +#, fuzzy +msgid "# Results received" +msgstr "# Bytes empfangen über TCP" + +#: src/datastore/datastore_api.c:1324 +msgid "# GET REPLICATION requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1391 +msgid "# GET ZERO ANONYMITY requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1455 +#, fuzzy +msgid "# GET requests executed" +msgstr "# dht Anfragen weitergeleitet" + +#: src/datastore/gnunet-service-datastore.c:351 +#, fuzzy +msgid "# bytes expired" +msgstr "# Bytes empfangen über TCP" + +#: src/datastore/gnunet-service-datastore.c:426 +msgid "# bytes purged (low-priority)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:486 +msgid "Transmission to client failed!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:640 +msgid "# results found" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:685 +#, c-format +msgid "" +"Insufficient space (%llu bytes are available) to satisfy `%s' request for " +"%llu bytes\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:696 +#, c-format +msgid "" +"The requested amount (%llu bytes) is larger than the cache size (%llu " +"bytes)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:700 +msgid "" +"Insufficient space to satisfy request and requested amount is larger than " +"cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:706 +msgid "Insufficient space to satisfy request" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:711 +#: src/datastore/gnunet-service-datastore.c:765 +#: src/datastore/gnunet-service-datastore.c:986 +#: src/datastore/gnunet-service-datastore.c:1465 +msgid "# reserved" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:780 +msgid "Could not find matching reservation" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:868 +#, c-format +msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1034 +#, fuzzy +msgid "# GET requests received" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/datastore/gnunet-service-datastore.c:1048 +msgid "# requests filtered by bloomfilter" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1076 +#, fuzzy +msgid "# UPDATE requests received" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/datastore/gnunet-service-datastore.c:1110 +#, fuzzy +msgid "# GET REPLICATION requests received" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/datastore/gnunet-service-datastore.c:1145 +#, fuzzy +msgid "# GET ZERO ANONYMITY requests received" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/datastore/gnunet-service-datastore.c:1172 +#, fuzzy +msgid "Content not found" +msgstr "Kommando `%s' wurde nicht gefunden!\n" + +#: src/datastore/gnunet-service-datastore.c:1182 +msgid "# bytes removed (explicit request)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1216 +#, fuzzy +msgid "# REMOVE requests received" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/datastore/gnunet-service-datastore.c:1260 +#, c-format +msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1323 +#, c-format +msgid "Loading `%s' datastore plugin\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1332 +#, fuzzy, c-format +msgid "Failed to load datastore plugin for `%s'\n" +msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" + +#: src/datastore/gnunet-service-datastore.c:1536 +#, fuzzy, c-format +msgid "# bytes used in file-sharing datastore `%s'" +msgstr "# bytes erlaubt in der Datenbank" + +#: src/datastore/gnunet-service-datastore.c:1547 +msgid "# quota" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1549 +msgid "# cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1562 +#, c-format +msgid "Could not use specified filename `%s' for bloomfilter.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1580 +#: src/datastore/gnunet-service-datastore.c:1596 +#, fuzzy, c-format +msgid "Failed to remove bogus bloomfilter file `%s'\n" +msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" + +#: src/datastore/gnunet-service-datastore.c:1626 +#, fuzzy +msgid "Failed to initialize bloomfilter.\n" +msgstr "SQLite Datenbank konnte nicht initialisiert werden.\n" + +#: src/datastore/gnunet-service-datastore.c:1655 +msgid "Rebuilding bloomfilter. Please be patient.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1660 +msgid "Plugin does not support get_keys function. Please fix!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1663 +msgid "Bloomfilter construction complete.\n" +msgstr "" + +#: src/datastore/plugin_datastore_mysql.c:529 +#: src/datastore/plugin_datastore_mysql.c:1336 +#, fuzzy, c-format +msgid "Failed to prepare statement `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/datastore/plugin_datastore_mysql.c:622 +#: src/datastore/plugin_datastore_mysql.c:1346 +#, fuzzy, c-format +msgid "`%s' for `%s' failed at %s:%d with error: %s\n" +msgstr "`%s' an `%s' schlug fehl bei %s:%d mit dem Fehler: %s\n" + +#: src/datastore/plugin_datastore_mysql.c:1581 +msgid "Mysql database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_postgres.c:173 +#, fuzzy, c-format +msgid "Unable to initialize Postgres with configuration `%s': %s" +msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" + +#: src/datastore/plugin_datastore_postgres.c:1017 +msgid "Postgres database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:61 +#, fuzzy, c-format +msgid "`%s' failed at %s:%u with error: %s" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/datastore/plugin_datastore_sqlite.c:239 +#: src/namestore/plugin_namestore_sqlite.c:223 +#, fuzzy, c-format +msgid "Option `%s' in section `%s' missing in configuration!\n" +msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" + +#: src/datastore/plugin_datastore_sqlite.c:266 +#: src/namestore/plugin_namestore_sqlite.c:248 +#, c-format +msgid "Unable to initialize SQLite: %s.\n" +msgstr "SQLite Datenbank konnte nicht initialisiert werden: %s.\n" + +#: src/datastore/plugin_datastore_sqlite.c:669 +#, fuzzy +msgid "Invalid data in database. Trying to fix (by deletion).\n" +msgstr "Ungültige Daten in %s. Korrektur wird versucht (durch Löschung).\n" + +#: src/datastore/plugin_datastore_sqlite.c:1159 +msgid "sqlite version to old to determine size, assuming zero\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1178 +#, c-format +msgid "" +"Using sqlite page utilization to estimate payload (%llu pages of size %llu " +"bytes)\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1218 +#: src/namestore/plugin_namestore_sqlite.c:779 +#, fuzzy +msgid "Sqlite database running\n" +msgstr "sqlite Datenspeicher" + +#: src/datastore/plugin_datastore_template.c:241 +msgid "Template database running\n" +msgstr "" + +#: src/dht/dht_api.c:280 +#, fuzzy +msgid "Failed to connect to the DHT service!\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-put.c:172 +#: src/gns/gnunet-gns-lookup.c:179 +msgid "the query key" +msgstr "" + +#: src/dht/gnunet-dht-get.c:204 src/gns/gnunet-gns-lookup.c:182 +msgid "how many parallel requests (replicas) to create" +msgstr "" + +#: src/dht/gnunet-dht-get.c:207 src/gns/gnunet-gns-lookup.c:185 +msgid "the type of data to look for" +msgstr "" + +#: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:181 +#: src/gns/gnunet-gns-lookup.c:188 +msgid "how long to execute this query before giving up?" +msgstr "" + +#: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-put.c:184 +#: src/fs/gnunet-download.c:270 src/fs/gnunet-publish.c:725 +#: src/fs/gnunet-search.c:297 src/fs/gnunet-unindex.c:169 +#: src/gns/gnunet-gns-lookup.c:191 src/nse/gnunet-nse-profiler.c:908 +msgid "be verbose (print progress information)" +msgstr "" + +#: src/dht/gnunet-dht-get.c:232 +msgid "Issue a GET request to the GNUnet DHT, prints results." +msgstr "" + +#: src/dht/gnunet-dht-put.c:100 +#, fuzzy +msgid "PUT request sent!\n" +msgstr "# gap Anfragen insgesamt empfangen" + +#: src/dht/gnunet-dht-put.c:124 +msgid "Must provide KEY and DATA for DHT put!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:132 +#, fuzzy, c-format +msgid "Could not connect to %s service!\n" +msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" + +#: src/dht/gnunet-dht-put.c:137 +#, fuzzy, c-format +msgid "Connected to %s service!\n" +msgstr "`%s' hat sich mit `%s' verbunden.\n" + +#: src/dht/gnunet-dht-put.c:152 +#, c-format +msgid "Issuing put request for `%s' with data `%s'!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:166 +msgid "the data to insert under the key" +msgstr "" + +#: src/dht/gnunet-dht-put.c:169 +msgid "how long to store this entry in the dht (in seconds)" +msgstr "" + +#: src/dht/gnunet-dht-put.c:175 +msgid "how many replicas to create" +msgstr "" + +#: src/dht/gnunet-dht-put.c:178 +msgid "the type to insert data as" +msgstr "" + +#: src/dht/gnunet-dht-put.c:203 +msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." +msgstr "" + +#: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:556 +#: src/testing/testing.c:1979 src/testing/testing.c:2009 +#, fuzzy +msgid "Failed to connect to transport service!\n" +msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" + +#: src/dht/gnunet-service-dht_clients.c:371 +#, fuzzy +msgid "# GET requests from clients injected" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/dht/gnunet-service-dht_clients.c:462 +#, fuzzy +msgid "# PUT requests received from clients" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/dht/gnunet-service-dht_clients.c:529 +#, fuzzy +msgid "# GET requests received from clients" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/dht/gnunet-service-dht_clients.c:624 +#, fuzzy +msgid "# GET STOP requests received from clients" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/dht/gnunet-service-dht_clients.c:854 +msgid "# Key match, type mismatches in REPLY to CLIENT" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:869 +msgid "# Duplicate REPLIES to CLIENT request dropped" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:906 +#, fuzzy, c-format +msgid "Unsupported block type (%u) in request!\n" +msgstr "Ungültige Nachricht des Typs %u empfangen. Nachricht wird verworfen.\n" + +#: src/dht/gnunet-service-dht_clients.c:928 +#, fuzzy +msgid "# RESULTS queued for clients" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/dht/gnunet-service-dht_clients.c:979 +#: src/dht/gnunet-service-dht_clients.c:1022 +msgid "# REPLIES ignored for CLIENTS (no match)" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:989 +#, fuzzy +msgid "Could not pass reply to client, message too big!\n" +msgstr "'join' Nachricht konnte nicht an gnunetd gesendet werden.\n" + +#: src/dht/gnunet-service-dht_datacache.c:93 +#, fuzzy, c-format +msgid "%s request received, but have no datacache!\n" +msgstr "# Bytes empfangen über TCP" + +#: src/dht/gnunet-service-dht_datacache.c:103 +msgid "# ITEMS stored in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:209 +msgid "# Good RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:220 +msgid "# Duplicate RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:226 +msgid "# Invalid RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:238 +msgid "# Unsupported RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:241 +#, c-format +msgid "Unsupported block type (%u) in local response!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:271 +#, fuzzy +msgid "# GET requests given to datacache" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/dht/gnunet-service-dht_hello.c:82 +#, fuzzy +msgid "# HELLOs obtained from peerinfo" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/dht/gnunet-service-dht_neighbours.c:481 +msgid "# Preference updates given to core" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:573 +#, fuzzy +msgid "# FIND PEER messages initiated" +msgstr "# PING Nachrichten erstellt" + +#: src/dht/gnunet-service-dht_neighbours.c:629 +#: src/dht/gnunet-service-dht_neighbours.c:689 +#, fuzzy +msgid "# Peers connected" +msgstr "# verbundener Knoten" + +#: src/dht/gnunet-service-dht_neighbours.c:723 +#, fuzzy +msgid "# Queued messages discarded (peer disconnected)" +msgstr "# defragmentierter Nachrichten" + +#: src/dht/gnunet-service-dht_neighbours.c:778 +#, fuzzy +msgid "# Bytes transmitted to other peers" +msgstr "# Bytes des Typs %d übertragen" + +#: src/dht/gnunet-service-dht_neighbours.c:816 +#, fuzzy +msgid "# Bytes of bandwdith requested from core" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/dht/gnunet-service-dht_neighbours.c:1040 +#: src/dht/gnunet-service-dht_neighbours.c:1068 +msgid "# Peers excluded from routing due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1049 +#: src/dht/gnunet-service-dht_neighbours.c:1085 +#, fuzzy +msgid "# Peer selection failed" +msgstr " Verbindung fehlgeschlagen\n" + +#: src/dht/gnunet-service-dht_neighbours.c:1221 +#, fuzzy +msgid "# PUT requests routed" +msgstr "# dht Anfragen weitergeleitet" + +#: src/dht/gnunet-service-dht_neighbours.c:1252 +#, fuzzy +msgid "# PUT messages queued for transmission" +msgstr "# PING Nachrichten erstellt" + +#: src/dht/gnunet-service-dht_neighbours.c:1333 +#, fuzzy +msgid "# GET requests routed" +msgstr "# dht Anfragen weitergeleitet" + +#: src/dht/gnunet-service-dht_neighbours.c:1364 +#, fuzzy +msgid "# GET messages queued for transmission" +msgstr "# PING Nachrichten erstellt" + +#: src/dht/gnunet-service-dht_neighbours.c:1467 +#, fuzzy +msgid "# RESULT messages queued for transmission" +msgstr "# PING Nachrichten erstellt" + +#: src/dht/gnunet-service-dht_neighbours.c:1555 +#, fuzzy +msgid "# P2P PUT requests received" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/dht/gnunet-service-dht_neighbours.c:1668 +msgid "# FIND PEER requests ignored due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1676 +msgid "# FIND PEER requests ignored due to lack of HELLO" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1767 +#, fuzzy +msgid "# P2P GET requests received" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/dht/gnunet-service-dht_neighbours.c:1811 +#, fuzzy +msgid "# P2P FIND PEER requests processed" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/dht/gnunet-service-dht_neighbours.c:1825 +#, fuzzy +msgid "# P2P GET requests ONLY routed" +msgstr "# dht Anfragen weitergeleitet" + +#: src/dht/gnunet-service-dht_neighbours.c:1895 +#, fuzzy +msgid "# P2P RESULTS received" +msgstr "# Bytes empfangen über TCP" + +#: src/dht/gnunet-service-dht_nse.c:59 +#, fuzzy +msgid "# Network size estimates received" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/dht/gnunet-service-dht_routing.c:211 +msgid "# Good REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:220 +msgid "# Duplicate REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:226 +msgid "# Invalid REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:236 +msgid "# Unsupported REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:314 +#: src/dht/gnunet-service-dht_routing.c:368 +msgid "# Entries removed from routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:324 +msgid "# Entries added to routing table" +msgstr "" + +#: src/dht/plugin_block_dht.c:124 +#, fuzzy, c-format +msgid "Block not of type %u\n" +msgstr "Kein Transport des Typs %d bekannt.\n" + +#: src/dht/plugin_block_dht.c:131 +msgid "Size mismatch for block\n" +msgstr "" + +#: src/dht/plugin_block_dht.c:140 +#, c-format +msgid "Block of type %u is malformed\n" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:337 +msgid "only monitor DNS queries" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:340 +msgid "only monitor DNS replies" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:348 +msgid "Monitor DNS queries." +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:236 +msgid "set A records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:239 +msgid "set AAAA records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:247 +msgid "Change DNS replies to point elsewhere." +msgstr "" + +#: src/dns/gnunet-service-dns.c:480 +#, fuzzy, c-format +msgid "Could not bind to any port: %s\n" +msgstr "IP des Hosts `%s' konnte nicht ermittelt werden: %s\n" + +#: src/dns/gnunet-service-dns.c:634 +msgid "# DNS requests answered via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:818 +msgid "# DNS exit failed (failed to open socket)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1001 +#, c-format +msgid "Received DNS response that is too small (%u bytes)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1046 +msgid "# External DNS response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1165 +msgid "# Client response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1198 +msgid "Changing DNS reply according to client specifications\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1279 +msgid "Received malformed IPv4-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1294 +msgid "Received malformed IPv6-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1303 +#, c-format +msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1312 +msgid "# Non-DNS UDP packet received via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1377 +#, fuzzy +msgid "# DNS requests received via TUN interface" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/dns/gnunet-service-dns.c:1461 +#, c-format +msgid "Configured DNS exit `%s' is not working / valid.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1493 src/exit/gnunet-daemon-exit.c:2673 +msgid "# Inbound MESH tunnels created" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1567 +msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" +msgstr "" + +#: src/dv/dv_api.c:179 +#, fuzzy +msgid "Failed to connect to the dv service!\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/dv/plugin_transport_dv.c:159 +#, fuzzy, c-format +msgid "%s Received message from %s of type %d, distance %u!\n" +msgstr "Beschädigte Nachricht von Knoten `%s' in %s:%d empfangen.\n" + +#: src/exit/gnunet-daemon-exit.c:508 +#, c-format +msgid "Got duplicate service records for `%s:%u'\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:563 +#, fuzzy +msgid "# Bytes transmitted via mesh tunnels" +msgstr "# Bytes des Typs %d übertragen" + +#: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2068 +#: src/exit/gnunet-daemon-exit.c:2318 src/vpn/gnunet-service-vpn.c:1388 +#: src/vpn/gnunet-service-vpn.c:1788 src/vpn/gnunet-service-vpn.c:1951 +msgid "# ICMPv4 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2127 +#: src/exit/gnunet-daemon-exit.c:2377 src/vpn/gnunet-service-vpn.c:1444 +#: src/vpn/gnunet-service-vpn.c:1847 src/vpn/gnunet-service-vpn.c:1984 +msgid "# ICMPv6 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:756 +msgid "# ICMP packets dropped (not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:763 +msgid "ICMP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:840 +msgid "UDP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:915 +msgid "TCP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:968 +#, fuzzy +msgid "# Packets received from TUN" +msgstr "# Bytes empfangen über HTTP" + +#: src/exit/gnunet-daemon-exit.c:982 +#, fuzzy +msgid "# Bytes received from TUN" +msgstr "# Bytes empfangen über HTTP" + +#: src/exit/gnunet-daemon-exit.c:1008 +msgid "IPv4 packet options received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1035 +#, c-format +msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1081 +#, c-format +msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1089 +#, c-format +msgid "Packet from unknown protocol %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1470 +#, fuzzy +msgid "# TCP packets sent via TUN" +msgstr "# Bytes gesendet über UDP" + +#: src/exit/gnunet-daemon-exit.c:1570 +#, fuzzy +msgid "# TCP service creation requests received via mesh" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/exit/gnunet-daemon-exit.c:1573 src/exit/gnunet-daemon-exit.c:1652 +#: src/exit/gnunet-daemon-exit.c:1762 src/exit/gnunet-daemon-exit.c:1992 +#: src/exit/gnunet-daemon-exit.c:2234 src/exit/gnunet-daemon-exit.c:2515 +#: src/exit/gnunet-daemon-exit.c:2615 +#, fuzzy +msgid "# Bytes received from MESH" +msgstr "# Bytes empfangen über HTTP" + +#: src/exit/gnunet-daemon-exit.c:1606 src/exit/gnunet-daemon-exit.c:2637 +#, c-format +msgid "No service found for %s on port %d!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1610 +#, fuzzy +msgid "# TCP requests dropped (no such service)" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/exit/gnunet-daemon-exit.c:1655 +#, fuzzy +msgid "# TCP IP-exit creation requests received via mesh" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/exit/gnunet-daemon-exit.c:1765 +#, fuzzy +msgid "# TCP data requests received via mesh" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/exit/gnunet-daemon-exit.c:1779 +#, fuzzy +msgid "# TCP DATA requests dropped (no session)" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/exit/gnunet-daemon-exit.c:1829 +#, fuzzy +msgid "# ICMP packets sent via TUN" +msgstr "# Bytes gesendet über UDP" + +#: src/exit/gnunet-daemon-exit.c:1995 +#, fuzzy +msgid "# ICMP IP-exit requests received via mesh" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/exit/gnunet-daemon-exit.c:2237 +#, fuzzy +msgid "# ICMP service requests received via mesh" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/exit/gnunet-daemon-exit.c:2303 src/vpn/gnunet-service-vpn.c:1378 +#: src/vpn/gnunet-service-vpn.c:1945 +msgid "# ICMPv4 packets dropped (impossible PT to v6)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2362 src/vpn/gnunet-service-vpn.c:1414 +#: src/vpn/gnunet-service-vpn.c:1426 src/vpn/gnunet-service-vpn.c:1835 +msgid "# ICMPv6 packets dropped (impossible PT to v4)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2412 +#, fuzzy +msgid "# UDP packets sent via TUN" +msgstr "# Bytes gesendet über UDP" + +#: src/exit/gnunet-daemon-exit.c:2518 +#, fuzzy +msgid "# UDP IP-exit requests received via mesh" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/exit/gnunet-daemon-exit.c:2618 +#, fuzzy +msgid "# UDP service requests received via mesh" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/exit/gnunet-daemon-exit.c:2641 +#, fuzzy +msgid "# UDP requests dropped (no such service)" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/exit/gnunet-daemon-exit.c:2881 +#, c-format +msgid "No addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2895 src/exit/gnunet-daemon-exit.c:2907 +#, c-format +msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2918 +#, c-format +msgid "No IP addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3047 +msgid "" +"This system does not support IPv4, will disable IPv4 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3055 +msgid "" +"This system does not support IPv6, will disable IPv6 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3062 +msgid "" +"Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " +"ENABLE_IPv4=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3068 +msgid "" +"Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " +"ENABLE_IPv6=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3074 src/pt/gnunet-daemon-pt.c:884 +msgid "No useful service enabled. Exiting.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3235 +msgid "Daemon to run to provide an IP exit node for the VPN" +msgstr "" + +#: src/fragmentation/defragmentation.c:270 +msgid "# acknowledgements sent for fragment" +msgstr "" + +#: src/fragmentation/defragmentation.c:454 +#, fuzzy +msgid "# fragments received" +msgstr "# verworfener Nachrichten" + +#: src/fragmentation/defragmentation.c:513 +#, fuzzy +msgid "# duplicate fragments received" +msgstr "# Bytes empfangen über TCP" + +#: src/fragmentation/defragmentation.c:526 +msgid "# messages defragmented" +msgstr "# defragmentierter Nachrichten" + +#: src/fragmentation/fragmentation.c:188 +#, fuzzy +msgid "# fragments transmitted" +msgstr "# Selbstbekanntmachungen übertragen" + +#: src/fragmentation/fragmentation.c:191 +#, fuzzy +msgid "# fragments retransmitted" +msgstr "# Selbstbekanntmachungen übertragen" + +#: src/fragmentation/fragmentation.c:255 +msgid "# messages fragmented" +msgstr "# fragmentierter Nachrichten" + +#: src/fragmentation/fragmentation.c:258 +msgid "# total size of fragmented messages" +msgstr "" + +#: src/fragmentation/fragmentation.c:343 +#, fuzzy +msgid "# fragment acknowledgements received" +msgstr "# Knotenankündigungen empfangen" + +#: src/fragmentation/fragmentation.c:349 +msgid "# bits removed from fragmentation ACKs" +msgstr "" + +#: src/fragmentation/fragmentation.c:373 +#, fuzzy +msgid "# fragmentation transmissions completed" +msgstr "# Klartext PONG Nachrichten empfangen" + +#: src/fs/fs_api.c:284 +#, fuzzy, c-format +msgid "Could not open file `%s': %s" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_api.c:293 +#, fuzzy, c-format +msgid "Could not read file `%s': %s" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_api.c:299 +#, c-format +msgid "Short read reading from file `%s'!" +msgstr "" + +#: src/fs/fs_api.c:877 +#, fuzzy, c-format +msgid "Failed to resume publishing information `%s': %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_api.c:1334 +#, c-format +msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" +msgstr "" + +#: src/fs/fs_api.c:1376 +#, c-format +msgid "Failure while resuming publishing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:1392 +#, fuzzy, c-format +msgid "Failed to resume publishing operation `%s': %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_api.c:2004 +#, c-format +msgid "Failure while resuming unindexing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2014 +#, fuzzy, c-format +msgid "Failed to resume unindexing operation `%s': %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_api.c:2139 src/fs/fs_api.c:2378 +#, fuzzy, c-format +msgid "Failed to resume sub-download `%s': %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_api.c:2156 +#, fuzzy, c-format +msgid "Failed to resume sub-search `%s': %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_api.c:2168 src/fs/fs_api.c:2187 src/fs/fs_api.c:2671 +#, c-format +msgid "Failure while resuming search operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2369 +#, c-format +msgid "Failed to resume sub-download `%s': could not open file `%s'\n" +msgstr "" + +#: src/fs/fs_api.c:2615 +msgid "Could not resume running search, will resume as paused search\n" +msgstr "" + +#: src/fs/fs_api.c:2709 +#, c-format +msgid "Failure while resuming download operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_directory.c:210 +#, fuzzy +msgid "MAGIC mismatch. This is not a GNUnet directory.\n" +msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#: src/fs/fs_download.c:310 +#, fuzzy +msgid "" +"Recursive downloads of directories larger than 4 GB are not supported on 32-" +"bit systems\n" +msgstr "Rekursiver Download des Verzeichnisses `%s' bei %llu von %llu Bytes.\n" + +#: src/fs/fs_download.c:330 +msgid "Directory too large for system address space\n" +msgstr "" + +#: src/fs/fs_download.c:488 src/fs/fs_download.c:500 +#, fuzzy, c-format +msgid "Failed to open file `%s' for writing" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_download.c:870 +#, fuzzy, c-format +msgid "Failed to create directory for recursive download of `%s'\n" +msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" + +#: src/fs/fs_download.c:951 +#, c-format +msgid "" +"Internal error or bogus download URI (expected %u bytes at depth %u and " +"offset %llu/%llu, got %u bytes)\n" +msgstr "" + +#: src/fs/fs_download.c:977 +msgid "internal error decrypting content" +msgstr "" + +#: src/fs/fs_download.c:1000 +#, fuzzy, c-format +msgid "Download failed: could not open file `%s': %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_download.c:1010 +#, fuzzy, c-format +msgid "Failed to seek to offset %llu in file `%s': %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_download.c:1019 +#, c-format +msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s\n" +msgstr "" + +#: src/fs/fs_download.c:1835 +#, fuzzy +msgid "Invalid URI" +msgstr "Ungültiger Parameter: `%s'\n" + +#: src/fs/fs_getopt.c:191 +#, c-format +msgid "" +"Unknown metadata type in metadata option `%s'. Using metadata type " +"`unknown' instead.\n" +msgstr "" + +#: src/fs/fs_list_indexed.c:90 +#, fuzzy, c-format +msgid "Failed to receive response for `%s' request from `%s' service.\n" +msgstr "Fehler beim Empfangen der Antwort von gnunetd auf die `%s' Nachricht\n" + +#: src/fs/fs_list_indexed.c:113 +#, fuzzy, c-format +msgid "Failed to receive valid response for `%s' request from `%s' service.\n" +msgstr "Fehler beim Empfangen der Antwort von gnunetd auf die `%s' Nachricht\n" + +#: src/fs/fs_list_indexed.c:151 +#, fuzzy, c-format +msgid "Failed to not connect to `%s' service.\n" +msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" + +#: src/fs/fs_misc.c:126 +#, fuzzy, c-format +msgid "Did not find mime type `%s' in extension list.\n" +msgstr "Knoten `%s' konnte nicht in der Routing Tabelle gefunden werden!\n" + +#: src/fs/fs_namespace_advertise.c:150 +#, fuzzy +msgid "Unknown error" +msgstr "Unbekannter Fehler" + +#: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 +#, fuzzy +msgid "Failed to serialize meta data" +msgstr "SQLite Datenbank konnte nicht initialisiert werden.\n" + +#: src/fs/fs_namespace_advertise.c:278 +#, fuzzy +msgid "Failed to connect to datastore service" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 +#, fuzzy, c-format +msgid "Configuration fails to specify `%s' in section `%s'\n" +msgstr "" +"Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein Verzeichnis " +"angeben, in dem FS Daten gespeichert werden.\n" + +#: src/fs/fs_namespace.c:112 +#, fuzzy, c-format +msgid "Failed to open `%s' for writing: %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 +#, fuzzy, c-format +msgid "Failed to write `%s': %s\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/fs/fs_namespace.c:256 +#, fuzzy, c-format +msgid "Failed to create or read private key for namespace `%s'\n" +msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" + +#: src/fs/fs_namespace.c:371 +#, fuzzy, c-format +msgid "Failed to read namespace private key file `%s', deleting it!\n" +msgstr "" +"Der Eintrag konnte dem Namespace `%s' nicht hinzugefügt werden (existiert " +"er?)\n" + +#: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 +#, fuzzy +msgid "Internal error." +msgstr "Unbekannter Fehler.\n" + +#: src/fs/fs_namespace.c:631 +#, fuzzy +msgid "Failed to connect to datastore." +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." + +#: src/fs/fs_publish.c:129 src/fs/fs_publish.c:395 +#, fuzzy, c-format +msgid "Publishing failed: %s" +msgstr "" +"\n" +"Fehler beim Uploaden der Datei: %s\n" + +#: src/fs/fs_publish.c:616 src/fs/fs_publish.c:633 src/fs/fs_publish.c:672 +#: src/fs/fs_publish.c:692 src/fs/fs_publish.c:717 src/fs/fs_publish.c:857 +#, fuzzy, c-format +msgid "Can not index file `%s': %s. Will try to insert instead.\n" +msgstr "Indizieren der Datei `%s' schlug fehl. Versuch Datei einzufügen...\n" + +#: src/fs/fs_publish.c:618 +msgid "timeout on index-start request to `fs' service" +msgstr "" + +#: src/fs/fs_publish.c:630 +#, fuzzy +msgid "unknown error" +msgstr "Unbekannter Fehler" + +#: src/fs/fs_publish.c:673 +msgid "failed to compute hash" +msgstr "" + +#: src/fs/fs_publish.c:693 +msgid "filename too long" +msgstr "" + +#: src/fs/fs_publish.c:718 +#, fuzzy +msgid "could not connect to `fs' service" +msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" + +#: src/fs/fs_publish.c:741 +#, fuzzy, c-format +msgid "Failed to get file identifiers for `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/fs/fs_publish.c:806 +#, fuzzy, c-format +msgid "Recursive upload failed at `%s': %s" +msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" + +#: src/fs/fs_publish.c:812 +#, fuzzy, c-format +msgid "Recursive upload failed: %s" +msgstr "" +"\n" +"Fehler beim Uploaden der Datei: %s\n" + +#: src/fs/fs_publish.c:858 +#, fuzzy +msgid "needs to be an actual file" +msgstr "`%s' ist keine normale Datei.\n" + +#: src/fs/fs_publish.c:1067 +#, c-format +msgid "Insufficient space for publishing: %s" +msgstr "" + +#: src/fs/fs_publish.c:1138 +#, c-format +msgid "Reserving space for %u entries and %llu bytes for publication\n" +msgstr "" + +#: src/fs/fs_publish_ksk.c:258 +#, fuzzy +msgid "Could not connect to datastore." +msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" + +#: src/fs/fs_search.c:810 +#, c-format +msgid "Got result with unknown block type `%d', ignoring" +msgstr "" + +#: src/fs/fs_test_lib.c:269 +#, fuzzy, c-format +msgid "Failed to start daemon: %s\n" +msgstr "Fehler beim Starten der Collection.\n" + +#: src/fs/fs_unindex.c:57 +msgid "Failed to find given position in file" +msgstr "" + +#: src/fs/fs_unindex.c:62 +#, fuzzy +msgid "Failed to read file" +msgstr "Zustellung der Nachricht `%s' fehlgeschlagen.\n" + +#: src/fs/fs_unindex.c:231 +msgid "Unexpected time for a response from `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:239 +msgid "Timeout waiting for `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:247 +#, fuzzy +msgid "Invalid response from `fs' service." +msgstr "Ungültige Antwort auf `%s'.\n" + +#: src/fs/fs_unindex.c:292 +#, fuzzy +msgid "Failed to connect to FS service for unindexing." +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." + +#: src/fs/fs_unindex.c:325 +#, fuzzy +msgid "Failed to connect to `datastore' service." +msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" + +#: src/fs/fs_unindex.c:338 +#, fuzzy +msgid "Failed to open file for unindexing." +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." + +#: src/fs/fs_unindex.c:372 +#, fuzzy +msgid "Failed to compute hash of file." +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." + +#: src/fs/fs_uri.c:220 +#, c-format +msgid "`%' must be followed by HEX number" +msgstr "" + +#: src/fs/fs_uri.c:279 +#, fuzzy +msgid "Malformed KSK URI (must not begin or end with `+')" +msgstr "Ungültige URL `%s' (muss mit `%s' beginnen)\n" + +#: src/fs/fs_uri.c:297 +msgid "`++' not allowed in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:304 +msgid "Quotes not balanced in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 +msgid "Malformed SKS URI" +msgstr "" + +#: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 +msgid "Malformed CHK URI" +msgstr "" + +#: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 +#: src/fs/fs_uri.c:621 +msgid "SKS URI malformed" +msgstr "" + +#: src/fs/fs_uri.c:603 +msgid "SKS URI malformed (could not decode public key)" +msgstr "" + +#: src/fs/fs_uri.c:609 +msgid "SKS URI malformed (could not find signature)" +msgstr "" + +#: src/fs/fs_uri.c:615 +msgid "SKS URI malformed (could not decode signature)" +msgstr "" + +#: src/fs/fs_uri.c:628 +msgid "SKS URI malformed (could not parse expiration time)" +msgstr "" + +#: src/fs/fs_uri.c:640 +msgid "SKS URI malformed (signature failed validation)" +msgstr "" + +#: src/fs/fs_uri.c:678 +msgid "Unrecognized URI type" +msgstr "" + +#: src/fs/fs_uri.c:903 +#, fuzzy +msgid "Lacking key configuration settings.\n" +msgstr "GNUnet Konfiguration" + +#: src/fs/fs_uri.c:910 +#, fuzzy, c-format +msgid "Could not access hostkey file `%s'.\n" +msgstr "Konfigurationsdatei `%s' konnte nicht geparst werden.\n" + +#: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 +msgid "No keywords specified!\n" +msgstr "Keine Schlüsselwörter angegeben!\n" + +#: src/fs/fs_uri.c:1148 +msgid "Number of double-quotes not balanced!\n" +msgstr "" + +#: src/fs/gnunet-directory.c:49 +#, c-format +msgid "\t\n" +msgstr "" + +#: src/fs/gnunet-directory.c:94 +#, fuzzy, c-format +msgid "Directory `%s' meta data:\n" +msgstr "==> Verzeichnis `%s':\n" + +#: src/fs/gnunet-directory.c:97 +#, fuzzy, c-format +msgid "Directory `%s' contents:\n" +msgstr "==> Verzeichnis `%s':\n" + +#: src/fs/gnunet-directory.c:132 +#, fuzzy +msgid "You must specify a filename to inspect.\n" +msgstr "Sie müssen eine Liste von Dateien zum Einfügen angeben.\n" + +#: src/fs/gnunet-directory.c:145 +#, fuzzy, c-format +msgid "Failed to read directory `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/fs/gnunet-directory.c:154 +#, fuzzy, c-format +msgid "`%s' is not a GNUnet directory\n" +msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#: src/fs/gnunet-directory.c:179 +#, fuzzy +msgid "Display contents of a GNUnet directory" +msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#: src/fs/gnunet-download.c:100 +#, fuzzy, c-format +msgid "Starting download `%s'.\n" +msgstr "Collection `%s' begonnen.\n" + +#: src/fs/gnunet-download.c:109 +#, fuzzy +msgid "" +msgstr "Unbekannter Fehler" + +#: src/fs/gnunet-download.c:118 +#, c-format +msgid "" +"Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " +"download\n" +msgstr "" + +#: src/fs/gnunet-download.c:128 +#, fuzzy, c-format +msgid "Error downloading: %s.\n" +msgstr "Fehler beim Download: %s\n" + +#: src/fs/gnunet-download.c:136 +#, fuzzy, c-format +msgid "Downloading `%s' done (%s/s).\n" +msgstr "Upload abgewiesen!" + +#: src/fs/gnunet-download.c:151 src/fs/gnunet-publish.c:190 +#: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 +#, c-format +msgid "Unexpected status: %d\n" +msgstr "" + +#: src/fs/gnunet-download.c:176 +#, fuzzy +msgid "You need to specify a URI argument.\n" +msgstr "Sie müssen einen Empfänger angeben!\n" + +#: src/fs/gnunet-download.c:182 src/fs/gnunet-publish.c:618 +#, fuzzy, c-format +msgid "Failed to parse URI: %s\n" +msgstr "Datei `%s' hat URI: %s\n" + +#: src/fs/gnunet-download.c:189 +msgid "Only CHK or LOC URIs supported.\n" +msgstr "" + +#: src/fs/gnunet-download.c:196 +msgid "Target filename must be specified.\n" +msgstr "" + +#: src/fs/gnunet-download.c:210 src/fs/gnunet-publish.c:596 +#: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 +#, fuzzy, c-format +msgid "Could not initialize `%s' subsystem.\n" +msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" + +#: src/fs/gnunet-download.c:247 src/fs/gnunet-search.c:285 +msgid "set the desired LEVEL of receiver-anonymity" +msgstr "Den Grad LEVEL der gewünschten Empfänger-Anonymität setzen" + +#: src/fs/gnunet-download.c:250 +msgid "delete incomplete downloads (when aborted with CTRL-C)" +msgstr "" + +#: src/fs/gnunet-download.c:253 src/fs/gnunet-search.c:288 +msgid "only search the local peer (no P2P network search)" +msgstr "" + +#: src/fs/gnunet-download.c:256 +msgid "write the file to FILENAME" +msgstr "Schreibe die Datei in DATEINAME" + +#: src/fs/gnunet-download.c:260 +msgid "set the maximum number of parallel downloads that is allowed" +msgstr "" + +#: src/fs/gnunet-download.c:264 +msgid "set the maximum number of parallel requests for blocks that is allowed" +msgstr "" + +#: src/fs/gnunet-download.c:267 +msgid "download a GNUnet directory recursively" +msgstr "Das GNUnet Verzeichnis rekursiv herunterladen" + +#: src/fs/gnunet-download.c:277 +msgid "" +"Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" +"chk/...)" +msgstr "" + +#: src/fs/gnunet-fs.c:117 +msgid "print a list of all indexed files" +msgstr "" + +#: src/fs/gnunet-fs.c:124 +#, fuzzy +msgid "Special file-sharing operations" +msgstr "Alle Optionen anzeigen" + +#: src/fs/gnunet-pseudonym.c:151 src/statistics/gnunet-statistics.c:126 +#, fuzzy, c-format +msgid "Invalid argument `%s'\n" +msgstr "Ungültiger Parameter: `%s'\n" + +#: src/fs/gnunet-pseudonym.c:165 +#, fuzzy, c-format +msgid "Namespace `%s' unknown.\n" +msgstr "Namespace `%s' hat das Rating %d.\n" + +#: src/fs/gnunet-pseudonym.c:240 src/fs/gnunet-pseudonym.c:247 +#: src/fs/gnunet-pseudonym.c:249 +#, fuzzy, c-format +msgid "Option `%s' ignored\n" +msgstr "%s: Option `%s' ist mehrdeutig\n" + +#: src/fs/gnunet-pseudonym.c:269 src/fs/gnunet-publish.c:672 +msgid "set the desired LEVEL of sender-anonymity" +msgstr "Gewünschten Grad an Sender-Anonymität festlegen" + +#: src/fs/gnunet-pseudonym.c:272 +msgid "create or advertise namespace NAME" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:275 +msgid "delete namespace NAME " +msgstr "" + +#: src/fs/gnunet-pseudonym.c:278 +#, fuzzy +msgid "" +"add an additional keyword for the advertisment (this option can be specified " +"multiple times)" +msgstr "" +"Ein zusätzliches Schlüsselwort für alle Dateien und Verzeichnisse hinzufügen " +"(diese Option kann mehrmals angegeben werden)" + +#: src/fs/gnunet-pseudonym.c:282 src/fs/gnunet-publish.c:691 +msgid "set the meta-data for the given TYPE to the given VALUE" +msgstr "" +"Die Meta-Daten des angegebenen Typs TYPE auf den angegebenen Wert VALUE " +"setzen" + +#: src/fs/gnunet-pseudonym.c:285 +#, fuzzy +msgid "print names of local namespaces" +msgstr "das Rating eines Namespaces setzen" + +#: src/fs/gnunet-pseudonym.c:288 +msgid "use the given PRIORITY for the advertisments" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:291 +msgid "do not print names of remote namespaces" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:294 src/fs/gnunet-publish.c:710 +msgid "set the desired replication LEVEL" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:297 +#, fuzzy +msgid "specify ID of the root of the namespace" +msgstr "das Rating eines Namespaces setzen" + +#: src/fs/gnunet-pseudonym.c:300 +#, fuzzy +msgid "change rating of namespace ID by VALUE" +msgstr "das Rating eines Namespaces setzen" + +#: src/fs/gnunet-pseudonym.c:308 +msgid "Manage GNUnet pseudonyms." +msgstr "" + +#: src/fs/gnunet-publish.c:147 +#, c-format +msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-publish.c:155 +#, fuzzy, c-format +msgid "Error publishing: %s.\n" +msgstr "Fehler beim Download: %s\n" + +#: src/fs/gnunet-publish.c:165 +#, c-format +msgid "Publishing `%s' done.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:169 +#, fuzzy, c-format +msgid "URI is `%s'.\n" +msgstr "Ich bin Peer `%s'.\n" + +#: src/fs/gnunet-publish.c:187 +#, fuzzy +msgid "Cleanup after abort complete.\n" +msgstr "`%s' Startvorgang abgeschlossen.\n" + +#: src/fs/gnunet-publish.c:299 +#, fuzzy, c-format +msgid "Meta data for file `%s' (%s)\n" +msgstr "Daten des Moduls `%s' werden aktualisiert\n" + +#: src/fs/gnunet-publish.c:301 +#, fuzzy, c-format +msgid "Keywords for file `%s' (%s)\n" +msgstr "Schlüsselwörter für Datei `%s':\n" + +#: src/fs/gnunet-publish.c:352 +#, fuzzy, c-format +msgid "Failed to create namespace `%s'\n" +msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" + +#: src/fs/gnunet-publish.c:427 +#, fuzzy +msgid "Could not publish\n" +msgstr "`%s' konnte nicht aufgelöst werden: %s\n" + +#: src/fs/gnunet-publish.c:454 +#, fuzzy +msgid "Could not start publishing.\n" +msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" + +#: src/fs/gnunet-publish.c:485 +#, fuzzy, c-format +msgid "Scanning directory `%s'.\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/fs/gnunet-publish.c:487 +#, fuzzy, c-format +msgid "Scanning file `%s'.\n" +msgstr "Collection `%s' begonnen.\n" + +#: src/fs/gnunet-publish.c:492 +#, c-format +msgid "There was trouble processing file `%s', skipping it.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:497 +#, fuzzy +msgid "Preprocessing complete.\n" +msgstr "GNUnet wurde erfolgreich heruntergefahren.\n" + +#: src/fs/gnunet-publish.c:501 +#, fuzzy, c-format +msgid "Extracting meta data from file `%s' complete.\n" +msgstr "Daten des Moduls `%s' werden aktualisiert\n" + +#: src/fs/gnunet-publish.c:505 +msgid "Meta data extraction has finished.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:512 +#, fuzzy +msgid "Internal error scanning directory.\n" +msgstr "=\tFehler beim Lesen des Verzeichnisses.\n" + +#: src/fs/gnunet-publish.c:546 +#, c-format +msgid "Cannot extract metadata from a URI!\n" +msgstr "" + +#: src/fs/gnunet-publish.c:553 +#, c-format +msgid "You must specify one and only one filename for insertion.\n" +msgstr "Sie dürfen nur eine Datei zum Deindizieren angeben.\n" + +#: src/fs/gnunet-publish.c:559 +#, fuzzy, c-format +msgid "You must NOT specify an URI and a filename.\n" +msgstr "Sie müssen einen Empfänger angeben!\n" + +#: src/fs/gnunet-publish.c:567 src/vpn/gnunet-vpn.c:214 +#, fuzzy, c-format +msgid "Option `%s' is required when using option `%s'.\n" +msgstr "Option `%s' macht keinen Sinn ohne die Option `%s'.\n" + +#: src/fs/gnunet-publish.c:577 src/fs/gnunet-publish.c:584 +#: src/transport/gnunet-transport.c:530 +#, c-format +msgid "Option `%s' makes no sense without option `%s'.\n" +msgstr "Option `%s' macht keinen Sinn ohne die Option `%s'.\n" + +#: src/fs/gnunet-publish.c:606 +#, fuzzy, c-format +msgid "Could not create namespace `%s'\n" +msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" + +#: src/fs/gnunet-publish.c:639 +#, fuzzy, c-format +msgid "Failed to access `%s': %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/gnunet-publish.c:651 +msgid "" +"Failed to start meta directory scanner. Is gnunet-helper-publish-fs " +"installed?\n" +msgstr "" + +#: src/fs/gnunet-publish.c:676 +msgid "disable adding the creation time to the metadata of the uploaded file" +msgstr "" + +#: src/fs/gnunet-publish.c:679 +msgid "do not use libextractor to add keywords or metadata" +msgstr "" + +#: src/fs/gnunet-publish.c:683 +msgid "" +"print list of extracted keywords that would be used, but do not perform " +"upload" +msgstr "" +"Liste der extrahierten Schlüsselworte, die verwendet werden würden, " +"ausgeben, aber keinen Upload durchführen" + +#: src/fs/gnunet-publish.c:687 +msgid "" +"add an additional keyword for the top-level file or directory (this option " +"can be specified multiple times)" +msgstr "" +"Ein zusätzliches Schlüsselwort für die Datei oder das Verzeichnis auf der " +"obersten Ebene hinzufügen (diese Option kann mehrmals angegeben werden)" + +#: src/fs/gnunet-publish.c:694 +msgid "" +"do not index, perform full insertion (stores entire file in encrypted form " +"in GNUnet database)" +msgstr "" +"Nicht indizieren, sondern komplett einfügen (speichert die gesamte Datei in " +"verschlüsselter Form in der GNUnet Datenbank)" + +#: src/fs/gnunet-publish.c:699 +msgid "" +"specify ID of an updated version to be published in the future (for " +"namespace insertions only)" +msgstr "" +"ID einer aktualisierten Version angeben, die in der Zukunft veröffentlich " +"werden soll. (nur für das Einfügen in Namespaces)" + +#: src/fs/gnunet-publish.c:703 +msgid "specify the priority of the content" +msgstr "Die Priorität des Inhalts angeben" + +#: src/fs/gnunet-publish.c:707 +msgid "publish the files under the pseudonym NAME (place file into namespace)" +msgstr "" +"Die Datei unter dem Pseudonym NAME veröffentlichen (platziert die Datei in " +"einem Namespace)" + +#: src/fs/gnunet-publish.c:713 +msgid "" +"only simulate the process but do not do any actual publishing (useful to " +"compute URIs)" +msgstr "" + +#: src/fs/gnunet-publish.c:717 +msgid "" +"set the ID of this version of the publication (for namespace insertions only)" +msgstr "" +"die ID dieser Version der Veröffentlichung setzen (nur für das Einfügen in " +"Namespaces)" + +#: src/fs/gnunet-publish.c:721 +msgid "" +"URI to be published (can be used instead of passing a file to add keywords " +"to the file with the respective URI)" +msgstr "" + +#: src/fs/gnunet-publish.c:736 +msgid "Publish a file or directory on GNUnet" +msgstr "" + +#: src/fs/gnunet-search.c:111 +#, c-format +msgid "Failed to write directory with search results to `%s'\n" +msgstr "" + +#: src/fs/gnunet-search.c:181 +#, fuzzy, c-format +msgid "Error searching: %s.\n" +msgstr "Fehler beim Verlassen der DHT.\n" + +#: src/fs/gnunet-search.c:231 +#, fuzzy +msgid "Could not create keyword URI from arguments.\n" +msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" + +#: src/fs/gnunet-search.c:255 +#, fuzzy +msgid "Could not start searching.\n" +msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" + +#: src/fs/gnunet-search.c:291 +msgid "write search results to file starting with PREFIX" +msgstr "" + +#: src/fs/gnunet-search.c:294 +msgid "automatically terminate search after VALUE ms" +msgstr "" + +#: src/fs/gnunet-search.c:301 +msgid "automatically terminate search after VALUE results are found" +msgstr "" + +#: src/fs/gnunet-search.c:308 +msgid "Search GNUnet for files that were published on GNUnet" +msgstr "" + +#: src/fs/gnunet-service-fs.c:240 +msgid "# running average P2P latency (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 +#, fuzzy +msgid "# Loopback routes suppressed" +msgstr "# gap Routing erfolgreich (insgesamt)" + +#: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 +#: src/topology/gnunet-daemon-topology.c:1290 +#: src/topology/gnunet-daemon-topology.c:1297 +#, fuzzy, c-format +msgid "Failed to connect to `%s' service.\n" +msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" + +#: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 +#: src/topology/gnunet-daemon-topology.c:654 +#: src/topology/gnunet-daemon-topology.c:756 +#: src/transport/gnunet-service-transport_neighbours.c:960 +#: src/transport/gnunet-service-transport_neighbours.c:1289 +#: src/transport/gnunet-service-transport_neighbours.c:1841 +#: src/transport/gnunet-service-transport_neighbours.c:2499 +#: src/transport/gnunet-service-transport_neighbours.c:2566 +#, fuzzy +msgid "# peers connected" +msgstr "# verbundener Knoten" + +#: src/fs/gnunet-service-fs_cp.c:696 +#, fuzzy +msgid "# migration stop messages received" +msgstr "# verschlüsselter PING Nachrichten empfangen" + +#: src/fs/gnunet-service-fs_cp.c:700 +#, c-format +msgid "Migration of content to peer `%s' blocked for %llu ms\n" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:735 +#, fuzzy +msgid "# replies transmitted to other peers" +msgstr "# Bytes des Typs %d übertragen" + +#: src/fs/gnunet-service-fs_cp.c:741 +msgid "# replies dropped" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 +msgid "# P2P searches active" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:858 +msgid "# artificial delays introduced (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:911 +#, fuzzy +msgid "# replies dropped due to type mismatch" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/fs/gnunet-service-fs_cp.c:919 +#, fuzzy +msgid "# replies received for other peers" +msgstr "# Bytes des Typs %d empfangen" + +#: src/fs/gnunet-service-fs_cp.c:933 +msgid "# replies dropped due to insufficient cover traffic" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:971 +msgid "# P2P searches destroyed due to ultimate reply" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1038 +#, fuzzy +msgid "# requests done for free (low load)" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/fs/gnunet-service-fs_cp.c:1062 +msgid "# request dropped, priority insufficient" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1072 +#, fuzzy +msgid "# requests done for a price (normal load)" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/fs/gnunet-service-fs_cp.c:1151 +msgid "# GET requests received (from other peers)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1185 +#, fuzzy +msgid "# requests dropped due to initiator not being connected" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/fs/gnunet-service-fs_cp.c:1207 +#, fuzzy +msgid "# requests dropped due to missing reverse route" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/fs/gnunet-service-fs_cp.c:1267 +#, fuzzy +msgid "# requests dropped due TTL underflow" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/fs/gnunet-service-fs_cp.c:1293 +#, fuzzy +msgid "# requests dropped due to higher-TTL request" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/fs/gnunet-service-fs_cp.c:1322 +#, fuzzy +msgid "# P2P query messages received and processed" +msgstr "# verschlüsselter PING Nachrichten empfangen" + +#: src/fs/gnunet-service-fs_cp.c:1687 +#, fuzzy +msgid "# migration stop messages sent" +msgstr "# verschlüsselter PING Nachrichten empfangen" + +#: src/fs/gnunet-service-fs_indexing.c:113 +#: src/fs/gnunet-service-fs_indexing.c:163 +#, fuzzy, c-format +msgid "Configuration option `%s' in section `%s' missing.\n" +msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" + +#: src/fs/gnunet-service-fs_indexing.c:121 +#: src/fs/gnunet-service-fs_indexing.c:177 +#, fuzzy, c-format +msgid "Could not open `%s'.\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/gnunet-service-fs_indexing.c:137 +#, fuzzy, c-format +msgid "Error writing `%s'.\n" +msgstr "Fehler beim Anlegen des Benutzers" + +#: src/fs/gnunet-service-fs_indexing.c:228 +#, c-format +msgid "" +"Index request received for file `%s' is already indexed as `%s'. Permitting " +"anyway.\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:266 +#, c-format +msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:481 +#, fuzzy, c-format +msgid "Failed to delete bogus block: %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/fs/gnunet-service-fs_indexing.c:539 +msgid "# index blocks removed: original file inaccessible" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:554 +#, fuzzy, c-format +msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" +msgstr "`%s' konnte nicht aufgelöst werden: %s\n" + +#: src/fs/gnunet-service-fs_indexing.c:556 +#, fuzzy +msgid "not indexed" +msgstr "Deindizierung schlug fehl." + +#: src/fs/gnunet-service-fs_indexing.c:571 +#, fuzzy, c-format +msgid "Indexed file `%s' changed at offset %llu\n" +msgstr "Indizierung der Daten schlug an Position %i fehl.\n" + +#: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 +#: src/fs/gnunet-service-fs_lc.c:488 +#, fuzzy +msgid "# client searches active" +msgstr "# gap Anfragen insgesamt empfangen" + +#: src/fs/gnunet-service-fs_lc.c:256 +#, fuzzy +msgid "# replies received for local clients" +msgstr "# gap Anfragen insgesamt empfangen" + +#: src/fs/gnunet-service-fs_lc.c:321 +#, fuzzy +msgid "# client searches received" +msgstr "# gap Anfragen insgesamt empfangen" + +#: src/fs/gnunet-service-fs_lc.c:356 +msgid "# client searches updated (merged content seen list)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:265 +msgid "# average retransmission delay (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:391 +#, fuzzy +msgid "# transmission failed (core has no bandwidth)" +msgstr "Kein Transport des Typs %d bekannt.\n" + +#: src/fs/gnunet-service-fs_pe.c:420 +#, fuzzy +msgid "# query messages sent to other peers" +msgstr "# Bytes ausgehender Nachrichten verworfen" + +#: src/fs/gnunet-service-fs_pe.c:469 +msgid "# delay heap timeout" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:476 +#, fuzzy +msgid "# query plans executed" +msgstr "# dht Anfragen weitergeleitet" + +#: src/fs/gnunet-service-fs_pe.c:538 +#, fuzzy +msgid "# requests merged" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/fs/gnunet-service-fs_pe.c:544 +#, fuzzy +msgid "# requests refreshed" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 +#: src/fs/gnunet-service-fs_pe.c:748 +msgid "# query plan entries" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:285 +#, fuzzy +msgid "# Pending requests created" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 +#, fuzzy +msgid "# Pending requests active" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/fs/gnunet-service-fs_pr.c:779 +#, fuzzy +msgid "# replies received and matched" +msgstr "# Bytes empfangen über TCP" + +#: src/fs/gnunet-service-fs_pr.c:808 +msgid "# duplicate replies discarded (bloomfilter)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:822 +#, c-format +msgid "Unsupported block type %u\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:835 +msgid "# results found locally" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:953 +msgid "# Datastore `PUT' failures" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:980 +#, fuzzy +msgid "# storage requests dropped due to high load" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/fs/gnunet-service-fs_pr.c:1015 +#, fuzzy +msgid "# Replies received from DHT" +msgstr "# Bytes empfangen über HTTP" + +#: src/fs/gnunet-service-fs_pr.c:1106 +#, c-format +msgid "Datastore lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1127 +#, c-format +msgid "On-demand lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1174 +msgid "# Datastore lookups concluded (no results)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1188 +msgid "# Datastore lookups concluded (seen all)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1197 +msgid "# Datastore lookups aborted (more than MAX_RESULTS)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1211 +msgid "# requested DBLOCK or IBLOCK not found" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1224 +msgid "# on-demand blocks matched requests" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1237 +msgid "# on-demand lookups performed successfully" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1242 +msgid "# on-demand lookups failed" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 +#: src/fs/gnunet-service-fs_pr.c:1447 +msgid "# Datastore lookups concluded (error queueing)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1327 +msgid "# Datastore lookups concluded (found last result)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1338 +msgid "# Datastore lookups concluded (load too high)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1424 +msgid "# Datastore lookups initiated" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1508 +#, fuzzy +msgid "# GAP PUT messages received" +msgstr "# verschlüsselter PONG Nachrichten empfangen" + +#: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 +#, fuzzy, c-format +msgid "Configuration fails to specify `%s', assuming default value." +msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" + +#: src/fs/gnunet-service-fs_push.c:629 +#, c-format +msgid "" +"Invalid value specified for option `%s' in section `%s', content pushing " +"disabled\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:89 +#, c-format +msgid "Unindexing at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:96 +#, fuzzy, c-format +msgid "Error unindexing: %s.\n" +msgstr "" +"\n" +"Fehler beim Deindizieren der Datei: %s\n" + +#: src/fs/gnunet-unindex.c:101 +#, fuzzy +msgid "Unindexing done.\n" +msgstr "Dateien deindizieren." + +#: src/fs/gnunet-unindex.c:131 +#, fuzzy, c-format +msgid "You must specify one and only one filename for unindexing.\n" +msgstr "Sie dürfen nur eine Datei zum Deindizieren angeben.\n" + +#: src/fs/gnunet-unindex.c:148 +#, fuzzy +msgid "Could not start unindex operation.\n" +msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" + +#: src/fs/gnunet-unindex.c:176 +msgid "Unindex a file that was previously indexed with gnunet-publish." +msgstr "" + +#: src/fs/plugin_block_fs.c:131 +msgid "Reply mismatched in terms of namespace. Discarded.\n" +msgstr "" + +#: src/gns/gns_api.c:221 +#, fuzzy +msgid "Failed to connect to the GNS service!\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/gns/gnunet-gns-lookup.c:210 +msgid "Issue a request to the GNUnet Naming System, prints results." +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:264 +msgid "" +"None of the functions for the hostlist daemon were enabled. I have no " +"reason to run!\n" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:317 +msgid "advertise our hostlist to other peers" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:322 +msgid "" +"bootstrap using hostlists (it is highly recommended that you always use this " +"option)" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:325 +msgid "enable learning about hostlist servers from other peers" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:329 +msgid "provide a hostlist server" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:341 +msgid "GNUnet hostlist server and client" +msgstr "" + +#: src/hostlist/hostlist-client.c:286 +msgid "# bytes downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:307 src/hostlist/hostlist-client.c:339 +#, fuzzy +msgid "# invalid HELLOs downloaded from hostlist servers" +msgstr "# Hellos per HTTP heruntergeladen" + +#: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:342 +#, fuzzy, c-format +msgid "Invalid `%s' message received from hostlist at `%s'\n" +msgstr "Ungültige `%s' Nachricht von Knoten `%s' empfangen.\n" + +#: src/hostlist/hostlist-client.c:330 +#, fuzzy +msgid "# valid HELLOs downloaded from hostlist servers" +msgstr "# Hellos per HTTP heruntergeladen" + +#: src/hostlist/hostlist-client.c:374 src/hostlist/hostlist-client.c:395 +#, c-format +msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:472 src/hostlist/hostlist-client.c:682 +#: src/hostlist/hostlist-client.c:688 src/hostlist/hostlist-client.c:740 +#: src/hostlist/hostlist-client.c:749 src/hostlist/hostlist-client.c:877 +#: src/hostlist/hostlist-client.c:967 src/hostlist/hostlist-client.c:972 +#: src/transport/plugin_transport_http_client.c:108 +#: src/transport/plugin_transport_http_client.c:123 +#, c-format +msgid "%s failed at %s:%d: `%s'\n" +msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" + +#: src/hostlist/hostlist-client.c:592 src/hostlist/hostlist-client.c:1342 +msgid "# advertised hostlist URIs" +msgstr "" + +#: src/hostlist/hostlist-client.c:622 +#, c-format +msgid "# advertised URI `%s' downloaded" +msgstr "" + +#: src/hostlist/hostlist-client.c:663 +#, c-format +msgid "" +"Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " +"gets dismissed.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:805 +#, fuzzy, c-format +msgid "Timeout trying to download hostlist from `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/hostlist/hostlist-client.c:822 +#, c-format +msgid "Download limit of %u bytes exceeded, stopping download\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:842 +#, fuzzy, c-format +msgid "%s failed for `%s' at %s:%d: `%s'\n" +msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" + +#: src/hostlist/hostlist-client.c:848 +#, fuzzy, c-format +msgid "Download of hostlist `%s' completed.\n" +msgstr "" +"Upload von `%s' komplett, derzeitige durchschnittliche Geschwindigkeit " +"beträgt %8.3f KB/s.\n" + +#: src/hostlist/hostlist-client.c:856 +#, c-format +msgid "Adding successfully tested hostlist `%s' datastore.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:909 +#, c-format +msgid "Bootstrapping using hostlist at `%s'.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:917 +msgid "# hostlist downloads initiated" +msgstr "" + +#: src/hostlist/hostlist-client.c:1045 src/hostlist/hostlist-client.c:1515 +msgid "# milliseconds between hostlist downloads" +msgstr "" + +#: src/hostlist/hostlist-client.c:1054 +#, c-format +msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1092 +msgid "Scheduled saving of hostlists\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1096 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1119 src/hostlist/hostlist-client.c:1135 +#, fuzzy +msgid "# active connections" +msgstr "GNUnet Konfiguration" + +#: src/hostlist/hostlist-client.c:1253 +#, c-format +msgid "Initial time between hostlist downloads is %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1284 +#, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1290 +#, fuzzy, c-format +msgid "Loading saved hostlist entries from file `%s' \n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/hostlist/hostlist-client.c:1294 +#, c-format +msgid "Hostlist file `%s' is not existing\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1305 +#, fuzzy, c-format +msgid "Could not open file `%s' for reading to load hostlists: %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/hostlist/hostlist-client.c:1338 +#, c-format +msgid "%u hostlist URIs loaded from file\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1340 +msgid "# hostlist URIs read from file" +msgstr "" + +#: src/hostlist/hostlist-client.c:1373 +#, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1387 +#, fuzzy, c-format +msgid "Could not open file `%s' for writing to save hostlists: %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/hostlist/hostlist-client.c:1392 +#, fuzzy, c-format +msgid "Writing %u hostlist URIs to `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/hostlist/hostlist-client.c:1416 src/hostlist/hostlist-client.c:1433 +#, c-format +msgid "Error writing hostlist URIs to file `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1428 +msgid "# hostlist URIs written to file" +msgstr "" + +#: src/hostlist/hostlist-client.c:1480 +msgid "Learning is enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1483 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1492 +msgid "Learning is not enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1504 +#, c-format +msgid "" +"Since learning is not enabled on this peer, hostlist file `%s' was removed\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1508 +#, fuzzy, c-format +msgid "Hostlist file `%s' could not be removed\n" +msgstr "Sitzungsschlüssel von Knoten `%s' konnte nicht überprüft werden.\n" + +#: src/hostlist/hostlist-server.c:134 +#, fuzzy +msgid "bytes in hostlist" +msgstr "# bytes in der Datenbank" + +#: src/hostlist/hostlist-server.c:157 +msgid "expired addresses encountered" +msgstr "" + +#: src/hostlist/hostlist-server.c:184 +#: src/topology/gnunet-daemon-topology.c:875 +#, fuzzy, c-format +msgid "Error in communication with PEERINFO service: %s\n" +msgstr "Informationen über andere GNUnet Knoten ausgeben." + +#: src/hostlist/hostlist-server.c:205 +msgid "HELLOs without addresses encountered (ignored)" +msgstr "" + +#: src/hostlist/hostlist-server.c:221 +msgid "bytes not included in hostlist (size limit)" +msgstr "" + +#: src/hostlist/hostlist-server.c:269 +#, fuzzy, c-format +msgid "Refusing `%s' request to hostlist server\n" +msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" + +#: src/hostlist/hostlist-server.c:272 +#, fuzzy +msgid "hostlist requests refused (not HTTP GET)" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/hostlist/hostlist-server.c:280 +msgid "Sending 100 CONTINUE reply\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:287 +#, c-format +msgid "Refusing `%s' request with %llu bytes of upload data\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:291 +#, fuzzy +msgid "hostlist requests refused (upload data)" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/hostlist/hostlist-server.c:299 +msgid "Could not handle hostlist request since I do not have a response yet\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:302 +#, fuzzy +msgid "hostlist requests refused (not ready)" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/hostlist/hostlist-server.c:306 +msgid "Received request for our hostlist\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:307 +#, fuzzy +msgid "hostlist requests processed" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/hostlist/hostlist-server.c:350 +#, fuzzy +msgid "# hostlist advertisements send" +msgstr "# Bekanntmachungen von anderen übertragen" + +#: src/hostlist/hostlist-server.c:397 +msgid "Advertisement message could not be queued by core\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:565 +#, fuzzy, c-format +msgid "Invalid port number %llu. Exiting.\n" +msgstr "Ungültige Parameter. Abbruch.\n" + +#: src/hostlist/hostlist-server.c:574 +#, c-format +msgid "Hostlist service starts on %s:%llu\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:588 +#, fuzzy, c-format +msgid "Address to obtain hostlist: `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/hostlist/hostlist-server.c:626 +#, fuzzy, c-format +msgid "Could not start hostlist HTTP server on port %u\n" +msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" + +#: src/mesh/gnunet-service-mesh.c:4595 +msgid "Wrong CORE service\n" +msgstr "" + +#: src/mesh/gnunet-service-mesh.c:4789 +#, fuzzy +msgid "Mesh service is lacking key configuration settings. Exiting.\n" +msgstr "GNUnet Konfiguration" + +#: src/mesh/gnunet-service-mesh.c:4798 +#, fuzzy +msgid "Mesh service could not access hostkey. Exiting.\n" +msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" + +#: src/namestore/namestore_api.c:272 src/namestore/namestore_api.c:313 +msgid "Namestore added record successfully" +msgstr "" + +#: src/namestore/namestore_api.c:281 src/namestore/namestore_api.c:322 +msgid "Namestore failed to add record" +msgstr "" + +#: src/nat/gnunet-nat-server.c:289 +#, c-format +msgid "Please pass valid port number as the first argument! (got `%s')\n" +msgstr "" + +#: src/nat/gnunet-nat-server.c:328 +msgid "GNUnet NAT traversal test helper daemon" +msgstr "" + +#: src/nat/nat.c:803 +#, c-format +msgid "gnunet-helper-nat-server generated malformed address `%s'\n" +msgstr "" + +#: src/nat/nat.c:852 +#, fuzzy, c-format +msgid "Failed to start %s\n" +msgstr "Fehler beim Starten der Collection.\n" + +#: src/nat/nat.c:1121 +#, fuzzy, c-format +msgid "Malformed %s `%s' given in configuration!\n" +msgstr "Fehler beim Speichern der Konfiguration!" + +#: src/nat/nat.c:1187 src/nat/nat.c:1197 +#, c-format +msgid "" +"Configuration requires `%s', but binary is not installed properly (SUID bit " +"not set). Option disabled.\n" +msgstr "" + +#: src/nat/nat.c:1329 +msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" +msgstr "" + +#: src/nat/nat.c:1341 +#, c-format +msgid "Running gnunet-helper-nat-client %s %s %u\n" +msgstr "" + +#: src/nat/nat_test.c:348 +#, fuzzy +msgid "Failed to connect to `gnunet-nat-server'\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/nat/nat_test.c:418 +#, c-format +msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" +msgstr "" + +#: src/nse/gnunet-nse-profiler.c:926 +#, fuzzy +msgid "Measure quality and performance of the NSE service." +msgstr "Auf den Dienst konnte nicht zugegriffen werden" + +#: src/nse/gnunet-service-nse.c:936 +#, c-format +msgid "Proof of work invalid: %llu!\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1391 src/nse/gnunet-service-nse.c:1410 +#: src/nse/gnunet-service-nse.c:1431 +msgid "NSE service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1398 +#, fuzzy +msgid "Invalid work requirement for NSE service. Exiting.\n" +msgstr "Ungültige Parameter. Abbruch.\n" + +#: src/nse/gnunet-service-nse.c:1419 +#, fuzzy +msgid "NSE service could not access hostkey. Exiting.\n" +msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:133 +#, fuzzy, c-format +msgid "Removing expired address of transport `%s'\n" +msgstr "Verfügbare(r) Transport(e): %s\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:195 +msgid "# peers known" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:239 +#, c-format +msgid "" +"File `%s' in directory `%s' does not match naming convention. Removed.\n" +msgstr "" +"Die Datei `%s' im Verzeichnis `%s' entspricht nicht der Namenskonvention. " +"Datei wurde entfernt.\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:305 +#, fuzzy, c-format +msgid "Still no peers found in `%s'!\n" +msgstr "Dienst `%s' konnte nicht ordentlich entladen werden!\n" + +#: src/peerinfo/peerinfo_api.c:279 +#, fuzzy, c-format +msgid "Failed to transmit message to `%s' service.\n" +msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" + +#: src/peerinfo/peerinfo_api.c:435 +#, fuzzy +msgid "Failed to receive response from `PEERINFO' service." +msgstr "Fehler beim Empfangen der Antwort von gnunetd auf die `%s' Nachricht\n" + +#: src/peerinfo/peerinfo_api.c:463 src/peerinfo/peerinfo_api.c:481 +#, fuzzy +msgid "Received invalid message from `PEERINFO' service.\n" +msgstr "Ungültige `%s' Anfrage von `%s' empfangen.\n" + +#: src/peerinfo/peerinfo_api.c:523 +#, fuzzy +msgid "Failed to transmit iteration request to `PEERINFO' service\n" +msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" + +#: src/peerinfo/peerinfo_api.c:557 +msgid "Timeout transmitting iteration request to `PEERINFO' service.\n" +msgstr "" + +#: src/peerinfo/peerinfo_api_notify.c:258 +#, fuzzy, c-format +msgid "Could not connect to `%s' service.\n" +msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:216 +#, fuzzy, c-format +msgid "Could not find option `%s:%s' in configuration.\n" +msgstr "Knoten `%s' konnte nicht in der Routing Tabelle gefunden werden!\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:223 +#, fuzzy, c-format +msgid "Loading hostkey from `%s' failed.\n" +msgstr "Das Parsen des Hello von `%s' schlug fehl.\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:235 +#, c-format +msgid "I am peer `%s'.\n" +msgstr "Ich bin Peer `%s'.\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:255 +msgid "output only the identity strings" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:258 +msgid "output our own identity only" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:264 +#, fuzzy +msgid "Print information about peers." +msgstr "Informationen über andere GNUnet Knoten ausgeben." + +#: src/pt/gnunet-daemon-pt.c:264 +#, fuzzy +msgid "Failed to pack DNS request. Dropping.\n" +msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" + +#: src/pt/gnunet-daemon-pt.c:270 +#, fuzzy +msgid "# DNS requests mapped to VPN" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/pt/gnunet-daemon-pt.c:323 +msgid "# DNS records modified" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:500 +msgid "# DNS replies intercepted" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:506 +#, fuzzy +msgid "Failed to parse DNS request. Dropping.\n" +msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" + +#: src/pt/gnunet-daemon-pt.c:602 +#, fuzzy +msgid "# DNS requests dropped (timeout)" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/pt/gnunet-daemon-pt.c:632 +#, fuzzy +msgid "# DNS requests intercepted" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/pt/gnunet-daemon-pt.c:637 +#, fuzzy +msgid "# DNS requests dropped (DNS mesh tunnel down)" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/pt/gnunet-daemon-pt.c:645 +#, fuzzy +msgid "# DNS requests dropped (malformed)" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/pt/gnunet-daemon-pt.c:716 +#, fuzzy +msgid "# DNS replies received" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/pt/gnunet-daemon-pt.c:730 +#, fuzzy +msgid "# DNS replies dropped (too late?)" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 +msgid "# DNS requests aborted (tunnel down)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 +#: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 +#, fuzzy, c-format +msgid "Failed to connect to %s service. Exiting.\n" +msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" + +#: src/pt/gnunet-daemon-pt.c:973 +msgid "Daemon to run to perform IP protocol translation to GNUnet" +msgstr "" + +#: src/statistics/gnunet-service-statistics.c:209 +#, fuzzy, c-format +msgid "Loading %llu bytes of statistics from `%s'\n" +msgstr "Dateien aus dem GNUnet herunterladen." + +#: src/statistics/gnunet-service-statistics.c:267 +#, fuzzy, c-format +msgid "Wrote %llu bytes of statistics to `%s'\n" +msgstr "Dateien aus dem GNUnet herunterladen." + +#: src/statistics/gnunet-statistics.c:98 +#, fuzzy +msgid "Failed to obtain statistics.\n" +msgstr "Statistiken über den Netzwerkverkehr konnten nicht ermittelt werden.\n" + +#: src/statistics/gnunet-statistics.c:164 +msgid "limit output to statistics for the given NAME" +msgstr "" + +#: src/statistics/gnunet-statistics.c:167 +msgid "make the value being set persistent" +msgstr "" + +#: src/statistics/gnunet-statistics.c:170 +msgid "limit output to the given SUBSYSTEM" +msgstr "" + +#: src/statistics/gnunet-statistics.c:173 +msgid "just print the statistics value" +msgstr "" + +#: src/statistics/gnunet-statistics.c:180 +msgid "Print statistics about GNUnet operations." +msgstr "Statistiken der GNUnet Aktivitäten ausgeben." + +#: src/statistics/statistics_api.c:390 +#, fuzzy +msgid "Failed to connect to statistics service!\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/template/gnunet-template.c:68 +#, fuzzy +msgid "help text" +msgstr "Hilfetext für -t" + +#: src/testing/gnunet-testing.c:157 +#, fuzzy +msgid "Could not read hostkeys file, specify hostkey file with -H!\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/testing/gnunet-testing.c:159 +#, c-format +msgid "Specified hostkey file `%s' not found!\n" +msgstr "" + +#: src/testing/gnunet-testing.c:273 +#, fuzzy +msgid "create unique configuration files" +msgstr "" +"Einen Wert aus der Konfigurationsdatei auf der Standardausgabe ausgeben" + +#: src/testing/gnunet-testing.c:275 +msgid "create hostkey files from pre-computed hostkey list" +msgstr "" + +#: src/testing/gnunet-testing.c:277 +msgid "host key file" +msgstr "" + +#: src/testing/gnunet-testing.c:279 +#, fuzzy +msgid "number of unique configuration files or hostkeys to create" +msgstr "" +"Einen Wert aus der Konfigurationsdatei auf der Standardausgabe ausgeben" + +#: src/testing/gnunet-testing.c:281 +#, fuzzy +msgid "configuration template" +msgstr "GNUnet Konfiguration" + +#: src/testing/gnunet-testing.c:287 +msgid "Command line tool to access the testing library" +msgstr "" + +#: src/testing/helper.c:56 +#, fuzzy +msgid "Peer is lacking HOSTKEY configuration setting.\n" +msgstr "GNUnet Konfiguration" + +#: src/testing/helper.c:64 +#, fuzzy +msgid "Could not access hostkey.\n" +msgstr "Konfigurationsdatei `%s' konnte nicht geparst werden.\n" + +#: src/testing/testing.c:204 +msgid "`scp' does not seem to terminate (timeout copying config).\n" +msgstr "" + +#: src/testing/testing.c:218 src/testing/testing.c:808 +#, fuzzy +msgid "`scp' did not complete cleanly.\n" +msgstr "`%s' ist zu keinem Knoten verbunden.\n" + +#: src/testing/testing.c:239 +#, fuzzy +msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" +msgstr "Fehler beim Starten der Collection.\n" + +#: src/testing/testing.c:240 +#, fuzzy +msgid "Failed to create pipe for `ssh' process.\n" +msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#: src/testing/testing.c:292 +#, fuzzy, c-format +msgid "Could not start `%s' process to create hostkey.\n" +msgstr "" +"IP(v4) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP in " +"der Konfigurationsdatei an.\n" + +#: src/testing/testing.c:299 +#, fuzzy +msgid "Failed to start `gnunet-peerinfo' process.\n" +msgstr "Fehler beim Starten der Collection.\n" + +#: src/testing/testing.c:300 src/testing/testing.c:488 +#, fuzzy +msgid "Failed to start `ssh' process.\n" +msgstr "Fehler beim Starten der Collection.\n" + +#: src/testing/testing.c:360 +#, fuzzy, c-format +msgid "Error reading from gnunet-peerinfo: %s\n" +msgstr "Fehler beim Lesen von Informationen von gnunetd.\n" + +#: src/testing/testing.c:364 +#, fuzzy +msgid "Malformed output from gnunet-peerinfo!\n" +msgstr "Fehler beim Lesen von Informationen von gnunetd.\n" + +#: src/testing/testing.c:374 +#, fuzzy +msgid "Failed to get hostkey!\n" +msgstr "Statistiken über den Netzwerkverkehr konnten nicht ermittelt werden.\n" + +#: src/testing/testing.c:406 +msgid "`Failed while waiting for topology setup!\n" +msgstr "" + +#: src/testing/testing.c:480 +#, fuzzy, c-format +msgid "Could not start `%s' process to start GNUnet.\n" +msgstr "" +"IP(v4) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP in " +"der Konfigurationsdatei an.\n" + +#: src/testing/testing.c:487 +#, fuzzy +msgid "Failed to start `gnunet-arm' process.\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/testing/testing.c:509 src/testing/testing.c:612 +msgid "`gnunet-arm' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:510 src/testing/testing.c:613 +#: src/testing/testing.c:633 +msgid "`ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:582 +msgid "Unable to get HELLO for peer!\n" +msgstr "" + +#: src/testing/testing.c:632 +msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" +msgstr "" + +#: src/testing/testing.c:653 src/testing/testing.c:685 +msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:668 src/testing/testing.c:723 +#, fuzzy +msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" +msgstr "`%s' ist zu keinem Knoten verbunden.\n" + +#: src/testing/testing.c:796 +msgid "`scp' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:966 +#, fuzzy, c-format +msgid "Starting service %s for peer `%4s'\n" +msgstr "Collection `%s' begonnen.\n" + +#: src/testing/testing.c:1237 src/testing/testing_group.c:6278 +#, fuzzy, c-format +msgid "Could not start `%s' process to copy configuration directory.\n" +msgstr "" +"IP(v4) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP in " +"der Konfigurationsdatei an.\n" + +#: src/testing/testing.c:1322 src/testing/testing.c:1397 +#, fuzzy, c-format +msgid "Terminating peer `%4s'\n" +msgstr "Zugriff verweigert für `%s' bei %s:%d.\n" + +#: src/testing/testing.c:1480 +#, fuzzy, c-format +msgid "Setting d->dead on peer `%4s'\n" +msgstr "Collection `%s' begonnen.\n" + +#: src/testing/testing.c:1610 +msgid "Peer not yet running, can not change configuration at this point." +msgstr "" + +#: src/testing/testing.c:1618 +#, fuzzy +msgid "Failed to write new configuration to disk." +msgstr "Fehler beim Speichern der Konfiguration!" + +#: src/testing/testing.c:1647 +#, fuzzy, c-format +msgid "Could not start `%s' process to copy configuration file.\n" +msgstr "" +"IP(v4) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP in " +"der Konfigurationsdatei an.\n" + +#: src/testing/testing.c:1650 +#, fuzzy +msgid "Failed to copy new configuration to remote machine." +msgstr "Fehler beim Speichern der Konfiguration!" + +#: src/testing/testing.c:1805 +#, fuzzy +msgid "Peers failed to connect" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." + +#: src/testing/testing.c:1933 +#, fuzzy +msgid "Failed to connect to core service of first peer!\n" +msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" + +#: src/testing/testing.c:2156 +msgid "Peers are not fully running yet, can not connect!\n" +msgstr "" + +#: src/testing/testing_group.c:1910 src/testing/testing_group.c:1922 +#: src/testing/testing_group.c:2023 src/testing/testing_group.c:2082 +#: src/testing/testing_group.c:2171 src/testing/testing_group.c:2191 +#: src/testing/testing_group.c:2328 src/testing/testing_peergroup.c:940 +#, fuzzy, c-format +msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" +msgstr "" +"Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein Verzeichnis " +"angeben, in dem FS Daten gespeichert werden.\n" + +#: src/testing/testing_group.c:1932 +#, fuzzy, c-format +msgid "Target is %d connections per peer." +msgstr "Fehler beim Aufbauen einer Verbindung mit gnunetd.\n" + +#: src/testing/testing_group.c:2179 +#, c-format +msgid "" +"Invalid value `%s' for option `%s' in section `%s': got %f, needed value " +"greater than 0\n" +msgstr "" + +#: src/testing/testing_group.c:2209 src/testing/testing_group.c:2402 +#, c-format +msgid "Connecting nodes in 2d torus topology: %u rows %u columns\n" +msgstr "" + +#: src/testing/testing_group.c:2246 +#, c-format +msgid "natural log of %d is %d, will run %d iterations\n" +msgstr "" + +#: src/testing/testing_group.c:2249 +#, c-format +msgid "Total connections added thus far: %u!\n" +msgstr "" + +#: src/testing/testing_group.c:2290 +#, c-format +msgid "Total connections added for small world: %d!\n" +msgstr "" + +#: src/testing/testing_group.c:2342 +#, c-format +msgid "rand is %f probability is %f\n" +msgstr "" + +#: src/testing/testing_group.c:2919 src/testing/testing_group.c:3118 +#, fuzzy, c-format +msgid "" +"No `%s' specified in peer configuration in section `%s', cannot copy friends " +"file!\n" +msgstr "" +"Option `%s' ist in der Konfigurationsdatei in der Sektion `%s' nicht " +"gesetzt, sie wird auf %dm gesetzt.\n" + +#: src/testing/testing_group.c:3020 +msgid "Finished copying all friend files!\n" +msgstr "" + +#: src/testing/testing_group.c:3133 +#, fuzzy, c-format +msgid "Copying file with command cp %s %s\n" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/testing/testing_group.c:3156 +#, fuzzy, c-format +msgid "Copying file with command scp %s %s\n" +msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#: src/testing/testing_group.c:3173 +#, c-format +msgid "Checking copy status of file %d\n" +msgstr "" + +#: src/testing/testing_group.c:3191 +#, c-format +msgid "File %d copied\n" +msgstr "" + +#: src/testing/testing_group.c:3206 +#, fuzzy +msgid "Finished copying all blacklist files!\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/testing/testing_group.c:3586 src/testing/testing_group.c:3723 +#: src/testing/testing_group.c:4884 src/testing/testing_group.c:5025 +msgid "Delaying connect, we have too many outstanding connections!\n" +msgstr "" + +#: src/testing/testing_group.c:3596 src/testing/testing_group.c:4894 +#: src/testing/testing_group.c:5035 +#, c-format +msgid "Creating connection, outstanding_connections is %d\n" +msgstr "" + +#: src/testing/testing_group.c:3608 +#, fuzzy, c-format +msgid "Offering HELLO of peer %s to peer %s\n" +msgstr "Verbindung zu %u.%u.%u.%u:%u fehlgeschlagen: %s\n" + +#: src/testing/testing_group.c:3734 +#, c-format +msgid "Creating connection, outstanding_connections is %d (max %d)\n" +msgstr "" + +#: src/testing/testing_group.c:3988 +msgid "Creating clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:3993 +msgid "Creating small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:3998 +msgid "Creating small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4002 +msgid "Creating ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4006 +msgid "Creating 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4010 +msgid "Creating Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4014 +msgid "Creating InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4018 +msgid "Creating Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4023 +msgid "Creating straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4027 +msgid "Creating topology from file!\n" +msgstr "" + +#: src/testing/testing_group.c:4043 +msgid "Creating no allowed topology (all peers can connect at core level)\n" +msgstr "" + +#: src/testing/testing_group.c:4058 +msgid "Failed during friend file copying!\n" +msgstr "" + +#: src/testing/testing_group.c:4064 +msgid "Friend files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:4081 +msgid "Blacklisting all but clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:4087 +msgid "Blacklisting all but small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4093 +msgid "Blacklisting all but small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4099 +msgid "Blacklisting all but ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4105 +msgid "Blacklisting all but 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4111 +msgid "Blacklisting all but Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4117 +msgid "Blacklisting all but InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4152 +msgid "Blacklisting all but Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4158 +msgid "Blacklisting all but straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4173 +#, fuzzy +msgid "Failed during blacklist file copying!\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/testing/testing_group.c:4179 +msgid "Blacklist files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:5263 +msgid "Creating clique CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5270 +msgid "Creating small world (ring) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5277 +msgid "Creating small world (2d-torus) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5283 +msgid "Creating ring CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5290 +msgid "Creating 2d torus CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5297 +msgid "Creating Erdos-Renyi CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5304 +msgid "Creating InterNAT CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5311 +msgid "Creating Scale Free CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5318 +msgid "Creating straight line CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5324 +msgid "Creating no CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5330 +#, fuzzy +msgid "Unknown topology specification, can't connect peers!\n" +msgstr "Syntaxfehler in Topolgieangabe, Bytes werden übersprungen.\n" + +#: src/testing/testing_group.c:5340 +#, c-format +msgid "Connecting random subset (%'.2f percent) of possible peers\n" +msgstr "" + +#: src/testing/testing_group.c:5348 +#, c-format +msgid "Connecting a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5357 +#, c-format +msgid "Using DFS to connect a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5367 +#, c-format +msgid "Finding additional %u closest peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:6062 src/transport/transport-testing.c:650 +#, fuzzy +msgid "Could not read hostkeys file!\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/testing/testing_group.c:6131 +#, fuzzy, c-format +msgid "Could not create configuration for peer number %u on `%s'!\n" +msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" + +#: src/topology/gnunet-daemon-topology.c:244 +msgid "# peers blacklisted" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:380 +#, fuzzy +msgid "# connect requests issued to transport" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/topology/gnunet-daemon-topology.c:675 +#: src/topology/gnunet-daemon-topology.c:761 +#, fuzzy +msgid "# friends connected" +msgstr "# verbundener Knoten" + +#: src/topology/gnunet-daemon-topology.c:950 +msgid "Failed to connect to core service, can not manage topology!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:982 +#, c-format +msgid "Option `%s' in section `%s' not specified!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:994 +#, fuzzy, c-format +msgid "Could not read friends list `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/topology/gnunet-daemon-topology.c:1000 +#, c-format +msgid "Friends file `%s' is empty.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1009 +#, fuzzy, c-format +msgid "Failed to read friends list from `%s': out of memory\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/topology/gnunet-daemon-topology.c:1017 +#, c-format +msgid "Failed to read friends list from `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/topology/gnunet-daemon-topology.c:1037 +#, fuzzy, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes.\n" +msgstr "Syntaxfehler in Topolgieangabe, Bytes werden übersprungen.\n" + +#: src/topology/gnunet-daemon-topology.c:1050 +#, fuzzy, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" +msgstr "Syntaxfehler in Topologieangabe, überspringe Bytes `%s'.\n" + +#: src/topology/gnunet-daemon-topology.c:1060 +#, fuzzy, c-format +msgid "Found friend `%s' in configuration\n" +msgstr " gconfig\tGTK Konfiguration\n" + +#: src/topology/gnunet-daemon-topology.c:1066 +#, c-format +msgid "Found myself `%s' in friend list (useless, ignored)\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1076 +#, fuzzy +msgid "# friends in configuration" +msgstr " gconfig\tGTK Konfiguration\n" + +#: src/topology/gnunet-daemon-topology.c:1082 +msgid "" +"Fewer friends specified than required by minimum friend count. Will only " +"connect to friends.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1089 +msgid "" +"More friendly connections required than target total number of connections.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1126 +#, fuzzy +msgid "# HELLO messages received" +msgstr "# verschlüsselter PONG Nachrichten empfangen" + +#: src/topology/gnunet-daemon-topology.c:1183 +#, fuzzy +msgid "# HELLO messages gossipped" +msgstr "# ausgehender Nachrichten verworfen" + +#: src/topology/gnunet-daemon-topology.c:1323 +msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:247 +#, fuzzy, c-format +msgid "Could not read blacklist file `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/transport/gnunet-service-transport_blacklist.c:254 +#, c-format +msgid "Blacklist file `%s' is empty.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:266 +#, fuzzy, c-format +msgid "Failed to read blacklist from `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/transport/gnunet-service-transport_blacklist.c:287 +#: src/transport/gnunet-service-transport_blacklist.c:311 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, giving up!\n" +msgstr "Syntaxfehler in Konfigurationsdatei `%s' in Zeile %d.\n" + +#: src/transport/gnunet-service-transport_blacklist.c:298 +#: src/transport/gnunet-service-transport_blacklist.c:336 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" +msgstr "Syntaxfehler in Topolgieangabe, Bytes werden übersprungen.\n" + +#: src/transport/gnunet-service-transport_blacklist.c:350 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" +msgstr "Syntaxfehler in Topologieangabe, überspringe Bytes `%s'.\n" + +#: src/transport/gnunet-service-transport_blacklist.c:364 +#, c-format +msgid "Found myself `%s' in blacklist (useless, ignored)\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:523 +#: src/transport/gnunet-service-transport_blacklist.c:764 +msgid "# disconnects due to blacklist" +msgstr "" + +#: src/transport/gnunet-service-transport.c:158 +#, fuzzy +msgid "# bytes payload discarded due to not connected peer " +msgstr "# Knotenankündigungen empfangen" + +#: src/transport/gnunet-service-transport.c:572 +msgid "Transport service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport.c:581 +msgid "Transport service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:353 +#, c-format +msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:358 +#, fuzzy +msgid "# messages dropped due to slow client" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/transport/gnunet-service-transport_clients.c:510 +#, c-format +msgid "Rejecting control connection from peer `%s', which is not me!\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:628 +#, fuzzy +msgid "# bytes payload received for other peers" +msgstr "# Bytes des Typs %d empfangen" + +#: src/transport/gnunet-service-transport_clients.c:645 +msgid "# bytes payload dropped (other peer was not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:696 +#, fuzzy +msgid "# REQUEST CONNECT messages received" +msgstr "# verschlüsselter PONG Nachrichten empfangen" + +#: src/transport/gnunet-service-transport_hello.c:172 +msgid "# refreshed my HELLO" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:482 +msgid "# failed connection attempts due to timeout" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:883 +#, fuzzy +msgid "# peers disconnected due to external request" +msgstr "# gap Anfragen verworfen: Kollision in RT" + +#: src/transport/gnunet-service-transport_neighbours.c:966 +#, fuzzy +msgid "# fast reconnects failed" +msgstr "# verbundener Knoten" + +#: src/transport/gnunet-service-transport_neighbours.c:1022 +#, fuzzy +msgid "# peers disconnected due to timeout" +msgstr "# geschlossener Verbindungen (HANGUP gesendet)" + +#: src/transport/gnunet-service-transport_neighbours.c:1047 +#, fuzzy +msgid "# keepalives sent" +msgstr "# p2p Trace-Antworten gesendet" + +#: src/transport/gnunet-service-transport_neighbours.c:1088 +#, fuzzy +msgid "# peers disconnected due to global disconnect" +msgstr "# Knotenankündigungen empfangen" + +#: src/transport/gnunet-service-transport_neighbours.c:1888 +#: src/transport/gnunet-service-transport_neighbours.c:1909 +#, fuzzy +msgid "# messages not sent (no such peer or not connected)" +msgstr "# defragmentierter Nachrichten" + +#: src/transport/gnunet-service-transport_neighbours.c:1925 +#, fuzzy +msgid "# bytes in message queue for other peers" +msgstr "# Bytes ausgehender Nachrichten verworfen" + +#: src/transport/gnunet-service-transport_neighbours.c:1977 +#, fuzzy +msgid "# messages discarded due to lack of neighbour record" +msgstr "# defragmentierter Nachrichten" + +#: src/transport/gnunet-service-transport_neighbours.c:2013 +#, fuzzy +msgid "# bandwidth quota violations by other peers" +msgstr "Verfolgt die Bandbreitennutzung von gnunetd" + +#: src/transport/gnunet-service-transport_neighbours.c:2031 +msgid "# ms throttling suggested" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2060 +#, fuzzy +msgid "# KEEPALIVE messages discarded (not connected)" +msgstr "# defragmentierter Nachrichten" + +#: src/transport/gnunet-service-transport_neighbours.c:2113 +#, fuzzy +msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" +msgstr "# defragmentierter Nachrichten" + +#: src/transport/gnunet-service-transport_neighbours.c:2121 +#, fuzzy +msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" +msgstr "# defragmentierter Nachrichten" + +#: src/transport/gnunet-service-transport_neighbours.c:2187 +msgid "# SET QUOTA messages ignored (no such peer)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2205 +msgid "# disconnects due to quota of 0" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2323 +msgid "# disconnect messages ignored (old format)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2336 +msgid "# disconnect messages ignored (timestamp)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2411 +#, fuzzy +msgid "# unexpected CONNECT_ACK messages (no peer)" +msgstr "COUNT Nachrichten versenden" + +#: src/transport/gnunet-service-transport_neighbours.c:2453 +#, fuzzy +msgid "# unexpected CONNECT_ACK messages" +msgstr "COUNT Nachrichten versenden" + +#: src/transport/gnunet-service-transport_neighbours.c:2544 +#, fuzzy +msgid "# unexpected ACK messages" +msgstr "# verschlüsselter PONG Nachrichten gesendet" + +#: src/transport/gnunet-service-transport_plugins.c:111 +msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:118 +#, fuzzy, c-format +msgid "Starting transport plugins `%s'\n" +msgstr "Teste Transport(e) %s\n" + +#: src/transport/gnunet-service-transport_plugins.c:122 +#, fuzzy, c-format +msgid "Loading `%s' transport plugin\n" +msgstr "Teste Transport(e) %s\n" + +#: src/transport/gnunet-service-transport_plugins.c:150 +#, fuzzy, c-format +msgid "Failed to load transport plugin for `%s'\n" +msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" + +#: src/transport/gnunet-service-transport_validation.c:410 +msgid "# address records discarded" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:459 +#, c-format +msgid "" +"Not transmitting `%s' with `%s', message too big (%u bytes!). This should " +"not happen.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:508 +#, fuzzy +msgid "# PING without HELLO messages sent" +msgstr "# Klartext PING Nachrichten gesendet" + +#: src/transport/gnunet-service-transport_validation.c:566 +msgid "# address revalidations started" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:798 +#, fuzzy +msgid "# PING message for different peer received" +msgstr "# PING Nachrichten erstellt" + +#: src/transport/gnunet-service-transport_validation.c:833 +#, c-format +msgid "" +"Not confirming PING with address `%s' since I cannot confirm having this " +"address.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:919 +msgid "# PONGs unicast via reliable transport" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:928 +msgid "# PONGs multicast to all available addresses" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1050 +msgid "# PONGs dropped, no matching pending validation" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1075 +msgid "# PONGs dropped, signature expired" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1134 +#, fuzzy, c-format +msgid "Adding `%s' without addresses for peer `%s'\n" +msgstr "Adresse des Knotens `%s' konnte nicht ermittelt werden.\n" + +#: src/transport/gnunet-transport.c:256 +msgid "No transport plugins configured, peer will never communicate\n" +msgstr "" + +#: src/transport/gnunet-transport.c:269 +#, c-format +msgid "No port configured for plugin `%s', cannot test it\n" +msgstr "" + +#: src/transport/gnunet-transport.c:319 +#, c-format +msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:326 +#, c-format +msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:359 +#, fuzzy, c-format +msgid "Transmitting %u bytes to %s\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/transport/gnunet-transport.c:379 +#, fuzzy, c-format +msgid "Connected to %s\n" +msgstr "`%s' hat sich mit `%s' verbunden.\n" + +#: src/transport/gnunet-transport.c:410 +#, fuzzy, c-format +msgid "Disconnected from %s\n" +msgstr "`%s' hat sich mit `%s' verbunden.\n" + +#: src/transport/gnunet-transport.c:439 +#, fuzzy, c-format +msgid "Received %u bytes from %s\n" +msgstr "GAP hat ungültige Inhalte von `%s' empfangen.\n" + +#: src/transport/gnunet-transport.c:453 +#, fuzzy, c-format +msgid "Peer `%s': %s %s\n" +msgstr "Ich bin Peer `%s'.\n" + +#: src/transport/gnunet-transport.c:483 +#, fuzzy, c-format +msgid "Peer `%s' disconnected\n" +msgstr "# verbundener Knoten" + +#: src/transport/gnunet-transport.c:539 +#, fuzzy, c-format +msgid "Failed to parse peer identity `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/transport/gnunet-transport.c:587 +msgid "measure how fast we are receiving data (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:590 +#, fuzzy +msgid "try to connect to the given peer" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/transport/gnunet-transport.c:593 +#, fuzzy +msgid "provide information about all current connections (once)" +msgstr "Informationen über andere GNUnet Knoten ausgeben." + +#: src/transport/gnunet-transport.c:596 +#, fuzzy +msgid "provide information about all current connections (continuously)" +msgstr "Informationen über andere GNUnet Knoten ausgeben." + +#: src/transport/gnunet-transport.c:599 +#, fuzzy +msgid "do not resolve hostnames" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/transport/gnunet-transport.c:603 +msgid "send data for benchmarking to the other peer (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:606 +msgid "test transport configuration (involves external server)" +msgstr "" + +#: src/transport/gnunet-transport.c:614 +#, fuzzy +msgid "Direct access to transport service." +msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" + +#: src/transport/plugin_transport_http.c:981 +msgid "Disabling IPv6 since it is not supported on this system!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1029 +#, fuzzy +msgid "Require valid port number for service in configuration!\n" +msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" + +#: src/transport/plugin_transport_http.c:1054 src/util/service.c:986 +#, fuzzy, c-format +msgid "Failed to resolve `%s': %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/transport/plugin_transport_http.c:1071 src/util/service.c:1003 +#, fuzzy, c-format +msgid "Failed to find %saddress for `%s'.\n" +msgstr "Fehler beim Binden an UDP Port %d.\n" + +#: src/transport/plugin_transport_http.c:1176 +#, c-format +msgid "Found %u addresses to report to NAT service\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1189 +#, c-format +msgid "FREEING %s\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1264 +#, fuzzy +msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" +msgstr "Netzwerkbekanntmachungen wurden per Konfiguration deaktiviert!\n" + +#: src/transport/plugin_transport_http.c:1277 +#, fuzzy +msgid "Port is required! Fix in configuration\n" +msgstr " gconfig\tGTK Konfiguration\n" + +#: src/transport/plugin_transport_http.c:1288 +msgid "Port 0, client only mode\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1308 +#, c-format +msgid "" +"Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1338 +#, c-format +msgid "" +"Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http_client.c:621 +#, c-format +msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:189 +msgid "" +"Could not create a new TLS certificate, program `gnunet-transport-" +"certificate-creation' could not be started!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:213 +msgid "No usable TLS certificate found and creating one failed!\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:370 +#, fuzzy, c-format +msgid "Received malformed message via %s. Ignored.\n" +msgstr "" +"Es wurde eine ungültige Nachricht per SMTP empfangen (ungültige Größe).\n" + +#: src/transport/plugin_transport_smtp.c:457 +#, fuzzy +msgid "SMTP filter string to invalid, lacks ': '\n" +msgstr "SMTP Filterstring zu lang, wurde auf `%s' abgeschnitten\n" + +#: src/transport/plugin_transport_smtp.c:466 +#, c-format +msgid "SMTP filter string to long, capped to `%s'\n" +msgstr "SMTP Filterstring zu lang, wurde auf `%s' abgeschnitten\n" + +#: src/transport/plugin_transport_smtp.c:561 +#: src/transport/plugin_transport_smtp.c:571 +#: src/transport/plugin_transport_smtp.c:584 +#: src/transport/plugin_transport_smtp.c:603 +#: src/transport/plugin_transport_smtp.c:626 +#: src/transport/plugin_transport_smtp.c:634 +#: src/transport/plugin_transport_smtp.c:647 +#: src/transport/plugin_transport_smtp.c:658 +#, fuzzy, c-format +msgid "SMTP: `%s' failed: %s.\n" +msgstr "`%s' schlug fehl: %s\n" + +#: src/transport/plugin_transport_smtp.c:801 +#, fuzzy +msgid "No email-address specified, can not start SMTP transport.\n" +msgstr "" +"Kein Filter für E-Mail angegeben, es kann keine Bekanntmachung erstellt " +"werden.\n" + +#: src/transport/plugin_transport_smtp.c:813 +#, fuzzy +msgid "# bytes received via SMTP" +msgstr "# Bytes empfangen über TCP" + +#: src/transport/plugin_transport_smtp.c:814 +#, fuzzy +msgid "# bytes sent via SMTP" +msgstr "# Bytes gesendet über TCP" + +#: src/transport/plugin_transport_smtp.c:816 +#, fuzzy +msgid "# bytes dropped by SMTP (outgoing)" +msgstr "# Bytes verworfen von TCP (ausgehend)" + +#: src/transport/plugin_transport_tcp.c:512 +#, c-format +msgid "Unexpected address length: %u bytes\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:616 +#: src/transport/plugin_transport_tcp.c:705 +#: src/transport/plugin_transport_tcp.c:757 +#: src/transport/plugin_transport_tcp.c:830 +#: src/transport/plugin_transport_tcp.c:909 +#, fuzzy +msgid "# bytes currently in TCP buffers" +msgstr "# Bytes gesendet über TCP" + +#: src/transport/plugin_transport_tcp.c:622 +#: src/transport/plugin_transport_tcp.c:856 +#: src/transport/plugin_transport_tcp.c:1561 +#, fuzzy +msgid "# TCP sessions active" +msgstr "# Sitzungsschlüssel akzeptiert" + +#: src/transport/plugin_transport_tcp.c:709 +#, fuzzy +msgid "# bytes discarded by TCP (timeout)" +msgstr "# Bytes verworfen von TCP (ausgehend)" + +#: src/transport/plugin_transport_tcp.c:760 +#, fuzzy +msgid "# bytes transmitted via TCP" +msgstr "# Bytes des Typs %d übertragen" + +#: src/transport/plugin_transport_tcp.c:834 +#, fuzzy +msgid "# bytes discarded by TCP (disconnect)" +msgstr "# Bytes verworfen von TCP (ausgehend)" + +#: src/transport/plugin_transport_tcp.c:1081 +#, c-format +msgid "Address of unexpected length: %u\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1116 +msgid "Found valid IPv4 NAT address (creating session)!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1186 +msgid "# transport-service disconnect requests for TCP" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1603 +#, fuzzy +msgid "# TCP WELCOME messages received" +msgstr "# verschlüsselter PONG Nachrichten empfangen" + +#: src/transport/plugin_transport_tcp.c:1756 +msgid "# bytes received via TCP" +msgstr "# Bytes empfangen über TCP" + +#: src/transport/plugin_transport_tcp.c:1823 +msgid "# network-level TCP disconnect events" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1962 src/util/service.c:889 +#, c-format +msgid "Require valid port number for service `%s' in configuration!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1976 +#, fuzzy +msgid "Failed to start service.\n" +msgstr "Fehler beim Starten der Collection.\n" + +#: src/transport/plugin_transport_tcp.c:2039 +#, fuzzy, c-format +msgid "Failed to find option %s in section %s!\n" +msgstr "Fehler beim Binden an UDP Port %d.\n" + +#: src/transport/plugin_transport_tcp.c:2062 +#, fuzzy, c-format +msgid "TCP transport listening on port %llu\n" +msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" + +#: src/transport/plugin_transport_tcp.c:2066 +msgid "TCP transport not listening on any port (client only)\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2070 +#, c-format +msgid "TCP transport advertises itself as being on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_udp_broadcasting.c:130 +#, fuzzy +msgid "# IPv6 multicast HELLO beacons received via udp" +msgstr "# verschlüsselter PONG Nachrichten empfangen" + +#: src/transport/plugin_transport_udp_broadcasting.c:172 +#, fuzzy +msgid "# IPv4 broadcast HELLO beacons received via udp" +msgstr "# verschlüsselter PONG Nachrichten empfangen" + +#: src/transport/plugin_transport_udp_broadcasting.c:393 +#, c-format +msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:1985 +#, fuzzy +msgid "Failed to open UDP sockets\n" +msgstr "Fehler beim Binden an UDP6 Port %d.\n" + +#: src/transport/plugin_transport_udp.c:2068 +#, c-format +msgid "Given `%s' option is out of range: %llu > %u\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:2112 +#, fuzzy, c-format +msgid "Invalid IPv6 address: `%s'\n" +msgstr "Ungültiger Parameter: `%s'\n" + +#: src/transport/plugin_transport_unix.c:1051 +#, fuzzy +msgid "Failed to open UNIX sockets\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/transport/plugin_transport_wlan.c:875 +#, fuzzy +msgid "# wlan session timeouts" +msgstr "# Sitzungsschlüssel akzeptiert" + +#: src/transport/plugin_transport_wlan.c:899 +#, fuzzy +msgid "# wlan session created" +msgstr "# Sitzungsschlüssel akzeptiert" + +#: src/transport/plugin_transport_wlan.c:980 +#: src/transport/plugin_transport_wlan.c:1138 +#: src/transport/plugin_transport_wlan.c:1159 +#: src/transport/plugin_transport_wlan.c:1190 +#: src/transport/plugin_transport_wlan.c:2334 +#: src/transport/plugin_transport_wlan.c:3142 +msgid "# wlan pending sessions" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1233 +#: src/transport/plugin_transport_wlan.c:1888 +#, fuzzy +msgid "# wlan pending fragments" +msgstr "# verworfener Nachrichten" + +#: src/transport/plugin_transport_wlan.c:1388 +#, c-format +msgid "" +"Finished reading from gnunet-helper-transport-wlan stdout with code: %d\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1732 +msgid "# wlan hello beacons send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1765 +#: src/transport/plugin_transport_wlan.c:1968 +#: src/transport/plugin_transport_wlan.c:2059 +#, c-format +msgid "Error writing to wlan helper. errno == %d, ERROR: %s\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1954 +msgid "# wlan acks send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2025 +#, fuzzy +msgid "# wlan fragments send" +msgstr "# verworfener Nachrichten" + +#: src/transport/plugin_transport_wlan.c:2161 +#, c-format +msgid "Wlan Address len %d is wrong\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2295 +#: src/transport/plugin_transport_wlan.c:2919 +#: src/transport/plugin_transport_wlan.c:3145 +msgid "# wlan mac endpoints" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2517 +#, fuzzy +msgid "# wlan whole messages received" +msgstr "# verschlüsselter PING Nachrichten empfangen" + +#: src/transport/plugin_transport_wlan.c:2708 +#, fuzzy +msgid "# wlan hello messages received" +msgstr "# verschlüsselter PING Nachrichten empfangen" + +#: src/transport/plugin_transport_wlan.c:2742 +#, fuzzy +msgid "# wlan fragments received" +msgstr "# verworfener Nachrichten" + +#: src/transport/plugin_transport_wlan.c:2790 +#, fuzzy +msgid "# wlan acks received" +msgstr "# gap Anfragen insgesamt empfangen" + +#: src/transport/plugin_transport_wlan.c:2879 +msgid "# wlan mac endpoints timeouts" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2903 +#, fuzzy +msgid "# wlan mac endpoints created" +msgstr "# Client Trace-Anfragen empfangen" + +#: src/transport/plugin_transport_wlan.c:2956 +msgid "# wlan WLAN_HELPER_DATA received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:3010 +#, fuzzy +msgid "# wlan messages for this client received" +msgstr "# verschlüsselter PING Nachrichten empfangen" + +#: src/transport/plugin_transport_wlan.c:3021 +#, fuzzy +msgid "# wlan messages inside WLAN_HELPER_DATA received" +msgstr "# verschlüsselter PING Nachrichten empfangen" + +#: src/transport/transport_api.c:588 +#, fuzzy, c-format +msgid "Received unexpected message of type %u in %s:%u\n" +msgstr "Es wurde eine unbekannte Testbed Nachricht des Typs %u empfangen.\n" + +#: src/util/bio.c:136 src/util/bio.c:142 +#, fuzzy, c-format +msgid "Error reading `%s': %s" +msgstr "Fehler beim Anlegen des Benutzers" + +#: src/util/bio.c:143 +#, fuzzy +msgid "End of file" +msgstr "Eine Konfigurationsdatei laden" + +#: src/util/bio.c:195 +#, c-format +msgid "Error reading length of string `%s'" +msgstr "" + +#: src/util/bio.c:205 +#, c-format +msgid "String `%s' longer than allowed (%u > %u)" +msgstr "" + +#: src/util/bio.c:250 +#, c-format +msgid "Serialized metadata `%s' larger than allowed (%u>%u)" +msgstr "" + +#: src/util/bio.c:264 +#, c-format +msgid "Metadata `%s' failed to deserialize" +msgstr "" + +#: src/util/client.c:304 +#, c-format +msgid "" +"Could not determine valid hostname and port for service `%s' from " +"configuration.\n" +msgstr "" + +#: src/util/client.c:312 +#, c-format +msgid "Need a non-empty hostname for service `%s'.\n" +msgstr "" + +#: src/util/client.c:657 +msgid "Failure to transmit TEST request.\n" +msgstr "" + +#: src/util/client.c:717 src/util/service.c:919 +#, c-format +msgid "UNIXPATH `%s' too long, maximum length is %llu\n" +msgstr "" + +#: src/util/client.c:859 +#, fuzzy, c-format +msgid "Could not connect to service `%s', must not be running.\n" +msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" + +#: src/util/client.c:875 +#, fuzzy, c-format +msgid "Failure to transmit request to service `%s'\n" +msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" + +#: src/util/client.c:1143 +msgid "Could not submit request, not expecting to receive a response.\n" +msgstr "" + +#: src/util/common_logging.c:239 src/util/common_logging.c:889 +msgid "DEBUG" +msgstr "DEBUG" + +#: src/util/common_logging.c:241 src/util/common_logging.c:887 +msgid "INFO" +msgstr "INFO" + +#: src/util/common_logging.c:243 src/util/common_logging.c:885 +msgid "WARNING" +msgstr "WARNUNG" + +#: src/util/common_logging.c:245 src/util/common_logging.c:883 +msgid "ERROR" +msgstr "FEHLER" + +#: src/util/common_logging.c:247 src/util/common_logging.c:891 +msgid "NONE" +msgstr "" + +#: src/util/common_logging.c:609 +#, fuzzy, c-format +msgid "Failed to create or access directory for log file `%s'\n" +msgstr "Konfigurationsdatei `%s' konnte nicht geparst werden.\n" + +#: src/util/common_logging.c:724 +#, c-format +msgid "Message `%.*s' repeated %u times in the last %s\n" +msgstr "" + +#: src/util/common_logging.c:892 +msgid "INVALID" +msgstr "" + +#: src/util/common_logging.c:991 +#, fuzzy +msgid "unknown address" +msgstr "Unbekannter Fehler" + +#: src/util/common_logging.c:1029 +#, fuzzy +msgid "invalid address" +msgstr "Ungültige Parameter: " + +#: src/util/configuration.c:245 +#, fuzzy, c-format +msgid "Syntax error in configuration file `%s' at line %u.\n" +msgstr "Syntaxfehler in Konfigurationsdatei `%s' in Zeile %d.\n" + +#: src/util/configuration.c:817 +#, c-format +msgid "" +"Configuration value '%s' for '%s' in section '%s' is not in set of legal " +"choices\n" +msgstr "" + +#: src/util/connection.c:460 +#, fuzzy, c-format +msgid "Access denied to `%s'\n" +msgstr "Zugriff verweigert für `%s' bei %s:%d.\n" + +#: src/util/connection.c:475 +#, c-format +msgid "Accepting connection from `%s': %p\n" +msgstr "" + +#: src/util/connection.c:629 +#, fuzzy, c-format +msgid "" +"Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" +msgstr "Fehler beim Aufbauen einer Verbindung mit gnunetd.\n" + +#: src/util/connection.c:821 src/util/connection.c:992 +#, fuzzy, c-format +msgid "Trying to connect to `%s' (%p)\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/util/connection.c:830 +#, fuzzy, c-format +msgid "Failed to connect to `%s' (%p)\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/util/connection.c:983 +#, fuzzy, c-format +msgid "Attempt to connect to `%s' failed\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/util/connection.c:1465 +#, c-format +msgid "" +"Could not satisfy pending transmission request, socket closed or connect " +"failed (%p).\n" +msgstr "" + +#: src/util/container_bloomfilter.c:507 +#, c-format +msgid "" +"Size of file on disk is incorrect for this Bloom filter (want %llu, have " +"%llu)\n" +msgstr "" + +#: src/util/crypto_random.c:280 +#, c-format +msgid "Starting `%s' process to generate entropy\n" +msgstr "" + +#: src/util/crypto_random.c:309 +#, c-format +msgid "libgcrypt has not the expected version (version %s is required).\n" +msgstr "" +"libgcrypt hat nicht die erwartete Version (Version %s wird vorausgesetzt).\n" + +#: src/util/crypto_rsa.c:618 src/util/crypto_rsa.c:665 +#, fuzzy, c-format +msgid "Could not aquire lock on file `%s': %s...\n" +msgstr "PID konnte nicht in Datei `%s' geschrieben werden: %s.\n" + +#: src/util/crypto_rsa.c:623 +#, fuzzy +msgid "Creating a new private key. This may take a while.\n" +msgstr "Ein neuer Hostkey wird erzeugt (dies kann eine Weile dauern).\n" + +#: src/util/crypto_rsa.c:641 +#, c-format +msgid "I am host `%s'. Stored new private key in `%s'.\n" +msgstr "" + +#: src/util/crypto_rsa.c:669 src/util/crypto_rsa.c:705 +msgid "This may be ok if someone is currently generating a hostkey.\n" +msgstr "" + +#: src/util/crypto_rsa.c:700 +#, c-format +msgid "" +"When trying to read hostkey file `%s' I found %u bytes but I need at least " +"%u.\n" +msgstr "" + +#: src/util/crypto_rsa.c:720 +#, fuzzy, c-format +msgid "File `%s' does not contain a valid private key. Deleting it.\n" +msgstr "Die Datei `%s' enthält kein Pseudonym.\n" + +#: src/util/crypto_rsa.c:738 +#, fuzzy, c-format +msgid "I am host `%s'. Read private key from `%s'.\n" +msgstr "Aufruf von `%s' mit Schlüssel `%s'.\n" + +#: src/util/crypto_rsa.c:959 +#, c-format +msgid "RSA signature verification failed at %s:%d: %s\n" +msgstr "RSA Signaturüberprüfung fehlgeschlagen bei %s:%d: %s\n" + +#: src/util/disk.c:479 +#, fuzzy, c-format +msgid "`%s' failed for drive `%S': %u\n" +msgstr "`%s' fehlgeschlagen für Laufwerk %s: %u\n" + +#: src/util/disk.c:1087 +#, fuzzy, c-format +msgid "Expected `%s' to be a directory!\n" +msgstr "`%s' erwartet, dass `%s' ein Verzeichnis ist!\n" + +#: src/util/disk.c:1441 src/util/service.c:1580 +#, fuzzy, c-format +msgid "Cannot obtain information about user `%s': %s\n" +msgstr "Fehler beim Speichern der Konfigurationsdatei: `%s': %s.\n" + +#: src/util/disk.c:1759 +#, fuzzy, c-format +msgid "No `%s' specified for service `%s' in configuration.\n" +msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" + +#: src/util/getopt.c:672 +#, c-format +msgid "%s: option `%s' is ambiguous\n" +msgstr "%s: Option `%s' ist mehrdeutig\n" + +#: src/util/getopt.c:696 +#, c-format +msgid "%s: option `--%s' does not allow an argument\n" +msgstr "%s: Option '--%s' erlaubt keinen Parameter\n" + +#: src/util/getopt.c:701 +#, c-format +msgid "%s: option `%c%s' does not allow an argument\n" +msgstr "%s: Option '%c%s' erlaubt keinen Parameter\n" + +#: src/util/getopt.c:718 src/util/getopt.c:886 +#, c-format +msgid "%s: option `%s' requires an argument\n" +msgstr "%s: Option `%s' benötigt einen Parameter\n" + +#: src/util/getopt.c:747 +#, c-format +msgid "%s: unrecognized option `--%s'\n" +msgstr "%s: unbekannte Option '--%s'\n" + +#: src/util/getopt.c:751 +#, c-format +msgid "%s: unrecognized option `%c%s'\n" +msgstr "%s: unbekannte Option '%c%s'\n" + +#: src/util/getopt.c:776 +#, c-format +msgid "%s: illegal option -- %c\n" +msgstr "%s: unerlaubte Option -- %c\n" + +#: src/util/getopt.c:778 +#, c-format +msgid "%s: invalid option -- %c\n" +msgstr "%s: ungültige Option -- %c\n" + +#: src/util/getopt.c:806 src/util/getopt.c:934 +#, c-format +msgid "%s: option requires an argument -- %c\n" +msgstr "%s: Option benötigt einen Parameter -- %c\n" + +#: src/util/getopt.c:854 +#, c-format +msgid "%s: option `-W %s' is ambiguous\n" +msgstr "%s: Option '-W %s' ist mehrdeutig\n" + +#: src/util/getopt.c:872 +#, c-format +msgid "%s: option `-W %s' does not allow an argument\n" +msgstr "%s: Option '-W %s' erlaubt keinen Parameter\n" + +#: src/util/getopt.c:1038 +#, fuzzy, c-format +msgid "Use %s to get a list of options.\n" +msgstr "Verwenden Sie --help, um eine Liste der Optionen zu erhalten.\n" + +#: src/util/getopt_helpers.c:84 +#, c-format +msgid "" +"Arguments mandatory for long options are also mandatory for short options.\n" +msgstr "" +"Parameter, die für lange Optionen zwingend sind, sind auch für kurze " +"Optionen zwingend.\n" + +#: src/util/getopt_helpers.c:255 src/util/getopt_helpers.c:283 +#, c-format +msgid "You must pass a number to the `%s' option.\n" +msgstr "Sie müssen für die Option `%s' zusätzlich eine Zahl angeben.\n" + +#: src/util/gnunet-resolver.c:148 +msgid "perform a reverse lookup" +msgstr "" + +#: src/util/gnunet-resolver.c:154 +msgid "Use build-in GNUnet stub resolver" +msgstr "" + +#: src/util/gnunet-service-resolver.c:288 +#, fuzzy, c-format +msgid "Could not resolve `%s' (%s): %s\n" +msgstr "`%s' konnte nicht aufgelöst werden: %s\n" + +#: src/util/gnunet-service-resolver.c:358 +#: src/util/gnunet-service-resolver.c:399 +#, c-format +msgid "Could not find IP of host `%s': %s\n" +msgstr "IP des Hosts `%s' konnte nicht ermittelt werden: %s\n" + +#: src/util/gnunet-service-resolver.c:494 +#, c-format +msgid "Resolver asked to look up `%s'.\n" +msgstr "" + +#: src/util/gnunet-service-resolver.c:529 +#, c-format +msgid "Resolver asked to look up IP address `%s'.\n" +msgstr "" + +#: src/util/helper.c:239 +#, fuzzy, c-format +msgid "Error reading from `%s': %s\n" +msgstr "Fehler beim Anlegen des Benutzers" + +#: src/util/helper.c:254 +#, c-format +msgid "Got 0 bytes from helper `%s' (EOF)\n" +msgstr "" + +#: src/util/helper.c:264 +#, fuzzy, c-format +msgid "Got %u bytes from helper `%s'\n" +msgstr "GAP hat ungültige Inhalte von `%s' empfangen.\n" + +#: src/util/helper.c:273 +#, fuzzy, c-format +msgid "Failed to parse inbound message from helper `%s'\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/util/helper.c:432 +#, fuzzy, c-format +msgid "Error writing to `%s': %s\n" +msgstr "Fehler beim Anlegen des Benutzers" + +#: src/util/network.c:1196 +#, c-format +msgid "" +"Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" +msgstr "" + +#: src/util/os_installation.c:299 +#, c-format +msgid "" +"Could not determine installation path for %s. Set `%s' environment " +"variable.\n" +msgstr "" + +#: src/util/os_installation.c:486 +#, fuzzy, c-format +msgid "Could not find binary `%s' in PATH!\n" +msgstr "Knoten `%s' konnte nicht in der Routing Tabelle gefunden werden!\n" + +#: src/util/os_installation.c:492 +#, fuzzy, c-format +msgid "access (%s, X_OK) failed: %s\n" +msgstr "`%s' schlug fehl: %s\n" + +#: src/util/os_installation.c:507 +#, fuzzy, c-format +msgid "stat (%s) failed: %s\n" +msgstr "`%s' schlug fehl: %s\n" + +#: src/util/os_priority.c:304 +#, fuzzy, c-format +msgid "Failed to open named pipe `%s' for reading: %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/util/os_priority.c:305 +#, fuzzy, c-format +msgid "Failed to open named pipe `%s' for writing: %s\n" +msgstr "Datei wurde als `%s' gespeichert.\n" + +#: src/util/plugin.c:89 +#, c-format +msgid "Initialization of plugin mechanism failed: %s!\n" +msgstr "Initialisierung des Plugin Mechanismuses fehlgeschlagen: %s!\n" + +#: src/util/plugin.c:146 +#, fuzzy, c-format +msgid "`%s' failed to resolve method '%s' with error: %s\n" +msgstr "" +"`%s' konnte die Methode '%s%s' nicht auflösen. Ort: %s:%d. Fehler: %s\n" + +#: src/util/plugin.c:219 +#, fuzzy, c-format +msgid "`%s' failed for library `%s' with error: %s\n" +msgstr "`%s' fehlgeschlagen für die Bibliothek `%s'. Ort: %s:%d. Fehler: %s\n" + +#: src/util/plugin.c:349 +#, fuzzy +msgid "Could not determine plugin installation path.\n" +msgstr "Öffentliche IP-Adresse konnte nicht ermittelt werden.\n" + +#: src/util/pseudonym.c:273 +#, fuzzy, c-format +msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" +msgstr "Fehler beim Parsen der Gerätedaten von `%s' bei %s:%d.\n" + +#: src/util/pseudonym.c:338 +#, fuzzy +msgid "no-name" +msgstr "Name anzeigen" + +#: src/util/resolver_api.c:202 +#, fuzzy, c-format +msgid "Must specify `%s' for `%s' in configuration!\n" +msgstr "Versuche, Datei `%s' für MySQL Konfiguration zu verwenden.\n" + +#: src/util/resolver_api.c:221 +#, fuzzy, c-format +msgid "" +"Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" +msgstr "" +"Sie müssen für `%s' in der Sektion `%s' der Konfigurationsdatei eine " +"positive Zahl angeben.\n" + +#: src/util/resolver_api.c:351 +#, fuzzy, c-format +msgid "Timeout trying to resolve IP address `%s'.\n" +msgstr "GNUnet verwendet nun die IP-Adresse %u.%u.%u.%u.\n" + +#: src/util/resolver_api.c:355 +#, fuzzy, c-format +msgid "Timeout trying to resolve hostname `%s'.\n" +msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#: src/util/resolver_api.c:426 +#, c-format +msgid "Resolver returns `%s' for IP `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:807 +#, c-format +msgid "Resolver returns `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:901 +#, c-format +msgid "Resolving our FQDN `%s'\n" +msgstr "" + +#: src/util/resolver_api.c:906 +#, fuzzy, c-format +msgid "Could not resolve our FQDN : %s\n" +msgstr "`%s' konnte nicht aufgelöst werden: %s\n" + +#: src/util/resolver_api.c:938 +#, c-format +msgid "Resolving our hostname `%s'\n" +msgstr "" + +#: src/util/scheduler.c:866 +msgid "Looks like we're busy waiting...\n" +msgstr "" + +#: src/util/scheduler.c:996 +#, c-format +msgid "Attempt to cancel dead task %llu!\n" +msgstr "" + +#: src/util/server.c:397 +#, fuzzy, c-format +msgid "`%s' failed for port %d (%s).\n" +msgstr "`%s' fehlgeschlagen für Laufwerk %s: %u\n" + +#: src/util/server.c:406 +#, fuzzy, c-format +msgid "`%s' failed for port %d (%s): address already in use\n" +msgstr "`%s' schlug fehl für Port %d: %s. Läuft gnunetd bereits?\n" + +#: src/util/server.c:411 +#, fuzzy, c-format +msgid "`%s' failed for `%s': address already in use\n" +msgstr "`%s' schlug fehl für Port %d: %s. Läuft gnunetd bereits?\n" + +#: src/util/server.c:640 +#, c-format +msgid "" +"Processing code for message of type %u did not call " +"GNUNET_SERVER_receive_done after %llums\n" +msgstr "" + +#: src/util/service.c:117 src/util/service.c:143 src/util/service.c:186 +#: src/util/service.c:207 src/util/service.c:214 +#, c-format +msgid "Invalid format for IP: `%s'\n" +msgstr "Ungültiges Format für IP: `%s'\n" + +#: src/util/service.c:170 +#, c-format +msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." +msgstr "Ungültige Netzwerk Notation ('/%d ist nicht gültig in IPv4 CIDR)." + +#: src/util/service.c:263 +#, c-format +msgid "Invalid network notation (does not end with ';': `%s')\n" +msgstr "Ungültige Netzwerk Notation (endet nicht mit ';': `%s')\n" + +#: src/util/service.c:296 +#, fuzzy, c-format +msgid "Wrong format `%s' for netmask\n" +msgstr "Falsches Format `%s' für Netzmaske: %s\n" + +#: src/util/service.c:326 +#, fuzzy, c-format +msgid "Wrong format `%s' for network\n" +msgstr "Falsches Format `%s' für Netzwerk: %s\n" + +#: src/util/service.c:668 +#, c-format +msgid "Access denied to UID %d / GID %d\n" +msgstr "" + +#: src/util/service.c:673 +#, fuzzy, c-format +msgid "Unknown address family %d\n" +msgstr "Unbekannte Operation `%s'\n" + +#: src/util/service.c:680 +#, c-format +msgid "Access from `%s' denied to service `%s'\n" +msgstr "" + +#: src/util/service.c:724 +#, c-format +msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:752 +#, c-format +msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:869 +#, c-format +msgid "" +"Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" +msgstr "" + +#: src/util/service.c:939 +#, c-format +msgid "" +"Disabling UNIX domain socket support for service `%s', failed to create UNIX " +"domain socket: %s\n" +msgstr "" + +#: src/util/service.c:956 +#, c-format +msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" +msgstr "" + +#: src/util/service.c:1191 +msgid "Could not access a pre-bound socket, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1242 src/util/service.c:1260 +#, c-format +msgid "Specified value for `%s' of service `%s' is invalid\n" +msgstr "" + +#: src/util/service.c:1287 +#, c-format +msgid "Could not access pre-bound socket %u, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1442 +#, fuzzy, c-format +msgid "Failed to start `%s' at `%s'\n" +msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#: src/util/service.c:1475 +#, fuzzy, c-format +msgid "Service `%s' runs at %s\n" +msgstr "Knoten `%s' mit Vertrauen %8u und Adresse `%s'\n" + +#: src/util/service.c:1521 +msgid "Service process failed to initialize\n" +msgstr "" + +#: src/util/service.c:1525 +msgid "Service process could not initialize server function\n" +msgstr "" + +#: src/util/service.c:1529 +msgid "Service process failed to report status\n" +msgstr "" + +#: src/util/service.c:1581 +msgid "No such user" +msgstr "" + +#: src/util/service.c:1594 +#, c-format +msgid "Cannot change user/group to `%s': %s\n" +msgstr "Benutzer/Gruppe kann nicht zu `%s' gewechselt werden: %s\n" + +#: src/util/service.c:1657 +msgid "do daemonize (detach from terminal)" +msgstr "" + +#: src/util/signal.c:80 +#, fuzzy, c-format +msgid "signal (%d, %p) returned %d.\n" +msgstr "Aufruf von `%s' gibt %d zurück.\n" + +#: src/util/strings.c:143 +msgid "b" +msgstr "b" + +#: src/util/strings.c:354 +#, c-format +msgid "Character sets requested were `%s'->`%s'\n" +msgstr "" + +#: src/util/strings.c:462 +msgid "Failed to expand `$HOME': environment variable `HOME' not set" +msgstr "" + +#: src/util/strings.c:554 +msgid "ms" +msgstr "ms" + +#: src/util/strings.c:559 +msgid "eternity" +msgstr "" + +#: src/util/strings.c:563 +msgid "s" +msgstr "s" + +#: src/util/strings.c:567 +msgid "m" +msgstr "m" + +#: src/util/strings.c:571 +msgid "h" +msgstr "h" + +#: src/util/strings.c:575 +msgid " days" +msgstr " Tage" + +#: src/util/strings.c:599 +msgid "end of time" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1065 +#, fuzzy +msgid "# Active tunnels" +msgstr "GNUnet Konfiguration" + +#: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 +#, fuzzy +msgid "# Peers connected to mesh tunnels" +msgstr "# verbundener Knoten" + +#: src/vpn/gnunet-service-vpn.c:699 +#, fuzzy +msgid "# Bytes given to mesh for transmission" +msgstr "# PING Nachrichten erstellt" + +#: src/vpn/gnunet-service-vpn.c:737 +#, fuzzy +msgid "# Bytes dropped in mesh queue (overflow)" +msgstr "# Bytes verworfen von UDP (outgoing)" + +#: src/vpn/gnunet-service-vpn.c:772 +#, fuzzy +msgid "# Mesh tunnels created" +msgstr "# dht Anfragen weitergeleitet" + +#: src/vpn/gnunet-service-vpn.c:795 +#, fuzzy +msgid "Failed to setup mesh tunnel!\n" +msgstr "Statistiken über den Netzwerkverkehr konnten nicht ermittelt werden.\n" + +#: src/vpn/gnunet-service-vpn.c:967 +#, c-format +msgid "Protocol %u not supported, dropping\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1285 +msgid "# ICMPv4 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1306 +msgid "# ICMPv6 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1511 +#, fuzzy +msgid "# Packets received from TUN interface" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/vpn/gnunet-service-vpn.c:1549 src/vpn/gnunet-service-vpn.c:1590 +#, c-format +msgid "Packet received for unmapped destination `%s' (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1600 +msgid "Received IPv4 packet with options (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1614 +#, c-format +msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1697 +#, fuzzy +msgid "# ICMP packets received from mesh" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/vpn/gnunet-service-vpn.c:2038 +#, fuzzy +msgid "# UDP packets received from mesh" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/vpn/gnunet-service-vpn.c:2196 +#, fuzzy +msgid "# TCP packets received from mesh" +msgstr "Empfangene Client-Nachricht ist ungültig.\n" + +#: src/vpn/gnunet-service-vpn.c:2347 +msgid "Failed to find unallocated IPv4 address in VPN's range\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2402 +#, fuzzy +msgid "Failed to find unallocated IPv6 address in VPN's range\n" +msgstr "Die öffentliche IPv6-Adresse konnte nicht ermittelt werden!\n" + +#: src/vpn/gnunet-service-vpn.c:2441 src/vpn/gnunet-service-vpn.c:2624 +#, fuzzy +msgid "# Active destinations" +msgstr "GNUnet Konfiguration" + +#: src/vpn/gnunet-service-vpn.c:2726 +msgid "Failed to allocate IP address for new destination\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3133 +msgid "IPv6 support disabled as this system does not support IPv6\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3165 +msgid "IPv4 support disabled as this system does not support IPv4\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:151 +#, fuzzy +msgid "Error creating tunnel\n" +msgstr "Hostkey wurde erfolgreich erzeugt.\n" + +#: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 +#, fuzzy, c-format +msgid "Option `%s' makes no sense with option `%s'.\n" +msgstr "Option `%s' macht keinen Sinn ohne die Option `%s'.\n" + +#: src/vpn/gnunet-vpn.c:208 +#, fuzzy, c-format +msgid "Option `%s' or `%s' is required.\n" +msgstr "%s: Option `%s' ist mehrdeutig\n" + +#: src/vpn/gnunet-vpn.c:220 +#, fuzzy, c-format +msgid "Option `%s' or `%s' is required when using option `%s'.\n" +msgstr "Option `%s' macht keinen Sinn ohne die Option `%s'.\n" + +#: src/vpn/gnunet-vpn.c:238 +#, fuzzy, c-format +msgid "`%s' is not a valid peer identifier.\n" +msgstr "`%s' ist nicht verfügbar." + +#: src/vpn/gnunet-vpn.c:260 +#, fuzzy, c-format +msgid "`%s' is not a valid IP address.\n" +msgstr "`%s' ist nicht verfügbar." + +#: src/vpn/gnunet-vpn.c:296 +msgid "request that result should be an IPv4 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:299 +msgid "request that result should be an IPv6 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:302 +msgid "print IP address only after mesh tunnel has been created" +msgstr "" + +#: src/vpn/gnunet-vpn.c:305 +msgid "how long should the mapping be valid for new tunnels?" +msgstr "" + +#: src/vpn/gnunet-vpn.c:308 +msgid "destination IP for the tunnel" +msgstr "" + +#: src/vpn/gnunet-vpn.c:311 +msgid "peer offering the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:314 +msgid "name of the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:317 +#, fuzzy +msgid "service is offered via TCP" +msgstr "# Bytes empfangen über TCP" + +#: src/vpn/gnunet-vpn.c:320 +#, fuzzy +msgid "service is offered via UDP" +msgstr "# Bytes empfangen über UDP" + +#: src/vpn/gnunet-vpn.c:329 +msgid "Setup tunnels via VPN." +msgstr "" + +#: src/include/gnunet_common.h:479 src/include/gnunet_common.h:484 +#: src/include/gnunet_common.h:490 +#, fuzzy, c-format +msgid "Assertion failed at %s:%d.\n" +msgstr "Absicherung fehlgeschlagen bei %s:%d.\n" + +#: src/include/gnunet_common.h:500 +#, fuzzy, c-format +msgid "External protocol violation detected at %s:%d.\n" +msgstr "Absicherung fehlgeschlagen bei %s:%d.\n" + +#: src/include/gnunet_common.h:521 src/include/gnunet_common.h:528 +#, fuzzy, c-format +msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" +msgstr "`%s' schlug bei Datei `%s' fehl. Ort: %s:%d. Fehler: %s\n" + +#, fuzzy +#~ msgid "Failed to send to `%s': %s\n" +#~ msgstr "Datei wurde als `%s' gespeichert.\n" + +#, fuzzy +#~ msgid "Could not access file: %s\n" +#~ msgstr "`%s' konnte nicht aufgelöst werden: %s\n" + +#, fuzzy +#~ msgid "`%s' failed on file `%s': %s" +#~ msgstr "`%s' fehlgeschlagen für Laufwerk %s: %u\n" + +#, fuzzy +#~ msgid "# bytes TCP was asked to transmit" +#~ msgstr "# Bytes des Typs %d übertragen" + +#, fuzzy +#~ msgid "# bytes discarded by TCP (failed to connect)" +#~ msgstr "# Bytes verworfen von TCP (ausgehend)" + +#, fuzzy +#~ msgid "# wlan messages queued" +#~ msgstr "# verschlüsselter PING Nachrichten empfangen" + +#~ msgid "print this help" +#~ msgstr "Gibt diese Hilfe aus" + +#~ msgid "print the version number" +#~ msgstr "Versionsnummer ausgeben" + +#~ msgid "be verbose" +#~ msgstr "umfangreiche Meldungen ausgeben" + +#~ msgid "use configuration file FILENAME" +#~ msgstr "Konfigurationsdatei FILENAME verwenden" + +#, fuzzy +#~ msgid "Failed to stop service `%s'!\n" +#~ msgstr "Fehler beim Binden an UDP Port %d.\n" + +#, fuzzy +#~ msgid "Failed to start service `%s'!\n" +#~ msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" + +#, fuzzy +#~ msgid "Service `%s' is not running.\n" +#~ msgstr "`%s' ist keine Datei.\n" + +#, fuzzy +#~ msgid "Binary implementing service `%s' not known!\n" +#~ msgstr "" +#~ "Signatur kann nicht verifiziert werden, der Knoten `%s' ist uns nicht " +#~ "bekannt!\n" + +#, fuzzy +#~ msgid "Service `%s' stopped\n" +#~ msgstr "Dienst gelöscht.\n" + +#, fuzzy +#~ msgid "Unable to start service `%s': %s\n" +#~ msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" + +#, fuzzy +#~ msgid "Unable to accept connection for service `%s': %s\n" +#~ msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" + +#, fuzzy +#~ msgid "Service `%s' started\n" +#~ msgstr "Dienst gelöscht.\n" + +#, fuzzy +#~ msgid "Peer `%s' plugin: `%s' address `%s'\n" +#~ msgstr "Knoten `%s' mit Vertrauen %8u und Adresse `%s'\n" + +#, fuzzy +#~ msgid "Failed to transmit request to DATASTORE.\n" +#~ msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" + +#, fuzzy +#~ msgid "Failed to create IPv4 broadcast socket on port %d\n" +#~ msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" + +#, fuzzy +#~ msgid "Failed to load block plugin `%s'\n" +#~ msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" + +#, fuzzy +#~ msgid "Could not resolve our FQDN : %s %u\n" +#~ msgstr "`%s' konnte nicht aufgelöst werden: %s\n" + +#, fuzzy +#~ msgid "Failed to load dhtlog plugin for `%s'\n" +#~ msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#, fuzzy +#~ msgid "Failed to get full path for `%s'\n" +#~ msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" + +#, fuzzy +#~ msgid "Failed to create file for dhtlog.\n" +#~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#, fuzzy +#~ msgid "Found peer `%s'\n" +#~ msgstr "Ich bin Peer `%s'.\n" + +#, fuzzy +#~ msgid "Failed to initialize MySQL database connection for dhtlog.\n" +#~ msgstr "SQLite Datenbank konnte nicht initialisiert werden.\n" + +#, fuzzy +#~ msgid "Loading udp transport plugin\n" +#~ msgstr "Teste Transport(e) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for udp\n" +#~ msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" + +#, fuzzy +#~ msgid "# SET QUOTA messages received" +#~ msgstr "# verschlüsselter PONG Nachrichten empfangen" + +#, fuzzy +#~ msgid "curl failed for `%s' at %s:%d: `%s'\n" +#~ msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" + +#, fuzzy +#~ msgid "Phase 3: sending messages\n" +#~ msgstr "Zustellung der Nachricht `%s' fehlgeschlagen.\n" + +#, fuzzy +#~ msgid "Loading HTTPS transport plugin `%s'\n" +#~ msgstr "Teste Transport(e) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for https\n" +#~ msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" + +#, fuzzy +#~ msgid "Fail! Could not connect peers\n" +#~ msgstr "`%s': Verbindung konnte nicht hergestellt werden.\n" + +#, fuzzy +#~ msgid "Loading tcp transport plugin\n" +#~ msgstr "Teste Transport(e) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for tcp\n" +#~ msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" + +#, fuzzy +#~ msgid "# HTTP peers active" +#~ msgstr "# Bytes empfangen über TCP" + +#, fuzzy +#~ msgid "Connection: %X: %s failed at %s:%d: `%s'\n" +#~ msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" + +#, fuzzy +#~ msgid "Misconfigured address to bind to in configuration!\n" +#~ msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" + +#, fuzzy +#~ msgid "Required configuration options missing in section `%s'\n" +#~ msgstr "" +#~ "Es muss eine Liste von Freunden in der Konfigurationsdatei unter `%s' in " +#~ "der Sektion `%s' angegeben werden.\n" + +#, fuzzy +#~ msgid "Loading HTTP transport plugin `%s'\n" +#~ msgstr "Teste Transport(e) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for http\n" +#~ msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" + +#, fuzzy +#~ msgid "# PING messages decrypted" +#~ msgstr "# PING Nachrichten erstellt" + +#, fuzzy +#~ msgid "Failed to connect to core service\n" +#~ msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#, fuzzy +#~ msgid "# bytes successfully transmitted by plugins" +#~ msgstr "# Bytes des Typs %d übertragen" + +#, fuzzy +#~ msgid "# connected addresses" +#~ msgstr "# verbundener Knoten" + +#, fuzzy +#~ msgid "# transport failed to selected peer address" +#~ msgstr "Transport %d wird ausgewählten anderen Knoten bekannt gegeben.\n" + +#, fuzzy +#~ msgid "# peer addresses considered valid" +#~ msgstr "# Knotenankündigungen empfangen" + +#, fuzzy +#~ msgid "# PING with HELLO messages sent" +#~ msgstr "# PING Nachrichten erstellt" + +#, fuzzy +#~ msgid "# HELLOs received for validation" +#~ msgstr "# Blöcke migriert" + +#, fuzzy +#~ msgid "Received `%s' message from `%s' destined for `%s' which is not me!\n" +#~ msgstr "Empfangener PING ist nicht an uns gerichtet!\n" + +#, fuzzy +#~ msgid "Could not send PONG to `%s': no address available\n" +#~ msgstr "Knoten `%s' konnte nicht in der Routing Tabelle gefunden werden!\n" + +#, fuzzy +#~ msgid "# HELLO messages received from other peers" +#~ msgstr "Ungültige `%s' Nachricht von Knoten `%s' empfangen.\n" + +#~ msgid "Error" +#~ msgstr "Fehler" + +#~ msgid "Help" +#~ msgstr "Hilfe" + +#, fuzzy +#~ msgid "Error!" +#~ msgstr "Fehler" + +#~ msgid "No" +#~ msgstr "Nein" + +#~ msgid "Yes" +#~ msgstr "Ja" + +#, fuzzy +#~ msgid "Abort" +#~ msgstr "_über" + +#, fuzzy +#~ msgid "Ok" +#~ msgstr "k" + +#~ msgid "GNUnet configuration" +#~ msgstr "GNUnet Konfiguration" + +#~ msgid "" +#~ "Welcome to GNUnet!\n" +#~ "\n" +#~ "This assistant will ask you a few basic questions in order to configure " +#~ "GNUnet.\n" +#~ "\n" +#~ "Please visit our homepage at\n" +#~ "\thttp://gnunet.org/\n" +#~ "and join our community at\n" +#~ "\thttp://gnunet.org/drupal/\n" +#~ "\n" +#~ "Have a lot of fun,\n" +#~ "\n" +#~ "the GNUnet team" +#~ msgstr "" +#~ "Willkommen bei GNUnet!\n" +#~ "\n" +#~ "Dieser Assistent wird Ihnen einige grundlegende Fragen stellen, um GNUnet " +#~ "zu konfigurieren.\n" +#~ "\n" +#~ "Bitte besuchen Sie unsere Homepage\n" +#~ "\thttp://gnunet.org\n" +#~ "und schließen Sie sich unserer Community an:\n" +#~ "\thttps://gnunet.org/drupal/\n" +#~ "\n" +#~ "Viel Spaß,\n" +#~ "\n" +#~ "das GNUnet-Team" + +#~ msgid "" +#~ "Choose the network interface that connects your computer to the internet " +#~ "from the list below." +#~ msgstr "" +#~ "Wählen Sie das Netzwerkgerät, das Ihren Computer mit dem Internet " +#~ "verbindet, aus unten stehender Liste." + +#~ msgid "" +#~ "The \"Network interface\" is the device that connects your computer to " +#~ "the internet. This is usually a modem, an ISDN card or a network card in " +#~ "case you are using DSL." +#~ msgstr "" +#~ "Das \"Netzwerkgerät\" ist das Gerät, das Ihren Computer mit dem Internet " +#~ "verbindet. Dies ist üblicherweise ein Modem, eine ISDN-Karte oder eine " +#~ "Netzwerkkarte falls Sie DSL nutzen." + +#, fuzzy +#~ msgid "Network configuration: interface" +#~ msgstr "Netzwerkgerät:" + +#~ msgid "" +#~ "What is the name of the network interface that connects your computer to " +#~ "the Internet?" +#~ msgstr "" +#~ "Was ist der Name des Netzwerkgerätes, das Ihren Computer mit dem Internet " +#~ "verbindet?" + +#, fuzzy +#~ msgid "Network configuration: IP" +#~ msgstr "GNUnet Konfiguration" + +#, fuzzy +#~ msgid "What is this computer's public IP address or hostname?" +#~ msgstr "" +#~ "Wie heißt die öffentliche IP-Adresse oder der öffentliche Name dieses " +#~ "Computers?\n" +#~ "Wenn Sie nicht sicher sind, lassen Sie dieses Feld leer." + +#, fuzzy +#~ msgid "" +#~ "If your provider always assigns the same IP-Address to you (a \"static\" " +#~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " +#~ "changes every now and then (\"dynamic\" IP-Address) but there's a " +#~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " +#~ "you can also enter it here.\n" +#~ "If left empty, GNUnet will try to automatically detect the IP.\n" +#~ "You can specify a hostname, GNUnet will then use DNS to resolve it.\n" +#~ "If in doubt, leave this empty." +#~ msgstr "" +#~ "Wenn Ihr Provider Ihnen immer die gleiche IP-Adresse zuweist (eine " +#~ "\"statische\" IP-Adresse), so geben Sie diese in das \"IP-Adresse\"-Feld " +#~ "ein. Wenn sich Ihre IP-Adresse immer wieder ändert (\"dynamische\" IP-" +#~ "Adresse), es jedoch einen Rechnernamen gibt, der immer auf Ihre aktuelle " +#~ "IP-Adresse verweist, so können Sie diesen ebenfalls eintragen.\n" +#~ "Wenn Sie nicht sicher sind, so können Sie das Feld leer lassen. GNUnet " +#~ "wird dann versuchen, Ihre IP-Adresse automatisch zu bestimmen." + +#, fuzzy +#~ msgid "Bandwidth configuration: upload" +#~ msgstr "GNUnet Konfiguration" + +#, fuzzy +#~ msgid "How much upstream bandwidth (in bytes/s) may be used?" +#~ msgstr "Wieviel Upstream (Bytes/s) darf verwendet werden?" + +#, fuzzy +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "The \"upstream\" is the data channel through which data is *sent* to the " +#~ "internet. The limit is the maximum amount which GNUnet is allowed to use. " +#~ "If you have a flatrate, you can set it to the maximum speed of your " +#~ "internet connection. You should not use a value that is higher than what " +#~ "your actual connection allows." +#~ msgstr "" +#~ "Hier können Sie GNUnets Ressourcenverwendung einschränken.\n" +#~ "\n" +#~ "Der \"Upstream\" ist der Datenkanal, durch den Daten an das Internet " +#~ "*gesendet* werden. Das Limit ist entweder das gesamte Maximum für diesem " +#~ "Computer oder wieviel GNUnet selbst verwenden darf. Dies können Sie " +#~ "später festlegen. Wenn Sie eine Flatrate haben, können Sie die maximale " +#~ "Geschwindigkeit Ihrer Internetverbindung angeben." + +#, fuzzy +#~ msgid "Bandwidth configuration: download" +#~ msgstr "GNUnet Konfiguration" + +#, fuzzy +#~ msgid "How much downstream bandwidth (in bytes/s) may be used?" +#~ msgstr "Wieviel Downstream (Bytes/s) darf verwendet werden?" + +#, fuzzy +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "The \"downstream\" is the data channel through which data is *received* " +#~ "from the internet. The limit is the maximum amount which GNUnet is " +#~ "allowed to use. If you have a flatrate, you can set it to the maximum " +#~ "speed of your internet connection. You should not use a value that is " +#~ "higher than what your actual connection allows." +#~ msgstr "" +#~ "Hier können Sie GNUnets Ressourcenverwendung einschränken.\n" +#~ "\n" +#~ "Der \"Downstream\" ist der Datenkanal, durch den Daten vom Internet " +#~ "*empfangen* werden. Das Limit ist entweder das gesamte Maximum für diesem " +#~ "Computer oder wieviel GNUnet selbst verwenden darf. Dies können Sie " +#~ "später festlegen. Wenn Sie eine Flatrate haben, können Sie die maximale " +#~ "Geschwindigkeit Ihrer Internetverbindung angeben." + +#, fuzzy +#~ msgid "Quota configuration" +#~ msgstr "GNUnet Konfiguration" + +#, fuzzy +#~ msgid "" +#~ "The GNUnet datastore contains all content that GNUnet needs to store " +#~ "(indexed, inserted and migrated content)." +#~ msgstr "" +#~ "Was ist die maximale Größe des GNUnet Datenspeichers (in MB)?\n" +#~ "Der GNUnet Datenspeicher enthält alle Daten, die GNUnet erzeugt " +#~ "(Indexdaten, eingefügte und migrierte Inhalte)." + +#, fuzzy +#~ msgid "Daemon configuration: user account" +#~ msgstr "Fehler beim Anlegen des Benutzerkontos:" + +#, fuzzy +#~ msgid "" +#~ "For security reasons, it is a good idea to let this setup create a new " +#~ "user account under which the GNUnet service is started at system " +#~ "startup.\n" +#~ "\n" +#~ "However, GNUnet may not be able to access files other than its own. This " +#~ "includes files you want to publish in GNUnet. You'll have to grant read " +#~ "permissions to the user specified below.\n" +#~ "\n" +#~ "Leave the field empty to run GNUnet with system privileges.\n" +#~ msgstr "" +#~ "Geben Sie den Benutzer an, dem der GNUnet Dienst gehören soll.\n" +#~ "\n" +#~ "Aus Sicherheitsgründen ist es eine gute Idee, dieses Setup ein neues " +#~ "Benutzerkonto anlegen zu lassen, unter dem der GNUnet Dienst beim " +#~ "Systemstart läuft.\n" +#~ "\n" +#~ "Natürlich kann GNUnet dann nur auf seine eigenen Dateien zugreifen. Dies " +#~ "betrifft auch Dateien, die Sie im GNUnet veröffentlichen möchten. Sie " +#~ "müssen dann dem unten angegebenen Benutzerkonto zuerst Leseberechtigungen " +#~ "geben.\n" +#~ "\n" +#~ "Lassen Sie dieses Feld leer, wenn Sie GNUnet mit Systemprivilegien laufen " +#~ "lassen möchten.\n" +#~ "\n" +#~ "GNUnet Benutzer:" + +#, fuzzy +#~ msgid "" +#~ "For security reasons, it is a good idea to let this setup create a new " +#~ "group for the chosen user account.\n" +#~ "\n" +#~ "You can also specify a already existent group here.\n" +#~ "\n" +#~ "Only members of this group will be allowed to start and stop the the " +#~ "GNUnet server and have access to GNUnet server data.\n" +#~ msgstr "" +#~ "Definieren Sie eine Gruppe, der der GNUnet Dienst gehört.\n" +#~ "\n" +#~ "Aus Sicherheitsgründen ist es eine gute Idee, dieses Setup eine neue " +#~ "Gruppe für das gewählte Benutzerkonto anlegen zu lassen.\n" +#~ "\n" +#~ "Sie können hier auch eine bestehende Gruppe angeben.\n" +#~ "\n" +#~ "Nur Mitglieder dieser Gruppe dürfen den GNUnet Server starten und " +#~ "anhalten und haben Zugriff auf die Daten des GNUnet Servers.\n" +#~ "\n" +#~ "GNUnet Gruppe:" + +#, fuzzy +#~ msgid "" +#~ "If you say \"yes\" here, the GNUnet background process will be " +#~ "automatically started when you turn on your computer. If you say \"no\" " +#~ "here, you have to launch GNUnet yourself each time you want to use it." +#~ msgstr "" +#~ "Möchten Sie GNUnet als Systemdienst starten?\n" +#~ "\n" +#~ "Wenn Sie hier \"Ja\" sagen, so wird der GNUnet Hintergrundprozess " +#~ "jedesmal automatisch gestartet, wenn Sie Ihren Computer einschalten. Wenn " +#~ "Sie hier \"Nein\" sagen, so müssen Sie GNUnet jedesmal selbst starten, " +#~ "wenn Sie es verwenden möchten." + +#, fuzzy +#~ msgid "Unable to create user account for daemon." +#~ msgstr "Fehler beim Anlegen des Benutzerkontos:" + +#, fuzzy +#~ msgid "Save configuration?" +#~ msgstr "GNUnet Konfiguration" + +#, fuzzy +#~ msgid "GNUnet Configuration" +#~ msgstr "GNUnet Konfiguration" + +#~ msgid "Back" +#~ msgstr "Zurück" + +#~ msgid "Up" +#~ msgstr "Oben" + +#~ msgid "Cancel" +#~ msgstr "Abbrechen" + +#, fuzzy +#~ msgid "Configuration unchanged, no need to save.\n" +#~ msgstr "" +#~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " +#~ "ausführen!\n" + +#, fuzzy +#~ msgid "Do you wish to save your new configuration?" +#~ msgstr "Möchten Sie Ihre Einstellungen speichern?" + +#, fuzzy +#~ msgid "" +#~ "\n" +#~ "Your configuration changes were NOT saved.\n" +#~ msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" + +#~ msgid "GNUnet service installed successfully.\n" +#~ msgstr "Der GNUnet Dienst wurde erfolgreich installiert.\n" + +#~ msgid "This version of Windows doesn't support services.\n" +#~ msgstr "Diese Version von Windows unterstützt keine Dienste.\n" + +#~ msgid "Error: can't open Service Control Manager: %s\n" +#~ msgstr "Fehler: der Dienstemanager konnte nicht geöffnet werden: %s\n" + +#~ msgid "Error: can't create service: %s\n" +#~ msgstr "Fehler: Dienst konnte nicht angelegt werden: %s\n" + +#~ msgid "Error: can't access service: %s\n" +#~ msgstr "Fehler: auf den Dienst konnte nicht zugegriffen werden: %s\n" + +#~ msgid "Error: can't delete service: %s\n" +#~ msgstr "Fehler: Dienst konnte nicht gelöscht werden: %s\n" + +#, fuzzy +#~ msgid "Configuration changed. Save?" +#~ msgstr "" +#~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " +#~ "ausführen!\n" + +#, fuzzy +#~ msgid "Error saving configuration." +#~ msgstr "Fehler beim Speichern der Konfiguration!" + +#, fuzzy +#~ msgid "(unknown connection)" +#~ msgstr "Netzwerkverbindung" + +#, fuzzy +#~ msgid "Do you want to save the new configuration?" +#~ msgstr "Möchten Sie Ihre Einstellungen speichern?" + +#~ msgid "Unable to change startup process:" +#~ msgstr "Startprozeß konnte nicht geändert werden:" + +#~ msgid "generate configuration for gnunetd, the GNUnet daemon" +#~ msgstr "Generiere Konfiguration für gnunetd, den GNUnet Daemon" + +#~ msgid "Tool to setup GNUnet." +#~ msgstr "Werkzeug für die Einrichtung von GNUnet." + +#, fuzzy +#~ msgid "Too many arguments.\n" +#~ msgstr "Ungültige Kommandozeilen Parameter.\n" + +#, fuzzy +#~ msgid "No interface specified, using default.\n" +#~ msgstr "Keine Oberfläche angegeben, verwende Standard\n" + +#, fuzzy +#~ msgid "Configuration file `%s' must be a filename (but is a directory).\n" +#~ msgstr "" +#~ "Konfigurationsdatei `%s' nicht gefunden. Bitte führen Sie gnunet-setup " +#~ "aus!\n" + +#, fuzzy +#~ msgid "Undefined option.\n" +#~ msgstr "Weitere Einstellungen" + +#, fuzzy +#~ msgid "Unknown operation '%s'.\n" +#~ msgstr "Unbekannte Operation `%s'\n" + +#, fuzzy +#~ msgid "yes" +#~ msgstr "Ja" + +#, fuzzy +#~ msgid "Yes\n" +#~ msgstr "Ja" + +#, fuzzy +#~ msgid "No\n" +#~ msgstr "Nein" + +#, fuzzy +#~ msgid "Help\n" +#~ msgstr "Hilfe" + +#, fuzzy +#~ msgid "Abort\n" +#~ msgstr "_über" + +#, fuzzy +#~ msgid "Configuration was unchanged, no need to save.\n" +#~ msgstr "" +#~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " +#~ "ausführen!\n" + +#~ msgid "Can't open Service Control Manager" +#~ msgstr "Der Dienstemanager konnte nicht geöffnet werden" + +#~ msgid "Can't create service" +#~ msgstr "Der Dienst konnte nicht angelegt werden" + +#~ msgid "Error changing the permissions of the GNUnet directory" +#~ msgstr "Fehler beim Ändern der Berechtigungen des GNUnet Verzeichnisses" + +#, fuzzy +#~ msgid "Cannot write to the registry" +#~ msgstr "Konnte nicht in die Registry schreiben" + +#~ msgid "Can't delete the service" +#~ msgstr "Dienst konnte nicht gelöscht werden" + +#~ msgid "This version of Windows does not support multiple users." +#~ msgstr "Diese Version von Windows ist nicht Mehrbenutzerfähig." + +#~ msgid "Error accessing local security policy" +#~ msgstr "Fehler beim Zugriff auf die lokale Sicherheitsrichtlinie" + +#~ msgid "Error granting service right to user" +#~ msgstr "Fehler beim Zuweisen des Dienstrechtes dem Benutzer" + +#~ msgid "Unknown error while creating a new user" +#~ msgstr "Unbekannter Fehler beim Anlegen des neuen Benutzers" + +#, fuzzy +#~ msgid "" +#~ "Configuration does not satisfy constraints of configuration specification " +#~ "file `%s'!\n" +#~ msgstr "" +#~ "Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein " +#~ "Verzeichnis für FS Daten angeben.\n" + +#~ msgid "FATAL" +#~ msgstr "SCHWERWIEGEND" + +#~ msgid "NOTHING" +#~ msgstr "NICHTS" + +#, fuzzy +#~ msgid "Syntax error in configuration entry HOST in section NETWORK: `%s'\n" +#~ msgstr "Syntaxfehler in Konfigurationsdatei `%s' in Zeile %d.\n" + +#, fuzzy +#~ msgid "Error connecting to %s:%u. Is the daemon running?\n" +#~ msgstr "Verbindung zu %u.%u.%u.%u:%u fehlgeschlagen: %s\n" + +#, fuzzy +#~ msgid "Cannot connect to %s:%u: %s\n" +#~ msgstr "Verbindung zu %u.%u.%u.%u:%u fehlgeschlagen: %s\n" + +#, fuzzy +#~ msgid "Reading result from gnunetd failed, reply invalid!\n" +#~ msgstr "`%s' fehlgeschlagen, Antwort ist ungültig!\n" + +#, fuzzy +#~ msgid "No interface specified in section `%s' under `%s'!\n" +#~ msgstr "" +#~ "Es sind keine Netzwerkgeräte in der Konfigurationsdatei in der Sektion `" +#~ "%s' unter `%s' definiert!\n" + +#~ msgid "Could not obtain IP for interface `%s' using `%s'.\n" +#~ msgstr "" +#~ "Es konnte keine IP für das Gerät `%s' unter Verwendung von `%s' ermittelt " +#~ "werden.\n" + +#, fuzzy +#~ msgid "" +#~ "Could not find interface `%s' using `%s', trying to find another " +#~ "interface.\n" +#~ msgstr "" +#~ "Gerät `%s' konnte in `%s' nicht gefunden werden, es wird versucht, ein " +#~ "anderes Gerät zu finden.\n" + +#~ msgid "Could not find an IP address for interface `%s'.\n" +#~ msgstr "Es konnte keine IP-Adresse für das Gerät `%s' ermittelt werden.\n" + +#, fuzzy +#~ msgid "" +#~ "There is more than one IP address specified for interface `%s'.\n" +#~ "GNUnet will use %s.\n" +#~ msgstr "" +#~ "Es ist mehr als eine IP-Adresse für das Gerät `%s' angegeben.\n" +#~ "GNUnet wird %u.%u.%u.%u. verwenden.\n" + +#~ msgid "Could not resolve `%s' to determine our IP address: %s\n" +#~ msgstr "" +#~ "`%s' konnte nicht aufgelöst werden, um unsere IP-Adresse zu ermitteln: " +#~ "%s\n" + +#, fuzzy +#~ msgid "Received malformed message (too small) from connection. Closing.\n" +#~ msgstr "" +#~ "Es wurde per TCP von einem anderen Knoten eine ungültige Nachricht (Größe " +#~ "%u) empfangen. Verbindung wird geschlossen.\n" + +#, fuzzy +#~ msgid "`%s' returned with error code %u" +#~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#~ msgid "Can't create semaphore: %i" +#~ msgstr "Semaphore konnte nicht angelegt werden: %i" + +#~ msgid "Cannot query the CPU usage (Windows NT).\n" +#~ msgstr "CPU Nutzung kann nicht ermittelt werden (Windows NT).\n" + +#~ msgid "Cannot query the CPU usage (Win 9x)\n" +#~ msgstr "CPU Nutzung kann nicht ermittelt werden (Win 9x).\n" + +#~ msgid "" +#~ "No network interfaces defined in configuration section `%s' under `%s'!\n" +#~ msgstr "" +#~ "Es sind keine Netzwerkgeräte in der Konfigurationsdatei in der Sektion `" +#~ "%s' unter `%s' definiert!\n" + +#, fuzzy +#~ msgid "Command `%s' failed with error code %u\n" +#~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#, fuzzy +#~ msgid "Invalid process priority `%s'\n" +#~ msgstr "Ungültige Antwort auf `%s'.\n" + +#, fuzzy +#~ msgid "Real-time delay violation (%llu ms) at %s:%u\n" +#~ msgstr "Unerwartete sehr große Allokierung (%u Bytes) bei %s:%d!\n" + +#, fuzzy +#~ msgid "`%s' failed with error code %d: %s\n" +#~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#, fuzzy +#~ msgid "Invalid argument for `%s'.\n" +#~ msgstr "Ungültiger Parameter: `%s'\n" + +#, fuzzy +#~ msgid "Deadlock due to `%s'.\n" +#~ msgstr "Durch `%s' ist ein Deadlock bei %s:%d entstanden\n" + +#, fuzzy +#~ msgid "Lock acquired for too long (%llu ms) at %s:%u\n" +#~ msgstr "Unerwartete sehr große Allokierung (%u Bytes) bei %s:%d!\n" + +#, fuzzy +#~ msgid "GNUnet error log" +#~ msgstr "GNUnet Netzwerk Topologie tracen." + +#~ msgid "Availability test failed for `%s' at %s:%d.\n" +#~ msgstr "Verfügbarkeitstest für `%s' fehlgeschlagen bei %s:%d.\n" + +#, fuzzy +#~ msgid "Failed to load state service. Trying to do without.\n" +#~ msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" + +#, fuzzy +#~ msgid "Starting datastore conversion (this may take a while).\n" +#~ msgstr "Ein neuer Hostkey wird erzeugt (dies kann eine Weile dauern).\n" + +#, fuzzy +#~ msgid "Failed to load sqstore service. Check your configuration!\n" +#~ msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" + +#, fuzzy +#~ msgid "" +#~ "%s:%d - RPC %s:%p could not be registered: another callback is already " +#~ "using this name (%p)\n" +#~ msgstr "" +#~ "%s::%s - RPC %s:%p konnte nicht registriert werden: ein anderer Callback " +#~ "verwendet bereits diesen Namen (%p)\n" + +#, fuzzy +#~ msgid "%s:%d - async RPC %s:%p could not be unregistered: not found\n" +#~ msgstr "" +#~ "%s::%s - async RPC %s:%p konnte nicht unregistriert werden: nicht " +#~ "gefunden\n" + +#~ msgid "`%s' registering handlers %d %d %d\n" +#~ msgstr "`%s' registriert Handler %d %d %d\n" + +#~ msgid "Using %u messages of size %u for %u times.\n" +#~ msgstr "Verwende %u Nachrichten der Größe %u %umal.\n" + +#~ msgid "Times: max %16llu min %16llu mean %12.3f variance %12.3f\n" +#~ msgstr "Zeiten: Max %16llu Min %16llu Mittel %12.3f Varianz %12.3f\n" + +#~ msgid "Loss: max %16u min %16u mean %12.3f variance %12.3f\n" +#~ msgstr "Verloren: Max %16u Min %16u Mittel %12.3f Varianz %12.3f\n" + +#~ msgid "Running benchmark...\n" +#~ msgstr "Benchmark läuft...\n" + +#~ msgid "allows profiling of direct peer-to-peer connections" +#~ msgstr "Ermöglicht das Untersuchen direkter Peer-to-Peer Verbindungen" + +#~ msgid "Start GNUnet transport benchmarking tool." +#~ msgstr "GNUnet Transport Benchmarking Werkzeug starten." + +#~ msgid "output in gnuplot format" +#~ msgstr "Ausgabe im gnuplot Format" + +#~ msgid "number of iterations" +#~ msgstr "Anzahl an Durchläufen" + +#~ msgid "number of messages to use per iteration" +#~ msgstr "Anzahl an Nachrichten, die pro Durchlauf verwendet wird" + +#~ msgid "receiver host identifier (ENC file name)" +#~ msgstr "Bezeichner des Empfängerhosts (ENC Dateiname)" + +#~ msgid "message size" +#~ msgstr "Nachrichtengröße" + +#~ msgid "sleep for SPACE ms after each a message block" +#~ msgstr "Für SPACE ms nach jedem Nachrichtenblock pausieren" + +#~ msgid "number of messages in a message block" +#~ msgstr "Anzahl an Nachrichten in einem Nachrichtenblock" + +#~ msgid "Error establishing connection with gnunetd.\n" +#~ msgstr "Fehler beim Aufbauen einer Verbindung mit gnunetd.\n" + +#~ msgid "You must specify a receiver!\n" +#~ msgstr "Sie müssen einen Empfänger angeben!\n" + +#~ msgid "Invalid receiver peer ID specified (`%s' is not valid name).\n" +#~ msgstr "" +#~ "Ungültige Empfängerknoten ID angegeben (`%s' ist kein gültiger Name).\n" + +#~ msgid "Time:\n" +#~ msgstr "Zeit:\n" + +#~ msgid "\tmax %llums\n" +#~ msgstr "\tMax %llums\n" + +#~ msgid "\tmin %llums\n" +#~ msgstr "\tMin %llums\n" + +#~ msgid "\tmean %8.4fms\n" +#~ msgstr "\tMittel %8.4fms\n" + +#~ msgid "\tvariance %8.4fms\n" +#~ msgstr "\tVarianz %8.4fms\n" + +#~ msgid "Loss:\n" +#~ msgstr "Verlust:\n" + +#~ msgid "\tmax %u\n" +#~ msgstr "\tMax %u\n" + +#~ msgid "\tmin %u\n" +#~ msgstr "\tMin %u\n" + +#~ msgid "\tmean %8.4f\n" +#~ msgstr "\tMittel %8.4fms\n" + +#~ msgid "\tvariance %8.4f\n" +#~ msgstr "\tVarianz %8.4f\n" + +#~ msgid "Output format not known, this should not happen.\n" +#~ msgstr "Ausgabeformat ist unbekannt, dies sollte nicht passieren.\n" + +#~ msgid "" +#~ "\n" +#~ "Did not receive the message from gnunetd. Is gnunetd running?\n" +#~ msgstr "" +#~ "\n" +#~ "Es wurde keine Nachricht von gnunetd empfangen. Läuft gnunetd?\n" + +#, fuzzy +#~ msgid "# bytes received in plaintext of type %d" +#~ msgstr "# Bytes des Typs %d empfangen" + +#, fuzzy +#~ msgid "# bytes allocated by SQLite" +#~ msgstr "# bytes erlaubt in der Datenbank" + +#~ msgid "" +#~ "Failed to load MySQL database module. Check that MySQL is running and " +#~ "configured properly!\n" +#~ msgstr "" +#~ "Fehler beim Laden des MySQL Datenbankmoduls. Prüfen Sie, ob MySQL läuft " +#~ "und richtig eingerichtet ist!\n" + +#~ msgid "probe network to the given DEPTH" +#~ msgstr "Netzwerk bis zur angegebenen Tiefe DEPTH sondieren" + +#~ msgid "" +#~ "specify output format; 0 for human readable output, 1 for dot, 2 for vcg" +#~ msgstr "" +#~ "Gibt das Ausgabeformat an: 0 für menschen-lesbar, 1 für dot, 2 für vcg" + +#, fuzzy +#~ msgid "use PRIORITY for the priority of the trace request" +#~ msgstr "PRIO als Priorität für die Trace Anfragen verwenden" + +#~ msgid "wait DELAY seconds for replies" +#~ msgstr "DELAY Sekunden auf Antworten warten" + +#~ msgid "" +#~ "Format specification invalid. Use 0 for user-readable, 1 for dot, 2 for " +#~ "vcg.\n" +#~ msgstr "" +#~ "Formatangabe ungültig. Verwenden Sie 0 für menschen-lesbar, 1 für dot und " +#~ "2 für vcg.\n" + +#~ msgid "allows mapping of the network topology" +#~ msgstr "Erlaubt die Kartographierung der Netzwerktopologie" + +#, fuzzy +#~ msgid "HELLO message from `%s' has an invalid signature. Dropping.\n" +#~ msgstr "" +#~ "Hello Nachricht von `%s' ist ungültig (Signatur ist ungültig). Nachricht " +#~ "wurde verworfen.\n" + +#, fuzzy +#~ msgid "HELLO message has expiration too far in the future. Dropping.\n" +#~ msgstr "" +#~ "Empfangene Hello Nachricht ist ungültig (Ablaufzeit über Limit). " +#~ "Nachricht wurde verworfen.\n" + +#, fuzzy +#~ msgid "Could not send HELLO+PING, ping buffer full.\n" +#~ msgstr "Hellos+PING konnten nicht gesendet werden, Ping Puffer ist voll.\n" + +#~ msgid "" +#~ "Announcing ourselves pointless: no other peers are known to us so far.\n" +#~ msgstr "" +#~ "Bekanntmachung von uns zwecklos: bis jetzt sind uns keine anderen Knoten " +#~ "bekannt.\n" + +#, fuzzy +#~ msgid "# Peer advertisements of type NAT received" +#~ msgstr "# Knotenankündigungen empfangen" + +#, fuzzy +#~ msgid "# Peer advertisements updating earlier HELLOs" +#~ msgstr "# Knotenankündigungen empfangen" + +#, fuzzy +#~ msgid "# Peer advertisements for unsupported transport" +#~ msgstr "# Knotenankündigungen empfangen" + +#, fuzzy +#~ msgid "# Peer advertisements not confirmed due to ping busy" +#~ msgstr "# Knotenankündigungen empfangen" + +#, fuzzy +#~ msgid "# Peer advertisements not confirmed due to lack of self ad" +#~ msgstr "# Knotenankündigungen empfangen" + +#, fuzzy +#~ msgid "# Peer advertisements not confirmed due to send error" +#~ msgstr "# Knotenankündigungen empfangen" + +#~ msgid "`%s' registering handler %d (plaintext and ciphertext)\n" +#~ msgstr "`%s' registriert Handler %d (Plaintext und Ciphertext)\n" + +#~ msgid "" +#~ "ensures that this peer is known by other peers and discovers other peers" +#~ msgstr "" +#~ "Stellt sicher, dass dieser Knoten anderen Knoten bekannt ist und entdeckt " +#~ "andere Knoten" + +#~ msgid "`%s' registering handler %d\n" +#~ msgstr "`%s' registriert Handler %d\n" + +#, fuzzy +#~ msgid "`%s' registering CS handlers %d and %d\n" +#~ msgstr "`%s' registriert Handler %d und %d\n" + +#~ msgid "enables P2P-chat (incomplete)" +#~ msgstr "Ermöglicht P2P-Chat" + +#, fuzzy +#~ msgid "Existing key in file `%s' failed format check, creating new key.\n" +#~ msgstr "" +#~ "Formatüberprüfung schlug für die existierende Hostkeydatei `%s' fehl, es " +#~ "wird ein neuer Hostkey erzeugt.\n" + +#, fuzzy +#~ msgid "Creating new key for this nickname (this may take a while).\n" +#~ msgstr "Ein neuer Hostkey wird erzeugt (dies kann eine Weile dauern).\n" + +#, fuzzy +#~ msgid "# max bytes allowed in dstore" +#~ msgstr "# bytes erlaubt in der Datenbank" + +#~ msgid "Transport library `%s' did not provide required function '%s%s'.\n" +#~ msgstr "" +#~ "Transport Bibliothek `%s' stellt nicht die benötigte Funktion '%s%s' zur " +#~ "Verfügung.\n" + +#, fuzzy +#~ msgid "Query (get KEY, put KEY VALUE) DHT table." +#~ msgstr "" +#~ "Eine DHT Tabelle abfragen (get KEY, put KEY VALUE, remove KEY VALUE)." + +#, fuzzy +#~ msgid "allow TIME ms to process a GET command" +#~ msgstr "TIME ms erlauben, um jedes Kommando zu bearbeiten" + +#, fuzzy +#~ msgid "Issuing `%s(%s,%s)' command.\n" +#~ msgstr "'%s(%s,%s)' fehlgeschlagen.\n" + +#~ msgid "Command `%s' requires an argument (`%s').\n" +#~ msgstr "Kommando `%s' benötigt eine zusätzliche Angabe (`%s').\n" + +#~ msgid "Command `%s' requires two arguments (`%s' and `%s').\n" +#~ msgstr "Kommando `%s' benötigt zwei zusätzliche Angaben (`%s' und `%s').\n" + +#~ msgid "Unsupported command `%s'. Aborting.\n" +#~ msgstr "Kommando `%s' wird nicht unterstützt. Vorgang wird abgebrochen.\n" + +#, fuzzy +#~ msgid "# dht discovery messages sent" +#~ msgstr "# verschlüsselter PING Nachrichten empfangen" + +#, fuzzy +#~ msgid "# dht put requests received" +#~ msgstr "# Client Trace-Anfragen empfangen" + +#, fuzzy +#~ msgid "`%s' registering p2p handlers: %d %d %d\n" +#~ msgstr "`%s' registriert Handler %d %d %d\n" + +#~ msgid "`%s' failed. Terminating connection to client.\n" +#~ msgstr "`%s' fehlgeschlagen. Beende Verbindung zu Client.\n" + +#, fuzzy +#~ msgid "`%s' registering client handlers: %d %d\n" +#~ msgstr "`%s' registriert Client-Handler %d\n" + +#~ msgid "" +#~ "Existing hostkey in file `%s' failed format check, creating new hostkey.\n" +#~ msgstr "" +#~ "Formatüberprüfung schlug für die existierende Hostkeydatei `%s' fehl, es " +#~ "wird ein neuer Hostkey erzeugt.\n" + +#~ msgid "Done creating hostkey.\n" +#~ msgstr "Hostkey wurde erfolgreich erzeugt.\n" + +#, fuzzy +#~ msgid "Removed file `%s' containing invalid HELLO data.\n" +#~ msgstr "Datei `%s' enthielt ungültige Hello Daten und wurde entfernt.\n" + +#~ msgid "Signature failed verification: signature invalid.\n" +#~ msgstr "" +#~ "Verifikation einer Signatur fehlgeschlagen: Signatur ist ungültig.\n" + +#~ msgid "Received malformed `%s' message. Dropping.\n" +#~ msgstr "Beschädigte `%s' Nachricht empfangen. Nachricht wird verworfen.\n" + +#~ msgid "Received ping for another peer. Dropping.\n" +#~ msgstr "Ping für einen anderen Knoten empfangen. Ping wird verworfen.\n" + +#~ msgid "" +#~ "Could not match PONG against any PING. Try increasing MAX_PING_PONG " +#~ "constant.\n" +#~ msgstr "" +#~ "PONG konnte keinem PING zugeordnet werden. Versuchen Sie die Konstante " +#~ "MAX_PING_PONG hochzusetzen.\n" + +#~ msgid "Cannot create PING, table full. Try increasing MAX_PING_PONG.\n" +#~ msgstr "" +#~ "PING konnte nicht erstellt werden, da die Tabelle voll ist. Versuchen " +#~ "Sie, die Konstante MAX_PING_PONG hochzusetzen.\n" + +#~ msgid "# plaintext PONG messages received" +#~ msgstr "# Klartext PONG Nachrichten empfangen" + +#~ msgid "# encrypted PING messages received" +#~ msgstr "# verschlüsselter PING Nachrichten empfangen" + +#~ msgid "# encrypted PING messages sent" +#~ msgstr "# verschlüsselter PING Nachrichten gesendet" + +#~ msgid "`%s' registering handlers %d %d (plaintext and ciphertext)\n" +#~ msgstr "`%s' registriert Handler %d %d (Plaintext und Ciphertext)\n" + +#~ msgid "Cannot encrypt sessionkey, peer `%s' not known!\n" +#~ msgstr "" +#~ "Sitzungsschlüssel kann nicht verschlüsselt werden, Knoten `%s' ist uns " +#~ "nicht bekannt!\n" + +#, fuzzy +#~ msgid "Could not create any HELLO for myself (have transports `%s')!\n" +#~ msgstr "Hostkey konnte nicht erzeugt werden!\n" + +#, fuzzy +#~ msgid "" +#~ "Session key received from peer `%s' has invalid format (discarded).\n" +#~ msgstr "Empfangene Nachricht ist ungültig.\n" + +#, fuzzy +#~ msgid "Session key received from peer `%s' is for `%s' and not for me!\n" +#~ msgstr "Empfangene Nachricht ist ungültig.\n" + +#~ msgid "setkey `%s' from `%s' fails CRC check (have: %u, want %u).\n" +#~ msgstr "" +#~ "setkey `%s' von `%s' hat eine ungültige CRC Prüfsumme (tatsächlich: %u, " +#~ "erwartet: %u).\n" + +#, fuzzy +#~ msgid "" +#~ "Error parsing encrypted session key from `%s', given message part size is " +#~ "invalid.\n" +#~ msgstr "" +#~ "Fehler beim Parsen des Verschlüsselten Sitzungsschlüssels, gegebene " +#~ "Nachrichtenteilgröße ist ungültig.\n" + +#, fuzzy +#~ msgid "Unknown type in embedded message from `%s': %u (size: %u)\n" +#~ msgstr "Unbekannter Typ in engebetteter Nachricht: %u (%u bytes)\n" + +#~ msgid "# session keys sent" +#~ msgstr "# Sitzungsschlüssel gesendet" + +#~ msgid "# sessions established" +#~ msgstr "# Sitzungen aufgebaut" + +#~ msgid "automate creation of a namespace by starting a collection" +#~ msgstr "" +#~ "Erstellung eines Namespaces durch das Anfangen einer Collection " +#~ "automatisieren" + +#~ msgid "create a new pseudonym under the given NICKNAME" +#~ msgstr "Neues Pseudonym unter dem angegebenen NICKNAME erstellen" + +#~ msgid "delete the pseudonym with the given NICKNAME" +#~ msgstr "Pseudonym mit dem angegeben NICKNAME löschen" + +#~ msgid "end automated building of a namespace (ends collection)" +#~ msgstr "" +#~ "Automatisierte Erstellung eines Namespaces beenden (beendet Collection)" + +#~ msgid "" +#~ "Create new pseudonyms, delete pseudonyms or list existing pseudonyms." +#~ msgstr "" +#~ "Erstellen von neuen Pseudonymen, Löschen von Pseudonymen und Auflisten " +#~ "von bestehenden Pseudonymen." + +#~ msgid "" +#~ "use the given keyword to advertise the namespace (use when creating a new " +#~ "pseudonym)" +#~ msgstr "" +#~ "Das angegebene schlüsselwort verwenden, um den Namespace bekanntzumachen " +#~ "(zu verwenden, wenn ein neues Pseudonym erstellt wird)" + +#, fuzzy +#~ msgid "specify metadata describing the namespace or collection" +#~ msgstr "" +#~ "Automatisierte Erstellung eines Namespaces beenden (beendet Collection)" + +#~ msgid "" +#~ "do not generate an advertisement for this namespace (use when creating a " +#~ "new pseudonym)" +#~ msgstr "" +#~ "Keine Bekanntmachung für diesen Namespace erstellen (zu verwenden, wenn " +#~ "ein neues Pseudonym erstellt wird)" + +#~ msgid "do not list the pseudonyms from the pseudonym database" +#~ msgstr "Keine Ausgabe der Pseudonyme in der Pseudonymdatenbank" + +#~ msgid "" +#~ "specify IDENTIFIER to be the address of the entrypoint to content in the " +#~ "namespace (use when creating a new pseudonym)" +#~ msgstr "" +#~ "IDENTIFIER als Adresse angeben, die der Einsprungspunkt zu den Inhalten " +#~ "im Namespace ist (zu verwenden, wenn ein neues Pseudonym erstellt wird)" + +#~ msgid "Namespace `%s' (%s) has rating %d.\n" +#~ msgstr "Namespace `%s' (%s) hat das Rating %d.\n" + +#~ msgid "\tRating (after update): %d\n" +#~ msgstr "\tRating (nach Update): %d\n" + +#~ msgid "Collection stopped.\n" +#~ msgstr "Collection beendet.\n" + +#~ msgid "Failed to stop collection (not active?).\n" +#~ msgstr "Fehler beim Beenden der Collection (nicht aktiv?).\n" + +#~ msgid "Pseudonym `%s' deleted.\n" +#~ msgstr "Pseudonym `%s' wurde gelöscht.\n" + +#~ msgid "Error deleting pseudonym `%s' (does not exist?).\n" +#~ msgstr "Fehler beim Löschen des Pseudonyms `%s' (existiert nicht?).\n" + +#, fuzzy +#~ msgid "Started collection.\n" +#~ msgstr "Collection `%s' begonnen.\n" + +#~ msgid "Namespace `%s' created (root: %s).\n" +#~ msgstr "Namespace `%s' wurde erstellt (Root: %s).\n" + +#, fuzzy +#~ msgid "You must specify a name for the collection (`%s' option).\n" +#~ msgstr "" +#~ "Sie müssen einen Namen für die PID Datei in Sektion `%s' unter `%s' " +#~ "angeben.\n" + +#~ msgid "%d files found in directory.\n" +#~ msgstr "%d Dateien im Verzeichnis gefunden.\n" + +#~ msgid "Perform directory related operations." +#~ msgstr "Verzeichnisbezogene Operationen durchführen." + +#~ msgid "" +#~ "remove all entries from the directory database and stop tracking URIs" +#~ msgstr "" +#~ "Alle Einträge aus der Verzeichnis Datenbank löschen und das Verfolgen von " +#~ "URIs abbrechen" + +#~ msgid "list entries from the directory database" +#~ msgstr "Einträge aus der Verzeichnis Datenbank auflisten" + +#~ msgid "start tracking entries for the directory database" +#~ msgstr "Anfangen, Einträge für die Verzeichnis Datenbank zu verfolgen" + +#~ msgid "Listed %d matching entries.\n" +#~ msgstr "%d übereinstimmende Einträge aufgelistet.\n" + +#, fuzzy +#~ msgid "Upload of `%s' at %llu out of %llu bytes.\n" +#~ msgstr "Download der Datei `%s' bei %16llu von %16llu Bytes (%8.3f kbps)\n" + +#, fuzzy +#~ msgid "Upload aborted.\n" +#~ msgstr "" +#~ "\n" +#~ "Upload abgebrochen.\n" + +#, fuzzy +#~ msgid "Uploading suspended.\n" +#~ msgstr "Upload abgewiesen!" + +#, fuzzy +#~ msgid "" +#~ "run in debug mode; gnunet-auto-share will not daemonize and error " +#~ "messages will be written to stderr instead of a logfile" +#~ msgstr "" +#~ "Im Debug-Modus ausführen. gnunetd wird nicht im Hintergrund laufen und " +#~ "Fehlermeldungen werden nicht in die Protokolldatei, sondern auf die " +#~ "Standardfehlerausgabe (stderr) geschrieben." + +#, fuzzy +#~ msgid "" +#~ "do not use libextractor to add additional references to directory entries " +#~ "and/or the published file" +#~ msgstr "" +#~ "benutze libextractor um weitere direkte Referenzen zu Dateien in " +#~ "Verzeichnissen zu erzeugen" + +#~ msgid "Created entry `%s' in namespace `%s'\n" +#~ msgstr "Eintag `%s' in Namespace `%s' wurde erstellt\n" + +#~ msgid "" +#~ "%16llu of %16llu bytes inserted (estimating %6s to completion) - %s\n" +#~ msgstr "" +#~ "%16llu von %16llu Bytes eingefügt (geschätzte %6s bis Fertigstellung) - " +#~ "%s\n" + +#~ msgid "" +#~ "Upload of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" +#~ msgstr "" +#~ "Upload von `%s' komplett, %llu Bytes brauchten %llu Sekunden (%8.3f KB/" +#~ "s).\n" + +#~ msgid "" +#~ "\n" +#~ "Upload aborted.\n" +#~ msgstr "" +#~ "\n" +#~ "Upload abgebrochen.\n" + +#, fuzzy +#~ msgid "" +#~ "\n" +#~ "Error uploading file: %s" +#~ msgstr "" +#~ "\n" +#~ "Fehler beim Uploaden der Datei: %s\n" + +#~ msgid "" +#~ "even if gnunetd is running on the local machine, force the creation of a " +#~ "copy instead of making a link to the GNUnet share directory" +#~ msgstr "" +#~ "Obwohl gnunetd auf der lokalen Maschiene läuft die Erstellung einer Kopie " +#~ "anstelle der Erzeugung eines Links auf das GNUnet Share-Verzeichnis " +#~ "erzwingen." + +#~ msgid "Make files available to GNUnet for sharing." +#~ msgstr "Dateien GNUnet zum Filesharing zur Verfügung stellen." + +#~ msgid "Could not access namespace `%s' (does not exist?).\n" +#~ msgstr "Konnte nicht auf den Namespace `%s' zugreifen (existiert nicht?).\n" + +#~ msgid "Search GNUnet for files." +#~ msgstr "Das GNUnet nach Dateien durchsuchen." + +#~ msgid "write encountered (decrypted) search results to FILENAME" +#~ msgstr "Begegnete (entschlüsselte) Suchergebnisse in FILENAME schreiben" + +#~ msgid "Error converting arguments to URI!\n" +#~ msgstr "Fehler beim Konvertieren von Parametern in URI!\n" + +#~ msgid "" +#~ "%16llu of %16llu bytes unindexed (estimating %llu seconds to " +#~ "completion) " +#~ msgstr "" +#~ "%16llu von %16llu Bytes deindiziert (schätze %llu Sekunden bis " +#~ "Fertigstellung) " + +#~ msgid "" +#~ "\n" +#~ "Unindexing of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" +#~ msgstr "" +#~ "\n" +#~ "Deindizierung von `%s' abgeschlossen, %llu Bytes benötigten %llu Sekunden " +#~ "(%8.3f kbps).\n" + +#, fuzzy +#~ msgid "Not enough arguments. You must specify a filename.\n" +#~ msgstr "" +#~ "Nicht genügend Parameter. Sie müssen eine GNUnet Datei URI angeben\n" + +#~ msgid "`%s' failed. Is `%s' a file?\n" +#~ msgstr "`%s' schlug fehl. Ist `%s' eine Datei?\n" + +#~ msgid "Download files from GNUnet." +#~ msgstr "Dateien aus dem GNUnet herunterladen." + +#~ msgid "Download of file `%s' at %16llu out of %16llu bytes (%8.3f KiB/s)\n" +#~ msgstr "Download der Datei `%s' bei %16llu von %16llu Bytes (%8.3f kbps)\n" + +#~ msgid "Download aborted.\n" +#~ msgstr "Download abgebrochen.\n" + +#~ msgid "Download of file `%s' complete. Speed was %8.3f KiB per second.\n" +#~ msgstr "" +#~ "Download der Datei `%s' abgeschlossen. Geschwindigkeit war %8.3f KB/s.\n" + +#~ msgid "Not enough arguments. You must specify a GNUnet file URI\n" +#~ msgstr "" +#~ "Nicht genügend Parameter. Sie müssen eine GNUnet Datei URI angeben\n" + +#~ msgid "URI `%s' invalid for gnunet-download.\n" +#~ msgstr "URI `%s' ist ungültig für gnunet-download.\n" + +#, fuzzy +#~ msgid "No filename specified, using `%s' instead (for now).\n" +#~ msgstr "Kein Tabellenname angegeben, verwende `%s'.\n" + +#, fuzzy +#~ msgid "Downloading %d files from directory `%s'.\n" +#~ msgstr "Dateien aus dem GNUnet herunterladen." + +#, fuzzy +#~ msgid "Did not find any files in directory `%s'\n" +#~ msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" + +#~ msgid "File stored as `%s'.\n" +#~ msgstr "Datei wurde als `%s' gespeichert.\n" + +#~ msgid "Collecting file identifiers disabled.\n" +#~ msgstr "Einsammeln von Dateibezeichnern deaktiviert.\n" + +#~ msgid "Cannot get size of file `%s'" +#~ msgstr "Die Größe der Datei `%s' konnte nicht ermittelt werden" + +#~ msgid "Cannot hash `%s'.\n" +#~ msgstr "`%s' konnte nicht gehashed werden.\n" + +#~ msgid "Initialization for indexing file `%s' failed.\n" +#~ msgstr "Initialisierung der Indizierung der Datei `%s' fehlgeschlagen.\n" + +#, fuzzy +#~ msgid "Cannot open file `%s': `%s'" +#~ msgstr "Konfigurationsdatei `%s' konnte nicht geöffnet werden.\n" + +#~ msgid "Renaming of file `%s' to `%s' failed: %s\n" +#~ msgstr "Umbenennen der Datei `%s' zu `%s' fehlgeschlagen: %s\n" + +#~ msgid "Could not rename file `%s' to `%s': file exists\n" +#~ msgstr "" +#~ "Datei `%s' konnte nicht zu `%s' umbenannt werden: Datei existiert " +#~ "bereits\n" + +#~ msgid "CHK URI not allowed for search.\n" +#~ msgstr "CHK URI ist nicht erlaubt für Suchen.\n" + +#~ msgid "LOC URI not allowed for search.\n" +#~ msgstr "LOC URI ist nicht erlaubt für Suchen.\n" + +#~ msgid "Format of pseudonym `%s' is invalid.\n" +#~ msgstr "Format des Pseudonyms `%s' ist ungültig.\n" + +#, fuzzy +#~ msgid "Format of file `%s' is invalid, trying to remove.\n" +#~ msgstr "Format der Datei `%s' ist ungültig.\n" + +#~ msgid "" +#~ "Decrypted content does not match key. This is either a bug or a " +#~ "maliciously inserted file. Download aborted.\n" +#~ msgstr "" +#~ "Entschlüsselter Inhalt entspricht nicht dem Schlüssel. Dies ist entweder " +#~ "ein Bug oder eine mit bösen Absichten eingefügte Datei. Download wurde " +#~ "abgebrochen.\n" + +#, fuzzy +#~ msgid "Application aborted." +#~ msgstr "_Optionen" + +#~ msgid "FSUI state file `%s' had syntax error at offset %u.\n" +#~ msgstr "FSUI Statusdatei `%s' hatte einen Syntaxfehler bei Offset %u.\n" + +#, fuzzy +#~ msgid "# gap content total planned" +#~ msgstr "# gap Anfragen insgesamt empfangen" + +#~ msgid "# gap requests total received" +#~ msgstr "# gap Anfragen insgesamt empfangen" + +#, fuzzy +#~ msgid "# gap content total received" +#~ msgstr "# gap Anfragen insgesamt empfangen" + +#, fuzzy +#~ msgid "" +#~ "`%s' registering client handlers %d %d %d %d %d %d %d %d and P2P handlers " +#~ "%d %d\n" +#~ msgstr "`%s' registriert die Client Handler %d %d %d %d %d %d %d %d %d\n" + +#~ msgid "enables (anonymous) file-sharing" +#~ msgstr "Ermöglicht (anonymes) Filesharing" + +#~ msgid "" +#~ "Because the file `%s' has been unavailable for 3 days it got removed from " +#~ "your share. Please unindex files before deleting them as the index now " +#~ "contains invalid references!\n" +#~ msgstr "" +#~ "Weil die Datei `%s' nun seit 3 Tagen nicht zur Verfügung steht, wurde Sie " +#~ "aus Ihrem Share entfernt. Bitte deindizieren Sie Dateien, bevor Sie sie " +#~ "löschen, da Ihr Index nun ungültige Referenzen enthält!\n" + +#~ msgid "" +#~ "Unindexed ODB block `%s' from offset %llu already missing from " +#~ "datastore.\n" +#~ msgstr "" +#~ "Deindizierter ODB Block `%s' vom Offset %llu fehlt bereits im " +#~ "Datenspeicher.\n" + +#, fuzzy +#~ msgid "# gap client requests tracked" +#~ msgstr "# gap Anfragen insgesamt empfangen" + +#~ msgid "# blocks migrated" +#~ msgstr "# Blöcke migriert" + +#, fuzzy +#~ msgid "# blocks injected for migration" +#~ msgstr "# Blöcke migriert" + +#, fuzzy +#~ msgid "# on-demand fetches for migration" +#~ msgstr "# Blöcke migriert" + +#, fuzzy +#~ msgid "# gap queries dropped (table full)" +#~ msgstr "# gap falsche Antworten" + +#, fuzzy +#~ msgid "# gap queries dropped (redundant)" +#~ msgstr "# gap falsche Antworten" + +#, fuzzy +#~ msgid "# trust earned" +#~ msgstr "# dht Anfragen weitergeleitet" + +#, fuzzy +#~ msgid "Friend list of %s:%d\n" +#~ msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" + +#, fuzzy +#~ msgid "set number of daemons to start" +#~ msgstr "Anzahl an Nachrichten, die pro Durchlauf verwendet wird" + +#, fuzzy +#~ msgid "Waiting for peers to connect" +#~ msgstr "" +#~ "Warte darauf, dass sich andere Knoten verbinden (%u Iterationen " +#~ "verbleiben)...\n" + +#, fuzzy +#~ msgid "Bootstrap data obtained from `%s' is invalid.\n" +#~ msgstr "Format des Pseudonyms `%s' ist ungültig.\n" + +#~ msgid "`%s' registering client handler %d\n" +#~ msgstr "`%s' registriert Client-Handler %d\n" + +#~ msgid "allows clients to determine gnunetd's configuration" +#~ msgstr "Erlaubt es Clients die Konfiguration von gnunetd abzufragen" + +#~ msgid "`%s' registering client handler %d and %d\n" +#~ msgstr "`%s' registriert Client-Handler %d and %d\n" + +#~ msgid "Uptime (seconds)" +#~ msgstr "Laufzeit (Sekunden)" + +#~ msgid "% of allowed network load (up)" +#~ msgstr "% of allowed network load (up)" + +#~ msgid "% of allowed network load (down)" +#~ msgstr "% of allowed network load (down)" + +#~ msgid "% of allowed cpu load" +#~ msgstr "% of allowed cpu load" + +#, fuzzy +#~ msgid "% of allowed io load" +#~ msgstr "% of allowed cpu load" + +#, fuzzy +#~ msgid "`%s' registering client handlers %d %d %d and p2p handler %d\n" +#~ msgstr "`%s' registriert die Client Handler %d %d %d %d %d %d %d %d %d\n" + +#~ msgid "keeps statistics about gnunetd's operation" +#~ msgstr "Hält Statistiken über Betrieb von gnunetd" + +#~ msgid "Supported peer-to-peer messages:\n" +#~ msgstr "unterstützte Peer-to-Peer Nachrichten:\n" + +#~ msgid "Supported client-server messages:\n" +#~ msgstr "unterstützte Client-Server Nachrichten:\n" + +#~ msgid "prints supported protocol messages" +#~ msgstr "gibt unterstützte Protokollnachrichten aus" + +#, fuzzy +#~ msgid "VPN Received unknown IP version %d...\n" +#~ msgstr "Es wurde eine unbekannte Testbed Nachricht des Typs %u empfangen.\n" + +#, fuzzy +#~ msgid "Cannot open tunnel device: %s" +#~ msgstr "Konfigurationsdatei `%s' konnte nicht geöffnet werden.\n" + +#, fuzzy +#~ msgid "Cannot set interface IPv6 address for gnu%d because %s\n" +#~ msgstr "Es konnte keine IP-Adresse für das Gerät `%s' ermittelt werden.\n" + +#, fuzzy +#~ msgid "Cannot add route IPv6 address for gnu%s because %s\n" +#~ msgstr "Es konnte keine IP-Adresse für das Gerät `%s' ermittelt werden.\n" + +#, fuzzy +#~ msgid "`%s' initialising RFC4913 module %d and %d\n" +#~ msgstr "`%s' registriert Handler %d und %d\n" + +#, fuzzy +#~ msgid "enables IPv6 over GNUnet (incomplete)" +#~ msgstr "Ermöglicht P2P-Chat" + +#~ msgid "Application module `%s' already initialized!\n" +#~ msgstr "Anwendungsmodul `%s' ist bereits initialisiert!\n" + +#~ msgid "Failed to load plugin `%s' at %s:%d. Unloading plugin.\n" +#~ msgstr "" +#~ "Fehler beim Laden des Plugins `%s' bei %s:%d. Plugin wird entladen.\n" + +#~ msgid "Could not shutdown `%s': application not loaded\n" +#~ msgstr "" +#~ "`%s' kann nicht heruntergefahren werden: Anwendung ist nicht geladen\n" + +#~ msgid "Could not shutdown application `%s': not initialized\n" +#~ msgstr "" +#~ "Anwendung `%s' kann nicht heruntergefahren werden: sie ist nicht " +#~ "initialisiert\n" + +#~ msgid "Could not find '%s%s' method in library `%s'.\n" +#~ msgstr "Methode '%s%s' kann in Bibliothek `%s' nicht gefunden werden.\n" + +#~ msgid "Could not release %p: service not loaded\n" +#~ msgstr "%p kann nicht freigegeben werden: Dienst ist nicht geladen\n" + +#~ msgid "Could not properly shutdown application `%s'.\n" +#~ msgstr "Anwendung `%s' konnte nicht ordentlich heruntergefahren werden.\n" + +#~ msgid "Could not properly unload service `%s'!\n" +#~ msgstr "Dienst `%s' konnte nicht ordentlich entladen werden!\n" + +#, fuzzy +#~ msgid "Core initialization failed.\n" +#~ msgstr " Verbindung fehlgeschlagen\n" + +#~ msgid "Updates GNUnet datastructures after version change." +#~ msgstr "GNUnet Datenstrukturen nach einer Versionsänderung aktualisieren." + +#~ msgid "run as user LOGIN" +#~ msgstr "als Benutzer LOGIN ausführen" + +#~ msgid "run in client mode (for getting client configuration values)" +#~ msgstr "" +#~ "Im Benuter-Modus laufen (um benutzerspezifische " +#~ "Konfigurationseinstellungen zu holen" + +#~ msgid "" +#~ "run in debug mode; gnunetd will not daemonize and error messages will be " +#~ "written to stderr instead of a logfile" +#~ msgstr "" +#~ "Im Debug-Modus ausführen. gnunetd wird nicht im Hintergrund laufen und " +#~ "Fehlermeldungen werden nicht in die Protokolldatei, sondern auf die " +#~ "Standardfehlerausgabe (stderr) geschrieben." + +#~ msgid "Starts the gnunetd daemon." +#~ msgstr "Startet den gnunetd Daemonen." + +#, fuzzy +#~ msgid "specify username as which gnunetd should run" +#~ msgstr "Gibt an, auf welchem Host gnunetd läuft" + +#~ msgid "Configuration or GNUnet version changed. You need to run `%s'!\n" +#~ msgstr "" +#~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " +#~ "ausführen!\n" + +#~ msgid "The `%s' request received from client is malformed.\n" +#~ msgstr "Die `%s' Anfrage, die vom Client empfangen wurde, ist beschädigt.\n" + +#~ msgid "" +#~ "Malformed network specification in the configuration in section `%s' for " +#~ "entry `%s': %s\n" +#~ msgstr "" +#~ "Beschädigte Netzwerkangabe in der Konfigurationsdatei in Sektion `%s' für " +#~ "Eintrag `%s': %s\n" + +#, fuzzy +#~ msgid "Registering failed, message type %d already in use.\n" +#~ msgstr "%s schlug fehl, Nachrichten Typ %d ist bereits in Verwendung.\n" + +#, fuzzy +#~ msgid "Unable to obtain filesystem information for `%s': %u\n" +#~ msgstr "Fehler beim Speichern der Konfigurationsdatei: `%s': %s.\n" + +#, fuzzy +#~ msgid "`%s' message invalid (signature invalid).\n" +#~ msgstr "Hello Nachricht ist ungültig (Signatur ist ungültig).\n" + +#~ msgid "`%s' selected %d out of %d messages (MTU: %d).\n" +#~ msgstr "`%s' wählte %d von %d Nachrichten aus (MTU: %d).\n" + +#~ msgid "Message details: %u: length %d, priority: %d\n" +#~ msgstr "Nachrichten Details: %u: Länge %d, Priorität: %d\n" + +#~ msgid "Message from `%s' discarded: invalid format.\n" +#~ msgstr "Nachricht von `%s' verworfen: ungültiges Format.\n" + +#~ msgid "Invalid sequence number %u <= %u, dropping message.\n" +#~ msgstr "Ungültige Sequenznummer %u <= %u, Nachricht wird verworfen.\n" + +#~ msgid "Message received more than one day old. Dropped.\n" +#~ msgstr "" +#~ "Empfangene Nachricht ist mehr als ein Tag alt. Nachricht wird verworfen.\n" + +#~ msgid "# connections closed (HANGUP sent)" +#~ msgstr "# geschlossener Verbindungen (HANGUP gesendet)" + +#~ msgid "# bytes noise sent" +#~ msgstr "# Bytes Rauschen gesendet" + +#, fuzzy +#~ msgid "# total bytes per second receive limit" +#~ msgstr "# Bytes Rauschen empfangen" + +#, fuzzy +#~ msgid "# total number of messages in send buffers" +#~ msgstr "Anzahl an Nachrichten in einem Nachrichtenblock" + +#, fuzzy +#~ msgid "# total number of bytes we were allowed to send but did not" +#~ msgstr "Anzahl an Nachrichten in einem Nachrichtenblock" + +#, fuzzy +#~ msgid "# total number of bytes we were allowed to sent" +#~ msgstr "Anzahl an Nachrichten in einem Nachrichtenblock" + +#~ msgid "`%s': Could not create hello.\n" +#~ msgstr "`%s': Hello konnte nicht erzeugt werden.\n" + +#~ msgid "`%s': Could not send.\n" +#~ msgstr "`%s': Kann nicht senden.\n" + +#~ msgid "`%s': Could not disconnect.\n" +#~ msgstr "`%s': Verbindung konnte nicht getrennt werden.\n" + +#, fuzzy +#~ msgid "" +#~ "`%s' transport OK. It took %ums to transmit %llu messages of %llu bytes " +#~ "each.\n" +#~ msgstr "" +#~ "`%s' Transport funktioniert. Es dauerte %ums, um %d Nachrichten zu je %d " +#~ "Bytes zu übertragen.\n" + +#, fuzzy +#~ msgid " Transport %d is not being tested\n" +#~ msgstr " Transport %d ist nicht verfügbar\n" + +#~ msgid "" +#~ "\n" +#~ "Contacting `%s'." +#~ msgstr "" +#~ "\n" +#~ "Kontaktiere `%s'." + +#~ msgid " Connection failed (bug?)\n" +#~ msgstr " Verbindung fehlgeschlagen (Bug?)\n" + +#, fuzzy +#~ msgid "OK!\n" +#~ msgstr "OK" + +#~ msgid "Tool to test if GNUnet transport services are operational." +#~ msgstr "" +#~ "Werkzeug, mit dem getestet werden kann, ob die GNUnet Transport Dienste " +#~ "funktionsfähig sind." + +#~ msgid "ping peers from HOSTLISTURL that match transports" +#~ msgstr "Knoten aus HOSTLISTURL anpingen, deren Transports passen" + +#~ msgid "send messages with SIZE bytes payload" +#~ msgstr "Nachrichten mit SIZE Bytes Nutzlast versenden" + +#~ msgid "specifies which TRANSPORT should be tested" +#~ msgstr "Gibt an, welcher TRANSPORT getestet werden soll" + +#~ msgid "specifies after how many MS to time-out" +#~ msgstr "Gibt an, nach wievielen MS die Zeit abgelaufen sein soll" + +#~ msgid "Testing transport(s) %s\n" +#~ msgstr "Teste Transport(e) %s\n" + +#~ msgid "Available transport(s): %s\n" +#~ msgstr "Verfügbare(r) Transport(e): %s\n" + +#, fuzzy +#~ msgid "" +#~ "\n" +#~ "%d out of %d peers contacted successfully (%d times transport " +#~ "unavailable).\n" +#~ msgstr "" +#~ "%d von %d Knoten erfolgreich kontaktiert (%d mal war der Transport nicht " +#~ "verfügbar).\n" + +#, fuzzy +#~ msgid "%s failed for url `%s' and post-data `%s' at %s:%d: `%s'\n" +#~ msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" + +#~ msgid "# bytes sent via HTTP" +#~ msgstr "# Bytes gesendet über HTTP" + +#~ msgid "# bytes dropped by HTTP (outgoing)" +#~ msgstr "# Bytes verworfen von HTTP" + +#, fuzzy +#~ msgid "# HTTP connect calls" +#~ msgstr "# verbundener Knoten" + +#, fuzzy +#~ msgid "Failed to obtain my (external) %s address!\n" +#~ msgstr "Fehler beim Bestimmen der (externen) IP-Adresse!\n" + +#, fuzzy +#~ msgid "MTU %llu for `%s' is probably too low!\n" +#~ msgstr "" +#~ "MTU für `%s' ist möglicherweise zu gering (Fragmentierung ist nicht " +#~ "implementiert!)\n" + +#~ msgid "specify host on which gnunetd is running" +#~ msgstr "Gibt an, auf welchem Host gnunetd läuft" + +#~ msgid "No help available." +#~ msgstr "Keine Hilfe verfügbar." + +#, fuzzy +#~ msgid "Show rarely used options" +#~ msgstr "Maskierte Optionen anzeigen" + +#, fuzzy +#~ msgid "Meta-configuration" +#~ msgstr "GNUnet Konfiguration" + +#, fuzzy +#~ msgid "Full pathname of GNUnet HOME directory" +#~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#, fuzzy +#~ msgid "Full pathname of GNUnet directory for file-sharing data" +#~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#, fuzzy +#~ msgid "Full pathname to the directory with the key-value database" +#~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#, fuzzy +#~ msgid "Note that the kvstore is currently not used." +#~ msgstr "# gap Routingschächte im Moment in Verwendung" + +#, fuzzy +#~ msgid "Full pathname of GNUnet directory for indexed files symbolic links" +#~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#, fuzzy +#~ msgid "Run gnunetd as this group." +#~ msgstr "gnunet-update ausführen" + +#, fuzzy +#~ msgid "General settings" +#~ msgstr "Weitere Einstellungen" + +#, fuzzy +#~ msgid "Settings for restricting connections to friends" +#~ msgstr "`%s' fehlgeschlagen. Beende Verbindung zu Client.\n" + +#, fuzzy +#~ msgid "Configuration file that specifies the MySQL username and password" +#~ msgstr "" +#~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " +#~ "ausführen!\n" + +#, fuzzy +#~ msgid "Configuration of the MySQL database" +#~ msgstr "" +#~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " +#~ "ausführen!\n" + +#, fuzzy +#~ msgid "MB of diskspace GNUnet can use for anonymous file sharing" +#~ msgstr "Ermöglicht (anonymes) Filesharing" + +#, fuzzy +#~ msgid "Number of entries in the migration buffer" +#~ msgstr "Anzahl an Nachrichten in einem Nachrichtenblock" + +#, fuzzy +#~ msgid "Options for anonymous file sharing" +#~ msgstr "Ermöglicht (anonymes) Filesharing" + +#, fuzzy +#~ msgid "Applications" +#~ msgstr "_Optionen" + +#, fuzzy +#~ msgid "Network interface" +#~ msgstr "Netzwerkgerät:" + +#, fuzzy +#~ msgid "Network interface to monitor" +#~ msgstr "Netzwerkgerät:" + +#, fuzzy +#~ msgid "Load management" +#~ msgstr "Ungültige Kommandozeilen Parameter.\n" + +#, fuzzy +#~ msgid "This is equivalent to the -H option. The format is IP:PORT." +#~ msgstr "Wert der Option anzeigen" + +#, fuzzy +#~ msgid "What is the path to the configuration file for gnunetd?" +#~ msgstr "" +#~ "Einen Wert aus der Konfigurationsdatei auf der Standardausgabe ausgeben" + +#, fuzzy +#~ msgid "General options" +#~ msgstr "Weitere Einstellungen" + +#, fuzzy +#~ msgid "Options related to gnunet-gtk" +#~ msgstr "Nicht verbunden zu gnunetd." + +#, fuzzy +#~ msgid "Full pathname of GNUnet client HOME directory" +#~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" + +#~ msgid "Could not determine my public IPv6 address.\n" +#~ msgstr "Die öffentliche IPv6-Adresse konnte nicht ermittelt werden.\n" + +#~ msgid "`%s': unknown service: %s\n" +#~ msgstr "`%s': unbekannter Dienst: %s\n" + +#, fuzzy +#~ msgid "# bytes received via TCP6" +#~ msgstr "# Bytes empfangen über TCP" + +#, fuzzy +#~ msgid "# bytes sent via TCP6" +#~ msgstr "# Bytes gesendet über TCP" + +#, fuzzy +#~ msgid "# bytes dropped by TCP6 (outgoing)" +#~ msgstr "# Bytes verworfen von TCP (ausgehend)" + +#~ msgid "UDP6: Could not determine my public IPv6 address.\n" +#~ msgstr "UDP6: Öffentliche IPv6-Adresse konnte nicht ermittelt werden.\n" + +#, fuzzy +#~ msgid "# bytes received via UDP6" +#~ msgstr "# Bytes empfangen über UDP" + +#, fuzzy +#~ msgid "# bytes sent via UDP6" +#~ msgstr "# Bytes gesendet über UDP" + +#, fuzzy +#~ msgid "# bytes dropped by UDP6 (outgoing)" +#~ msgstr "# Bytes verworfen von UDP (outgoing)" + +#~ msgid "HTTP: Could not determine my public IP address.\n" +#~ msgstr "HTTP: öffentliche IP-Adresse konnte nicht ermittelt werden.\n" + +#, fuzzy +#~ msgid "Received malformed message instead of welcome message. Closing.\n" +#~ msgstr "" +#~ "Es wurde per TCP von einem anderen Knoten eine ungültige Nachricht (Größe " +#~ "%u) empfangen. Verbindung wird geschlossen.\n" + +#, fuzzy +#~ msgid "Received malformed message from tcp-peer connection. Closing.\n" +#~ msgstr "" +#~ "Es wurde per TCP von einem anderen Knoten eine ungültige Nachricht (Größe " +#~ "%u) empfangen. Verbindung wird geschlossen.\n" + +#, fuzzy +#~ msgid "TCP: Could not determine my public IP address.\n" +#~ msgstr "HTTP: öffentliche IP-Adresse konnte nicht ermittelt werden.\n" + +#~ msgid "Cannot connect to %u.%u.%u.%u:%u: %s\n" +#~ msgstr "Verbindung zu %u.%u.%u.%u:%u fehlgeschlagen: %s\n" + +#~ msgid "UDP: Could not determine my public IP address.\n" +#~ msgstr "UDP: öffentliche IP-Adresse konnte nicht ermittelt werden.\n" + +#~ msgid "Failed to send message of size %d via UDP to %u.%u.%u.%u:%u: %s\n" +#~ msgstr "" +#~ "Eine Nachricht der Größe %d konnte nicht per UDP an %u.%u.%u.%u:%u " +#~ "versendet werden: %s\n" + +#, fuzzy +#~ msgid "Received malformed message from udp-peer connection. Closing.\n" +#~ msgstr "" +#~ "Es wurde per TCP von einem anderen Knoten eine ungültige Nachricht (Größe " +#~ "%u) empfangen. Verbindung wird geschlossen.\n" + +#~ msgid "'%s(%s,%s)' succeeded\n" +#~ msgstr "'%s(%s,%s)' erfolgreich abgeschlossen\n" + +#~ msgid "'%s(%s,%s)' failed.\n" +#~ msgstr "'%s(%s,%s)' fehlgeschlagen.\n" + +#~ msgid "" +#~ "%s::%s - RPC %s:%p could not be unregistered: another callback registered " +#~ "under that name: %p\n" +#~ msgstr "" +#~ "%s::%s - RPC %s:%p konnte nicht unregistriert werden: ein anderer " +#~ "Callback ist unter diesem Namen registiert: %p\n" + +#~ msgid "%s::%s - RPC %s:%p could not be unregistered: not found\n" +#~ msgstr "" +#~ "%s::%s - RPC %s:%p konnte nicht unregistriert werden: nicht gefunden\n" + +#~ msgid "Dropping RPC request %u: message malformed.\n" +#~ msgstr "RPC Anfrage %u wird verworfen: Nachricht ist beschädigt.\n" + +#~ msgid "`%s' called with timeout above 1 hour (bug?)\n" +#~ msgstr "`%s' mit einem Timeout von über einer Stunde aufgerufen (Fehler?)\n" + +#~ msgid "RPC not unregistered: %s:%p\n" +#~ msgstr "RPC nicht unregistriert: %s:%p\n" + +#~ msgid "RPC async reply invalid.\n" +#~ msgstr "RPC async Antwort ungültig.\n" + +#~ msgid "async RPC reply not received.\n" +#~ msgstr "async RPC Antwort nicht empfangen.\n" + +#~ msgid "" +#~ "Cover traffic requested but traffic service not loaded. Rejecting " +#~ "request.\n" +#~ msgstr "" +#~ "Verdeckender Netzwerkverkehr angefordert, aber der Verkehrsdienst wurde " +#~ "nicht geladen. Anfrage wird abgelehnt.\n" + +#~ msgid "Cannot satisfy desired level of anonymity, ignoring request.\n" +#~ msgstr "" +#~ "Gewünschter Grad an Anonymität kann nicht erreicht werden, Anfrage wird " +#~ "ignoriert.\n" + +#~ msgid "# gap requests policy: immediate drop" +#~ msgstr "# gap Anfragen mit taktischer Entscheidung: sofortiges Verwerfen" + +#~ msgid "# gap requests policy: not routed" +#~ msgstr "# gap Anfragen mit taktischer Entscheidung: kein Routing" + +#~ msgid "# gap requests policy: not answered" +#~ msgstr "# gap Anfragen mit taktischer Entscheidung: nicht Antworten" + +#~ msgid "# gap requests processed: attempted add to RT" +#~ msgstr "# gap Anfragen verarbeitet: versucht, der RT hinzuzufügen" + +#~ msgid "# gap requests processed: local result" +#~ msgstr "# gap Anfragen verarbeitet: lokales Ergebnis" + +#~ msgid "# gap requests forwarded (counting each peer)" +#~ msgstr "#gap Anfragen weitergeleitet (jeder Knoten gezählt)" + +#~ msgid "# gap duplicate requests (pending)" +#~ msgstr "# gap doppelte Anfragen (unfertig)" + +#~ msgid "# gap duplicate requests that were re-tried" +#~ msgstr "# gap doppelte Anfragen, die wiederholt wurden" + +#~ msgid "# gap re-try ttl difference (cummulative)" +#~ msgstr "# gap Wiederholungs-TTL-Differenz (kummulativ)" + +#~ msgid "# gap reply duplicates" +#~ msgstr "#gap doppelte Antworten" + +#~ msgid "# gap routing slots currently in use" +#~ msgstr "# gap Routingschächte im Moment in Verwendung" + +#, fuzzy +#~ msgid "# gap rewards pending" +#~ msgstr "# gap doppelte Anfragen (unfertig)" + +#, fuzzy +#~ msgid "# gap response weights" +#~ msgstr "# gap falsche Antworten" + +#~ msgid "" +#~ "Traffic service failed to load; gap cannot ensure cover-traffic " +#~ "availability.\n" +#~ msgstr "" +#~ "Verkehrsdienst konnte nicht geladen werden, GAP kann keinen verdeckenden " +#~ "Netzwerkverkehr sicherstellen.\n" + +#~ msgid "`%s' registering handlers %d %d\n" +#~ msgstr "`%s' registriert Handler %d %d\n" + +#~ msgid "" +#~ "set interval for availability of updates to SECONDS (for namespace " +#~ "insertions only)" +#~ msgstr "" +#~ "Intervall der Verfügbarkeit von Updates auf SECONDS setzen (nur für das " +#~ "Einfügen in Namespaces)" + +#~ msgid "" +#~ "specifies this as an aperiodic but updated publication (for namespace " +#~ "insertions only)" +#~ msgstr "" +#~ "Dies als unregelmäßige aber aktualisierbare Veröffentlichung kennzeichnen " +#~ "(nur für das Einfügen in Namespaces)" + +#~ msgid "specify creation time for SBlock (see man-page for format)" +#~ msgstr "Erstellungszeit für den SBLOCK angeben (s. Manpage zum Format)" + +#~ msgid "" +#~ "ID of the previous version of the content (for namespace update only)" +#~ msgstr "" +#~ "ID der vorherigen Version des Inhalts (nur für das Einfügen in Namespaces)" + +#~ msgid "Parsing time failed. Use `%s' format.\n" +#~ msgstr "Das Parsen der Zeit schlug fehl. Verwenden Sie das `%s' Format.\n" + +#~ msgid "exit after receiving LIMIT results" +#~ msgstr "Abbrechen, nachdem LIMIT Ergebnisse empfangen wurden" + +#~ msgid "wait DELAY seconds for search results before aborting" +#~ msgstr "TIMEOUT Sekunden auf Suchergebnisse warten, bevor abgebrochen wird" + +#, fuzzy +#~ msgid "# FS currently tracked queries from clients" +#~ msgstr "# Client Trace-Antworten gesendet" + +#~ msgid "Indexed file disappeared, deleting block for query `%s'\n" +#~ msgstr "" +#~ "Indizierte Datei ist verschwunden, Block für Anfrage `%s' wird gelöscht\n" + +#~ msgid "" +#~ "Configuration file must specify directory for storage of FS data in " +#~ "section `%s' under `%s'.\n" +#~ msgstr "" +#~ "Die Konfigurationsdatei muss ein Verzeichnis für die Speicherung von FS " +#~ "Daten in der Sektion `%s' unter `%s' angeben.\n" + +#~ msgid "AND" +#~ msgstr "UND" + +#~ msgid "Error running search (no reason given)." +#~ msgstr "Das Starten der Suche schlug fehl (Ursache unbekannt)." + +#~ msgid "Download failed (no reason given)" +#~ msgstr "ECRS Download schlug fehl (Ursache unbekannt)." + +#~ msgid "Could not unlink temporary file `%s': %s\n" +#~ msgstr "Temporäre Datei `%s' konnte nicht gelöscht werden: %s\n" + +#~ msgid "Write(%d, %p, %d) failed: %s\n" +#~ msgstr "Write(%d, %p, %d) schlug fehl: %s\n" + +#~ msgid "" +#~ "Content `%s' seems to be not available on the network (tried %u times).\n" +#~ msgstr "" +#~ "Inhalt `%s' scheint im Netzwerk nicht verfügbar zu sein (%u mal " +#~ "versucht).\n" + +#~ msgid "Cannot create pseudonym `%s', file `%s' exists.\n" +#~ msgstr "" +#~ "Pseudonym `%s' kann nicht erstellt werden, da die Datei `%s' bereits " +#~ "existiert.\n" + +#~ msgid "Publication interval for periodic publication changed." +#~ msgstr "" +#~ "Veröffentlichungsintervall für periodische Veröffentlichung wurde " +#~ "geändert." + +#~ msgid "" +#~ "Publishing update for periodically updated content more than a week ahead " +#~ "of schedule.\n" +#~ msgstr "" +#~ "Veröffentlichungsdatum für periodisch aktualisierten Inhalt ist mehr als " +#~ "eine Woche früher als geplant.\n" + +#~ msgid "Message received from peer is invalid.\n" +#~ msgstr "Empfangene Nachricht ist ungültig.\n" + +#~ msgid "Maximum number of chat clients reached.\n" +#~ msgstr "Maximale Anzahl an Chat Clients erreicht.\n" + +#~ msgid "Now %d of %d chat clients at this node.\n" +#~ msgstr "Jetzt sind %d von %d auf diesem Knoten.\n" + +#, fuzzy +#~ msgid "Invalid data in %s (NCS). Trying to fix (by deletion).\n" +#~ msgstr "Ungültige Daten in %s. Korrektur wird versucht (durch Löschung).\n" + +#, fuzzy +#~ msgid "`%s' failed at %s:%d with error `%s' after %llums\n" +#~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#~ msgid "" +#~ "Directory `%s' in directory `%s' does not match naming convention. " +#~ "Removed.\n" +#~ msgstr "" +#~ "Die Datei `%s' im Verzeichnis `%s' entspricht nicht der Namenskonvention. " +#~ "Datei wurde entfernt.\n" + +#~ msgid "Start GNUnet-testbed helper." +#~ msgstr "GNUnet-testbed Helfer starten." + +#~ msgid "Cannot connect to LOOPBACK port %d: %s\n" +#~ msgstr "Verbindung zum LOOPBACK port %d schlug fehl: %s\n" + +#~ msgid "Could not execute `%s': %s\n" +#~ msgstr "`%s' konnte nicht ausgeführt werden: %s\n" + +#~ msgid "No client service started. Trying again in 30 seconds.\n" +#~ msgstr "Kein Client Dienst gestartet. Erneuter Versuch in 30 Sekunden.\n" + +#~ msgid "" +#~ "Error (%s) binding the TCP listener to port %d. No proxy service " +#~ "started.\n" +#~ "Trying again in %d seconds...\n" +#~ msgstr "" +#~ "Fehler (%s) beim Binden des TCP Listeners an den Port %d. Der Proxy " +#~ "Dienst wurde nicht gestartet.\n" +#~ "Erneuter Versuch in %d Sekunden...\n" + +#~ msgid "Rejected unauthorized connection from %u.%u.%u.%u.\n" +#~ msgstr "Unauthorisierte Verbindung von %u.%u.%u.%u. wurde abgewiesen.\n" + +#~ msgid "Protocol violation on socket. Expected command.\n" +#~ msgstr "Protokollverletzung auf Socket. Kommando erwartet.\n" + +#~ msgid "Start GNUnet testbed controller." +#~ msgstr "GNUnet testbed Controller starten." + +#~ msgid "Malformed entry in the configuration in section %s under %s: %s\n" +#~ msgstr "" +#~ "Beschädigter Eintrag in der Konfigurationsdatei in Sektion %s unter %s: " +#~ "%s\n" + +#~ msgid "Could not send acknowledgement back to client.\n" +#~ msgstr "Bestätigung konnte nicht an Client zurück gesendet werden.\n" + +#~ msgid "size of `%s' message is wrong. Ignoring.\n" +#~ msgstr "Größe der `%s' Nachricht ist falsch. Nachricht wird ignoriert.\n" + +#~ msgid "TESTBED could not generate hello message for protocol %u\n" +#~ msgstr "" +#~ "Das TESTBED konnte keine Hello Nachricht für das Protokoll %u erzeugen\n" + +#~ msgid "received invalid `%s' message\n" +#~ msgstr "ungültige `%s' Nachricht empfangen\n" + +#~ msgid "received invalid `%s' message (empty module name)\n" +#~ msgstr "ungültige `%s' Nachricht empfangen (leerer Modulname)\n" + +#~ msgid "loading module `%s' failed. Notifying client.\n" +#~ msgstr "das Laden von Modul `%s' schlug fehl. Client wird benachrichtigt.\n" + +#~ msgid "unloading module failed. Notifying client.\n" +#~ msgstr "das Entladen des Moduls schlug fehl. Client wird benachrichtigt.\n" + +#~ msgid "received invalid `%s' message: %s.\n" +#~ msgstr "ungültige `%s' Nachricht empfangen: %s.\n" + +#~ msgid "'..' is not allowed in file name (%s).\n" +#~ msgstr "'..' ist nicht erlaubt in einem Dateinamen (%s).\n" + +#~ msgid "Empty filename for UPLOAD_FILE message is invalid!\n" +#~ msgstr "Leerer Dateiname für UPLOAD_FILE Nachricht ist ungültig!\n" + +#~ msgid "Filename for UPLOAD_FILE message is not null-terminated (invalid!)\n" +#~ msgstr "" +#~ "Dateiname für UPLOAD_FILE Nachricht ist nicht Null-terminiert " +#~ "(ungültig!)\n" + +#~ msgid "Invalid message received at %s:%d." +#~ msgstr "Ungültige Nachricht empfangen bei %s:%d." + +#~ msgid "received invalid testbed message of size %u\n" +#~ msgstr "ungültige Testbed Nachricht der Größe %u empfangen\n" + +#~ msgid "" +#~ "Received testbed message of type %u but unexpected size %u, expected %u\n" +#~ msgstr "" +#~ "Empfangene Testbed Nachricht des Typs %u hat die unerwartete Größe %u, es " +#~ "wurde %u erwartet\n" + +#~ msgid "No testbed URL given, not registered.\n" +#~ msgstr "" +#~ "Keine Testbed URL angegeben, es wurde keine Registrierung vorgenommen.\n" + +#~ msgid "Could not resolve name of HTTP proxy `%s'.\n" +#~ msgstr "Der Name des HTTP Proxies `%s' konnte nicht aufgelöst werden.\n" + +#~ msgid "Malformed http URL: `%s' at `%s'. Testbed-client not registered.\n" +#~ msgstr "" +#~ "Beschädigte HTTP URL: `%s' bei `%s'. Testbed-Client wurde nicht " +#~ "registriert.\n" + +#~ msgid "Could not register testbed, host `%s' unknown\n" +#~ msgstr "" +#~ "Testbed konnte nicht registriert werden, Host `%s' ist nicht bekannt.\n" + +#~ msgid "Failed to send HTTP request to host `%s': %s\n" +#~ msgstr "HTTP Anfrage konnte nicht an Host `%s' gesendet werden: %s\n" + +#~ msgid "Failed so send HTTP request `%s' to host `%s': %s\n" +#~ msgstr "Fehler beim Senden der HTTP Anfrage `%s' an Host `%s': %s\n" + +#~ msgid "Exit register (error: no http response read).\n" +#~ msgstr "Abbruch der Registrierung (Fehler: keine HTTP Antwort gelesen).\n" + +#~ msgid "allows construction of a P2P-testbed (incomplete)" +#~ msgstr "Ermöglicht die Konstruktion einer P2P-Testumgebung (inkomplett)" + +#, fuzzy +#~ msgid "`%s' failed at %s:%d in %s with error: %s\n" +#~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#~ msgid "GNUnet configuration assistant" +#~ msgstr "GNUnet Konfigurationsassistent" + +#, fuzzy +#~ msgid "" +#~ "Welcome to GNUnet!\n" +#~ "\n" +#~ "This assistant will ask you a few basic questions in order to configure " +#~ "GNUnet.\n" +#~ "\n" +#~ "Please visit our homepage at\n" +#~ "\thttp://gnunet.org\n" +#~ "and join our community at\n" +#~ "\thttps://gnunet.org/drupal/\n" +#~ "\n" +#~ "Have a lot of fun,\n" +#~ "\n" +#~ "The GNUnet team" +#~ msgstr "" +#~ "Willkommen bei GNUnet!\n" +#~ "\n" +#~ "Dieser Assistent wird Ihnen einige grundlegende Fragen stellen, um GNUnet " +#~ "zu konfigurieren.\n" +#~ "\n" +#~ "Bitte besuchen Sie unsere Homepage\n" +#~ "\thttp://gnunet.org\n" +#~ "und schließen Sie sich unserer Community an:\n" +#~ "\thttps://gnunet.org/drupal/\n" +#~ "\n" +#~ "Viel Spaß,\n" +#~ "\n" +#~ "das GNUnet-Team" + +#~ msgid "Next" +#~ msgstr "Weiter" + +#~ msgid "" +#~ "Enter information about your network connection here.\n" +#~ "\n" +#~ "The \"Network interface\" is the device that connects your computer to " +#~ "the internet. This is usually a modem, an ISDN card or a network card in " +#~ "case you are using DSL.\n" +#~ "\n" +#~ "If your provider always assigns the same IP-Address to you (a \"static\" " +#~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " +#~ "changes every now and then (\"dynamic\" IP-Address) but there's a " +#~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " +#~ "you can also enter it here.\n" +#~ "If in doubt, leave the field empty. GNUnet will then try to determine " +#~ "your IP-Address.\n" +#~ "\n" +#~ "If you are connected to the internet through another computer doing SNAT, " +#~ "a router or a \"hardware firewall\" and other computers on the internet " +#~ "cannot connect to this computer, check the last option on this page. " +#~ "Leave it unchecked on direct connections through modems, ISDN cards and " +#~ "DNAT (also known as \"port forwarding\")." +#~ msgstr "" +#~ "Geben Sie hier Ihre Netzwerkinformationen ein.\n" +#~ "\n" +#~ "Das \"Netzwerkgerät\" ist das Gerät, das Ihren Computer mit dem Internet " +#~ "verbindet. Dies ist normalerweise ein Modem, eine ISDN-Karte oder eine " +#~ "Netzwerkkarte für den Fall, dass Sie DSL benutzen.\n" +#~ "\n" +#~ "Wenn Ihnen Ihr Provider immer die gleiche IP-Adresse zuweist (eine " +#~ "\"statische\" IP-Adresse), geben Sie diese in das \"IP-Adresse\"-Feld " +#~ "ein. Wenn Ihre IP-Adresse sich hin und wieder ändert (\"dynamische\" IP-" +#~ "Adresse), es jedoch einen Hostnamen gibt, der immer auf Ihre aktuelle IP-" +#~ "Adresse zeigt (\"Dynamisches DNS\"), so können Sie ihn auch eingeben.\n" +#~ "Im Zweifel lassen Sie das Feld leer. GNUnet wird dann versuchen, die IP-" +#~ "Adresse automatisch zu bestimmen.\n" +#~ "\n" +#~ "Wenn Sie nicht direkt mit dem Internet verbunden sind, sondern dies über " +#~ "einen anderen Rechner mit SNAT, einem Router oder einer \"Hardware " +#~ "Firewall\" geschieht und andere Computer im Internet keine Verbindung mit " +#~ "diesem Computer herstellen können, so aktivieren Sie die letzte Option " +#~ "auf dieser Seite. Lassen Sie sie jedoch deaktiviert, wenn Sie eine " +#~ "direkte Verbindung über ein Modem, eine ISDN-Karte oder einen anderen " +#~ "Rechner mit DNAT (auch bekannt als \"Port forwarding\") zum Internet " +#~ "haben." + +#~ msgid "Computer cannot receive inbound connections (SNAT/Firewall)" +#~ msgstr "" +#~ "Computer kann keine ankommenden Verbindungen akzeptieren (SNAT/Firewall)" + +#~ msgid "IP-Address/Hostname:" +#~ msgstr "IP-Adresse/Hostname:" + +#, fuzzy +#~ msgid "Network interface:" +#~ msgstr "Netzwerkgerät:" + +#~ msgid "" +#~ "You can limit GNUnet's ressource usage here.\n" +#~ "\n" +#~ "\"Bandwidth limitation\" is how much data may be sent per second. If you " +#~ "have a flatrate you can set it to the maximum speed of your internet " +#~ "connection.\n" +#~ "\n" +#~ "The \"Max. CPU usage\" is the percentage of processor time GNUnet is " +#~ "allowed to use." +#~ msgstr "" +#~ "Hier können Sie GNUnet's Ressourcennutzung einschränken.\n" +#~ "\n" +#~ "\"Bandbreitenbeschränkung\" gibt an, wieviele Daten maximal pro Sekunde " +#~ "übetragen werden dürfen. Wenn Sie eine Flatrate haben, können Sie diese " +#~ "Werte auf die maximal erreichbare Geschwindigkeit Ihrer " +#~ "Internetverbindung setzen.\n" +#~ "\n" +#~ "Die \"Max. CPU Nutzung\" gibt den Prozentsatz an CPU-Zeit an, den GNUnet " +#~ "für sich verwenden darf." + +#~ msgid "Downstream (Bytes/s):" +#~ msgstr "Downstream (Bytes/s):" + +#~ msgid "Upstream (Bytes/s):" +#~ msgstr "Upstream (Bytes/s):" + +#~ msgid "Bandwidth limitation" +#~ msgstr "Bandbreitenbeschränkung" + +#~ msgid "Use denoted bandwidth for GNUnet" +#~ msgstr "Angegebene Bandbreite für GNUnet verwenden" + +#~ msgid "Share denoted bandwidth with other applications" +#~ msgstr "Angegebene Bandbreite mit anderen Anwendungen teilen" + +#~ msgid "Bandwidth sharing" +#~ msgstr "Aufteilung der Bandbreite" + +#~ msgid "Max. CPU usage (%):" +#~ msgstr "Max. CPU Nutzung (%):" + +#~ msgid "CPU usage" +#~ msgstr "CPU Nutzung" + +#~ msgid "Load limitation" +#~ msgstr "Lastbeschränkung" + +#~ msgid "" +#~ "GNUnet is able to store data from other peers in your datastore. This is " +#~ "useful if an adversary has access to your inserted content and you need " +#~ "to deny that the content is yours. With \"content migration\" on, the " +#~ "content could have \"migrated\" over the internet to your node without " +#~ "your knowledge.\n" +#~ "It also helps to spread popular content over different peers to enhance " +#~ "availability.\n" +#~ "\n" +#~ "The GNUnet datastore contains all data that GNUnet generates (index data, " +#~ "inserted and migrated content). Its maximum size can be specified below.\n" +#~ "\n" +#~ "If you are an experienced user, you may want to tweak your GNUnet " +#~ "installation using the enhanced configurator.\n" +#~ "\n" +#~ "After changing the configuration and/or updating GNUnet, it is sometimes " +#~ "required to run gnunet-update to update internal data structures. " +#~ "Depending on the changes made, this may take some time." +#~ msgstr "" +#~ "GNUnet ist in der Lage, Daten von anderen Knoten in Ihrem Datenspeicher " +#~ "zu speichern. Das ist nützlich, wenn ein Widersacher Zugriff auf Ihre " +#~ "eingefügten Inhalte erlangt und Sie abstreiten müssen, dass diese Daten " +#~ "Ihnen gehören. Mit \"Inhaltsmigration\" angeschaltet können die Inhalte " +#~ "über das Internet von einem anderen Knoten zu Ihrem Rechner ohne Ihr " +#~ "Wissen \"gewandert\" sein.\n" +#~ "Außerdem hilft es, beliebte Inhalte über verschiedene Netzteilnehmer zu " +#~ "verteilen, um so die Verfügbarkeit zu erhöhen.\n" +#~ "\n" +#~ "Der GNUnet Datenspeicher enthält alle Daten, die GNUnet erzeugt " +#~ "(Indexdaten, eingefügte und migrierte Inhalte). Seine maximale Größe kann " +#~ "unten angegeben werden.\n" +#~ "\n" +#~ "Wenn Sie ein fortgeschrittener Benutzer sind, möchten Sie vielleicht " +#~ "weitere Feinjustierungen an GNUnet über den \"erweiterten Konfigurator\" " +#~ "vornehmen.\n" +#~ "Nachdem die Konfiguration verändert und/oder GNUnet upgedated wurde ist " +#~ "es manchmal nötig, gnunet-update auszuführen, um interne Datenstrukturen " +#~ "zu aktualisieren. Abhängig von den gemachten Änderungen kann dies etwas " +#~ "Zeit in Anspruch nehmen." + +#~ msgid "Store migrated content" +#~ msgstr "Migrierte Inhalte speichern" + +#~ msgid "Maximum datastore size (MB):" +#~ msgstr "Maximale Größe des Datenspeichers (MB):" + +#~ msgid "Start the GNUnet background process on computer startup" +#~ msgstr "" +#~ "GNUnet Hintergrundprozeß beim Starten des Computers automatisch starten" + +#~ msgid "Open the enhanced configurator" +#~ msgstr "Erweiterten Konfigurator starten" + +#, fuzzy +#~ msgid "Run gnunet-update" +#~ msgstr "gnunet-update schlug fehlt!" + +#, fuzzy +#~ msgid "Other settings" +#~ msgstr "Weitere Einstellungen" + +#~ msgid "Finish" +#~ msgstr "Fertigstellen" + +#~ msgid "" +#~ "Define the user and the group owning the GNUnet service here.\n" +#~ "\n" +#~ "For security reasons, it is a good idea to let this setup create a new " +#~ "user account and a new group under which the GNUnet service is started at " +#~ "system startup.\n" +#~ "\n" +#~ "However, GNUnet may not be able to access files other than its own. This " +#~ "includes files you want to publish in GNUnet. You'll have to grant read " +#~ "permissions to the user specified below.\n" +#~ "\n" +#~ "Leave the fields empty to run GNUnet with system privileges." +#~ msgstr "" +#~ "Geben Sie den Benutzer und die Gruppe an, der der GNUnet Dienst gehören " +#~ "soll.\n" +#~ "\n" +#~ "Aus Sicherheitsgründen ist es eine gute Idee, dieses Setup ein neues " +#~ "Benutzerkonto und eine neue Gruppe anlegen zu lassen, unter der der " +#~ "GNUnet Dienst beim Systemstart läuft.\n" +#~ "\n" +#~ "Natürlich kann GNUnet dann nur auf seine eigenen Dateien zugreifen. Dies " +#~ "betrifft auch Dateien, die Sie im GNUnet veröffentlichen möchten. Sie " +#~ "müssen dann dem unten angegebenen Benutzerkonto zuerst Leseberechtigungen " +#~ "geben.\n" +#~ "\n" +#~ "Lassen Sie dieses Feld leer, wenn Sie GNUnet mit Systemprivilegien laufen " +#~ "lassen möchten." + +#~ msgid "User account:" +#~ msgstr "Benutzerkonto:" + +#~ msgid "Group:" +#~ msgstr "Gruppe:" + +#, fuzzy +#~ msgid "gnunet-setup" +#~ msgstr "gnunet-update ausführen" + +#, fuzzy +#~ msgid "Save configuration" +#~ msgstr "GNUnet Konfiguration" + +#, fuzzy +#~ msgid "Show copyright information for gnunet-setup." +#~ msgstr "Fehler beim Lesen von Informationen von gnunetd.\n" + +#, fuzzy +#~ msgid "About gnunet-setup" +#~ msgstr "gnunet-update ausführen" + +#, fuzzy +#~ msgid "This is the configuration tool for GNUnet." +#~ msgstr "" +#~ "Einen Wert aus der Konfigurationsdatei auf der Standardausgabe ausgeben" + +#~ msgid "Not for English ;-)" +#~ msgstr "Nils Durner and Christian Grothoff" + +#, fuzzy +#~ msgid "Description" +#~ msgstr "Frage" + +#, fuzzy +#~ msgid "Section" +#~ msgstr "Frage" + +#, fuzzy +#~ msgid "Option" +#~ msgstr "_Optionen" + +#~ msgid "TRACEKIT: routing table full, trace request dropped\n" +#~ msgstr "TRACEKIT: Routing-Tabelle ist voll, Trace-Anfrage wird verworfen\n" + +#~ msgid "TRACEKIT: received invalid `%s' message\n" +#~ msgstr "TRACEKIT: ungültige `%s' Nachricht empfangen\n" + +#~ msgid "Format specification invalid. Use 0 for user-readable, 1 for dot\n" +#~ msgstr "" +#~ "Formatangabe ungültig. Verwenden Sie 0 für menschen-lesbar und 1 für dot\n" + +#~ msgid "Peer `%s' did not report back.\n" +#~ msgstr "Knoten `%s' hat sich nicht zurückgemeldet.\n" + +#~ msgid "" +#~ "You must specify the name of a pipe for the SMTP transport in section `" +#~ "%s' under `%s'.\n" +#~ msgstr "" +#~ "Für den SMTP Transport müssen Sie den Namen einer Pipe in Sektion `%s', " +#~ "Eintrag `%s' eintragen.\n" + +#~ msgid "Sending E-mail to `%s' failed.\n" +#~ msgstr "Das Senden einer E-Mail an `%s' schlug fehl.\n" + +#~ msgid "%.*s filter %s (SMTP)" +#~ msgstr "%.*s filter %s (SMTP)" + +#~ msgid "MTU for `%s' is probably too low (fragmentation not implemented!)\n" +#~ msgstr "" +#~ "MTU für `%s' ist möglicherweise zu gering (Fragmentierung ist nicht " +#~ "implementiert!)\n" + +#, fuzzy +#~ msgid "Network configuration: NAT" +#~ msgstr "GNUnet Konfiguration" + +#~ msgid "" +#~ "Is this machine behind NAT?\n" +#~ "\n" +#~ "If you are connected to the internet through another computer doing SNAT, " +#~ "a router or a \"hardware firewall\" and other computers on the internet " +#~ "cannot connect to this computer, say \"yes\" here. Answer \"no\" on " +#~ "direct connections through modems, ISDN cards and DNAT (also known as " +#~ "\"port forwarding\")." +#~ msgstr "" +#~ "Ist diese Maschine hinter NAT?\n" +#~ "\n" +#~ "Wenn Sie mit dem Internet über einen anderen Computer per SNAT, einem " +#~ "Router oder einer \"Hardware Firewall\" verbunden sind und andere " +#~ "Computer im Internet keine Verbindung zu diesem Computer herstellen " +#~ "können, so sagen Sie hier \"Ja\". Antworten Sie \"Nein\" bei direkten " +#~ "Verbindungen über Modem, ISDN-Karten und DNAT (auch bekannt als \"Port " +#~ "forwarding\")." + +#, fuzzy +#~ msgid "Configuration of the logging system" +#~ msgstr "" +#~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " +#~ "ausführen!\n" + +#, fuzzy +#~ msgid "Run gnunetd as this user." +#~ msgstr "gnunet-update ausführen" + +#, fuzzy +#~ msgid "Run gnunetd during system startup?" +#~ msgstr "gnunet-update ausführen" + +#, fuzzy +#~ msgid "Path settings" +#~ msgstr "Weitere Einstellungen" + +#~ msgid "specify nickname" +#~ msgstr "Spitznamen angeben" + +#~ msgid "Start GNUnet chat client." +#~ msgstr "GNUnet chat client starten" + +#~ msgid "You must specify a nickname (use option `%s').\n" +#~ msgstr "" +#~ "Sie müssen einen Spitznamen angeben (verwenden Sie die Option `%s').\n" + +#~ msgid "Could not send message to gnunetd\n" +#~ msgstr "Nachricht konnte nicht an gnunetd gesendet werden.\n" + +#~ msgid "mysql datastore" +#~ msgstr "mysql Datenspeicher" + +#, fuzzy +#~ msgid "" +#~ "`%s' failed at %s:%d with error: I/%s S/%s SC/%s SS/%s SSC/%s U/%s D/%s " +#~ "DG/%s\n" +#~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" + +#~ msgid "Database failed to delete `%s'.\n" +#~ msgstr "Die Datenbank konnte `%s' nicht löschen.\n" + +#, fuzzy +#~ msgid "Error log:\n" +#~ msgstr "Fehler" + +#, fuzzy +#~ msgid "# bytes received via TCP-OLD" +#~ msgstr "# Bytes empfangen über TCP" + +#, fuzzy +#~ msgid "# bytes sent via TCP-OLD" +#~ msgstr "# Bytes gesendet über TCP" + +#, fuzzy +#~ msgid "# bytes dropped by TCP-OLD (outgoing)" +#~ msgstr "# Bytes verworfen von TCP (ausgehend)" + +#~ msgid "hello advertisement for protocol %d received.\n" +#~ msgstr "Hello Ankündigung für Protokoll %d empfangen.\n" + +#~ msgid "`%s' failed (%d, %u). Will not send PING.\n" +#~ msgstr "`%s' fehlgeschlagen (%d, %u). PING wird nicht gesendet.\n" + +#~ msgid "Removing hello from peer `%s' (expired %ds ago).\n" +#~ msgstr "Hello von Knoten `%s' wird entfernt (lief vor %ds ab).\n" + +#~ msgid "Waiting for gnunetd to start (%u iterations left)...\n" +#~ msgstr "Warte auf den Start von gnunetd (%u Iterationen verbleiben)...\n" + +#, fuzzy +#~ msgid "Deleting expired content. This may take a while.\n" +#~ msgstr "Ein neuer Hostkey wird erzeugt (dies kann eine Weile dauern).\n" + +#~ msgid "User `%s' not known, cannot change UID to it.\n" +#~ msgstr "" +#~ "Benutzer `%s' ist nicht bekannt, UID kann nicht gewechselt werden.\n" + +#~ msgid "" +#~ "Expected welcome on http connection, got garbage. Closing connection.\n" +#~ msgstr "" +#~ "Es wurde eine Willkommensnachricht erwartet, tatsächlich wurde jedoch " +#~ "keine gesendet. HTTP-Verbindung wird geschlossen.\n" + +#~ msgid "%s: Rejected connection from blacklisted address %u.%u.%u.%u.\n" +#~ msgstr "" +#~ "%s: Abgewiesene Verbindung von schwarzgelisteter Adresse %u.%u.%u.%u.\n" + +#~ msgid "" +#~ "Could not bind the HTTP listener to port %d. No transport service " +#~ "started.\n" +#~ msgstr "" +#~ "HTTP-Listener konnte nicht an Port %d gebunden werden. Der Transport " +#~ "Dienst wurde nicht gestartet.\n" + +#~ msgid "Unexpected reply to `%s' operation.\n" +#~ msgstr "Unerwartete Antwort zu `%s' Operation.\n" + +#~ msgid "join table called NAME" +#~ msgstr "Tabelle NAME anschließen" + +#~ msgid "Malformed optional field `%s' received from peer `%s'.\n" +#~ msgstr "Ungültiges optionales Feld `%s' empfangen von Knoten `%s'.\n" + +#~ msgid "Malformed response to `%s' on master table.\n" +#~ msgstr "Beschädigte Antwort auf `%s' in Master Tabelle.\n" + +#~ msgid "Invalid response to `%s' from `%s'\n" +#~ msgstr "Ungültige Antwort auf `%s' von `%s'\n" + +#~ msgid "Received invalid RPC `%s'.\n" +#~ msgstr "Ungültiger RPC `%s' empfangen.\n" + +#~ msgid "RPC for `%s' received for table that we do not participate in!\n" +#~ msgstr "" +#~ "RPC für `%s' empfangen für eine Tabelle, an der wir nicht beteiligt " +#~ "sind!\n" + +#~ msgid "`%s' failed. Terminating connection to client.\n" +#~ msgstr "`%s' fehlgeschlagen. Beende Verbindung zu Client.\n" + +#~ msgid "" +#~ "`%s' called with cron job not in queue, adding. This may not be what you " +#~ "want.\n" +#~ msgstr "" +#~ "`%s' aufgerufen wobei Cron Job nicht Warteschlange ist. Er wird " +#~ "hinzugefügt. Das ist möglicherweise nicht, was Sie wollen.\n" + +#~ msgid "" +#~ "Share denoted bandwidth with other applications?\n" +#~ "\n" +#~ "Say \"yes\" here, if you don't want other network traffic to interfere " +#~ "with GNUnet's operation, but still wish to constrain GNUnet's bandwidth " +#~ "usage to values entered in the previous steps, or if you can't reliably " +#~ "measure the maximum capabilities of your connection. \"No\" can be very " +#~ "useful if other applications are causing a lot of traffic on your LAN. " +#~ "In this case, you do not want to limit the traffic that GNUnet can " +#~ "inflict on your internet connection whenever your high-speed LAN gets " +#~ "used (e.g. by NFS)." +#~ msgstr "" +#~ "Angegebene Bandbreite mit anderen Anwendungen teilen?\n" +#~ "\n" +#~ "Sagen Sie hier \"Ja\", wenn Sie nicht möchten, dass anderer " +#~ "Netzwerkverkehr GNUnets Funktion stört aber dennoch GNUnets Bandbreite " +#~ "gemäß den Angaben in den vorherigen Schritten einschränken möchten oder " +#~ "Sie die maximalen Möglichkeiten Ihrer Internetverbindung nicht " +#~ "zuverlässig messen können. \"Nein\" kann nützlich sein, wenn andere " +#~ "Anwendungen viel Netzwerkverkehr in Ihrem LAN verursachen. In diesem Fall " +#~ "möchten Sie nicht GNUnets Netzwerkverkehr über die Internetverbindung " +#~ "einschränken, wann immer Ihre Hochgeschwindigkeits-LAN-Verbindung " +#~ "verwendet wird (z.B. durch NFS)." + +#~ msgid "How much CPU (in %) may be used?" +#~ msgstr "Wieviel CPU (in %) darf verwendet werden?" + +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "This is the percentage of processor time GNUnet is allowed to use." +#~ msgstr "" +#~ "Hier können Sie GNUnets Ressourcenverwendung einschränken.\n" +#~ "\n" +#~ "Dies ist der Prozentsatz an Prozessorzeit, den GNUnet verwenden darf." + +#~ msgid "" +#~ "Store migrated content?\n" +#~ "\n" +#~ "GNUnet is able to store data from other peers in your datastore. This is " +#~ "useful if an adversary has access to your inserted content and you need " +#~ "to deny that the content is yours. With \"content migration\" on, the " +#~ "content could have \"migrated\" over the internet to your node without " +#~ "your knowledge.\n" +#~ "It also helps to spread popular content over different peers to enhance " +#~ "availability." +#~ msgstr "" +#~ "Sollen migrierte Inhalte gespeichert werden?\n" +#~ "GNUnet ist in der Lage, Daten von anderen Knoten in Ihrem Datenspeicher " +#~ "zu speichern. Das ist nützlich, wenn ein Widersacher Zugriff auf Ihre " +#~ "eingefügten Inhalte erlangt und Sie abstreiten müssen, dass diese Daten " +#~ "Ihnen gehören. Ist die \"Inhaltsmigration\" angeschaltet, so können die " +#~ "Inhalte über das Internet von einem anderen Knoten zu Ihrem Rechner ohne " +#~ "Ihr Wissen \"gewandert\" sein.\n" +#~ "Außerdem hilft es, beliebte Inhalte über verschiedene Netzteilnehmer zu " +#~ "verteilen, um so die Verfügbarkeit zu erhöhen." + +#~ msgid "" +#~ "If you are an experienced user, you may want to tweak your GNUnet " +#~ "installation using the enhanced configurator.\n" +#~ "\n" +#~ "Do you want to start it after saving your configuration?" +#~ msgstr "" +#~ "Wenn Sie ein erfahrener Benutzer sind, so möchten Sie vielleicht Ihre " +#~ "GNUnet Installation über den erweiterten Konfigurator optimieren.\n" +#~ "\n" +#~ "Möchten Sie ihn starten, nachdem Ihre Konfiguration gespeichert wurde?" + +#~ msgid "" +#~ "Unable to save configuration file %s: %s.\n" +#~ "\n" +#~ "Try again?" +#~ msgstr "" +#~ "Konfigurationsdatei %s kann nicht gespeichert werden: %s.\n" +#~ "\n" +#~ "Soll es nochmals versucht werden?" + +#~ msgid "Failed to send `%s'. Closing connection.\n" +#~ msgstr "Fehler beim Senden von `%s'. Verbindung wird geschlossen.\n" + +#~ msgid "Received invalid `%s' request (size %d)\n" +#~ msgstr "Ungültige Anfrage `%s' empfangen (Größe %d)\n" + +#~ msgid "Received invalid `%s' request (wrong table)\n" +#~ msgstr "Ungültige Anfrage `%s' empfangen (falsche Tabelle)\n" + +#~ msgid "Received unknown request type %d at %s:%d\n" +#~ msgstr "Unbekannte Anfrageart %d empfangen bei %s:%d\n" + +#~ msgid "This client already participates in the given DHT!\n" +#~ msgstr "Dieser Client beteiligt sich bereits an der angegebenen DHT!\n" + +#~ msgid "Cannot leave DHT: table not known!\n" +#~ msgstr "DHT kann nicht verlassen werden: Tabelle unbekannt!\n" + +#~ msgid "gnunetd signaled error in response to `%s' message\n" +#~ msgstr "gnunetd gab in Bezug auf die `%s' Nachricht einen Fehler zurück.\n" + +#~ msgid "Failed to send `%s' message to gnunetd\n" +#~ msgstr "Fehler beim Senden der `%s' Nachricht an gnunetd\n" + +#~ msgid "Join a DHT." +#~ msgstr "Einer DHT anschließen." + +#~ msgid "allow SIZE bytes of memory for the local table" +#~ msgstr "SIZE bytes an Speicher für die lokale Tabelle erlauben" + +#~ msgid "Call to `%s' with value '%.*s' (%d bytes).\n" +#~ msgstr "Aufruf von `%s' mit Wert '%.*s' (%d Bytes).\n" + +#~ msgid "Error joining DHT.\n" +#~ msgstr "Fehler beim Beitreten zu der DHT.\n" + +#~ msgid "Joined DHT. Press CTRL-C to leave.\n" +#~ msgstr "Der DHT beigetreten. Drücken Sie STRG-C, um sie zu verlassen.\n" + +#~ msgid "`%s' failed: table not found!\n" +#~ msgstr "`%s' fehlgeschlagen: Tabelle nicht gefunden!\n" + +#~ msgid "sendAck failed. Terminating connection to client.\n" +#~ msgstr "sendAck fehlgeschlagen. Beende Verbindung zu Client.\n" + +#, fuzzy +#~ msgid "Upload failed (consult logs)." +#~ msgstr "ECRS Download schlug fehl (siehe Protokolldateien)." + +#~ msgid "Could not resolve name of SMTP server `%s': %s" +#~ msgstr "Der Name des SMTP servers `%s' konnte nicht aufgelöst werden: %s" + +#~ msgid "SMTP server send unexpected response at %s:%d.\n" +#~ msgstr "Der SMTP server sendete eine unerwartete Antwort bei %s:%d.\n" + +#~ msgid "" +#~ "SMTP server failed to respond with 250 confirmation code to `%s' " +#~ "request.\n" +#~ msgstr "" +#~ "SMTP Server antwortete nicht mit einem 250 Bestätigungscode auf eine `%s' " +#~ "Anfrage.\n" + +#~ msgid "query table called NAME" +#~ msgstr "Frage Tabelle mit dem Namen NAME ab" + +#~ msgid "No commands specified.\n" +#~ msgstr "Keine Kommandos angegeben.\n" + +#~ msgid "Superflous arguments (ignored).\n" +#~ msgstr "überflüssige Parameter (werden ignoriert).\n" + +#~ msgid "Query `%s' had no results.\n" +#~ msgstr "Abfrage `%s' hatte keine Ergebnisse.\n" + +#~ msgid "FSUI persistence: error restoring download\n" +#~ msgstr "FSUI Beständigkeit: Fehler beim Wiederherstellen des Downloads\n" + +#~ msgid "ECRS download suspending." +#~ msgstr "ECRS download wird eingefroren." + +#~ msgid "Upload failed." +#~ msgstr "Upload fehlgeschlagen." + +#~ msgid "Cannot upload directory without using recursion." +#~ msgstr "" +#~ "Verzeichnis kann nicht ohne die Verwendung von Rekursion hochgeladen " +#~ "werden." + +#, fuzzy +#~ msgid "expected `%s' to be a directory!\n" +#~ msgstr "`%s' erwartet, dass `%s' ein Verzeichnis ist!\n" + +#~ msgid "Sorry, no help is available for this option.\n" +#~ msgstr "Sorry, für diese Option steht keine Hilfe zur Verfügung.\n" + +#~ msgid "" +#~ "Cannot determine port to bind to. Define in configuration file in " +#~ "section `%s' under `%s' or in `%s' under %s/%s.\n" +#~ msgstr "" +#~ "Der Port, an dem Verbindungen entgegengenommen werden sollen, konnte " +#~ "nicht ermittelt werden. Bitte definieren Sie ihn in der " +#~ "Konfigurationsdatei in der Sektion `%s' unter `%s' oder in `%s' unter %s/" +#~ "%s.\n" + +#, fuzzy +#~ msgid "UDP6: select returned, but ioctl reports %d bytes available!\n" +#~ msgstr "" +#~ "UDP: select kam zurück aber ioctl berichtet, dass 0 Bytes verfügbar " +#~ "sind!\n" + +#~ msgid "Received invalid UDP6 message from %s:%d, dropping.\n" +#~ msgstr "" +#~ "Ungültige UDP6 Nachricht von %s:%d empfangen, Nachricht wird ignoriert.\n" + +#~ msgid "Packet received from %s:%d (UDP6) failed format check." +#~ msgstr "" +#~ "Die Formatüberprüfung des Pakets, das von %s:%d (UDP6) empfangen wurde, " +#~ "schlug fehl." + +#~ msgid "%s: Rejected connection from blacklisted address %s.\n" +#~ msgstr "%s: Zurückgewiesene Verbindung von schwarzgelisteter Adresse %s.\n" + +#~ msgid "" +#~ "Expected welcome message on tcp connection, got garbage (%u, %u). " +#~ "Closing.\n" +#~ msgstr "" +#~ "Es wurde eine Willkommensnachricht erwartet, über die TCP Verbindung " +#~ "wurde aber keine gesendet (%u, %u). Verbindung wird geschlossen.\n" + +#, fuzzy +#~ msgid "UDP: select returned, but ioctl reports %d bytes available!\n" +#~ msgstr "" +#~ "UDP: select kam zurück aber ioctl berichtet, dass 0 Bytes verfügbar " +#~ "sind!\n" + +#~ msgid "Received invalid UDP message from %u.%u.%u.%u:%u, dropping.\n" +#~ msgstr "" +#~ "Es wurde eine ungültige UDP Nachricht von %u.%u.%u.%u:%u empfangen, " +#~ "Nachricht wird ignoriert.\n" + +#~ msgid "Packet received from %u.%u.%u.%u:%u (UDP) failed format check.\n" +#~ msgstr "" +#~ "Ein Paket empfangen von %u.%u.%u.%u:%u (UDP) hat ein ungültiges Format.\n" + +#~ msgid "Expected welcome message on tcp connection, got garbage. Closing.\n" +#~ msgstr "" +#~ "Es wurde eine Willkommensnachricht erwartet, über die TCP Verbindung " +#~ "wurde jedoch keine gesendet. Verbindung wird geschlossen.\n" + +#~ msgid "" +#~ "Received malformed message from tcp6-peer connection. Closing " +#~ "connection.\n" +#~ msgstr "" +#~ "über die TCP6-Verbindung zu einem anderen Knoten wurde eine ungültige " +#~ "Nachricht empfangen. Verbindung wird geschlossen.\n" + +#~ msgid "Version mismatch (`%s' vs. '%*.s'), run gnunet-update!\n" +#~ msgstr "" +#~ "Versionen stimmen nicht überein (`%s' vs. '%*.s'), lassen Sie gnunet-" +#~ "update laufen!\n" + +#~ msgid "" +#~ "Configuration file must specify directory for storing FS data in section `" +#~ "%s' under `%s'.\n" +#~ msgstr "" +#~ "Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein " +#~ "Verzeichnis angeben, in dem FS Daten gespeichert werden.\n" + +#~ msgid "" +#~ "Configuration file must specify a directory for GNUnet to store per-peer " +#~ "data under %s%s\n" +#~ msgstr "" +#~ "Die Konfigurationsdatei muss unter %s%s ein Verzeichnis angeben, in dem " +#~ "GNUnet knotenspezifische Daten speichern kann.\n" + +#~ msgid "%s `%s' returned no known hosts!\n" +#~ msgstr "%s `%s' ergab keine bekannten Knoten!\n" + +#~ msgid "" +#~ "You should specify at least one transport service under option `%s' in " +#~ "section `%s'.\n" +#~ msgstr "" +#~ "Sie sollten mindestens einen Transport Dienst unter der Option `%s' in " +#~ "der Sektion `%s' angegeben.\n" + +#~ msgid "" +#~ "specify that the contents of the namespace are of the given MIMETYPE (use " +#~ "when creating a new pseudonym)" +#~ msgstr "" +#~ "Angeben, dass die Inhalte des Namespaces vom angegebenen MIMETYOE sind " +#~ "(zu verwenden, wenn ein neues Pseudonym erstellt wird)" + +#~ msgid "" +#~ "specify NAME to be the realname of the user controlling the namespace " +#~ "(use when creating a new pseudonym)" +#~ msgstr "" +#~ "NAME als den Realnamen des Benutzers angeben, der den Namespace verwaltet " +#~ "(zu verwenden, wenn ein neues Pseudonym erstellt wird)" + +#~ msgid "" +#~ "use DESCRIPTION to describe the content of the namespace (use when " +#~ "creating a new pseudonym)" +#~ msgstr "" +#~ "DESCRIPTION als Beschreibung der Inhalte des Namespaces verwenden (zu " +#~ "verwenden, wenn ein neues Pseudonym erstellt wird)" + +#~ msgid "" +#~ "specify the given URI as an address that contains more information about " +#~ "the namespace (use when creating a new pseudonym)" +#~ msgstr "" +#~ "die angegebene URI als die Adresse angeben, die weitere Informationen " +#~ "über den Namespace enthält (zu verwenden, wenn ein neues Pseudonym " +#~ "erstellt wird)" + +#~ msgid "%8u of %8u bytes deleted." +#~ msgstr "%8u von %8u Bytes gelöscht." + +#~ msgid "specify the file to delete from GNUnet (obligatory, file must exist)" +#~ msgstr "" +#~ "vom GNUnet zu löschende Datei angeben (obgligatorisch, Datei muss " +#~ "existieren)" + +#~ msgid "" +#~ "Remove file from GNUnet. The specified file is not removed\n" +#~ "from the filesystem but just from the local GNUnet datastore." +#~ msgstr "" +#~ "Datei auf GNUnet löschen. Die angegebene Datei wird nicht aus dem " +#~ "Dateisystem gelöscht, sondern aus dem lokalen GNUnet Datenspeicher." + +#~ msgid "You must specify a filename (option -f)\n" +#~ msgstr "Sie müssen eine Datei angeben (Option -f)\n" + +#~ msgid "" +#~ "Error deleting file %s.\n" +#~ "Probably a few blocks were already missing from the database.\n" +#~ msgstr "" +#~ "Fehler beim Löschen der Datei %s.\n" +#~ "Möglicherweise fehlen bereits einige wenige Datenblöcke in der " +#~ "Datenbank.\n" + +#~ msgid "gnunet-directory [OPTIONS] [FILENAMES]" +#~ msgstr "gnunet-directory [OPTIONEN] [DATEINAMEN]" + +#~ msgid "process directories recursively" +#~ msgstr "Verzeichnisse rekursiv bearbeiten" + +#~ msgid "You must pass a positive number to the `%s' option.\n" +#~ msgstr "Sie müssen eine positive Zahl zu der Option `%s' übergeben.\n" + +#~ msgid "Only one file or directory can be specified at a time.\n" +#~ msgstr "Nur eine Datei oder Verzeichnis kann auf einmal angegeben werden.\n" + +#~ msgid "You must specify a file or directory to upload.\n" +#~ msgstr "Sie müssen eine Datei oder Verzeichnis für den Upload angeben.\n" + +#~ msgid "Not enough arguments. You must specify a keyword or identifier.\n" +#~ msgstr "" +#~ "Nicht genügend Parameter. Sie müssen ein Schlüsselwort oder einen " +#~ "Bezeichner angeben.\n" + +#~ msgid "LEVEL" +#~ msgstr "GRAD" + +#~ msgid "FILENAME" +#~ msgstr "DATEINAME" + +#~ msgid "" +#~ "Configuration file must specify a directory for GNUnet to store per-peer " +#~ "data under %s%s.\n" +#~ msgstr "" +#~ "Die Konfigurationsdatei muss unter %s%s ein Verzeichnis für GNUnet " +#~ "angeben, in dem Knotenbezogene Daten gespeichert werden.\n" + +#~ msgid "Template for gnunet-clients." +#~ msgstr "Vorlage für gnunet-clients." + +#~ msgid "Invalid port \"%s\" in hostlist specification, trying port %d.\n" +#~ msgstr "Ungültiger Port \"%s\" in Angabe der Hostlist, versuche Port %d.\n" + +#~ msgid "Could not download list of peer contacts, host `%s' unknown.\n" +#~ msgstr "" +#~ "Die Liste mit Knotenkontakten konnte nicht heruntergeladen werden, Host `" +#~ "%s' ist unbekannt.\n" + +#~ msgid "Parsing HTTP response for URL `%s' failed.\n" +#~ msgstr "Das Parsen der HTTP Antwort für die URL `%s' schlug fehl.\n" + +#~ msgid "Could not resolve name of HTTP proxy `%s'. Trying without a proxy.\n" +#~ msgstr "" +#~ "Der Name des HTTP Proxies `%s' konnte nicht aufgelöst werden. Es wird " +#~ "ohne Proxy versucht.\n" + +#~ msgid "Did not receive reply from gnunetd about traffic conditions.\n" +#~ msgstr "Keine Antwort von gnunetd über die Netzwerkverkehrsbedingungen.\n" + +#~ msgid "" +#~ "Configuration file must specify a directory for GNUnet to store per-peer " +#~ "data under %s\\%s.\n" +#~ msgstr "" +#~ "Die Konfigurationsdatei muss unter %s\\%s ein Verzeichnis für GNUnet " +#~ "angeben, in dem knotenbezogene Daten gespeichert werden.\n" + +#~ msgid "Option `%s' makes no sense without option `%s'." +#~ msgstr "Option `%s' macht keinen Sinn ohne die Option `%s'." + +#~ msgid "" +#~ "\n" +#~ "Exiting.\n" +#~ msgstr "" +#~ "\n" +#~ "Abbruch.\n" + +#~ msgid "Updated data for %d applications.\n" +#~ msgstr "Daten für %d Anwendungen wurden aktualisiert.\n" + +#~ msgid "Argument %d: `%s'\n" +#~ msgstr "Parameter %d: `%s'\n" + +#~ msgid "`%s' starting\n" +#~ msgstr "`%s' startet\n" + +#~ msgid "FATAL: Identity plugin not found!\n" +#~ msgstr "SCHWERWIEGEND: Identity Plugin wurde nicht gefunden!\n" + +#~ msgid "You must specify a non-empty set of transports to test!\n" +#~ msgstr "" +#~ "Sie müssen eine Menge an Transporten angeben, die getestet werden " +#~ "sollen!\n" + +#~ msgid "Available MODEs:\n" +#~ msgstr "Verfügbare MODEs:\n" + +#~ msgid " config\t\ttext-based configuration\n" +#~ msgstr " config\t\ttext-basierte Konfiguration\n" + +#~ msgid " menuconfig\ttext-based menu\n" +#~ msgstr "menuconfig\ttext-basiertes Menü\n" + +#~ msgid " wizard-curses\tBasic text-based graphical configuration\n" +#~ msgstr " wizard-curses\tEinfache text-basierte grafische Konfiguration\n" + +#~ msgid "" +#~ " wizard-gtk\tBasic GTK configuration\n" +#~ "\n" +#~ msgstr "" +#~ " wizard-gtk\tEinfache GTK Konfiguration\n" +#~ "\n" + +#~ msgid "gnunet-setup must have write-access to the configuration file `%s'\n" +#~ msgstr "" +#~ "gnunet-setup benötigt Schreibberechtigungen für die Konfigurationsdatei `" +#~ "%s'\n" + +#~ msgid "" +#~ "Can only run wizard to configure gnunetd.\n" +#~ "Did you forget the `%s' option?\n" +#~ msgstr "" +#~ "Der Assistent kann nur zur Einrichtung von gnunetd gestartet werden.\n" +#~ "Haben Sie die `%s'-Option vergessen?\n" + +#~ msgid "%s: symbol value `%s' invalid for %s\n" +#~ msgstr "%s: Symbolwert `%s' ist ungültig für %s\n" + +#~ msgid "Gtk GNUnet Configurator" +#~ msgstr "Gtk GNUnet Konfigurator" + +#~ msgid "_File" +#~ msgstr "_Datei" + +#~ msgid "_Load" +#~ msgstr "_öffnen" + +#~ msgid "Save the config in .config" +#~ msgstr "Die Konfiguration in .config speichern" + +#~ msgid "_Save" +#~ msgstr "_Speichern" + +#~ msgid "_Quit" +#~ msgstr "_Beenden" + +#~ msgid "Show _name" +#~ msgstr "_Name anzeigen" + +#~ msgid "Show range (Y/M/N)" +#~ msgstr "Bereich anzeigen (Y/M/N)" + +#~ msgid "Show _range" +#~ msgstr "_Bereich anzeigen" + +#~ msgid "Show _data" +#~ msgstr "_Daten anzeigen" + +#~ msgid "Show all _options" +#~ msgstr "Alle _Optionen anzeigen" + +#~ msgid "_Help" +#~ msgstr "_Hilfe" + +#~ msgid "_Introduction" +#~ msgstr "_Einführung" + +#~ msgid "Goes up of one level (single view)" +#~ msgstr "Bewegt sich eine Ebene nach oben (einfache Ansicht)" + +#~ msgid "Load" +#~ msgstr "Laden" + +#~ msgid "Save a config file" +#~ msgstr "Konfigurationsdatei speichern" + +#~ msgid "Save" +#~ msgstr "Speichern" + +#~ msgid "Single view" +#~ msgstr "Einfache Ansicht" + +#~ msgid "Single" +#~ msgstr "Einfach" + +#~ msgid "Split view" +#~ msgstr "Geteilte Ansicht" + +#~ msgid "Split" +#~ msgstr "Geteilt" + +#~ msgid "Full view" +#~ msgstr "Volle Ansicht" + +#~ msgid "Full" +#~ msgstr "Voll" + +#~ msgid "Collapse the whole tree in the right frame" +#~ msgstr "Den gesamten Baum im rechten Frame kollabieren" + +#~ msgid "Collapse" +#~ msgstr "Kollabieren" + +#~ msgid "Expand the whole tree in the right frame" +#~ msgstr "Den gesamten Baum im rechten Frame expandieren" + +#~ msgid "Expand" +#~ msgstr "Expandieren" + +#, fuzzy +#~ msgid "Introduction" +#~ msgstr "_Einführung" + +#~ msgid "inlining configration file `%s'\n" +#~ msgstr "Binde Konfigurationsdatei `%s' ein\n" + +#~ msgid "" +#~ "Configuration file not found. Please run GNUnet Setup (Client " +#~ "Configuration) first." +#~ msgstr "" +#~ "Die Konfigurationsdatei wurde nicht gefunden. Bitte führen Sie zuerst " +#~ "GNUnet Setup (Client Konfiguration) aus." + +#~ msgid "Configuration file `%s' not found. Run `gnunet-setup -d'!\n" +#~ msgstr "" +#~ "Konfigurationsdatei `%s' nicht gefunden. Bitte führen Sie `gnunet-setup -" +#~ "d' aus!\n" + +#~ msgid "Cron stopped\n" +#~ msgstr "Cron angehalten\n" + +#~ msgid "Caught signal %d.\n" +#~ msgstr "Signal %d empfangen.\n" + +#~ msgid "Invalid network notation (additional characters: `%s')." +#~ msgstr "Ungültige Netzwerk Notation (zusätzliche Zeichen: `%s')." + +#~ msgid "FAILURE" +#~ msgstr "FEHLSCHLAG" + +#~ msgid "MESSAGE" +#~ msgstr "MELDUNG" + +#~ msgid "CRON" +#~ msgstr "CRON" + +#~ msgid "EVERYTHING" +#~ msgstr "ALLES" + +#~ msgid "Invalid LOGLEVEL `%s' specified.\n" +#~ msgstr "Ungültiger LOGLEVEL `%s' angegeben.\n" + +#~ msgid "Failure at %s:%d.\n" +#~ msgstr "Fehler bei %s:%d.\n" + +#~ msgid "" +#~ "Cannot determine port of gnunetd server. Define in configuration file in " +#~ "section `%s' under `%s'.\n" +#~ msgstr "" +#~ "Der Port des gnunetd Servers konnte nicht ermittelt werden. Definieren " +#~ "Sie ihn in der Sektion `%s' unter `%s'.\n" + +#~ msgid "" +#~ "Usage: %s\n" +#~ "%s\n" +#~ "\n" +#~ msgstr "" +#~ "Verwendung: %s\n" +#~ "%s\n" +#~ "\n" + +#~ msgid "Invalid argument for `%s' at %s:%d.\n" +#~ msgstr "Ungültiger Parameter für `%s' bei %s:%d.\n" + +#~ msgid "g" +#~ msgstr "g" + +#~ msgid "t" +#~ msgstr "t" + +#~ msgid "`%s' failed, other side closed connection.\n" +#~ msgstr "" +#~ "`%s' fehlgeschlagen, die andere Seite hat die Verbindung geschlossen\n" + +#~ msgid "Attempted path to `%s' was `%s'.\n" +#~ msgstr "Versuchter Pfad für `%s' war `%s'.\n" + +#~ msgid "set verbosity to LEVEL" +#~ msgstr "Umfang der Meldungen auf LEVEL setzen" + +#~ msgid "_License" +#~ msgstr "_Lizenz" + +#~ msgid "Sorry, no help available for this option yet." +#~ msgstr "Sorry, für diese Option steht noch keine Hilfe zur Verfügung" + +#~ msgid "Couldn't find pixmap file: %s" +#~ msgstr "Pixmapdatei %s konnte nicht gefunden werden" + +#~ msgid "" +#~ "Welcome to GNUnet!\n" +#~ "\n" +#~ "This assistant will ask you a few basic questions in order to configure " +#~ "GNUnet.\n" +#~ "\n" +#~ "Please visit our homepage at\n" +#~ "\thttp://www.gnunet.org\n" +#~ "and join our community at\n" +#~ "\thttp://www.gnunet.org/drupal/\n" +#~ "\n" +#~ "Have a lot of fun,\n" +#~ "\n" +#~ "the GNUnet team" +#~ msgstr "" +#~ "Willkommen bei GNUnet!\n" +#~ "\n" +#~ "Dieser Assistent wird Ihnen einige grundlegende Fragen stellen, um GNUnet " +#~ "zu konfigurieren.\n" +#~ "\n" +#~ "Bitte besuchen Sie unsere Homepage\n" +#~ "\thttp://gnunet.org\n" +#~ "und schließen Sie sich unserer Community an:\n" +#~ "\thttps://gnunet.org/drupal/\n" +#~ "\n" +#~ "Viel Spaß,\n" +#~ "\n" +#~ "das GNUnet-Team" + +#~ msgid "" +#~ "You must specify a directory for FS files in the configuration in section " +#~ "`%s' under `%s'." +#~ msgstr "" +#~ "Sie müssen ein Verzeichnis für FS Dateien in der Konfigurationsdatei in " +#~ "der Sektion `%s' unter `%s' angeben." + +#~ msgid "Invalid data in MySQL database. Please verify integrity!\n" +#~ msgstr "" +#~ "Ungültige Daten in der MySQL Datenbank. Bitte überprüfen Sie die " +#~ "Integrität!\n" + +#~ msgid "SQL Database corrupt, ignoring result.\n" +#~ msgstr "SQL Datenbank beschädigt, Ergebnis wird ignoriert.\n" + +#~ msgid "Invalid data in database. Please verify integrity!\n" +#~ msgstr "" +#~ "Es befinden sich ungültige Daten in Datenbank. Bitte überprüfen Sie die " +#~ "Integrität!\n" + +#~ msgid "menuconfig is not available\n" +#~ msgstr " menuconfig ist nicht verfügbar\n" + +#~ msgid "wizard-curses is not available\n" +#~ msgstr "wizard-curses ist nicht verfügbar\n" + +#~ msgid "wizard-gtk is not available\n" +#~ msgstr "wizard-gtk ist nicht verfügbar\n" + +#~ msgid "gconfig is not available\n" +#~ msgstr "gconfig ist nicht verfügbar\n" + +#~ msgid "" +#~ "Indexing file `%s' failed. Check file permissions and consult your GNUnet " +#~ "server's logs.\n" +#~ msgstr "" +#~ "Indizierung der Datei `%s' schlug fehl. Bitte prüfen Sie die " +#~ "Dateiberechtigungen und ziehen Sie die Protokolldateien des GNUnet-" +#~ "Servers zu Rate.\n" + +#~ msgid "Show _debug info" +#~ msgstr "_Debug Informationen anzeigen" + +#~ msgid "" +#~ "USAGE: gnunet-setup MODULE\n" +#~ "\n" +#~ "MODULE\n" +#~ " recreate\trecreate configuration files\n" +#~ " config\t\ttext-based configuration\n" +#~ " menuconfig\ttext-based menu\n" +#~ " gconfig\tGTK configuration\n" +#~ " wizard-curses\tBasic text-based graphical configuration\n" +#~ " wizard-gtk\tBasic GTK configuration\n" +#~ "\n" +#~ msgstr "" +#~ "Verwendung: gnunet-setup MODUL\n" +#~ "\n" +#~ "MODUL\n" +#~ " recreate\tKonfigurationsdateien neu erzeugen\n" +#~ " config\t\tText-basierte Konfiguration\n" +#~ " menuconfig\tText-basiertes Menü\n" +#~ " gconfig\tGTK Konfiguration\n" +#~ " wizard-curses\tEinfache text-basierte grafische Konfiguration\n" +#~ " wizard-gtk\tEinfache GTK Konfiguration\n" +#~ "\n" + +#~ msgid "Please specify a path where the configuration files will be stored." +#~ msgstr "" +#~ "Bitte geben Sie den Pfad an, wohin die Konfigurationsdateien gespeichert " +#~ "werden." + +#~ msgid "Session with peer `%s' confirmed, but I cannot connect! (bug?)\n" +#~ msgstr "" +#~ "Sitzung mit Knoten `%s' ist bestätigt es kann jedoch nicht verbunden " +#~ "werden! (Bug?)\n" + +#~ msgid "LOGLEVEL not specified, that is not ok.\n" +#~ msgstr "LOGLEVEL wurde nicht angegeben, das ist nicht in Ordnung.\n" + +#~ msgid "" +#~ "Interfaces string (%s) in configuration section `%s' under `%s' is " +#~ "malformed.\n" +#~ msgstr "" +#~ "Geräteangabe (%s) in der Konfigurationssektion `%s' unter `%s' ist " +#~ "beschädigt.\n" + +#~ msgid "" +#~ "No network interfaces specified in the configuration file in section `%s' " +#~ "under `%s'.\n" +#~ msgstr "" +#~ "Es sind keine Netzwerkgeräte in der Konfigurationsdatei in der Sektion " +#~ "'%s' unter `%s' definiert.\n" + +#~ msgid "Failed to parse interface data `%s' output at %s:%d.\n" +#~ msgstr "Fehler beim Parsen der Gerätedaten `%s' Ausgabe bei %s:%d.\n" + +#~ msgid "Could not decoding file `%s' at %s:%d.\n" +#~ msgstr "Datei `%s' konnte nicht dekodiert werden bei %s:%d.\n" + +#~ msgid "" +#~ "Configuration file must specify directory for network identities in " +#~ "section %s under %s.\n" +#~ msgstr "" +#~ "Die Konfigurationsdatei muss in Sektion %s unter %s ein Verzeichnis für " +#~ "Identitäten angeben.\n" + +#~ msgid "Sender %u.%u.%u.%u is blacklisted, dropping message.\n" +#~ msgstr "" +#~ "Sender %u.%u.%u.%u steht auf schwarzer Liste, Nachricht wird ignoriert.\n" + +#~ msgid "Sender %s is blacklisted, dropping message.\n" +#~ msgstr "Sender %s steht auf schwarzer Liste, Nachricht wird ignoriert.\n" + +#~ msgid "Removed file `%s' containing invalid peer advertisement.\n" +#~ msgstr "" +#~ "Datei `%s' enthielt eine ungültige Knotenbekanntmachung und wurde " +#~ "entfernt.\n" + +#~ msgid "Removed invalid HELO file `%s'\n" +#~ msgstr "Ungültige HELO Datei `%s' wurde entfernt.\n" + +#~ msgid "Could not determine IP address of the local machine!\n" +#~ msgstr "IP-Adresse der lokalen Maschiene konnte nicht ermittelt werden!\n" + +#~ msgid "Could not determine IP(v6) address of the local machine!\n" +#~ msgstr "" +#~ "IP(v6)-Adresse der lokalen Maschiene konnte nicht ermittelt werden!\n" + +#~ msgid "" +#~ "Could not find IP(v6) for this host. Please provide the IP in the " +#~ "configuration file.\n" +#~ msgstr "" +#~ "IP(v6) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP " +#~ "in der Konfigurationsdatei an.\n" + +#~ msgid "Save _as" +#~ msgstr "Speichern _unter" + +#~ msgid "Save the config in a file" +#~ msgstr "Die Konfiguration in einer Datei speichern" + +#~ msgid "Error: can't open Service Control Manager: %s (%i)\n" +#~ msgstr "Fehler: der Dienstemanager konnte nicht geöffnet werden: %s (%i)\n" + +#~ msgid "Error: can't create service: %s (#%i)\n" +#~ msgstr "Fehler: Dienst konnte nicht erzeugt werden: %s (#%i)\n" + +#~ msgid "Failure at at %s:%d.\n" +#~ msgstr "Fehler bei %s:%d.\n" diff --git a/po/en@boldquot.header b/po/en@boldquot.header new file mode 100644 index 0000000..fedb6a0 --- /dev/null +++ b/po/en@boldquot.header @@ -0,0 +1,25 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# +# This catalog furthermore displays the text between the quotation marks in +# bold face, assuming the VT100/XTerm escape sequences. +# diff --git a/po/en@quot.header b/po/en@quot.header new file mode 100644 index 0000000..a9647fc --- /dev/null +++ b/po/en@quot.header @@ -0,0 +1,22 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# diff --git a/po/es.gmo b/po/es.gmo new file mode 100644 index 0000000..a3b0ad6 Binary files /dev/null and b/po/es.gmo differ diff --git a/po/es.po b/po/es.po new file mode 100644 index 0000000..83d1065 --- /dev/null +++ b/po/es.po @@ -0,0 +1,8787 @@ +# Spanish translations for GNUnet package. +# +# This file is distributed under the same license as the GNUnet package. +# Miguel Angel Arruga Vivas , 2006. +# +msgid "" +msgstr "" +"Project-Id-Version: GNUnet 0.7.0e\n" +"Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" +"POT-Creation-Date: 2012-02-28 18:30+0100\n" +"PO-Revision-Date: 2006-06-29 12:05+0200\n" +"Last-Translator: Miguel Angel Arruga \n" +"Language-Team: Spanish\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/arm/arm_api.c:187 +msgid "Failed to transmit shutdown request to client.\n" +msgstr "" + +#: src/arm/arm_api.c:378 +#, fuzzy, c-format +msgid "Configuration failes to specify option `%s' in section `%s'!\n" +msgstr "" +"El fichero de configuración debe especificar el directorio para almacenar " +"los datos FS en la sección '%s' bajo '%s'.\n" + +#: src/arm/arm_api.c:392 +#, fuzzy, c-format +msgid "Configuration fails to specify option `%s' in section `%s'!\n" +msgstr "" +"El fichero de configuración debe especificar el directorio para almacenar " +"los datos FS en la sección '%s' bajo '%s'.\n" + +#: src/arm/arm_api.c:467 +#, fuzzy, c-format +msgid "Error receiving response to `%s' request from ARM for service `%s'\n" +msgstr "Recibida respuesta anómala a'%s' del par '%s'.\n" + +#: src/arm/arm_api.c:523 +#, c-format +msgid "Requesting start of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:524 +#, c-format +msgid "Requesting termination of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:546 +#, c-format +msgid "Error while trying to transmit request to start `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:548 +#, c-format +msgid "Error while trying to transmit request to stop `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:581 +#, fuzzy, c-format +msgid "Asked to start service `%s' within %llu ms\n" +msgstr "'%s': No se recibió el mensaje en %llu ms.\n" + +#: src/arm/arm_api.c:654 +#, fuzzy, c-format +msgid "Stopping service `%s' within %llu ms\n" +msgstr "No se ha recibido una respuesta en %llums.\n" + +#: src/arm/gnunet-arm.c:149 +#, fuzzy, c-format +msgid "Service `%s' is unknown to ARM.\n" +msgstr "El espacio '%s' ha sido valorado con un %d.\n" + +#: src/arm/gnunet-arm.c:154 +#, fuzzy, c-format +msgid "Service `%s' has been stopped.\n" +msgstr "Servicio eliminado.\n" + +#: src/arm/gnunet-arm.c:157 +#, fuzzy, c-format +msgid "Service `%s' was already running.\n" +msgstr "¡Esta búsqueda está aún pendiente!\n" + +#: src/arm/gnunet-arm.c:162 +#, fuzzy, c-format +msgid "Service `%s' has been started.\n" +msgstr "Servicio eliminado.\n" + +#: src/arm/gnunet-arm.c:165 +#, fuzzy, c-format +msgid "Service `%s' was already being stopped.\n" +msgstr "Servicio eliminado.\n" + +#: src/arm/gnunet-arm.c:169 +#, fuzzy, c-format +msgid "Service `%s' was already not running.\n" +msgstr "¡Esta búsqueda está aún pendiente!\n" + +#: src/arm/gnunet-arm.c:173 +#, fuzzy +msgid "Request ignored as ARM is shutting down.\n" +msgstr "'%s' se esta cerrando.\n" + +#: src/arm/gnunet-arm.c:177 +#, fuzzy +msgid "Error communicating with ARM service.\n" +msgstr "Imprime información de los pares de GNUnet." + +#: src/arm/gnunet-arm.c:181 +#, fuzzy +msgid "Timeout communicating with ARM service.\n" +msgstr "Imprime información de los pares de GNUnet." + +#: src/arm/gnunet-arm.c:185 +#, fuzzy +msgid "Operation failed.\n" +msgstr "La verificación de la firma RSA fallo en %s: %d: %s\n" + +#: src/arm/gnunet-arm.c:189 +msgid "Unknown response code from ARM.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:216 +#, c-format +msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:224 src/arm/gnunet-arm.c:324 +msgid "Fatal error initializing ARM API.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:247 +#, fuzzy, c-format +msgid "Failed to remove configuration file %s\n" +msgstr "Imposible guardar el fichero de configuración '%s':" + +#: src/arm/gnunet-arm.c:253 +#, fuzzy, c-format +msgid "Failed to remove servicehome directory %s\n" +msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#: src/arm/gnunet-arm.c:355 +msgid "stop all GNUnet services" +msgstr "" + +#: src/arm/gnunet-arm.c:357 +msgid "start a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:359 +msgid "stop a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:361 +msgid "start all GNUnet default services" +msgstr "" + +#: src/arm/gnunet-arm.c:364 +msgid "stop and start all GNUnet default services" +msgstr "" + +#: src/arm/gnunet-arm.c:367 +msgid "delete config file and directory on exit" +msgstr "" + +#: src/arm/gnunet-arm.c:369 +msgid "don't print status messages" +msgstr "" + +#: src/arm/gnunet-arm.c:372 +#, fuzzy +msgid "timeout for completing current operation" +msgstr "tiempo para esperar hasta completar una iteración (en ms)" + +#: src/arm/gnunet-arm.c:383 +msgid "Control services and the Automated Restart Manager (ARM)" +msgstr "" + +#: src/arm/gnunet-service-arm.c:328 +#, fuzzy, c-format +msgid "Failed to start service `%s'\n" +msgstr "Falló al comenzar la recolección.\n" + +#: src/arm/gnunet-service-arm.c:331 +#, fuzzy, c-format +msgid "Starting service `%s'\n" +msgstr "Iniciada colección '%s'.\n" + +#: src/arm/gnunet-service-arm.c:357 +#, fuzzy +msgid "Could not send status result to client\n" +msgstr "Imposible mandar el mensaje a gnunetd\n" + +#: src/arm/gnunet-service-arm.c:484 +#, fuzzy, c-format +msgid "Unable to create socket for service `%s': %s\n" +msgstr "Imposible crear la cuenta de usuario:" + +#: src/arm/gnunet-service-arm.c:506 +#, c-format +msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:520 +#, c-format +msgid "ARM now monitors connections to service `%s' at `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:628 +#, fuzzy, c-format +msgid "Preparing to stop `%s'\n" +msgstr "Iniciada colección '%s'.\n" + +#: src/arm/gnunet-service-arm.c:782 +#, fuzzy, c-format +msgid "Restarting service `%s'.\n" +msgstr "Iniciada colección '%s'.\n" + +#: src/arm/gnunet-service-arm.c:877 +msgid "exit" +msgstr "" + +#: src/arm/gnunet-service-arm.c:882 +msgid "signal" +msgstr "" + +#: src/arm/gnunet-service-arm.c:887 +msgid "unknown" +msgstr "desconocido" + +#: src/arm/gnunet-service-arm.c:921 +#, c-format +msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:967 src/arm/mockup-service.c:41 +#, fuzzy +msgid "Failed to transmit shutdown ACK.\n" +msgstr "Falló al comenzar la recolección.\n" + +#: src/arm/gnunet-service-arm.c:1067 +#, fuzzy, c-format +msgid "Configuration file `%s' for service `%s' not valid: %s\n" +msgstr "Fichero de configuración '%s' creado.\n" + +#: src/arm/gnunet-service-arm.c:1069 +msgid "option missing" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1152 +#, fuzzy, c-format +msgid "Starting default services `%s'\n" +msgstr "Iniciada colección '%s'.\n" + +#: src/arm/gnunet-service-arm.c:1163 +#, c-format +msgid "Default service `%s' not configured correctly!\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1177 +msgid "" +"No default services configured, GNUnet will not really start right now.\n" +msgstr "" + +#: src/arm/mockup-service.c:46 +msgid "Transmitting shutdown ACK.\n" +msgstr "" + +#: src/arm/mockup-service.c:69 +msgid "Initiating shutdown as requested by client.\n" +msgstr "" + +#: src/block/block.c:105 +#, fuzzy, c-format +msgid "Loading block plugin `%s'\n" +msgstr "Probando transporte(s) %s\n" + +#: src/chat/chat.c:175 +#, fuzzy +msgid "Could not transmit confirmation receipt\n" +msgstr "Imposible acceder a la información del espacio.\n" + +#: src/chat/chat.c:283 +msgid "The current user must be the the first one joined\n" +msgstr "" + +#: src/chat/chat.c:412 +#, fuzzy, c-format +msgid "Unknown message type: '%u'\n" +msgstr "Operación desconocida '%s'\n" + +#: src/chat/chat.c:472 +#, fuzzy, c-format +msgid "Configuration option `%s' in section `%s' missing\n" +msgstr "Fichero de configuración '%s' creado.\n" + +#: src/chat/chat.c:480 +#, fuzzy, c-format +msgid "Failed to access chat home directory `%s'\n" +msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#: src/chat/chat.c:498 +#, fuzzy, c-format +msgid "Failed to create/open key in file `%s'\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/chat/chat.c:559 +#, fuzzy +msgid "Could not serialize metadata\n" +msgstr "¡Imposible inicializar libgnunetutil!\n" + +#: src/chat/chat.c:674 +#, fuzzy +msgid "Failed to connect to the chat service\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/chat/chat.c:680 +msgid "Undefined mandatory parameter: joinCallback\n" +msgstr "" + +#: src/chat/chat.c:686 +msgid "Undefined mandatory parameter: messageCallback\n" +msgstr "" + +#: src/chat/chat.c:692 +msgid "Undefined mandatory parameter: memberCallback\n" +msgstr "" + +#: src/chat/gnunet-chat.c:92 +msgid "Joined\n" +msgstr "" + +#: src/chat/gnunet-chat.c:124 +msgid "anonymous" +msgstr "" + +#: src/chat/gnunet-chat.c:130 +#, fuzzy, c-format +msgid "(%s) `%s' said: %s\n" +msgstr "'%s' %s falló: %s\n" + +#: src/chat/gnunet-chat.c:133 src/chat/gnunet-chat.c:136 +#, fuzzy, c-format +msgid "(%s) `%s' said to you: %s\n" +msgstr "'%s' %s falló: %s\n" + +#: src/chat/gnunet-chat.c:139 +#, fuzzy, c-format +msgid "(%s) `%s' said for sure: %s\n" +msgstr "'%s' %s falló: %s\n" + +#: src/chat/gnunet-chat.c:142 +#, fuzzy, c-format +msgid "(%s) `%s' said to you for sure: %s\n" +msgstr "'%s' falló con el código de error %s: %s" + +#: src/chat/gnunet-chat.c:145 +#, fuzzy, c-format +msgid "(%s) `%s' was confirmed that you received: %s\n" +msgstr "'%s' falló con el código de error %d: %s" + +#: src/chat/gnunet-chat.c:148 +#, fuzzy, c-format +msgid "(%s) `%s' was confirmed that you and only you received: %s\n" +msgstr "'%s' falló con el código de error %d: %s" + +#: src/chat/gnunet-chat.c:151 +#, fuzzy, c-format +msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" +msgstr "'%s' falló con el código de error %d: %s" + +#: src/chat/gnunet-chat.c:156 +#, fuzzy, c-format +msgid "" +"(%s) `%s' was confirmed that you and only you received from him or her: %s\n" +msgstr "'%s' falló con el código de error %d: %s" + +#: src/chat/gnunet-chat.c:159 +#, fuzzy, c-format +msgid "(%s) `%s' said off the record: %s\n" +msgstr "'%s' falló con el código de error %s: %s" + +#: src/chat/gnunet-chat.c:162 +#, c-format +msgid "(%s) <%s> said using an unknown message type: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:193 +#, c-format +msgid "'%s' acknowledged message #%d\n" +msgstr "" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' entered the room\n" +msgstr "" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' left the room\n" +msgstr "" + +#: src/chat/gnunet-chat.c:284 src/chat/gnunet-chat.c:316 +#, fuzzy +msgid "Could not change username\n" +msgstr "Imposible crear el espacio '%s' (¿existe?).\n" + +#: src/chat/gnunet-chat.c:288 src/chat/gnunet-chat.c:630 +#, fuzzy, c-format +msgid "Joining room `%s' as user `%s'...\n" +msgstr "Respuesta inválida a '%s' del par '%s'.\n" + +#: src/chat/gnunet-chat.c:320 +#, fuzzy, c-format +msgid "Changed username to `%s'\n" +msgstr "Imposible cambiar el usuario/grupo a '%s': %s\n" + +#: src/chat/gnunet-chat.c:333 +#, fuzzy, c-format +msgid "Users in room `%s': " +msgstr "Fichero almacenado en '%s'.\n" + +#: src/chat/gnunet-chat.c:371 +msgid "Syntax: /msg USERNAME MESSAGE" +msgstr "" + +#: src/chat/gnunet-chat.c:379 +#, fuzzy, c-format +msgid "Unknown user `%s'\n" +msgstr "Operación desconocida '%s'\n" + +#: src/chat/gnunet-chat.c:395 +#, c-format +msgid "User `%s' is currently not in the room!\n" +msgstr "" + +#: src/chat/gnunet-chat.c:448 +#, fuzzy, c-format +msgid "Unknown command `%s'\n" +msgstr "Operación desconocida '%s'\n" + +#: src/chat/gnunet-chat.c:459 +msgid "" +"Use `/join #roomname' to join a chat room. Joining a room will cause you to " +"leave the current room" +msgstr "" + +#: src/chat/gnunet-chat.c:463 +msgid "" +"Use `/nick nickname' to change your nickname. This will cause you to leave " +"the current room and immediately rejoin it with the new name." +msgstr "" + +#: src/chat/gnunet-chat.c:467 +msgid "" +"Use `/msg nickname message' to send a private message to the specified user" +msgstr "" + +#: src/chat/gnunet-chat.c:470 +msgid "The `/notice' command is an alias for `/msg'" +msgstr "" + +#: src/chat/gnunet-chat.c:472 +msgid "The `/query' command is an alias for `/msg'" +msgstr "" + +#: src/chat/gnunet-chat.c:474 +msgid "Use `/sig message' to send a signed public message" +msgstr "" + +#: src/chat/gnunet-chat.c:477 +msgid "Use `/ack message' to require signed acknowledgment of the message" +msgstr "" + +#: src/chat/gnunet-chat.c:480 +msgid "Use `/anonymous message' to send a public anonymous message" +msgstr "" + +#: src/chat/gnunet-chat.c:482 +msgid "The `/anon' command is an alias for `/anonymous'" +msgstr "" + +#: src/chat/gnunet-chat.c:484 +msgid "Use `/quit' to terminate gnunet-chat" +msgstr "" + +#: src/chat/gnunet-chat.c:486 +msgid "The `/leave' command is an alias for `/quit'" +msgstr "" + +#: src/chat/gnunet-chat.c:489 +msgid "Use `/names' to list all of the current members in the chat room" +msgstr "" + +#: src/chat/gnunet-chat.c:491 +msgid "Use `/help command' to get help for a specific command" +msgstr "" + +#: src/chat/gnunet-chat.c:606 +#, fuzzy +msgid "You must specify a nickname\n" +msgstr "¡Debes especificar un receptor!\n" + +#: src/chat/gnunet-chat.c:622 +#, fuzzy, c-format +msgid "Failed to join room `%s'\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/chat/gnunet-chat.c:655 +msgid "set the nickname to use (required)" +msgstr "" + +#: src/chat/gnunet-chat.c:658 +msgid "set the chat room to join" +msgstr "" + +#: src/chat/gnunet-chat.c:670 +msgid "Join a chat on GNUnet." +msgstr "" + +#: src/chat/gnunet-service-chat.c:267 +#, fuzzy +msgid "Failed to queue a message notification\n" +msgstr "Imposible guardar la configuración" + +#: src/chat/gnunet-service-chat.c:546 +#, fuzzy +msgid "Failed to queue a join notification\n" +msgstr "Imposible guardar la configuración" + +#: src/chat/gnunet-service-chat.c:729 +#, fuzzy +msgid "Failed to queue a confirmation receipt\n" +msgstr "Imposible guardar la configuración" + +#: src/chat/gnunet-service-chat.c:907 +#, fuzzy +msgid "Failed to queue a leave notification\n" +msgstr "Imposible guardar la configuración" + +#: src/core/core_api.c:798 +msgid "Client was disconnected from core service, trying to reconnect.\n" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:77 +#: src/peerinfo-tool/gnunet-peerinfo.c:60 +#, fuzzy, c-format +msgid "Peer `%s'\n" +msgstr "Yo soy el par '%s'.\n" + +#: src/core/gnunet-core-list-connections.c:175 +#: src/peerinfo-tool/gnunet-peerinfo.c:194 +#, fuzzy, c-format +msgid "Invalid command line argument `%s'\n" +msgstr "Argumentos en la linea de comandos inválidos:\n" + +#: src/core/gnunet-core-list-connections.c:196 +#: src/peerinfo-tool/gnunet-peerinfo.c:252 +msgid "don't resolve host names" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:203 +#, fuzzy +msgid "Print information about connected peers." +msgstr "Imprime información de los pares de GNUnet." + +#: src/core/gnunet-service-core.c:99 +#, c-format +msgid "Core service of `%4s' ready.\n" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:360 +#, fuzzy +msgid "# send requests dropped (disconnected)" +msgstr "# Anuncios de los pares recibidos" + +#: src/core/gnunet-service-core_clients.c:465 +#, fuzzy +msgid "# messages discarded (session disconnected)" +msgstr "# mensajes defragmentados" + +#: src/core/gnunet-service-core_clients.c:801 +#, fuzzy, c-format +msgid "# bytes of messages of type %u received" +msgstr "# bytes de ruido recibidos" + +#: src/core/gnunet-service-core_kx.c:493 +msgid "# bytes encrypted" +msgstr "# bytes encriptados" + +#: src/core/gnunet-service-core_kx.c:543 +msgid "# bytes decrypted" +msgstr "# bytes desencriptados" + +#: src/core/gnunet-service-core_kx.c:604 src/dv/gnunet-service-dv.c:3002 +#: src/hostlist/hostlist-server.c:436 src/peerinfo-tool/gnunet-peerinfo.c:151 +#, fuzzy +msgid "Error in communication with PEERINFO service\n" +msgstr "Imprime información de los pares de GNUnet." + +#: src/core/gnunet-service-core_kx.c:623 +msgid "# Delayed connecting due to lack of public key" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:673 +msgid "# key exchanges initiated" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:694 +msgid "# key exchanges stopped" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:746 +#, fuzzy +msgid "# session keys received" +msgstr "# claves de la sesión rechazadas" + +#: src/core/gnunet-service-core_kx.c:765 +#, fuzzy, c-format +msgid "`%s' is for `%s', not for me. Ignoring.\n" +msgstr "el tamaño del '%s' mensaje es demasiado corto. Ignorandolo.\n" + +#: src/core/gnunet-service-core_kx.c:803 +#, fuzzy +msgid "# SET_KEY messages decrypted" +msgstr "# mensajes defragmentados" + +#: src/core/gnunet-service-core_kx.c:883 +#: src/transport/gnunet-service-transport_validation.c:803 +#, fuzzy +msgid "# PING messages received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/core/gnunet-service-core_kx.c:917 +#, c-format +msgid "" +"Received PING from `%s' for different identity: I am `%s', PONG identity: `" +"%s'\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:938 +#, fuzzy +msgid "# PONG messages created" +msgstr "# mensajes fragmentados" + +#: src/core/gnunet-service-core_kx.c:1026 +#, fuzzy +msgid "# sessions terminated by timeout" +msgstr "# bytes omitidos por TCP (salientes)" + +#: src/core/gnunet-service-core_kx.c:1037 +#, fuzzy +msgid "# keepalive messages sent" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/core/gnunet-service-core_kx.c:1095 +#: src/transport/gnunet-service-transport_validation.c:1026 +#, fuzzy +msgid "# PONG messages received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/core/gnunet-service-core_kx.c:1125 +#, fuzzy +msgid "# PONG messages decrypted" +msgstr "# mensajes defragmentados" + +#: src/core/gnunet-service-core_kx.c:1157 +#, fuzzy +msgid "# session keys confirmed via PONG" +msgstr "# Anuncios de los pares recibidos" + +#: src/core/gnunet-service-core_kx.c:1223 +#, fuzzy +msgid "# SET_KEY and PING messages created" +msgstr "# mensajes de texto mandados por PING" + +#: src/core/gnunet-service-core_kx.c:1364 +msgid "# failed to decrypt message (no session key)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1406 +#: src/core/gnunet-service-core_kx.c:1431 +#, fuzzy +msgid "# bytes dropped (duplicates)" +msgstr "# bytes omitidos por UDP (salientes)" + +#: src/core/gnunet-service-core_kx.c:1418 +#, fuzzy +msgid "# bytes dropped (out of sequence)" +msgstr "# bytes omitidos por UDP (salientes)" + +#: src/core/gnunet-service-core_kx.c:1455 +#, fuzzy, c-format +msgid "Message received far too old (%llu ms). Content ignored.\n" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/core/gnunet-service-core_kx.c:1459 +#, fuzzy +msgid "# bytes dropped (ancient message)" +msgstr "# bytes omitidos por UDP (salientes)" + +#: src/core/gnunet-service-core_kx.c:1467 +#, fuzzy +msgid "# bytes of payload decrypted" +msgstr "# bytes desencriptados" + +#: src/core/gnunet-service-core_kx.c:1528 +#, fuzzy +msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" +msgstr "Configuración de GNUnet" + +#: src/core/gnunet-service-core_kx.c:1536 +msgid "Core service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1546 src/hostlist/hostlist-server.c:555 +#: src/peerinfo-tool/gnunet-peerinfo.c:202 +#: src/transport/gnunet-service-transport.c:595 +#, fuzzy +msgid "Could not access PEERINFO service. Exiting.\n" +msgstr "Imposible acceder a la información del espacio.\n" + +#: src/core/gnunet-service-core_neighbours.c:163 +#, fuzzy +msgid "# sessions terminated by transport disconnect" +msgstr "# Anuncios de los pares recibidos" + +#: src/core/gnunet-service-core_neighbours.c:180 +#: src/core/gnunet-service-core_neighbours.c:342 +msgid "# neighbour entries allocated" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:251 +msgid "# encrypted bytes given to transport" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:430 +#, fuzzy, c-format +msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" +msgstr "Mensaje no válido del tipo %u recibido. Omitiendo.\n" + +#: src/core/gnunet-service-core_sessions.c:208 +#: src/core/gnunet-service-core_sessions.c:273 +msgid "# entries in session map" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:238 +msgid "# type map refreshes sent" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:414 +msgid "# messages discarded (expired prior to transmission)" +msgstr "" + +#: src/core/gnunet-service-core_typemap.c:110 +#: src/core/gnunet-service-core_typemap.c:121 +#, fuzzy +msgid "# type maps received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/core/gnunet-service-core_typemap.c:151 +msgid "# updates to my type map" +msgstr "" + +#: src/datacache/datacache.c:118 src/datacache/datacache.c:255 +#: src/datastore/gnunet-service-datastore.c:854 +#, fuzzy +msgid "# bytes stored" +msgstr "# bytes en la base de datos" + +#: src/datacache/datacache.c:144 src/datacache/datacache.c:151 +#: src/datastore/gnunet-service-datastore.c:1531 +#: src/datastore/gnunet-service-datastore.c:1542 +#, fuzzy, c-format +msgid "No `%s' specified for `%s' in configuration!\n" +msgstr "¡Ninguna aplicación definida en la configuración!\n" + +#: src/datacache/datacache.c:183 +#, c-format +msgid "Loading `%s' datacache plugin\n" +msgstr "" + +#: src/datacache/datacache.c:191 +#, fuzzy, c-format +msgid "Failed to load datacache plugin for `%s'\n" +msgstr "Falló al actualizar los datos del módulo '%s'\n" + +#: src/datacache/datacache.c:281 +#, fuzzy +msgid "# requests received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datacache/datacache.c:291 +msgid "# requests filtered by bloom filter" +msgstr "" + +#: src/datacache/plugin_datacache_mysql.c:103 +#: src/datacache/plugin_datacache_mysql.c:110 +#: src/datacache/plugin_datacache_mysql.c:517 +#: src/datacache/plugin_datacache_mysql.c:526 +#: src/datacache/plugin_datacache_mysql.c:598 +#: src/datacache/plugin_datacache_mysql.c:614 +#: src/datacache/plugin_datacache_sqlite.c:71 +#: src/datacache/plugin_datacache_sqlite.c:74 +#: src/datastore/plugin_datastore_mysql.c:139 +#: src/datastore/plugin_datastore_mysql.c:146 +#: src/datastore/plugin_datastore_mysql.c:613 +#: src/datastore/plugin_datastore_mysql.c:673 +#: src/datastore/plugin_datastore_mysql.c:685 +#: src/datastore/plugin_datastore_mysql.c:1362 +#: src/datastore/plugin_datastore_mysql.c:1376 +#: src/datastore/plugin_datastore_sqlite.c:61 +#: src/namestore/plugin_namestore_sqlite.c:49 src/util/crypto_ksk.c:49 +#: src/util/crypto_rsa.c:92 src/include/gnunet_common.h:507 +#: src/include/gnunet_common.h:514 +#, c-format +msgid "`%s' failed at %s:%d with error: %s\n" +msgstr "'%s' falló en %s: %d con el error: %s\n" + +#: src/datacache/plugin_datacache_mysql.c:224 +#: src/datastore/plugin_datastore_mysql.c:316 +#, c-format +msgid "Trying to use file `%s' for MySQL configuration.\n" +msgstr "Intentando usar el fichero '%s' para la configuración de MySQL.\n" + +#: src/datacache/plugin_datacache_mysql.c:230 +#: src/datastore/plugin_datastore_mysql.c:322 +#, fuzzy, c-format +msgid "Could not access file `%s': %s\n" +msgstr "Imposible ejecutar '%s': %s\n" + +#: src/datacache/plugin_datacache_mysql.c:979 +msgid "MySQL datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_postgres.c:79 +#: src/datastore/plugin_datastore_postgres.c:93 +#, fuzzy, c-format +msgid "`%s:%s' failed at %s:%d with error: %s" +msgstr "'%s' falló en %s: %d con el error: %s\n" + +#: src/datacache/plugin_datacache_postgres.c:149 +#, fuzzy, c-format +msgid "Unable to initialize Postgres: %s" +msgstr "Imposible inicializar SQLite.\n" + +#: src/datacache/plugin_datacache_postgres.c:499 +msgid "Postgres datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:424 +msgid "Sqlite datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:457 +#: src/datastore/plugin_datastore_sqlite.c:414 +#: src/namestore/plugin_namestore_sqlite.c:381 +msgid "Tried to close sqlite without finalizing all prepared statements.\n" +msgstr "" + +#: src/datacache/plugin_datacache_template.c:121 +msgid "Template datacache running\n" +msgstr "" + +#: src/datastore/datastore_api.c:289 +#, fuzzy +msgid "Failed to transmit request to drop database.\n" +msgstr "Falló al mandar la petición HTTP al host '%s': %s\n" + +#: src/datastore/datastore_api.c:372 +msgid "# queue entry timeouts" +msgstr "" + +#: src/datastore/datastore_api.c:418 +msgid "# queue overflows" +msgstr "" + +#: src/datastore/datastore_api.c:445 +msgid "# queue entries created" +msgstr "" + +#: src/datastore/datastore_api.c:465 +#, fuzzy +msgid "# Requests dropped from datastore queue" +msgstr "# Anuncios de los pares recibidos" + +#: src/datastore/datastore_api.c:513 +msgid "# datastore connections (re)created" +msgstr "" + +#: src/datastore/datastore_api.c:540 +msgid "# reconnected to DATASTORE" +msgstr "" + +#: src/datastore/datastore_api.c:608 +#, fuzzy +msgid "# transmission request failures" +msgstr "# mensajes de texto mandados por PING" + +#: src/datastore/datastore_api.c:631 +#, fuzzy +msgid "# bytes sent to datastore" +msgstr "# bytes en la base de datos" + +#: src/datastore/datastore_api.c:772 +#, fuzzy +msgid "Failed to receive status response from database." +msgstr "" +"\n" +"Fallo al recibir la respuesta de gnunetd.\n" + +#: src/datastore/datastore_api.c:786 +msgid "Error reading response from datastore service" +msgstr "" + +#: src/datastore/datastore_api.c:798 src/datastore/datastore_api.c:804 +#, fuzzy +msgid "Invalid error message received from datastore service" +msgstr "Mensaje '%s' inválido recibido del par '%s'.\n" + +#: src/datastore/datastore_api.c:810 +#, fuzzy +msgid "# status messages received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datastore/datastore_api.c:883 +#, fuzzy +msgid "# PUT requests executed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datastore/datastore_api.c:954 +msgid "# RESERVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1019 +msgid "# RELEASE RESERVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1080 +#, fuzzy +msgid "# UPDATE requests executed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datastore/datastore_api.c:1148 +#, fuzzy +msgid "# REMOVE requests executed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datastore/datastore_api.c:1193 +#, fuzzy +msgid "Failed to receive response from database.\n" +msgstr "" +"\n" +"Fallo al recibir la respuesta de gnunetd.\n" + +#: src/datastore/datastore_api.c:1253 +#, fuzzy +msgid "# Results received" +msgstr "# bytes recibidos por TCP" + +#: src/datastore/datastore_api.c:1324 +msgid "# GET REPLICATION requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1391 +msgid "# GET ZERO ANONYMITY requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1455 +#, fuzzy +msgid "# GET requests executed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datastore/gnunet-service-datastore.c:351 +#, fuzzy +msgid "# bytes expired" +msgstr "# bytes recibidos por TCP" + +#: src/datastore/gnunet-service-datastore.c:426 +msgid "# bytes purged (low-priority)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:486 +msgid "Transmission to client failed!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:640 +msgid "# results found" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:685 +#, c-format +msgid "" +"Insufficient space (%llu bytes are available) to satisfy `%s' request for " +"%llu bytes\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:696 +#, c-format +msgid "" +"The requested amount (%llu bytes) is larger than the cache size (%llu " +"bytes)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:700 +msgid "" +"Insufficient space to satisfy request and requested amount is larger than " +"cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:706 +msgid "Insufficient space to satisfy request" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:711 +#: src/datastore/gnunet-service-datastore.c:765 +#: src/datastore/gnunet-service-datastore.c:986 +#: src/datastore/gnunet-service-datastore.c:1465 +msgid "# reserved" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:780 +msgid "Could not find matching reservation" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:868 +#, c-format +msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1034 +#, fuzzy +msgid "# GET requests received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datastore/gnunet-service-datastore.c:1048 +msgid "# requests filtered by bloomfilter" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1076 +#, fuzzy +msgid "# UPDATE requests received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datastore/gnunet-service-datastore.c:1110 +#, fuzzy +msgid "# GET REPLICATION requests received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datastore/gnunet-service-datastore.c:1145 +#, fuzzy +msgid "# GET ZERO ANONYMITY requests received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datastore/gnunet-service-datastore.c:1172 +#, fuzzy +msgid "Content not found" +msgstr "¡Comando '%s' no encontrado!\n" + +#: src/datastore/gnunet-service-datastore.c:1182 +msgid "# bytes removed (explicit request)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1216 +#, fuzzy +msgid "# REMOVE requests received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/datastore/gnunet-service-datastore.c:1260 +#, c-format +msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1323 +#, c-format +msgid "Loading `%s' datastore plugin\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1332 +#, fuzzy, c-format +msgid "Failed to load datastore plugin for `%s'\n" +msgstr "Imposible inicializar la aplicación '%s'\n" + +#: src/datastore/gnunet-service-datastore.c:1536 +#, fuzzy, c-format +msgid "# bytes used in file-sharing datastore `%s'" +msgstr "# bytes en la base de datos" + +#: src/datastore/gnunet-service-datastore.c:1547 +msgid "# quota" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1549 +msgid "# cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1562 +#, c-format +msgid "Could not use specified filename `%s' for bloomfilter.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1580 +#: src/datastore/gnunet-service-datastore.c:1596 +#, fuzzy, c-format +msgid "Failed to remove bogus bloomfilter file `%s'\n" +msgstr "Imposible guardar el fichero de configuración '%s':" + +#: src/datastore/gnunet-service-datastore.c:1626 +#, fuzzy +msgid "Failed to initialize bloomfilter.\n" +msgstr "Imposible inicializar SQLite.\n" + +#: src/datastore/gnunet-service-datastore.c:1655 +msgid "Rebuilding bloomfilter. Please be patient.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1660 +msgid "Plugin does not support get_keys function. Please fix!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1663 +msgid "Bloomfilter construction complete.\n" +msgstr "" + +#: src/datastore/plugin_datastore_mysql.c:529 +#: src/datastore/plugin_datastore_mysql.c:1336 +#, fuzzy, c-format +msgid "Failed to prepare statement `%s'\n" +msgstr "Falló al actualizar los datos del módulo '%s'\n" + +#: src/datastore/plugin_datastore_mysql.c:622 +#: src/datastore/plugin_datastore_mysql.c:1346 +#, fuzzy, c-format +msgid "`%s' for `%s' failed at %s:%d with error: %s\n" +msgstr "'%s' a '%s' falló en %s: %d con error %s\n" + +#: src/datastore/plugin_datastore_mysql.c:1581 +msgid "Mysql database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_postgres.c:173 +#, fuzzy, c-format +msgid "Unable to initialize Postgres with configuration `%s': %s" +msgstr "Imposible guardar el fichero de configuración '%s':" + +#: src/datastore/plugin_datastore_postgres.c:1017 +msgid "Postgres database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:61 +#, fuzzy, c-format +msgid "`%s' failed at %s:%u with error: %s" +msgstr "'%s' falló en %s: %d con el error: %s\n" + +#: src/datastore/plugin_datastore_sqlite.c:239 +#: src/namestore/plugin_namestore_sqlite.c:223 +#, fuzzy, c-format +msgid "Option `%s' in section `%s' missing in configuration!\n" +msgstr "¡Ninguna aplicación definida en la configuración!\n" + +#: src/datastore/plugin_datastore_sqlite.c:266 +#: src/namestore/plugin_namestore_sqlite.c:248 +#, fuzzy, c-format +msgid "Unable to initialize SQLite: %s.\n" +msgstr "Imposible inicializar SQLite.\n" + +#: src/datastore/plugin_datastore_sqlite.c:669 +#, fuzzy +msgid "Invalid data in database. Trying to fix (by deletion).\n" +msgstr "Datos no válidos en %s. Intentando fijar (por borrado).\n" + +#: src/datastore/plugin_datastore_sqlite.c:1159 +msgid "sqlite version to old to determine size, assuming zero\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1178 +#, c-format +msgid "" +"Using sqlite page utilization to estimate payload (%llu pages of size %llu " +"bytes)\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1218 +#: src/namestore/plugin_namestore_sqlite.c:779 +#, fuzzy +msgid "Sqlite database running\n" +msgstr "base de datos sqlite" + +#: src/datastore/plugin_datastore_template.c:241 +msgid "Template database running\n" +msgstr "" + +#: src/dht/dht_api.c:280 +#, fuzzy +msgid "Failed to connect to the DHT service!\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-put.c:172 +#: src/gns/gnunet-gns-lookup.c:179 +msgid "the query key" +msgstr "" + +#: src/dht/gnunet-dht-get.c:204 src/gns/gnunet-gns-lookup.c:182 +msgid "how many parallel requests (replicas) to create" +msgstr "" + +#: src/dht/gnunet-dht-get.c:207 src/gns/gnunet-gns-lookup.c:185 +msgid "the type of data to look for" +msgstr "" + +#: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:181 +#: src/gns/gnunet-gns-lookup.c:188 +msgid "how long to execute this query before giving up?" +msgstr "" + +#: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-put.c:184 +#: src/fs/gnunet-download.c:270 src/fs/gnunet-publish.c:725 +#: src/fs/gnunet-search.c:297 src/fs/gnunet-unindex.c:169 +#: src/gns/gnunet-gns-lookup.c:191 src/nse/gnunet-nse-profiler.c:908 +msgid "be verbose (print progress information)" +msgstr "" + +#: src/dht/gnunet-dht-get.c:232 +msgid "Issue a GET request to the GNUnet DHT, prints results." +msgstr "" + +#: src/dht/gnunet-dht-put.c:100 +msgid "PUT request sent!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:124 +msgid "Must provide KEY and DATA for DHT put!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:132 +#, fuzzy, c-format +msgid "Could not connect to %s service!\n" +msgstr "Imposible conectar con gnunetd.\n" + +#: src/dht/gnunet-dht-put.c:137 +#, fuzzy, c-format +msgid "Connected to %s service!\n" +msgstr "'%s' conectado a '%s'.\n" + +#: src/dht/gnunet-dht-put.c:152 +#, c-format +msgid "Issuing put request for `%s' with data `%s'!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:166 +msgid "the data to insert under the key" +msgstr "" + +#: src/dht/gnunet-dht-put.c:169 +msgid "how long to store this entry in the dht (in seconds)" +msgstr "" + +#: src/dht/gnunet-dht-put.c:175 +msgid "how many replicas to create" +msgstr "" + +#: src/dht/gnunet-dht-put.c:178 +msgid "the type to insert data as" +msgstr "" + +#: src/dht/gnunet-dht-put.c:203 +msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." +msgstr "" + +#: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:556 +#: src/testing/testing.c:1979 src/testing/testing.c:2009 +#, fuzzy +msgid "Failed to connect to transport service!\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/dht/gnunet-service-dht_clients.c:371 +#, fuzzy +msgid "# GET requests from clients injected" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/dht/gnunet-service-dht_clients.c:462 +#, fuzzy +msgid "# PUT requests received from clients" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/dht/gnunet-service-dht_clients.c:529 +#, fuzzy +msgid "# GET requests received from clients" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/dht/gnunet-service-dht_clients.c:624 +#, fuzzy +msgid "# GET STOP requests received from clients" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/dht/gnunet-service-dht_clients.c:854 +msgid "# Key match, type mismatches in REPLY to CLIENT" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:869 +msgid "# Duplicate REPLIES to CLIENT request dropped" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:906 +#, fuzzy, c-format +msgid "Unsupported block type (%u) in request!\n" +msgstr "Mensaje no válido del tipo %u recibido. Omitiendo.\n" + +#: src/dht/gnunet-service-dht_clients.c:928 +#, fuzzy +msgid "# RESULTS queued for clients" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/dht/gnunet-service-dht_clients.c:979 +#: src/dht/gnunet-service-dht_clients.c:1022 +msgid "# REPLIES ignored for CLIENTS (no match)" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:989 +#, fuzzy +msgid "Could not pass reply to client, message too big!\n" +msgstr "Imposible mandar el mensaje a gnunetd\n" + +#: src/dht/gnunet-service-dht_datacache.c:93 +#, fuzzy, c-format +msgid "%s request received, but have no datacache!\n" +msgstr "# bytes recibidos por TCP" + +#: src/dht/gnunet-service-dht_datacache.c:103 +msgid "# ITEMS stored in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:209 +msgid "# Good RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:220 +msgid "# Duplicate RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:226 +msgid "# Invalid RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:238 +msgid "# Unsupported RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:241 +#, c-format +msgid "Unsupported block type (%u) in local response!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:271 +#, fuzzy +msgid "# GET requests given to datacache" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/dht/gnunet-service-dht_hello.c:82 +#, fuzzy +msgid "# HELLOs obtained from peerinfo" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/dht/gnunet-service-dht_neighbours.c:481 +msgid "# Preference updates given to core" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:573 +#, fuzzy +msgid "# FIND PEER messages initiated" +msgstr "# mensajes fragmentados" + +#: src/dht/gnunet-service-dht_neighbours.c:629 +#: src/dht/gnunet-service-dht_neighbours.c:689 +#, fuzzy +msgid "# Peers connected" +msgstr "# de pares conectados" + +#: src/dht/gnunet-service-dht_neighbours.c:723 +#, fuzzy +msgid "# Queued messages discarded (peer disconnected)" +msgstr "# mensajes defragmentados" + +#: src/dht/gnunet-service-dht_neighbours.c:778 +#, fuzzy +msgid "# Bytes transmitted to other peers" +msgstr "# bytes recibidos por TCP" + +#: src/dht/gnunet-service-dht_neighbours.c:816 +#, fuzzy +msgid "# Bytes of bandwdith requested from core" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/dht/gnunet-service-dht_neighbours.c:1040 +#: src/dht/gnunet-service-dht_neighbours.c:1068 +msgid "# Peers excluded from routing due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1049 +#: src/dht/gnunet-service-dht_neighbours.c:1085 +#, fuzzy +msgid "# Peer selection failed" +msgstr "Conexión fallida\n" + +#: src/dht/gnunet-service-dht_neighbours.c:1221 +#, fuzzy +msgid "# PUT requests routed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/dht/gnunet-service-dht_neighbours.c:1252 +#, fuzzy +msgid "# PUT messages queued for transmission" +msgstr "# bytes de mensajes salientes omitidos" + +#: src/dht/gnunet-service-dht_neighbours.c:1333 +#, fuzzy +msgid "# GET requests routed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/dht/gnunet-service-dht_neighbours.c:1364 +#, fuzzy +msgid "# GET messages queued for transmission" +msgstr "# bytes de mensajes salientes omitidos" + +#: src/dht/gnunet-service-dht_neighbours.c:1467 +msgid "# RESULT messages queued for transmission" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1555 +#, fuzzy +msgid "# P2P PUT requests received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/dht/gnunet-service-dht_neighbours.c:1668 +msgid "# FIND PEER requests ignored due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1676 +msgid "# FIND PEER requests ignored due to lack of HELLO" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1767 +#, fuzzy +msgid "# P2P GET requests received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/dht/gnunet-service-dht_neighbours.c:1811 +#, fuzzy +msgid "# P2P FIND PEER requests processed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/dht/gnunet-service-dht_neighbours.c:1825 +#, fuzzy +msgid "# P2P GET requests ONLY routed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/dht/gnunet-service-dht_neighbours.c:1895 +#, fuzzy +msgid "# P2P RESULTS received" +msgstr "# bytes recibidos por TCP" + +#: src/dht/gnunet-service-dht_nse.c:59 +#, fuzzy +msgid "# Network size estimates received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/dht/gnunet-service-dht_routing.c:211 +msgid "# Good REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:220 +msgid "# Duplicate REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:226 +msgid "# Invalid REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:236 +msgid "# Unsupported REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:314 +#: src/dht/gnunet-service-dht_routing.c:368 +msgid "# Entries removed from routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:324 +msgid "# Entries added to routing table" +msgstr "" + +#: src/dht/plugin_block_dht.c:124 +#, c-format +msgid "Block not of type %u\n" +msgstr "" + +#: src/dht/plugin_block_dht.c:131 +msgid "Size mismatch for block\n" +msgstr "" + +#: src/dht/plugin_block_dht.c:140 +#, c-format +msgid "Block of type %u is malformed\n" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:337 +msgid "only monitor DNS queries" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:340 +msgid "only monitor DNS replies" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:348 +msgid "Monitor DNS queries." +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:236 +msgid "set A records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:239 +msgid "set AAAA records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:247 +msgid "Change DNS replies to point elsewhere." +msgstr "" + +#: src/dns/gnunet-service-dns.c:480 +#, fuzzy, c-format +msgid "Could not bind to any port: %s\n" +msgstr "Imposible encontrar la IP del host '%s': %s\n" + +#: src/dns/gnunet-service-dns.c:634 +msgid "# DNS requests answered via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:818 +msgid "# DNS exit failed (failed to open socket)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1001 +#, c-format +msgid "Received DNS response that is too small (%u bytes)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1046 +msgid "# External DNS response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1165 +msgid "# Client response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1198 +msgid "Changing DNS reply according to client specifications\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1279 +msgid "Received malformed IPv4-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1294 +msgid "Received malformed IPv6-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1303 +#, c-format +msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1312 +msgid "# Non-DNS UDP packet received via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1377 +#, fuzzy +msgid "# DNS requests received via TUN interface" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/dns/gnunet-service-dns.c:1461 +#, c-format +msgid "Configured DNS exit `%s' is not working / valid.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1493 src/exit/gnunet-daemon-exit.c:2673 +msgid "# Inbound MESH tunnels created" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1567 +msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" +msgstr "" + +#: src/dv/dv_api.c:179 +#, fuzzy +msgid "Failed to connect to the dv service!\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/dv/plugin_transport_dv.c:159 +#, fuzzy, c-format +msgid "%s Received message from %s of type %d, distance %u!\n" +msgstr "Recibido mensaje corrupto del par '%s' en %s:%d.\n" + +#: src/exit/gnunet-daemon-exit.c:508 +#, c-format +msgid "Got duplicate service records for `%s:%u'\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:563 +#, fuzzy +msgid "# Bytes transmitted via mesh tunnels" +msgstr "# bytes desencriptados" + +#: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2068 +#: src/exit/gnunet-daemon-exit.c:2318 src/vpn/gnunet-service-vpn.c:1388 +#: src/vpn/gnunet-service-vpn.c:1788 src/vpn/gnunet-service-vpn.c:1951 +msgid "# ICMPv4 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2127 +#: src/exit/gnunet-daemon-exit.c:2377 src/vpn/gnunet-service-vpn.c:1444 +#: src/vpn/gnunet-service-vpn.c:1847 src/vpn/gnunet-service-vpn.c:1984 +msgid "# ICMPv6 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:756 +msgid "# ICMP packets dropped (not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:763 +msgid "ICMP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:840 +msgid "UDP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:915 +msgid "TCP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:968 +#, fuzzy +msgid "# Packets received from TUN" +msgstr "# bytes recibidos vía HTTP" + +#: src/exit/gnunet-daemon-exit.c:982 +#, fuzzy +msgid "# Bytes received from TUN" +msgstr "# bytes recibidos vía HTTP" + +#: src/exit/gnunet-daemon-exit.c:1008 +msgid "IPv4 packet options received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1035 +#, c-format +msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1081 +#, c-format +msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1089 +#, c-format +msgid "Packet from unknown protocol %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1470 +#, fuzzy +msgid "# TCP packets sent via TUN" +msgstr "# bytes enviados vía UDP" + +#: src/exit/gnunet-daemon-exit.c:1570 +#, fuzzy +msgid "# TCP service creation requests received via mesh" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/exit/gnunet-daemon-exit.c:1573 src/exit/gnunet-daemon-exit.c:1652 +#: src/exit/gnunet-daemon-exit.c:1762 src/exit/gnunet-daemon-exit.c:1992 +#: src/exit/gnunet-daemon-exit.c:2234 src/exit/gnunet-daemon-exit.c:2515 +#: src/exit/gnunet-daemon-exit.c:2615 +#, fuzzy +msgid "# Bytes received from MESH" +msgstr "# bytes recibidos vía HTTP" + +#: src/exit/gnunet-daemon-exit.c:1606 src/exit/gnunet-daemon-exit.c:2637 +#, c-format +msgid "No service found for %s on port %d!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1610 +#, fuzzy +msgid "# TCP requests dropped (no such service)" +msgstr "# Anuncios de los pares recibidos" + +#: src/exit/gnunet-daemon-exit.c:1655 +#, fuzzy +msgid "# TCP IP-exit creation requests received via mesh" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/exit/gnunet-daemon-exit.c:1765 +#, fuzzy +msgid "# TCP data requests received via mesh" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/exit/gnunet-daemon-exit.c:1779 +#, fuzzy +msgid "# TCP DATA requests dropped (no session)" +msgstr "# Anuncios de los pares recibidos" + +#: src/exit/gnunet-daemon-exit.c:1829 +#, fuzzy +msgid "# ICMP packets sent via TUN" +msgstr "# bytes enviados vía UDP" + +#: src/exit/gnunet-daemon-exit.c:1995 +#, fuzzy +msgid "# ICMP IP-exit requests received via mesh" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/exit/gnunet-daemon-exit.c:2237 +#, fuzzy +msgid "# ICMP service requests received via mesh" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/exit/gnunet-daemon-exit.c:2303 src/vpn/gnunet-service-vpn.c:1378 +#: src/vpn/gnunet-service-vpn.c:1945 +msgid "# ICMPv4 packets dropped (impossible PT to v6)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2362 src/vpn/gnunet-service-vpn.c:1414 +#: src/vpn/gnunet-service-vpn.c:1426 src/vpn/gnunet-service-vpn.c:1835 +msgid "# ICMPv6 packets dropped (impossible PT to v4)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2412 +#, fuzzy +msgid "# UDP packets sent via TUN" +msgstr "# bytes enviados vía UDP" + +#: src/exit/gnunet-daemon-exit.c:2518 +#, fuzzy +msgid "# UDP IP-exit requests received via mesh" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/exit/gnunet-daemon-exit.c:2618 +#, fuzzy +msgid "# UDP service requests received via mesh" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/exit/gnunet-daemon-exit.c:2641 +#, fuzzy +msgid "# UDP requests dropped (no such service)" +msgstr "# Anuncios de los pares recibidos" + +#: src/exit/gnunet-daemon-exit.c:2881 +#, c-format +msgid "No addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2895 src/exit/gnunet-daemon-exit.c:2907 +#, c-format +msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2918 +#, c-format +msgid "No IP addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3047 +msgid "" +"This system does not support IPv4, will disable IPv4 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3055 +msgid "" +"This system does not support IPv6, will disable IPv6 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3062 +msgid "" +"Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " +"ENABLE_IPv4=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3068 +msgid "" +"Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " +"ENABLE_IPv6=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3074 src/pt/gnunet-daemon-pt.c:884 +msgid "No useful service enabled. Exiting.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3235 +msgid "Daemon to run to provide an IP exit node for the VPN" +msgstr "" + +#: src/fragmentation/defragmentation.c:270 +msgid "# acknowledgements sent for fragment" +msgstr "" + +#: src/fragmentation/defragmentation.c:454 +#, fuzzy +msgid "# fragments received" +msgstr "# fragmentos descartados" + +#: src/fragmentation/defragmentation.c:513 +#, fuzzy +msgid "# duplicate fragments received" +msgstr "# bytes recibidos por TCP" + +#: src/fragmentation/defragmentation.c:526 +msgid "# messages defragmented" +msgstr "# mensajes defragmentados" + +#: src/fragmentation/fragmentation.c:188 +#, fuzzy +msgid "# fragments transmitted" +msgstr "# Auto-anuncios transmitidos" + +#: src/fragmentation/fragmentation.c:191 +#, fuzzy +msgid "# fragments retransmitted" +msgstr "# Auto-anuncios transmitidos" + +#: src/fragmentation/fragmentation.c:255 +msgid "# messages fragmented" +msgstr "# mensajes fragmentados" + +#: src/fragmentation/fragmentation.c:258 +msgid "# total size of fragmented messages" +msgstr "" + +#: src/fragmentation/fragmentation.c:343 +#, fuzzy +msgid "# fragment acknowledgements received" +msgstr "# Anuncios de los pares recibidos" + +#: src/fragmentation/fragmentation.c:349 +msgid "# bits removed from fragmentation ACKs" +msgstr "" + +#: src/fragmentation/fragmentation.c:373 +#, fuzzy +msgid "# fragmentation transmissions completed" +msgstr "# mensajes de texto mandados por PING" + +#: src/fs/fs_api.c:284 +#, fuzzy, c-format +msgid "Could not open file `%s': %s" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_api.c:293 +#, fuzzy, c-format +msgid "Could not read file `%s': %s" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_api.c:299 +#, c-format +msgid "Short read reading from file `%s'!" +msgstr "" + +#: src/fs/fs_api.c:877 +#, fuzzy, c-format +msgid "Failed to resume publishing information `%s': %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_api.c:1334 +#, c-format +msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" +msgstr "" + +#: src/fs/fs_api.c:1376 +#, c-format +msgid "Failure while resuming publishing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:1392 +#, fuzzy, c-format +msgid "Failed to resume publishing operation `%s': %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_api.c:2004 +#, c-format +msgid "Failure while resuming unindexing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2014 +#, fuzzy, c-format +msgid "Failed to resume unindexing operation `%s': %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_api.c:2139 src/fs/fs_api.c:2378 +#, fuzzy, c-format +msgid "Failed to resume sub-download `%s': %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_api.c:2156 +#, fuzzy, c-format +msgid "Failed to resume sub-search `%s': %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_api.c:2168 src/fs/fs_api.c:2187 src/fs/fs_api.c:2671 +#, c-format +msgid "Failure while resuming search operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2369 +#, c-format +msgid "Failed to resume sub-download `%s': could not open file `%s'\n" +msgstr "" + +#: src/fs/fs_api.c:2615 +msgid "Could not resume running search, will resume as paused search\n" +msgstr "" + +#: src/fs/fs_api.c:2709 +#, c-format +msgid "Failure while resuming download operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_directory.c:210 +#, fuzzy +msgid "MAGIC mismatch. This is not a GNUnet directory.\n" +msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#: src/fs/fs_download.c:310 +msgid "" +"Recursive downloads of directories larger than 4 GB are not supported on 32-" +"bit systems\n" +msgstr "" + +#: src/fs/fs_download.c:330 +msgid "Directory too large for system address space\n" +msgstr "" + +#: src/fs/fs_download.c:488 src/fs/fs_download.c:500 +#, fuzzy, c-format +msgid "Failed to open file `%s' for writing" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_download.c:870 +#, fuzzy, c-format +msgid "Failed to create directory for recursive download of `%s'\n" +msgstr "Falló al actualizar los datos del módulo '%s'\n" + +#: src/fs/fs_download.c:951 +#, c-format +msgid "" +"Internal error or bogus download URI (expected %u bytes at depth %u and " +"offset %llu/%llu, got %u bytes)\n" +msgstr "" + +#: src/fs/fs_download.c:977 +msgid "internal error decrypting content" +msgstr "" + +#: src/fs/fs_download.c:1000 +#, fuzzy, c-format +msgid "Download failed: could not open file `%s': %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_download.c:1010 +#, fuzzy, c-format +msgid "Failed to seek to offset %llu in file `%s': %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_download.c:1019 +#, c-format +msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s\n" +msgstr "" + +#: src/fs/fs_download.c:1835 +#, fuzzy +msgid "Invalid URI" +msgstr "Argumento no válido: '%s'\n" + +#: src/fs/fs_getopt.c:191 +#, c-format +msgid "" +"Unknown metadata type in metadata option `%s'. Using metadata type " +"`unknown' instead.\n" +msgstr "" +"Tipo de metadatos desconocido en la opción de metadatos '%s'. Usando el " +"tipo de metadatos 'desconocido' en su lugar.\n" + +#: src/fs/fs_list_indexed.c:90 +#, fuzzy, c-format +msgid "Failed to receive response for `%s' request from `%s' service.\n" +msgstr "Falló al recibir la respuesta al mensaje '%s' de gnunetd\n" + +#: src/fs/fs_list_indexed.c:113 +#, fuzzy, c-format +msgid "Failed to receive valid response for `%s' request from `%s' service.\n" +msgstr "Falló al recibir la respuesta al mensaje '%s' de gnunetd\n" + +#: src/fs/fs_list_indexed.c:151 +#, fuzzy, c-format +msgid "Failed to not connect to `%s' service.\n" +msgstr "Falló al inicializar el servicio '%s'.\n" + +#: src/fs/fs_misc.c:126 +#, fuzzy, c-format +msgid "Did not find mime type `%s' in extension list.\n" +msgstr "¡Imposible encontrar el par '%s' en la tabla de enrutado!\n" + +#: src/fs/fs_namespace_advertise.c:150 +#, fuzzy +msgid "Unknown error" +msgstr "Error desconocido" + +#: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 +#, fuzzy +msgid "Failed to serialize meta data" +msgstr "Imposible inicializar SQLite.\n" + +#: src/fs/fs_namespace_advertise.c:278 +#, fuzzy +msgid "Failed to connect to datastore service" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 +#, fuzzy, c-format +msgid "Configuration fails to specify `%s' in section `%s'\n" +msgstr "" +"El fichero de configuración debe especificar el directorio para almacenar " +"los datos FS en la sección '%s' bajo '%s'.\n" + +#: src/fs/fs_namespace.c:112 +#, fuzzy, c-format +msgid "Failed to open `%s' for writing: %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 +#, fuzzy, c-format +msgid "Failed to write `%s': %s\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/fs/fs_namespace.c:256 +#, fuzzy, c-format +msgid "Failed to create or read private key for namespace `%s'\n" +msgstr "Falló al actualizar los datos del módulo '%s'\n" + +#: src/fs/fs_namespace.c:371 +#, fuzzy, c-format +msgid "Failed to read namespace private key file `%s', deleting it!\n" +msgstr "Fallo al añadir la entrada al espacio '%s' (¿existe?)\n" + +#: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 +#, fuzzy +msgid "Internal error." +msgstr "Error desconocido.\n" + +#: src/fs/fs_namespace.c:631 +#, fuzzy +msgid "Failed to connect to datastore." +msgstr "Fallo al conectarse a gnunetd" + +#: src/fs/fs_publish.c:129 src/fs/fs_publish.c:395 +#, fuzzy, c-format +msgid "Publishing failed: %s" +msgstr "" +"\n" +"Error subiendo el fichero %s\n" + +#: src/fs/fs_publish.c:616 src/fs/fs_publish.c:633 src/fs/fs_publish.c:672 +#: src/fs/fs_publish.c:692 src/fs/fs_publish.c:717 src/fs/fs_publish.c:857 +#, fuzzy, c-format +msgid "Can not index file `%s': %s. Will try to insert instead.\n" +msgstr "Indexación del fichero '%s' fallida. Intentando insertar fichero...\n" + +#: src/fs/fs_publish.c:618 +msgid "timeout on index-start request to `fs' service" +msgstr "" + +#: src/fs/fs_publish.c:630 +#, fuzzy +msgid "unknown error" +msgstr "Error desconocido" + +#: src/fs/fs_publish.c:673 +msgid "failed to compute hash" +msgstr "" + +#: src/fs/fs_publish.c:693 +msgid "filename too long" +msgstr "" + +#: src/fs/fs_publish.c:718 +#, fuzzy +msgid "could not connect to `fs' service" +msgstr "Imposible conectar con gnunetd.\n" + +#: src/fs/fs_publish.c:741 +#, fuzzy, c-format +msgid "Failed to get file identifiers for `%s'\n" +msgstr "Falló al actualizar los datos del módulo '%s'\n" + +#: src/fs/fs_publish.c:806 +#, fuzzy, c-format +msgid "Recursive upload failed at `%s': %s" +msgstr "'%s' falló en %s: %d con error: '%s'.\n" + +#: src/fs/fs_publish.c:812 +#, fuzzy, c-format +msgid "Recursive upload failed: %s" +msgstr "" +"\n" +"Error subiendo el fichero %s\n" + +#: src/fs/fs_publish.c:858 +#, fuzzy +msgid "needs to be an actual file" +msgstr "'%s' no es un fichero regular.\n" + +#: src/fs/fs_publish.c:1067 +#, c-format +msgid "Insufficient space for publishing: %s" +msgstr "" + +#: src/fs/fs_publish.c:1138 +#, c-format +msgid "Reserving space for %u entries and %llu bytes for publication\n" +msgstr "" + +#: src/fs/fs_publish_ksk.c:258 +#, fuzzy +msgid "Could not connect to datastore." +msgstr "Imposible conectar con gnunetd.\n" + +#: src/fs/fs_search.c:810 +#, c-format +msgid "Got result with unknown block type `%d', ignoring" +msgstr "" + +#: src/fs/fs_test_lib.c:269 +#, fuzzy, c-format +msgid "Failed to start daemon: %s\n" +msgstr "Falló al comenzar la recolección.\n" + +#: src/fs/fs_unindex.c:57 +msgid "Failed to find given position in file" +msgstr "" + +#: src/fs/fs_unindex.c:62 +#, fuzzy +msgid "Failed to read file" +msgstr "Falló al entregar el mensaje '%s'.\n" + +#: src/fs/fs_unindex.c:231 +msgid "Unexpected time for a response from `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:239 +msgid "Timeout waiting for `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:247 +#, fuzzy +msgid "Invalid response from `fs' service." +msgstr "Respuesta inválida a '%s'.\n" + +#: src/fs/fs_unindex.c:292 +#, fuzzy +msgid "Failed to connect to FS service for unindexing." +msgstr "Fallo al conectarse a gnunetd" + +#: src/fs/fs_unindex.c:325 +#, fuzzy +msgid "Failed to connect to `datastore' service." +msgstr "Falló al inicializar el servicio '%s'.\n" + +#: src/fs/fs_unindex.c:338 +#, fuzzy +msgid "Failed to open file for unindexing." +msgstr "Fallo al conectarse a gnunetd" + +#: src/fs/fs_unindex.c:372 +#, fuzzy +msgid "Failed to compute hash of file." +msgstr "Fallo al conectarse a gnunetd" + +#: src/fs/fs_uri.c:220 +#, c-format +msgid "`%' must be followed by HEX number" +msgstr "" + +#: src/fs/fs_uri.c:279 +#, fuzzy +msgid "Malformed KSK URI (must not begin or end with `+')" +msgstr "URL invalida '%s' (debe comenzar por '%s')\n" + +#: src/fs/fs_uri.c:297 +msgid "`++' not allowed in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:304 +msgid "Quotes not balanced in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 +msgid "Malformed SKS URI" +msgstr "" + +#: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 +msgid "Malformed CHK URI" +msgstr "" + +#: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 +#: src/fs/fs_uri.c:621 +msgid "SKS URI malformed" +msgstr "" + +#: src/fs/fs_uri.c:603 +msgid "SKS URI malformed (could not decode public key)" +msgstr "" + +#: src/fs/fs_uri.c:609 +msgid "SKS URI malformed (could not find signature)" +msgstr "" + +#: src/fs/fs_uri.c:615 +msgid "SKS URI malformed (could not decode signature)" +msgstr "" + +#: src/fs/fs_uri.c:628 +msgid "SKS URI malformed (could not parse expiration time)" +msgstr "" + +#: src/fs/fs_uri.c:640 +msgid "SKS URI malformed (signature failed validation)" +msgstr "" + +#: src/fs/fs_uri.c:678 +msgid "Unrecognized URI type" +msgstr "" + +#: src/fs/fs_uri.c:903 +#, fuzzy +msgid "Lacking key configuration settings.\n" +msgstr "Configuración de GNUnet" + +#: src/fs/fs_uri.c:910 +#, fuzzy, c-format +msgid "Could not access hostkey file `%s'.\n" +msgstr "Imposible pasar el fichero de configuración '%s'.\n" + +#: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 +msgid "No keywords specified!\n" +msgstr "¡Ninguna clave especificada!\n" + +#: src/fs/fs_uri.c:1148 +msgid "Number of double-quotes not balanced!\n" +msgstr "" + +#: src/fs/gnunet-directory.c:49 +#, c-format +msgid "\t\n" +msgstr "" + +#: src/fs/gnunet-directory.c:94 +#, fuzzy, c-format +msgid "Directory `%s' meta data:\n" +msgstr "==> Directorio '%s':\n" + +#: src/fs/gnunet-directory.c:97 +#, fuzzy, c-format +msgid "Directory `%s' contents:\n" +msgstr "==> Directorio '%s':\n" + +#: src/fs/gnunet-directory.c:132 +#, fuzzy +msgid "You must specify a filename to inspect.\n" +msgstr "Debes especificar una lista de ficheros a insertar.\n" + +#: src/fs/gnunet-directory.c:145 +#, fuzzy, c-format +msgid "Failed to read directory `%s'\n" +msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#: src/fs/gnunet-directory.c:154 +#, fuzzy, c-format +msgid "`%s' is not a GNUnet directory\n" +msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#: src/fs/gnunet-directory.c:179 +#, fuzzy +msgid "Display contents of a GNUnet directory" +msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#: src/fs/gnunet-download.c:100 +#, fuzzy, c-format +msgid "Starting download `%s'.\n" +msgstr "Iniciada colección '%s'.\n" + +#: src/fs/gnunet-download.c:109 +#, fuzzy +msgid "" +msgstr "Error desconocido" + +#: src/fs/gnunet-download.c:118 +#, c-format +msgid "" +"Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " +"download\n" +msgstr "" + +#: src/fs/gnunet-download.c:128 +#, fuzzy, c-format +msgid "Error downloading: %s.\n" +msgstr "Error descargando: %s\n" + +#: src/fs/gnunet-download.c:136 +#, fuzzy, c-format +msgid "Downloading `%s' done (%s/s).\n" +msgstr "¡Subida rechazada!" + +#: src/fs/gnunet-download.c:151 src/fs/gnunet-publish.c:190 +#: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 +#, fuzzy, c-format +msgid "Unexpected status: %d\n" +msgstr "Estado de descarga inesperado." + +#: src/fs/gnunet-download.c:176 +#, fuzzy +msgid "You need to specify a URI argument.\n" +msgstr "¡Debes especificar un receptor!\n" + +#: src/fs/gnunet-download.c:182 src/fs/gnunet-publish.c:618 +#, fuzzy, c-format +msgid "Failed to parse URI: %s\n" +msgstr "El fichero '%s' tiene la URI: '%s'\n" + +#: src/fs/gnunet-download.c:189 +msgid "Only CHK or LOC URIs supported.\n" +msgstr "" + +#: src/fs/gnunet-download.c:196 +msgid "Target filename must be specified.\n" +msgstr "" + +#: src/fs/gnunet-download.c:210 src/fs/gnunet-publish.c:596 +#: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 +#, fuzzy, c-format +msgid "Could not initialize `%s' subsystem.\n" +msgstr "Falló al inicializar el servicio '%s'.\n" + +#: src/fs/gnunet-download.c:247 src/fs/gnunet-search.c:285 +msgid "set the desired LEVEL of receiver-anonymity" +msgstr "seleccione el NIVEL deseado de anonimidad-del-receptor" + +#: src/fs/gnunet-download.c:250 +msgid "delete incomplete downloads (when aborted with CTRL-C)" +msgstr "" + +#: src/fs/gnunet-download.c:253 src/fs/gnunet-search.c:288 +msgid "only search the local peer (no P2P network search)" +msgstr "" + +#: src/fs/gnunet-download.c:256 +msgid "write the file to FILENAME" +msgstr "escribe el fichero al FICHERO" + +#: src/fs/gnunet-download.c:260 +msgid "set the maximum number of parallel downloads that is allowed" +msgstr "" + +#: src/fs/gnunet-download.c:264 +msgid "set the maximum number of parallel requests for blocks that is allowed" +msgstr "" + +#: src/fs/gnunet-download.c:267 +msgid "download a GNUnet directory recursively" +msgstr "descarga un directorio de GNUnet recursivamente" + +#: src/fs/gnunet-download.c:277 +msgid "" +"Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" +"chk/...)" +msgstr "" + +#: src/fs/gnunet-fs.c:117 +msgid "print a list of all indexed files" +msgstr "" + +#: src/fs/gnunet-fs.c:124 +msgid "Special file-sharing operations" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:151 src/statistics/gnunet-statistics.c:126 +#, fuzzy, c-format +msgid "Invalid argument `%s'\n" +msgstr "Argumento no válido: '%s'\n" + +#: src/fs/gnunet-pseudonym.c:165 +#, fuzzy, c-format +msgid "Namespace `%s' unknown.\n" +msgstr "El espacio '%s' ha sido valorado con un %d.\n" + +#: src/fs/gnunet-pseudonym.c:240 src/fs/gnunet-pseudonym.c:247 +#: src/fs/gnunet-pseudonym.c:249 +#, fuzzy, c-format +msgid "Option `%s' ignored\n" +msgstr "%s: la opción '%s' es ambigua\n" + +#: src/fs/gnunet-pseudonym.c:269 src/fs/gnunet-publish.c:672 +msgid "set the desired LEVEL of sender-anonymity" +msgstr "seleccione el NIVEL deseado de anonimato al enviar" + +#: src/fs/gnunet-pseudonym.c:272 +msgid "create or advertise namespace NAME" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:275 +msgid "delete namespace NAME " +msgstr "" + +#: src/fs/gnunet-pseudonym.c:278 +#, fuzzy +msgid "" +"add an additional keyword for the advertisment (this option can be specified " +"multiple times)" +msgstr "" +"añade una clave adicional para todos los ficheros y directorios (esta opción " +"puede ser especificada varias veces)" + +#: src/fs/gnunet-pseudonym.c:282 src/fs/gnunet-publish.c:691 +msgid "set the meta-data for the given TYPE to the given VALUE" +msgstr "cambia el meta-dato para el TIPO dado al VALOR dado" + +#: src/fs/gnunet-pseudonym.c:285 +#, fuzzy +msgid "print names of local namespaces" +msgstr "cambia la valoración de un espacio" + +#: src/fs/gnunet-pseudonym.c:288 +msgid "use the given PRIORITY for the advertisments" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:291 +msgid "do not print names of remote namespaces" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:294 src/fs/gnunet-publish.c:710 +msgid "set the desired replication LEVEL" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:297 +#, fuzzy +msgid "specify ID of the root of the namespace" +msgstr "cambia la valoración de un espacio" + +#: src/fs/gnunet-pseudonym.c:300 +#, fuzzy +msgid "change rating of namespace ID by VALUE" +msgstr "cambia la valoración de un espacio" + +#: src/fs/gnunet-pseudonym.c:308 +msgid "Manage GNUnet pseudonyms." +msgstr "" + +#: src/fs/gnunet-publish.c:147 +#, c-format +msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-publish.c:155 +#, fuzzy, c-format +msgid "Error publishing: %s.\n" +msgstr "Error descargando: %s\n" + +#: src/fs/gnunet-publish.c:165 +#, c-format +msgid "Publishing `%s' done.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:169 +#, fuzzy, c-format +msgid "URI is `%s'.\n" +msgstr "Yo soy el par '%s'.\n" + +#: src/fs/gnunet-publish.c:187 +#, fuzzy +msgid "Cleanup after abort complete.\n" +msgstr "'%s' comienzo completo.\n" + +#: src/fs/gnunet-publish.c:299 +#, fuzzy, c-format +msgid "Meta data for file `%s' (%s)\n" +msgstr "Actualizando los datos del módulo '%s'\n" + +#: src/fs/gnunet-publish.c:301 +#, fuzzy, c-format +msgid "Keywords for file `%s' (%s)\n" +msgstr "Claves para los ficheros '%s':\n" + +#: src/fs/gnunet-publish.c:352 +#, fuzzy, c-format +msgid "Failed to create namespace `%s'\n" +msgstr "Imposible crear el espacio '%s' (¿existe?).\n" + +#: src/fs/gnunet-publish.c:427 +#, fuzzy +msgid "Could not publish\n" +msgstr "Imposible ejecutar '%s': %s\n" + +#: src/fs/gnunet-publish.c:454 +#, fuzzy +msgid "Could not start publishing.\n" +msgstr "Imposible inicializar la aplicación '%s'\n" + +#: src/fs/gnunet-publish.c:485 +#, fuzzy, c-format +msgid "Scanning directory `%s'.\n" +msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#: src/fs/gnunet-publish.c:487 +#, fuzzy, c-format +msgid "Scanning file `%s'.\n" +msgstr "Iniciada colección '%s'.\n" + +#: src/fs/gnunet-publish.c:492 +#, c-format +msgid "There was trouble processing file `%s', skipping it.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:497 +#, fuzzy +msgid "Preprocessing complete.\n" +msgstr "Cierre completado.\n" + +#: src/fs/gnunet-publish.c:501 +#, fuzzy, c-format +msgid "Extracting meta data from file `%s' complete.\n" +msgstr "Actualizando los datos del módulo '%s'\n" + +#: src/fs/gnunet-publish.c:505 +msgid "Meta data extraction has finished.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:512 +#, fuzzy +msgid "Internal error scanning directory.\n" +msgstr "=\tError leyendo el directorio.\n" + +#: src/fs/gnunet-publish.c:546 +#, c-format +msgid "Cannot extract metadata from a URI!\n" +msgstr "" + +#: src/fs/gnunet-publish.c:553 +#, fuzzy, c-format +msgid "You must specify one and only one filename for insertion.\n" +msgstr "Debes especificar uno y solo un fichero para desindexar.\n" + +#: src/fs/gnunet-publish.c:559 +#, fuzzy, c-format +msgid "You must NOT specify an URI and a filename.\n" +msgstr "¡Debes especificar un receptor!\n" + +#: src/fs/gnunet-publish.c:567 src/vpn/gnunet-vpn.c:214 +#, fuzzy, c-format +msgid "Option `%s' is required when using option `%s'.\n" +msgstr "La opción '%s' no tiene sentido sin la opción '%s'.\n" + +#: src/fs/gnunet-publish.c:577 src/fs/gnunet-publish.c:584 +#: src/transport/gnunet-transport.c:530 +#, c-format +msgid "Option `%s' makes no sense without option `%s'.\n" +msgstr "La opción '%s' no tiene sentido sin la opción '%s'.\n" + +#: src/fs/gnunet-publish.c:606 +#, fuzzy, c-format +msgid "Could not create namespace `%s'\n" +msgstr "Imposible crear el espacio '%s' (¿existe?).\n" + +#: src/fs/gnunet-publish.c:639 +#, fuzzy, c-format +msgid "Failed to access `%s': %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/gnunet-publish.c:651 +msgid "" +"Failed to start meta directory scanner. Is gnunet-helper-publish-fs " +"installed?\n" +msgstr "" + +#: src/fs/gnunet-publish.c:676 +msgid "disable adding the creation time to the metadata of the uploaded file" +msgstr "" + +#: src/fs/gnunet-publish.c:679 +msgid "do not use libextractor to add keywords or metadata" +msgstr "" + +#: src/fs/gnunet-publish.c:683 +msgid "" +"print list of extracted keywords that would be used, but do not perform " +"upload" +msgstr "" +"imprime la lista de las claves extraidas que podrían ser usadas, pero no " +"realiza la subida" + +#: src/fs/gnunet-publish.c:687 +msgid "" +"add an additional keyword for the top-level file or directory (this option " +"can be specified multiple times)" +msgstr "" +"añade una clave adicional para el fichero del nivel más alto o el directorio " +"(esta opción puede ser especificada varias veces)" + +#: src/fs/gnunet-publish.c:694 +msgid "" +"do not index, perform full insertion (stores entire file in encrypted form " +"in GNUnet database)" +msgstr "" +"no indexar, hacer inserciones totales (almacena el fichero entero de forma " +"encriptada en la base de datos de GNUnet)" + +#: src/fs/gnunet-publish.c:699 +msgid "" +"specify ID of an updated version to be published in the future (for " +"namespace insertions only)" +msgstr "" +"especifica la ID de una versión actualizada para ser publicada en el futuro " +"(para inserciones en el espacio únicamente)" + +#: src/fs/gnunet-publish.c:703 +msgid "specify the priority of the content" +msgstr "especifica la prioridad del contenido" + +#: src/fs/gnunet-publish.c:707 +msgid "publish the files under the pseudonym NAME (place file into namespace)" +msgstr "" +"publica los ficheros bajo el pseudónimo NOMBRE (coloca el fichero en el " +"espacio)" + +#: src/fs/gnunet-publish.c:713 +msgid "" +"only simulate the process but do not do any actual publishing (useful to " +"compute URIs)" +msgstr "" + +#: src/fs/gnunet-publish.c:717 +msgid "" +"set the ID of this version of the publication (for namespace insertions only)" +msgstr "" +"cambia la ID de esta versión de la publicación (para inserciones en el " +"espacio únicamente)" + +#: src/fs/gnunet-publish.c:721 +msgid "" +"URI to be published (can be used instead of passing a file to add keywords " +"to the file with the respective URI)" +msgstr "" + +#: src/fs/gnunet-publish.c:736 +msgid "Publish a file or directory on GNUnet" +msgstr "" + +#: src/fs/gnunet-search.c:111 +#, c-format +msgid "Failed to write directory with search results to `%s'\n" +msgstr "" + +#: src/fs/gnunet-search.c:181 +#, fuzzy, c-format +msgid "Error searching: %s.\n" +msgstr "Error abandonando DHT.\n" + +#: src/fs/gnunet-search.c:231 +#, fuzzy +msgid "Could not create keyword URI from arguments.\n" +msgstr "Imposible crear el espacio '%s' (¿existe?).\n" + +#: src/fs/gnunet-search.c:255 +#, fuzzy +msgid "Could not start searching.\n" +msgstr "Imposible crear el espacio '%s' (¿existe?).\n" + +#: src/fs/gnunet-search.c:291 +msgid "write search results to file starting with PREFIX" +msgstr "" + +#: src/fs/gnunet-search.c:294 +msgid "automatically terminate search after VALUE ms" +msgstr "" + +#: src/fs/gnunet-search.c:301 +msgid "automatically terminate search after VALUE results are found" +msgstr "" + +#: src/fs/gnunet-search.c:308 +msgid "Search GNUnet for files that were published on GNUnet" +msgstr "" + +#: src/fs/gnunet-service-fs.c:240 +msgid "# running average P2P latency (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 +msgid "# Loopback routes suppressed" +msgstr "" + +#: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 +#: src/topology/gnunet-daemon-topology.c:1290 +#: src/topology/gnunet-daemon-topology.c:1297 +#, fuzzy, c-format +msgid "Failed to connect to `%s' service.\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 +#: src/topology/gnunet-daemon-topology.c:654 +#: src/topology/gnunet-daemon-topology.c:756 +#: src/transport/gnunet-service-transport_neighbours.c:960 +#: src/transport/gnunet-service-transport_neighbours.c:1289 +#: src/transport/gnunet-service-transport_neighbours.c:1841 +#: src/transport/gnunet-service-transport_neighbours.c:2499 +#: src/transport/gnunet-service-transport_neighbours.c:2566 +#, fuzzy +msgid "# peers connected" +msgstr "# de pares conectados" + +#: src/fs/gnunet-service-fs_cp.c:696 +#, fuzzy +msgid "# migration stop messages received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_cp.c:700 +#, c-format +msgid "Migration of content to peer `%s' blocked for %llu ms\n" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:735 +msgid "# replies transmitted to other peers" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:741 +msgid "# replies dropped" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 +msgid "# P2P searches active" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:858 +msgid "# artificial delays introduced (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:911 +#, fuzzy +msgid "# replies dropped due to type mismatch" +msgstr "# Anuncios de los pares recibidos" + +#: src/fs/gnunet-service-fs_cp.c:919 +msgid "# replies received for other peers" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:933 +msgid "# replies dropped due to insufficient cover traffic" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:971 +msgid "# P2P searches destroyed due to ultimate reply" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1038 +#, fuzzy +msgid "# requests done for free (low load)" +msgstr "# Anuncios de los pares recibidos" + +#: src/fs/gnunet-service-fs_cp.c:1062 +msgid "# request dropped, priority insufficient" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1072 +#, fuzzy +msgid "# requests done for a price (normal load)" +msgstr "# Anuncios de los pares recibidos" + +#: src/fs/gnunet-service-fs_cp.c:1151 +msgid "# GET requests received (from other peers)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1185 +#, fuzzy +msgid "# requests dropped due to initiator not being connected" +msgstr "# Anuncios de los pares recibidos" + +#: src/fs/gnunet-service-fs_cp.c:1207 +#, fuzzy +msgid "# requests dropped due to missing reverse route" +msgstr "# Anuncios de los pares recibidos" + +#: src/fs/gnunet-service-fs_cp.c:1267 +#, fuzzy +msgid "# requests dropped due TTL underflow" +msgstr "# Anuncios de los pares recibidos" + +#: src/fs/gnunet-service-fs_cp.c:1293 +#, fuzzy +msgid "# requests dropped due to higher-TTL request" +msgstr "# Anuncios de los pares recibidos" + +#: src/fs/gnunet-service-fs_cp.c:1322 +#, fuzzy +msgid "# P2P query messages received and processed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_cp.c:1687 +#, fuzzy +msgid "# migration stop messages sent" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_indexing.c:113 +#: src/fs/gnunet-service-fs_indexing.c:163 +#, fuzzy, c-format +msgid "Configuration option `%s' in section `%s' missing.\n" +msgstr "Fichero de configuración '%s' creado.\n" + +#: src/fs/gnunet-service-fs_indexing.c:121 +#: src/fs/gnunet-service-fs_indexing.c:177 +#, fuzzy, c-format +msgid "Could not open `%s'.\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/gnunet-service-fs_indexing.c:137 +#, fuzzy, c-format +msgid "Error writing `%s'.\n" +msgstr "Error creando usuario" + +#: src/fs/gnunet-service-fs_indexing.c:228 +#, c-format +msgid "" +"Index request received for file `%s' is already indexed as `%s'. Permitting " +"anyway.\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:266 +#, c-format +msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:481 +#, fuzzy, c-format +msgid "Failed to delete bogus block: %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/fs/gnunet-service-fs_indexing.c:539 +msgid "# index blocks removed: original file inaccessible" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:554 +#, fuzzy, c-format +msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" +msgstr "Imposible resolver '%s': %s\n" + +#: src/fs/gnunet-service-fs_indexing.c:556 +#, fuzzy +msgid "not indexed" +msgstr "El desindexado falló" + +#: src/fs/gnunet-service-fs_indexing.c:571 +#, fuzzy, c-format +msgid "Indexed file `%s' changed at offset %llu\n" +msgstr "La indexación de los datos falló en la posición %i.\n" + +#: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 +#: src/fs/gnunet-service-fs_lc.c:488 +#, fuzzy +msgid "# client searches active" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_lc.c:256 +#, fuzzy +msgid "# replies received for local clients" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/fs/gnunet-service-fs_lc.c:321 +#, fuzzy +msgid "# client searches received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_lc.c:356 +msgid "# client searches updated (merged content seen list)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:265 +msgid "# average retransmission delay (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:391 +msgid "# transmission failed (core has no bandwidth)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:420 +#, fuzzy +msgid "# query messages sent to other peers" +msgstr "# bytes de mensajes salientes omitidos" + +#: src/fs/gnunet-service-fs_pe.c:469 +msgid "# delay heap timeout" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:476 +#, fuzzy +msgid "# query plans executed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_pe.c:538 +#, fuzzy +msgid "# requests merged" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_pe.c:544 +#, fuzzy +msgid "# requests refreshed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 +#: src/fs/gnunet-service-fs_pe.c:748 +msgid "# query plan entries" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:285 +#, fuzzy +msgid "# Pending requests created" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 +#, fuzzy +msgid "# Pending requests active" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_pr.c:779 +#, fuzzy +msgid "# replies received and matched" +msgstr "# bytes recibidos por TCP" + +#: src/fs/gnunet-service-fs_pr.c:808 +msgid "# duplicate replies discarded (bloomfilter)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:822 +#, c-format +msgid "Unsupported block type %u\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:835 +msgid "# results found locally" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:953 +msgid "# Datastore `PUT' failures" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:980 +#, fuzzy +msgid "# storage requests dropped due to high load" +msgstr "# Anuncios de los pares recibidos" + +#: src/fs/gnunet-service-fs_pr.c:1015 +#, fuzzy +msgid "# Replies received from DHT" +msgstr "# bytes recibidos vía HTTP" + +#: src/fs/gnunet-service-fs_pr.c:1106 +#, c-format +msgid "Datastore lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1127 +#, c-format +msgid "On-demand lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1174 +msgid "# Datastore lookups concluded (no results)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1188 +msgid "# Datastore lookups concluded (seen all)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1197 +msgid "# Datastore lookups aborted (more than MAX_RESULTS)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1211 +msgid "# requested DBLOCK or IBLOCK not found" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1224 +msgid "# on-demand blocks matched requests" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1237 +msgid "# on-demand lookups performed successfully" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1242 +msgid "# on-demand lookups failed" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 +#: src/fs/gnunet-service-fs_pr.c:1447 +msgid "# Datastore lookups concluded (error queueing)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1327 +msgid "# Datastore lookups concluded (found last result)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1338 +msgid "# Datastore lookups concluded (load too high)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1424 +msgid "# Datastore lookups initiated" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1508 +#, fuzzy +msgid "# GAP PUT messages received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 +#, fuzzy, c-format +msgid "Configuration fails to specify `%s', assuming default value." +msgstr "Fichero de configuración '%s' creado.\n" + +#: src/fs/gnunet-service-fs_push.c:629 +#, c-format +msgid "" +"Invalid value specified for option `%s' in section `%s', content pushing " +"disabled\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:89 +#, c-format +msgid "Unindexing at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:96 +#, fuzzy, c-format +msgid "Error unindexing: %s.\n" +msgstr "" +"\n" +"Error desindexando el fichero: %s\n" + +#: src/fs/gnunet-unindex.c:101 +#, fuzzy +msgid "Unindexing done.\n" +msgstr "Desindexar los ficheros." + +#: src/fs/gnunet-unindex.c:131 +#, fuzzy, c-format +msgid "You must specify one and only one filename for unindexing.\n" +msgstr "Debes especificar uno y solo un fichero para desindexar.\n" + +#: src/fs/gnunet-unindex.c:148 +#, fuzzy +msgid "Could not start unindex operation.\n" +msgstr "Imposible acceder a la información del espacio.\n" + +#: src/fs/gnunet-unindex.c:176 +msgid "Unindex a file that was previously indexed with gnunet-publish." +msgstr "" + +#: src/fs/plugin_block_fs.c:131 +msgid "Reply mismatched in terms of namespace. Discarded.\n" +msgstr "" + +#: src/gns/gns_api.c:221 +#, fuzzy +msgid "Failed to connect to the GNS service!\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/gns/gnunet-gns-lookup.c:210 +msgid "Issue a request to the GNUnet Naming System, prints results." +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:264 +msgid "" +"None of the functions for the hostlist daemon were enabled. I have no " +"reason to run!\n" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:317 +msgid "advertise our hostlist to other peers" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:322 +msgid "" +"bootstrap using hostlists (it is highly recommended that you always use this " +"option)" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:325 +msgid "enable learning about hostlist servers from other peers" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:329 +msgid "provide a hostlist server" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:341 +msgid "GNUnet hostlist server and client" +msgstr "" + +#: src/hostlist/hostlist-client.c:286 +msgid "# bytes downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:307 src/hostlist/hostlist-client.c:339 +#, fuzzy +msgid "# invalid HELLOs downloaded from hostlist servers" +msgstr "# saludos descargados vía HTTP" + +#: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:342 +#, fuzzy, c-format +msgid "Invalid `%s' message received from hostlist at `%s'\n" +msgstr "Mensaje '%s' inválido recibido del par '%s'.\n" + +#: src/hostlist/hostlist-client.c:330 +#, fuzzy +msgid "# valid HELLOs downloaded from hostlist servers" +msgstr "# saludos descargados vía HTTP" + +#: src/hostlist/hostlist-client.c:374 src/hostlist/hostlist-client.c:395 +#, c-format +msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:472 src/hostlist/hostlist-client.c:682 +#: src/hostlist/hostlist-client.c:688 src/hostlist/hostlist-client.c:740 +#: src/hostlist/hostlist-client.c:749 src/hostlist/hostlist-client.c:877 +#: src/hostlist/hostlist-client.c:967 src/hostlist/hostlist-client.c:972 +#: src/transport/plugin_transport_http_client.c:108 +#: src/transport/plugin_transport_http_client.c:123 +#, fuzzy, c-format +msgid "%s failed at %s:%d: `%s'\n" +msgstr "'%s' falló en %s: %d con error: '%s'.\n" + +#: src/hostlist/hostlist-client.c:592 src/hostlist/hostlist-client.c:1342 +msgid "# advertised hostlist URIs" +msgstr "" + +#: src/hostlist/hostlist-client.c:622 +#, c-format +msgid "# advertised URI `%s' downloaded" +msgstr "" + +#: src/hostlist/hostlist-client.c:663 +#, c-format +msgid "" +"Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " +"gets dismissed.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:805 +#, c-format +msgid "Timeout trying to download hostlist from `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:822 +#, c-format +msgid "Download limit of %u bytes exceeded, stopping download\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:842 +#, fuzzy, c-format +msgid "%s failed for `%s' at %s:%d: `%s'\n" +msgstr "'%s' falló en %s: %d con error: '%s'.\n" + +#: src/hostlist/hostlist-client.c:848 +#, fuzzy, c-format +msgid "Download of hostlist `%s' completed.\n" +msgstr "" +"Subida de '%s' completada, la velocidad media de subida actual es %8.3f " +"kbps.\n" + +#: src/hostlist/hostlist-client.c:856 +#, c-format +msgid "Adding successfully tested hostlist `%s' datastore.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:909 +#, c-format +msgid "Bootstrapping using hostlist at `%s'.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:917 +msgid "# hostlist downloads initiated" +msgstr "" + +#: src/hostlist/hostlist-client.c:1045 src/hostlist/hostlist-client.c:1515 +msgid "# milliseconds between hostlist downloads" +msgstr "" + +#: src/hostlist/hostlist-client.c:1054 +#, c-format +msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1092 +msgid "Scheduled saving of hostlists\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1096 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1119 src/hostlist/hostlist-client.c:1135 +#, fuzzy +msgid "# active connections" +msgstr "Configuración de GNUnet" + +#: src/hostlist/hostlist-client.c:1253 +#, c-format +msgid "Initial time between hostlist downloads is %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1284 +#, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1290 +#, c-format +msgid "Loading saved hostlist entries from file `%s' \n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1294 +#, c-format +msgid "Hostlist file `%s' is not existing\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1305 +#, fuzzy, c-format +msgid "Could not open file `%s' for reading to load hostlists: %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/hostlist/hostlist-client.c:1338 +#, c-format +msgid "%u hostlist URIs loaded from file\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1340 +msgid "# hostlist URIs read from file" +msgstr "" + +#: src/hostlist/hostlist-client.c:1373 +#, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1387 +#, fuzzy, c-format +msgid "Could not open file `%s' for writing to save hostlists: %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/hostlist/hostlist-client.c:1392 +#, c-format +msgid "Writing %u hostlist URIs to `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1416 src/hostlist/hostlist-client.c:1433 +#, fuzzy, c-format +msgid "Error writing hostlist URIs to file `%s'\n" +msgstr "Error creando usuario" + +#: src/hostlist/hostlist-client.c:1428 +msgid "# hostlist URIs written to file" +msgstr "" + +#: src/hostlist/hostlist-client.c:1480 +msgid "Learning is enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1483 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1492 +msgid "Learning is not enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1504 +#, c-format +msgid "" +"Since learning is not enabled on this peer, hostlist file `%s' was removed\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1508 +#, fuzzy, c-format +msgid "Hostlist file `%s' could not be removed\n" +msgstr "La clave de sesión del par '%s' no pudo ser verificada.\n" + +#: src/hostlist/hostlist-server.c:134 +#, fuzzy +msgid "bytes in hostlist" +msgstr "# bytes en la base de datos" + +#: src/hostlist/hostlist-server.c:157 +msgid "expired addresses encountered" +msgstr "" + +#: src/hostlist/hostlist-server.c:184 +#: src/topology/gnunet-daemon-topology.c:875 +#, fuzzy, c-format +msgid "Error in communication with PEERINFO service: %s\n" +msgstr "Imprime información de los pares de GNUnet." + +#: src/hostlist/hostlist-server.c:205 +msgid "HELLOs without addresses encountered (ignored)" +msgstr "" + +#: src/hostlist/hostlist-server.c:221 +msgid "bytes not included in hostlist (size limit)" +msgstr "" + +#: src/hostlist/hostlist-server.c:269 +#, c-format +msgid "Refusing `%s' request to hostlist server\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:272 +#, fuzzy +msgid "hostlist requests refused (not HTTP GET)" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/hostlist/hostlist-server.c:280 +msgid "Sending 100 CONTINUE reply\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:287 +#, c-format +msgid "Refusing `%s' request with %llu bytes of upload data\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:291 +#, fuzzy +msgid "hostlist requests refused (upload data)" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/hostlist/hostlist-server.c:299 +msgid "Could not handle hostlist request since I do not have a response yet\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:302 +#, fuzzy +msgid "hostlist requests refused (not ready)" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/hostlist/hostlist-server.c:306 +msgid "Received request for our hostlist\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:307 +#, fuzzy +msgid "hostlist requests processed" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/hostlist/hostlist-server.c:350 +#, fuzzy +msgid "# hostlist advertisements send" +msgstr "# Anuncios a extraños mandados" + +#: src/hostlist/hostlist-server.c:397 +msgid "Advertisement message could not be queued by core\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:565 +#, fuzzy, c-format +msgid "Invalid port number %llu. Exiting.\n" +msgstr "Argumentos no válidos. Saliendo.\n" + +#: src/hostlist/hostlist-server.c:574 +#, c-format +msgid "Hostlist service starts on %s:%llu\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:588 +#, c-format +msgid "Address to obtain hostlist: `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:626 +#, c-format +msgid "Could not start hostlist HTTP server on port %u\n" +msgstr "" + +#: src/mesh/gnunet-service-mesh.c:4595 +#, fuzzy +msgid "Wrong CORE service\n" +msgstr "Deteniendo cron\n" + +#: src/mesh/gnunet-service-mesh.c:4789 +#, fuzzy +msgid "Mesh service is lacking key configuration settings. Exiting.\n" +msgstr "Configuración de GNUnet" + +#: src/mesh/gnunet-service-mesh.c:4798 +#, fuzzy +msgid "Mesh service could not access hostkey. Exiting.\n" +msgstr "Imposible acceder a la información del espacio.\n" + +#: src/namestore/namestore_api.c:272 src/namestore/namestore_api.c:313 +msgid "Namestore added record successfully" +msgstr "" + +#: src/namestore/namestore_api.c:281 src/namestore/namestore_api.c:322 +msgid "Namestore failed to add record" +msgstr "" + +#: src/nat/gnunet-nat-server.c:289 +#, c-format +msgid "Please pass valid port number as the first argument! (got `%s')\n" +msgstr "" + +#: src/nat/gnunet-nat-server.c:328 +msgid "GNUnet NAT traversal test helper daemon" +msgstr "" + +#: src/nat/nat.c:803 +#, c-format +msgid "gnunet-helper-nat-server generated malformed address `%s'\n" +msgstr "" + +#: src/nat/nat.c:852 +#, fuzzy, c-format +msgid "Failed to start %s\n" +msgstr "Falló al comenzar la recolección.\n" + +#: src/nat/nat.c:1121 +#, fuzzy, c-format +msgid "Malformed %s `%s' given in configuration!\n" +msgstr "Imposible guardar la configuración" + +#: src/nat/nat.c:1187 src/nat/nat.c:1197 +#, c-format +msgid "" +"Configuration requires `%s', but binary is not installed properly (SUID bit " +"not set). Option disabled.\n" +msgstr "" + +#: src/nat/nat.c:1329 +msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" +msgstr "" + +#: src/nat/nat.c:1341 +#, c-format +msgid "Running gnunet-helper-nat-client %s %s %u\n" +msgstr "" + +#: src/nat/nat_test.c:348 +#, fuzzy +msgid "Failed to connect to `gnunet-nat-server'\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/nat/nat_test.c:418 +#, c-format +msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" +msgstr "" + +#: src/nse/gnunet-nse-profiler.c:926 +#, fuzzy +msgid "Measure quality and performance of the NSE service." +msgstr "Imposible acceder al servicio" + +#: src/nse/gnunet-service-nse.c:936 +#, c-format +msgid "Proof of work invalid: %llu!\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1391 src/nse/gnunet-service-nse.c:1410 +#: src/nse/gnunet-service-nse.c:1431 +msgid "NSE service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1398 +#, fuzzy +msgid "Invalid work requirement for NSE service. Exiting.\n" +msgstr "Argumentos no válidos. Saliendo.\n" + +#: src/nse/gnunet-service-nse.c:1419 +#, fuzzy +msgid "NSE service could not access hostkey. Exiting.\n" +msgstr "Imposible acceder a la información del espacio.\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:133 +#, fuzzy, c-format +msgid "Removing expired address of transport `%s'\n" +msgstr "Transporte(s) disponible(s): %s\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:195 +msgid "# peers known" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:239 +#, c-format +msgid "" +"File `%s' in directory `%s' does not match naming convention. Removed.\n" +msgstr "" +"El fichero '%s' en el directorio '%s' no sigue la convención de nombres. " +"Eliminando.\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:305 +#, fuzzy, c-format +msgid "Still no peers found in `%s'!\n" +msgstr "¡Imposible descargar adecuadamente el servicio '%s'!\n" + +#: src/peerinfo/peerinfo_api.c:279 +#, fuzzy, c-format +msgid "Failed to transmit message to `%s' service.\n" +msgstr "Falló al inicializar el servicio '%s'.\n" + +#: src/peerinfo/peerinfo_api.c:435 +#, fuzzy +msgid "Failed to receive response from `PEERINFO' service." +msgstr "Falló al recibir la respuesta al mensaje '%s' de gnunetd\n" + +#: src/peerinfo/peerinfo_api.c:463 src/peerinfo/peerinfo_api.c:481 +#, fuzzy +msgid "Received invalid message from `PEERINFO' service.\n" +msgstr "Recibido mensaje UDP6 inválido de %s:%d, omitiendo.\n" + +#: src/peerinfo/peerinfo_api.c:523 +#, fuzzy +msgid "Failed to transmit iteration request to `PEERINFO' service\n" +msgstr "Falló al inicializar el servicio '%s'.\n" + +#: src/peerinfo/peerinfo_api.c:557 +msgid "Timeout transmitting iteration request to `PEERINFO' service.\n" +msgstr "" + +#: src/peerinfo/peerinfo_api_notify.c:258 +#, fuzzy, c-format +msgid "Could not connect to `%s' service.\n" +msgstr "Imposible conectar con gnunetd.\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:216 +#, fuzzy, c-format +msgid "Could not find option `%s:%s' in configuration.\n" +msgstr "¡Imposible encontrar el par '%s' en la tabla de enrutado!\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:223 +#, fuzzy, c-format +msgid "Loading hostkey from `%s' failed.\n" +msgstr "Analizando saludo de '%s' se produjo un fallo.\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:235 +#, c-format +msgid "I am peer `%s'.\n" +msgstr "Yo soy el par '%s'.\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:255 +msgid "output only the identity strings" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:258 +msgid "output our own identity only" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:264 +#, fuzzy +msgid "Print information about peers." +msgstr "Imprime información de los pares de GNUnet." + +#: src/pt/gnunet-daemon-pt.c:264 +#, fuzzy +msgid "Failed to pack DNS request. Dropping.\n" +msgstr "Falló al mandar la petición HTTP al host '%s': %s\n" + +#: src/pt/gnunet-daemon-pt.c:270 +#, fuzzy +msgid "# DNS requests mapped to VPN" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/pt/gnunet-daemon-pt.c:323 +msgid "# DNS records modified" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:500 +msgid "# DNS replies intercepted" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:506 +#, fuzzy +msgid "Failed to parse DNS request. Dropping.\n" +msgstr "Falló al mandar la petición HTTP al host '%s': %s\n" + +#: src/pt/gnunet-daemon-pt.c:602 +#, fuzzy +msgid "# DNS requests dropped (timeout)" +msgstr "# Anuncios de los pares recibidos" + +#: src/pt/gnunet-daemon-pt.c:632 +#, fuzzy +msgid "# DNS requests intercepted" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/pt/gnunet-daemon-pt.c:637 +#, fuzzy +msgid "# DNS requests dropped (DNS mesh tunnel down)" +msgstr "# Anuncios de los pares recibidos" + +#: src/pt/gnunet-daemon-pt.c:645 +#, fuzzy +msgid "# DNS requests dropped (malformed)" +msgstr "# Anuncios de los pares recibidos" + +#: src/pt/gnunet-daemon-pt.c:716 +#, fuzzy +msgid "# DNS replies received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/pt/gnunet-daemon-pt.c:730 +#, fuzzy +msgid "# DNS replies dropped (too late?)" +msgstr "# Anuncios de los pares recibidos" + +#: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 +msgid "# DNS requests aborted (tunnel down)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 +#: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 +#, fuzzy, c-format +msgid "Failed to connect to %s service. Exiting.\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/pt/gnunet-daemon-pt.c:973 +msgid "Daemon to run to perform IP protocol translation to GNUnet" +msgstr "" + +#: src/statistics/gnunet-service-statistics.c:209 +#, fuzzy, c-format +msgid "Loading %llu bytes of statistics from `%s'\n" +msgstr "Descarga los ficheros de GNUnet" + +#: src/statistics/gnunet-service-statistics.c:267 +#, fuzzy, c-format +msgid "Wrote %llu bytes of statistics to `%s'\n" +msgstr "Descarga los ficheros de GNUnet" + +#: src/statistics/gnunet-statistics.c:98 +#, fuzzy +msgid "Failed to obtain statistics.\n" +msgstr "Fallo en las estadísticas del tráfico.\n" + +#: src/statistics/gnunet-statistics.c:164 +msgid "limit output to statistics for the given NAME" +msgstr "" + +#: src/statistics/gnunet-statistics.c:167 +msgid "make the value being set persistent" +msgstr "" + +#: src/statistics/gnunet-statistics.c:170 +msgid "limit output to the given SUBSYSTEM" +msgstr "" + +#: src/statistics/gnunet-statistics.c:173 +msgid "just print the statistics value" +msgstr "" + +#: src/statistics/gnunet-statistics.c:180 +msgid "Print statistics about GNUnet operations." +msgstr "Imprime estadísticas acerca de las operaciones de GNUnet." + +#: src/statistics/statistics_api.c:390 +#, fuzzy +msgid "Failed to connect to statistics service!\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/template/gnunet-template.c:68 +#, fuzzy +msgid "help text" +msgstr "texto de ayuda para -t" + +#: src/testing/gnunet-testing.c:157 +#, fuzzy +msgid "Could not read hostkeys file, specify hostkey file with -H!\n" +msgstr "Imposible inicializar la aplicación '%s'\n" + +#: src/testing/gnunet-testing.c:159 +#, c-format +msgid "Specified hostkey file `%s' not found!\n" +msgstr "" + +#: src/testing/gnunet-testing.c:273 +#, fuzzy +msgid "create unique configuration files" +msgstr "Imposible guardar el fichero de configuración '%s':" + +#: src/testing/gnunet-testing.c:275 +msgid "create hostkey files from pre-computed hostkey list" +msgstr "" + +#: src/testing/gnunet-testing.c:277 +msgid "host key file" +msgstr "" + +#: src/testing/gnunet-testing.c:279 +#, fuzzy +msgid "number of unique configuration files or hostkeys to create" +msgstr "Imposible guardar el fichero de configuración '%s':" + +#: src/testing/gnunet-testing.c:281 +#, fuzzy +msgid "configuration template" +msgstr "Configuración de GNUnet" + +#: src/testing/gnunet-testing.c:287 +msgid "Command line tool to access the testing library" +msgstr "" + +#: src/testing/helper.c:56 +#, fuzzy +msgid "Peer is lacking HOSTKEY configuration setting.\n" +msgstr "Configuración de GNUnet" + +#: src/testing/helper.c:64 +#, fuzzy +msgid "Could not access hostkey.\n" +msgstr "Imposible pasar el fichero de configuración '%s'.\n" + +#: src/testing/testing.c:204 +msgid "`scp' does not seem to terminate (timeout copying config).\n" +msgstr "" + +#: src/testing/testing.c:218 src/testing/testing.c:808 +#, fuzzy +msgid "`scp' did not complete cleanly.\n" +msgstr "'%s' no esta conectado a ningún par.\n" + +#: src/testing/testing.c:239 +#, fuzzy +msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" +msgstr "Falló al comenzar la recolección.\n" + +#: src/testing/testing.c:240 +#, fuzzy +msgid "Failed to create pipe for `ssh' process.\n" +msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#: src/testing/testing.c:292 +#, fuzzy, c-format +msgid "Could not start `%s' process to create hostkey.\n" +msgstr "Imposible mandar el mensaje a gnunetd\n" + +#: src/testing/testing.c:299 +#, fuzzy +msgid "Failed to start `gnunet-peerinfo' process.\n" +msgstr "Falló al comenzar la recolección.\n" + +#: src/testing/testing.c:300 src/testing/testing.c:488 +#, fuzzy +msgid "Failed to start `ssh' process.\n" +msgstr "Falló al comenzar la recolección.\n" + +#: src/testing/testing.c:360 +#, fuzzy, c-format +msgid "Error reading from gnunet-peerinfo: %s\n" +msgstr "Se produjo un error leyendo información de gnunetd.\n" + +#: src/testing/testing.c:364 +#, fuzzy +msgid "Malformed output from gnunet-peerinfo!\n" +msgstr "Se produjo un error leyendo información de gnunetd.\n" + +#: src/testing/testing.c:374 +#, fuzzy +msgid "Failed to get hostkey!\n" +msgstr "Fallo en las estadísticas del tráfico.\n" + +#: src/testing/testing.c:406 +msgid "`Failed while waiting for topology setup!\n" +msgstr "" + +#: src/testing/testing.c:480 +#, fuzzy, c-format +msgid "Could not start `%s' process to start GNUnet.\n" +msgstr "Imposible crear el espacio '%s' (¿existe?).\n" + +#: src/testing/testing.c:487 +#, fuzzy +msgid "Failed to start `gnunet-arm' process.\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/testing/testing.c:509 src/testing/testing.c:612 +msgid "`gnunet-arm' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:510 src/testing/testing.c:613 +#: src/testing/testing.c:633 +msgid "`ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:582 +msgid "Unable to get HELLO for peer!\n" +msgstr "" + +#: src/testing/testing.c:632 +msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" +msgstr "" + +#: src/testing/testing.c:653 src/testing/testing.c:685 +msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:668 src/testing/testing.c:723 +#, fuzzy +msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" +msgstr "'%s' no esta conectado a ningún par.\n" + +#: src/testing/testing.c:796 +msgid "`scp' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:966 +#, fuzzy, c-format +msgid "Starting service %s for peer `%4s'\n" +msgstr "Iniciada colección '%s'.\n" + +#: src/testing/testing.c:1237 src/testing/testing_group.c:6278 +#, fuzzy, c-format +msgid "Could not start `%s' process to copy configuration directory.\n" +msgstr "Imposible acceder a la información del espacio.\n" + +#: src/testing/testing.c:1322 src/testing/testing.c:1397 +#, fuzzy, c-format +msgid "Terminating peer `%4s'\n" +msgstr "Permiso denegado para '%s' en %s:%d.\n" + +#: src/testing/testing.c:1480 +#, fuzzy, c-format +msgid "Setting d->dead on peer `%4s'\n" +msgstr "Iniciada colección '%s'.\n" + +#: src/testing/testing.c:1610 +msgid "Peer not yet running, can not change configuration at this point." +msgstr "" + +#: src/testing/testing.c:1618 +#, fuzzy +msgid "Failed to write new configuration to disk." +msgstr "Imposible guardar la configuración" + +#: src/testing/testing.c:1647 +#, fuzzy, c-format +msgid "Could not start `%s' process to copy configuration file.\n" +msgstr "¡Imposible encontrar el par '%s' en la tabla de enrutado!\n" + +#: src/testing/testing.c:1650 +#, fuzzy +msgid "Failed to copy new configuration to remote machine." +msgstr "Imposible guardar la configuración" + +#: src/testing/testing.c:1805 +#, fuzzy +msgid "Peers failed to connect" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/testing/testing.c:1933 +#, fuzzy +msgid "Failed to connect to core service of first peer!\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/testing/testing.c:2156 +msgid "Peers are not fully running yet, can not connect!\n" +msgstr "" + +#: src/testing/testing_group.c:1910 src/testing/testing_group.c:1922 +#: src/testing/testing_group.c:2023 src/testing/testing_group.c:2082 +#: src/testing/testing_group.c:2171 src/testing/testing_group.c:2191 +#: src/testing/testing_group.c:2328 src/testing/testing_peergroup.c:940 +#, fuzzy, c-format +msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" +msgstr "" +"El fichero de configuración debe especificar el directorio para almacenar " +"los datos FS en la sección '%s' bajo '%s'.\n" + +#: src/testing/testing_group.c:1932 +#, fuzzy, c-format +msgid "Target is %d connections per peer." +msgstr "Se produjo un error estableciendo conexión con gnunetd.\n" + +#: src/testing/testing_group.c:2179 +#, c-format +msgid "" +"Invalid value `%s' for option `%s' in section `%s': got %f, needed value " +"greater than 0\n" +msgstr "" + +#: src/testing/testing_group.c:2209 src/testing/testing_group.c:2402 +#, c-format +msgid "Connecting nodes in 2d torus topology: %u rows %u columns\n" +msgstr "" + +#: src/testing/testing_group.c:2246 +#, c-format +msgid "natural log of %d is %d, will run %d iterations\n" +msgstr "" + +#: src/testing/testing_group.c:2249 +#, c-format +msgid "Total connections added thus far: %u!\n" +msgstr "" + +#: src/testing/testing_group.c:2290 +#, c-format +msgid "Total connections added for small world: %d!\n" +msgstr "" + +#: src/testing/testing_group.c:2342 +#, c-format +msgid "rand is %f probability is %f\n" +msgstr "" + +#: src/testing/testing_group.c:2919 src/testing/testing_group.c:3118 +#, c-format +msgid "" +"No `%s' specified in peer configuration in section `%s', cannot copy friends " +"file!\n" +msgstr "" + +#: src/testing/testing_group.c:3020 +msgid "Finished copying all friend files!\n" +msgstr "" + +#: src/testing/testing_group.c:3133 +#, fuzzy, c-format +msgid "Copying file with command cp %s %s\n" +msgstr "'%s' falló con el código de error %s: %s" + +#: src/testing/testing_group.c:3156 +#, fuzzy, c-format +msgid "Copying file with command scp %s %s\n" +msgstr "'%s' falló con el código de error %s: %s" + +#: src/testing/testing_group.c:3173 +#, c-format +msgid "Checking copy status of file %d\n" +msgstr "" + +#: src/testing/testing_group.c:3191 +#, c-format +msgid "File %d copied\n" +msgstr "" + +#: src/testing/testing_group.c:3206 +#, fuzzy +msgid "Finished copying all blacklist files!\n" +msgstr "Imposible inicializar la aplicación '%s'\n" + +#: src/testing/testing_group.c:3586 src/testing/testing_group.c:3723 +#: src/testing/testing_group.c:4884 src/testing/testing_group.c:5025 +msgid "Delaying connect, we have too many outstanding connections!\n" +msgstr "" + +#: src/testing/testing_group.c:3596 src/testing/testing_group.c:4894 +#: src/testing/testing_group.c:5035 +#, c-format +msgid "Creating connection, outstanding_connections is %d\n" +msgstr "" + +#: src/testing/testing_group.c:3608 +#, fuzzy, c-format +msgid "Offering HELLO of peer %s to peer %s\n" +msgstr "Imposible conectar a %u.%u.%u.%u:%u: %s\n" + +#: src/testing/testing_group.c:3734 +#, c-format +msgid "Creating connection, outstanding_connections is %d (max %d)\n" +msgstr "" + +#: src/testing/testing_group.c:3988 +msgid "Creating clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:3993 +msgid "Creating small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:3998 +msgid "Creating small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4002 +msgid "Creating ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4006 +msgid "Creating 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4010 +msgid "Creating Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4014 +msgid "Creating InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4018 +msgid "Creating Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4023 +msgid "Creating straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4027 +msgid "Creating topology from file!\n" +msgstr "" + +#: src/testing/testing_group.c:4043 +msgid "Creating no allowed topology (all peers can connect at core level)\n" +msgstr "" + +#: src/testing/testing_group.c:4058 +msgid "Failed during friend file copying!\n" +msgstr "" + +#: src/testing/testing_group.c:4064 +msgid "Friend files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:4081 +msgid "Blacklisting all but clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:4087 +msgid "Blacklisting all but small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4093 +msgid "Blacklisting all but small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4099 +msgid "Blacklisting all but ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4105 +msgid "Blacklisting all but 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4111 +msgid "Blacklisting all but Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4117 +msgid "Blacklisting all but InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4152 +msgid "Blacklisting all but Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4158 +msgid "Blacklisting all but straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4173 +#, fuzzy +msgid "Failed during blacklist file copying!\n" +msgstr "Falló al pasar los datos de la interfaz de '%s' de %s:%d.\n" + +#: src/testing/testing_group.c:4179 +msgid "Blacklist files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:5263 +msgid "Creating clique CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5270 +msgid "Creating small world (ring) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5277 +msgid "Creating small world (2d-torus) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5283 +msgid "Creating ring CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5290 +msgid "Creating 2d torus CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5297 +msgid "Creating Erdos-Renyi CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5304 +msgid "Creating InterNAT CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5311 +msgid "Creating Scale Free CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5318 +msgid "Creating straight line CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5324 +msgid "Creating no CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5330 +msgid "Unknown topology specification, can't connect peers!\n" +msgstr "" + +#: src/testing/testing_group.c:5340 +#, c-format +msgid "Connecting random subset (%'.2f percent) of possible peers\n" +msgstr "" + +#: src/testing/testing_group.c:5348 +#, c-format +msgid "Connecting a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5357 +#, c-format +msgid "Using DFS to connect a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5367 +#, c-format +msgid "Finding additional %u closest peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:6062 src/transport/transport-testing.c:650 +#, fuzzy +msgid "Could not read hostkeys file!\n" +msgstr "Imposible inicializar la aplicación '%s'\n" + +#: src/testing/testing_group.c:6131 +#, fuzzy, c-format +msgid "Could not create configuration for peer number %u on `%s'!\n" +msgstr "Imposible acceder a la información del espacio.\n" + +#: src/topology/gnunet-daemon-topology.c:244 +msgid "# peers blacklisted" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:380 +#, fuzzy +msgid "# connect requests issued to transport" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/topology/gnunet-daemon-topology.c:675 +#: src/topology/gnunet-daemon-topology.c:761 +#, fuzzy +msgid "# friends connected" +msgstr "# de pares conectados" + +#: src/topology/gnunet-daemon-topology.c:950 +msgid "Failed to connect to core service, can not manage topology!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:982 +#, c-format +msgid "Option `%s' in section `%s' not specified!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:994 +#, fuzzy, c-format +msgid "Could not read friends list `%s'\n" +msgstr "Imposible inicializar la aplicación '%s'\n" + +#: src/topology/gnunet-daemon-topology.c:1000 +#, fuzzy, c-format +msgid "Friends file `%s' is empty.\n" +msgstr "El formato del fichero '%s' no es válido.\n" + +#: src/topology/gnunet-daemon-topology.c:1009 +#, fuzzy, c-format +msgid "Failed to read friends list from `%s': out of memory\n" +msgstr "Imposible inicializar la aplicación '%s'\n" + +#: src/topology/gnunet-daemon-topology.c:1017 +#, c-format +msgid "Failed to read friends list from `%s'\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1037 +#, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1050 +#, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1060 +#, fuzzy, c-format +msgid "Found friend `%s' in configuration\n" +msgstr " gconfig\tConfiguración GTK\n" + +#: src/topology/gnunet-daemon-topology.c:1066 +#, c-format +msgid "Found myself `%s' in friend list (useless, ignored)\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1076 +#, fuzzy +msgid "# friends in configuration" +msgstr " gconfig\tConfiguración GTK\n" + +#: src/topology/gnunet-daemon-topology.c:1082 +msgid "" +"Fewer friends specified than required by minimum friend count. Will only " +"connect to friends.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1089 +msgid "" +"More friendly connections required than target total number of connections.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1126 +#, fuzzy +msgid "# HELLO messages received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/topology/gnunet-daemon-topology.c:1183 +#, fuzzy +msgid "# HELLO messages gossipped" +msgstr "# mensajes salientes omitidos" + +#: src/topology/gnunet-daemon-topology.c:1323 +msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:247 +#, fuzzy, c-format +msgid "Could not read blacklist file `%s'\n" +msgstr "Imposible inicializar la aplicación '%s'\n" + +#: src/transport/gnunet-service-transport_blacklist.c:254 +#, c-format +msgid "Blacklist file `%s' is empty.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:266 +#, fuzzy, c-format +msgid "Failed to read blacklist from `%s'\n" +msgstr "Falló al pasar los datos de la interfaz de '%s' de %s:%d.\n" + +#: src/transport/gnunet-service-transport_blacklist.c:287 +#: src/transport/gnunet-service-transport_blacklist.c:311 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, giving up!\n" +msgstr "" +"Error de sintaxis en el fichero de configuración '%s' en la linea %d.\n" + +#: src/transport/gnunet-service-transport_blacklist.c:298 +#: src/transport/gnunet-service-transport_blacklist.c:336 +#, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:350 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" +msgstr "" +"Error de sintaxis en el fichero de configuración '%s' en la linea %d.\n" + +#: src/transport/gnunet-service-transport_blacklist.c:364 +#, c-format +msgid "Found myself `%s' in blacklist (useless, ignored)\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:523 +#: src/transport/gnunet-service-transport_blacklist.c:764 +msgid "# disconnects due to blacklist" +msgstr "" + +#: src/transport/gnunet-service-transport.c:158 +#, fuzzy +msgid "# bytes payload discarded due to not connected peer " +msgstr "# Anuncios de los pares recibidos" + +#: src/transport/gnunet-service-transport.c:572 +msgid "Transport service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport.c:581 +msgid "Transport service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:353 +#, c-format +msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:358 +#, fuzzy +msgid "# messages dropped due to slow client" +msgstr "# Anuncios de los pares recibidos" + +#: src/transport/gnunet-service-transport_clients.c:510 +#, c-format +msgid "Rejecting control connection from peer `%s', which is not me!\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:628 +#, fuzzy +msgid "# bytes payload received for other peers" +msgstr "# bytes recibidos por TCP" + +#: src/transport/gnunet-service-transport_clients.c:645 +msgid "# bytes payload dropped (other peer was not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:696 +#, fuzzy +msgid "# REQUEST CONNECT messages received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/gnunet-service-transport_hello.c:172 +msgid "# refreshed my HELLO" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:482 +msgid "# failed connection attempts due to timeout" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:883 +#, fuzzy +msgid "# peers disconnected due to external request" +msgstr "# Anuncios de los pares recibidos" + +#: src/transport/gnunet-service-transport_neighbours.c:966 +#, fuzzy +msgid "# fast reconnects failed" +msgstr "# de pares conectados" + +#: src/transport/gnunet-service-transport_neighbours.c:1022 +#, fuzzy +msgid "# peers disconnected due to timeout" +msgstr "# de pares conectados" + +#: src/transport/gnunet-service-transport_neighbours.c:1047 +#, fuzzy +msgid "# keepalives sent" +msgstr "# claves de la sesión mandadas" + +#: src/transport/gnunet-service-transport_neighbours.c:1088 +#, fuzzy +msgid "# peers disconnected due to global disconnect" +msgstr "# Anuncios de los pares recibidos" + +#: src/transport/gnunet-service-transport_neighbours.c:1888 +#: src/transport/gnunet-service-transport_neighbours.c:1909 +#, fuzzy +msgid "# messages not sent (no such peer or not connected)" +msgstr "# mensajes defragmentados" + +#: src/transport/gnunet-service-transport_neighbours.c:1925 +#, fuzzy +msgid "# bytes in message queue for other peers" +msgstr "# bytes de mensajes salientes omitidos" + +#: src/transport/gnunet-service-transport_neighbours.c:1977 +#, fuzzy +msgid "# messages discarded due to lack of neighbour record" +msgstr "# mensajes defragmentados" + +#: src/transport/gnunet-service-transport_neighbours.c:2013 +msgid "# bandwidth quota violations by other peers" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2031 +msgid "# ms throttling suggested" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2060 +#, fuzzy +msgid "# KEEPALIVE messages discarded (not connected)" +msgstr "# mensajes defragmentados" + +#: src/transport/gnunet-service-transport_neighbours.c:2113 +#, fuzzy +msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" +msgstr "# mensajes defragmentados" + +#: src/transport/gnunet-service-transport_neighbours.c:2121 +#, fuzzy +msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" +msgstr "# mensajes defragmentados" + +#: src/transport/gnunet-service-transport_neighbours.c:2187 +msgid "# SET QUOTA messages ignored (no such peer)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2205 +msgid "# disconnects due to quota of 0" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2323 +msgid "# disconnect messages ignored (old format)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2336 +msgid "# disconnect messages ignored (timestamp)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2411 +#, fuzzy +msgid "# unexpected CONNECT_ACK messages (no peer)" +msgstr "envia COUNT mensajes" + +#: src/transport/gnunet-service-transport_neighbours.c:2453 +#, fuzzy +msgid "# unexpected CONNECT_ACK messages" +msgstr "envia COUNT mensajes" + +#: src/transport/gnunet-service-transport_neighbours.c:2544 +#, fuzzy +msgid "# unexpected ACK messages" +msgstr "# de pares conectados" + +#: src/transport/gnunet-service-transport_plugins.c:111 +msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:118 +#, fuzzy, c-format +msgid "Starting transport plugins `%s'\n" +msgstr "Probando transporte(s) %s\n" + +#: src/transport/gnunet-service-transport_plugins.c:122 +#, fuzzy, c-format +msgid "Loading `%s' transport plugin\n" +msgstr "Probando transporte(s) %s\n" + +#: src/transport/gnunet-service-transport_plugins.c:150 +#, fuzzy, c-format +msgid "Failed to load transport plugin for `%s'\n" +msgstr "Imposible inicializar la aplicación '%s'\n" + +#: src/transport/gnunet-service-transport_validation.c:410 +msgid "# address records discarded" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:459 +#, c-format +msgid "" +"Not transmitting `%s' with `%s', message too big (%u bytes!). This should " +"not happen.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:508 +#, fuzzy +msgid "# PING without HELLO messages sent" +msgstr "# mensajes de texto mandados por PING" + +#: src/transport/gnunet-service-transport_validation.c:566 +msgid "# address revalidations started" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:798 +#, fuzzy +msgid "# PING message for different peer received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/gnunet-service-transport_validation.c:833 +#, c-format +msgid "" +"Not confirming PING with address `%s' since I cannot confirm having this " +"address.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:919 +msgid "# PONGs unicast via reliable transport" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:928 +msgid "# PONGs multicast to all available addresses" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1050 +msgid "# PONGs dropped, no matching pending validation" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1075 +msgid "# PONGs dropped, signature expired" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1134 +#, fuzzy, c-format +msgid "Adding `%s' without addresses for peer `%s'\n" +msgstr "Imposible obtener la dirección del par '%s'.\n" + +#: src/transport/gnunet-transport.c:256 +msgid "No transport plugins configured, peer will never communicate\n" +msgstr "" + +#: src/transport/gnunet-transport.c:269 +#, c-format +msgid "No port configured for plugin `%s', cannot test it\n" +msgstr "" + +#: src/transport/gnunet-transport.c:319 +#, c-format +msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:326 +#, c-format +msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:359 +#, c-format +msgid "Transmitting %u bytes to %s\n" +msgstr "" + +#: src/transport/gnunet-transport.c:379 +#, fuzzy, c-format +msgid "Connected to %s\n" +msgstr "'%s' conectado a '%s'.\n" + +#: src/transport/gnunet-transport.c:410 +#, fuzzy, c-format +msgid "Disconnected from %s\n" +msgstr "'%s' conectado a '%s'.\n" + +#: src/transport/gnunet-transport.c:439 +#, fuzzy, c-format +msgid "Received %u bytes from %s\n" +msgstr "GAP recibido contenido no válido de '%s'\n" + +#: src/transport/gnunet-transport.c:453 +#, fuzzy, c-format +msgid "Peer `%s': %s %s\n" +msgstr "Yo soy el par '%s'.\n" + +#: src/transport/gnunet-transport.c:483 +#, fuzzy, c-format +msgid "Peer `%s' disconnected\n" +msgstr "# de pares conectados" + +#: src/transport/gnunet-transport.c:539 +#, fuzzy, c-format +msgid "Failed to parse peer identity `%s'\n" +msgstr "Falló al actualizar los datos del módulo '%s'\n" + +#: src/transport/gnunet-transport.c:587 +msgid "measure how fast we are receiving data (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:590 +#, fuzzy +msgid "try to connect to the given peer" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/transport/gnunet-transport.c:593 +#, fuzzy +msgid "provide information about all current connections (once)" +msgstr "Imprime información de los pares de GNUnet." + +#: src/transport/gnunet-transport.c:596 +#, fuzzy +msgid "provide information about all current connections (continuously)" +msgstr "Imprime información de los pares de GNUnet." + +#: src/transport/gnunet-transport.c:599 +msgid "do not resolve hostnames" +msgstr "" + +#: src/transport/gnunet-transport.c:603 +msgid "send data for benchmarking to the other peer (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:606 +msgid "test transport configuration (involves external server)" +msgstr "" + +#: src/transport/gnunet-transport.c:614 +#, fuzzy +msgid "Direct access to transport service." +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/transport/plugin_transport_http.c:981 +msgid "Disabling IPv6 since it is not supported on this system!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1029 +#, fuzzy +msgid "Require valid port number for service in configuration!\n" +msgstr "¡Ninguna aplicación definida en la configuración!\n" + +#: src/transport/plugin_transport_http.c:1054 src/util/service.c:986 +#, fuzzy, c-format +msgid "Failed to resolve `%s': %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/transport/plugin_transport_http.c:1071 src/util/service.c:1003 +#, fuzzy, c-format +msgid "Failed to find %saddress for `%s'.\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/transport/plugin_transport_http.c:1176 +#, c-format +msgid "Found %u addresses to report to NAT service\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1189 +#, c-format +msgid "FREEING %s\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1264 +#, fuzzy +msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" +msgstr "¡Advertencias de la red desconectadas por configuración!\n" + +#: src/transport/plugin_transport_http.c:1277 +#, fuzzy +msgid "Port is required! Fix in configuration\n" +msgstr " gconfig\tConfiguración GTK\n" + +#: src/transport/plugin_transport_http.c:1288 +msgid "Port 0, client only mode\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1308 +#, c-format +msgid "" +"Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1338 +#, c-format +msgid "" +"Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http_client.c:621 +#, c-format +msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:189 +msgid "" +"Could not create a new TLS certificate, program `gnunet-transport-" +"certificate-creation' could not be started!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:213 +msgid "No usable TLS certificate found and creating one failed!\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:370 +#, fuzzy, c-format +msgid "Received malformed message via %s. Ignored.\n" +msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" + +#: src/transport/plugin_transport_smtp.c:457 +msgid "SMTP filter string to invalid, lacks ': '\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:466 +#, c-format +msgid "SMTP filter string to long, capped to `%s'\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:561 +#: src/transport/plugin_transport_smtp.c:571 +#: src/transport/plugin_transport_smtp.c:584 +#: src/transport/plugin_transport_smtp.c:603 +#: src/transport/plugin_transport_smtp.c:626 +#: src/transport/plugin_transport_smtp.c:634 +#: src/transport/plugin_transport_smtp.c:647 +#: src/transport/plugin_transport_smtp.c:658 +#, fuzzy, c-format +msgid "SMTP: `%s' failed: %s.\n" +msgstr "'%s' %s falló: %s\n" + +#: src/transport/plugin_transport_smtp.c:801 +msgid "No email-address specified, can not start SMTP transport.\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:813 +#, fuzzy +msgid "# bytes received via SMTP" +msgstr "# bytes recibidos por TCP" + +#: src/transport/plugin_transport_smtp.c:814 +#, fuzzy +msgid "# bytes sent via SMTP" +msgstr "# bytes enviados por TCP" + +#: src/transport/plugin_transport_smtp.c:816 +#, fuzzy +msgid "# bytes dropped by SMTP (outgoing)" +msgstr "# bytes omitidos por TCP (salientes)" + +#: src/transport/plugin_transport_tcp.c:512 +#, c-format +msgid "Unexpected address length: %u bytes\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:616 +#: src/transport/plugin_transport_tcp.c:705 +#: src/transport/plugin_transport_tcp.c:757 +#: src/transport/plugin_transport_tcp.c:830 +#: src/transport/plugin_transport_tcp.c:909 +#, fuzzy +msgid "# bytes currently in TCP buffers" +msgstr "# bytes enviados por TCP" + +#: src/transport/plugin_transport_tcp.c:622 +#: src/transport/plugin_transport_tcp.c:856 +#: src/transport/plugin_transport_tcp.c:1561 +#, fuzzy +msgid "# TCP sessions active" +msgstr "# claves de la sesión aceptadas" + +#: src/transport/plugin_transport_tcp.c:709 +#, fuzzy +msgid "# bytes discarded by TCP (timeout)" +msgstr "# bytes omitidos por TCP (salientes)" + +#: src/transport/plugin_transport_tcp.c:760 +#, fuzzy +msgid "# bytes transmitted via TCP" +msgstr "# bytes desencriptados" + +#: src/transport/plugin_transport_tcp.c:834 +#, fuzzy +msgid "# bytes discarded by TCP (disconnect)" +msgstr "# bytes omitidos por TCP (salientes)" + +#: src/transport/plugin_transport_tcp.c:1081 +#, c-format +msgid "Address of unexpected length: %u\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1116 +msgid "Found valid IPv4 NAT address (creating session)!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1186 +msgid "# transport-service disconnect requests for TCP" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1603 +#, fuzzy +msgid "# TCP WELCOME messages received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/plugin_transport_tcp.c:1756 +msgid "# bytes received via TCP" +msgstr "# bytes recibidos por TCP" + +#: src/transport/plugin_transport_tcp.c:1823 +msgid "# network-level TCP disconnect events" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1962 src/util/service.c:889 +#, c-format +msgid "Require valid port number for service `%s' in configuration!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1976 +#, fuzzy +msgid "Failed to start service.\n" +msgstr "Falló al comenzar la recolección.\n" + +#: src/transport/plugin_transport_tcp.c:2039 +#, fuzzy, c-format +msgid "Failed to find option %s in section %s!\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/transport/plugin_transport_tcp.c:2062 +#, c-format +msgid "TCP transport listening on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2066 +msgid "TCP transport not listening on any port (client only)\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2070 +#, c-format +msgid "TCP transport advertises itself as being on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_udp_broadcasting.c:130 +#, fuzzy +msgid "# IPv6 multicast HELLO beacons received via udp" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/plugin_transport_udp_broadcasting.c:172 +#, fuzzy +msgid "# IPv4 broadcast HELLO beacons received via udp" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/plugin_transport_udp_broadcasting.c:393 +#, c-format +msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:1985 +#, fuzzy +msgid "Failed to open UDP sockets\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/transport/plugin_transport_udp.c:2068 +#, c-format +msgid "Given `%s' option is out of range: %llu > %u\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:2112 +#, fuzzy, c-format +msgid "Invalid IPv6 address: `%s'\n" +msgstr "Argumento no válido: '%s'\n" + +#: src/transport/plugin_transport_unix.c:1051 +#, fuzzy +msgid "Failed to open UNIX sockets\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/transport/plugin_transport_wlan.c:875 +#, fuzzy +msgid "# wlan session timeouts" +msgstr "# claves de la sesión aceptadas" + +#: src/transport/plugin_transport_wlan.c:899 +#, fuzzy +msgid "# wlan session created" +msgstr "# claves de la sesión aceptadas" + +#: src/transport/plugin_transport_wlan.c:980 +#: src/transport/plugin_transport_wlan.c:1138 +#: src/transport/plugin_transport_wlan.c:1159 +#: src/transport/plugin_transport_wlan.c:1190 +#: src/transport/plugin_transport_wlan.c:2334 +#: src/transport/plugin_transport_wlan.c:3142 +msgid "# wlan pending sessions" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1233 +#: src/transport/plugin_transport_wlan.c:1888 +#, fuzzy +msgid "# wlan pending fragments" +msgstr "# fragmentos descartados" + +#: src/transport/plugin_transport_wlan.c:1388 +#, c-format +msgid "" +"Finished reading from gnunet-helper-transport-wlan stdout with code: %d\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1732 +msgid "# wlan hello beacons send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1765 +#: src/transport/plugin_transport_wlan.c:1968 +#: src/transport/plugin_transport_wlan.c:2059 +#, c-format +msgid "Error writing to wlan helper. errno == %d, ERROR: %s\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1954 +msgid "# wlan acks send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2025 +#, fuzzy +msgid "# wlan fragments send" +msgstr "# fragmentos descartados" + +#: src/transport/plugin_transport_wlan.c:2161 +#, c-format +msgid "Wlan Address len %d is wrong\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2295 +#: src/transport/plugin_transport_wlan.c:2919 +#: src/transport/plugin_transport_wlan.c:3145 +msgid "# wlan mac endpoints" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2517 +#, fuzzy +msgid "# wlan whole messages received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/plugin_transport_wlan.c:2708 +#, fuzzy +msgid "# wlan hello messages received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/plugin_transport_wlan.c:2742 +#, fuzzy +msgid "# wlan fragments received" +msgstr "# fragmentos descartados" + +#: src/transport/plugin_transport_wlan.c:2790 +#, fuzzy +msgid "# wlan acks received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/plugin_transport_wlan.c:2879 +msgid "# wlan mac endpoints timeouts" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2903 +#, fuzzy +msgid "# wlan mac endpoints created" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/plugin_transport_wlan.c:2956 +msgid "# wlan WLAN_HELPER_DATA received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:3010 +#, fuzzy +msgid "# wlan messages for this client received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/plugin_transport_wlan.c:3021 +#, fuzzy +msgid "# wlan messages inside WLAN_HELPER_DATA received" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/transport/transport_api.c:588 +#, fuzzy, c-format +msgid "Received unexpected message of type %u in %s:%u\n" +msgstr "Recibido mensaje corrupto del par '%s' en %s:%d.\n" + +#: src/util/bio.c:136 src/util/bio.c:142 +#, fuzzy, c-format +msgid "Error reading `%s': %s" +msgstr "Error creando usuario" + +#: src/util/bio.c:143 +#, fuzzy +msgid "End of file" +msgstr "Cargar un fichero de configuración" + +#: src/util/bio.c:195 +#, c-format +msgid "Error reading length of string `%s'" +msgstr "" + +#: src/util/bio.c:205 +#, c-format +msgid "String `%s' longer than allowed (%u > %u)" +msgstr "" + +#: src/util/bio.c:250 +#, c-format +msgid "Serialized metadata `%s' larger than allowed (%u>%u)" +msgstr "" + +#: src/util/bio.c:264 +#, c-format +msgid "Metadata `%s' failed to deserialize" +msgstr "" + +#: src/util/client.c:304 +#, c-format +msgid "" +"Could not determine valid hostname and port for service `%s' from " +"configuration.\n" +msgstr "" + +#: src/util/client.c:312 +#, c-format +msgid "Need a non-empty hostname for service `%s'.\n" +msgstr "" + +#: src/util/client.c:657 +msgid "Failure to transmit TEST request.\n" +msgstr "" + +#: src/util/client.c:717 src/util/service.c:919 +#, c-format +msgid "UNIXPATH `%s' too long, maximum length is %llu\n" +msgstr "" + +#: src/util/client.c:859 +#, fuzzy, c-format +msgid "Could not connect to service `%s', must not be running.\n" +msgstr "Imposible conectar con gnunetd.\n" + +#: src/util/client.c:875 +#, fuzzy, c-format +msgid "Failure to transmit request to service `%s'\n" +msgstr "Falló al mandar la petición HTTP al host '%s': %s\n" + +#: src/util/client.c:1143 +msgid "Could not submit request, not expecting to receive a response.\n" +msgstr "" + +#: src/util/common_logging.c:239 src/util/common_logging.c:889 +msgid "DEBUG" +msgstr "DEPURACIÓN" + +#: src/util/common_logging.c:241 src/util/common_logging.c:887 +msgid "INFO" +msgstr "INFORMACIÓN" + +#: src/util/common_logging.c:243 src/util/common_logging.c:885 +msgid "WARNING" +msgstr "PELIGRO" + +#: src/util/common_logging.c:245 src/util/common_logging.c:883 +msgid "ERROR" +msgstr "ERROR" + +#: src/util/common_logging.c:247 src/util/common_logging.c:891 +msgid "NONE" +msgstr "" + +#: src/util/common_logging.c:609 +#, fuzzy, c-format +msgid "Failed to create or access directory for log file `%s'\n" +msgstr "Imposible pasar el fichero de configuración '%s'.\n" + +#: src/util/common_logging.c:724 +#, c-format +msgid "Message `%.*s' repeated %u times in the last %s\n" +msgstr "" + +#: src/util/common_logging.c:892 +msgid "INVALID" +msgstr "" + +#: src/util/common_logging.c:991 +#, fuzzy +msgid "unknown address" +msgstr "desconocido" + +#: src/util/common_logging.c:1029 +#, fuzzy +msgid "invalid address" +msgstr "Argumentos inválidos: " + +#: src/util/configuration.c:245 +#, fuzzy, c-format +msgid "Syntax error in configuration file `%s' at line %u.\n" +msgstr "" +"Error de sintaxis en el fichero de configuración '%s' en la linea %d.\n" + +#: src/util/configuration.c:817 +#, c-format +msgid "" +"Configuration value '%s' for '%s' in section '%s' is not in set of legal " +"choices\n" +msgstr "" + +#: src/util/connection.c:460 +#, fuzzy, c-format +msgid "Access denied to `%s'\n" +msgstr "Permiso denegado para '%s' en %s:%d.\n" + +#: src/util/connection.c:475 +#, c-format +msgid "Accepting connection from `%s': %p\n" +msgstr "" + +#: src/util/connection.c:629 +#, fuzzy, c-format +msgid "" +"Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" +msgstr "Se produjo un error estableciendo conexión con gnunetd.\n" + +#: src/util/connection.c:821 src/util/connection.c:992 +#, fuzzy, c-format +msgid "Trying to connect to `%s' (%p)\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/util/connection.c:830 +#, fuzzy, c-format +msgid "Failed to connect to `%s' (%p)\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/util/connection.c:983 +#, fuzzy, c-format +msgid "Attempt to connect to `%s' failed\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/util/connection.c:1465 +#, c-format +msgid "" +"Could not satisfy pending transmission request, socket closed or connect " +"failed (%p).\n" +msgstr "" + +#: src/util/container_bloomfilter.c:507 +#, c-format +msgid "" +"Size of file on disk is incorrect for this Bloom filter (want %llu, have " +"%llu)\n" +msgstr "" + +#: src/util/crypto_random.c:280 +#, c-format +msgid "Starting `%s' process to generate entropy\n" +msgstr "" + +#: src/util/crypto_random.c:309 +#, c-format +msgid "libgcrypt has not the expected version (version %s is required).\n" +msgstr "" +"libgcrypt no está en la versión esperada (se necesita la versión %s).\n" + +#: src/util/crypto_rsa.c:618 src/util/crypto_rsa.c:665 +#, fuzzy, c-format +msgid "Could not aquire lock on file `%s': %s...\n" +msgstr "Imposible escribir PID al fichero '%s': %s.\n" + +#: src/util/crypto_rsa.c:623 +#, fuzzy +msgid "Creating a new private key. This may take a while.\n" +msgstr "Creando nueva clave local (esto puede llevar un tiempo).\n" + +#: src/util/crypto_rsa.c:641 +#, c-format +msgid "I am host `%s'. Stored new private key in `%s'.\n" +msgstr "" + +#: src/util/crypto_rsa.c:669 src/util/crypto_rsa.c:705 +msgid "This may be ok if someone is currently generating a hostkey.\n" +msgstr "" + +#: src/util/crypto_rsa.c:700 +#, c-format +msgid "" +"When trying to read hostkey file `%s' I found %u bytes but I need at least " +"%u.\n" +msgstr "" + +#: src/util/crypto_rsa.c:720 +#, fuzzy, c-format +msgid "File `%s' does not contain a valid private key. Deleting it.\n" +msgstr "El fichero '%s' no contiene un pseudónimo.\n" + +#: src/util/crypto_rsa.c:738 +#, fuzzy, c-format +msgid "I am host `%s'. Read private key from `%s'.\n" +msgstr "Llamada a '%s' con la clave '%s'.\n" + +#: src/util/crypto_rsa.c:959 +#, c-format +msgid "RSA signature verification failed at %s:%d: %s\n" +msgstr "La verificación de la firma RSA fallo en %s: %d: %s\n" + +#: src/util/disk.c:479 +#, fuzzy, c-format +msgid "`%s' failed for drive `%S': %u\n" +msgstr "'%s' falló para la unidad %s: %u\n" + +#: src/util/disk.c:1087 +#, fuzzy, c-format +msgid "Expected `%s' to be a directory!\n" +msgstr "¡'%s' se esperaba que '%s' fuera un directorio!\n" + +#: src/util/disk.c:1441 src/util/service.c:1580 +#, fuzzy, c-format +msgid "Cannot obtain information about user `%s': %s\n" +msgstr "Imposible guardar el fichero de configuración '%s': %s.\n" + +#: src/util/disk.c:1759 +#, fuzzy, c-format +msgid "No `%s' specified for service `%s' in configuration.\n" +msgstr "¡Ninguna aplicación definida en la configuración!\n" + +#: src/util/getopt.c:672 +#, c-format +msgid "%s: option `%s' is ambiguous\n" +msgstr "%s: la opción '%s' es ambigua\n" + +#: src/util/getopt.c:696 +#, c-format +msgid "%s: option `--%s' does not allow an argument\n" +msgstr "%s: la opción '--%s' no permite un argumento\n" + +#: src/util/getopt.c:701 +#, c-format +msgid "%s: option `%c%s' does not allow an argument\n" +msgstr "%s: la opción '%c%s' no permite un argumento\n" + +#: src/util/getopt.c:718 src/util/getopt.c:886 +#, c-format +msgid "%s: option `%s' requires an argument\n" +msgstr "%s: la opción '%s' requiere un argumento\n" + +#: src/util/getopt.c:747 +#, c-format +msgid "%s: unrecognized option `--%s'\n" +msgstr "%s: opción no reconocida '--%s'\n" + +#: src/util/getopt.c:751 +#, c-format +msgid "%s: unrecognized option `%c%s'\n" +msgstr "%s: opción no reconocida '%c%s'\n" + +#: src/util/getopt.c:776 +#, c-format +msgid "%s: illegal option -- %c\n" +msgstr "%s: opción ilegal -- %c\n" + +#: src/util/getopt.c:778 +#, c-format +msgid "%s: invalid option -- %c\n" +msgstr "%s: opción no válida -- %c\n" + +#: src/util/getopt.c:806 src/util/getopt.c:934 +#, c-format +msgid "%s: option requires an argument -- %c\n" +msgstr "%s: la opción requiere un argumento --%c\n" + +#: src/util/getopt.c:854 +#, c-format +msgid "%s: option `-W %s' is ambiguous\n" +msgstr "%s: la opción '-W %s' es ambigua\n" + +#: src/util/getopt.c:872 +#, c-format +msgid "%s: option `-W %s' does not allow an argument\n" +msgstr "%s: la opción '-W %s' no permite un argumento\n" + +#: src/util/getopt.c:1038 +#, fuzzy, c-format +msgid "Use %s to get a list of options.\n" +msgstr "Usar --help para obtener una lista de opciones.\n" + +#: src/util/getopt_helpers.c:84 +#, c-format +msgid "" +"Arguments mandatory for long options are also mandatory for short options.\n" +msgstr "" + +#: src/util/getopt_helpers.c:255 src/util/getopt_helpers.c:283 +#, c-format +msgid "You must pass a number to the `%s' option.\n" +msgstr "Tienes que introducir un número en la opción '%s'.\n" + +#: src/util/gnunet-resolver.c:148 +msgid "perform a reverse lookup" +msgstr "" + +#: src/util/gnunet-resolver.c:154 +msgid "Use build-in GNUnet stub resolver" +msgstr "" + +#: src/util/gnunet-service-resolver.c:288 +#, fuzzy, c-format +msgid "Could not resolve `%s' (%s): %s\n" +msgstr "Imposible resolver '%s': %s\n" + +#: src/util/gnunet-service-resolver.c:358 +#: src/util/gnunet-service-resolver.c:399 +#, c-format +msgid "Could not find IP of host `%s': %s\n" +msgstr "Imposible encontrar la IP del host '%s': %s\n" + +#: src/util/gnunet-service-resolver.c:494 +#, c-format +msgid "Resolver asked to look up `%s'.\n" +msgstr "" + +#: src/util/gnunet-service-resolver.c:529 +#, c-format +msgid "Resolver asked to look up IP address `%s'.\n" +msgstr "" + +#: src/util/helper.c:239 +#, fuzzy, c-format +msgid "Error reading from `%s': %s\n" +msgstr "Error creando usuario" + +#: src/util/helper.c:254 +#, c-format +msgid "Got 0 bytes from helper `%s' (EOF)\n" +msgstr "" + +#: src/util/helper.c:264 +#, fuzzy, c-format +msgid "Got %u bytes from helper `%s'\n" +msgstr "GAP recibido contenido no válido de '%s'\n" + +#: src/util/helper.c:273 +#, fuzzy, c-format +msgid "Failed to parse inbound message from helper `%s'\n" +msgstr "Falló al pasar los datos de la interfaz de '%s' de %s:%d.\n" + +#: src/util/helper.c:432 +#, fuzzy, c-format +msgid "Error writing to `%s': %s\n" +msgstr "Error creando usuario" + +#: src/util/network.c:1196 +#, c-format +msgid "" +"Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" +msgstr "" + +#: src/util/os_installation.c:299 +#, c-format +msgid "" +"Could not determine installation path for %s. Set `%s' environment " +"variable.\n" +msgstr "" + +#: src/util/os_installation.c:486 +#, fuzzy, c-format +msgid "Could not find binary `%s' in PATH!\n" +msgstr "¡Imposible encontrar el par '%s' en la tabla de enrutado!\n" + +#: src/util/os_installation.c:492 +#, fuzzy, c-format +msgid "access (%s, X_OK) failed: %s\n" +msgstr "'%s' %s falló: %s\n" + +#: src/util/os_installation.c:507 +#, fuzzy, c-format +msgid "stat (%s) failed: %s\n" +msgstr "'%s' %s falló: %s\n" + +#: src/util/os_priority.c:304 +#, fuzzy, c-format +msgid "Failed to open named pipe `%s' for reading: %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/util/os_priority.c:305 +#, fuzzy, c-format +msgid "Failed to open named pipe `%s' for writing: %s\n" +msgstr "Fichero almacenado en '%s'.\n" + +#: src/util/plugin.c:89 +#, c-format +msgid "Initialization of plugin mechanism failed: %s!\n" +msgstr "¡El mecanismo de iniciación de los plugins falló: %s!\n" + +#: src/util/plugin.c:146 +#, fuzzy, c-format +msgid "`%s' failed to resolve method '%s' with error: %s\n" +msgstr "'%s' falló al resolver el método '%s%s' en %s:%d con un error: %s\n" + +#: src/util/plugin.c:219 +#, fuzzy, c-format +msgid "`%s' failed for library `%s' with error: %s\n" +msgstr "'%s' falló en la biblioteca '%s' en %s:%d con un error: %s\n" + +#: src/util/plugin.c:349 +#, fuzzy +msgid "Could not determine plugin installation path.\n" +msgstr "Imposible determinar mi dirección IPv6 pública.\n" + +#: src/util/pseudonym.c:273 +#, fuzzy, c-format +msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" +msgstr "Falló al pasar los datos de la interfaz de '%s' de %s:%d.\n" + +#: src/util/pseudonym.c:338 +#, fuzzy +msgid "no-name" +msgstr "Mostrar el nombre" + +#: src/util/resolver_api.c:202 +#, fuzzy, c-format +msgid "Must specify `%s' for `%s' in configuration!\n" +msgstr "Intentando usar el fichero '%s' para la configuración de MySQL.\n" + +#: src/util/resolver_api.c:221 +#, fuzzy, c-format +msgid "" +"Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" +msgstr "" +"Debes especificar un número positivo para '%s' en la configuración en la " +"sección '%s'.\n" + +#: src/util/resolver_api.c:351 +#, fuzzy, c-format +msgid "Timeout trying to resolve IP address `%s'.\n" +msgstr "GNUnet usa ahora la dirección IP %u.%u.%u.%u.\n" + +#: src/util/resolver_api.c:355 +#, c-format +msgid "Timeout trying to resolve hostname `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:426 +#, c-format +msgid "Resolver returns `%s' for IP `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:807 +#, c-format +msgid "Resolver returns `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:901 +#, c-format +msgid "Resolving our FQDN `%s'\n" +msgstr "" + +#: src/util/resolver_api.c:906 +#, fuzzy, c-format +msgid "Could not resolve our FQDN : %s\n" +msgstr "Imposible resolver '%s': %s\n" + +#: src/util/resolver_api.c:938 +#, c-format +msgid "Resolving our hostname `%s'\n" +msgstr "" + +#: src/util/scheduler.c:866 +msgid "Looks like we're busy waiting...\n" +msgstr "" + +#: src/util/scheduler.c:996 +#, c-format +msgid "Attempt to cancel dead task %llu!\n" +msgstr "" + +#: src/util/server.c:397 +#, fuzzy, c-format +msgid "`%s' failed for port %d (%s).\n" +msgstr "'%s' falló para la unidad %s: %u\n" + +#: src/util/server.c:406 +#, fuzzy, c-format +msgid "`%s' failed for port %d (%s): address already in use\n" +msgstr "" +"'%s' falló para el puerto %d: %s. ¿Está gnunet ejecutandose actualmente?\n" + +#: src/util/server.c:411 +#, fuzzy, c-format +msgid "`%s' failed for `%s': address already in use\n" +msgstr "" +"'%s' falló para el puerto %d: %s. ¿Está gnunet ejecutandose actualmente?\n" + +#: src/util/server.c:640 +#, c-format +msgid "" +"Processing code for message of type %u did not call " +"GNUNET_SERVER_receive_done after %llums\n" +msgstr "" + +#: src/util/service.c:117 src/util/service.c:143 src/util/service.c:186 +#: src/util/service.c:207 src/util/service.c:214 +#, c-format +msgid "Invalid format for IP: `%s'\n" +msgstr "Formato no válido para la IP: '%s'\n" + +#: src/util/service.c:170 +#, c-format +msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." +msgstr "Notación de red no válida ('/%d' no es válido en IPv4 CIDR)." + +#: src/util/service.c:263 +#, c-format +msgid "Invalid network notation (does not end with ';': `%s')\n" +msgstr "Notación de red no válida (no termina con ';': '%s')\n" + +#: src/util/service.c:296 +#, fuzzy, c-format +msgid "Wrong format `%s' for netmask\n" +msgstr "Formato '%s' erróneo para la máscara de red: %s\n" + +#: src/util/service.c:326 +#, fuzzy, c-format +msgid "Wrong format `%s' for network\n" +msgstr "Formato '%s' erróneo para la red: %s\n" + +#: src/util/service.c:668 +#, c-format +msgid "Access denied to UID %d / GID %d\n" +msgstr "" + +#: src/util/service.c:673 +#, fuzzy, c-format +msgid "Unknown address family %d\n" +msgstr "Operación desconocida '%s'\n" + +#: src/util/service.c:680 +#, c-format +msgid "Access from `%s' denied to service `%s'\n" +msgstr "" + +#: src/util/service.c:724 +#, c-format +msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:752 +#, c-format +msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:869 +#, c-format +msgid "" +"Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" +msgstr "" + +#: src/util/service.c:939 +#, c-format +msgid "" +"Disabling UNIX domain socket support for service `%s', failed to create UNIX " +"domain socket: %s\n" +msgstr "" + +#: src/util/service.c:956 +#, c-format +msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" +msgstr "" + +#: src/util/service.c:1191 +msgid "Could not access a pre-bound socket, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1242 src/util/service.c:1260 +#, c-format +msgid "Specified value for `%s' of service `%s' is invalid\n" +msgstr "" + +#: src/util/service.c:1287 +#, c-format +msgid "Could not access pre-bound socket %u, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1442 +#, fuzzy, c-format +msgid "Failed to start `%s' at `%s'\n" +msgstr "Fallo al conectar a gnunetd.\n" + +#: src/util/service.c:1475 +#, fuzzy, c-format +msgid "Service `%s' runs at %s\n" +msgstr "Par '%s' con credibilidad %8u y dirección '%s'\n" + +#: src/util/service.c:1521 +msgid "Service process failed to initialize\n" +msgstr "" + +#: src/util/service.c:1525 +msgid "Service process could not initialize server function\n" +msgstr "" + +#: src/util/service.c:1529 +msgid "Service process failed to report status\n" +msgstr "" + +#: src/util/service.c:1581 +msgid "No such user" +msgstr "" + +#: src/util/service.c:1594 +#, c-format +msgid "Cannot change user/group to `%s': %s\n" +msgstr "Imposible cambiar el usuario/grupo a '%s': %s\n" + +#: src/util/service.c:1657 +msgid "do daemonize (detach from terminal)" +msgstr "" + +#: src/util/signal.c:80 +#, fuzzy, c-format +msgid "signal (%d, %p) returned %d.\n" +msgstr "La llamada a '%s' devuelve %d.\n" + +#: src/util/strings.c:143 +msgid "b" +msgstr "b" + +#: src/util/strings.c:354 +#, c-format +msgid "Character sets requested were `%s'->`%s'\n" +msgstr "" + +#: src/util/strings.c:462 +msgid "Failed to expand `$HOME': environment variable `HOME' not set" +msgstr "" + +#: src/util/strings.c:554 +msgid "ms" +msgstr "ms" + +#: src/util/strings.c:559 +msgid "eternity" +msgstr "" + +#: src/util/strings.c:563 +msgid "s" +msgstr "s" + +#: src/util/strings.c:567 +msgid "m" +msgstr "m" + +#: src/util/strings.c:571 +msgid "h" +msgstr "h" + +#: src/util/strings.c:575 +msgid " days" +msgstr " días" + +#: src/util/strings.c:599 +msgid "end of time" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1065 +#, fuzzy +msgid "# Active tunnels" +msgstr "Configuración de GNUnet" + +#: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 +#, fuzzy +msgid "# Peers connected to mesh tunnels" +msgstr "# de pares conectados" + +#: src/vpn/gnunet-service-vpn.c:699 +#, fuzzy +msgid "# Bytes given to mesh for transmission" +msgstr "# bytes de mensajes salientes omitidos" + +#: src/vpn/gnunet-service-vpn.c:737 +#, fuzzy +msgid "# Bytes dropped in mesh queue (overflow)" +msgstr "# bytes omitidos por UDP (salientes)" + +#: src/vpn/gnunet-service-vpn.c:772 +#, fuzzy +msgid "# Mesh tunnels created" +msgstr "# mensajes PONG encriptados recibidos" + +#: src/vpn/gnunet-service-vpn.c:795 +#, fuzzy +msgid "Failed to setup mesh tunnel!\n" +msgstr "Fallo en las estadísticas del tráfico.\n" + +#: src/vpn/gnunet-service-vpn.c:967 +#, c-format +msgid "Protocol %u not supported, dropping\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1285 +msgid "# ICMPv4 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1306 +msgid "# ICMPv6 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1511 +#, fuzzy +msgid "# Packets received from TUN interface" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/vpn/gnunet-service-vpn.c:1549 src/vpn/gnunet-service-vpn.c:1590 +#, c-format +msgid "Packet received for unmapped destination `%s' (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1600 +msgid "Received IPv4 packet with options (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1614 +#, c-format +msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1697 +#, fuzzy +msgid "# ICMP packets received from mesh" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/vpn/gnunet-service-vpn.c:2038 +#, fuzzy +msgid "# UDP packets received from mesh" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/vpn/gnunet-service-vpn.c:2196 +#, fuzzy +msgid "# TCP packets received from mesh" +msgstr "El mensaje recibido del cliente es inválido\n" + +#: src/vpn/gnunet-service-vpn.c:2347 +msgid "Failed to find unallocated IPv4 address in VPN's range\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2402 +#, fuzzy +msgid "Failed to find unallocated IPv6 address in VPN's range\n" +msgstr "¡Falló al obtener mi dirección IPv6 (externa)!\n" + +#: src/vpn/gnunet-service-vpn.c:2441 src/vpn/gnunet-service-vpn.c:2624 +#, fuzzy +msgid "# Active destinations" +msgstr "Configuración de GNUnet" + +#: src/vpn/gnunet-service-vpn.c:2726 +msgid "Failed to allocate IP address for new destination\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3133 +msgid "IPv6 support disabled as this system does not support IPv6\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3165 +msgid "IPv4 support disabled as this system does not support IPv4\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:151 +#, fuzzy +msgid "Error creating tunnel\n" +msgstr "Correcto al crear la clave local.\n" + +#: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 +#, fuzzy, c-format +msgid "Option `%s' makes no sense with option `%s'.\n" +msgstr "La opción '%s' no tiene sentido sin la opción '%s'.\n" + +#: src/vpn/gnunet-vpn.c:208 +#, fuzzy, c-format +msgid "Option `%s' or `%s' is required.\n" +msgstr "%s: la opción '%s' es ambigua\n" + +#: src/vpn/gnunet-vpn.c:220 +#, fuzzy, c-format +msgid "Option `%s' or `%s' is required when using option `%s'.\n" +msgstr "La opción '%s' no tiene sentido sin la opción '%s'.\n" + +#: src/vpn/gnunet-vpn.c:238 +#, fuzzy, c-format +msgid "`%s' is not a valid peer identifier.\n" +msgstr "'%s' no esta disponible." + +#: src/vpn/gnunet-vpn.c:260 +#, fuzzy, c-format +msgid "`%s' is not a valid IP address.\n" +msgstr "'%s' no esta disponible." + +#: src/vpn/gnunet-vpn.c:296 +msgid "request that result should be an IPv4 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:299 +msgid "request that result should be an IPv6 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:302 +msgid "print IP address only after mesh tunnel has been created" +msgstr "" + +#: src/vpn/gnunet-vpn.c:305 +msgid "how long should the mapping be valid for new tunnels?" +msgstr "" + +#: src/vpn/gnunet-vpn.c:308 +msgid "destination IP for the tunnel" +msgstr "" + +#: src/vpn/gnunet-vpn.c:311 +msgid "peer offering the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:314 +msgid "name of the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:317 +#, fuzzy +msgid "service is offered via TCP" +msgstr "# bytes recibidos por TCP" + +#: src/vpn/gnunet-vpn.c:320 +#, fuzzy +msgid "service is offered via UDP" +msgstr "# bytes recibidos vía UDP" + +#: src/vpn/gnunet-vpn.c:329 +msgid "Setup tunnels via VPN." +msgstr "" + +#: src/include/gnunet_common.h:479 src/include/gnunet_common.h:484 +#: src/include/gnunet_common.h:490 +#, fuzzy, c-format +msgid "Assertion failed at %s:%d.\n" +msgstr "La verificación de la firma RSA fallo en %s: %d: %s\n" + +#: src/include/gnunet_common.h:500 +#, fuzzy, c-format +msgid "External protocol violation detected at %s:%d.\n" +msgstr "La verificación de la firma RSA fallo en %s: %d: %s\n" + +#: src/include/gnunet_common.h:521 src/include/gnunet_common.h:528 +#, fuzzy, c-format +msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" +msgstr "'%s' falló en el fichero '%s' en %s: %d con el error: %s\n" + +#, fuzzy +#~ msgid "Failed to send to `%s': %s\n" +#~ msgstr "Fichero almacenado en '%s'.\n" + +#, fuzzy +#~ msgid "Could not access file: %s\n" +#~ msgstr "Imposible ejecutar '%s': %s\n" + +#, fuzzy +#~ msgid "`%s' failed on file `%s': %s" +#~ msgstr "'%s' falló para la unidad %s: %u\n" + +#, fuzzy +#~ msgid "# bytes TCP was asked to transmit" +#~ msgstr "# bytes desencriptados" + +#, fuzzy +#~ msgid "# bytes discarded by TCP (failed to connect)" +#~ msgstr "# bytes omitidos por TCP (salientes)" + +#, fuzzy +#~ msgid "# wlan messages queued" +#~ msgstr "# mensajes PONG encriptados recibidos" + +#~ msgid "print this help" +#~ msgstr "imprime esta ayuda" + +#~ msgid "print the version number" +#~ msgstr "imprime el número de versión" + +#, fuzzy +#~ msgid "use configuration file FILENAME" +#~ msgstr "usa el fichero de configuración FILENAME" + +#, fuzzy +#~ msgid "Failed to stop service `%s'!\n" +#~ msgstr "Fichero almacenado en '%s'.\n" + +#, fuzzy +#~ msgid "Failed to start service `%s'!\n" +#~ msgstr "Falló al comenzar la recolección.\n" + +#, fuzzy +#~ msgid "Service `%s' is not running.\n" +#~ msgstr "'%s' no es un fichero.\n" + +#, fuzzy +#~ msgid "Binary implementing service `%s' not known!\n" +#~ msgstr "La verificación de la firma falló: el par '%s' no es conocido.\n" + +#, fuzzy +#~ msgid "Service `%s' stopped\n" +#~ msgstr "Servicio eliminado.\n" + +#, fuzzy +#~ msgid "Unable to start service `%s': %s\n" +#~ msgstr "Imposible guardar el fichero de configuración '%s':" + +#, fuzzy +#~ msgid "Unable to accept connection for service `%s': %s\n" +#~ msgstr "Imposible guardar el fichero de configuración '%s':" + +#, fuzzy +#~ msgid "Service `%s' started\n" +#~ msgstr "Servicio eliminado.\n" + +#, fuzzy +#~ msgid "Peer `%s' plugin: `%s' address `%s'\n" +#~ msgstr "Par '%s' con credibilidad %8u y dirección '%s'\n" + +#~ msgid "KiB" +#~ msgstr "KiB" + +#~ msgid "MiB" +#~ msgstr "MiB" + +#~ msgid "GiB" +#~ msgstr "GiB" + +#~ msgid "TiB" +#~ msgstr "TiB" + +#, fuzzy +#~ msgid "Failed to create IPv4 broadcast socket on port %d\n" +#~ msgstr "Falló al actualizar los datos del módulo '%s'\n" + +#, fuzzy +#~ msgid "Failed to load block plugin `%s'\n" +#~ msgstr "Imposible inicializar la aplicación '%s'\n" + +#, fuzzy +#~ msgid "Could not resolve our FQDN : %s %u\n" +#~ msgstr "Imposible resolver '%s': %s\n" + +#, fuzzy +#~ msgid "Failed to load dhtlog plugin for `%s'\n" +#~ msgstr "Imposible inicializar la aplicación '%s'\n" + +#, fuzzy +#~ msgid "Failed to get full path for `%s'\n" +#~ msgstr "Falló al actualizar los datos del módulo '%s'\n" + +#, fuzzy +#~ msgid "Failed to create file for dhtlog.\n" +#~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#, fuzzy +#~ msgid "Found peer `%s'\n" +#~ msgstr "Yo soy el par '%s'.\n" + +#, fuzzy +#~ msgid "Failed to initialize MySQL database connection for dhtlog.\n" +#~ msgstr "Imposible inicializar SQLite.\n" + +#, fuzzy +#~ msgid "Loading udp transport plugin\n" +#~ msgstr "Probando transporte(s) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for udp\n" +#~ msgstr "Imposible inicializar la aplicación '%s'\n" + +#, fuzzy +#~ msgid "# SET QUOTA messages received" +#~ msgstr "# mensajes PONG encriptados recibidos" + +#, fuzzy +#~ msgid "curl failed for `%s' at %s:%d: `%s'\n" +#~ msgstr "'%s' falló en %s: %d con error: '%s'.\n" + +#, fuzzy +#~ msgid "Phase 3: sending messages\n" +#~ msgstr "Falló al entregar el mensaje '%s'.\n" + +#, fuzzy +#~ msgid "Loading HTTPS transport plugin `%s'\n" +#~ msgstr "Probando transporte(s) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for https\n" +#~ msgstr "Imposible inicializar la aplicación '%s'\n" + +#, fuzzy +#~ msgid "Fail! Could not connect peers\n" +#~ msgstr "'%s': Imposible conectar.\n" + +#, fuzzy +#~ msgid "Loading tcp transport plugin\n" +#~ msgstr "Probando transporte(s) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for tcp\n" +#~ msgstr "Imposible inicializar la aplicación '%s'\n" + +#, fuzzy +#~ msgid "# HTTP peers active" +#~ msgstr "# bytes recibidos por TCP" + +#, fuzzy +#~ msgid "Connection: %X: %s failed at %s:%d: `%s'\n" +#~ msgstr "'%s' falló en %s: %d con error: '%s'.\n" + +#, fuzzy +#~ msgid "Misconfigured address to bind to in configuration!\n" +#~ msgstr "¡Ninguna aplicación definida en la configuración!\n" + +#, fuzzy +#~ msgid "Loading HTTP transport plugin `%s'\n" +#~ msgstr "Probando transporte(s) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for http\n" +#~ msgstr "Imposible inicializar la aplicación '%s'\n" + +#, fuzzy +#~ msgid "# PING messages decrypted" +#~ msgstr "# mensajes defragmentados" + +#, fuzzy +#~ msgid "Failed to connect to core service\n" +#~ msgstr "Fallo al conectar a gnunetd.\n" + +#, fuzzy +#~ msgid "# bytes successfully transmitted by plugins" +#~ msgstr "# bytes desencriptados" + +#, fuzzy +#~ msgid "# transport failed to selected peer address" +#~ msgstr "Anunciando mi transporte %d a los pares seleccionados.\n" + +#, fuzzy +#~ msgid "# peer addresses considered valid" +#~ msgstr "# Anuncios de los pares recibidos" + +#, fuzzy +#~ msgid "# PING with HELLO messages sent" +#~ msgstr "# mensajes de texto mandados por PING" + +#, fuzzy +#~ msgid "# HELLOs received for validation" +#~ msgstr "# blocks migrados" + +#, fuzzy +#~ msgid "Received `%s' message from `%s' destined for `%s' which is not me!\n" +#~ msgstr "¡Recibido PING no destinado a nosotros!\n" + +#, fuzzy +#~ msgid "Could not send PONG to `%s': no address available\n" +#~ msgstr "¡Imposible encontrar el par '%s' en la tabla de enrutado!\n" + +#, fuzzy +#~ msgid "# HELLO messages received from other peers" +#~ msgstr "Mensaje '%s' inválido recibido del par '%s'.\n" + +#~ msgid "Error" +#~ msgstr "Error" + +#~ msgid "Help" +#~ msgstr "Ayuda" + +#~ msgid "Error!" +#~ msgstr "¡Error!" + +#~ msgid "No" +#~ msgstr "No" + +#~ msgid "Yes" +#~ msgstr "Sí" + +#, fuzzy +#~ msgid "Abort" +#~ msgstr "_Acerca de" + +#, fuzzy +#~ msgid "Ok" +#~ msgstr "k" + +#~ msgid "GNUnet configuration" +#~ msgstr "Configuración de GNUnet" + +#~ msgid "" +#~ "Welcome to GNUnet!\n" +#~ "\n" +#~ "This assistant will ask you a few basic questions in order to configure " +#~ "GNUnet.\n" +#~ "\n" +#~ "Please visit our homepage at\n" +#~ "\thttp://gnunet.org/\n" +#~ "and join our community at\n" +#~ "\thttp://gnunet.org/drupal/\n" +#~ "\n" +#~ "Have a lot of fun,\n" +#~ "\n" +#~ "the GNUnet team" +#~ msgstr "" +#~ "¡Bienvenido a GNUnet!\n" +#~ "\n" +#~ "Este asistente te preguntará unas cuestiones básicas para configurar " +#~ "GNUnet.\n" +#~ "\n" +#~ "Por favor, visita nuestra página en\n" +#~ "\thttp://gnunet.org/\n" +#~ "y únete a nuestra comunidad en \n" +#~ "\thttp://gnunet.org/drupal/\n" +#~ "\n" +#~ "Diviertete,\n" +#~ "\n" +#~ "el equipo de GNUnet" + +#~ msgid "" +#~ "Choose the network interface that connects your computer to the internet " +#~ "from the list below." +#~ msgstr "" +#~ "Escoge la interfaz de red que conecta tu ordenador a Internet de la lista " +#~ "de abajo." + +#~ msgid "" +#~ "The \"Network interface\" is the device that connects your computer to " +#~ "the internet. This is usually a modem, an ISDN card or a network card in " +#~ "case you are using DSL." +#~ msgstr "" +#~ "La \"Interfaz de red\" es el dispositivo que conecta tu ordenador a " +#~ "Internet. Normalmente es un módem, una tarjeta de RDSI o una tarjeta de " +#~ "red en el caso de los xDSL como el ADSL." + +#, fuzzy +#~ msgid "Network configuration: interface" +#~ msgstr "Interfaz de red:" + +#~ msgid "" +#~ "What is the name of the network interface that connects your computer to " +#~ "the Internet?" +#~ msgstr "" +#~ "¿Cuál es el nombre de la interfaz de red que conecta tu ordenador a " +#~ "Internet?" + +#, fuzzy +#~ msgid "Network configuration: IP" +#~ msgstr "Configuración de GNUnet" + +#, fuzzy +#~ msgid "What is this computer's public IP address or hostname?" +#~ msgstr "" +#~ "¿Cuál es es la dirección pública IP o el nombre del dominio de éste " +#~ "ordenador?\n" +#~ "\n" +#~ "En caso de duda, dejar este campo en blanco." + +#, fuzzy +#~ msgid "" +#~ "If your provider always assigns the same IP-Address to you (a \"static\" " +#~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " +#~ "changes every now and then (\"dynamic\" IP-Address) but there's a " +#~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " +#~ "you can also enter it here.\n" +#~ "If left empty, GNUnet will try to automatically detect the IP.\n" +#~ "You can specify a hostname, GNUnet will then use DNS to resolve it.\n" +#~ "If in doubt, leave this empty." +#~ msgstr "" +#~ "Si tu proveedor siempre te asigna la misma dirección IP (una IP \"estática" +#~ "\") introducela en el campo \"Dirección IP\". Si tu dirección IP cambia " +#~ "pero hay un nombre de dominio que siempre apunta a tu dirección IP actual " +#~ "(\"DNS dinámica\"), puedes introducirlo allí también.\n" +#~ "En caso de duda deja el campo en blanco. GNUnet intentará determinar tu " +#~ "dirección IP" + +#, fuzzy +#~ msgid "Bandwidth configuration: upload" +#~ msgstr "Configuración de GNUnet" + +#, fuzzy +#~ msgid "How much upstream bandwidth (in bytes/s) may be used?" +#~ msgstr "¿Cuánta subida (Bytes/s) será usada por GNUnet?" + +#, fuzzy +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "The \"upstream\" is the data channel through which data is *sent* to the " +#~ "internet. The limit is the maximum amount which GNUnet is allowed to use. " +#~ "If you have a flatrate, you can set it to the maximum speed of your " +#~ "internet connection. You should not use a value that is higher than what " +#~ "your actual connection allows." +#~ msgstr "" +#~ "Puedes limitar el uso de recursos de GNUnet aquí.\n" +#~ "\n" +#~ "La \"subida\" es el canal de datos a través del cual los datos son " +#~ "*mandados* a Internet. El límite, o bien es el total máximo para este " +#~ "ordenador, o bien el que se le permita usar a GNUnet. Puedes especificar " +#~ "este valor más tarde. Si tienes una tarifa plana puedes configurarlo a la " +#~ "máxima velocidad de tu conexión a Internet." + +#, fuzzy +#~ msgid "Bandwidth configuration: download" +#~ msgstr "Configuración de GNUnet" + +#, fuzzy +#~ msgid "How much downstream bandwidth (in bytes/s) may be used?" +#~ msgstr "¿Cuánta bajada (Bytes/s) será usada por GNUnet?" + +#, fuzzy +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "The \"downstream\" is the data channel through which data is *received* " +#~ "from the internet. The limit is the maximum amount which GNUnet is " +#~ "allowed to use. If you have a flatrate, you can set it to the maximum " +#~ "speed of your internet connection. You should not use a value that is " +#~ "higher than what your actual connection allows." +#~ msgstr "" +#~ "Puedes limitar el uso de recursos de GNUnet aquí.\n" +#~ "\n" +#~ "La \"bajada\" es el canal de datos a través del cuál los datos son " +#~ "*recibidos* de Internet. El límite, o bien es el total máximo de este " +#~ "ordenador, o bien el que se le permita usar a GNUnet. Puedes especificar " +#~ "este valor más tarde. Si tienes una tarifa plana puedes configurarlo a la " +#~ "máxima velocidad de tu conexión a Internet." + +#, fuzzy +#~ msgid "Quota configuration" +#~ msgstr "Configuración de GNUnet" + +#, fuzzy +#~ msgid "" +#~ "The GNUnet datastore contains all content that GNUnet needs to store " +#~ "(indexed, inserted and migrated content)." +#~ msgstr "" +#~ "¿Cuál es el tamaño máximo de almacenamiento en MB?\n" +#~ "\n" +#~ "El almacenamiento de GNUnet contiene todos los datos que GNUnet genera " +#~ "(datos del índice, contenido insertado y migrado)." + +#, fuzzy +#~ msgid "Daemon configuration: user account" +#~ msgstr "Imposible crear la cuenta de usuario:" + +#, fuzzy +#~ msgid "" +#~ "For security reasons, it is a good idea to let this setup create a new " +#~ "user account under which the GNUnet service is started at system " +#~ "startup.\n" +#~ "\n" +#~ "However, GNUnet may not be able to access files other than its own. This " +#~ "includes files you want to publish in GNUnet. You'll have to grant read " +#~ "permissions to the user specified below.\n" +#~ "\n" +#~ "Leave the field empty to run GNUnet with system privileges.\n" +#~ msgstr "" +#~ "Define el usuario bajo el que correrán los servicios de GNUnet.\n" +#~ "\n" +#~ "Por razones de seguridad, es una buena idea dejar que la configuración " +#~ "cree una nueva cuenta de usuario bajo el cual el servicio de GNUnet es " +#~ "arrancado al iniciar el sistema.\n" +#~ "\n" +#~ "Por consiguiente, GNUnet no tiene la posibilidad de acceder a otros " +#~ "ficheros que no sean los que posee. Ésto incluye los ficheros que quieras " +#~ "publicar en GNUnet. Tendrás que garantizar que el usuario especificado " +#~ "aquí posea permisos de lectura.\n" +#~ "\n" +#~ "Deja los campos vacíos para arrancar GNUnet con privilegios de sistema.\n" +#~ "Usuario de GNUnet:" + +#, fuzzy +#~ msgid "" +#~ "For security reasons, it is a good idea to let this setup create a new " +#~ "group for the chosen user account.\n" +#~ "\n" +#~ "You can also specify a already existent group here.\n" +#~ "\n" +#~ "Only members of this group will be allowed to start and stop the the " +#~ "GNUnet server and have access to GNUnet server data.\n" +#~ msgstr "" +#~ "Define el grupo bajo el que correrán los servicios de GNUnet aquí.\n" +#~ "\n" +#~ "Por razones de seguridad, es una buena idea dejar que la configuración " +#~ "cree un nuevo grupo para la cuenta de usuario creada.\n" +#~ "\n" +#~ "Puedes especificar un grupo ya existente aquí.\n" +#~ "\n" +#~ "Sólo los miembros de este grupo esta autorizados a arrancar y parar el " +#~ "servidor de GNUnet y tener acceso a los datos del servidor de GNUnet.\n" +#~ "\n" +#~ "Grupo de GNUnet:" + +#, fuzzy +#~ msgid "" +#~ "If you say \"yes\" here, the GNUnet background process will be " +#~ "automatically started when you turn on your computer. If you say \"no\" " +#~ "here, you have to launch GNUnet yourself each time you want to use it." +#~ msgstr "" +#~ "¿Quieres arrancar GNUnet como un servicio de sistema?\n" +#~ "n\n" +#~ "Si dices \"sí\" aquí, el proceso en segundo plano de GNUnet sera " +#~ "automáticamente arrancado cuando enciendas tu ordenador. Si dices \"no\" " +#~ "aquí, tendrás que ejecutar GNUnet tu mismo cada vez que quieras usarlo." + +#, fuzzy +#~ msgid "Unable to create user account for daemon." +#~ msgstr "Imposible crear la cuenta de usuario:" + +#, fuzzy +#~ msgid "Save configuration?" +#~ msgstr "Configuración de GNUnet" + +#, fuzzy +#~ msgid "GNUnet Configuration" +#~ msgstr "Configuración de GNUnet" + +#~ msgid "Back" +#~ msgstr "Atrás" + +#~ msgid "Up" +#~ msgstr "Arriba" + +#~ msgid "Cancel" +#~ msgstr "Cancelar" + +#, fuzzy +#~ msgid "Configuration unchanged, no need to save.\n" +#~ msgstr "" +#~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " +#~ "'%s'!\n" + +#, fuzzy +#~ msgid "Do you wish to save your new configuration?" +#~ msgstr "¿Quieres guardar tu configuración?" + +#, fuzzy +#~ msgid "" +#~ "\n" +#~ "Your configuration changes were NOT saved.\n" +#~ msgstr "Fichero de configuración '%s' creado.\n" + +#~ msgid "GNUnet service installed successfully.\n" +#~ msgstr "Servicio de GNUnet instalado satisfactoriamente.\n" + +#~ msgid "This version of Windows doesn't support services.\n" +#~ msgstr "Esta versión de Windows no soporta servicios.\n" + +#, fuzzy +#~ msgid "Error: can't open Service Control Manager: %s\n" +#~ msgstr "Error: imposible abrir el Service Control Manager: &s\n" + +#~ msgid "Error: can't create service: %s\n" +#~ msgstr "Error: imposible crear el servicio: %s\n" + +#~ msgid "Error: can't access service: %s\n" +#~ msgstr "Error: imposible acceder al servicio: %s\n" + +#~ msgid "Error: can't delete service: %s\n" +#~ msgstr "Error: imposible borrar el servicio: %s\n" + +#, fuzzy +#~ msgid "Configuration changed. Save?" +#~ msgstr "" +#~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " +#~ "'%s'!\n" + +#, fuzzy +#~ msgid "Error saving configuration." +#~ msgstr "Imposible guardar la configuración" + +#, fuzzy +#~ msgid "(unknown connection)" +#~ msgstr "Conexión de red" + +#, fuzzy +#~ msgid "Do you want to save the new configuration?" +#~ msgstr "¿Quieres guardar tu configuración?" + +#~ msgid "Unable to change startup process:" +#~ msgstr "Imposible cambiar el proceso de arranque:" + +#~ msgid "generate configuration for gnunetd, the GNUnet daemon" +#~ msgstr "genera configuración para gnunetd, el demonio de GNUnet" + +#~ msgid "Tool to setup GNUnet." +#~ msgstr "Herramienta de configuración de GNUnet." + +#, fuzzy +#~ msgid "Too many arguments.\n" +#~ msgstr "Argumentos en la linea de comandos inválidos.\n" + +#, fuzzy +#~ msgid "No interface specified, using default.\n" +#~ msgstr "Ninguna interfaz especificada, usando la marcada por defecto\n" + +#, fuzzy +#~ msgid "Configuration file `%s' must be a filename (but is a directory).\n" +#~ msgstr "" +#~ "El fichero de configuración '%s' no ha sido encontrado. ¡Ejecute gnunet-" +#~ "setup!\n" + +#, fuzzy +#~ msgid "Undefined option.\n" +#~ msgstr "Otras configuraciones" + +#, fuzzy +#~ msgid "Unknown operation '%s'.\n" +#~ msgstr "Operación desconocida '%s'\n" + +#, fuzzy +#~ msgid "yes" +#~ msgstr "Bytes" + +#~ msgid "Yes\n" +#~ msgstr "Sí\n" + +#~ msgid "No\n" +#~ msgstr "No\n" + +#~ msgid "Help\n" +#~ msgstr "Ayuda\n" + +#, fuzzy +#~ msgid "Abort\n" +#~ msgstr "_Acerca de" + +#, fuzzy +#~ msgid "Configuration was unchanged, no need to save.\n" +#~ msgstr "" +#~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " +#~ "'%s'!\n" + +#~ msgid "Can't open Service Control Manager" +#~ msgstr "Imposible abrir el Service Control Manager" + +#~ msgid "Can't create service" +#~ msgstr "Imposible crear el servicio" + +#~ msgid "Error changing the permissions of the GNUnet directory" +#~ msgstr "Error cambiando los permisos del directorio de GNUnet" + +#, fuzzy +#~ msgid "Cannot write to the registry" +#~ msgstr "Imposible escribir en el registro" + +#~ msgid "Can't delete the service" +#~ msgstr "Imposible borrar el servicio" + +#~ msgid "This version of Windows does not support multiple users." +#~ msgstr "Esta versión de Windows no permite usuarios múltiples" + +#~ msgid "Error accessing local security policy" +#~ msgstr "Error accediendo a la política de seguridad local" + +#~ msgid "Error granting service right to user" +#~ msgstr "Error garantizando el servicio correcto al usuario" + +#~ msgid "Unknown error while creating a new user" +#~ msgstr "Error desconocido mientras se creaba un nuevo usuario" + +#, fuzzy +#~ msgid "" +#~ "Configuration does not satisfy constraints of configuration specification " +#~ "file `%s'!\n" +#~ msgstr "" +#~ "La configuración debe especificar un directorio para los datos FS en la " +#~ "sección '%s' bajo'%s'.\n" + +#~ msgid "FATAL" +#~ msgstr "FATAL" + +#~ msgid "NOTHING" +#~ msgstr "NADA" + +#, fuzzy +#~ msgid "Syntax error in configuration entry HOST in section NETWORK: `%s'\n" +#~ msgstr "" +#~ "Error de sintaxis en el fichero de configuración '%s' en la linea %d.\n" + +#, fuzzy +#~ msgid "Error connecting to %s:%u. Is the daemon running?\n" +#~ msgstr "Imposible conectar a %u.%u.%u.%u:%u: %s\n" + +#, fuzzy +#~ msgid "Cannot connect to %s:%u: %s\n" +#~ msgstr "Imposible conectar a %u.%u.%u.%u:%u: %s\n" + +#, fuzzy +#~ msgid "Reading result from gnunetd failed, reply invalid!\n" +#~ msgstr "¡'%s' falló, respuesta no válida!\n" + +#, fuzzy +#~ msgid "No interface specified in section `%s' under `%s'!\n" +#~ msgstr "Ninguna interfaz especificada, usando la marcada por defecto\n" + +#~ msgid "Could not obtain IP for interface `%s' using `%s'.\n" +#~ msgstr "Imposible obtener IP para la interfaz '%s' usando '%s'.\n" + +#, fuzzy +#~ msgid "" +#~ "Could not find interface `%s' using `%s', trying to find another " +#~ "interface.\n" +#~ msgstr "Imposible obtener IP para la interfaz '%s' usando '%s'.\n" + +#~ msgid "Could not find an IP address for interface `%s'.\n" +#~ msgstr "Imposible obtener la dirección IP para la interfaz '%s'.\n" + +#, fuzzy +#~ msgid "" +#~ "There is more than one IP address specified for interface `%s'.\n" +#~ "GNUnet will use %s.\n" +#~ msgstr "" +#~ "Hay más de una dirección IP especificada para la interfaz '%s'.\n" +#~ "GNUnet usará %u.%u.%u.%u.\n" + +#~ msgid "Could not resolve `%s' to determine our IP address: %s\n" +#~ msgstr "Imposible resolver '%s' para determinar nuestra dirección IP: %s\n" + +#, fuzzy +#~ msgid "Received malformed message (too small) from connection. Closing.\n" +#~ msgstr "Recibida respuesta anómala a'%s' del par '%s'.\n" + +#, fuzzy +#~ msgid "`%s' returned with error code %u" +#~ msgstr "'%s' falló con el código de error %s: %s" + +#~ msgid "Can't create semaphore: %i" +#~ msgstr "Imposible crear un semáforo: %i" + +#, fuzzy +#~ msgid "Command `%s' failed with error code %u\n" +#~ msgstr "'%s' falló con el código de error %s: %s" + +#, fuzzy +#~ msgid "Invalid process priority `%s'\n" +#~ msgstr "Respuesta inválida a '%s'.\n" + +#, fuzzy +#~ msgid "`%s' failed with error code %d: %s\n" +#~ msgstr "'%s' falló con el código de error %d: %s" + +#, fuzzy +#~ msgid "Invalid argument for `%s'.\n" +#~ msgstr "Argumento no válido: '%s'\n" + +#~ msgid "Availability test failed for `%s' at %s:%d.\n" +#~ msgstr "Test de disponibilidad fallido para '%s' en %s:%d.\n" + +#, fuzzy +#~ msgid "Starting datastore conversion (this may take a while).\n" +#~ msgstr "Creando nueva clave local (esto puede llevar un tiempo).\n" + +#, fuzzy +#~ msgid "Failed to load sqstore service. Check your configuration!\n" +#~ msgstr "Imposible guardar la configuración" + +#, fuzzy +#~ msgid "" +#~ "%s:%d - RPC %s:%p could not be registered: another callback is already " +#~ "using this name (%p)\n" +#~ msgstr "" +#~ "%s::%s - RPC %s:%p no pudo ser registrada: otro evento está actualmente " +#~ "usando este nombre (%p)\n" + +#, fuzzy +#~ msgid "%s:%d - async RPC %s:%p could not be unregistered: not found\n" +#~ msgstr "" +#~ "%s::%s RPC asíncrona %s:%p no pudo ser desregistrada: no encontrada\n" + +#~ msgid "`%s' registering handlers %d %d %d\n" +#~ msgstr "'%s' registrando manejadores %d %d %d\n" + +#~ msgid "Using %u messages of size %u for %u times.\n" +#~ msgstr "Usando %u mensajes de un tamaño de %u durante %u veces.\n" + +#~ msgid "output in gnuplot format" +#~ msgstr "salida en formato de gnuplot" + +#~ msgid "number of iterations" +#~ msgstr "número de repeticiones" + +#~ msgid "number of messages to use per iteration" +#~ msgstr "número de mensajes a usar por iteración" + +#~ msgid "message size" +#~ msgstr "tamaño del mensaje" + +#~ msgid "sleep for SPACE ms after each a message block" +#~ msgstr "duerme durante SPACE ms después de cada bloque de mensajes" + +#~ msgid "number of messages in a message block" +#~ msgstr "número de mensajes en un bloque de mensajes" + +#~ msgid "Error establishing connection with gnunetd.\n" +#~ msgstr "Se produjo un error estableciendo conexión con gnunetd.\n" + +#~ msgid "You must specify a receiver!\n" +#~ msgstr "¡Debes especificar un receptor!\n" + +#~ msgid "Invalid receiver peer ID specified (`%s' is not valid name).\n" +#~ msgstr "" +#~ "ID del par receptor especificada no válida ('%s' no es un nombre " +#~ "válido).\n" + +#~ msgid "Time:\n" +#~ msgstr "Tiempo:\n" + +#~ msgid "\tmax %llums\n" +#~ msgstr "\tmax %llums\n" + +#~ msgid "\tmin %llums\n" +#~ msgstr "\tmin %llums\n" + +#~ msgid "\tmean %8.4fms\n" +#~ msgstr "\tmean %8.4fms\n" + +#~ msgid "\tvariance %8.4fms\n" +#~ msgstr "\tvariance %8.4fms\n" + +#~ msgid "Loss:\n" +#~ msgstr "Perdido:\n" + +#~ msgid "\tmax %u\n" +#~ msgstr "\tmax %u\n" + +#~ msgid "\tmin %u\n" +#~ msgstr "\tmin %u\n" + +#~ msgid "\tmean %8.4f\n" +#~ msgstr "\tmean %8.4f\n" + +#~ msgid "\tvariance %8.4f\n" +#~ msgstr "\tvariance %8.4f\n" + +#~ msgid "Output format not known, this should not happen.\n" +#~ msgstr "El formato de salida es desconocido, ésto no debería pasar.\n" + +#~ msgid "" +#~ "\n" +#~ "Did not receive the message from gnunetd. Is gnunetd running?\n" +#~ msgstr "" +#~ "\n" +#~ "No se recibió el mensaje de gnunetd. ¿Está gnunetd ejecutandose?\n" + +#, fuzzy +#~ msgid "# bytes received in plaintext of type %d" +#~ msgstr "# bytes recibidos por TCP" + +#, fuzzy +#~ msgid "# bytes allocated by SQLite" +#~ msgstr "# bytes en la base de datos" + +#~ msgid "" +#~ "Failed to load MySQL database module. Check that MySQL is running and " +#~ "configured properly!\n" +#~ msgstr "" +#~ "Falló al cargar el modulo de la base de datos MySQL. ¡Comprueba que " +#~ "MySQL esta ejecutandose y esta configurada correctamente!\n" + +#, fuzzy +#~ msgid "use PRIORITY for the priority of the trace request" +#~ msgstr "especifica la prioridad del contenido" + +#, fuzzy +#~ msgid "HELLO message from `%s' has an invalid signature. Dropping.\n" +#~ msgstr "mensaje de saludo de '%s' inválido (firma inválida). Omitiendo.\n" + +#, fuzzy +#~ msgid "HELLO message has expiration too far in the future. Dropping.\n" +#~ msgstr "" +#~ "mensaje de saludo recibido inválido (tiempo superior al límite). " +#~ "Omitiendo.\n" + +#, fuzzy +#~ msgid "Could not send HELLO+PING, ping buffer full.\n" +#~ msgstr "Imposible mandar ahora saludos+PING, buffer del ping lleno.\n" + +#~ msgid "" +#~ "Announcing ourselves pointless: no other peers are known to us so far.\n" +#~ msgstr "" +#~ "Es inútil anunciarnos: no hay más pares que nos conozcan más allá.\n" + +#, fuzzy +#~ msgid "# Peer advertisements of type NAT received" +#~ msgstr "# Anuncios de los pares recibidos" + +#, fuzzy +#~ msgid "# Peer advertisements updating earlier HELLOs" +#~ msgstr "# Anuncios de los pares recibidos" + +#, fuzzy +#~ msgid "# Peer advertisements for unsupported transport" +#~ msgstr "# Anuncios de los pares recibidos" + +#, fuzzy +#~ msgid "# Peer advertisements not confirmed due to ping busy" +#~ msgstr "# Anuncios de los pares recibidos" + +#, fuzzy +#~ msgid "# Peer advertisements not confirmed due to lack of self ad" +#~ msgstr "# Anuncios de los pares recibidos" + +#, fuzzy +#~ msgid "# Peer advertisements not confirmed due to send error" +#~ msgstr "# Anuncios de los pares recibidos" + +#~ msgid "`%s' registering handler %d (plaintext and ciphertext)\n" +#~ msgstr "'%s' registrando manejador %d (texto plano e hipertexto)\n" + +#~ msgid "" +#~ "ensures that this peer is known by other peers and discovers other peers" +#~ msgstr "" +#~ "Asegura que este par es conocido por otros pares y descubre otros pares" + +#~ msgid "`%s' registering handler %d\n" +#~ msgstr "'%s' registrando manejador %d\n" + +#, fuzzy +#~ msgid "`%s' registering CS handlers %d and %d\n" +#~ msgstr "'%s' registrando manejadores %d y %d\n" + +#~ msgid "enables P2P-chat (incomplete)" +#~ msgstr "Activa el chat P2P (incompleto)" + +#, fuzzy +#~ msgid "Existing key in file `%s' failed format check, creating new key.\n" +#~ msgstr "" +#~ "Se produjo un fallo al comprobar la clave local existente en el fichero " +#~ "'%s', creando nueva clave local.\n" + +#, fuzzy +#~ msgid "Creating new key for this nickname (this may take a while).\n" +#~ msgstr "Creando nueva clave local (esto puede llevar un tiempo).\n" + +#, fuzzy +#~ msgid "# max bytes allowed in dstore" +#~ msgstr "# bytes en la base de datos" + +#~ msgid "Transport library `%s' did not provide required function '%s%s'.\n" +#~ msgstr "" +#~ "La biblioteca de transporte '%s' no provee la función '%s%s' requerida.\n" + +#, fuzzy +#~ msgid "Query (get KEY, put KEY VALUE) DHT table." +#~ msgstr "" +#~ "Pregunta (coje KEY, pone KEY VALUE, borra KEY VALUE) a una tabla DHT." + +#, fuzzy +#~ msgid "allow TIME ms to process a GET command" +#~ msgstr "Reserva TIME ms para procesar cada comando" + +#, fuzzy +#~ msgid "Issuing `%s(%s,%s)' command.\n" +#~ msgstr "'%s(%s, %s)' falló.\n" + +#~ msgid "Command `%s' requires an argument (`%s').\n" +#~ msgstr "El comando '%s' requiere un argumento ('%s').\n" + +#~ msgid "Command `%s' requires two arguments (`%s' and `%s').\n" +#~ msgstr "El comando '%s' requiere dos argumentos ('%s' y '%s').\n" + +#~ msgid "Unsupported command `%s'. Aborting.\n" +#~ msgstr "Comando inesperado '%s'. Abortando.\n" + +#, fuzzy +#~ msgid "# dht put requests received" +#~ msgstr "# bytes recibidos por TCP" + +#, fuzzy +#~ msgid "`%s' registering p2p handlers: %d %d %d\n" +#~ msgstr "'%s' registrando manejadores %d %d %d\n" + +#~ msgid "`%s' failed. Terminating connection to client.\n" +#~ msgstr "'%s' falló. Finalizando conexión con el cleinte.\n" + +#, fuzzy +#~ msgid "`%s' registering client handlers: %d %d\n" +#~ msgstr "'%s' registrando un manejador de clientes %d\n" + +#~ msgid "" +#~ "Existing hostkey in file `%s' failed format check, creating new hostkey.\n" +#~ msgstr "" +#~ "Se produjo un fallo al comprobar la clave local existente en el fichero " +#~ "'%s', creando nueva clave local.\n" + +#~ msgid "Done creating hostkey.\n" +#~ msgstr "Correcto al crear la clave local.\n" + +#, fuzzy +#~ msgid "Removed file `%s' containing invalid HELLO data.\n" +#~ msgstr "Borrando el fichero '%s' que contiene datos de saludo no válidos.\n" + +#~ msgid "Signature failed verification: signature invalid.\n" +#~ msgstr "Falló la verificación de la firma: firma no válida.\n" + +#~ msgid "Received malformed `%s' message. Dropping.\n" +#~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" + +#~ msgid "Received ping for another peer. Dropping.\n" +#~ msgstr "Recibido ping de otro par. Omitiendo.\n" + +#~ msgid "`%s' registering handlers %d %d (plaintext and ciphertext)\n" +#~ msgstr "'%s' registrando manejadores %d %d (texto plano e hipertexto)\n" + +#, fuzzy +#~ msgid "Cannot encrypt sessionkey, peer `%s' not known!\n" +#~ msgstr "¡Imposible encriptar la clave de sesión, otro par desconocido!\n" + +#, fuzzy +#~ msgid "Could not create any HELLO for myself (have transports `%s')!\n" +#~ msgstr "¡Imposible crear la clave local!\n" + +#, fuzzy +#~ msgid "" +#~ "Session key received from peer `%s' has invalid format (discarded).\n" +#~ msgstr "El mensaje recibido del par es inválido.\n" + +#, fuzzy +#~ msgid "Session key received from peer `%s' is for `%s' and not for me!\n" +#~ msgstr "El mensaje recibido del par es inválido.\n" + +#~ msgid "setkey `%s' from `%s' fails CRC check (have: %u, want %u).\n" +#~ msgstr "" +#~ "el cambio de clave '%s' de '%s' falló al comprobar el CRC (dio: %u, " +#~ "esperado %u).\n" + +#, fuzzy +#~ msgid "" +#~ "Error parsing encrypted session key from `%s', given message part size is " +#~ "invalid.\n" +#~ msgstr "" +#~ "Error pasando la clave de sesión encriptada, el mensaje dado del tamaño " +#~ "de las partes es inválido.\n" + +#, fuzzy +#~ msgid "Unknown type in embedded message from `%s': %u (size: %u)\n" +#~ msgstr "Tipo desconocido en el mensaje embebido: %u (tamaño: %u)\n" + +#~ msgid "# sessions established" +#~ msgstr "# sesiones establecidas" + +#~ msgid "automate creation of a namespace by starting a collection" +#~ msgstr "creación automática de un espacio al empezar una colección" + +#~ msgid "create a new pseudonym under the given NICKNAME" +#~ msgstr "crea un nuevo pseudónimo bajo el APODO dado" + +#~ msgid "delete the pseudonym with the given NICKNAME" +#~ msgstr "borra el pseudónimo con el APODO dado" + +#~ msgid "end automated building of a namespace (ends collection)" +#~ msgstr "" +#~ "finaliza la construcción automática de un espacio (finaliza la " +#~ "recolección)" + +#~ msgid "" +#~ "Create new pseudonyms, delete pseudonyms or list existing pseudonyms." +#~ msgstr "" +#~ "Crea nuevos pseudónimos, borra pseudónimos o lista los pseudónimos " +#~ "existentes." + +#~ msgid "" +#~ "use the given keyword to advertise the namespace (use when creating a new " +#~ "pseudonym)" +#~ msgstr "" +#~ "usa la clave dada para anunciar el espacio (úsalo cuando crees un nuevo " +#~ "pseudónimo)" + +#, fuzzy +#~ msgid "specify metadata describing the namespace or collection" +#~ msgstr "" +#~ "finaliza la construcción automática de un espacio (finaliza la " +#~ "recolección)" + +#~ msgid "" +#~ "do not generate an advertisement for this namespace (use when creating a " +#~ "new pseudonym)" +#~ msgstr "" +#~ "no genera un anuncio para este espacio (úsalo cuando crees un nuevo " +#~ "pseudónimo)" + +#~ msgid "do not list the pseudonyms from the pseudonym database" +#~ msgstr "no listar los pseudónimos de la base de datos de pseudónimos" + +#~ msgid "" +#~ "specify IDENTIFIER to be the address of the entrypoint to content in the " +#~ "namespace (use when creating a new pseudonym)" +#~ msgstr "" +#~ "especifica el IDENTIFIER para ser la dirección del punto de entrada al " +#~ "contenido en el espacio (úsalo cuando crees un nuevo pseudónimo)" + +#~ msgid "Namespace `%s' (%s) has rating %d.\n" +#~ msgstr "El espacio '%s' (%s) ha sido valorado con un %d.\n" + +#~ msgid "\tRating (after update): %d\n" +#~ msgstr "\tValoración (después de la actualización): %d\n" + +#~ msgid "Collection stopped.\n" +#~ msgstr "Colección detenida.\n" + +#~ msgid "Failed to stop collection (not active?).\n" +#~ msgstr "Falló al parar la recolección (¿no está activa?).\n" + +#~ msgid "Pseudonym `%s' deleted.\n" +#~ msgstr "El pseudónimo '%s' fue borrado.\n" + +#~ msgid "Error deleting pseudonym `%s' (does not exist?).\n" +#~ msgstr "Error borrando el pseudónimo '%s' (¿no existe?).\n" + +#, fuzzy +#~ msgid "Started collection.\n" +#~ msgstr "Iniciada colección '%s'.\n" + +#~ msgid "Namespace `%s' created (root: %s).\n" +#~ msgstr "El espacio '%s' fue creado (root: %s).\n" + +#, fuzzy +#~ msgid "You must specify a name for the collection (`%s' option).\n" +#~ msgstr "Debes especificar un apodo (use la opción '%s').\n" + +#~ msgid "%d files found in directory.\n" +#~ msgstr "%d ficheros encontrados en el directorio.\n" + +#~ msgid "Perform directory related operations." +#~ msgstr "Realiza operaciones respecto al directorio." + +#~ msgid "" +#~ "remove all entries from the directory database and stop tracking URIs" +#~ msgstr "" +#~ "borra todas las entradas de la base de datos del directorio y detiene el " +#~ "seguimiento de URIs" + +#~ msgid "list entries from the directory database" +#~ msgstr "lista las entradas de la base de datos del directorio" + +#~ msgid "start tracking entries for the directory database" +#~ msgstr "comienza a seguir las entradas de la base de datos del directorio" + +#~ msgid "Listed %d matching entries.\n" +#~ msgstr "%d entradas encontradas.\n" + +#, fuzzy +#~ msgid "Upload of `%s' at %llu out of %llu bytes.\n" +#~ msgstr "Descargado del fichero '%s' el %16llu de %16llu bytes(%8.3f kbps)\n" + +#, fuzzy +#~ msgid "Upload aborted.\n" +#~ msgstr "Descarga abortada" + +#, fuzzy +#~ msgid "Uploading suspended.\n" +#~ msgstr "¡Subida rechazada!" + +#, fuzzy +#~ msgid "" +#~ "run in debug mode; gnunet-auto-share will not daemonize and error " +#~ "messages will be written to stderr instead of a logfile" +#~ msgstr "" +#~ "se ejecuta en modo de depuración; gnunetd no sera un demonio y los " +#~ "mensajes de error serán escritos a través de stderr en vez de en un " +#~ "fichero de log" + +#, fuzzy +#~ msgid "" +#~ "do not use libextractor to add additional references to directory entries " +#~ "and/or the published file" +#~ msgstr "" +#~ "usa libextractor para añadir referencias directas adicionales a las " +#~ "entradas del directorio" + +#~ msgid "Created entry `%s' in namespace `%s'\n" +#~ msgstr "Creada la entrada '%s' en el espacio '%s'\n" + +#, fuzzy +#~ msgid "" +#~ "%16llu of %16llu bytes inserted (estimating %6s to completion) - %s\n" +#~ msgstr "%16llu de %16llu bytes insertados (%s estimado para completar)\n" + +#, fuzzy +#~ msgid "" +#~ "Upload of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" +#~ msgstr "" +#~ "Subida de '%s' completada, %llu bytes tomaron %llu segundos (%8.3f " +#~ "kbps).\n" + +#, fuzzy +#~ msgid "" +#~ "\n" +#~ "Upload aborted.\n" +#~ msgstr "Descarga abortada" + +#, fuzzy +#~ msgid "" +#~ "\n" +#~ "Error uploading file: %s" +#~ msgstr "" +#~ "\n" +#~ "Error subiendo el fichero %s\n" + +#~ msgid "" +#~ "even if gnunetd is running on the local machine, force the creation of a " +#~ "copy instead of making a link to the GNUnet share directory" +#~ msgstr "" +#~ "aunque gnunetd este corriendo en el ordenador local, fuerza la creación " +#~ "de una copia en vez de hacer un enlace al directorio para compartir de " +#~ "GNUnet" + +#~ msgid "Make files available to GNUnet for sharing." +#~ msgstr "Permite a GNUnet disponer de los ficheros para compartirlos." + +#~ msgid "Could not access namespace `%s' (does not exist?).\n" +#~ msgstr "Imposible acceder al espacio '%s' (¿no existe?).\n" + +#~ msgid "Search GNUnet for files." +#~ msgstr "Buscar GNUnet en busca de ficheros." + +#~ msgid "write encountered (decrypted) search results to FILENAME" +#~ msgstr "escribe los resultados encontrados (desencriptados) a FILENAME" + +#~ msgid "Error converting arguments to URI!\n" +#~ msgstr "¡Se produjo un error al convertir los argumentos a una URI!\n" + +#~ msgid "" +#~ "%16llu of %16llu bytes unindexed (estimating %llu seconds to " +#~ "completion) " +#~ msgstr "" +#~ "%16llu de %16llu bytes desindexados (estimados %llu segundos para " +#~ "completar) " + +#, fuzzy +#~ msgid "" +#~ "\n" +#~ "Unindexing of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" +#~ msgstr "" +#~ "\n" +#~ "El desindexado de '%s' se completó, %llu bytes tomaron %llu segundos " +#~ "(%8.3f kbps).\n" + +#, fuzzy +#~ msgid "Not enough arguments. You must specify a filename.\n" +#~ msgstr "" +#~ "Argumentos insuficientes. Debes especificar una URI de un fichero de " +#~ "GNUnet\n" + +#~ msgid "`%s' failed. Is `%s' a file?\n" +#~ msgstr "'%s' falló. ¿Es '%s' un fichero?\n" + +#~ msgid "Download files from GNUnet." +#~ msgstr "Descarga los ficheros de GNUnet" + +#, fuzzy +#~ msgid "Download of file `%s' at %16llu out of %16llu bytes (%8.3f KiB/s)\n" +#~ msgstr "Descargado del fichero '%s' el %16llu de %16llu bytes(%8.3f kbps)\n" + +#, fuzzy +#~ msgid "Download aborted.\n" +#~ msgstr "Descarga abortada" + +#, fuzzy +#~ msgid "Download of file `%s' complete. Speed was %8.3f KiB per second.\n" +#~ msgstr "" +#~ "Descarga del fichero '%s' completada. La velocidad media fue " +#~ "%8.3fkilobytes por segundo.\n" + +#~ msgid "Not enough arguments. You must specify a GNUnet file URI\n" +#~ msgstr "" +#~ "Argumentos insuficientes. Debes especificar una URI de un fichero de " +#~ "GNUnet\n" + +#~ msgid "URI `%s' invalid for gnunet-download.\n" +#~ msgstr "La URI '%s' no es válida para una descarga-de-gnunet.\n" + +#, fuzzy +#~ msgid "No filename specified, using `%s' instead (for now).\n" +#~ msgstr "Ningún nombre especificado para la tabla, usando '%s'.\n" + +#, fuzzy +#~ msgid "Downloading %d files from directory `%s'.\n" +#~ msgstr "Descarga los ficheros de GNUnet" + +#, fuzzy +#~ msgid "Did not find any files in directory `%s'\n" +#~ msgstr "Falló al actualizar los datos del módulo '%s'\n" + +#~ msgid "File stored as `%s'.\n" +#~ msgstr "Fichero almacenado en '%s'.\n" + +#~ msgid "Collecting file identifiers disabled.\n" +#~ msgstr "Recolección de identificadores de fichero desactivada.\n" + +#~ msgid "Deleted corrupt URI database in `%s'." +#~ msgstr "Borrada base de datos de URIs corrupta en '%s'." + +#~ msgid "Cannot get size of file `%s'" +#~ msgstr "Imposible determinar el tamaño del fichero '%s'" + +#~ msgid "Cannot hash `%s'.\n" +#~ msgstr "Imposible hallar el hash de '%s'.\n" + +#~ msgid "Initialization for indexing file `%s' failed.\n" +#~ msgstr "" +#~ "Durante la inicialización de la indexación del fichero '%s' se produjo un " +#~ "fallo.\n" + +#, fuzzy +#~ msgid "Cannot open file `%s': `%s'" +#~ msgstr "Imposible abrir el fichero de configuración '%s'.\n" + +#~ msgid "Renaming of file `%s' to `%s' failed: %s\n" +#~ msgstr "Al renombrar el fichero '%s' a '%s' se produjo un fallo: %s\n" + +#~ msgid "Could not rename file `%s' to `%s': file exists\n" +#~ msgstr "Imposible renombrar el fichero '%s' a '%s': el fichero ya existe\n" + +#~ msgid "CHK URI not allowed for search.\n" +#~ msgstr "CHK URI no autorizado para buscar.\n" + +#~ msgid "LOC URI not allowed for search.\n" +#~ msgstr "LOC URI no autorizado para buscar.\n" + +#~ msgid "File `%s' does not contain a pseudonym.\n" +#~ msgstr "El fichero '%s' no contiene un pseudónimo.\n" + +#~ msgid "Format of pseudonym `%s' is invalid.\n" +#~ msgstr "Formato del pseudónimo '%s' no es válido.\n" + +#, fuzzy +#~ msgid "Format of file `%s' is invalid, trying to remove.\n" +#~ msgstr "El formato del fichero '%s' no es válido.\n" + +#~ msgid "" +#~ "Decrypted content does not match key. This is either a bug or a " +#~ "maliciously inserted file. Download aborted.\n" +#~ msgstr "" +#~ "El contenido desencriptado no encuentra una clave. Esto puede ser un bug " +#~ "o un fichero introducido maliciosamente. Descarga abortada.\n" + +#, fuzzy +#~ msgid "Application aborted." +#~ msgstr "_Opciones" + +#~ msgid "FSUI state file `%s' had syntax error at offset %u.\n" +#~ msgstr "" +#~ "Fichero del estado de FSUI '%s' tiene un error de sintáxis en la " +#~ "asignación %u.\n" + +#, fuzzy +#~ msgid "" +#~ "`%s' registering client handlers %d %d %d %d %d %d %d %d and P2P handlers " +#~ "%d %d\n" +#~ msgstr "" +#~ "'%s' registrando manejadores de clientes %d %d %d %d %d %d %d %d %d\n" + +#~ msgid "enables (anonymous) file-sharing" +#~ msgstr "activa la compartición de ficheros anónima" + +#~ msgid "" +#~ "Because the file `%s' has been unavailable for 3 days it got removed from " +#~ "your share. Please unindex files before deleting them as the index now " +#~ "contains invalid references!\n" +#~ msgstr "" +#~ "El fichero '%s' se ha eliminado de tus compartidos porque no ha estado " +#~ "disponible durante tres días. Por favor, desindexa los ficheros antes de " +#~ "borrarlos porque eso causa que el índice tenga referencias no válidas.\n" + +#, fuzzy +#~ msgid "" +#~ "Unindexed ODB block `%s' from offset %llu already missing from " +#~ "datastore.\n" +#~ msgstr "" +#~ "Bloque ODB '%s' desindexado del offset %llu perdido de la base de datos.\n" + +#, fuzzy +#~ msgid "# gap client requests tracked" +#~ msgstr "# mensajes PONG encriptados recibidos" + +#~ msgid "# blocks migrated" +#~ msgstr "# blocks migrados" + +#, fuzzy +#~ msgid "# blocks injected for migration" +#~ msgstr "# blocks migrados" + +#, fuzzy +#~ msgid "# on-demand fetches for migration" +#~ msgstr "# blocks migrados" + +#, fuzzy +#~ msgid "Friend list of %s:%d\n" +#~ msgstr "Fallo al conectar a gnunetd.\n" + +#, fuzzy +#~ msgid "set number of daemons to start" +#~ msgstr "número de mensajes a usar por iteración" + +#, fuzzy +#~ msgid "Waiting for peers to connect" +#~ msgstr "Esperando a los pares para conectar (%u ciclos restantes)...\n" + +#, fuzzy +#~ msgid "Bootstrap data obtained from `%s' is invalid.\n" +#~ msgstr "Formato del pseudónimo '%s' no es válido.\n" + +#~ msgid "`%s' registering client handler %d\n" +#~ msgstr "'%s' registrando un manejador de clientes %d\n" + +#~ msgid "allows clients to determine gnunetd's configuration" +#~ msgstr "permite a los clientes determinar la configuración de gnunetd" + +#~ msgid "`%s' registering client handler %d and %d\n" +#~ msgstr "'%s' registrando manejador de clientes %d y %d\n" + +#, fuzzy +#~ msgid "% of allowed network load (up)" +#~ msgstr "% de red permitida para la subida" + +#, fuzzy +#~ msgid "% of allowed network load (down)" +#~ msgstr "% de red permitida para bajada" + +#, fuzzy +#~ msgid "% of allowed cpu load" +#~ msgstr "% de CPU permitida para el uso" + +#, fuzzy +#~ msgid "% of allowed io load" +#~ msgstr "% de CPU permitida para el uso" + +#, fuzzy +#~ msgid "`%s' registering client handlers %d %d %d and p2p handler %d\n" +#~ msgstr "" +#~ "'%s' registrando manejadores de clientes %d %d %d %d %d %d %d %d %d\n" + +#~ msgid "Supported peer-to-peer messages:\n" +#~ msgstr "Mensajes P2P soportados:\n" + +#~ msgid "Supported client-server messages:\n" +#~ msgstr "Mensajes cliente-servidor soportados:\n" + +#~ msgid "prints supported protocol messages" +#~ msgstr "imprime los mensajes del protocolo" + +#, fuzzy +#~ msgid "VPN Received unknown IP version %d...\n" +#~ msgstr "Recibida petición de tipo desconocido %d en %s: %d\n" + +#, fuzzy +#~ msgid "Cannot open tunnel device: %s" +#~ msgstr "Imposible abrir el fichero de configuración '%s'.\n" + +#, fuzzy +#~ msgid "Cannot set interface IPv6 address for gnu%d because %s\n" +#~ msgstr "Imposible obtener la dirección IP para la interfaz '%s'.\n" + +#, fuzzy +#~ msgid "Cannot add route IPv6 address for gnu%s because %s\n" +#~ msgstr "Imposible obtener la dirección IP para la interfaz '%s'.\n" + +#, fuzzy +#~ msgid "`%s' initialising RFC4913 module %d and %d\n" +#~ msgstr "'%s' registrando manejadores %d y %d\n" + +#, fuzzy +#~ msgid "enables IPv6 over GNUnet (incomplete)" +#~ msgstr "Activa el chat P2P (incompleto)" + +#~ msgid "Application module `%s' already initialized!\n" +#~ msgstr "¡El módulo de la aplicación '%s' ya esta inicializado!\n" + +#~ msgid "Failed to load plugin `%s' at %s:%d. Unloading plugin.\n" +#~ msgstr "Falló al cargar el plugin '%s' en %s:%d. Descargando plugin.\n" + +#~ msgid "Could not shutdown `%s': application not loaded\n" +#~ msgstr "Imposible apagar '%s': aplicación no cargada\n" + +#~ msgid "Could not shutdown application `%s': not initialized\n" +#~ msgstr "Imposible apagar la aplicación '%s': no inicializada\n" + +#~ msgid "Could not find '%s%s' method in library `%s'.\n" +#~ msgstr "Imposible encontrar el método '%s%s' en la biblioteca '%s'.\n" + +#~ msgid "Could not properly shutdown application `%s'.\n" +#~ msgstr "Imposible apagar la aplicación '%s' adecuadamente.\n" + +#~ msgid "Could not properly unload service `%s'!\n" +#~ msgstr "¡Imposible descargar adecuadamente el servicio '%s'!\n" + +#, fuzzy +#~ msgid "Core initialization failed.\n" +#~ msgstr "Conexión fallida\n" + +#~ msgid "run as user LOGIN" +#~ msgstr "ejecuta como el usuario LOGIN" + +#~ msgid "" +#~ "run in debug mode; gnunetd will not daemonize and error messages will be " +#~ "written to stderr instead of a logfile" +#~ msgstr "" +#~ "se ejecuta en modo de depuración; gnunetd no sera un demonio y los " +#~ "mensajes de error serán escritos a través de stderr en vez de en un " +#~ "fichero de log" + +#~ msgid "Starts the gnunetd daemon." +#~ msgstr "Arranca el demonio de gnunetd." + +#, fuzzy +#~ msgid "specify username as which gnunetd should run" +#~ msgstr "especifica el host en el que gnunetd esta ejecutandose" + +#~ msgid "Configuration or GNUnet version changed. You need to run `%s'!\n" +#~ msgstr "" +#~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " +#~ "'%s'!\n" + +#~ msgid "The `%s' request received from client is malformed.\n" +#~ msgstr "La petición '%s' recibida del cliente esta mal formada.\n" + +#, fuzzy +#~ msgid "Registering failed, message type %d already in use.\n" +#~ msgstr "%s falló, el mensaje del tipo %d ya está en uso.\n" + +#, fuzzy +#~ msgid "Unable to obtain filesystem information for `%s': %u\n" +#~ msgstr "Imposible guardar el fichero de configuración '%s': %s.\n" + +#, fuzzy +#~ msgid "`%s' message invalid (signature invalid).\n" +#~ msgstr "mensaje de saludo inválido (firma no válida).\n" + +#~ msgid "Message details: %u: length %d, priority: %d\n" +#~ msgstr "Detalles del mensaje: %u: longitud %d, prioridad: %d\n" + +#~ msgid "Message from `%s' discarded: invalid format.\n" +#~ msgstr "Mensaje de '%s' descartado: formato inválido.\n" + +#~ msgid "Invalid sequence number %u <= %u, dropping message.\n" +#~ msgstr "Secuencia de números no válida %u <= %u, omitiendo mensaje.\n" + +#~ msgid "Message received more than one day old. Dropped.\n" +#~ msgstr "Mensajes recibidos de mas de un día de antigüedad. Omitidos.\n" + +#~ msgid "# bytes noise sent" +#~ msgstr "# \"bytes-ruido\" mandados" + +#, fuzzy +#~ msgid "# total bytes per second receive limit" +#~ msgstr "# bytes de ruido recibidos" + +#, fuzzy +#~ msgid "# total number of messages in send buffers" +#~ msgstr "número de mensajes en un bloque de mensajes" + +#, fuzzy +#~ msgid "# total number of bytes we were allowed to send but did not" +#~ msgstr "número de mensajes en un bloque de mensajes" + +#, fuzzy +#~ msgid "# total number of bytes we were allowed to sent" +#~ msgstr "número de mensajes en un bloque de mensajes" + +#~ msgid "`%s': Could not create hello.\n" +#~ msgstr "'%s': Imposible crear saludo.\n" + +#~ msgid "`%s': Could not send.\n" +#~ msgstr "'%s': Imposible mandar.\n" + +#~ msgid "`%s': Could not disconnect.\n" +#~ msgstr "'%s': Imposible desconectar.\n" + +#, fuzzy +#~ msgid "" +#~ "`%s' transport OK. It took %ums to transmit %llu messages of %llu bytes " +#~ "each.\n" +#~ msgstr "" +#~ "Transporte '%s' OK. Tomó %ums transmitir %d mensajes de %d bytes cada " +#~ "uno.\n" + +#~ msgid " Transport %d is not being tested\n" +#~ msgstr " El transporte %d no esta siendo probado\n" + +#~ msgid "" +#~ "\n" +#~ "Contacting `%s'." +#~ msgstr "" +#~ "\n" +#~ "Contactando '%s'." + +#~ msgid " Connection failed (bug?)\n" +#~ msgstr "Conexión fallida (¿bug?)\n" + +#, fuzzy +#~ msgid "OK!\n" +#~ msgstr "OK" + +#~ msgid "send messages with SIZE bytes payload" +#~ msgstr "manda mensajes con SIZE bytes payload" + +#~ msgid "Testing transport(s) %s\n" +#~ msgstr "Probando transporte(s) %s\n" + +#~ msgid "Available transport(s): %s\n" +#~ msgstr "Transporte(s) disponible(s): %s\n" + +#, fuzzy +#~ msgid "%s failed for url `%s' and post-data `%s' at %s:%d: `%s'\n" +#~ msgstr "'%s' falló en %s: %d con error: '%s'.\n" + +#~ msgid "# bytes sent via HTTP" +#~ msgstr "# bytes mandados vía HTTP" + +#~ msgid "# bytes dropped by HTTP (outgoing)" +#~ msgstr "#bytes omitidos vía HTTP (salientes)" + +#, fuzzy +#~ msgid "# HTTP curl receive callbacks" +#~ msgstr "# bytes recibidos por TCP" + +#, fuzzy +#~ msgid "# HTTP connect calls" +#~ msgstr "# de pares conectados" + +#, fuzzy +#~ msgid "Failed to obtain my (external) %s address!\n" +#~ msgstr "¡Falló al obtener mi dirección IP (externa)!\n" + +#, fuzzy +#~ msgid "specify host on which gnunetd is running" +#~ msgstr "especifica el host en el que gnunetd esta ejecutandose" + +#, fuzzy +#~ msgid "No help available." +#~ msgstr "'%s' no esta disponible." + +#, fuzzy +#~ msgid "Show rarely used options" +#~ msgstr "Mostrar todas las opciones" + +#, fuzzy +#~ msgid "Meta-configuration" +#~ msgstr "Configuración de GNUnet" + +#, fuzzy +#~ msgid "Full pathname of GNUnet HOME directory" +#~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#, fuzzy +#~ msgid "Full pathname of GNUnet directory for file-sharing data" +#~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#, fuzzy +#~ msgid "Full pathname to the directory with the key-value database" +#~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#, fuzzy +#~ msgid "Full pathname of GNUnet directory for indexed files symbolic links" +#~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#, fuzzy +#~ msgid "Disable automatic establishment of connections" +#~ msgstr "Se produjo un error estableciendo conexión con gnunetd.\n" + +#, fuzzy +#~ msgid "Run gnunetd as this group." +#~ msgstr "Ejecutar gnunet-update" + +#, fuzzy +#~ msgid "General settings" +#~ msgstr "Otras configuraciones" + +#, fuzzy +#~ msgid "Settings for restricting connections to friends" +#~ msgstr "'%s' falló. Finalizando conexión con el cleinte.\n" + +#, fuzzy +#~ msgid "Name of the MySQL database GNUnet should use" +#~ msgstr "Imposible inicializar SQLite.\n" + +#, fuzzy +#~ msgid "Configuration file that specifies the MySQL username and password" +#~ msgstr "" +#~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " +#~ "'%s'!\n" + +#, fuzzy +#~ msgid "Configuration of the MySQL database" +#~ msgstr "" +#~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " +#~ "'%s'!\n" + +#, fuzzy +#~ msgid "MB of diskspace GNUnet can use for anonymous file sharing" +#~ msgstr "activa la compartición de ficheros anónima" + +#, fuzzy +#~ msgid "Number of entries in the migration buffer" +#~ msgstr "número de mensajes en un bloque de mensajes" + +#, fuzzy +#~ msgid "" +#~ "MB of diskspace GNUnet can use for caching DHT index data (the data will " +#~ "be stored in /tmp)" +#~ msgstr "activa la compartición de ficheros anónima" + +#, fuzzy +#~ msgid "Options for anonymous file sharing" +#~ msgstr "activa la compartición de ficheros anónima" + +#, fuzzy +#~ msgid "Applications" +#~ msgstr "_Opciones" + +#, fuzzy +#~ msgid "Network interface" +#~ msgstr "Interfaz de red:" + +#, fuzzy +#~ msgid "Network interface to monitor" +#~ msgstr "Interfaz de red:" + +#, fuzzy +#~ msgid "Load management" +#~ msgstr "Argumentos en la linea de comandos inválidos.\n" + +#, fuzzy +#~ msgid "This is equivalent to the -H option. The format is IP:PORT." +#~ msgstr "Muestra el valor de la opción" + +#, fuzzy +#~ msgid "What is the path to the configuration file for gnunetd?" +#~ msgstr "Esta es la herramienta de configuración de GNUnet." + +#, fuzzy +#~ msgid "General options" +#~ msgstr "Otras configuraciones" + +#, fuzzy +#~ msgid "Full pathname of GNUnet client HOME directory" +#~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" + +#, fuzzy +#~ msgid "`%s' failed at %s:%d in %s with error: %s\n" +#~ msgstr "'%s' falló en %s: %d con el error: %s\n" + +#, fuzzy +#~ msgid "`%s' failed at %s:%d with error `%s' after %llums\n" +#~ msgstr "'%s' falló en %s: %d con el error: %s\n" + +#~ msgid "'%s(%s,%s)' succeeded\n" +#~ msgstr "'%s (%s, %s)' logrado satisfactoriamente\n" + +#~ msgid "'%s(%s,%s)' failed.\n" +#~ msgstr "'%s(%s, %s)' falló.\n" + +#, fuzzy +#~ msgid "" +#~ "Directory `%s' in directory `%s' does not match naming convention. " +#~ "Removed.\n" +#~ msgstr "" +#~ "El fichero '%s' en el directorio '%s' no sigue la convención de nombres. " +#~ "Eliminando.\n" + +#, fuzzy +#~ msgid "You must specify one and only one directory for sharing.\n" +#~ msgstr "Debes especificar uno y solo un fichero para desindexar.\n" + +#~ msgid "" +#~ "set interval for availability of updates to SECONDS (for namespace " +#~ "insertions only)" +#~ msgstr "" +#~ "cambia el intervalo de disponibilidad de las actualizaciones a SEGUNDOS " +#~ "(para inserciones en el espacio solamente)" + +#~ msgid "" +#~ "specifies this as an aperiodic but updated publication (for namespace " +#~ "insertions only)" +#~ msgstr "" +#~ "especifica esto como una aperiódica pero actualizada publicación (para " +#~ "inserciones en el espacio únicamente)" + +#~ msgid "specify creation time for SBlock (see man-page for format)" +#~ msgstr "" +#~ "especifica el tiempo para la creación de un Superbloque (vea la página " +#~ "del manual para el formato)" + +#~ msgid "" +#~ "ID of the previous version of the content (for namespace update only)" +#~ msgstr "" +#~ "ID de la versión previa del contenido (para actualizaciones del espacio " +#~ "únicamente)" + +#~ msgid "Parsing time failed. Use `%s' format.\n" +#~ msgstr "Se produjo un fallo al analizar el tiempo. Use el formato '%s'.\n" + +#~ msgid "Publication interval for periodic publication changed." +#~ msgstr "Intervalo de publicación periódica cambiado." + +#~ msgid "" +#~ "Publishing update for periodically updated content more than a week ahead " +#~ "of schedule.\n" +#~ msgstr "" +#~ "publicaciones actualizadas para contenido actualizado periódicamente más " +#~ "de una semana antes de la tarea planificada.\n" + +#, fuzzy +#~ msgid "Received malformed message via TCP. Closing.\n" +#~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" + +#~ msgid "Cannot create pseudonym `%s', file `%s' exists.\n" +#~ msgstr "Imposible crear el pseudónimo '%s', el fichero '%s' ya existe.\n" + +#~ msgid "GNUnet configuration assistant" +#~ msgstr "Asistente de configuración de GNUnet" + +#~ msgid "" +#~ "Welcome to GNUnet!\n" +#~ "\n" +#~ "This assistant will ask you a few basic questions in order to configure " +#~ "GNUnet.\n" +#~ "\n" +#~ "Please visit our homepage at\n" +#~ "\thttp://gnunet.org\n" +#~ "and join our community at\n" +#~ "\thttps://gnunet.org/drupal/\n" +#~ "\n" +#~ "Have a lot of fun,\n" +#~ "\n" +#~ "The GNUnet team" +#~ msgstr "" +#~ "¡Bienvenido a GNUnet!\n" +#~ "\n" +#~ "Este asistente le preguntará unos datos básicos para configurar GNUnet.\n" +#~ "\n" +#~ "Por favor, visite nuestra página en\n" +#~ "\thttps://gnunet.org/drupal/\n" +#~ "\n" +#~ "Diviertase,\n" +#~ "\n" +#~ "El equipo de GNUnet" + +#~ msgid "Next" +#~ msgstr "Siguiente" + +#~ msgid "" +#~ "Enter information about your network connection here.\n" +#~ "\n" +#~ "The \"Network interface\" is the device that connects your computer to " +#~ "the internet. This is usually a modem, an ISDN card or a network card in " +#~ "case you are using DSL.\n" +#~ "\n" +#~ "If your provider always assigns the same IP-Address to you (a \"static\" " +#~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " +#~ "changes every now and then (\"dynamic\" IP-Address) but there's a " +#~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " +#~ "you can also enter it here.\n" +#~ "If in doubt, leave the field empty. GNUnet will then try to determine " +#~ "your IP-Address.\n" +#~ "\n" +#~ "If you are connected to the internet through another computer doing SNAT, " +#~ "a router or a \"hardware firewall\" and other computers on the internet " +#~ "cannot connect to this computer, check the last option on this page. " +#~ "Leave it unchecked on direct connections through modems, ISDN cards and " +#~ "DNAT (also known as \"port forwarding\")." +#~ msgstr "" +#~ "Introduce información acerca de tu conexión aquí.\n" +#~ "\n" +#~ "La \"Interfaz de red\" es el dispositivo que conecta tu ordenador a " +#~ "Internet. Normalmente es un módem, una tarjeta de RDSI, un módem ADSL o " +#~ "una tarjeta de red en el caso de un router.\n" +#~ "\n" +#~ "Si tu proveedor siempre te da la misma dirección IP (una dirección IP " +#~ "\"estática\") introducelo en el campo \"Dirección IP\". Si tu dirección " +#~ "IP cambia (una dirección IP \"dinámica\") pero hay un nombre de dominio " +#~ "que siempre apunta a tu dirección IP actual (\"DNS dinámica\") también " +#~ "puedes introducirla aquí.\n" +#~ "En caso de duda deja el campo vacío. GNUnet intentara determinar tu " +#~ "dirección IP automaticamente.\n" +#~ "\n" +#~ "Si tu estas conectado a Internet a través de otro ordenador haciendo " +#~ "SNAT, a un router o a un \"cortafuegos de hardware\" y otros ordenadores " +#~ "no pueden conectar con tu ordenador marca la última opción en ésta " +#~ "página. Déjala sin marcar en conexiones directas a través de modems, " +#~ "tarjetas de RDSI y DNAT (también conocido como \"seguimiento de puertos" +#~ "\")." + +#~ msgid "Computer cannot receive inbound connections (SNAT/Firewall)" +#~ msgstr "" +#~ "El ordenador no puede recibir conexiones entrantes (SNAT/Cortafuegos)" + +#~ msgid "IP-Address/Hostname:" +#~ msgstr "Dirección IP/Nombre del dominio" + +#, fuzzy +#~ msgid "Network interface:" +#~ msgstr "Interfaz de red:" + +#~ msgid "" +#~ "You can limit GNUnet's ressource usage here.\n" +#~ "\n" +#~ "\"Bandwidth limitation\" is how much data may be sent per second. If you " +#~ "have a flatrate you can set it to the maximum speed of your internet " +#~ "connection.\n" +#~ "\n" +#~ "The \"Max. CPU usage\" is the percentage of processor time GNUnet is " +#~ "allowed to use." +#~ msgstr "" +#~ "Puedes limitar el uso de recursos de GNUnet aquí.\n" +#~ "\n" +#~ "\"Limitación de ancho de banda\" es cuantos datos pueden ser mandados por " +#~ "segundo. Si tienes una tarifa plana puedes seleccionar la velocidad " +#~ "máxima de tu conexión a Internet.\n" +#~ "\n" +#~ "El \"Uso máximo de CPU\" es el porcentaje del tiempo de procesado que " +#~ "GNUnet puede usar." + +#~ msgid "Downstream (Bytes/s):" +#~ msgstr "Bajada (Bytes/s):" + +#~ msgid "Upstream (Bytes/s):" +#~ msgstr "Subida (Bytes/s):" + +#~ msgid "Bandwidth limitation" +#~ msgstr "Limitación del ancho de banda" + +#~ msgid "Use denoted bandwidth for GNUnet" +#~ msgstr "Usa el ancho de banda marcado para GNUnet" + +#~ msgid "Share denoted bandwidth with other applications" +#~ msgstr "Comparte el ancho de banda marcado con otras aplicaciones" + +#~ msgid "Bandwidth sharing" +#~ msgstr "Ancho de banda compartido" + +#~ msgid "Max. CPU usage (%):" +#~ msgstr "Uso máximo de la CPU (%):" + +#~ msgid "CPU usage" +#~ msgstr "Uso de CPU" + +#~ msgid "Load limitation" +#~ msgstr "Limitación de carga" + +#~ msgid "" +#~ "GNUnet is able to store data from other peers in your datastore. This is " +#~ "useful if an adversary has access to your inserted content and you need " +#~ "to deny that the content is yours. With \"content migration\" on, the " +#~ "content could have \"migrated\" over the internet to your node without " +#~ "your knowledge.\n" +#~ "It also helps to spread popular content over different peers to enhance " +#~ "availability.\n" +#~ "\n" +#~ "The GNUnet datastore contains all data that GNUnet generates (index data, " +#~ "inserted and migrated content). Its maximum size can be specified below.\n" +#~ "\n" +#~ "If you are an experienced user, you may want to tweak your GNUnet " +#~ "installation using the enhanced configurator.\n" +#~ "\n" +#~ "After changing the configuration and/or updating GNUnet, it is sometimes " +#~ "required to run gnunet-update to update internal data structures. " +#~ "Depending on the changes made, this may take some time." +#~ msgstr "" +#~ "GNUnet es capaz de almacenar datos de otros pares en tu base de datos. " +#~ "Ésto es útil si un adversario tiene acceso a tu contenido y tu necesitas " +#~ "negar que ese contenido sea tuyo. Con la \"migración de contenido\" " +#~ "activada, tu contenido puede haber \"migrado\" por Internet hasta tu nodo " +#~ "sin tu conocimiento.\n" +#~ "Ésto también ayuda a difundir contenidos populares por diferentes pares " +#~ "para facilitar su disponibilidad.\n" +#~ "\n" +#~ "La base de datos de GNUnet contiene todos los datos que GNUnet genera " +#~ "(índices, contenido insertado y descargado). Su máximo tamaño puede ser " +#~ "especificado debajo.\n" +#~ "\n" +#~ "Si eres un usuario experimentado, puedes desear exprimir tu instalación " +#~ "de GNUnet usando la herramienta de configuración avanzada.\n" +#~ "\n" +#~ "Después de cambiar la configuración y/o actualizar GNUnet, a veces " +#~ "esnecesario ejecutar gnunet-update para actualizar las estructuras de " +#~ "datos internas. Dependiendo de los cambios que se hayan hecho, ésto podrá " +#~ "tomar algún tiempo." + +#~ msgid "Store migrated content" +#~ msgstr "Almacena contenido migrado" + +#~ msgid "Maximum datastore size (MB):" +#~ msgstr "Máximo tamaño de almacenamiento (MB):" + +#~ msgid "Start the GNUnet background process on computer startup" +#~ msgstr "Arranca el demonio de GNUnet al encender el ordenador" + +#~ msgid "Open the enhanced configurator" +#~ msgstr "Abre el editor de configuración avanzado" + +#, fuzzy +#~ msgid "Run gnunet-update" +#~ msgstr "¡gnunet-update falló!" + +#, fuzzy +#~ msgid "Other settings" +#~ msgstr "Otras configuraciones" + +#~ msgid "Finish" +#~ msgstr "Finalizar" + +#~ msgid "" +#~ "Define the user and the group owning the GNUnet service here.\n" +#~ "\n" +#~ "For security reasons, it is a good idea to let this setup create a new " +#~ "user account and a new group under which the GNUnet service is started at " +#~ "system startup.\n" +#~ "\n" +#~ "However, GNUnet may not be able to access files other than its own. This " +#~ "includes files you want to publish in GNUnet. You'll have to grant read " +#~ "permissions to the user specified below.\n" +#~ "\n" +#~ "Leave the fields empty to run GNUnet with system privileges." +#~ msgstr "" +#~ "Define el usuario y el grupo bajo el que correrán los servicios de GNUnet " +#~ "aquí.\n" +#~ "\n" +#~ "Por razones de seguridad, es una buena idea dejar que la configuración " +#~ "cree una nueva cuenta de usuario y un nuevo grupo bajo el cual el " +#~ "servicio de GNUnet es arrancado al iniciar el sistema.\n" +#~ "\n" +#~ "Por consiguiente, GNUnet no tiene la posibilidad de acceder a otros " +#~ "ficheros que no sean los que posee. Ésto incluye los ficheros que quieras " +#~ "publicar en GNUnet. Tendrás que garantizar que el usuario especificado " +#~ "aquí posea permisos de lectura.\n" +#~ "\n" +#~ "Deja los campos vacíos para arrancar GNUnet con privilegios de sistema." + +#~ msgid "User account:" +#~ msgstr "Cuenta de usuario:" + +#~ msgid "Group:" +#~ msgstr "Grupo:" + +#~ msgid "gnunet-setup" +#~ msgstr "gnunet-setup" + +#, fuzzy +#~ msgid "Save configuration" +#~ msgstr "Configuración de GNUnet" + +#, fuzzy +#~ msgid "Show copyright information for gnunet-setup." +#~ msgstr "Se produjo un error leyendo información de gnunetd.\n" + +#, fuzzy +#~ msgid "About gnunet-setup" +#~ msgstr "gnunet-setup" + +#, fuzzy +#~ msgid "(C) 2001-2007 Christian Grothoff (and other contributing authors)" +#~ msgstr "" +#~ "C) 2001-2006 Christian Grothoff (y otros autores que han contribuido)" + +#~ msgid "This is the configuration tool for GNUnet." +#~ msgstr "Esta es la herramienta de configuración de GNUnet." + +#~ msgid "Could not unlink temporary file `%s': %s\n" +#~ msgstr "Imposible desenlazar temporalmente el fichero '%s': %s\n" + +#~ msgid "Write(%d, %p, %d) failed: %s\n" +#~ msgstr "Escribiendo(%d, %p, %d) se produjo un fallo: %s\n" + +#~ msgid "AND" +#~ msgstr "Y" + +#, fuzzy +#~ msgid "Could not find IPv6 address of host `%s': %s\n" +#~ msgstr "Imposible encontrar la IP del host '%s': %s\n" + +#, fuzzy +#~ msgid "Error running search (no reason given)." +#~ msgstr "Se produjo un fallo al comenzar la búsqueda. Consulte los logs.\n" + +#, fuzzy +#~ msgid "Download failed (no reason given)" +#~ msgstr "La descarga del ERCS falló (vea los logs)." + +#~ msgid "Maximum number of chat clients reached.\n" +#~ msgstr "Número máximo de clientes en el chat alcanzado.\n" + +#~ msgid "Now %d of %d chat clients at this node.\n" +#~ msgstr "Ahora hay %d de %d clientes de chat en este nodo.\n" + +#, fuzzy +#~ msgid "Invalid data in %s (NCS). Trying to fix (by deletion).\n" +#~ msgstr "Datos no válidos en %s. Intentando fijar (por borrado).\n" + +#~ msgid "HTTP: Could not determine my public IP address.\n" +#~ msgstr "HTTP: Imposible determinar mi dirección IP pública.\n" + +#~ msgid "" +#~ "%s::%s - RPC %s:%p could not be unregistered: another callback registered " +#~ "under that name: %p\n" +#~ msgstr "" +#~ "%s::%s - RPC %s:%p no pudo ser desregistrada: otro evento está " +#~ "actualmente registrado con este nombre (%p)\n" + +#~ msgid "%s::%s - RPC %s:%p could not be unregistered: not found\n" +#~ msgstr "%s::%s - RPC %s:%p no pudo ser desregistrada: no encontrada\n" + +#~ msgid "Dropping RPC request %u: message malformed.\n" +#~ msgstr "Omitiendo la petición RPC %u: mensaje mal formado.\n" + +#~ msgid "`%s' called with timeout above 1 hour (bug?)\n" +#~ msgstr "'%s' fue llamada con un retraso de una hora(¿bug?)\n" + +#~ msgid "RPC not unregistered: %s:%p\n" +#~ msgstr "No fue desregistrada RPC: %s:%p\n" + +#~ msgid "RPC async reply invalid.\n" +#~ msgstr "RPC respuesta asíncrona no válida.\n" + +#~ msgid "async RPC reply not received.\n" +#~ msgstr "respuesta RPC asíncrona no recibida.\n" + +#~ msgid "`%s': unknown service: %s\n" +#~ msgstr "'%s': servicio desconocido: %s\n" + +#, fuzzy +#~ msgid "# bytes received via TCP6" +#~ msgstr "# bytes recibidos por TCP" + +#, fuzzy +#~ msgid "# bytes sent via TCP6" +#~ msgstr "# bytes enviados por TCP" + +#, fuzzy +#~ msgid "# bytes dropped by TCP6 (outgoing)" +#~ msgstr "# bytes omitidos por TCP (salientes)" + +#~ msgid "UDP6: Could not determine my public IPv6 address.\n" +#~ msgstr "UDP6: Imposible determinar mi dirección IPv6 pública.\n" + +#, fuzzy +#~ msgid "# bytes received via UDP6" +#~ msgstr "# bytes recibidos vía UDP" + +#, fuzzy +#~ msgid "# bytes sent via UDP6" +#~ msgstr "# bytes enviados vía UDP" + +#, fuzzy +#~ msgid "# bytes dropped by UDP6 (outgoing)" +#~ msgstr "# bytes omitidos por UDP (salientes)" + +#, fuzzy +#~ msgid "Received malformed message instead of welcome message. Closing.\n" +#~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" + +#, fuzzy +#~ msgid "Received malformed message from tcp-peer connection. Closing.\n" +#~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" + +#, fuzzy +#~ msgid "TCP: Could not determine my public IP address.\n" +#~ msgstr "HTTP: Imposible determinar mi dirección IP pública.\n" + +#~ msgid "Cannot connect to %u.%u.%u.%u:%u: %s\n" +#~ msgstr "Imposible conectar a %u.%u.%u.%u:%u: %s\n" + +#~ msgid "UDP: Could not determine my public IP address.\n" +#~ msgstr "UDP: Imposible determinar mi dirección IP pública.\n" + +#~ msgid "Failed to send message of size %d via UDP to %u.%u.%u.%u:%u: %s\n" +#~ msgstr "" +#~ "Falló al mandar el mensaje de tamaño %d a través de UDP a %u.%u.%u.%u:%u: " +#~ "%s\n" + +#, fuzzy +#~ msgid "Received malformed message from udp-peer connection. Closing.\n" +#~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" + +#~ msgid "exit after receiving LIMIT results" +#~ msgstr "sale después de recibir LIMIT resultados" + +#, fuzzy +#~ msgid "wait DELAY seconds for search results before aborting" +#~ msgstr "espera TIMEOUT segundos para buscar resultados después de abortar" + +#~ msgid "Message received from peer is invalid.\n" +#~ msgstr "El mensaje recibido del par es inválido.\n" + +#~ msgid "myself" +#~ msgstr "yo" + +#~ msgid "" +#~ "Cover traffic requested but traffic service not loaded. Rejecting " +#~ "request.\n" +#~ msgstr "" +#~ "Solicitada la cobertura de tráfico pero el servicio de tráfico no ha sido " +#~ "cargado. Rechazando la petición.\n" + +#~ msgid "Cannot satisfy desired level of anonymity, ignoring request.\n" +#~ msgstr "" +#~ "Imposible satisfacer el nivel deseado de anonimato, ignorando la " +#~ "petición.\n" + +#~ msgid "`%s' registering handlers %d %d\n" +#~ msgstr "'%s' registrando manejadores %d %d\n" + +#, fuzzy +#~ msgid "Indexed file disappeared, deleting block for query `%s'\n" +#~ msgstr "" +#~ "Fichero indexado desaparecido, borrando el bloque para preguntas '%s'\n" + +#~ msgid "" +#~ "Configuration file must specify directory for storage of FS data in " +#~ "section `%s' under `%s'.\n" +#~ msgstr "" +#~ "El fichero de configuración debe especificar un directorio para el " +#~ "almacenamiento de los datos de FS en la sección '%s' bajo '%s'.\n" + +#~ msgid "" +#~ "Content `%s' seems to be not available on the network (tried %u times).\n" +#~ msgstr "" +#~ "El contenido '%s' parece no estar disponible en la red (intentado %u " +#~ "veces).\n" + +#, fuzzy +#~ msgid "Start GNUnet-testbed helper." +#~ msgstr "Arranca el cliente de chat de GNUnet" + +#~ msgid "Cannot connect to LOOPBACK port %d: %s\n" +#~ msgstr "Imposible conectar al puerto de LOOPBACK %d: %s\n" + +#~ msgid "No client service started. Trying again in 30 seconds.\n" +#~ msgstr "" +#~ "No hay ningún servicio de cliente ejecutandose. Se volverá a intentar en " +#~ "30 segundos.\n" + +#, fuzzy +#~ msgid "" +#~ "Error (%s) binding the TCP listener to port %d. No proxy service " +#~ "started.\n" +#~ "Trying again in %d seconds...\n" +#~ msgstr "" +#~ "No hay ningún servicio de cliente ejecutandose. Se volverá a intentar en " +#~ "30 segundos.\n" + +#~ msgid "Rejected unauthorized connection from %u.%u.%u.%u.\n" +#~ msgstr "Rechazada conexión no autorizada de %u.%u.%u.%u.\n" + +#~ msgid "Protocol violation on socket. Expected command.\n" +#~ msgstr "Violación del protocolo en el socket. Esperando comando.\n" + +#, fuzzy +#~ msgid "Start GNUnet testbed controller." +#~ msgstr "Arranca el cliente de chat de GNUnet" + +#~ msgid "Malformed entry in the configuration in section %s under %s: %s\n" +#~ msgstr "" +#~ "Entrada mal formada en la configuración en la sección %s bajo %s: %s\n" + +#~ msgid "size of `%s' message is wrong. Ignoring.\n" +#~ msgstr "el tamaño del mensaje '%s' es erroneo. Se ignora.\n" + +#~ msgid "TESTBED could not generate hello message for protocol %u\n" +#~ msgstr "" +#~ "TESTBED no puede generar el mensaje de saludo para el protocolo %u\n" + +#~ msgid "received invalid `%s' message\n" +#~ msgstr "recibido mensaje '%s' no válido\n" + +#~ msgid "received invalid `%s' message (empty module name)\n" +#~ msgstr "recibido mensaje '%s' no válido (nombre del módulo vacío)\n" + +#~ msgid "loading module `%s' failed. Notifying client.\n" +#~ msgstr "" +#~ "se produjo un fallo al cargar el módulo '%s'. Notificando al cliente.\n" + +#~ msgid "unloading module failed. Notifying client.\n" +#~ msgstr "" +#~ "se produjo un fallo al descargar el módulo. Notificando al cliente.\n" + +#~ msgid "received invalid `%s' message: %s.\n" +#~ msgstr "recibido mensaje '%s' no válido: %s.\n" + +#~ msgid "'..' is not allowed in file name (%s).\n" +#~ msgstr "'..' no esta permitido en el nombre del fichero(%s).\n" + +#~ msgid "Empty filename for UPLOAD_FILE message is invalid!\n" +#~ msgstr "" +#~ "¡Nombre del fichero vacío para el mensaje UPLOAD_FILE es inválido!\n" + +#~ msgid "Filename for UPLOAD_FILE message is not null-terminated (invalid!)\n" +#~ msgstr "" +#~ "Nombre del fichero para el mensaje UPLOAD_FILE no esta terminado en null " +#~ "(¡inválido!)\n" + +#~ msgid "Invalid message received at %s:%d." +#~ msgstr "Mensaje inválido recibido en %s:%d." + +#, fuzzy +#~ msgid "received invalid testbed message of size %u\n" +#~ msgstr "recibido mensaje '%s' no válido: %s.\n" + +#~ msgid "Could not resolve name of HTTP proxy `%s'.\n" +#~ msgstr "Imposible resolver el nombre del proxy HTTP '%s'.\n" + +#, fuzzy +#~ msgid "Could not register testbed, host `%s' unknown\n" +#~ msgstr "" +#~ "Imposible descargar lista de contactos, servidor '%s' desconocido.\n" + +#~ msgid "Failed so send HTTP request `%s' to host `%s': %s\n" +#~ msgstr "Falló al mandar la petición HTTP '%s' al host '%s': %s\n" + +#~ msgid "Exit register (error: no http response read).\n" +#~ msgstr "Saliendo del registro (error: no se leyó una respuesta de http).\n" + +#, fuzzy +#~ msgid "Description" +#~ msgstr "Pregunta" + +#, fuzzy +#~ msgid "Section" +#~ msgstr "Pregunta" + +#, fuzzy +#~ msgid "Option" +#~ msgstr "_Opciones" + +#~ msgid "Sending E-mail to `%s' failed.\n" +#~ msgstr "Enviando un correo electrónico a '%s' se produjo un fallo.\n" + +#, fuzzy +#~ msgid "Network configuration: NAT" +#~ msgstr "Configuración de GNUnet" + +#~ msgid "" +#~ "Is this machine behind NAT?\n" +#~ "\n" +#~ "If you are connected to the internet through another computer doing SNAT, " +#~ "a router or a \"hardware firewall\" and other computers on the internet " +#~ "cannot connect to this computer, say \"yes\" here. Answer \"no\" on " +#~ "direct connections through modems, ISDN cards and DNAT (also known as " +#~ "\"port forwarding\")." +#~ msgstr "" +#~ "¿Tu máquina esta detrás de un NAT?\n" +#~ "\n" +#~ "Si tu estás conectado a Internet a través de otro ordenador haciendo " +#~ "SNAT, un router o un \"cortafuegos de hardware\" y otros ordenadores no " +#~ "pueden conectarse al tuyo a través de Internet directamente, responde \"si" +#~ "\" aquí. Responde \"no\" en conexiones directas a través de módems, " +#~ "tarjetas de RDSI y DNAT (también conocido como \"seguimiento de puertos" +#~ "\")." + +#, fuzzy +#~ msgid "Configuration of the logging system" +#~ msgstr "" +#~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " +#~ "'%s'!\n" + +#, fuzzy +#~ msgid "Run gnunetd as this user." +#~ msgstr "Ejecutar gnunet-update" + +#, fuzzy +#~ msgid "Run gnunetd during system startup?" +#~ msgstr "Ejecutar gnunet-update" + +#, fuzzy +#~ msgid "Path settings" +#~ msgstr "Otras configuraciones" + +#~ msgid "specify nickname" +#~ msgstr "especifica el apodo" + +#~ msgid "You must specify a nickname (use option `%s').\n" +#~ msgstr "Debes especificar un apodo (use la opción '%s').\n" + +#~ msgid "mysql datastore" +#~ msgstr "base de datos mysql" + +#, fuzzy +#~ msgid "" +#~ "`%s' failed at %s:%d with error: I/%s S/%s SC/%s SS/%s SSC/%s U/%s D/%s " +#~ "DG/%s\n" +#~ msgstr "'%s' falló en %s: %d con el error: %s\n" + +#~ msgid "Database failed to delete `%s'.\n" +#~ msgstr "Falló al borrar de la base de datos %s.\n" + +#, fuzzy +#~ msgid "Error log:\n" +#~ msgstr "Error" + +#, fuzzy +#~ msgid "# bytes received via TCP-OLD" +#~ msgstr "# bytes recibidos por TCP" + +#, fuzzy +#~ msgid "# bytes sent via TCP-OLD" +#~ msgstr "# bytes enviados por TCP" + +#, fuzzy +#~ msgid "# bytes dropped by TCP-OLD (outgoing)" +#~ msgstr "# bytes omitidos por TCP (salientes)" + +#~ msgid "hello advertisement for protocol %d received.\n" +#~ msgstr "Inicio de comunicación del protocolo %d recibido.\n" + +#~ msgid "`%s' failed (%d, %u). Will not send PING.\n" +#~ msgstr "'%s' falló (%d, %u). No se mandará el PING.\n" + +#~ msgid "Removing hello from peer `%s' (expired %ds ago).\n" +#~ msgstr "Eliminando saludo del par '%s' (expiró hace %ds).\n" + +#~ msgid "Waiting for gnunetd to start (%u iterations left)...\n" +#~ msgstr "Esperando a gnunetd para empezar (%u ciclos restantes)...\n" + +#, fuzzy +#~ msgid "Deleting expired content. This may take a while.\n" +#~ msgstr "Creando nueva clave local (esto puede llevar un tiempo).\n" + +#~ msgid "User `%s' not known, cannot change UID to it.\n" +#~ msgstr "Usuario '%s' desconocido, imposible cambiar la UID a él.\n" + +#~ msgid "" +#~ "Expected welcome on http connection, got garbage. Closing connection.\n" +#~ msgstr "" +#~ "Esperada bienvenida en la conexión http, encontrada basura. Cerrando la " +#~ "conexión.\n" + +#~ msgid "%s: Rejected connection from blacklisted address %u.%u.%u.%u.\n" +#~ msgstr "" +#~ "%s: Conexión rechazada de una dirección de la \"lista negra\" %u.%u.%u." +#~ "%u.\n" + +#~ msgid "Unexpected reply to `%s' operation.\n" +#~ msgstr "Respuesta inesperada a la operación '%s'.\n" + +#~ msgid "join table called NAME" +#~ msgstr "únete a la tabla llamada NAME" + +#~ msgid "Malformed optional field `%s' received from peer `%s'.\n" +#~ msgstr "Campo opcional anómalo '%s' recibido del par '%s'.\n" + +#~ msgid "Malformed response to `%s' on master table.\n" +#~ msgstr "Respuesta anómala a '%s' en la tabla maestra.\n" + +#~ msgid "Invalid response to `%s' from `%s'\n" +#~ msgstr "Respuesta inválida a '%s' de '%s'\n" + +#~ msgid "Received invalid RPC `%s'.\n" +#~ msgstr "Recibido RPC '%s' inválida.\n" + +#~ msgid "RPC for `%s' received for table that we do not participate in!\n" +#~ msgstr "¡RPC para '%s' recibida de la tabla en la cual no participamos!\n" + +#~ msgid "`%s' failed. Terminating connection to client.\n" +#~ msgstr "'%s' falló. Finalizando conexión con el cliente.\n" + +#~ msgid "" +#~ "Share denoted bandwidth with other applications?\n" +#~ "\n" +#~ "Say \"yes\" here, if you don't want other network traffic to interfere " +#~ "with GNUnet's operation, but still wish to constrain GNUnet's bandwidth " +#~ "usage to values entered in the previous steps, or if you can't reliably " +#~ "measure the maximum capabilities of your connection. \"No\" can be very " +#~ "useful if other applications are causing a lot of traffic on your LAN. " +#~ "In this case, you do not want to limit the traffic that GNUnet can " +#~ "inflict on your internet connection whenever your high-speed LAN gets " +#~ "used (e.g. by NFS)." +#~ msgstr "" +#~ "¿Compartir el ancho de banda marcado con otras aplicaciones?\n" +#~ "\n" +#~ "Di \"sí\" aquí si no quieres que el resto del tráfico de la red no " +#~ "interfiera con las operaciones de GNUnet, pero aun quieres mantener el " +#~ "ancho de banda usado por GNUnet introducido en los pasos previos, o no " +#~ "puedes asegurar las máximas capacidades de tu conexión. \"No\" puede ser " +#~ "muy útil si otras aplicaciones crean mucho tráfico en tu LAN. En ese " +#~ "caso no quieres limitar el tráfico que GNUnet puede crear en tu conexión " +#~ "a Internet cuando una LAN de alta velocidad es usada (por ejemplo bajo " +#~ "NFS)." + +#~ msgid "How much CPU (in %) may be used?" +#~ msgstr "¿Cuánta CPU (en %) podrá ser usada?" + +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "This is the percentage of processor time GNUnet is allowed to use." +#~ msgstr "" +#~ "Tu puedes limitar el uso de recursos de GNUnet aquí.\n" +#~ "\n" +#~ "Este es el porcentaje del tiempo del procesador que GNUnet puede usar." + +#~ msgid "" +#~ "Store migrated content?\n" +#~ "\n" +#~ "GNUnet is able to store data from other peers in your datastore. This is " +#~ "useful if an adversary has access to your inserted content and you need " +#~ "to deny that the content is yours. With \"content migration\" on, the " +#~ "content could have \"migrated\" over the internet to your node without " +#~ "your knowledge.\n" +#~ "It also helps to spread popular content over different peers to enhance " +#~ "availability." +#~ msgstr "" +#~ "¿Almacena el contenido migrado?\n" +#~ "\n" +#~ "GNUnet puede almacenar datos de otros pares en tu ordenador. Esto es muy " +#~ "útil si un adversario accede a tu contenido insertado y necesitas negar " +#~ "que dicho contenido sea tuyo. Con la \"migración de contenidos\" " +#~ "activada, el contenido puede haber \"migrado\" a través de internet a tu " +#~ "nodo sin tu conocimiento.\n" +#~ "Ésto también ayuda a repartir contenido popular a través de diferentes " +#~ "pares para aumentar la disponibilidad." + +#~ msgid "" +#~ "If you are an experienced user, you may want to tweak your GNUnet " +#~ "installation using the enhanced configurator.\n" +#~ "\n" +#~ "Do you want to start it after saving your configuration?" +#~ msgstr "" +#~ "Si eres un usuario experimentado, puedes desear exprimir tu instalación " +#~ "de GNUnet usando la herramienta de configuración avanzada.\n" +#~ "\n" +#~ "¿Quieres arrancarla después de guardar tu configuración?" + +#~ msgid "" +#~ "Unable to save configuration file %s: %s.\n" +#~ "\n" +#~ "Try again?" +#~ msgstr "" +#~ "Imposible guardar el fichero de configuración %s: %s.\n" +#~ "\n" +#~ "¿Intentar de nuevo?" + +#~ msgid "Failed to send `%s'. Closing connection.\n" +#~ msgstr "Fallo al mandar '%s'. Cerrando la conexión.\n" + +#~ msgid "Received invalid `%s' request (size %d)\n" +#~ msgstr "Recibida petición '%s' no válida (tamaño %d)\n" + +#~ msgid "Received invalid `%s' request (wrong table)\n" +#~ msgstr "Recibida petición '%s' no válida (tabla errónea)\n" + +#~ msgid "This client already participates in the given DHT!\n" +#~ msgstr "Este cliente ya participa en el DHT dado\n" + +#~ msgid "Cannot leave DHT: table not known!\n" +#~ msgstr "Imposible dejar DHT: ¡tabla no conocida!\n" + +#~ msgid "gnunetd signaled error in response to `%s' message\n" +#~ msgstr "gnunetd lanzó una señal de error en respuesta al mensaje '%s'\n" + +#~ msgid "Failed to send `%s' message to gnunetd\n" +#~ msgstr "Falló al mandar el mensaje '%s' a gnunetd\n" + +#~ msgid "Join a DHT." +#~ msgstr "Únete a DHT" + +#~ msgid "allow SIZE bytes of memory for the local table" +#~ msgstr "Reserva SIZE bytes de memoria para la tabla local" + +#~ msgid "Call to `%s' with value '%.*s' (%d bytes).\n" +#~ msgstr "Llama a '%s' con el valor '%.*s' (%d bytes).\n" + +#~ msgid "Error joining DHT.\n" +#~ msgstr "Error uniéndose a DHT.\n" + +#~ msgid "Joined DHT. Press CTRL-C to leave.\n" +#~ msgstr "Unido a DHT. Pulsa CTRL-C para abandonarlo.\n" + +#~ msgid "`%s' failed: table not found!\n" +#~ msgstr "'%s' falló: ¡tabla no encontrada!\n" + +#~ msgid "sendAck failed. Terminating connection to client.\n" +#~ msgstr "sendAck falló. Finalizando conexión con el cliente.\n" + +#, fuzzy +#~ msgid "Upload failed (consult logs)." +#~ msgstr "La descarga del ERCS falló (vea los logs)." + +#~ msgid "Could not resolve name of SMTP server `%s': %s" +#~ msgstr "Imposible resolver el nombre del servidor de SMTP '%s': %s" + +#~ msgid "query table called NAME" +#~ msgstr "pregunta a la tabla llamada NAME" + +#~ msgid "No commands specified.\n" +#~ msgstr "Ningún comando fue especificado.\n" + +#~ msgid "Superflous arguments (ignored).\n" +#~ msgstr "Argumentos superfluos (ignorados).\n" + +#~ msgid "Query `%s' had no results.\n" +#~ msgstr "La pregunta '%s' no tuvo resultados.\n" + +#~ msgid "FSUI persistence: error restoring download\n" +#~ msgstr "FSUI persistente: error restableciendo la descarga\n" + +#~ msgid "ECRS download suspending." +#~ msgstr "La descarga del ERCS fue suspendida." + +#~ msgid "Upload failed." +#~ msgstr "Subida fallida" + +#~ msgid "Cannot upload directory without using recursion." +#~ msgstr "Imposible compartir un directorio sin hacerlo recursivamente." + +#, fuzzy +#~ msgid "expected `%s' to be a directory!\n" +#~ msgstr "¡'%s' se esperaba que '%s' fuera un directorio!\n" + +#~ msgid "Sorry, no help is available for this option.\n" +#~ msgstr "Lo siento, no hay ayuda disponible para esta opción.\n" + +#~ msgid "%s: Rejected connection from blacklisted address %s.\n" +#~ msgstr "%s: Conexión rechazada de una dirección de la \"lista negra\" %s.\n" + +#~ msgid "Received invalid UDP message from %u.%u.%u.%u:%u, dropping.\n" +#~ msgstr "Recibido mensaje UDP no válido del %u.%u.%u.%u:%u, omitiendo.\n" + +#~ msgid "" +#~ "Configuration file must specify directory for storing FS data in section `" +#~ "%s' under `%s'.\n" +#~ msgstr "" +#~ "El fichero de configuración debe especificar el directorio para almacenar " +#~ "los datos FS en la sección '%s' bajo '%s'.\n" + +#~ msgid "" +#~ "Configuration file must specify a directory for GNUnet to store per-peer " +#~ "data under %s%s\n" +#~ msgstr "" +#~ "El fichero de configuración debe especificar un directorio para que " +#~ "GNUnet almacene la información por-par bajo%s%s\n" + +#~ msgid "%s `%s' returned no known hosts!\n" +#~ msgstr "¡%s '%s' devolvió hosts desconocidos!\n" + +#~ msgid "" +#~ "specify that the contents of the namespace are of the given MIMETYPE (use " +#~ "when creating a new pseudonym)" +#~ msgstr "" +#~ "especifica que los contenidos del espacio son del MIMETYPE dado (úsalo " +#~ "cuando crees un nuevo pseudónimo)" + +#~ msgid "" +#~ "specify NAME to be the realname of the user controlling the namespace " +#~ "(use when creating a new pseudonym)" +#~ msgstr "" +#~ "especifica el NAME para ser el nombre real del usuario que controla el " +#~ "espacio (úsalo cuando crees un nuevo pseudónimo)" + +#~ msgid "" +#~ "use DESCRIPTION to describe the content of the namespace (use when " +#~ "creating a new pseudonym)" +#~ msgstr "" +#~ "usa la DESCRIPTION para describir el contenido del espacio (úsalo cuando " +#~ "crees un nuevo pseudónimo)" + +#~ msgid "" +#~ "specify the given URI as an address that contains more information about " +#~ "the namespace (use when creating a new pseudonym)" +#~ msgstr "" +#~ "especifica la URI dada como dirección que contiene mas información del " +#~ "espacio (úsalo cuando crees un nuevo pseudónimo)" + +#~ msgid "%8u of %8u bytes deleted." +#~ msgstr "%8u de %8u bytes borrados." + +#~ msgid "specify the file to delete from GNUnet (obligatory, file must exist)" +#~ msgstr "" +#~ "especifica el fichero a borrar de GNUnet (el fichero debe existir " +#~ "obligatoriamente)" + +#~ msgid "" +#~ "Remove file from GNUnet. The specified file is not removed\n" +#~ "from the filesystem but just from the local GNUnet datastore." +#~ msgstr "" +#~ "Borra el fichero de GNUnet. El fichero especificado no es borrado\n" +#~ "del sistema de ficheros, solamente de la base de datos local de GNUnet." + +#~ msgid "You must specify a filename (option -f)\n" +#~ msgstr "Debes especificar un fichero (opción -f)\n" + +#~ msgid "" +#~ "Error deleting file %s.\n" +#~ "Probably a few blocks were already missing from the database.\n" +#~ msgstr "" +#~ "Error borrando el fichero %s.\n" +#~ "Probablemente algunos bloques se hayan perdido de la base de datos.\n" + +#~ msgid "gnunet-directory [OPTIONS] [FILENAMES]" +#~ msgstr "directorio-de-gnunet [OPCIONES] [FICHEROS]" + +#~ msgid "process directories recursively" +#~ msgstr "procesa los directorios recursivamente" + +#~ msgid "You must pass a positive number to the `%s' option.\n" +#~ msgstr "Debes pasar un número positivo a la opción '%s'.\n" + +#~ msgid "Only one file or directory can be specified at a time.\n" +#~ msgstr "Solo un fichero o un directorio puede ser especificado cada vez.\n" + +#~ msgid "You must specify a file or directory to upload.\n" +#~ msgstr "Debes especificar un fichero o directorio para subir.\n" + +#~ msgid "Not enough arguments. You must specify a keyword or identifier.\n" +#~ msgstr "" +#~ "No hay suficientes argumentos. Debes especificar una clave o un " +#~ "identificador.\n" + +#~ msgid "LEVEL" +#~ msgstr "NIVEL" + +#~ msgid "FILENAME" +#~ msgstr "FICHERO" + +#~ msgid "" +#~ "Configuration file must specify a directory for GNUnet to store per-peer " +#~ "data under %s%s.\n" +#~ msgstr "" +#~ "El fichero de configuración debe especificar un directorio para que " +#~ "GNUnet almacene la información por-par bajo %s%s.\n" + +#~ msgid "Template for gnunet-clients." +#~ msgstr "Plantilla para clientes-de-gnunet." + +#~ msgid "Invalid port \"%s\" in hostlist specification, trying port %d.\n" +#~ msgstr "" +#~ "Puerto inválido \"%s\" en la especificación de la lista local, probando " +#~ "el puerto %d.\n" + +#~ msgid "Parsing HTTP response for URL `%s' failed.\n" +#~ msgstr "Analizando HTTP de la URL '%s' se produjo un fallo.\n" + +#~ msgid "Could not resolve name of HTTP proxy `%s'. Trying without a proxy.\n" +#~ msgstr "" +#~ "Imposible resolver el nombre del proxy HTTP '%s'. Intentándolo sin un " +#~ "proxy.\n" + +#~ msgid "Option `%s' makes no sense without option `%s'." +#~ msgstr "La opción '%s' no tiene ningún sentido sin la opción '%s'." + +#~ msgid "" +#~ "\n" +#~ "Exiting.\n" +#~ msgstr "" +#~ "\n" +#~ "Saliendo.\n" + +#~ msgid "Updated data for %d applications.\n" +#~ msgstr "Actualizados los datos para %d aplicaciones.\n" + +#~ msgid "Argument %d: `%s'\n" +#~ msgstr "Argumento %d: '%s'\n" + +#~ msgid "`%s' starting\n" +#~ msgstr "'%s' comenzando\n" + +#~ msgid "FATAL: Identity plugin not found!\n" +#~ msgstr "FATAL: ¡Plugin de identidad no encontrado!\n" + +#~ msgid "Available MODEs:\n" +#~ msgstr "MODOs disponibles:\n" + +#~ msgid " config\t\ttext-based configuration\n" +#~ msgstr " configuración\t\tconfiguración basada en texto\n" + +#~ msgid " menuconfig\ttext-based menu\n" +#~ msgstr " menuconfig\tmenú basado en texto\n" + +#~ msgid " wizard-curses\tBasic text-based graphical configuration\n" +#~ msgstr "" +#~ " wizard-curses\t Configuración básica en modo gráfico pero basado en " +#~ "texto\n" + +#~ msgid "" +#~ " wizard-gtk\tBasic GTK configuration\n" +#~ "\n" +#~ msgstr "" +#~ " wizard-gtk\tConfiguración GTK básica\n" +#~ "\n" + +#~ msgid "gnunet-setup must have write-access to the configuration file `%s'\n" +#~ msgstr "" +#~ "gnunet-setup debe tener acceso de escritura al fichero de configuración " +#~ "'%s'\n" + +#, fuzzy +#~ msgid "" +#~ "Can only run wizard to configure gnunetd.\n" +#~ "Did you forget the `%s' option?\n" +#~ msgstr "" +#~ "Solo se puede arrancar wizard para configurar gnunetd.\n" +#~ "¿Te olvidaste de la opción %s'?\n" + +#~ msgid "%s: symbol value `%s' invalid for %s\n" +#~ msgstr "%s: valor del símbolo '%s' no válido para %s\n" + +#~ msgid "Gtk GNUnet Configurator" +#~ msgstr "Configurador Gtk de GNUnet" + +#~ msgid "_File" +#~ msgstr "_Fichero" + +#~ msgid "_Load" +#~ msgstr "_Cargar" + +#~ msgid "Save the config in .config" +#~ msgstr "Guardar la configuración en .config" + +#~ msgid "_Save" +#~ msgstr "_Guardar" + +#~ msgid "_Quit" +#~ msgstr "_Salir" + +#~ msgid "Show _name" +#~ msgstr "Mostrar el _nombre" + +#~ msgid "Show range (Y/M/N)" +#~ msgstr "Muestra el rango (Y/M/N)" + +#~ msgid "Show _range" +#~ msgstr "Muestra el _rango" + +#~ msgid "Show _data" +#~ msgstr "Mostrar los _datos" + +#~ msgid "Show all _options" +#~ msgstr "Mostrar todas las _opciones" + +#~ msgid "_Help" +#~ msgstr "_Ayuda" + +#~ msgid "_Introduction" +#~ msgstr "_Introducción" + +#~ msgid "Goes up of one level (single view)" +#~ msgstr "Sube un nivel (vista única)" + +#~ msgid "Load" +#~ msgstr "Cargar" + +#~ msgid "Save a config file" +#~ msgstr "Guardar un fichero de configuración" + +#~ msgid "Save" +#~ msgstr "Guardar" + +#~ msgid "Single view" +#~ msgstr "Vista única" + +#~ msgid "Single" +#~ msgstr "Única" + +#~ msgid "Split view" +#~ msgstr "Vista doble" + +#~ msgid "Split" +#~ msgstr "Doble" + +#~ msgid "Full view" +#~ msgstr "Vista completa" + +#~ msgid "Full" +#~ msgstr "Completa" + +#~ msgid "Collapse the whole tree in the right frame" +#~ msgstr "Contraer el árbol completo en el lateral izquierdo" + +#~ msgid "Collapse" +#~ msgstr "Contraer" + +#~ msgid "Expand the whole tree in the right frame" +#~ msgstr "Expandir el árbol entero en el lateral izquierdo" + +#~ msgid "Expand" +#~ msgstr "Expandir" + +#~ msgid "" +#~ "This is GNUnet's configuration interface.\n" +#~ "\n" +#~ "GNUnet's options are separated into categories. You can browse them in " +#~ "the left tree. If you click on one of the categories, its options are " +#~ "shown above. \n" +#~ "\n" +#~ "To change the value of an option, simply click on its value and enter a " +#~ "new value. To get additional information about a specific option, click " +#~ "on its description." +#~ msgstr "" +#~ "Ésta es la interfaz de configuración de GNUnet.\n" +#~ "\n" +#~ "Las opciones de GNUnet están separadas en categorías. Tu puedes " +#~ "explorarlas en el árbol de la izquierda. Si pulsas en una de las " +#~ "categorías las opciones son mostradas encima.\n" +#~ "\n" +#~ "Para cambiar el valor de una opción, simplemente pulsa en su valor e " +#~ "introduce uno nuevo. Para obtener información adicional acerca de una " +#~ "opción específica, pulsa en su descripción." + +#~ msgid "Introduction" +#~ msgstr "Introducción" + +#, fuzzy +#~ msgid "" +#~ "Welcome to GNUnet Setup.\n" +#~ "\n" +#~ "For each option, a blank box indicates the feature is disabled, and " +#~ "checked one indicates it is enabled.\n" +#~ "If you do not see an option that you believe should be present, try " +#~ "turning on Show All Options under the Options menu.\n" +#~ "\n" +#~ "Although there is no cross reference yet to help you figure out what " +#~ "other options must be enabled to support the option you are interested " +#~ "in, you can still view the help of a grayed-out option.\n" +#~ "\n" +#~ "Toggling Show Debug Info under the Options menu will show the " +#~ "dependencies, which you can then match by examining other options." +#~ msgstr "" +#~ "Bienvenido a la configuración de GNUnet.\n" +#~ "\n" +#~ "Para cada opción una caja en blanco indica que la opción está desactivada " +#~ "y una marcada indica que está activada.\n" +#~ "Si no ves una opción que crees que debería estar presente, prueba " +#~ "activando la opción \"Mostrar todas las opciones\" en el menú de " +#~ "\"Opciones\".\n" +#~ "\n" +#~ "Although·there·is·no·cross·reference·yet·to·help·you·figure·out·what·other·options·must·be·enabled·to·support·the·option·you·are·interested·in," +#~ "·you·can·still·view·the·help·of·a·grayed-out·option.\n" +#~ "\n" +#~ "Toggling·Show·Debug·Info·under·the·Options·menu·will·show·the·dependencies," +#~ "·which·you·can·then·match·by·examining·other·options." + +#~ msgid "" +#~ "Configuration file not found. Please run GNUnet Setup (Client " +#~ "Configuration) first." +#~ msgstr "" +#~ "Fichero de configuración no encontrado. Por favor, ejecuta GNUnet Setup " +#~ "(Configuración del cliente) primero." + +#~ msgid "Configuration file `%s' not found. Run `gnunet-setup -d'!\n" +#~ msgstr "" +#~ "El·fichero·de·configuración·'%s'·no·ha·sido·encontrado.··¡Ejecute·'gnunet-" +#~ "setup -d'!\n" + +#~ msgid "Cron stopped\n" +#~ msgstr "Cron detenido\n" + +#~ msgid "Caught signal %d.\n" +#~ msgstr "Cogida señal %d.\n" + +#~ msgid "Invalid network notation (additional characters: `%s')." +#~ msgstr "Notación de red no válida (caracteres adicionales: '%s')." + +#~ msgid "FAILURE" +#~ msgstr "FALLO" + +#~ msgid "MESSAGE" +#~ msgstr "MENSAJE" + +#~ msgid "CRON" +#~ msgstr "CRON" + +#~ msgid "EVERYTHING" +#~ msgstr "TODO" + +#~ msgid "Invalid LOGLEVEL `%s' specified.\n" +#~ msgstr "LOGLEVEL inválido '%s' especificado.\n" + +#~ msgid "Failure at %s:%d.\n" +#~ msgstr "Fallo en %s:%d.\n" + +#~ msgid "" +#~ "Cannot determine port of gnunetd server. Define in configuration file in " +#~ "section `%s' under `%s'.\n" +#~ msgstr "" +#~ "Imposible determinar el puerto del servidor de gnunetd. Defínelo en el " +#~ "fichero de configuración en la sección '%s' bajo '%s'.\n" + +#~ msgid "" +#~ "Usage: %s\n" +#~ "%s\n" +#~ "\n" +#~ msgstr "" +#~ "Uso: %s\n" +#~ "%s\n" +#~ "\n" + +#~ msgid "Invalid argument for `%s' at %s:%d.\n" +#~ msgstr "Argumento no válido para '%s' en %s:%d.\n" + +#~ msgid "g" +#~ msgstr "g" + +#~ msgid "t" +#~ msgstr "t" + +#~ msgid "`%s' failed, other side closed connection.\n" +#~ msgstr "'%s' falló, conexión cerrada en el otro lado.\n" + +#~ msgid "Attempted path to `%s' was `%s'.\n" +#~ msgstr "La ruta esperada a '%s' fue '%s'.\n" diff --git a/po/gnunet.pot b/po/gnunet.pot new file mode 100644 index 0000000..9dcff6a --- /dev/null +++ b/po/gnunet.pot @@ -0,0 +1,5480 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Christian Grothoff +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" +"POT-Creation-Date: 2012-02-28 18:30+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/arm/arm_api.c:187 +msgid "Failed to transmit shutdown request to client.\n" +msgstr "" + +#: src/arm/arm_api.c:378 +#, c-format +msgid "Configuration failes to specify option `%s' in section `%s'!\n" +msgstr "" + +#: src/arm/arm_api.c:392 +#, c-format +msgid "Configuration fails to specify option `%s' in section `%s'!\n" +msgstr "" + +#: src/arm/arm_api.c:467 +#, c-format +msgid "Error receiving response to `%s' request from ARM for service `%s'\n" +msgstr "" + +#: src/arm/arm_api.c:523 +#, c-format +msgid "Requesting start of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:524 +#, c-format +msgid "Requesting termination of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:546 +#, c-format +msgid "Error while trying to transmit request to start `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:548 +#, c-format +msgid "Error while trying to transmit request to stop `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:581 +#, c-format +msgid "Asked to start service `%s' within %llu ms\n" +msgstr "" + +#: src/arm/arm_api.c:654 +#, c-format +msgid "Stopping service `%s' within %llu ms\n" +msgstr "" + +#: src/arm/gnunet-arm.c:149 +#, c-format +msgid "Service `%s' is unknown to ARM.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:154 +#, c-format +msgid "Service `%s' has been stopped.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:157 +#, c-format +msgid "Service `%s' was already running.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:162 +#, c-format +msgid "Service `%s' has been started.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:165 +#, c-format +msgid "Service `%s' was already being stopped.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:169 +#, c-format +msgid "Service `%s' was already not running.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:173 +msgid "Request ignored as ARM is shutting down.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:177 +msgid "Error communicating with ARM service.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:181 +msgid "Timeout communicating with ARM service.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:185 +msgid "Operation failed.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:189 +msgid "Unknown response code from ARM.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:216 +#, c-format +msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:224 src/arm/gnunet-arm.c:324 +msgid "Fatal error initializing ARM API.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:247 +#, c-format +msgid "Failed to remove configuration file %s\n" +msgstr "" + +#: src/arm/gnunet-arm.c:253 +#, c-format +msgid "Failed to remove servicehome directory %s\n" +msgstr "" + +#: src/arm/gnunet-arm.c:355 +msgid "stop all GNUnet services" +msgstr "" + +#: src/arm/gnunet-arm.c:357 +msgid "start a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:359 +msgid "stop a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:361 +msgid "start all GNUnet default services" +msgstr "" + +#: src/arm/gnunet-arm.c:364 +msgid "stop and start all GNUnet default services" +msgstr "" + +#: src/arm/gnunet-arm.c:367 +msgid "delete config file and directory on exit" +msgstr "" + +#: src/arm/gnunet-arm.c:369 +msgid "don't print status messages" +msgstr "" + +#: src/arm/gnunet-arm.c:372 +msgid "timeout for completing current operation" +msgstr "" + +#: src/arm/gnunet-arm.c:383 +msgid "Control services and the Automated Restart Manager (ARM)" +msgstr "" + +#: src/arm/gnunet-service-arm.c:328 +#, c-format +msgid "Failed to start service `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:331 +#, c-format +msgid "Starting service `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:357 +msgid "Could not send status result to client\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:484 +#, c-format +msgid "Unable to create socket for service `%s': %s\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:506 +#, c-format +msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:520 +#, c-format +msgid "ARM now monitors connections to service `%s' at `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:628 +#, c-format +msgid "Preparing to stop `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:782 +#, c-format +msgid "Restarting service `%s'.\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:877 +msgid "exit" +msgstr "" + +#: src/arm/gnunet-service-arm.c:882 +msgid "signal" +msgstr "" + +#: src/arm/gnunet-service-arm.c:887 +msgid "unknown" +msgstr "" + +#: src/arm/gnunet-service-arm.c:921 +#, c-format +msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:967 src/arm/mockup-service.c:41 +msgid "Failed to transmit shutdown ACK.\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1067 +#, c-format +msgid "Configuration file `%s' for service `%s' not valid: %s\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1069 +msgid "option missing" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1152 +#, c-format +msgid "Starting default services `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1163 +#, c-format +msgid "Default service `%s' not configured correctly!\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1177 +msgid "" +"No default services configured, GNUnet will not really start right now.\n" +msgstr "" + +#: src/arm/mockup-service.c:46 +msgid "Transmitting shutdown ACK.\n" +msgstr "" + +#: src/arm/mockup-service.c:69 +msgid "Initiating shutdown as requested by client.\n" +msgstr "" + +#: src/block/block.c:105 +#, c-format +msgid "Loading block plugin `%s'\n" +msgstr "" + +#: src/chat/chat.c:175 +msgid "Could not transmit confirmation receipt\n" +msgstr "" + +#: src/chat/chat.c:283 +msgid "The current user must be the the first one joined\n" +msgstr "" + +#: src/chat/chat.c:412 +#, c-format +msgid "Unknown message type: '%u'\n" +msgstr "" + +#: src/chat/chat.c:472 +#, c-format +msgid "Configuration option `%s' in section `%s' missing\n" +msgstr "" + +#: src/chat/chat.c:480 +#, c-format +msgid "Failed to access chat home directory `%s'\n" +msgstr "" + +#: src/chat/chat.c:498 +#, c-format +msgid "Failed to create/open key in file `%s'\n" +msgstr "" + +#: src/chat/chat.c:559 +msgid "Could not serialize metadata\n" +msgstr "" + +#: src/chat/chat.c:674 +msgid "Failed to connect to the chat service\n" +msgstr "" + +#: src/chat/chat.c:680 +msgid "Undefined mandatory parameter: joinCallback\n" +msgstr "" + +#: src/chat/chat.c:686 +msgid "Undefined mandatory parameter: messageCallback\n" +msgstr "" + +#: src/chat/chat.c:692 +msgid "Undefined mandatory parameter: memberCallback\n" +msgstr "" + +#: src/chat/gnunet-chat.c:92 +msgid "Joined\n" +msgstr "" + +#: src/chat/gnunet-chat.c:124 +msgid "anonymous" +msgstr "" + +#: src/chat/gnunet-chat.c:130 +#, c-format +msgid "(%s) `%s' said: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:133 src/chat/gnunet-chat.c:136 +#, c-format +msgid "(%s) `%s' said to you: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:139 +#, c-format +msgid "(%s) `%s' said for sure: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:142 +#, c-format +msgid "(%s) `%s' said to you for sure: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:145 +#, c-format +msgid "(%s) `%s' was confirmed that you received: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:148 +#, c-format +msgid "(%s) `%s' was confirmed that you and only you received: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:151 +#, c-format +msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:156 +#, c-format +msgid "" +"(%s) `%s' was confirmed that you and only you received from him or her: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:159 +#, c-format +msgid "(%s) `%s' said off the record: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:162 +#, c-format +msgid "(%s) <%s> said using an unknown message type: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:193 +#, c-format +msgid "'%s' acknowledged message #%d\n" +msgstr "" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' entered the room\n" +msgstr "" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' left the room\n" +msgstr "" + +#: src/chat/gnunet-chat.c:284 src/chat/gnunet-chat.c:316 +msgid "Could not change username\n" +msgstr "" + +#: src/chat/gnunet-chat.c:288 src/chat/gnunet-chat.c:630 +#, c-format +msgid "Joining room `%s' as user `%s'...\n" +msgstr "" + +#: src/chat/gnunet-chat.c:320 +#, c-format +msgid "Changed username to `%s'\n" +msgstr "" + +#: src/chat/gnunet-chat.c:333 +#, c-format +msgid "Users in room `%s': " +msgstr "" + +#: src/chat/gnunet-chat.c:371 +msgid "Syntax: /msg USERNAME MESSAGE" +msgstr "" + +#: src/chat/gnunet-chat.c:379 +#, c-format +msgid "Unknown user `%s'\n" +msgstr "" + +#: src/chat/gnunet-chat.c:395 +#, c-format +msgid "User `%s' is currently not in the room!\n" +msgstr "" + +#: src/chat/gnunet-chat.c:448 +#, c-format +msgid "Unknown command `%s'\n" +msgstr "" + +#: src/chat/gnunet-chat.c:459 +msgid "" +"Use `/join #roomname' to join a chat room. Joining a room will cause you to " +"leave the current room" +msgstr "" + +#: src/chat/gnunet-chat.c:463 +msgid "" +"Use `/nick nickname' to change your nickname. This will cause you to leave " +"the current room and immediately rejoin it with the new name." +msgstr "" + +#: src/chat/gnunet-chat.c:467 +msgid "" +"Use `/msg nickname message' to send a private message to the specified user" +msgstr "" + +#: src/chat/gnunet-chat.c:470 +msgid "The `/notice' command is an alias for `/msg'" +msgstr "" + +#: src/chat/gnunet-chat.c:472 +msgid "The `/query' command is an alias for `/msg'" +msgstr "" + +#: src/chat/gnunet-chat.c:474 +msgid "Use `/sig message' to send a signed public message" +msgstr "" + +#: src/chat/gnunet-chat.c:477 +msgid "Use `/ack message' to require signed acknowledgment of the message" +msgstr "" + +#: src/chat/gnunet-chat.c:480 +msgid "Use `/anonymous message' to send a public anonymous message" +msgstr "" + +#: src/chat/gnunet-chat.c:482 +msgid "The `/anon' command is an alias for `/anonymous'" +msgstr "" + +#: src/chat/gnunet-chat.c:484 +msgid "Use `/quit' to terminate gnunet-chat" +msgstr "" + +#: src/chat/gnunet-chat.c:486 +msgid "The `/leave' command is an alias for `/quit'" +msgstr "" + +#: src/chat/gnunet-chat.c:489 +msgid "Use `/names' to list all of the current members in the chat room" +msgstr "" + +#: src/chat/gnunet-chat.c:491 +msgid "Use `/help command' to get help for a specific command" +msgstr "" + +#: src/chat/gnunet-chat.c:606 +msgid "You must specify a nickname\n" +msgstr "" + +#: src/chat/gnunet-chat.c:622 +#, c-format +msgid "Failed to join room `%s'\n" +msgstr "" + +#: src/chat/gnunet-chat.c:655 +msgid "set the nickname to use (required)" +msgstr "" + +#: src/chat/gnunet-chat.c:658 +msgid "set the chat room to join" +msgstr "" + +#: src/chat/gnunet-chat.c:670 +msgid "Join a chat on GNUnet." +msgstr "" + +#: src/chat/gnunet-service-chat.c:267 +msgid "Failed to queue a message notification\n" +msgstr "" + +#: src/chat/gnunet-service-chat.c:546 +msgid "Failed to queue a join notification\n" +msgstr "" + +#: src/chat/gnunet-service-chat.c:729 +msgid "Failed to queue a confirmation receipt\n" +msgstr "" + +#: src/chat/gnunet-service-chat.c:907 +msgid "Failed to queue a leave notification\n" +msgstr "" + +#: src/core/core_api.c:798 +msgid "Client was disconnected from core service, trying to reconnect.\n" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:77 +#: src/peerinfo-tool/gnunet-peerinfo.c:60 +#, c-format +msgid "Peer `%s'\n" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:175 +#: src/peerinfo-tool/gnunet-peerinfo.c:194 +#, c-format +msgid "Invalid command line argument `%s'\n" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:196 +#: src/peerinfo-tool/gnunet-peerinfo.c:252 +msgid "don't resolve host names" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:203 +msgid "Print information about connected peers." +msgstr "" + +#: src/core/gnunet-service-core.c:99 +#, c-format +msgid "Core service of `%4s' ready.\n" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:360 +msgid "# send requests dropped (disconnected)" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:465 +msgid "# messages discarded (session disconnected)" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:801 +#, c-format +msgid "# bytes of messages of type %u received" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:493 +msgid "# bytes encrypted" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:543 +msgid "# bytes decrypted" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:604 src/dv/gnunet-service-dv.c:3002 +#: src/hostlist/hostlist-server.c:436 src/peerinfo-tool/gnunet-peerinfo.c:151 +msgid "Error in communication with PEERINFO service\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:623 +msgid "# Delayed connecting due to lack of public key" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:673 +msgid "# key exchanges initiated" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:694 +msgid "# key exchanges stopped" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:746 +msgid "# session keys received" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:765 +#, c-format +msgid "`%s' is for `%s', not for me. Ignoring.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:803 +msgid "# SET_KEY messages decrypted" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:883 +#: src/transport/gnunet-service-transport_validation.c:803 +msgid "# PING messages received" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:917 +#, c-format +msgid "" +"Received PING from `%s' for different identity: I am `%s', PONG identity: `" +"%s'\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:938 +msgid "# PONG messages created" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1026 +msgid "# sessions terminated by timeout" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1037 +msgid "# keepalive messages sent" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1095 +#: src/transport/gnunet-service-transport_validation.c:1026 +msgid "# PONG messages received" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1125 +msgid "# PONG messages decrypted" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1157 +msgid "# session keys confirmed via PONG" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1223 +msgid "# SET_KEY and PING messages created" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1364 +msgid "# failed to decrypt message (no session key)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1406 +#: src/core/gnunet-service-core_kx.c:1431 +msgid "# bytes dropped (duplicates)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1418 +msgid "# bytes dropped (out of sequence)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1455 +#, c-format +msgid "Message received far too old (%llu ms). Content ignored.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1459 +msgid "# bytes dropped (ancient message)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1467 +msgid "# bytes of payload decrypted" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1528 +msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1536 +msgid "Core service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1546 src/hostlist/hostlist-server.c:555 +#: src/peerinfo-tool/gnunet-peerinfo.c:202 +#: src/transport/gnunet-service-transport.c:595 +msgid "Could not access PEERINFO service. Exiting.\n" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:163 +msgid "# sessions terminated by transport disconnect" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:180 +#: src/core/gnunet-service-core_neighbours.c:342 +msgid "# neighbour entries allocated" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:251 +msgid "# encrypted bytes given to transport" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:430 +#, c-format +msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:208 +#: src/core/gnunet-service-core_sessions.c:273 +msgid "# entries in session map" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:238 +msgid "# type map refreshes sent" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:414 +msgid "# messages discarded (expired prior to transmission)" +msgstr "" + +#: src/core/gnunet-service-core_typemap.c:110 +#: src/core/gnunet-service-core_typemap.c:121 +msgid "# type maps received" +msgstr "" + +#: src/core/gnunet-service-core_typemap.c:151 +msgid "# updates to my type map" +msgstr "" + +#: src/datacache/datacache.c:118 src/datacache/datacache.c:255 +#: src/datastore/gnunet-service-datastore.c:854 +msgid "# bytes stored" +msgstr "" + +#: src/datacache/datacache.c:144 src/datacache/datacache.c:151 +#: src/datastore/gnunet-service-datastore.c:1531 +#: src/datastore/gnunet-service-datastore.c:1542 +#, c-format +msgid "No `%s' specified for `%s' in configuration!\n" +msgstr "" + +#: src/datacache/datacache.c:183 +#, c-format +msgid "Loading `%s' datacache plugin\n" +msgstr "" + +#: src/datacache/datacache.c:191 +#, c-format +msgid "Failed to load datacache plugin for `%s'\n" +msgstr "" + +#: src/datacache/datacache.c:281 +msgid "# requests received" +msgstr "" + +#: src/datacache/datacache.c:291 +msgid "# requests filtered by bloom filter" +msgstr "" + +#: src/datacache/plugin_datacache_mysql.c:103 +#: src/datacache/plugin_datacache_mysql.c:110 +#: src/datacache/plugin_datacache_mysql.c:517 +#: src/datacache/plugin_datacache_mysql.c:526 +#: src/datacache/plugin_datacache_mysql.c:598 +#: src/datacache/plugin_datacache_mysql.c:614 +#: src/datacache/plugin_datacache_sqlite.c:71 +#: src/datacache/plugin_datacache_sqlite.c:74 +#: src/datastore/plugin_datastore_mysql.c:139 +#: src/datastore/plugin_datastore_mysql.c:146 +#: src/datastore/plugin_datastore_mysql.c:613 +#: src/datastore/plugin_datastore_mysql.c:673 +#: src/datastore/plugin_datastore_mysql.c:685 +#: src/datastore/plugin_datastore_mysql.c:1362 +#: src/datastore/plugin_datastore_mysql.c:1376 +#: src/datastore/plugin_datastore_sqlite.c:61 +#: src/namestore/plugin_namestore_sqlite.c:49 src/util/crypto_ksk.c:49 +#: src/util/crypto_rsa.c:92 src/include/gnunet_common.h:507 +#: src/include/gnunet_common.h:514 +#, c-format +msgid "`%s' failed at %s:%d with error: %s\n" +msgstr "" + +#: src/datacache/plugin_datacache_mysql.c:224 +#: src/datastore/plugin_datastore_mysql.c:316 +#, c-format +msgid "Trying to use file `%s' for MySQL configuration.\n" +msgstr "" + +#: src/datacache/plugin_datacache_mysql.c:230 +#: src/datastore/plugin_datastore_mysql.c:322 +#, c-format +msgid "Could not access file `%s': %s\n" +msgstr "" + +#: src/datacache/plugin_datacache_mysql.c:979 +msgid "MySQL datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_postgres.c:79 +#: src/datastore/plugin_datastore_postgres.c:93 +#, c-format +msgid "`%s:%s' failed at %s:%d with error: %s" +msgstr "" + +#: src/datacache/plugin_datacache_postgres.c:149 +#, c-format +msgid "Unable to initialize Postgres: %s" +msgstr "" + +#: src/datacache/plugin_datacache_postgres.c:499 +msgid "Postgres datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:424 +msgid "Sqlite datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:457 +#: src/datastore/plugin_datastore_sqlite.c:414 +#: src/namestore/plugin_namestore_sqlite.c:381 +msgid "Tried to close sqlite without finalizing all prepared statements.\n" +msgstr "" + +#: src/datacache/plugin_datacache_template.c:121 +msgid "Template datacache running\n" +msgstr "" + +#: src/datastore/datastore_api.c:289 +msgid "Failed to transmit request to drop database.\n" +msgstr "" + +#: src/datastore/datastore_api.c:372 +msgid "# queue entry timeouts" +msgstr "" + +#: src/datastore/datastore_api.c:418 +msgid "# queue overflows" +msgstr "" + +#: src/datastore/datastore_api.c:445 +msgid "# queue entries created" +msgstr "" + +#: src/datastore/datastore_api.c:465 +msgid "# Requests dropped from datastore queue" +msgstr "" + +#: src/datastore/datastore_api.c:513 +msgid "# datastore connections (re)created" +msgstr "" + +#: src/datastore/datastore_api.c:540 +msgid "# reconnected to DATASTORE" +msgstr "" + +#: src/datastore/datastore_api.c:608 +msgid "# transmission request failures" +msgstr "" + +#: src/datastore/datastore_api.c:631 +msgid "# bytes sent to datastore" +msgstr "" + +#: src/datastore/datastore_api.c:772 +msgid "Failed to receive status response from database." +msgstr "" + +#: src/datastore/datastore_api.c:786 +msgid "Error reading response from datastore service" +msgstr "" + +#: src/datastore/datastore_api.c:798 src/datastore/datastore_api.c:804 +msgid "Invalid error message received from datastore service" +msgstr "" + +#: src/datastore/datastore_api.c:810 +msgid "# status messages received" +msgstr "" + +#: src/datastore/datastore_api.c:883 +msgid "# PUT requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:954 +msgid "# RESERVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1019 +msgid "# RELEASE RESERVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1080 +msgid "# UPDATE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1148 +msgid "# REMOVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1193 +msgid "Failed to receive response from database.\n" +msgstr "" + +#: src/datastore/datastore_api.c:1253 +msgid "# Results received" +msgstr "" + +#: src/datastore/datastore_api.c:1324 +msgid "# GET REPLICATION requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1391 +msgid "# GET ZERO ANONYMITY requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1455 +msgid "# GET requests executed" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:351 +msgid "# bytes expired" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:426 +msgid "# bytes purged (low-priority)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:486 +msgid "Transmission to client failed!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:640 +msgid "# results found" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:685 +#, c-format +msgid "" +"Insufficient space (%llu bytes are available) to satisfy `%s' request for " +"%llu bytes\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:696 +#, c-format +msgid "" +"The requested amount (%llu bytes) is larger than the cache size (%llu " +"bytes)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:700 +msgid "" +"Insufficient space to satisfy request and requested amount is larger than " +"cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:706 +msgid "Insufficient space to satisfy request" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:711 +#: src/datastore/gnunet-service-datastore.c:765 +#: src/datastore/gnunet-service-datastore.c:986 +#: src/datastore/gnunet-service-datastore.c:1465 +msgid "# reserved" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:780 +msgid "Could not find matching reservation" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:868 +#, c-format +msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1034 +msgid "# GET requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1048 +msgid "# requests filtered by bloomfilter" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1076 +msgid "# UPDATE requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1110 +msgid "# GET REPLICATION requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1145 +msgid "# GET ZERO ANONYMITY requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1172 +msgid "Content not found" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1182 +msgid "# bytes removed (explicit request)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1216 +msgid "# REMOVE requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1260 +#, c-format +msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1323 +#, c-format +msgid "Loading `%s' datastore plugin\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1332 +#, c-format +msgid "Failed to load datastore plugin for `%s'\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1536 +#, c-format +msgid "# bytes used in file-sharing datastore `%s'" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1547 +msgid "# quota" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1549 +msgid "# cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1562 +#, c-format +msgid "Could not use specified filename `%s' for bloomfilter.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1580 +#: src/datastore/gnunet-service-datastore.c:1596 +#, c-format +msgid "Failed to remove bogus bloomfilter file `%s'\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1626 +msgid "Failed to initialize bloomfilter.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1655 +msgid "Rebuilding bloomfilter. Please be patient.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1660 +msgid "Plugin does not support get_keys function. Please fix!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1663 +msgid "Bloomfilter construction complete.\n" +msgstr "" + +#: src/datastore/plugin_datastore_mysql.c:529 +#: src/datastore/plugin_datastore_mysql.c:1336 +#, c-format +msgid "Failed to prepare statement `%s'\n" +msgstr "" + +#: src/datastore/plugin_datastore_mysql.c:622 +#: src/datastore/plugin_datastore_mysql.c:1346 +#, c-format +msgid "`%s' for `%s' failed at %s:%d with error: %s\n" +msgstr "" + +#: src/datastore/plugin_datastore_mysql.c:1581 +msgid "Mysql database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_postgres.c:173 +#, c-format +msgid "Unable to initialize Postgres with configuration `%s': %s" +msgstr "" + +#: src/datastore/plugin_datastore_postgres.c:1017 +msgid "Postgres database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:61 +#, c-format +msgid "`%s' failed at %s:%u with error: %s" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:239 +#: src/namestore/plugin_namestore_sqlite.c:223 +#, c-format +msgid "Option `%s' in section `%s' missing in configuration!\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:266 +#: src/namestore/plugin_namestore_sqlite.c:248 +#, c-format +msgid "Unable to initialize SQLite: %s.\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:669 +msgid "Invalid data in database. Trying to fix (by deletion).\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1159 +msgid "sqlite version to old to determine size, assuming zero\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1178 +#, c-format +msgid "" +"Using sqlite page utilization to estimate payload (%llu pages of size %llu " +"bytes)\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1218 +#: src/namestore/plugin_namestore_sqlite.c:779 +msgid "Sqlite database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_template.c:241 +msgid "Template database running\n" +msgstr "" + +#: src/dht/dht_api.c:280 +msgid "Failed to connect to the DHT service!\n" +msgstr "" + +#: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-put.c:172 +#: src/gns/gnunet-gns-lookup.c:179 +msgid "the query key" +msgstr "" + +#: src/dht/gnunet-dht-get.c:204 src/gns/gnunet-gns-lookup.c:182 +msgid "how many parallel requests (replicas) to create" +msgstr "" + +#: src/dht/gnunet-dht-get.c:207 src/gns/gnunet-gns-lookup.c:185 +msgid "the type of data to look for" +msgstr "" + +#: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:181 +#: src/gns/gnunet-gns-lookup.c:188 +msgid "how long to execute this query before giving up?" +msgstr "" + +#: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-put.c:184 +#: src/fs/gnunet-download.c:270 src/fs/gnunet-publish.c:725 +#: src/fs/gnunet-search.c:297 src/fs/gnunet-unindex.c:169 +#: src/gns/gnunet-gns-lookup.c:191 src/nse/gnunet-nse-profiler.c:908 +msgid "be verbose (print progress information)" +msgstr "" + +#: src/dht/gnunet-dht-get.c:232 +msgid "Issue a GET request to the GNUnet DHT, prints results." +msgstr "" + +#: src/dht/gnunet-dht-put.c:100 +msgid "PUT request sent!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:124 +msgid "Must provide KEY and DATA for DHT put!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:132 +#, c-format +msgid "Could not connect to %s service!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:137 +#, c-format +msgid "Connected to %s service!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:152 +#, c-format +msgid "Issuing put request for `%s' with data `%s'!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:166 +msgid "the data to insert under the key" +msgstr "" + +#: src/dht/gnunet-dht-put.c:169 +msgid "how long to store this entry in the dht (in seconds)" +msgstr "" + +#: src/dht/gnunet-dht-put.c:175 +msgid "how many replicas to create" +msgstr "" + +#: src/dht/gnunet-dht-put.c:178 +msgid "the type to insert data as" +msgstr "" + +#: src/dht/gnunet-dht-put.c:203 +msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." +msgstr "" + +#: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:556 +#: src/testing/testing.c:1979 src/testing/testing.c:2009 +msgid "Failed to connect to transport service!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:371 +msgid "# GET requests from clients injected" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:462 +msgid "# PUT requests received from clients" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:529 +msgid "# GET requests received from clients" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:624 +msgid "# GET STOP requests received from clients" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:854 +msgid "# Key match, type mismatches in REPLY to CLIENT" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:869 +msgid "# Duplicate REPLIES to CLIENT request dropped" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:906 +#, c-format +msgid "Unsupported block type (%u) in request!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:928 +msgid "# RESULTS queued for clients" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:979 +#: src/dht/gnunet-service-dht_clients.c:1022 +msgid "# REPLIES ignored for CLIENTS (no match)" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:989 +msgid "Could not pass reply to client, message too big!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:93 +#, c-format +msgid "%s request received, but have no datacache!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:103 +msgid "# ITEMS stored in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:209 +msgid "# Good RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:220 +msgid "# Duplicate RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:226 +msgid "# Invalid RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:238 +msgid "# Unsupported RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:241 +#, c-format +msgid "Unsupported block type (%u) in local response!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:271 +msgid "# GET requests given to datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_hello.c:82 +msgid "# HELLOs obtained from peerinfo" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:481 +msgid "# Preference updates given to core" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:573 +msgid "# FIND PEER messages initiated" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:629 +#: src/dht/gnunet-service-dht_neighbours.c:689 +msgid "# Peers connected" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:723 +msgid "# Queued messages discarded (peer disconnected)" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:778 +msgid "# Bytes transmitted to other peers" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:816 +msgid "# Bytes of bandwdith requested from core" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1040 +#: src/dht/gnunet-service-dht_neighbours.c:1068 +msgid "# Peers excluded from routing due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1049 +#: src/dht/gnunet-service-dht_neighbours.c:1085 +msgid "# Peer selection failed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1221 +msgid "# PUT requests routed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1252 +msgid "# PUT messages queued for transmission" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1333 +msgid "# GET requests routed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1364 +msgid "# GET messages queued for transmission" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1467 +msgid "# RESULT messages queued for transmission" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1555 +msgid "# P2P PUT requests received" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1668 +msgid "# FIND PEER requests ignored due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1676 +msgid "# FIND PEER requests ignored due to lack of HELLO" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1767 +msgid "# P2P GET requests received" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1811 +msgid "# P2P FIND PEER requests processed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1825 +msgid "# P2P GET requests ONLY routed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1895 +msgid "# P2P RESULTS received" +msgstr "" + +#: src/dht/gnunet-service-dht_nse.c:59 +msgid "# Network size estimates received" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:211 +msgid "# Good REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:220 +msgid "# Duplicate REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:226 +msgid "# Invalid REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:236 +msgid "# Unsupported REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:314 +#: src/dht/gnunet-service-dht_routing.c:368 +msgid "# Entries removed from routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:324 +msgid "# Entries added to routing table" +msgstr "" + +#: src/dht/plugin_block_dht.c:124 +#, c-format +msgid "Block not of type %u\n" +msgstr "" + +#: src/dht/plugin_block_dht.c:131 +msgid "Size mismatch for block\n" +msgstr "" + +#: src/dht/plugin_block_dht.c:140 +#, c-format +msgid "Block of type %u is malformed\n" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:337 +msgid "only monitor DNS queries" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:340 +msgid "only monitor DNS replies" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:348 +msgid "Monitor DNS queries." +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:236 +msgid "set A records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:239 +msgid "set AAAA records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:247 +msgid "Change DNS replies to point elsewhere." +msgstr "" + +#: src/dns/gnunet-service-dns.c:480 +#, c-format +msgid "Could not bind to any port: %s\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:634 +msgid "# DNS requests answered via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:818 +msgid "# DNS exit failed (failed to open socket)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1001 +#, c-format +msgid "Received DNS response that is too small (%u bytes)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1046 +msgid "# External DNS response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1165 +msgid "# Client response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1198 +msgid "Changing DNS reply according to client specifications\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1279 +msgid "Received malformed IPv4-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1294 +msgid "Received malformed IPv6-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1303 +#, c-format +msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1312 +msgid "# Non-DNS UDP packet received via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1377 +msgid "# DNS requests received via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1461 +#, c-format +msgid "Configured DNS exit `%s' is not working / valid.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1493 src/exit/gnunet-daemon-exit.c:2673 +msgid "# Inbound MESH tunnels created" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1567 +msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" +msgstr "" + +#: src/dv/dv_api.c:179 +msgid "Failed to connect to the dv service!\n" +msgstr "" + +#: src/dv/plugin_transport_dv.c:159 +#, c-format +msgid "%s Received message from %s of type %d, distance %u!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:508 +#, c-format +msgid "Got duplicate service records for `%s:%u'\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:563 +msgid "# Bytes transmitted via mesh tunnels" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2068 +#: src/exit/gnunet-daemon-exit.c:2318 src/vpn/gnunet-service-vpn.c:1388 +#: src/vpn/gnunet-service-vpn.c:1788 src/vpn/gnunet-service-vpn.c:1951 +msgid "# ICMPv4 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2127 +#: src/exit/gnunet-daemon-exit.c:2377 src/vpn/gnunet-service-vpn.c:1444 +#: src/vpn/gnunet-service-vpn.c:1847 src/vpn/gnunet-service-vpn.c:1984 +msgid "# ICMPv6 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:756 +msgid "# ICMP packets dropped (not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:763 +msgid "ICMP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:840 +msgid "UDP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:915 +msgid "TCP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:968 +msgid "# Packets received from TUN" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:982 +msgid "# Bytes received from TUN" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1008 +msgid "IPv4 packet options received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1035 +#, c-format +msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1081 +#, c-format +msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1089 +#, c-format +msgid "Packet from unknown protocol %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1470 +msgid "# TCP packets sent via TUN" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1570 +msgid "# TCP service creation requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1573 src/exit/gnunet-daemon-exit.c:1652 +#: src/exit/gnunet-daemon-exit.c:1762 src/exit/gnunet-daemon-exit.c:1992 +#: src/exit/gnunet-daemon-exit.c:2234 src/exit/gnunet-daemon-exit.c:2515 +#: src/exit/gnunet-daemon-exit.c:2615 +msgid "# Bytes received from MESH" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1606 src/exit/gnunet-daemon-exit.c:2637 +#, c-format +msgid "No service found for %s on port %d!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1610 +msgid "# TCP requests dropped (no such service)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1655 +msgid "# TCP IP-exit creation requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1765 +msgid "# TCP data requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1779 +msgid "# TCP DATA requests dropped (no session)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1829 +msgid "# ICMP packets sent via TUN" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1995 +msgid "# ICMP IP-exit requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2237 +msgid "# ICMP service requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2303 src/vpn/gnunet-service-vpn.c:1378 +#: src/vpn/gnunet-service-vpn.c:1945 +msgid "# ICMPv4 packets dropped (impossible PT to v6)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2362 src/vpn/gnunet-service-vpn.c:1414 +#: src/vpn/gnunet-service-vpn.c:1426 src/vpn/gnunet-service-vpn.c:1835 +msgid "# ICMPv6 packets dropped (impossible PT to v4)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2412 +msgid "# UDP packets sent via TUN" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2518 +msgid "# UDP IP-exit requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2618 +msgid "# UDP service requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2641 +msgid "# UDP requests dropped (no such service)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2881 +#, c-format +msgid "No addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2895 src/exit/gnunet-daemon-exit.c:2907 +#, c-format +msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2918 +#, c-format +msgid "No IP addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3047 +msgid "" +"This system does not support IPv4, will disable IPv4 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3055 +msgid "" +"This system does not support IPv6, will disable IPv6 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3062 +msgid "" +"Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " +"ENABLE_IPv4=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3068 +msgid "" +"Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " +"ENABLE_IPv6=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3074 src/pt/gnunet-daemon-pt.c:884 +msgid "No useful service enabled. Exiting.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3235 +msgid "Daemon to run to provide an IP exit node for the VPN" +msgstr "" + +#: src/fragmentation/defragmentation.c:270 +msgid "# acknowledgements sent for fragment" +msgstr "" + +#: src/fragmentation/defragmentation.c:454 +msgid "# fragments received" +msgstr "" + +#: src/fragmentation/defragmentation.c:513 +msgid "# duplicate fragments received" +msgstr "" + +#: src/fragmentation/defragmentation.c:526 +msgid "# messages defragmented" +msgstr "" + +#: src/fragmentation/fragmentation.c:188 +msgid "# fragments transmitted" +msgstr "" + +#: src/fragmentation/fragmentation.c:191 +msgid "# fragments retransmitted" +msgstr "" + +#: src/fragmentation/fragmentation.c:255 +msgid "# messages fragmented" +msgstr "" + +#: src/fragmentation/fragmentation.c:258 +msgid "# total size of fragmented messages" +msgstr "" + +#: src/fragmentation/fragmentation.c:343 +msgid "# fragment acknowledgements received" +msgstr "" + +#: src/fragmentation/fragmentation.c:349 +msgid "# bits removed from fragmentation ACKs" +msgstr "" + +#: src/fragmentation/fragmentation.c:373 +msgid "# fragmentation transmissions completed" +msgstr "" + +#: src/fs/fs_api.c:284 +#, c-format +msgid "Could not open file `%s': %s" +msgstr "" + +#: src/fs/fs_api.c:293 +#, c-format +msgid "Could not read file `%s': %s" +msgstr "" + +#: src/fs/fs_api.c:299 +#, c-format +msgid "Short read reading from file `%s'!" +msgstr "" + +#: src/fs/fs_api.c:877 +#, c-format +msgid "Failed to resume publishing information `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:1334 +#, c-format +msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" +msgstr "" + +#: src/fs/fs_api.c:1376 +#, c-format +msgid "Failure while resuming publishing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:1392 +#, c-format +msgid "Failed to resume publishing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2004 +#, c-format +msgid "Failure while resuming unindexing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2014 +#, c-format +msgid "Failed to resume unindexing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2139 src/fs/fs_api.c:2378 +#, c-format +msgid "Failed to resume sub-download `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2156 +#, c-format +msgid "Failed to resume sub-search `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2168 src/fs/fs_api.c:2187 src/fs/fs_api.c:2671 +#, c-format +msgid "Failure while resuming search operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2369 +#, c-format +msgid "Failed to resume sub-download `%s': could not open file `%s'\n" +msgstr "" + +#: src/fs/fs_api.c:2615 +msgid "Could not resume running search, will resume as paused search\n" +msgstr "" + +#: src/fs/fs_api.c:2709 +#, c-format +msgid "Failure while resuming download operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_directory.c:210 +msgid "MAGIC mismatch. This is not a GNUnet directory.\n" +msgstr "" + +#: src/fs/fs_download.c:310 +msgid "" +"Recursive downloads of directories larger than 4 GB are not supported on 32-" +"bit systems\n" +msgstr "" + +#: src/fs/fs_download.c:330 +msgid "Directory too large for system address space\n" +msgstr "" + +#: src/fs/fs_download.c:488 src/fs/fs_download.c:500 +#, c-format +msgid "Failed to open file `%s' for writing" +msgstr "" + +#: src/fs/fs_download.c:870 +#, c-format +msgid "Failed to create directory for recursive download of `%s'\n" +msgstr "" + +#: src/fs/fs_download.c:951 +#, c-format +msgid "" +"Internal error or bogus download URI (expected %u bytes at depth %u and " +"offset %llu/%llu, got %u bytes)\n" +msgstr "" + +#: src/fs/fs_download.c:977 +msgid "internal error decrypting content" +msgstr "" + +#: src/fs/fs_download.c:1000 +#, c-format +msgid "Download failed: could not open file `%s': %s\n" +msgstr "" + +#: src/fs/fs_download.c:1010 +#, c-format +msgid "Failed to seek to offset %llu in file `%s': %s\n" +msgstr "" + +#: src/fs/fs_download.c:1019 +#, c-format +msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s\n" +msgstr "" + +#: src/fs/fs_download.c:1835 +msgid "Invalid URI" +msgstr "" + +#: src/fs/fs_getopt.c:191 +#, c-format +msgid "" +"Unknown metadata type in metadata option `%s'. Using metadata type " +"`unknown' instead.\n" +msgstr "" + +#: src/fs/fs_list_indexed.c:90 +#, c-format +msgid "Failed to receive response for `%s' request from `%s' service.\n" +msgstr "" + +#: src/fs/fs_list_indexed.c:113 +#, c-format +msgid "Failed to receive valid response for `%s' request from `%s' service.\n" +msgstr "" + +#: src/fs/fs_list_indexed.c:151 +#, c-format +msgid "Failed to not connect to `%s' service.\n" +msgstr "" + +#: src/fs/fs_misc.c:126 +#, c-format +msgid "Did not find mime type `%s' in extension list.\n" +msgstr "" + +#: src/fs/fs_namespace_advertise.c:150 +msgid "Unknown error" +msgstr "" + +#: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 +msgid "Failed to serialize meta data" +msgstr "" + +#: src/fs/fs_namespace_advertise.c:278 +msgid "Failed to connect to datastore service" +msgstr "" + +#: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 +#, c-format +msgid "Configuration fails to specify `%s' in section `%s'\n" +msgstr "" + +#: src/fs/fs_namespace.c:112 +#, c-format +msgid "Failed to open `%s' for writing: %s\n" +msgstr "" + +#: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 +#, c-format +msgid "Failed to write `%s': %s\n" +msgstr "" + +#: src/fs/fs_namespace.c:256 +#, c-format +msgid "Failed to create or read private key for namespace `%s'\n" +msgstr "" + +#: src/fs/fs_namespace.c:371 +#, c-format +msgid "Failed to read namespace private key file `%s', deleting it!\n" +msgstr "" + +#: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 +msgid "Internal error." +msgstr "" + +#: src/fs/fs_namespace.c:631 +msgid "Failed to connect to datastore." +msgstr "" + +#: src/fs/fs_publish.c:129 src/fs/fs_publish.c:395 +#, c-format +msgid "Publishing failed: %s" +msgstr "" + +#: src/fs/fs_publish.c:616 src/fs/fs_publish.c:633 src/fs/fs_publish.c:672 +#: src/fs/fs_publish.c:692 src/fs/fs_publish.c:717 src/fs/fs_publish.c:857 +#, c-format +msgid "Can not index file `%s': %s. Will try to insert instead.\n" +msgstr "" + +#: src/fs/fs_publish.c:618 +msgid "timeout on index-start request to `fs' service" +msgstr "" + +#: src/fs/fs_publish.c:630 +msgid "unknown error" +msgstr "" + +#: src/fs/fs_publish.c:673 +msgid "failed to compute hash" +msgstr "" + +#: src/fs/fs_publish.c:693 +msgid "filename too long" +msgstr "" + +#: src/fs/fs_publish.c:718 +msgid "could not connect to `fs' service" +msgstr "" + +#: src/fs/fs_publish.c:741 +#, c-format +msgid "Failed to get file identifiers for `%s'\n" +msgstr "" + +#: src/fs/fs_publish.c:806 +#, c-format +msgid "Recursive upload failed at `%s': %s" +msgstr "" + +#: src/fs/fs_publish.c:812 +#, c-format +msgid "Recursive upload failed: %s" +msgstr "" + +#: src/fs/fs_publish.c:858 +msgid "needs to be an actual file" +msgstr "" + +#: src/fs/fs_publish.c:1067 +#, c-format +msgid "Insufficient space for publishing: %s" +msgstr "" + +#: src/fs/fs_publish.c:1138 +#, c-format +msgid "Reserving space for %u entries and %llu bytes for publication\n" +msgstr "" + +#: src/fs/fs_publish_ksk.c:258 +msgid "Could not connect to datastore." +msgstr "" + +#: src/fs/fs_search.c:810 +#, c-format +msgid "Got result with unknown block type `%d', ignoring" +msgstr "" + +#: src/fs/fs_test_lib.c:269 +#, c-format +msgid "Failed to start daemon: %s\n" +msgstr "" + +#: src/fs/fs_unindex.c:57 +msgid "Failed to find given position in file" +msgstr "" + +#: src/fs/fs_unindex.c:62 +msgid "Failed to read file" +msgstr "" + +#: src/fs/fs_unindex.c:231 +msgid "Unexpected time for a response from `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:239 +msgid "Timeout waiting for `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:247 +msgid "Invalid response from `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:292 +msgid "Failed to connect to FS service for unindexing." +msgstr "" + +#: src/fs/fs_unindex.c:325 +msgid "Failed to connect to `datastore' service." +msgstr "" + +#: src/fs/fs_unindex.c:338 +msgid "Failed to open file for unindexing." +msgstr "" + +#: src/fs/fs_unindex.c:372 +msgid "Failed to compute hash of file." +msgstr "" + +#: src/fs/fs_uri.c:220 +#, c-format +msgid "`%' must be followed by HEX number" +msgstr "" + +#: src/fs/fs_uri.c:279 +msgid "Malformed KSK URI (must not begin or end with `+')" +msgstr "" + +#: src/fs/fs_uri.c:297 +msgid "`++' not allowed in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:304 +msgid "Quotes not balanced in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 +msgid "Malformed SKS URI" +msgstr "" + +#: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 +msgid "Malformed CHK URI" +msgstr "" + +#: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 +#: src/fs/fs_uri.c:621 +msgid "SKS URI malformed" +msgstr "" + +#: src/fs/fs_uri.c:603 +msgid "SKS URI malformed (could not decode public key)" +msgstr "" + +#: src/fs/fs_uri.c:609 +msgid "SKS URI malformed (could not find signature)" +msgstr "" + +#: src/fs/fs_uri.c:615 +msgid "SKS URI malformed (could not decode signature)" +msgstr "" + +#: src/fs/fs_uri.c:628 +msgid "SKS URI malformed (could not parse expiration time)" +msgstr "" + +#: src/fs/fs_uri.c:640 +msgid "SKS URI malformed (signature failed validation)" +msgstr "" + +#: src/fs/fs_uri.c:678 +msgid "Unrecognized URI type" +msgstr "" + +#: src/fs/fs_uri.c:903 +msgid "Lacking key configuration settings.\n" +msgstr "" + +#: src/fs/fs_uri.c:910 +#, c-format +msgid "Could not access hostkey file `%s'.\n" +msgstr "" + +#: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 +msgid "No keywords specified!\n" +msgstr "" + +#: src/fs/fs_uri.c:1148 +msgid "Number of double-quotes not balanced!\n" +msgstr "" + +#: src/fs/gnunet-directory.c:49 +#, c-format +msgid "\t\n" +msgstr "" + +#: src/fs/gnunet-directory.c:94 +#, c-format +msgid "Directory `%s' meta data:\n" +msgstr "" + +#: src/fs/gnunet-directory.c:97 +#, c-format +msgid "Directory `%s' contents:\n" +msgstr "" + +#: src/fs/gnunet-directory.c:132 +msgid "You must specify a filename to inspect.\n" +msgstr "" + +#: src/fs/gnunet-directory.c:145 +#, c-format +msgid "Failed to read directory `%s'\n" +msgstr "" + +#: src/fs/gnunet-directory.c:154 +#, c-format +msgid "`%s' is not a GNUnet directory\n" +msgstr "" + +#: src/fs/gnunet-directory.c:179 +msgid "Display contents of a GNUnet directory" +msgstr "" + +#: src/fs/gnunet-download.c:100 +#, c-format +msgid "Starting download `%s'.\n" +msgstr "" + +#: src/fs/gnunet-download.c:109 +msgid "" +msgstr "" + +#: src/fs/gnunet-download.c:118 +#, c-format +msgid "" +"Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " +"download\n" +msgstr "" + +#: src/fs/gnunet-download.c:128 +#, c-format +msgid "Error downloading: %s.\n" +msgstr "" + +#: src/fs/gnunet-download.c:136 +#, c-format +msgid "Downloading `%s' done (%s/s).\n" +msgstr "" + +#: src/fs/gnunet-download.c:151 src/fs/gnunet-publish.c:190 +#: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 +#, c-format +msgid "Unexpected status: %d\n" +msgstr "" + +#: src/fs/gnunet-download.c:176 +msgid "You need to specify a URI argument.\n" +msgstr "" + +#: src/fs/gnunet-download.c:182 src/fs/gnunet-publish.c:618 +#, c-format +msgid "Failed to parse URI: %s\n" +msgstr "" + +#: src/fs/gnunet-download.c:189 +msgid "Only CHK or LOC URIs supported.\n" +msgstr "" + +#: src/fs/gnunet-download.c:196 +msgid "Target filename must be specified.\n" +msgstr "" + +#: src/fs/gnunet-download.c:210 src/fs/gnunet-publish.c:596 +#: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 +#, c-format +msgid "Could not initialize `%s' subsystem.\n" +msgstr "" + +#: src/fs/gnunet-download.c:247 src/fs/gnunet-search.c:285 +msgid "set the desired LEVEL of receiver-anonymity" +msgstr "" + +#: src/fs/gnunet-download.c:250 +msgid "delete incomplete downloads (when aborted with CTRL-C)" +msgstr "" + +#: src/fs/gnunet-download.c:253 src/fs/gnunet-search.c:288 +msgid "only search the local peer (no P2P network search)" +msgstr "" + +#: src/fs/gnunet-download.c:256 +msgid "write the file to FILENAME" +msgstr "" + +#: src/fs/gnunet-download.c:260 +msgid "set the maximum number of parallel downloads that is allowed" +msgstr "" + +#: src/fs/gnunet-download.c:264 +msgid "set the maximum number of parallel requests for blocks that is allowed" +msgstr "" + +#: src/fs/gnunet-download.c:267 +msgid "download a GNUnet directory recursively" +msgstr "" + +#: src/fs/gnunet-download.c:277 +msgid "" +"Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" +"chk/...)" +msgstr "" + +#: src/fs/gnunet-fs.c:117 +msgid "print a list of all indexed files" +msgstr "" + +#: src/fs/gnunet-fs.c:124 +msgid "Special file-sharing operations" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:151 src/statistics/gnunet-statistics.c:126 +#, c-format +msgid "Invalid argument `%s'\n" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:165 +#, c-format +msgid "Namespace `%s' unknown.\n" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:240 src/fs/gnunet-pseudonym.c:247 +#: src/fs/gnunet-pseudonym.c:249 +#, c-format +msgid "Option `%s' ignored\n" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:269 src/fs/gnunet-publish.c:672 +msgid "set the desired LEVEL of sender-anonymity" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:272 +msgid "create or advertise namespace NAME" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:275 +msgid "delete namespace NAME " +msgstr "" + +#: src/fs/gnunet-pseudonym.c:278 +msgid "" +"add an additional keyword for the advertisment (this option can be specified " +"multiple times)" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:282 src/fs/gnunet-publish.c:691 +msgid "set the meta-data for the given TYPE to the given VALUE" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:285 +msgid "print names of local namespaces" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:288 +msgid "use the given PRIORITY for the advertisments" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:291 +msgid "do not print names of remote namespaces" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:294 src/fs/gnunet-publish.c:710 +msgid "set the desired replication LEVEL" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:297 +msgid "specify ID of the root of the namespace" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:300 +msgid "change rating of namespace ID by VALUE" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:308 +msgid "Manage GNUnet pseudonyms." +msgstr "" + +#: src/fs/gnunet-publish.c:147 +#, c-format +msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-publish.c:155 +#, c-format +msgid "Error publishing: %s.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:165 +#, c-format +msgid "Publishing `%s' done.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:169 +#, c-format +msgid "URI is `%s'.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:187 +msgid "Cleanup after abort complete.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:299 +#, c-format +msgid "Meta data for file `%s' (%s)\n" +msgstr "" + +#: src/fs/gnunet-publish.c:301 +#, c-format +msgid "Keywords for file `%s' (%s)\n" +msgstr "" + +#: src/fs/gnunet-publish.c:352 +#, c-format +msgid "Failed to create namespace `%s'\n" +msgstr "" + +#: src/fs/gnunet-publish.c:427 +msgid "Could not publish\n" +msgstr "" + +#: src/fs/gnunet-publish.c:454 +msgid "Could not start publishing.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:485 +#, c-format +msgid "Scanning directory `%s'.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:487 +#, c-format +msgid "Scanning file `%s'.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:492 +#, c-format +msgid "There was trouble processing file `%s', skipping it.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:497 +msgid "Preprocessing complete.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:501 +#, c-format +msgid "Extracting meta data from file `%s' complete.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:505 +msgid "Meta data extraction has finished.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:512 +msgid "Internal error scanning directory.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:546 +#, c-format +msgid "Cannot extract metadata from a URI!\n" +msgstr "" + +#: src/fs/gnunet-publish.c:553 +#, c-format +msgid "You must specify one and only one filename for insertion.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:559 +#, c-format +msgid "You must NOT specify an URI and a filename.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:567 src/vpn/gnunet-vpn.c:214 +#, c-format +msgid "Option `%s' is required when using option `%s'.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:577 src/fs/gnunet-publish.c:584 +#: src/transport/gnunet-transport.c:530 +#, c-format +msgid "Option `%s' makes no sense without option `%s'.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:606 +#, c-format +msgid "Could not create namespace `%s'\n" +msgstr "" + +#: src/fs/gnunet-publish.c:639 +#, c-format +msgid "Failed to access `%s': %s\n" +msgstr "" + +#: src/fs/gnunet-publish.c:651 +msgid "" +"Failed to start meta directory scanner. Is gnunet-helper-publish-fs " +"installed?\n" +msgstr "" + +#: src/fs/gnunet-publish.c:676 +msgid "disable adding the creation time to the metadata of the uploaded file" +msgstr "" + +#: src/fs/gnunet-publish.c:679 +msgid "do not use libextractor to add keywords or metadata" +msgstr "" + +#: src/fs/gnunet-publish.c:683 +msgid "" +"print list of extracted keywords that would be used, but do not perform " +"upload" +msgstr "" + +#: src/fs/gnunet-publish.c:687 +msgid "" +"add an additional keyword for the top-level file or directory (this option " +"can be specified multiple times)" +msgstr "" + +#: src/fs/gnunet-publish.c:694 +msgid "" +"do not index, perform full insertion (stores entire file in encrypted form " +"in GNUnet database)" +msgstr "" + +#: src/fs/gnunet-publish.c:699 +msgid "" +"specify ID of an updated version to be published in the future (for " +"namespace insertions only)" +msgstr "" + +#: src/fs/gnunet-publish.c:703 +msgid "specify the priority of the content" +msgstr "" + +#: src/fs/gnunet-publish.c:707 +msgid "publish the files under the pseudonym NAME (place file into namespace)" +msgstr "" + +#: src/fs/gnunet-publish.c:713 +msgid "" +"only simulate the process but do not do any actual publishing (useful to " +"compute URIs)" +msgstr "" + +#: src/fs/gnunet-publish.c:717 +msgid "" +"set the ID of this version of the publication (for namespace insertions only)" +msgstr "" + +#: src/fs/gnunet-publish.c:721 +msgid "" +"URI to be published (can be used instead of passing a file to add keywords " +"to the file with the respective URI)" +msgstr "" + +#: src/fs/gnunet-publish.c:736 +msgid "Publish a file or directory on GNUnet" +msgstr "" + +#: src/fs/gnunet-search.c:111 +#, c-format +msgid "Failed to write directory with search results to `%s'\n" +msgstr "" + +#: src/fs/gnunet-search.c:181 +#, c-format +msgid "Error searching: %s.\n" +msgstr "" + +#: src/fs/gnunet-search.c:231 +msgid "Could not create keyword URI from arguments.\n" +msgstr "" + +#: src/fs/gnunet-search.c:255 +msgid "Could not start searching.\n" +msgstr "" + +#: src/fs/gnunet-search.c:291 +msgid "write search results to file starting with PREFIX" +msgstr "" + +#: src/fs/gnunet-search.c:294 +msgid "automatically terminate search after VALUE ms" +msgstr "" + +#: src/fs/gnunet-search.c:301 +msgid "automatically terminate search after VALUE results are found" +msgstr "" + +#: src/fs/gnunet-search.c:308 +msgid "Search GNUnet for files that were published on GNUnet" +msgstr "" + +#: src/fs/gnunet-service-fs.c:240 +msgid "# running average P2P latency (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 +msgid "# Loopback routes suppressed" +msgstr "" + +#: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 +#: src/topology/gnunet-daemon-topology.c:1290 +#: src/topology/gnunet-daemon-topology.c:1297 +#, c-format +msgid "Failed to connect to `%s' service.\n" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 +#: src/topology/gnunet-daemon-topology.c:654 +#: src/topology/gnunet-daemon-topology.c:756 +#: src/transport/gnunet-service-transport_neighbours.c:960 +#: src/transport/gnunet-service-transport_neighbours.c:1289 +#: src/transport/gnunet-service-transport_neighbours.c:1841 +#: src/transport/gnunet-service-transport_neighbours.c:2499 +#: src/transport/gnunet-service-transport_neighbours.c:2566 +msgid "# peers connected" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:696 +msgid "# migration stop messages received" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:700 +#, c-format +msgid "Migration of content to peer `%s' blocked for %llu ms\n" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:735 +msgid "# replies transmitted to other peers" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:741 +msgid "# replies dropped" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 +msgid "# P2P searches active" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:858 +msgid "# artificial delays introduced (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:911 +msgid "# replies dropped due to type mismatch" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:919 +msgid "# replies received for other peers" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:933 +msgid "# replies dropped due to insufficient cover traffic" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:971 +msgid "# P2P searches destroyed due to ultimate reply" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1038 +msgid "# requests done for free (low load)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1062 +msgid "# request dropped, priority insufficient" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1072 +msgid "# requests done for a price (normal load)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1151 +msgid "# GET requests received (from other peers)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1185 +msgid "# requests dropped due to initiator not being connected" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1207 +msgid "# requests dropped due to missing reverse route" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1267 +msgid "# requests dropped due TTL underflow" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1293 +msgid "# requests dropped due to higher-TTL request" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1322 +msgid "# P2P query messages received and processed" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1687 +msgid "# migration stop messages sent" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:113 +#: src/fs/gnunet-service-fs_indexing.c:163 +#, c-format +msgid "Configuration option `%s' in section `%s' missing.\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:121 +#: src/fs/gnunet-service-fs_indexing.c:177 +#, c-format +msgid "Could not open `%s'.\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:137 +#, c-format +msgid "Error writing `%s'.\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:228 +#, c-format +msgid "" +"Index request received for file `%s' is already indexed as `%s'. Permitting " +"anyway.\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:266 +#, c-format +msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:481 +#, c-format +msgid "Failed to delete bogus block: %s\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:539 +msgid "# index blocks removed: original file inaccessible" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:554 +#, c-format +msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:556 +msgid "not indexed" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:571 +#, c-format +msgid "Indexed file `%s' changed at offset %llu\n" +msgstr "" + +#: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 +#: src/fs/gnunet-service-fs_lc.c:488 +msgid "# client searches active" +msgstr "" + +#: src/fs/gnunet-service-fs_lc.c:256 +msgid "# replies received for local clients" +msgstr "" + +#: src/fs/gnunet-service-fs_lc.c:321 +msgid "# client searches received" +msgstr "" + +#: src/fs/gnunet-service-fs_lc.c:356 +msgid "# client searches updated (merged content seen list)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:265 +msgid "# average retransmission delay (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:391 +msgid "# transmission failed (core has no bandwidth)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:420 +msgid "# query messages sent to other peers" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:469 +msgid "# delay heap timeout" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:476 +msgid "# query plans executed" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:538 +msgid "# requests merged" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:544 +msgid "# requests refreshed" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 +#: src/fs/gnunet-service-fs_pe.c:748 +msgid "# query plan entries" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:285 +msgid "# Pending requests created" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 +msgid "# Pending requests active" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:779 +msgid "# replies received and matched" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:808 +msgid "# duplicate replies discarded (bloomfilter)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:822 +#, c-format +msgid "Unsupported block type %u\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:835 +msgid "# results found locally" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:953 +msgid "# Datastore `PUT' failures" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:980 +msgid "# storage requests dropped due to high load" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1015 +msgid "# Replies received from DHT" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1106 +#, c-format +msgid "Datastore lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1127 +#, c-format +msgid "On-demand lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1174 +msgid "# Datastore lookups concluded (no results)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1188 +msgid "# Datastore lookups concluded (seen all)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1197 +msgid "# Datastore lookups aborted (more than MAX_RESULTS)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1211 +msgid "# requested DBLOCK or IBLOCK not found" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1224 +msgid "# on-demand blocks matched requests" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1237 +msgid "# on-demand lookups performed successfully" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1242 +msgid "# on-demand lookups failed" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 +#: src/fs/gnunet-service-fs_pr.c:1447 +msgid "# Datastore lookups concluded (error queueing)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1327 +msgid "# Datastore lookups concluded (found last result)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1338 +msgid "# Datastore lookups concluded (load too high)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1424 +msgid "# Datastore lookups initiated" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1508 +msgid "# GAP PUT messages received" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 +#, c-format +msgid "Configuration fails to specify `%s', assuming default value." +msgstr "" + +#: src/fs/gnunet-service-fs_push.c:629 +#, c-format +msgid "" +"Invalid value specified for option `%s' in section `%s', content pushing " +"disabled\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:89 +#, c-format +msgid "Unindexing at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:96 +#, c-format +msgid "Error unindexing: %s.\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:101 +msgid "Unindexing done.\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:131 +#, c-format +msgid "You must specify one and only one filename for unindexing.\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:148 +msgid "Could not start unindex operation.\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:176 +msgid "Unindex a file that was previously indexed with gnunet-publish." +msgstr "" + +#: src/fs/plugin_block_fs.c:131 +msgid "Reply mismatched in terms of namespace. Discarded.\n" +msgstr "" + +#: src/gns/gns_api.c:221 +msgid "Failed to connect to the GNS service!\n" +msgstr "" + +#: src/gns/gnunet-gns-lookup.c:210 +msgid "Issue a request to the GNUnet Naming System, prints results." +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:264 +msgid "" +"None of the functions for the hostlist daemon were enabled. I have no " +"reason to run!\n" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:317 +msgid "advertise our hostlist to other peers" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:322 +msgid "" +"bootstrap using hostlists (it is highly recommended that you always use this " +"option)" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:325 +msgid "enable learning about hostlist servers from other peers" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:329 +msgid "provide a hostlist server" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:341 +msgid "GNUnet hostlist server and client" +msgstr "" + +#: src/hostlist/hostlist-client.c:286 +msgid "# bytes downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:307 src/hostlist/hostlist-client.c:339 +msgid "# invalid HELLOs downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:342 +#, c-format +msgid "Invalid `%s' message received from hostlist at `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:330 +msgid "# valid HELLOs downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:374 src/hostlist/hostlist-client.c:395 +#, c-format +msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:472 src/hostlist/hostlist-client.c:682 +#: src/hostlist/hostlist-client.c:688 src/hostlist/hostlist-client.c:740 +#: src/hostlist/hostlist-client.c:749 src/hostlist/hostlist-client.c:877 +#: src/hostlist/hostlist-client.c:967 src/hostlist/hostlist-client.c:972 +#: src/transport/plugin_transport_http_client.c:108 +#: src/transport/plugin_transport_http_client.c:123 +#, c-format +msgid "%s failed at %s:%d: `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:592 src/hostlist/hostlist-client.c:1342 +msgid "# advertised hostlist URIs" +msgstr "" + +#: src/hostlist/hostlist-client.c:622 +#, c-format +msgid "# advertised URI `%s' downloaded" +msgstr "" + +#: src/hostlist/hostlist-client.c:663 +#, c-format +msgid "" +"Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " +"gets dismissed.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:805 +#, c-format +msgid "Timeout trying to download hostlist from `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:822 +#, c-format +msgid "Download limit of %u bytes exceeded, stopping download\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:842 +#, c-format +msgid "%s failed for `%s' at %s:%d: `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:848 +#, c-format +msgid "Download of hostlist `%s' completed.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:856 +#, c-format +msgid "Adding successfully tested hostlist `%s' datastore.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:909 +#, c-format +msgid "Bootstrapping using hostlist at `%s'.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:917 +msgid "# hostlist downloads initiated" +msgstr "" + +#: src/hostlist/hostlist-client.c:1045 src/hostlist/hostlist-client.c:1515 +msgid "# milliseconds between hostlist downloads" +msgstr "" + +#: src/hostlist/hostlist-client.c:1054 +#, c-format +msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1092 +msgid "Scheduled saving of hostlists\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1096 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1119 src/hostlist/hostlist-client.c:1135 +msgid "# active connections" +msgstr "" + +#: src/hostlist/hostlist-client.c:1253 +#, c-format +msgid "Initial time between hostlist downloads is %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1284 +#, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1290 +#, c-format +msgid "Loading saved hostlist entries from file `%s' \n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1294 +#, c-format +msgid "Hostlist file `%s' is not existing\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1305 +#, c-format +msgid "Could not open file `%s' for reading to load hostlists: %s\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1338 +#, c-format +msgid "%u hostlist URIs loaded from file\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1340 +msgid "# hostlist URIs read from file" +msgstr "" + +#: src/hostlist/hostlist-client.c:1373 +#, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1387 +#, c-format +msgid "Could not open file `%s' for writing to save hostlists: %s\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1392 +#, c-format +msgid "Writing %u hostlist URIs to `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1416 src/hostlist/hostlist-client.c:1433 +#, c-format +msgid "Error writing hostlist URIs to file `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1428 +msgid "# hostlist URIs written to file" +msgstr "" + +#: src/hostlist/hostlist-client.c:1480 +msgid "Learning is enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1483 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1492 +msgid "Learning is not enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1504 +#, c-format +msgid "" +"Since learning is not enabled on this peer, hostlist file `%s' was removed\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1508 +#, c-format +msgid "Hostlist file `%s' could not be removed\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:134 +msgid "bytes in hostlist" +msgstr "" + +#: src/hostlist/hostlist-server.c:157 +msgid "expired addresses encountered" +msgstr "" + +#: src/hostlist/hostlist-server.c:184 +#: src/topology/gnunet-daemon-topology.c:875 +#, c-format +msgid "Error in communication with PEERINFO service: %s\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:205 +msgid "HELLOs without addresses encountered (ignored)" +msgstr "" + +#: src/hostlist/hostlist-server.c:221 +msgid "bytes not included in hostlist (size limit)" +msgstr "" + +#: src/hostlist/hostlist-server.c:269 +#, c-format +msgid "Refusing `%s' request to hostlist server\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:272 +msgid "hostlist requests refused (not HTTP GET)" +msgstr "" + +#: src/hostlist/hostlist-server.c:280 +msgid "Sending 100 CONTINUE reply\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:287 +#, c-format +msgid "Refusing `%s' request with %llu bytes of upload data\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:291 +msgid "hostlist requests refused (upload data)" +msgstr "" + +#: src/hostlist/hostlist-server.c:299 +msgid "Could not handle hostlist request since I do not have a response yet\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:302 +msgid "hostlist requests refused (not ready)" +msgstr "" + +#: src/hostlist/hostlist-server.c:306 +msgid "Received request for our hostlist\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:307 +msgid "hostlist requests processed" +msgstr "" + +#: src/hostlist/hostlist-server.c:350 +msgid "# hostlist advertisements send" +msgstr "" + +#: src/hostlist/hostlist-server.c:397 +msgid "Advertisement message could not be queued by core\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:565 +#, c-format +msgid "Invalid port number %llu. Exiting.\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:574 +#, c-format +msgid "Hostlist service starts on %s:%llu\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:588 +#, c-format +msgid "Address to obtain hostlist: `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:626 +#, c-format +msgid "Could not start hostlist HTTP server on port %u\n" +msgstr "" + +#: src/mesh/gnunet-service-mesh.c:4595 +msgid "Wrong CORE service\n" +msgstr "" + +#: src/mesh/gnunet-service-mesh.c:4789 +msgid "Mesh service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/mesh/gnunet-service-mesh.c:4798 +msgid "Mesh service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/namestore/namestore_api.c:272 src/namestore/namestore_api.c:313 +msgid "Namestore added record successfully" +msgstr "" + +#: src/namestore/namestore_api.c:281 src/namestore/namestore_api.c:322 +msgid "Namestore failed to add record" +msgstr "" + +#: src/nat/gnunet-nat-server.c:289 +#, c-format +msgid "Please pass valid port number as the first argument! (got `%s')\n" +msgstr "" + +#: src/nat/gnunet-nat-server.c:328 +msgid "GNUnet NAT traversal test helper daemon" +msgstr "" + +#: src/nat/nat.c:803 +#, c-format +msgid "gnunet-helper-nat-server generated malformed address `%s'\n" +msgstr "" + +#: src/nat/nat.c:852 +#, c-format +msgid "Failed to start %s\n" +msgstr "" + +#: src/nat/nat.c:1121 +#, c-format +msgid "Malformed %s `%s' given in configuration!\n" +msgstr "" + +#: src/nat/nat.c:1187 src/nat/nat.c:1197 +#, c-format +msgid "" +"Configuration requires `%s', but binary is not installed properly (SUID bit " +"not set). Option disabled.\n" +msgstr "" + +#: src/nat/nat.c:1329 +msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" +msgstr "" + +#: src/nat/nat.c:1341 +#, c-format +msgid "Running gnunet-helper-nat-client %s %s %u\n" +msgstr "" + +#: src/nat/nat_test.c:348 +msgid "Failed to connect to `gnunet-nat-server'\n" +msgstr "" + +#: src/nat/nat_test.c:418 +#, c-format +msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" +msgstr "" + +#: src/nse/gnunet-nse-profiler.c:926 +msgid "Measure quality and performance of the NSE service." +msgstr "" + +#: src/nse/gnunet-service-nse.c:936 +#, c-format +msgid "Proof of work invalid: %llu!\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1391 src/nse/gnunet-service-nse.c:1410 +#: src/nse/gnunet-service-nse.c:1431 +msgid "NSE service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1398 +msgid "Invalid work requirement for NSE service. Exiting.\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1419 +msgid "NSE service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:133 +#, c-format +msgid "Removing expired address of transport `%s'\n" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:195 +msgid "# peers known" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:239 +#, c-format +msgid "" +"File `%s' in directory `%s' does not match naming convention. Removed.\n" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:305 +#, c-format +msgid "Still no peers found in `%s'!\n" +msgstr "" + +#: src/peerinfo/peerinfo_api.c:279 +#, c-format +msgid "Failed to transmit message to `%s' service.\n" +msgstr "" + +#: src/peerinfo/peerinfo_api.c:435 +msgid "Failed to receive response from `PEERINFO' service." +msgstr "" + +#: src/peerinfo/peerinfo_api.c:463 src/peerinfo/peerinfo_api.c:481 +msgid "Received invalid message from `PEERINFO' service.\n" +msgstr "" + +#: src/peerinfo/peerinfo_api.c:523 +msgid "Failed to transmit iteration request to `PEERINFO' service\n" +msgstr "" + +#: src/peerinfo/peerinfo_api.c:557 +msgid "Timeout transmitting iteration request to `PEERINFO' service.\n" +msgstr "" + +#: src/peerinfo/peerinfo_api_notify.c:258 +#, c-format +msgid "Could not connect to `%s' service.\n" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:216 +#, c-format +msgid "Could not find option `%s:%s' in configuration.\n" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:223 +#, c-format +msgid "Loading hostkey from `%s' failed.\n" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:235 +#, c-format +msgid "I am peer `%s'.\n" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:255 +msgid "output only the identity strings" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:258 +msgid "output our own identity only" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:264 +msgid "Print information about peers." +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:264 +msgid "Failed to pack DNS request. Dropping.\n" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:270 +msgid "# DNS requests mapped to VPN" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:323 +msgid "# DNS records modified" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:500 +msgid "# DNS replies intercepted" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:506 +msgid "Failed to parse DNS request. Dropping.\n" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:602 +msgid "# DNS requests dropped (timeout)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:632 +msgid "# DNS requests intercepted" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:637 +msgid "# DNS requests dropped (DNS mesh tunnel down)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:645 +msgid "# DNS requests dropped (malformed)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:716 +msgid "# DNS replies received" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:730 +msgid "# DNS replies dropped (too late?)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 +msgid "# DNS requests aborted (tunnel down)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 +#: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 +#, c-format +msgid "Failed to connect to %s service. Exiting.\n" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:973 +msgid "Daemon to run to perform IP protocol translation to GNUnet" +msgstr "" + +#: src/statistics/gnunet-service-statistics.c:209 +#, c-format +msgid "Loading %llu bytes of statistics from `%s'\n" +msgstr "" + +#: src/statistics/gnunet-service-statistics.c:267 +#, c-format +msgid "Wrote %llu bytes of statistics to `%s'\n" +msgstr "" + +#: src/statistics/gnunet-statistics.c:98 +msgid "Failed to obtain statistics.\n" +msgstr "" + +#: src/statistics/gnunet-statistics.c:164 +msgid "limit output to statistics for the given NAME" +msgstr "" + +#: src/statistics/gnunet-statistics.c:167 +msgid "make the value being set persistent" +msgstr "" + +#: src/statistics/gnunet-statistics.c:170 +msgid "limit output to the given SUBSYSTEM" +msgstr "" + +#: src/statistics/gnunet-statistics.c:173 +msgid "just print the statistics value" +msgstr "" + +#: src/statistics/gnunet-statistics.c:180 +msgid "Print statistics about GNUnet operations." +msgstr "" + +#: src/statistics/statistics_api.c:390 +msgid "Failed to connect to statistics service!\n" +msgstr "" + +#: src/template/gnunet-template.c:68 +msgid "help text" +msgstr "" + +#: src/testing/gnunet-testing.c:157 +msgid "Could not read hostkeys file, specify hostkey file with -H!\n" +msgstr "" + +#: src/testing/gnunet-testing.c:159 +#, c-format +msgid "Specified hostkey file `%s' not found!\n" +msgstr "" + +#: src/testing/gnunet-testing.c:273 +msgid "create unique configuration files" +msgstr "" + +#: src/testing/gnunet-testing.c:275 +msgid "create hostkey files from pre-computed hostkey list" +msgstr "" + +#: src/testing/gnunet-testing.c:277 +msgid "host key file" +msgstr "" + +#: src/testing/gnunet-testing.c:279 +msgid "number of unique configuration files or hostkeys to create" +msgstr "" + +#: src/testing/gnunet-testing.c:281 +msgid "configuration template" +msgstr "" + +#: src/testing/gnunet-testing.c:287 +msgid "Command line tool to access the testing library" +msgstr "" + +#: src/testing/helper.c:56 +msgid "Peer is lacking HOSTKEY configuration setting.\n" +msgstr "" + +#: src/testing/helper.c:64 +msgid "Could not access hostkey.\n" +msgstr "" + +#: src/testing/testing.c:204 +msgid "`scp' does not seem to terminate (timeout copying config).\n" +msgstr "" + +#: src/testing/testing.c:218 src/testing/testing.c:808 +msgid "`scp' did not complete cleanly.\n" +msgstr "" + +#: src/testing/testing.c:239 +msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" +msgstr "" + +#: src/testing/testing.c:240 +msgid "Failed to create pipe for `ssh' process.\n" +msgstr "" + +#: src/testing/testing.c:292 +#, c-format +msgid "Could not start `%s' process to create hostkey.\n" +msgstr "" + +#: src/testing/testing.c:299 +msgid "Failed to start `gnunet-peerinfo' process.\n" +msgstr "" + +#: src/testing/testing.c:300 src/testing/testing.c:488 +msgid "Failed to start `ssh' process.\n" +msgstr "" + +#: src/testing/testing.c:360 +#, c-format +msgid "Error reading from gnunet-peerinfo: %s\n" +msgstr "" + +#: src/testing/testing.c:364 +msgid "Malformed output from gnunet-peerinfo!\n" +msgstr "" + +#: src/testing/testing.c:374 +msgid "Failed to get hostkey!\n" +msgstr "" + +#: src/testing/testing.c:406 +msgid "`Failed while waiting for topology setup!\n" +msgstr "" + +#: src/testing/testing.c:480 +#, c-format +msgid "Could not start `%s' process to start GNUnet.\n" +msgstr "" + +#: src/testing/testing.c:487 +msgid "Failed to start `gnunet-arm' process.\n" +msgstr "" + +#: src/testing/testing.c:509 src/testing/testing.c:612 +msgid "`gnunet-arm' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:510 src/testing/testing.c:613 +#: src/testing/testing.c:633 +msgid "`ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:582 +msgid "Unable to get HELLO for peer!\n" +msgstr "" + +#: src/testing/testing.c:632 +msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" +msgstr "" + +#: src/testing/testing.c:653 src/testing/testing.c:685 +msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:668 src/testing/testing.c:723 +msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" +msgstr "" + +#: src/testing/testing.c:796 +msgid "`scp' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:966 +#, c-format +msgid "Starting service %s for peer `%4s'\n" +msgstr "" + +#: src/testing/testing.c:1237 src/testing/testing_group.c:6278 +#, c-format +msgid "Could not start `%s' process to copy configuration directory.\n" +msgstr "" + +#: src/testing/testing.c:1322 src/testing/testing.c:1397 +#, c-format +msgid "Terminating peer `%4s'\n" +msgstr "" + +#: src/testing/testing.c:1480 +#, c-format +msgid "Setting d->dead on peer `%4s'\n" +msgstr "" + +#: src/testing/testing.c:1610 +msgid "Peer not yet running, can not change configuration at this point." +msgstr "" + +#: src/testing/testing.c:1618 +msgid "Failed to write new configuration to disk." +msgstr "" + +#: src/testing/testing.c:1647 +#, c-format +msgid "Could not start `%s' process to copy configuration file.\n" +msgstr "" + +#: src/testing/testing.c:1650 +msgid "Failed to copy new configuration to remote machine." +msgstr "" + +#: src/testing/testing.c:1805 +msgid "Peers failed to connect" +msgstr "" + +#: src/testing/testing.c:1933 +msgid "Failed to connect to core service of first peer!\n" +msgstr "" + +#: src/testing/testing.c:2156 +msgid "Peers are not fully running yet, can not connect!\n" +msgstr "" + +#: src/testing/testing_group.c:1910 src/testing/testing_group.c:1922 +#: src/testing/testing_group.c:2023 src/testing/testing_group.c:2082 +#: src/testing/testing_group.c:2171 src/testing/testing_group.c:2191 +#: src/testing/testing_group.c:2328 src/testing/testing_peergroup.c:940 +#, c-format +msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" +msgstr "" + +#: src/testing/testing_group.c:1932 +#, c-format +msgid "Target is %d connections per peer." +msgstr "" + +#: src/testing/testing_group.c:2179 +#, c-format +msgid "" +"Invalid value `%s' for option `%s' in section `%s': got %f, needed value " +"greater than 0\n" +msgstr "" + +#: src/testing/testing_group.c:2209 src/testing/testing_group.c:2402 +#, c-format +msgid "Connecting nodes in 2d torus topology: %u rows %u columns\n" +msgstr "" + +#: src/testing/testing_group.c:2246 +#, c-format +msgid "natural log of %d is %d, will run %d iterations\n" +msgstr "" + +#: src/testing/testing_group.c:2249 +#, c-format +msgid "Total connections added thus far: %u!\n" +msgstr "" + +#: src/testing/testing_group.c:2290 +#, c-format +msgid "Total connections added for small world: %d!\n" +msgstr "" + +#: src/testing/testing_group.c:2342 +#, c-format +msgid "rand is %f probability is %f\n" +msgstr "" + +#: src/testing/testing_group.c:2919 src/testing/testing_group.c:3118 +#, c-format +msgid "" +"No `%s' specified in peer configuration in section `%s', cannot copy friends " +"file!\n" +msgstr "" + +#: src/testing/testing_group.c:3020 +msgid "Finished copying all friend files!\n" +msgstr "" + +#: src/testing/testing_group.c:3133 +#, c-format +msgid "Copying file with command cp %s %s\n" +msgstr "" + +#: src/testing/testing_group.c:3156 +#, c-format +msgid "Copying file with command scp %s %s\n" +msgstr "" + +#: src/testing/testing_group.c:3173 +#, c-format +msgid "Checking copy status of file %d\n" +msgstr "" + +#: src/testing/testing_group.c:3191 +#, c-format +msgid "File %d copied\n" +msgstr "" + +#: src/testing/testing_group.c:3206 +msgid "Finished copying all blacklist files!\n" +msgstr "" + +#: src/testing/testing_group.c:3586 src/testing/testing_group.c:3723 +#: src/testing/testing_group.c:4884 src/testing/testing_group.c:5025 +msgid "Delaying connect, we have too many outstanding connections!\n" +msgstr "" + +#: src/testing/testing_group.c:3596 src/testing/testing_group.c:4894 +#: src/testing/testing_group.c:5035 +#, c-format +msgid "Creating connection, outstanding_connections is %d\n" +msgstr "" + +#: src/testing/testing_group.c:3608 +#, c-format +msgid "Offering HELLO of peer %s to peer %s\n" +msgstr "" + +#: src/testing/testing_group.c:3734 +#, c-format +msgid "Creating connection, outstanding_connections is %d (max %d)\n" +msgstr "" + +#: src/testing/testing_group.c:3988 +msgid "Creating clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:3993 +msgid "Creating small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:3998 +msgid "Creating small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4002 +msgid "Creating ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4006 +msgid "Creating 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4010 +msgid "Creating Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4014 +msgid "Creating InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4018 +msgid "Creating Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4023 +msgid "Creating straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4027 +msgid "Creating topology from file!\n" +msgstr "" + +#: src/testing/testing_group.c:4043 +msgid "Creating no allowed topology (all peers can connect at core level)\n" +msgstr "" + +#: src/testing/testing_group.c:4058 +msgid "Failed during friend file copying!\n" +msgstr "" + +#: src/testing/testing_group.c:4064 +msgid "Friend files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:4081 +msgid "Blacklisting all but clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:4087 +msgid "Blacklisting all but small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4093 +msgid "Blacklisting all but small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4099 +msgid "Blacklisting all but ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4105 +msgid "Blacklisting all but 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4111 +msgid "Blacklisting all but Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4117 +msgid "Blacklisting all but InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4152 +msgid "Blacklisting all but Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4158 +msgid "Blacklisting all but straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4173 +msgid "Failed during blacklist file copying!\n" +msgstr "" + +#: src/testing/testing_group.c:4179 +msgid "Blacklist files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:5263 +msgid "Creating clique CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5270 +msgid "Creating small world (ring) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5277 +msgid "Creating small world (2d-torus) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5283 +msgid "Creating ring CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5290 +msgid "Creating 2d torus CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5297 +msgid "Creating Erdos-Renyi CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5304 +msgid "Creating InterNAT CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5311 +msgid "Creating Scale Free CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5318 +msgid "Creating straight line CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5324 +msgid "Creating no CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5330 +msgid "Unknown topology specification, can't connect peers!\n" +msgstr "" + +#: src/testing/testing_group.c:5340 +#, c-format +msgid "Connecting random subset (%'.2f percent) of possible peers\n" +msgstr "" + +#: src/testing/testing_group.c:5348 +#, c-format +msgid "Connecting a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5357 +#, c-format +msgid "Using DFS to connect a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5367 +#, c-format +msgid "Finding additional %u closest peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:6062 src/transport/transport-testing.c:650 +msgid "Could not read hostkeys file!\n" +msgstr "" + +#: src/testing/testing_group.c:6131 +#, c-format +msgid "Could not create configuration for peer number %u on `%s'!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:244 +msgid "# peers blacklisted" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:380 +msgid "# connect requests issued to transport" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:675 +#: src/topology/gnunet-daemon-topology.c:761 +msgid "# friends connected" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:950 +msgid "Failed to connect to core service, can not manage topology!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:982 +#, c-format +msgid "Option `%s' in section `%s' not specified!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:994 +#, c-format +msgid "Could not read friends list `%s'\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1000 +#, c-format +msgid "Friends file `%s' is empty.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1009 +#, c-format +msgid "Failed to read friends list from `%s': out of memory\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1017 +#, c-format +msgid "Failed to read friends list from `%s'\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1037 +#, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1050 +#, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1060 +#, c-format +msgid "Found friend `%s' in configuration\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1066 +#, c-format +msgid "Found myself `%s' in friend list (useless, ignored)\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1076 +msgid "# friends in configuration" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1082 +msgid "" +"Fewer friends specified than required by minimum friend count. Will only " +"connect to friends.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1089 +msgid "" +"More friendly connections required than target total number of connections.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1126 +msgid "# HELLO messages received" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1183 +msgid "# HELLO messages gossipped" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1323 +msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:247 +#, c-format +msgid "Could not read blacklist file `%s'\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:254 +#, c-format +msgid "Blacklist file `%s' is empty.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:266 +#, c-format +msgid "Failed to read blacklist from `%s'\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:287 +#: src/transport/gnunet-service-transport_blacklist.c:311 +#, c-format +msgid "Syntax error in blacklist file at offset %llu, giving up!\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:298 +#: src/transport/gnunet-service-transport_blacklist.c:336 +#, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:350 +#, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:364 +#, c-format +msgid "Found myself `%s' in blacklist (useless, ignored)\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:523 +#: src/transport/gnunet-service-transport_blacklist.c:764 +msgid "# disconnects due to blacklist" +msgstr "" + +#: src/transport/gnunet-service-transport.c:158 +msgid "# bytes payload discarded due to not connected peer " +msgstr "" + +#: src/transport/gnunet-service-transport.c:572 +msgid "Transport service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport.c:581 +msgid "Transport service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:353 +#, c-format +msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:358 +msgid "# messages dropped due to slow client" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:510 +#, c-format +msgid "Rejecting control connection from peer `%s', which is not me!\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:628 +msgid "# bytes payload received for other peers" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:645 +msgid "# bytes payload dropped (other peer was not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:696 +msgid "# REQUEST CONNECT messages received" +msgstr "" + +#: src/transport/gnunet-service-transport_hello.c:172 +msgid "# refreshed my HELLO" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:482 +msgid "# failed connection attempts due to timeout" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:883 +msgid "# peers disconnected due to external request" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:966 +msgid "# fast reconnects failed" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1022 +msgid "# peers disconnected due to timeout" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1047 +msgid "# keepalives sent" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1088 +msgid "# peers disconnected due to global disconnect" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1888 +#: src/transport/gnunet-service-transport_neighbours.c:1909 +msgid "# messages not sent (no such peer or not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1925 +msgid "# bytes in message queue for other peers" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1977 +msgid "# messages discarded due to lack of neighbour record" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2013 +msgid "# bandwidth quota violations by other peers" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2031 +msgid "# ms throttling suggested" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2060 +msgid "# KEEPALIVE messages discarded (not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2113 +msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2121 +msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2187 +msgid "# SET QUOTA messages ignored (no such peer)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2205 +msgid "# disconnects due to quota of 0" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2323 +msgid "# disconnect messages ignored (old format)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2336 +msgid "# disconnect messages ignored (timestamp)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2411 +msgid "# unexpected CONNECT_ACK messages (no peer)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2453 +msgid "# unexpected CONNECT_ACK messages" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2544 +msgid "# unexpected ACK messages" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:111 +msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:118 +#, c-format +msgid "Starting transport plugins `%s'\n" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:122 +#, c-format +msgid "Loading `%s' transport plugin\n" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:150 +#, c-format +msgid "Failed to load transport plugin for `%s'\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:410 +msgid "# address records discarded" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:459 +#, c-format +msgid "" +"Not transmitting `%s' with `%s', message too big (%u bytes!). This should " +"not happen.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:508 +msgid "# PING without HELLO messages sent" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:566 +msgid "# address revalidations started" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:798 +msgid "# PING message for different peer received" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:833 +#, c-format +msgid "" +"Not confirming PING with address `%s' since I cannot confirm having this " +"address.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:919 +msgid "# PONGs unicast via reliable transport" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:928 +msgid "# PONGs multicast to all available addresses" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1050 +msgid "# PONGs dropped, no matching pending validation" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1075 +msgid "# PONGs dropped, signature expired" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1134 +#, c-format +msgid "Adding `%s' without addresses for peer `%s'\n" +msgstr "" + +#: src/transport/gnunet-transport.c:256 +msgid "No transport plugins configured, peer will never communicate\n" +msgstr "" + +#: src/transport/gnunet-transport.c:269 +#, c-format +msgid "No port configured for plugin `%s', cannot test it\n" +msgstr "" + +#: src/transport/gnunet-transport.c:319 +#, c-format +msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:326 +#, c-format +msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:359 +#, c-format +msgid "Transmitting %u bytes to %s\n" +msgstr "" + +#: src/transport/gnunet-transport.c:379 +#, c-format +msgid "Connected to %s\n" +msgstr "" + +#: src/transport/gnunet-transport.c:410 +#, c-format +msgid "Disconnected from %s\n" +msgstr "" + +#: src/transport/gnunet-transport.c:439 +#, c-format +msgid "Received %u bytes from %s\n" +msgstr "" + +#: src/transport/gnunet-transport.c:453 +#, c-format +msgid "Peer `%s': %s %s\n" +msgstr "" + +#: src/transport/gnunet-transport.c:483 +#, c-format +msgid "Peer `%s' disconnected\n" +msgstr "" + +#: src/transport/gnunet-transport.c:539 +#, c-format +msgid "Failed to parse peer identity `%s'\n" +msgstr "" + +#: src/transport/gnunet-transport.c:587 +msgid "measure how fast we are receiving data (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:590 +msgid "try to connect to the given peer" +msgstr "" + +#: src/transport/gnunet-transport.c:593 +msgid "provide information about all current connections (once)" +msgstr "" + +#: src/transport/gnunet-transport.c:596 +msgid "provide information about all current connections (continuously)" +msgstr "" + +#: src/transport/gnunet-transport.c:599 +msgid "do not resolve hostnames" +msgstr "" + +#: src/transport/gnunet-transport.c:603 +msgid "send data for benchmarking to the other peer (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:606 +msgid "test transport configuration (involves external server)" +msgstr "" + +#: src/transport/gnunet-transport.c:614 +msgid "Direct access to transport service." +msgstr "" + +#: src/transport/plugin_transport_http.c:981 +msgid "Disabling IPv6 since it is not supported on this system!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1029 +msgid "Require valid port number for service in configuration!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1054 src/util/service.c:986 +#, c-format +msgid "Failed to resolve `%s': %s\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1071 src/util/service.c:1003 +#, c-format +msgid "Failed to find %saddress for `%s'.\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1176 +#, c-format +msgid "Found %u addresses to report to NAT service\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1189 +#, c-format +msgid "FREEING %s\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1264 +msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1277 +msgid "Port is required! Fix in configuration\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1288 +msgid "Port 0, client only mode\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1308 +#, c-format +msgid "" +"Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1338 +#, c-format +msgid "" +"Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http_client.c:621 +#, c-format +msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:189 +msgid "" +"Could not create a new TLS certificate, program `gnunet-transport-" +"certificate-creation' could not be started!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:213 +msgid "No usable TLS certificate found and creating one failed!\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:370 +#, c-format +msgid "Received malformed message via %s. Ignored.\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:457 +msgid "SMTP filter string to invalid, lacks ': '\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:466 +#, c-format +msgid "SMTP filter string to long, capped to `%s'\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:561 +#: src/transport/plugin_transport_smtp.c:571 +#: src/transport/plugin_transport_smtp.c:584 +#: src/transport/plugin_transport_smtp.c:603 +#: src/transport/plugin_transport_smtp.c:626 +#: src/transport/plugin_transport_smtp.c:634 +#: src/transport/plugin_transport_smtp.c:647 +#: src/transport/plugin_transport_smtp.c:658 +#, c-format +msgid "SMTP: `%s' failed: %s.\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:801 +msgid "No email-address specified, can not start SMTP transport.\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:813 +msgid "# bytes received via SMTP" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:814 +msgid "# bytes sent via SMTP" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:816 +msgid "# bytes dropped by SMTP (outgoing)" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:512 +#, c-format +msgid "Unexpected address length: %u bytes\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:616 +#: src/transport/plugin_transport_tcp.c:705 +#: src/transport/plugin_transport_tcp.c:757 +#: src/transport/plugin_transport_tcp.c:830 +#: src/transport/plugin_transport_tcp.c:909 +msgid "# bytes currently in TCP buffers" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:622 +#: src/transport/plugin_transport_tcp.c:856 +#: src/transport/plugin_transport_tcp.c:1561 +msgid "# TCP sessions active" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:709 +msgid "# bytes discarded by TCP (timeout)" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:760 +msgid "# bytes transmitted via TCP" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:834 +msgid "# bytes discarded by TCP (disconnect)" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1081 +#, c-format +msgid "Address of unexpected length: %u\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1116 +msgid "Found valid IPv4 NAT address (creating session)!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1186 +msgid "# transport-service disconnect requests for TCP" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1603 +msgid "# TCP WELCOME messages received" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1756 +msgid "# bytes received via TCP" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1823 +msgid "# network-level TCP disconnect events" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1962 src/util/service.c:889 +#, c-format +msgid "Require valid port number for service `%s' in configuration!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1976 +msgid "Failed to start service.\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2039 +#, c-format +msgid "Failed to find option %s in section %s!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2062 +#, c-format +msgid "TCP transport listening on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2066 +msgid "TCP transport not listening on any port (client only)\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2070 +#, c-format +msgid "TCP transport advertises itself as being on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_udp_broadcasting.c:130 +msgid "# IPv6 multicast HELLO beacons received via udp" +msgstr "" + +#: src/transport/plugin_transport_udp_broadcasting.c:172 +msgid "# IPv4 broadcast HELLO beacons received via udp" +msgstr "" + +#: src/transport/plugin_transport_udp_broadcasting.c:393 +#, c-format +msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:1985 +msgid "Failed to open UDP sockets\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:2068 +#, c-format +msgid "Given `%s' option is out of range: %llu > %u\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:2112 +#, c-format +msgid "Invalid IPv6 address: `%s'\n" +msgstr "" + +#: src/transport/plugin_transport_unix.c:1051 +msgid "Failed to open UNIX sockets\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:875 +msgid "# wlan session timeouts" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:899 +msgid "# wlan session created" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:980 +#: src/transport/plugin_transport_wlan.c:1138 +#: src/transport/plugin_transport_wlan.c:1159 +#: src/transport/plugin_transport_wlan.c:1190 +#: src/transport/plugin_transport_wlan.c:2334 +#: src/transport/plugin_transport_wlan.c:3142 +msgid "# wlan pending sessions" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1233 +#: src/transport/plugin_transport_wlan.c:1888 +msgid "# wlan pending fragments" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1388 +#, c-format +msgid "" +"Finished reading from gnunet-helper-transport-wlan stdout with code: %d\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1732 +msgid "# wlan hello beacons send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1765 +#: src/transport/plugin_transport_wlan.c:1968 +#: src/transport/plugin_transport_wlan.c:2059 +#, c-format +msgid "Error writing to wlan helper. errno == %d, ERROR: %s\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1954 +msgid "# wlan acks send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2025 +msgid "# wlan fragments send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2161 +#, c-format +msgid "Wlan Address len %d is wrong\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2295 +#: src/transport/plugin_transport_wlan.c:2919 +#: src/transport/plugin_transport_wlan.c:3145 +msgid "# wlan mac endpoints" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2517 +msgid "# wlan whole messages received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2708 +msgid "# wlan hello messages received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2742 +msgid "# wlan fragments received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2790 +msgid "# wlan acks received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2879 +msgid "# wlan mac endpoints timeouts" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2903 +msgid "# wlan mac endpoints created" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2956 +msgid "# wlan WLAN_HELPER_DATA received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:3010 +msgid "# wlan messages for this client received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:3021 +msgid "# wlan messages inside WLAN_HELPER_DATA received" +msgstr "" + +#: src/transport/transport_api.c:588 +#, c-format +msgid "Received unexpected message of type %u in %s:%u\n" +msgstr "" + +#: src/util/bio.c:136 src/util/bio.c:142 +#, c-format +msgid "Error reading `%s': %s" +msgstr "" + +#: src/util/bio.c:143 +msgid "End of file" +msgstr "" + +#: src/util/bio.c:195 +#, c-format +msgid "Error reading length of string `%s'" +msgstr "" + +#: src/util/bio.c:205 +#, c-format +msgid "String `%s' longer than allowed (%u > %u)" +msgstr "" + +#: src/util/bio.c:250 +#, c-format +msgid "Serialized metadata `%s' larger than allowed (%u>%u)" +msgstr "" + +#: src/util/bio.c:264 +#, c-format +msgid "Metadata `%s' failed to deserialize" +msgstr "" + +#: src/util/client.c:304 +#, c-format +msgid "" +"Could not determine valid hostname and port for service `%s' from " +"configuration.\n" +msgstr "" + +#: src/util/client.c:312 +#, c-format +msgid "Need a non-empty hostname for service `%s'.\n" +msgstr "" + +#: src/util/client.c:657 +msgid "Failure to transmit TEST request.\n" +msgstr "" + +#: src/util/client.c:717 src/util/service.c:919 +#, c-format +msgid "UNIXPATH `%s' too long, maximum length is %llu\n" +msgstr "" + +#: src/util/client.c:859 +#, c-format +msgid "Could not connect to service `%s', must not be running.\n" +msgstr "" + +#: src/util/client.c:875 +#, c-format +msgid "Failure to transmit request to service `%s'\n" +msgstr "" + +#: src/util/client.c:1143 +msgid "Could not submit request, not expecting to receive a response.\n" +msgstr "" + +#: src/util/common_logging.c:239 src/util/common_logging.c:889 +msgid "DEBUG" +msgstr "" + +#: src/util/common_logging.c:241 src/util/common_logging.c:887 +msgid "INFO" +msgstr "" + +#: src/util/common_logging.c:243 src/util/common_logging.c:885 +msgid "WARNING" +msgstr "" + +#: src/util/common_logging.c:245 src/util/common_logging.c:883 +msgid "ERROR" +msgstr "" + +#: src/util/common_logging.c:247 src/util/common_logging.c:891 +msgid "NONE" +msgstr "" + +#: src/util/common_logging.c:609 +#, c-format +msgid "Failed to create or access directory for log file `%s'\n" +msgstr "" + +#: src/util/common_logging.c:724 +#, c-format +msgid "Message `%.*s' repeated %u times in the last %s\n" +msgstr "" + +#: src/util/common_logging.c:892 +msgid "INVALID" +msgstr "" + +#: src/util/common_logging.c:991 +msgid "unknown address" +msgstr "" + +#: src/util/common_logging.c:1029 +msgid "invalid address" +msgstr "" + +#: src/util/configuration.c:245 +#, c-format +msgid "Syntax error in configuration file `%s' at line %u.\n" +msgstr "" + +#: src/util/configuration.c:817 +#, c-format +msgid "" +"Configuration value '%s' for '%s' in section '%s' is not in set of legal " +"choices\n" +msgstr "" + +#: src/util/connection.c:460 +#, c-format +msgid "Access denied to `%s'\n" +msgstr "" + +#: src/util/connection.c:475 +#, c-format +msgid "Accepting connection from `%s': %p\n" +msgstr "" + +#: src/util/connection.c:629 +#, c-format +msgid "" +"Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" +msgstr "" + +#: src/util/connection.c:821 src/util/connection.c:992 +#, c-format +msgid "Trying to connect to `%s' (%p)\n" +msgstr "" + +#: src/util/connection.c:830 +#, c-format +msgid "Failed to connect to `%s' (%p)\n" +msgstr "" + +#: src/util/connection.c:983 +#, c-format +msgid "Attempt to connect to `%s' failed\n" +msgstr "" + +#: src/util/connection.c:1465 +#, c-format +msgid "" +"Could not satisfy pending transmission request, socket closed or connect " +"failed (%p).\n" +msgstr "" + +#: src/util/container_bloomfilter.c:507 +#, c-format +msgid "" +"Size of file on disk is incorrect for this Bloom filter (want %llu, have " +"%llu)\n" +msgstr "" + +#: src/util/crypto_random.c:280 +#, c-format +msgid "Starting `%s' process to generate entropy\n" +msgstr "" + +#: src/util/crypto_random.c:309 +#, c-format +msgid "libgcrypt has not the expected version (version %s is required).\n" +msgstr "" + +#: src/util/crypto_rsa.c:618 src/util/crypto_rsa.c:665 +#, c-format +msgid "Could not aquire lock on file `%s': %s...\n" +msgstr "" + +#: src/util/crypto_rsa.c:623 +msgid "Creating a new private key. This may take a while.\n" +msgstr "" + +#: src/util/crypto_rsa.c:641 +#, c-format +msgid "I am host `%s'. Stored new private key in `%s'.\n" +msgstr "" + +#: src/util/crypto_rsa.c:669 src/util/crypto_rsa.c:705 +msgid "This may be ok if someone is currently generating a hostkey.\n" +msgstr "" + +#: src/util/crypto_rsa.c:700 +#, c-format +msgid "" +"When trying to read hostkey file `%s' I found %u bytes but I need at least " +"%u.\n" +msgstr "" + +#: src/util/crypto_rsa.c:720 +#, c-format +msgid "File `%s' does not contain a valid private key. Deleting it.\n" +msgstr "" + +#: src/util/crypto_rsa.c:738 +#, c-format +msgid "I am host `%s'. Read private key from `%s'.\n" +msgstr "" + +#: src/util/crypto_rsa.c:959 +#, c-format +msgid "RSA signature verification failed at %s:%d: %s\n" +msgstr "" + +#: src/util/disk.c:479 +#, c-format +msgid "`%s' failed for drive `%S': %u\n" +msgstr "" + +#: src/util/disk.c:1087 +#, c-format +msgid "Expected `%s' to be a directory!\n" +msgstr "" + +#: src/util/disk.c:1441 src/util/service.c:1580 +#, c-format +msgid "Cannot obtain information about user `%s': %s\n" +msgstr "" + +#: src/util/disk.c:1759 +#, c-format +msgid "No `%s' specified for service `%s' in configuration.\n" +msgstr "" + +#: src/util/getopt.c:672 +#, c-format +msgid "%s: option `%s' is ambiguous\n" +msgstr "" + +#: src/util/getopt.c:696 +#, c-format +msgid "%s: option `--%s' does not allow an argument\n" +msgstr "" + +#: src/util/getopt.c:701 +#, c-format +msgid "%s: option `%c%s' does not allow an argument\n" +msgstr "" + +#: src/util/getopt.c:718 src/util/getopt.c:886 +#, c-format +msgid "%s: option `%s' requires an argument\n" +msgstr "" + +#: src/util/getopt.c:747 +#, c-format +msgid "%s: unrecognized option `--%s'\n" +msgstr "" + +#: src/util/getopt.c:751 +#, c-format +msgid "%s: unrecognized option `%c%s'\n" +msgstr "" + +#: src/util/getopt.c:776 +#, c-format +msgid "%s: illegal option -- %c\n" +msgstr "" + +#: src/util/getopt.c:778 +#, c-format +msgid "%s: invalid option -- %c\n" +msgstr "" + +#: src/util/getopt.c:806 src/util/getopt.c:934 +#, c-format +msgid "%s: option requires an argument -- %c\n" +msgstr "" + +#: src/util/getopt.c:854 +#, c-format +msgid "%s: option `-W %s' is ambiguous\n" +msgstr "" + +#: src/util/getopt.c:872 +#, c-format +msgid "%s: option `-W %s' does not allow an argument\n" +msgstr "" + +#: src/util/getopt.c:1038 +#, c-format +msgid "Use %s to get a list of options.\n" +msgstr "" + +#: src/util/getopt_helpers.c:84 +#, c-format +msgid "" +"Arguments mandatory for long options are also mandatory for short options.\n" +msgstr "" + +#: src/util/getopt_helpers.c:255 src/util/getopt_helpers.c:283 +#, c-format +msgid "You must pass a number to the `%s' option.\n" +msgstr "" + +#: src/util/gnunet-resolver.c:148 +msgid "perform a reverse lookup" +msgstr "" + +#: src/util/gnunet-resolver.c:154 +msgid "Use build-in GNUnet stub resolver" +msgstr "" + +#: src/util/gnunet-service-resolver.c:288 +#, c-format +msgid "Could not resolve `%s' (%s): %s\n" +msgstr "" + +#: src/util/gnunet-service-resolver.c:358 +#: src/util/gnunet-service-resolver.c:399 +#, c-format +msgid "Could not find IP of host `%s': %s\n" +msgstr "" + +#: src/util/gnunet-service-resolver.c:494 +#, c-format +msgid "Resolver asked to look up `%s'.\n" +msgstr "" + +#: src/util/gnunet-service-resolver.c:529 +#, c-format +msgid "Resolver asked to look up IP address `%s'.\n" +msgstr "" + +#: src/util/helper.c:239 +#, c-format +msgid "Error reading from `%s': %s\n" +msgstr "" + +#: src/util/helper.c:254 +#, c-format +msgid "Got 0 bytes from helper `%s' (EOF)\n" +msgstr "" + +#: src/util/helper.c:264 +#, c-format +msgid "Got %u bytes from helper `%s'\n" +msgstr "" + +#: src/util/helper.c:273 +#, c-format +msgid "Failed to parse inbound message from helper `%s'\n" +msgstr "" + +#: src/util/helper.c:432 +#, c-format +msgid "Error writing to `%s': %s\n" +msgstr "" + +#: src/util/network.c:1196 +#, c-format +msgid "" +"Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" +msgstr "" + +#: src/util/os_installation.c:299 +#, c-format +msgid "" +"Could not determine installation path for %s. Set `%s' environment " +"variable.\n" +msgstr "" + +#: src/util/os_installation.c:486 +#, c-format +msgid "Could not find binary `%s' in PATH!\n" +msgstr "" + +#: src/util/os_installation.c:492 +#, c-format +msgid "access (%s, X_OK) failed: %s\n" +msgstr "" + +#: src/util/os_installation.c:507 +#, c-format +msgid "stat (%s) failed: %s\n" +msgstr "" + +#: src/util/os_priority.c:304 +#, c-format +msgid "Failed to open named pipe `%s' for reading: %s\n" +msgstr "" + +#: src/util/os_priority.c:305 +#, c-format +msgid "Failed to open named pipe `%s' for writing: %s\n" +msgstr "" + +#: src/util/plugin.c:89 +#, c-format +msgid "Initialization of plugin mechanism failed: %s!\n" +msgstr "" + +#: src/util/plugin.c:146 +#, c-format +msgid "`%s' failed to resolve method '%s' with error: %s\n" +msgstr "" + +#: src/util/plugin.c:219 +#, c-format +msgid "`%s' failed for library `%s' with error: %s\n" +msgstr "" + +#: src/util/plugin.c:349 +msgid "Could not determine plugin installation path.\n" +msgstr "" + +#: src/util/pseudonym.c:273 +#, c-format +msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" +msgstr "" + +#: src/util/pseudonym.c:338 +msgid "no-name" +msgstr "" + +#: src/util/resolver_api.c:202 +#, c-format +msgid "Must specify `%s' for `%s' in configuration!\n" +msgstr "" + +#: src/util/resolver_api.c:221 +#, c-format +msgid "" +"Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" +msgstr "" + +#: src/util/resolver_api.c:351 +#, c-format +msgid "Timeout trying to resolve IP address `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:355 +#, c-format +msgid "Timeout trying to resolve hostname `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:426 +#, c-format +msgid "Resolver returns `%s' for IP `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:807 +#, c-format +msgid "Resolver returns `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:901 +#, c-format +msgid "Resolving our FQDN `%s'\n" +msgstr "" + +#: src/util/resolver_api.c:906 +#, c-format +msgid "Could not resolve our FQDN : %s\n" +msgstr "" + +#: src/util/resolver_api.c:938 +#, c-format +msgid "Resolving our hostname `%s'\n" +msgstr "" + +#: src/util/scheduler.c:866 +msgid "Looks like we're busy waiting...\n" +msgstr "" + +#: src/util/scheduler.c:996 +#, c-format +msgid "Attempt to cancel dead task %llu!\n" +msgstr "" + +#: src/util/server.c:397 +#, c-format +msgid "`%s' failed for port %d (%s).\n" +msgstr "" + +#: src/util/server.c:406 +#, c-format +msgid "`%s' failed for port %d (%s): address already in use\n" +msgstr "" + +#: src/util/server.c:411 +#, c-format +msgid "`%s' failed for `%s': address already in use\n" +msgstr "" + +#: src/util/server.c:640 +#, c-format +msgid "" +"Processing code for message of type %u did not call " +"GNUNET_SERVER_receive_done after %llums\n" +msgstr "" + +#: src/util/service.c:117 src/util/service.c:143 src/util/service.c:186 +#: src/util/service.c:207 src/util/service.c:214 +#, c-format +msgid "Invalid format for IP: `%s'\n" +msgstr "" + +#: src/util/service.c:170 +#, c-format +msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." +msgstr "" + +#: src/util/service.c:263 +#, c-format +msgid "Invalid network notation (does not end with ';': `%s')\n" +msgstr "" + +#: src/util/service.c:296 +#, c-format +msgid "Wrong format `%s' for netmask\n" +msgstr "" + +#: src/util/service.c:326 +#, c-format +msgid "Wrong format `%s' for network\n" +msgstr "" + +#: src/util/service.c:668 +#, c-format +msgid "Access denied to UID %d / GID %d\n" +msgstr "" + +#: src/util/service.c:673 +#, c-format +msgid "Unknown address family %d\n" +msgstr "" + +#: src/util/service.c:680 +#, c-format +msgid "Access from `%s' denied to service `%s'\n" +msgstr "" + +#: src/util/service.c:724 +#, c-format +msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:752 +#, c-format +msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:869 +#, c-format +msgid "" +"Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" +msgstr "" + +#: src/util/service.c:939 +#, c-format +msgid "" +"Disabling UNIX domain socket support for service `%s', failed to create UNIX " +"domain socket: %s\n" +msgstr "" + +#: src/util/service.c:956 +#, c-format +msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" +msgstr "" + +#: src/util/service.c:1191 +msgid "Could not access a pre-bound socket, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1242 src/util/service.c:1260 +#, c-format +msgid "Specified value for `%s' of service `%s' is invalid\n" +msgstr "" + +#: src/util/service.c:1287 +#, c-format +msgid "Could not access pre-bound socket %u, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1442 +#, c-format +msgid "Failed to start `%s' at `%s'\n" +msgstr "" + +#: src/util/service.c:1475 +#, c-format +msgid "Service `%s' runs at %s\n" +msgstr "" + +#: src/util/service.c:1521 +msgid "Service process failed to initialize\n" +msgstr "" + +#: src/util/service.c:1525 +msgid "Service process could not initialize server function\n" +msgstr "" + +#: src/util/service.c:1529 +msgid "Service process failed to report status\n" +msgstr "" + +#: src/util/service.c:1581 +msgid "No such user" +msgstr "" + +#: src/util/service.c:1594 +#, c-format +msgid "Cannot change user/group to `%s': %s\n" +msgstr "" + +#: src/util/service.c:1657 +msgid "do daemonize (detach from terminal)" +msgstr "" + +#: src/util/signal.c:80 +#, c-format +msgid "signal (%d, %p) returned %d.\n" +msgstr "" + +#: src/util/strings.c:143 +msgid "b" +msgstr "" + +#: src/util/strings.c:354 +#, c-format +msgid "Character sets requested were `%s'->`%s'\n" +msgstr "" + +#: src/util/strings.c:462 +msgid "Failed to expand `$HOME': environment variable `HOME' not set" +msgstr "" + +#: src/util/strings.c:554 +msgid "ms" +msgstr "" + +#: src/util/strings.c:559 +msgid "eternity" +msgstr "" + +#: src/util/strings.c:563 +msgid "s" +msgstr "" + +#: src/util/strings.c:567 +msgid "m" +msgstr "" + +#: src/util/strings.c:571 +msgid "h" +msgstr "" + +#: src/util/strings.c:575 +msgid " days" +msgstr "" + +#: src/util/strings.c:599 +msgid "end of time" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1065 +msgid "# Active tunnels" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 +msgid "# Peers connected to mesh tunnels" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:699 +msgid "# Bytes given to mesh for transmission" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:737 +msgid "# Bytes dropped in mesh queue (overflow)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:772 +msgid "# Mesh tunnels created" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:795 +msgid "Failed to setup mesh tunnel!\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:967 +#, c-format +msgid "Protocol %u not supported, dropping\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1285 +msgid "# ICMPv4 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1306 +msgid "# ICMPv6 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1511 +msgid "# Packets received from TUN interface" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1549 src/vpn/gnunet-service-vpn.c:1590 +#, c-format +msgid "Packet received for unmapped destination `%s' (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1600 +msgid "Received IPv4 packet with options (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1614 +#, c-format +msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1697 +msgid "# ICMP packets received from mesh" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2038 +msgid "# UDP packets received from mesh" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2196 +msgid "# TCP packets received from mesh" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2347 +msgid "Failed to find unallocated IPv4 address in VPN's range\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2402 +msgid "Failed to find unallocated IPv6 address in VPN's range\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2441 src/vpn/gnunet-service-vpn.c:2624 +msgid "# Active destinations" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2726 +msgid "Failed to allocate IP address for new destination\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3133 +msgid "IPv6 support disabled as this system does not support IPv6\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3165 +msgid "IPv4 support disabled as this system does not support IPv4\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:151 +msgid "Error creating tunnel\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 +#, c-format +msgid "Option `%s' makes no sense with option `%s'.\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:208 +#, c-format +msgid "Option `%s' or `%s' is required.\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:220 +#, c-format +msgid "Option `%s' or `%s' is required when using option `%s'.\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:238 +#, c-format +msgid "`%s' is not a valid peer identifier.\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:260 +#, c-format +msgid "`%s' is not a valid IP address.\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:296 +msgid "request that result should be an IPv4 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:299 +msgid "request that result should be an IPv6 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:302 +msgid "print IP address only after mesh tunnel has been created" +msgstr "" + +#: src/vpn/gnunet-vpn.c:305 +msgid "how long should the mapping be valid for new tunnels?" +msgstr "" + +#: src/vpn/gnunet-vpn.c:308 +msgid "destination IP for the tunnel" +msgstr "" + +#: src/vpn/gnunet-vpn.c:311 +msgid "peer offering the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:314 +msgid "name of the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:317 +msgid "service is offered via TCP" +msgstr "" + +#: src/vpn/gnunet-vpn.c:320 +msgid "service is offered via UDP" +msgstr "" + +#: src/vpn/gnunet-vpn.c:329 +msgid "Setup tunnels via VPN." +msgstr "" + +#: src/include/gnunet_common.h:479 src/include/gnunet_common.h:484 +#: src/include/gnunet_common.h:490 +#, c-format +msgid "Assertion failed at %s:%d.\n" +msgstr "" + +#: src/include/gnunet_common.h:500 +#, c-format +msgid "External protocol violation detected at %s:%d.\n" +msgstr "" + +#: src/include/gnunet_common.h:521 src/include/gnunet_common.h:528 +#, c-format +msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" +msgstr "" diff --git a/po/insert-header.sin b/po/insert-header.sin new file mode 100644 index 0000000..b26de01 --- /dev/null +++ b/po/insert-header.sin @@ -0,0 +1,23 @@ +# Sed script that inserts the file called HEADER before the header entry. +# +# At each occurrence of a line starting with "msgid ", we execute the following +# commands. At the first occurrence, insert the file. At the following +# occurrences, do nothing. The distinction between the first and the following +# occurrences is achieved by looking at the hold space. +/^msgid /{ +x +# Test if the hold space is empty. +s/m/m/ +ta +# Yes it was empty. First occurrence. Read the file. +r HEADER +# Output the file's contents by reading the next line. But don't lose the +# current line while doing this. +g +N +bb +:a +# The hold space was nonempty. Following occurrences. Do nothing. +x +:b +} diff --git a/po/quot.sed b/po/quot.sed new file mode 100644 index 0000000..0122c46 --- /dev/null +++ b/po/quot.sed @@ -0,0 +1,6 @@ +s/"\([^"]*\)"/“\1â€/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“â€/""/g diff --git a/po/remove-potcdate.sin b/po/remove-potcdate.sin new file mode 100644 index 0000000..2436c49 --- /dev/null +++ b/po/remove-potcdate.sin @@ -0,0 +1,19 @@ +# Sed script that remove the POT-Creation-Date line in the header entry +# from a POT file. +# +# The distinction between the first and the following occurrences of the +# pattern is achieved by looking at the hold space. +/^"POT-Creation-Date: .*"$/{ +x +# Test if the hold space is empty. +s/P/P/ +ta +# Yes it was empty. First occurrence. Remove the line. +g +d +bb +:a +# The hold space was nonempty. Following occurrences. Do nothing. +x +:b +} diff --git a/po/stamp-po b/po/stamp-po new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/po/stamp-po @@ -0,0 +1 @@ +timestamp diff --git a/po/sv.gmo b/po/sv.gmo new file mode 100644 index 0000000..8e049a7 Binary files /dev/null and b/po/sv.gmo differ diff --git a/po/sv.po b/po/sv.po new file mode 100644 index 0000000..b475a4e --- /dev/null +++ b/po/sv.po @@ -0,0 +1,7275 @@ +# Swedish translation of GNUnet. +# Copyright (C) 2006 Free Software Foundation, Inc. +# This file is distributed under the same license as the GNUnet package. +# Daniel Nylander , 2006. +# +msgid "" +msgstr "" +"Project-Id-Version: GNUnet 0.7.0b\n" +"Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" +"POT-Creation-Date: 2012-02-28 18:30+0100\n" +"PO-Revision-Date: 2006-01-21 17:16+0100\n" +"Last-Translator: Daniel Nylander \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/arm/arm_api.c:187 +msgid "Failed to transmit shutdown request to client.\n" +msgstr "" + +#: src/arm/arm_api.c:378 +#, fuzzy, c-format +msgid "Configuration failes to specify option `%s' in section `%s'!\n" +msgstr "Konfigurationsfil \"%s\" hittades inte. Kör \"gnunet-setup -d\"!\n" + +#: src/arm/arm_api.c:392 +#, fuzzy, c-format +msgid "Configuration fails to specify option `%s' in section `%s'!\n" +msgstr "Konfigurationsfil \"%s\" skapad.\n" + +#: src/arm/arm_api.c:467 +#, c-format +msgid "Error receiving response to `%s' request from ARM for service `%s'\n" +msgstr "" + +#: src/arm/arm_api.c:523 +#, c-format +msgid "Requesting start of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:524 +#, c-format +msgid "Requesting termination of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:546 +#, c-format +msgid "Error while trying to transmit request to start `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:548 +#, c-format +msgid "Error while trying to transmit request to stop `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:581 +#, fuzzy, c-format +msgid "Asked to start service `%s' within %llu ms\n" +msgstr "\"%s\": Mottog inte meddelande inom %llu ms.\n" + +#: src/arm/arm_api.c:654 +#, fuzzy, c-format +msgid "Stopping service `%s' within %llu ms\n" +msgstr "Inget svar mottaget inom %llums.\n" + +#: src/arm/gnunet-arm.c:149 +#, fuzzy, c-format +msgid "Service `%s' is unknown to ARM.\n" +msgstr "\"%s\" är inte en fil.\n" + +#: src/arm/gnunet-arm.c:154 +#, fuzzy, c-format +msgid "Service `%s' has been stopped.\n" +msgstr "Tjänst borttagen.\n" + +#: src/arm/gnunet-arm.c:157 +#, fuzzy, c-format +msgid "Service `%s' was already running.\n" +msgstr "\"%s\" är inte en fil.\n" + +#: src/arm/gnunet-arm.c:162 +#, fuzzy, c-format +msgid "Service `%s' has been started.\n" +msgstr "Tjänst borttagen.\n" + +#: src/arm/gnunet-arm.c:165 +#, fuzzy, c-format +msgid "Service `%s' was already being stopped.\n" +msgstr "Tjänst borttagen.\n" + +#: src/arm/gnunet-arm.c:169 +#, fuzzy, c-format +msgid "Service `%s' was already not running.\n" +msgstr "\"%s\" är inte en fil.\n" + +#: src/arm/gnunet-arm.c:173 +msgid "Request ignored as ARM is shutting down.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:177 +#, fuzzy +msgid "Error communicating with ARM service.\n" +msgstr "Skriv ut information om GNUnets motparter." + +#: src/arm/gnunet-arm.c:181 +#, fuzzy +msgid "Timeout communicating with ARM service.\n" +msgstr "Skriv ut information om GNUnets motparter." + +#: src/arm/gnunet-arm.c:185 +#, fuzzy +msgid "Operation failed.\n" +msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" + +#: src/arm/gnunet-arm.c:189 +msgid "Unknown response code from ARM.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:216 +#, c-format +msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:224 src/arm/gnunet-arm.c:324 +msgid "Fatal error initializing ARM API.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:247 +#, fuzzy, c-format +msgid "Failed to remove configuration file %s\n" +msgstr "Kunde inte spara konfigurationsfil \"%s\":" + +#: src/arm/gnunet-arm.c:253 +#, fuzzy, c-format +msgid "Failed to remove servicehome directory %s\n" +msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" + +#: src/arm/gnunet-arm.c:355 +msgid "stop all GNUnet services" +msgstr "" + +#: src/arm/gnunet-arm.c:357 +msgid "start a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:359 +msgid "stop a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:361 +msgid "start all GNUnet default services" +msgstr "" + +#: src/arm/gnunet-arm.c:364 +msgid "stop and start all GNUnet default services" +msgstr "" + +#: src/arm/gnunet-arm.c:367 +msgid "delete config file and directory on exit" +msgstr "" + +#: src/arm/gnunet-arm.c:369 +msgid "don't print status messages" +msgstr "" + +#: src/arm/gnunet-arm.c:372 +msgid "timeout for completing current operation" +msgstr "" + +#: src/arm/gnunet-arm.c:383 +msgid "Control services and the Automated Restart Manager (ARM)" +msgstr "" + +#: src/arm/gnunet-service-arm.c:328 +#, fuzzy, c-format +msgid "Failed to start service `%s'\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/arm/gnunet-service-arm.c:331 +#, fuzzy, c-format +msgid "Starting service `%s'\n" +msgstr "Startade samling \"%s\".\n" + +#: src/arm/gnunet-service-arm.c:357 +#, fuzzy +msgid "Could not send status result to client\n" +msgstr "Kunde inte skicka begäran till gnunetd.\n" + +#: src/arm/gnunet-service-arm.c:484 +#, fuzzy, c-format +msgid "Unable to create socket for service `%s': %s\n" +msgstr "Kunde inte skapa användarkonto:" + +#: src/arm/gnunet-service-arm.c:506 +#, c-format +msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:520 +#, c-format +msgid "ARM now monitors connections to service `%s' at `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:628 +#, fuzzy, c-format +msgid "Preparing to stop `%s'\n" +msgstr "Startade samling \"%s\".\n" + +#: src/arm/gnunet-service-arm.c:782 +#, fuzzy, c-format +msgid "Restarting service `%s'.\n" +msgstr "Startade samling \"%s\".\n" + +#: src/arm/gnunet-service-arm.c:877 +msgid "exit" +msgstr "" + +#: src/arm/gnunet-service-arm.c:882 +msgid "signal" +msgstr "" + +#: src/arm/gnunet-service-arm.c:887 +#, fuzzy +msgid "unknown" +msgstr "Okänt fel" + +#: src/arm/gnunet-service-arm.c:921 +#, c-format +msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:967 src/arm/mockup-service.c:41 +#, fuzzy +msgid "Failed to transmit shutdown ACK.\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/arm/gnunet-service-arm.c:1067 +#, fuzzy, c-format +msgid "Configuration file `%s' for service `%s' not valid: %s\n" +msgstr "Konfigurationsfil \"%s\" skapad.\n" + +#: src/arm/gnunet-service-arm.c:1069 +msgid "option missing" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1152 +#, fuzzy, c-format +msgid "Starting default services `%s'\n" +msgstr "Startade samling \"%s\".\n" + +#: src/arm/gnunet-service-arm.c:1163 +#, c-format +msgid "Default service `%s' not configured correctly!\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1177 +msgid "" +"No default services configured, GNUnet will not really start right now.\n" +msgstr "" + +#: src/arm/mockup-service.c:46 +msgid "Transmitting shutdown ACK.\n" +msgstr "" + +#: src/arm/mockup-service.c:69 +msgid "Initiating shutdown as requested by client.\n" +msgstr "" + +#: src/block/block.c:105 +#, fuzzy, c-format +msgid "Loading block plugin `%s'\n" +msgstr "Testar transport(er) %s\n" + +#: src/chat/chat.c:175 +#, fuzzy +msgid "Could not transmit confirmation receipt\n" +msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" + +#: src/chat/chat.c:283 +msgid "The current user must be the the first one joined\n" +msgstr "" + +#: src/chat/chat.c:412 +#, fuzzy, c-format +msgid "Unknown message type: '%u'\n" +msgstr "Okänd operation \"%s\"\n" + +#: src/chat/chat.c:472 +#, fuzzy, c-format +msgid "Configuration option `%s' in section `%s' missing\n" +msgstr "Konfigurationsfil \"%s\" skapad.\n" + +#: src/chat/chat.c:480 +#, fuzzy, c-format +msgid "Failed to access chat home directory `%s'\n" +msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" + +#: src/chat/chat.c:498 +#, fuzzy, c-format +msgid "Failed to create/open key in file `%s'\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/chat/chat.c:559 +#, fuzzy +msgid "Could not serialize metadata\n" +msgstr "Kunde inte initiera libgnunetutil!\n" + +#: src/chat/chat.c:674 +#, fuzzy +msgid "Failed to connect to the chat service\n" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/chat/chat.c:680 +msgid "Undefined mandatory parameter: joinCallback\n" +msgstr "" + +#: src/chat/chat.c:686 +msgid "Undefined mandatory parameter: messageCallback\n" +msgstr "" + +#: src/chat/chat.c:692 +msgid "Undefined mandatory parameter: memberCallback\n" +msgstr "" + +#: src/chat/gnunet-chat.c:92 +msgid "Joined\n" +msgstr "" + +#: src/chat/gnunet-chat.c:124 +msgid "anonymous" +msgstr "" + +#: src/chat/gnunet-chat.c:130 +#, fuzzy, c-format +msgid "(%s) `%s' said: %s\n" +msgstr "\"%s\" %s misslyckades: %s\n" + +#: src/chat/gnunet-chat.c:133 src/chat/gnunet-chat.c:136 +#, fuzzy, c-format +msgid "(%s) `%s' said to you: %s\n" +msgstr "\"%s\" %s misslyckades: %s\n" + +# drive = hard drive ? +#: src/chat/gnunet-chat.c:139 +#, fuzzy, c-format +msgid "(%s) `%s' said for sure: %s\n" +msgstr "\"%s\" misslyckades för enhet %s: %u\n" + +# drive = hard drive ? +#: src/chat/gnunet-chat.c:142 +#, fuzzy, c-format +msgid "(%s) `%s' said to you for sure: %s\n" +msgstr "\"%s\" misslyckades för enhet %s: %u\n" + +#: src/chat/gnunet-chat.c:145 +#, c-format +msgid "(%s) `%s' was confirmed that you received: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:148 +#, c-format +msgid "(%s) `%s' was confirmed that you and only you received: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:151 +#, c-format +msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:156 +#, c-format +msgid "" +"(%s) `%s' was confirmed that you and only you received from him or her: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:159 +#, fuzzy, c-format +msgid "(%s) `%s' said off the record: %s\n" +msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" + +#: src/chat/gnunet-chat.c:162 +#, c-format +msgid "(%s) <%s> said using an unknown message type: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:193 +#, c-format +msgid "'%s' acknowledged message #%d\n" +msgstr "" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' entered the room\n" +msgstr "" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' left the room\n" +msgstr "" + +#: src/chat/gnunet-chat.c:284 src/chat/gnunet-chat.c:316 +#, fuzzy +msgid "Could not change username\n" +msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" + +#: src/chat/gnunet-chat.c:288 src/chat/gnunet-chat.c:630 +#, fuzzy, c-format +msgid "Joining room `%s' as user `%s'...\n" +msgstr "Ogiltigt svar till \"%s\" frÃ¥n motpart \"%s\".\n" + +#: src/chat/gnunet-chat.c:320 +#, fuzzy, c-format +msgid "Changed username to `%s'\n" +msgstr "Kan inte ändra användare/grupp till \"%s\": %s\n" + +#: src/chat/gnunet-chat.c:333 +#, c-format +msgid "Users in room `%s': " +msgstr "" + +#: src/chat/gnunet-chat.c:371 +msgid "Syntax: /msg USERNAME MESSAGE" +msgstr "" + +#: src/chat/gnunet-chat.c:379 +#, fuzzy, c-format +msgid "Unknown user `%s'\n" +msgstr "Okänd operation \"%s\"\n" + +#: src/chat/gnunet-chat.c:395 +#, c-format +msgid "User `%s' is currently not in the room!\n" +msgstr "" + +#: src/chat/gnunet-chat.c:448 +#, fuzzy, c-format +msgid "Unknown command `%s'\n" +msgstr "Okänd operation \"%s\"\n" + +#: src/chat/gnunet-chat.c:459 +msgid "" +"Use `/join #roomname' to join a chat room. Joining a room will cause you to " +"leave the current room" +msgstr "" + +#: src/chat/gnunet-chat.c:463 +msgid "" +"Use `/nick nickname' to change your nickname. This will cause you to leave " +"the current room and immediately rejoin it with the new name." +msgstr "" + +#: src/chat/gnunet-chat.c:467 +msgid "" +"Use `/msg nickname message' to send a private message to the specified user" +msgstr "" + +#: src/chat/gnunet-chat.c:470 +msgid "The `/notice' command is an alias for `/msg'" +msgstr "" + +#: src/chat/gnunet-chat.c:472 +msgid "The `/query' command is an alias for `/msg'" +msgstr "" + +#: src/chat/gnunet-chat.c:474 +msgid "Use `/sig message' to send a signed public message" +msgstr "" + +#: src/chat/gnunet-chat.c:477 +msgid "Use `/ack message' to require signed acknowledgment of the message" +msgstr "" + +#: src/chat/gnunet-chat.c:480 +msgid "Use `/anonymous message' to send a public anonymous message" +msgstr "" + +#: src/chat/gnunet-chat.c:482 +msgid "The `/anon' command is an alias for `/anonymous'" +msgstr "" + +#: src/chat/gnunet-chat.c:484 +msgid "Use `/quit' to terminate gnunet-chat" +msgstr "" + +#: src/chat/gnunet-chat.c:486 +msgid "The `/leave' command is an alias for `/quit'" +msgstr "" + +#: src/chat/gnunet-chat.c:489 +msgid "Use `/names' to list all of the current members in the chat room" +msgstr "" + +#: src/chat/gnunet-chat.c:491 +msgid "Use `/help command' to get help for a specific command" +msgstr "" + +#: src/chat/gnunet-chat.c:606 +#, fuzzy +msgid "You must specify a nickname\n" +msgstr "Du mÃ¥ste ange en mottagare!\n" + +#: src/chat/gnunet-chat.c:622 +#, fuzzy, c-format +msgid "Failed to join room `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/chat/gnunet-chat.c:655 +msgid "set the nickname to use (required)" +msgstr "" + +#: src/chat/gnunet-chat.c:658 +msgid "set the chat room to join" +msgstr "" + +#: src/chat/gnunet-chat.c:670 +msgid "Join a chat on GNUnet." +msgstr "" + +#: src/chat/gnunet-service-chat.c:267 +#, fuzzy +msgid "Failed to queue a message notification\n" +msgstr "Kunde inte spara konfiguration!" + +#: src/chat/gnunet-service-chat.c:546 +#, fuzzy +msgid "Failed to queue a join notification\n" +msgstr "Kunde inte spara konfiguration!" + +#: src/chat/gnunet-service-chat.c:729 +#, fuzzy +msgid "Failed to queue a confirmation receipt\n" +msgstr "Kunde inte spara konfiguration!" + +#: src/chat/gnunet-service-chat.c:907 +#, fuzzy +msgid "Failed to queue a leave notification\n" +msgstr "Kunde inte spara konfiguration!" + +#: src/core/core_api.c:798 +msgid "Client was disconnected from core service, trying to reconnect.\n" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:77 +#: src/peerinfo-tool/gnunet-peerinfo.c:60 +#, fuzzy, c-format +msgid "Peer `%s'\n" +msgstr "Jag är ändpunkt \"%s\".\n" + +#: src/core/gnunet-core-list-connections.c:175 +#: src/peerinfo-tool/gnunet-peerinfo.c:194 +#, fuzzy, c-format +msgid "Invalid command line argument `%s'\n" +msgstr "Ogiltiga kommandoradsargument:\n" + +#: src/core/gnunet-core-list-connections.c:196 +#: src/peerinfo-tool/gnunet-peerinfo.c:252 +msgid "don't resolve host names" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:203 +#, fuzzy +msgid "Print information about connected peers." +msgstr "Skriv ut information om GNUnets motparter." + +#: src/core/gnunet-service-core.c:99 +#, c-format +msgid "Core service of `%4s' ready.\n" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:360 +msgid "# send requests dropped (disconnected)" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:465 +#, fuzzy +msgid "# messages discarded (session disconnected)" +msgstr "Nätverksannonsering avstängd i konfigurationen!\n" + +#: src/core/gnunet-service-core_clients.c:801 +#, fuzzy, c-format +msgid "# bytes of messages of type %u received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/core/gnunet-service-core_kx.c:493 +msgid "# bytes encrypted" +msgstr "# byte krypterade" + +#: src/core/gnunet-service-core_kx.c:543 +msgid "# bytes decrypted" +msgstr "# byte dekrypterade" + +#: src/core/gnunet-service-core_kx.c:604 src/dv/gnunet-service-dv.c:3002 +#: src/hostlist/hostlist-server.c:436 src/peerinfo-tool/gnunet-peerinfo.c:151 +#, fuzzy +msgid "Error in communication with PEERINFO service\n" +msgstr "Skriv ut information om GNUnets motparter." + +#: src/core/gnunet-service-core_kx.c:623 +msgid "# Delayed connecting due to lack of public key" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:673 +msgid "# key exchanges initiated" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:694 +msgid "# key exchanges stopped" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:746 +#, fuzzy +msgid "# session keys received" +msgstr "# sessionnycklar vägrade" + +#: src/core/gnunet-service-core_kx.c:765 +#, fuzzy, c-format +msgid "`%s' is for `%s', not for me. Ignoring.\n" +msgstr "storlek pÃ¥ \"%s\" meddelande är för litet. Ignorerar.\n" + +#: src/core/gnunet-service-core_kx.c:803 +#, fuzzy +msgid "# SET_KEY messages decrypted" +msgstr "# PING-meddelanden skapade" + +#: src/core/gnunet-service-core_kx.c:883 +#: src/transport/gnunet-service-transport_validation.c:803 +#, fuzzy +msgid "# PING messages received" +msgstr "# PING-meddelanden skapade" + +#: src/core/gnunet-service-core_kx.c:917 +#, c-format +msgid "" +"Received PING from `%s' for different identity: I am `%s', PONG identity: `" +"%s'\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:938 +#, fuzzy +msgid "# PONG messages created" +msgstr "# PING-meddelanden skapade" + +#: src/core/gnunet-service-core_kx.c:1026 +#, fuzzy +msgid "# sessions terminated by timeout" +msgstr "# byte kastade via TCP (utgÃ¥ende)" + +#: src/core/gnunet-service-core_kx.c:1037 +#, fuzzy +msgid "# keepalive messages sent" +msgstr "# PING-meddelanden i klartext skickade" + +#: src/core/gnunet-service-core_kx.c:1095 +#: src/transport/gnunet-service-transport_validation.c:1026 +#, fuzzy +msgid "# PONG messages received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/core/gnunet-service-core_kx.c:1125 +#, fuzzy +msgid "# PONG messages decrypted" +msgstr "# PING-meddelanden skapade" + +#: src/core/gnunet-service-core_kx.c:1157 +#, fuzzy +msgid "# session keys confirmed via PONG" +msgstr "# sessionnycklar vägrade" + +#: src/core/gnunet-service-core_kx.c:1223 +#, fuzzy +msgid "# SET_KEY and PING messages created" +msgstr "# PING-meddelanden skapade" + +#: src/core/gnunet-service-core_kx.c:1364 +msgid "# failed to decrypt message (no session key)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1406 +#: src/core/gnunet-service-core_kx.c:1431 +#, fuzzy +msgid "# bytes dropped (duplicates)" +msgstr "# byte kastade via UDP (utgÃ¥ende)" + +#: src/core/gnunet-service-core_kx.c:1418 +#, fuzzy +msgid "# bytes dropped (out of sequence)" +msgstr "# byte kastade via UDP (utgÃ¥ende)" + +#: src/core/gnunet-service-core_kx.c:1455 +#, fuzzy, c-format +msgid "Message received far too old (%llu ms). Content ignored.\n" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/core/gnunet-service-core_kx.c:1459 +#, fuzzy +msgid "# bytes dropped (ancient message)" +msgstr "# byte kastade via UDP (utgÃ¥ende)" + +#: src/core/gnunet-service-core_kx.c:1467 +#, fuzzy +msgid "# bytes of payload decrypted" +msgstr "# byte dekrypterade" + +#: src/core/gnunet-service-core_kx.c:1528 +#, fuzzy +msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" +msgstr "GNUnet-konfiguration" + +#: src/core/gnunet-service-core_kx.c:1536 +msgid "Core service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1546 src/hostlist/hostlist-server.c:555 +#: src/peerinfo-tool/gnunet-peerinfo.c:202 +#: src/transport/gnunet-service-transport.c:595 +#, fuzzy +msgid "Could not access PEERINFO service. Exiting.\n" +msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" + +#: src/core/gnunet-service-core_neighbours.c:163 +#, fuzzy +msgid "# sessions terminated by transport disconnect" +msgstr "Nätverksannonsering avstängd i konfigurationen!\n" + +#: src/core/gnunet-service-core_neighbours.c:180 +#: src/core/gnunet-service-core_neighbours.c:342 +msgid "# neighbour entries allocated" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:251 +msgid "# encrypted bytes given to transport" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:430 +#, c-format +msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:208 +#: src/core/gnunet-service-core_sessions.c:273 +msgid "# entries in session map" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:238 +msgid "# type map refreshes sent" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:414 +msgid "# messages discarded (expired prior to transmission)" +msgstr "" + +#: src/core/gnunet-service-core_typemap.c:110 +#: src/core/gnunet-service-core_typemap.c:121 +#, fuzzy +msgid "# type maps received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/core/gnunet-service-core_typemap.c:151 +msgid "# updates to my type map" +msgstr "" + +#: src/datacache/datacache.c:118 src/datacache/datacache.c:255 +#: src/datastore/gnunet-service-datastore.c:854 +#, fuzzy +msgid "# bytes stored" +msgstr "# byte krypterade" + +#: src/datacache/datacache.c:144 src/datacache/datacache.c:151 +#: src/datastore/gnunet-service-datastore.c:1531 +#: src/datastore/gnunet-service-datastore.c:1542 +#, fuzzy, c-format +msgid "No `%s' specified for `%s' in configuration!\n" +msgstr "Inga applikationer definierade i konfiguration!\n" + +#: src/datacache/datacache.c:183 +#, c-format +msgid "Loading `%s' datacache plugin\n" +msgstr "" + +#: src/datacache/datacache.c:191 +#, fuzzy, c-format +msgid "Failed to load datacache plugin for `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/datacache/datacache.c:281 +#, fuzzy +msgid "# requests received" +msgstr "# byte mottogs via TCP" + +#: src/datacache/datacache.c:291 +msgid "# requests filtered by bloom filter" +msgstr "" + +#: src/datacache/plugin_datacache_mysql.c:103 +#: src/datacache/plugin_datacache_mysql.c:110 +#: src/datacache/plugin_datacache_mysql.c:517 +#: src/datacache/plugin_datacache_mysql.c:526 +#: src/datacache/plugin_datacache_mysql.c:598 +#: src/datacache/plugin_datacache_mysql.c:614 +#: src/datacache/plugin_datacache_sqlite.c:71 +#: src/datacache/plugin_datacache_sqlite.c:74 +#: src/datastore/plugin_datastore_mysql.c:139 +#: src/datastore/plugin_datastore_mysql.c:146 +#: src/datastore/plugin_datastore_mysql.c:613 +#: src/datastore/plugin_datastore_mysql.c:673 +#: src/datastore/plugin_datastore_mysql.c:685 +#: src/datastore/plugin_datastore_mysql.c:1362 +#: src/datastore/plugin_datastore_mysql.c:1376 +#: src/datastore/plugin_datastore_sqlite.c:61 +#: src/namestore/plugin_namestore_sqlite.c:49 src/util/crypto_ksk.c:49 +#: src/util/crypto_rsa.c:92 src/include/gnunet_common.h:507 +#: src/include/gnunet_common.h:514 +#, c-format +msgid "`%s' failed at %s:%d with error: %s\n" +msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" + +#: src/datacache/plugin_datacache_mysql.c:224 +#: src/datastore/plugin_datastore_mysql.c:316 +#, c-format +msgid "Trying to use file `%s' for MySQL configuration.\n" +msgstr "Försöker använda fil \"%s\" för MySQL-konfiguration.\n" + +#: src/datacache/plugin_datacache_mysql.c:230 +#: src/datastore/plugin_datastore_mysql.c:322 +#, fuzzy, c-format +msgid "Could not access file `%s': %s\n" +msgstr "Kunde inte köra \"%s\": %s\n" + +#: src/datacache/plugin_datacache_mysql.c:979 +msgid "MySQL datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_postgres.c:79 +#: src/datastore/plugin_datastore_postgres.c:93 +#, fuzzy, c-format +msgid "`%s:%s' failed at %s:%d with error: %s" +msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" + +#: src/datacache/plugin_datacache_postgres.c:149 +#, fuzzy, c-format +msgid "Unable to initialize Postgres: %s" +msgstr "Kunde inte initiera SQLite.\n" + +#: src/datacache/plugin_datacache_postgres.c:499 +msgid "Postgres datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:424 +msgid "Sqlite datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:457 +#: src/datastore/plugin_datastore_sqlite.c:414 +#: src/namestore/plugin_namestore_sqlite.c:381 +msgid "Tried to close sqlite without finalizing all prepared statements.\n" +msgstr "" + +#: src/datacache/plugin_datacache_template.c:121 +msgid "Template datacache running\n" +msgstr "" + +#: src/datastore/datastore_api.c:289 +#, fuzzy +msgid "Failed to transmit request to drop database.\n" +msgstr "Misslyckades att skicka HTTP-begäran till värd \"%s\": %s\n" + +#: src/datastore/datastore_api.c:372 +msgid "# queue entry timeouts" +msgstr "" + +#: src/datastore/datastore_api.c:418 +msgid "# queue overflows" +msgstr "" + +#: src/datastore/datastore_api.c:445 +#, fuzzy +msgid "# queue entries created" +msgstr "# PING-meddelanden skapade" + +#: src/datastore/datastore_api.c:465 +msgid "# Requests dropped from datastore queue" +msgstr "" + +#: src/datastore/datastore_api.c:513 +#, fuzzy +msgid "# datastore connections (re)created" +msgstr "Nätverksanslutning" + +#: src/datastore/datastore_api.c:540 +msgid "# reconnected to DATASTORE" +msgstr "" + +#: src/datastore/datastore_api.c:608 +#, fuzzy +msgid "# transmission request failures" +msgstr "# klartext PONG-meddelanden mottagna" + +#: src/datastore/datastore_api.c:631 +#, fuzzy +msgid "# bytes sent to datastore" +msgstr "# byte krypterade" + +#: src/datastore/datastore_api.c:772 +#, fuzzy +msgid "Failed to receive status response from database." +msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" + +#: src/datastore/datastore_api.c:786 +msgid "Error reading response from datastore service" +msgstr "" + +#: src/datastore/datastore_api.c:798 src/datastore/datastore_api.c:804 +#, fuzzy +msgid "Invalid error message received from datastore service" +msgstr "Ogiltigt meddelande mottogs den %s:%d." + +#: src/datastore/datastore_api.c:810 +#, fuzzy +msgid "# status messages received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/datastore/datastore_api.c:883 +msgid "# PUT requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:954 +msgid "# RESERVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1019 +msgid "# RELEASE RESERVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1080 +msgid "# UPDATE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1148 +msgid "# REMOVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1193 +#, fuzzy +msgid "Failed to receive response from database.\n" +msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" + +#: src/datastore/datastore_api.c:1253 +#, fuzzy +msgid "# Results received" +msgstr "# byte mottogs via TCP" + +#: src/datastore/datastore_api.c:1324 +msgid "# GET REPLICATION requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1391 +msgid "# GET ZERO ANONYMITY requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1455 +msgid "# GET requests executed" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:351 +#, fuzzy +msgid "# bytes expired" +msgstr "# byte mottogs via TCP" + +#: src/datastore/gnunet-service-datastore.c:426 +msgid "# bytes purged (low-priority)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:486 +msgid "Transmission to client failed!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:640 +msgid "# results found" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:685 +#, c-format +msgid "" +"Insufficient space (%llu bytes are available) to satisfy `%s' request for " +"%llu bytes\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:696 +#, c-format +msgid "" +"The requested amount (%llu bytes) is larger than the cache size (%llu " +"bytes)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:700 +msgid "" +"Insufficient space to satisfy request and requested amount is larger than " +"cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:706 +msgid "Insufficient space to satisfy request" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:711 +#: src/datastore/gnunet-service-datastore.c:765 +#: src/datastore/gnunet-service-datastore.c:986 +#: src/datastore/gnunet-service-datastore.c:1465 +msgid "# reserved" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:780 +msgid "Could not find matching reservation" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:868 +#, c-format +msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1034 +#, fuzzy +msgid "# GET requests received" +msgstr "# byte mottogs via TCP" + +#: src/datastore/gnunet-service-datastore.c:1048 +msgid "# requests filtered by bloomfilter" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1076 +#, fuzzy +msgid "# UPDATE requests received" +msgstr "# byte mottogs via TCP" + +#: src/datastore/gnunet-service-datastore.c:1110 +msgid "# GET REPLICATION requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1145 +msgid "# GET ZERO ANONYMITY requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1172 +#, fuzzy +msgid "Content not found" +msgstr "Kommando \"%s\" hittades inte!\n" + +#: src/datastore/gnunet-service-datastore.c:1182 +msgid "# bytes removed (explicit request)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1216 +#, fuzzy +msgid "# REMOVE requests received" +msgstr "# byte mottogs via TCP" + +#: src/datastore/gnunet-service-datastore.c:1260 +#, c-format +msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1323 +#, c-format +msgid "Loading `%s' datastore plugin\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1332 +#, fuzzy, c-format +msgid "Failed to load datastore plugin for `%s'\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/datastore/gnunet-service-datastore.c:1536 +#, fuzzy, c-format +msgid "# bytes used in file-sharing datastore `%s'" +msgstr "# byte krypterade" + +#: src/datastore/gnunet-service-datastore.c:1547 +msgid "# quota" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1549 +msgid "# cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1562 +#, c-format +msgid "Could not use specified filename `%s' for bloomfilter.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1580 +#: src/datastore/gnunet-service-datastore.c:1596 +#, fuzzy, c-format +msgid "Failed to remove bogus bloomfilter file `%s'\n" +msgstr "Kunde inte spara konfigurationsfil \"%s\":" + +#: src/datastore/gnunet-service-datastore.c:1626 +#, fuzzy +msgid "Failed to initialize bloomfilter.\n" +msgstr "Misslyckades att initiera tjänsten \"%s\".\n" + +#: src/datastore/gnunet-service-datastore.c:1655 +msgid "Rebuilding bloomfilter. Please be patient.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1660 +msgid "Plugin does not support get_keys function. Please fix!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1663 +msgid "Bloomfilter construction complete.\n" +msgstr "" + +#: src/datastore/plugin_datastore_mysql.c:529 +#: src/datastore/plugin_datastore_mysql.c:1336 +#, fuzzy, c-format +msgid "Failed to prepare statement `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/datastore/plugin_datastore_mysql.c:622 +#: src/datastore/plugin_datastore_mysql.c:1346 +#, fuzzy, c-format +msgid "`%s' for `%s' failed at %s:%d with error: %s\n" +msgstr "\"%s\" till \"%s\" misslyckades vid %s:%d med fel: %s\n" + +#: src/datastore/plugin_datastore_mysql.c:1581 +msgid "Mysql database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_postgres.c:173 +#, fuzzy, c-format +msgid "Unable to initialize Postgres with configuration `%s': %s" +msgstr "Kunde inte spara konfigurationsfil \"%s\":" + +#: src/datastore/plugin_datastore_postgres.c:1017 +msgid "Postgres database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:61 +#, fuzzy, c-format +msgid "`%s' failed at %s:%u with error: %s" +msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" + +#: src/datastore/plugin_datastore_sqlite.c:239 +#: src/namestore/plugin_namestore_sqlite.c:223 +#, fuzzy, c-format +msgid "Option `%s' in section `%s' missing in configuration!\n" +msgstr "Inga applikationer definierade i konfiguration!\n" + +#: src/datastore/plugin_datastore_sqlite.c:266 +#: src/namestore/plugin_namestore_sqlite.c:248 +#, fuzzy, c-format +msgid "Unable to initialize SQLite: %s.\n" +msgstr "Kunde inte initiera SQLite.\n" + +#: src/datastore/plugin_datastore_sqlite.c:669 +msgid "Invalid data in database. Trying to fix (by deletion).\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1159 +msgid "sqlite version to old to determine size, assuming zero\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1178 +#, c-format +msgid "" +"Using sqlite page utilization to estimate payload (%llu pages of size %llu " +"bytes)\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1218 +#: src/namestore/plugin_namestore_sqlite.c:779 +msgid "Sqlite database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_template.c:241 +msgid "Template database running\n" +msgstr "" + +#: src/dht/dht_api.c:280 +#, fuzzy +msgid "Failed to connect to the DHT service!\n" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-put.c:172 +#: src/gns/gnunet-gns-lookup.c:179 +msgid "the query key" +msgstr "" + +#: src/dht/gnunet-dht-get.c:204 src/gns/gnunet-gns-lookup.c:182 +msgid "how many parallel requests (replicas) to create" +msgstr "" + +#: src/dht/gnunet-dht-get.c:207 src/gns/gnunet-gns-lookup.c:185 +msgid "the type of data to look for" +msgstr "" + +#: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:181 +#: src/gns/gnunet-gns-lookup.c:188 +msgid "how long to execute this query before giving up?" +msgstr "" + +#: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-put.c:184 +#: src/fs/gnunet-download.c:270 src/fs/gnunet-publish.c:725 +#: src/fs/gnunet-search.c:297 src/fs/gnunet-unindex.c:169 +#: src/gns/gnunet-gns-lookup.c:191 src/nse/gnunet-nse-profiler.c:908 +msgid "be verbose (print progress information)" +msgstr "" + +#: src/dht/gnunet-dht-get.c:232 +msgid "Issue a GET request to the GNUnet DHT, prints results." +msgstr "" + +#: src/dht/gnunet-dht-put.c:100 +msgid "PUT request sent!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:124 +msgid "Must provide KEY and DATA for DHT put!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:132 +#, fuzzy, c-format +msgid "Could not connect to %s service!\n" +msgstr "Kunde inte ansluta till gnunetd.\n" + +#: src/dht/gnunet-dht-put.c:137 +#, fuzzy, c-format +msgid "Connected to %s service!\n" +msgstr "\"%s\" ansluten till \"%s\".\n" + +#: src/dht/gnunet-dht-put.c:152 +#, c-format +msgid "Issuing put request for `%s' with data `%s'!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:166 +msgid "the data to insert under the key" +msgstr "" + +#: src/dht/gnunet-dht-put.c:169 +msgid "how long to store this entry in the dht (in seconds)" +msgstr "" + +#: src/dht/gnunet-dht-put.c:175 +msgid "how many replicas to create" +msgstr "" + +#: src/dht/gnunet-dht-put.c:178 +msgid "the type to insert data as" +msgstr "" + +#: src/dht/gnunet-dht-put.c:203 +msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." +msgstr "" + +#: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:556 +#: src/testing/testing.c:1979 src/testing/testing.c:2009 +#, fuzzy +msgid "Failed to connect to transport service!\n" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/dht/gnunet-service-dht_clients.c:371 +#, fuzzy +msgid "# GET requests from clients injected" +msgstr "# byte mottogs via TCP" + +#: src/dht/gnunet-service-dht_clients.c:462 +#, fuzzy +msgid "# PUT requests received from clients" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/dht/gnunet-service-dht_clients.c:529 +#, fuzzy +msgid "# GET requests received from clients" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/dht/gnunet-service-dht_clients.c:624 +#, fuzzy +msgid "# GET STOP requests received from clients" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/dht/gnunet-service-dht_clients.c:854 +msgid "# Key match, type mismatches in REPLY to CLIENT" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:869 +msgid "# Duplicate REPLIES to CLIENT request dropped" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:906 +#, c-format +msgid "Unsupported block type (%u) in request!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:928 +#, fuzzy +msgid "# RESULTS queued for clients" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/dht/gnunet-service-dht_clients.c:979 +#: src/dht/gnunet-service-dht_clients.c:1022 +msgid "# REPLIES ignored for CLIENTS (no match)" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:989 +#, fuzzy +msgid "Could not pass reply to client, message too big!\n" +msgstr "Kunde inte skicka meddelande till gnunetd\n" + +#: src/dht/gnunet-service-dht_datacache.c:93 +#, fuzzy, c-format +msgid "%s request received, but have no datacache!\n" +msgstr "# byte mottagna av typen %d" + +#: src/dht/gnunet-service-dht_datacache.c:103 +msgid "# ITEMS stored in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:209 +msgid "# Good RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:220 +msgid "# Duplicate RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:226 +msgid "# Invalid RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:238 +msgid "# Unsupported RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:241 +#, c-format +msgid "Unsupported block type (%u) in local response!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:271 +#, fuzzy +msgid "# GET requests given to datacache" +msgstr "# byte mottogs via TCP" + +#: src/dht/gnunet-service-dht_hello.c:82 +#, fuzzy +msgid "# HELLOs obtained from peerinfo" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/dht/gnunet-service-dht_neighbours.c:481 +msgid "# Preference updates given to core" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:573 +#, fuzzy +msgid "# FIND PEER messages initiated" +msgstr "# PING-meddelanden skapade" + +#: src/dht/gnunet-service-dht_neighbours.c:629 +#: src/dht/gnunet-service-dht_neighbours.c:689 +#, fuzzy +msgid "# Peers connected" +msgstr "# av anslutna parter" + +#: src/dht/gnunet-service-dht_neighbours.c:723 +#, fuzzy +msgid "# Queued messages discarded (peer disconnected)" +msgstr "Nätverksannonsering avstängd i konfigurationen!\n" + +#: src/dht/gnunet-service-dht_neighbours.c:778 +#, fuzzy +msgid "# Bytes transmitted to other peers" +msgstr "# byte skickade av typen %d" + +#: src/dht/gnunet-service-dht_neighbours.c:816 +msgid "# Bytes of bandwdith requested from core" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1040 +#: src/dht/gnunet-service-dht_neighbours.c:1068 +msgid "# Peers excluded from routing due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1049 +#: src/dht/gnunet-service-dht_neighbours.c:1085 +msgid "# Peer selection failed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1221 +#, fuzzy +msgid "# PUT requests routed" +msgstr "# byte mottogs via TCP" + +#: src/dht/gnunet-service-dht_neighbours.c:1252 +#, fuzzy +msgid "# PUT messages queued for transmission" +msgstr "# PING-meddelanden skapade" + +#: src/dht/gnunet-service-dht_neighbours.c:1333 +#, fuzzy +msgid "# GET requests routed" +msgstr "# byte mottogs via TCP" + +#: src/dht/gnunet-service-dht_neighbours.c:1364 +#, fuzzy +msgid "# GET messages queued for transmission" +msgstr "# PING-meddelanden skapade" + +#: src/dht/gnunet-service-dht_neighbours.c:1467 +#, fuzzy +msgid "# RESULT messages queued for transmission" +msgstr "# PING-meddelanden skapade" + +#: src/dht/gnunet-service-dht_neighbours.c:1555 +#, fuzzy +msgid "# P2P PUT requests received" +msgstr "# byte mottogs via TCP" + +#: src/dht/gnunet-service-dht_neighbours.c:1668 +msgid "# FIND PEER requests ignored due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1676 +msgid "# FIND PEER requests ignored due to lack of HELLO" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1767 +#, fuzzy +msgid "# P2P GET requests received" +msgstr "# byte mottogs via TCP" + +#: src/dht/gnunet-service-dht_neighbours.c:1811 +#, fuzzy +msgid "# P2P FIND PEER requests processed" +msgstr "# byte mottogs via TCP" + +#: src/dht/gnunet-service-dht_neighbours.c:1825 +#, fuzzy +msgid "# P2P GET requests ONLY routed" +msgstr "# byte mottogs via TCP" + +#: src/dht/gnunet-service-dht_neighbours.c:1895 +#, fuzzy +msgid "# P2P RESULTS received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/dht/gnunet-service-dht_nse.c:59 +#, fuzzy +msgid "# Network size estimates received" +msgstr "# byte mottogs via TCP" + +#: src/dht/gnunet-service-dht_routing.c:211 +msgid "# Good REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:220 +msgid "# Duplicate REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:226 +msgid "# Invalid REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:236 +msgid "# Unsupported REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:314 +#: src/dht/gnunet-service-dht_routing.c:368 +msgid "# Entries removed from routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:324 +msgid "# Entries added to routing table" +msgstr "" + +#: src/dht/plugin_block_dht.c:124 +#, fuzzy, c-format +msgid "Block not of type %u\n" +msgstr "Ingen transport av typ %d är känd.\n" + +#: src/dht/plugin_block_dht.c:131 +msgid "Size mismatch for block\n" +msgstr "" + +#: src/dht/plugin_block_dht.c:140 +#, c-format +msgid "Block of type %u is malformed\n" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:337 +msgid "only monitor DNS queries" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:340 +msgid "only monitor DNS replies" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:348 +msgid "Monitor DNS queries." +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:236 +msgid "set A records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:239 +msgid "set AAAA records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:247 +msgid "Change DNS replies to point elsewhere." +msgstr "" + +#: src/dns/gnunet-service-dns.c:480 +#, fuzzy, c-format +msgid "Could not bind to any port: %s\n" +msgstr "Kunde inte köra \"%s\": %s\n" + +#: src/dns/gnunet-service-dns.c:634 +msgid "# DNS requests answered via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:818 +msgid "# DNS exit failed (failed to open socket)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1001 +#, c-format +msgid "Received DNS response that is too small (%u bytes)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1046 +msgid "# External DNS response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1165 +msgid "# Client response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1198 +msgid "Changing DNS reply according to client specifications\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1279 +msgid "Received malformed IPv4-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1294 +msgid "Received malformed IPv6-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1303 +#, c-format +msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1312 +msgid "# Non-DNS UDP packet received via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1377 +#, fuzzy +msgid "# DNS requests received via TUN interface" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/dns/gnunet-service-dns.c:1461 +#, c-format +msgid "Configured DNS exit `%s' is not working / valid.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1493 src/exit/gnunet-daemon-exit.c:2673 +msgid "# Inbound MESH tunnels created" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1567 +msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" +msgstr "" + +#: src/dv/dv_api.c:179 +#, fuzzy +msgid "Failed to connect to the dv service!\n" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/dv/plugin_transport_dv.c:159 +#, fuzzy, c-format +msgid "%s Received message from %s of type %d, distance %u!\n" +msgstr "Mottog skadat meddelande frÃ¥n motpart \"%s\"i %s:%d.\n" + +#: src/exit/gnunet-daemon-exit.c:508 +#, c-format +msgid "Got duplicate service records for `%s:%u'\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:563 +#, fuzzy +msgid "# Bytes transmitted via mesh tunnels" +msgstr "# byte skickade av typen %d" + +#: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2068 +#: src/exit/gnunet-daemon-exit.c:2318 src/vpn/gnunet-service-vpn.c:1388 +#: src/vpn/gnunet-service-vpn.c:1788 src/vpn/gnunet-service-vpn.c:1951 +msgid "# ICMPv4 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2127 +#: src/exit/gnunet-daemon-exit.c:2377 src/vpn/gnunet-service-vpn.c:1444 +#: src/vpn/gnunet-service-vpn.c:1847 src/vpn/gnunet-service-vpn.c:1984 +msgid "# ICMPv6 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:756 +msgid "# ICMP packets dropped (not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:763 +msgid "ICMP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:840 +msgid "UDP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:915 +msgid "TCP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:968 +#, fuzzy +msgid "# Packets received from TUN" +msgstr "# byte mottagna via HTTP" + +#: src/exit/gnunet-daemon-exit.c:982 +#, fuzzy +msgid "# Bytes received from TUN" +msgstr "# byte mottagna via HTTP" + +#: src/exit/gnunet-daemon-exit.c:1008 +msgid "IPv4 packet options received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1035 +#, c-format +msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1081 +#, c-format +msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1089 +#, c-format +msgid "Packet from unknown protocol %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1470 +#, fuzzy +msgid "# TCP packets sent via TUN" +msgstr "# byte skickade via UDP" + +#: src/exit/gnunet-daemon-exit.c:1570 +msgid "# TCP service creation requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1573 src/exit/gnunet-daemon-exit.c:1652 +#: src/exit/gnunet-daemon-exit.c:1762 src/exit/gnunet-daemon-exit.c:1992 +#: src/exit/gnunet-daemon-exit.c:2234 src/exit/gnunet-daemon-exit.c:2515 +#: src/exit/gnunet-daemon-exit.c:2615 +#, fuzzy +msgid "# Bytes received from MESH" +msgstr "# byte mottagna via HTTP" + +#: src/exit/gnunet-daemon-exit.c:1606 src/exit/gnunet-daemon-exit.c:2637 +#, c-format +msgid "No service found for %s on port %d!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1610 +#, fuzzy +msgid "# TCP requests dropped (no such service)" +msgstr "# byte mottogs via TCP" + +#: src/exit/gnunet-daemon-exit.c:1655 +#, fuzzy +msgid "# TCP IP-exit creation requests received via mesh" +msgstr "# byte mottogs via TCP" + +#: src/exit/gnunet-daemon-exit.c:1765 +#, fuzzy +msgid "# TCP data requests received via mesh" +msgstr "# byte mottogs via TCP" + +#: src/exit/gnunet-daemon-exit.c:1779 +#, fuzzy +msgid "# TCP DATA requests dropped (no session)" +msgstr "# byte mottogs via TCP" + +#: src/exit/gnunet-daemon-exit.c:1829 +#, fuzzy +msgid "# ICMP packets sent via TUN" +msgstr "# byte skickade via UDP" + +#: src/exit/gnunet-daemon-exit.c:1995 +#, fuzzy +msgid "# ICMP IP-exit requests received via mesh" +msgstr "# byte mottogs via TCP" + +#: src/exit/gnunet-daemon-exit.c:2237 +#, fuzzy +msgid "# ICMP service requests received via mesh" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/exit/gnunet-daemon-exit.c:2303 src/vpn/gnunet-service-vpn.c:1378 +#: src/vpn/gnunet-service-vpn.c:1945 +msgid "# ICMPv4 packets dropped (impossible PT to v6)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2362 src/vpn/gnunet-service-vpn.c:1414 +#: src/vpn/gnunet-service-vpn.c:1426 src/vpn/gnunet-service-vpn.c:1835 +msgid "# ICMPv6 packets dropped (impossible PT to v4)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2412 +#, fuzzy +msgid "# UDP packets sent via TUN" +msgstr "# byte skickade via UDP" + +#: src/exit/gnunet-daemon-exit.c:2518 +#, fuzzy +msgid "# UDP IP-exit requests received via mesh" +msgstr "# byte mottogs via TCP" + +#: src/exit/gnunet-daemon-exit.c:2618 +#, fuzzy +msgid "# UDP service requests received via mesh" +msgstr "# byte mottogs via TCP" + +#: src/exit/gnunet-daemon-exit.c:2641 +#, fuzzy +msgid "# UDP requests dropped (no such service)" +msgstr "# byte mottogs via TCP" + +#: src/exit/gnunet-daemon-exit.c:2881 +#, c-format +msgid "No addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2895 src/exit/gnunet-daemon-exit.c:2907 +#, c-format +msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2918 +#, c-format +msgid "No IP addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3047 +msgid "" +"This system does not support IPv4, will disable IPv4 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3055 +msgid "" +"This system does not support IPv6, will disable IPv6 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3062 +msgid "" +"Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " +"ENABLE_IPv4=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3068 +msgid "" +"Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " +"ENABLE_IPv6=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3074 src/pt/gnunet-daemon-pt.c:884 +msgid "No useful service enabled. Exiting.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3235 +msgid "Daemon to run to provide an IP exit node for the VPN" +msgstr "" + +#: src/fragmentation/defragmentation.c:270 +msgid "# acknowledgements sent for fragment" +msgstr "" + +#: src/fragmentation/defragmentation.c:454 +#, fuzzy +msgid "# fragments received" +msgstr "# byte mottogs via TCP" + +#: src/fragmentation/defragmentation.c:513 +#, fuzzy +msgid "# duplicate fragments received" +msgstr "# byte mottogs via TCP" + +#: src/fragmentation/defragmentation.c:526 +msgid "# messages defragmented" +msgstr "" + +#: src/fragmentation/fragmentation.c:188 +#, fuzzy +msgid "# fragments transmitted" +msgstr "# byte skickade av typen %d" + +#: src/fragmentation/fragmentation.c:191 +#, fuzzy +msgid "# fragments retransmitted" +msgstr "# byte skickade av typen %d" + +#: src/fragmentation/fragmentation.c:255 +msgid "# messages fragmented" +msgstr "" + +#: src/fragmentation/fragmentation.c:258 +msgid "# total size of fragmented messages" +msgstr "" + +#: src/fragmentation/fragmentation.c:343 +msgid "# fragment acknowledgements received" +msgstr "" + +#: src/fragmentation/fragmentation.c:349 +msgid "# bits removed from fragmentation ACKs" +msgstr "" + +#: src/fragmentation/fragmentation.c:373 +#, fuzzy +msgid "# fragmentation transmissions completed" +msgstr "# klartext PONG-meddelanden mottagna" + +#: src/fs/fs_api.c:284 +#, fuzzy, c-format +msgid "Could not open file `%s': %s" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/fs/fs_api.c:293 +#, fuzzy, c-format +msgid "Could not read file `%s': %s" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/fs/fs_api.c:299 +#, c-format +msgid "Short read reading from file `%s'!" +msgstr "" + +#: src/fs/fs_api.c:877 +#, fuzzy, c-format +msgid "Failed to resume publishing information `%s': %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/fs_api.c:1334 +#, c-format +msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" +msgstr "" + +#: src/fs/fs_api.c:1376 +#, c-format +msgid "Failure while resuming publishing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:1392 +#, fuzzy, c-format +msgid "Failed to resume publishing operation `%s': %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/fs_api.c:2004 +#, c-format +msgid "Failure while resuming unindexing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2014 +#, fuzzy, c-format +msgid "Failed to resume unindexing operation `%s': %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/fs_api.c:2139 src/fs/fs_api.c:2378 +#, fuzzy, c-format +msgid "Failed to resume sub-download `%s': %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/fs_api.c:2156 +#, fuzzy, c-format +msgid "Failed to resume sub-search `%s': %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/fs_api.c:2168 src/fs/fs_api.c:2187 src/fs/fs_api.c:2671 +#, c-format +msgid "Failure while resuming search operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2369 +#, c-format +msgid "Failed to resume sub-download `%s': could not open file `%s'\n" +msgstr "" + +#: src/fs/fs_api.c:2615 +msgid "Could not resume running search, will resume as paused search\n" +msgstr "" + +#: src/fs/fs_api.c:2709 +#, c-format +msgid "Failure while resuming download operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_directory.c:210 +#, fuzzy +msgid "MAGIC mismatch. This is not a GNUnet directory.\n" +msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" + +#: src/fs/fs_download.c:310 +msgid "" +"Recursive downloads of directories larger than 4 GB are not supported on 32-" +"bit systems\n" +msgstr "" + +#: src/fs/fs_download.c:330 +msgid "Directory too large for system address space\n" +msgstr "" + +#: src/fs/fs_download.c:488 src/fs/fs_download.c:500 +#, fuzzy, c-format +msgid "Failed to open file `%s' for writing" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/fs_download.c:870 +#, fuzzy, c-format +msgid "Failed to create directory for recursive download of `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/fs/fs_download.c:951 +#, c-format +msgid "" +"Internal error or bogus download URI (expected %u bytes at depth %u and " +"offset %llu/%llu, got %u bytes)\n" +msgstr "" + +#: src/fs/fs_download.c:977 +msgid "internal error decrypting content" +msgstr "" + +#: src/fs/fs_download.c:1000 +#, fuzzy, c-format +msgid "Download failed: could not open file `%s': %s\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/fs/fs_download.c:1010 +#, fuzzy, c-format +msgid "Failed to seek to offset %llu in file `%s': %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/fs_download.c:1019 +#, c-format +msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s\n" +msgstr "" + +#: src/fs/fs_download.c:1835 +#, fuzzy +msgid "Invalid URI" +msgstr "Ogiltiga argument: " + +#: src/fs/fs_getopt.c:191 +#, c-format +msgid "" +"Unknown metadata type in metadata option `%s'. Using metadata type " +"`unknown' instead.\n" +msgstr "" + +#: src/fs/fs_list_indexed.c:90 +#, fuzzy, c-format +msgid "Failed to receive response for `%s' request from `%s' service.\n" +msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" + +#: src/fs/fs_list_indexed.c:113 +#, fuzzy, c-format +msgid "Failed to receive valid response for `%s' request from `%s' service.\n" +msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" + +#: src/fs/fs_list_indexed.c:151 +#, fuzzy, c-format +msgid "Failed to not connect to `%s' service.\n" +msgstr "Misslyckades att initiera tjänsten \"%s\".\n" + +#: src/fs/fs_misc.c:126 +#, fuzzy, c-format +msgid "Did not find mime type `%s' in extension list.\n" +msgstr "Kunde inte hitta motpart \"%s\" i routingtabell!\n" + +#: src/fs/fs_namespace_advertise.c:150 +#, fuzzy +msgid "Unknown error" +msgstr "Okänt fel" + +#: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 +#, fuzzy +msgid "Failed to serialize meta data" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/fs_namespace_advertise.c:278 +#, fuzzy +msgid "Failed to connect to datastore service" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 +#, fuzzy, c-format +msgid "Configuration fails to specify `%s' in section `%s'\n" +msgstr "Konfigurationsfil \"%s\" skapad.\n" + +#: src/fs/fs_namespace.c:112 +#, fuzzy, c-format +msgid "Failed to open `%s' for writing: %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 +#, fuzzy, c-format +msgid "Failed to write `%s': %s\n" +msgstr "Fel vid %s:%d.\n" + +#: src/fs/fs_namespace.c:256 +#, fuzzy, c-format +msgid "Failed to create or read private key for namespace `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/fs/fs_namespace.c:371 +#, c-format +msgid "Failed to read namespace private key file `%s', deleting it!\n" +msgstr "" + +#: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 +#, fuzzy +msgid "Internal error." +msgstr "Okänt fel.\n" + +#: src/fs/fs_namespace.c:631 +#, fuzzy +msgid "Failed to connect to datastore." +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/fs/fs_publish.c:129 src/fs/fs_publish.c:395 +#, fuzzy, c-format +msgid "Publishing failed: %s" +msgstr "" +"\n" +"Fel vid uppladdning av fil: %s\n" + +#: src/fs/fs_publish.c:616 src/fs/fs_publish.c:633 src/fs/fs_publish.c:672 +#: src/fs/fs_publish.c:692 src/fs/fs_publish.c:717 src/fs/fs_publish.c:857 +#, fuzzy, c-format +msgid "Can not index file `%s': %s. Will try to insert instead.\n" +msgstr "Indexering av fil \"%s\" misslyckades. Försöker att infoga fil...\n" + +#: src/fs/fs_publish.c:618 +msgid "timeout on index-start request to `fs' service" +msgstr "" + +#: src/fs/fs_publish.c:630 +#, fuzzy +msgid "unknown error" +msgstr "Okänt fel" + +#: src/fs/fs_publish.c:673 +msgid "failed to compute hash" +msgstr "" + +#: src/fs/fs_publish.c:693 +msgid "filename too long" +msgstr "" + +#: src/fs/fs_publish.c:718 +#, fuzzy +msgid "could not connect to `fs' service" +msgstr "Kunde inte ansluta till gnunetd.\n" + +#: src/fs/fs_publish.c:741 +#, fuzzy, c-format +msgid "Failed to get file identifiers for `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/fs/fs_publish.c:806 +#, fuzzy, c-format +msgid "Recursive upload failed at `%s': %s" +msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" + +#: src/fs/fs_publish.c:812 +#, fuzzy, c-format +msgid "Recursive upload failed: %s" +msgstr "" +"\n" +"Fel vid uppladdning av fil: %s\n" + +#: src/fs/fs_publish.c:858 +msgid "needs to be an actual file" +msgstr "" + +#: src/fs/fs_publish.c:1067 +#, c-format +msgid "Insufficient space for publishing: %s" +msgstr "" + +#: src/fs/fs_publish.c:1138 +#, c-format +msgid "Reserving space for %u entries and %llu bytes for publication\n" +msgstr "" + +#: src/fs/fs_publish_ksk.c:258 +#, fuzzy +msgid "Could not connect to datastore." +msgstr "Kunde inte ansluta till gnunetd.\n" + +#: src/fs/fs_search.c:810 +#, c-format +msgid "Got result with unknown block type `%d', ignoring" +msgstr "" + +#: src/fs/fs_test_lib.c:269 +#, fuzzy, c-format +msgid "Failed to start daemon: %s\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/fs/fs_unindex.c:57 +msgid "Failed to find given position in file" +msgstr "" + +#: src/fs/fs_unindex.c:62 +#, fuzzy +msgid "Failed to read file" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/fs_unindex.c:231 +msgid "Unexpected time for a response from `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:239 +msgid "Timeout waiting for `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:247 +#, fuzzy +msgid "Invalid response from `fs' service." +msgstr "Ogiltigt svar till \"%s\" frÃ¥n \"%s\"\n" + +#: src/fs/fs_unindex.c:292 +#, fuzzy +msgid "Failed to connect to FS service for unindexing." +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/fs/fs_unindex.c:325 +#, fuzzy +msgid "Failed to connect to `datastore' service." +msgstr "Misslyckades att initiera tjänsten \"%s\".\n" + +#: src/fs/fs_unindex.c:338 +#, fuzzy +msgid "Failed to open file for unindexing." +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/fs/fs_unindex.c:372 +#, fuzzy +msgid "Failed to compute hash of file." +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/fs/fs_uri.c:220 +#, c-format +msgid "`%' must be followed by HEX number" +msgstr "" + +#: src/fs/fs_uri.c:279 +#, fuzzy +msgid "Malformed KSK URI (must not begin or end with `+')" +msgstr "Ogiltig URL \"%s\" (mÃ¥ste börja med \"%s\")\n" + +#: src/fs/fs_uri.c:297 +msgid "`++' not allowed in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:304 +msgid "Quotes not balanced in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 +msgid "Malformed SKS URI" +msgstr "" + +#: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 +msgid "Malformed CHK URI" +msgstr "" + +#: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 +#: src/fs/fs_uri.c:621 +msgid "SKS URI malformed" +msgstr "" + +#: src/fs/fs_uri.c:603 +msgid "SKS URI malformed (could not decode public key)" +msgstr "" + +#: src/fs/fs_uri.c:609 +msgid "SKS URI malformed (could not find signature)" +msgstr "" + +#: src/fs/fs_uri.c:615 +msgid "SKS URI malformed (could not decode signature)" +msgstr "" + +#: src/fs/fs_uri.c:628 +msgid "SKS URI malformed (could not parse expiration time)" +msgstr "" + +#: src/fs/fs_uri.c:640 +msgid "SKS URI malformed (signature failed validation)" +msgstr "" + +#: src/fs/fs_uri.c:678 +msgid "Unrecognized URI type" +msgstr "" + +#: src/fs/fs_uri.c:903 +#, fuzzy +msgid "Lacking key configuration settings.\n" +msgstr "GNUnet-konfiguration" + +#: src/fs/fs_uri.c:910 +#, fuzzy, c-format +msgid "Could not access hostkey file `%s'.\n" +msgstr "Kunde inte tolka konfigurationsfil \"%s\".\n" + +#: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 +msgid "No keywords specified!\n" +msgstr "Inga nyckelord angivna!\n" + +#: src/fs/fs_uri.c:1148 +msgid "Number of double-quotes not balanced!\n" +msgstr "" + +#: src/fs/gnunet-directory.c:49 +#, c-format +msgid "\t\n" +msgstr "" + +#: src/fs/gnunet-directory.c:94 +#, fuzzy, c-format +msgid "Directory `%s' meta data:\n" +msgstr "==> Katalog \"%s\":\n" + +#: src/fs/gnunet-directory.c:97 +#, fuzzy, c-format +msgid "Directory `%s' contents:\n" +msgstr "==> Katalog \"%s\":\n" + +#: src/fs/gnunet-directory.c:132 +#, fuzzy +msgid "You must specify a filename to inspect.\n" +msgstr "Du mÃ¥ste ange en lista av filer att lägga in.\n" + +#: src/fs/gnunet-directory.c:145 +#, fuzzy, c-format +msgid "Failed to read directory `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/fs/gnunet-directory.c:154 +#, fuzzy, c-format +msgid "`%s' is not a GNUnet directory\n" +msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" + +#: src/fs/gnunet-directory.c:179 +#, fuzzy +msgid "Display contents of a GNUnet directory" +msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" + +#: src/fs/gnunet-download.c:100 +#, fuzzy, c-format +msgid "Starting download `%s'.\n" +msgstr "Startade samling \"%s\".\n" + +#: src/fs/gnunet-download.c:109 +#, fuzzy +msgid "" +msgstr "Okänt fel" + +#: src/fs/gnunet-download.c:118 +#, c-format +msgid "" +"Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " +"download\n" +msgstr "" + +#: src/fs/gnunet-download.c:128 +#, fuzzy, c-format +msgid "Error downloading: %s.\n" +msgstr "Fel vid nedladdning: %s\n" + +#: src/fs/gnunet-download.c:136 +#, fuzzy, c-format +msgid "Downloading `%s' done (%s/s).\n" +msgstr "Uppladdning vägrades!" + +#: src/fs/gnunet-download.c:151 src/fs/gnunet-publish.c:190 +#: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 +#, c-format +msgid "Unexpected status: %d\n" +msgstr "" + +#: src/fs/gnunet-download.c:176 +#, fuzzy +msgid "You need to specify a URI argument.\n" +msgstr "Du mÃ¥ste ange en och endast en fil att avindexera.\n" + +#: src/fs/gnunet-download.c:182 src/fs/gnunet-publish.c:618 +#, fuzzy, c-format +msgid "Failed to parse URI: %s\n" +msgstr "Fil \"%s\" har URI: %s\n" + +#: src/fs/gnunet-download.c:189 +msgid "Only CHK or LOC URIs supported.\n" +msgstr "" + +#: src/fs/gnunet-download.c:196 +msgid "Target filename must be specified.\n" +msgstr "" + +#: src/fs/gnunet-download.c:210 src/fs/gnunet-publish.c:596 +#: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 +#, fuzzy, c-format +msgid "Could not initialize `%s' subsystem.\n" +msgstr "Misslyckades att initiera tjänsten \"%s\".\n" + +#: src/fs/gnunet-download.c:247 src/fs/gnunet-search.c:285 +msgid "set the desired LEVEL of receiver-anonymity" +msgstr "" + +#: src/fs/gnunet-download.c:250 +msgid "delete incomplete downloads (when aborted with CTRL-C)" +msgstr "" + +#: src/fs/gnunet-download.c:253 src/fs/gnunet-search.c:288 +msgid "only search the local peer (no P2P network search)" +msgstr "" + +#: src/fs/gnunet-download.c:256 +msgid "write the file to FILENAME" +msgstr "skriv filen till FILNAMN" + +#: src/fs/gnunet-download.c:260 +msgid "set the maximum number of parallel downloads that is allowed" +msgstr "" + +#: src/fs/gnunet-download.c:264 +msgid "set the maximum number of parallel requests for blocks that is allowed" +msgstr "" + +#: src/fs/gnunet-download.c:267 +msgid "download a GNUnet directory recursively" +msgstr "hämta en GNUnet-katalog rekursivt" + +#: src/fs/gnunet-download.c:277 +msgid "" +"Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" +"chk/...)" +msgstr "" + +#: src/fs/gnunet-fs.c:117 +msgid "print a list of all indexed files" +msgstr "" + +#: src/fs/gnunet-fs.c:124 +#, fuzzy +msgid "Special file-sharing operations" +msgstr "Visa alla alternativ" + +#: src/fs/gnunet-pseudonym.c:151 src/statistics/gnunet-statistics.c:126 +#, fuzzy, c-format +msgid "Invalid argument `%s'\n" +msgstr "Ogiltigt argument: \"%s\"\n" + +#: src/fs/gnunet-pseudonym.c:165 +#, fuzzy, c-format +msgid "Namespace `%s' unknown.\n" +msgstr "Namnrymd \"%s\" skapad(rot: %s).\n" + +#: src/fs/gnunet-pseudonym.c:240 src/fs/gnunet-pseudonym.c:247 +#: src/fs/gnunet-pseudonym.c:249 +#, fuzzy, c-format +msgid "Option `%s' ignored\n" +msgstr "%s: flagga \"%s\" är tvetydig\n" + +#: src/fs/gnunet-pseudonym.c:269 src/fs/gnunet-publish.c:672 +msgid "set the desired LEVEL of sender-anonymity" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:272 +msgid "create or advertise namespace NAME" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:275 +msgid "delete namespace NAME " +msgstr "" + +#: src/fs/gnunet-pseudonym.c:278 +msgid "" +"add an additional keyword for the advertisment (this option can be specified " +"multiple times)" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:282 src/fs/gnunet-publish.c:691 +msgid "set the meta-data for the given TYPE to the given VALUE" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:285 +msgid "print names of local namespaces" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:288 +msgid "use the given PRIORITY for the advertisments" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:291 +msgid "do not print names of remote namespaces" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:294 src/fs/gnunet-publish.c:710 +msgid "set the desired replication LEVEL" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:297 +#, fuzzy +msgid "specify ID of the root of the namespace" +msgstr "ange prioritet för innehÃ¥llet" + +#: src/fs/gnunet-pseudonym.c:300 +msgid "change rating of namespace ID by VALUE" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:308 +msgid "Manage GNUnet pseudonyms." +msgstr "" + +#: src/fs/gnunet-publish.c:147 +#, c-format +msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-publish.c:155 +#, fuzzy, c-format +msgid "Error publishing: %s.\n" +msgstr "Fel vid nedladdning: %s\n" + +#: src/fs/gnunet-publish.c:165 +#, c-format +msgid "Publishing `%s' done.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:169 +#, fuzzy, c-format +msgid "URI is `%s'.\n" +msgstr "Jag är ändpunkt \"%s\".\n" + +#: src/fs/gnunet-publish.c:187 +#, fuzzy +msgid "Cleanup after abort complete.\n" +msgstr "\"%s\" uppstart klar.\n" + +#: src/fs/gnunet-publish.c:299 +#, fuzzy, c-format +msgid "Meta data for file `%s' (%s)\n" +msgstr "Uppdaterar data för modul \"%s\"\n" + +#: src/fs/gnunet-publish.c:301 +#, fuzzy, c-format +msgid "Keywords for file `%s' (%s)\n" +msgstr "Nyckelord för fil \"%s\":\n" + +#: src/fs/gnunet-publish.c:352 +#, fuzzy, c-format +msgid "Failed to create namespace `%s'\n" +msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" + +#: src/fs/gnunet-publish.c:427 +#, fuzzy +msgid "Could not publish\n" +msgstr "Kunde inte köra \"%s\": %s\n" + +#: src/fs/gnunet-publish.c:454 +#, fuzzy +msgid "Could not start publishing.\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/fs/gnunet-publish.c:485 +#, fuzzy, c-format +msgid "Scanning directory `%s'.\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/fs/gnunet-publish.c:487 +#, fuzzy, c-format +msgid "Scanning file `%s'.\n" +msgstr "Startade samling \"%s\".\n" + +#: src/fs/gnunet-publish.c:492 +#, c-format +msgid "There was trouble processing file `%s', skipping it.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:497 +#, fuzzy +msgid "Preprocessing complete.\n" +msgstr "Nedstängning klar.\n" + +#: src/fs/gnunet-publish.c:501 +#, fuzzy, c-format +msgid "Extracting meta data from file `%s' complete.\n" +msgstr "Uppdaterar data för modul \"%s\"\n" + +#: src/fs/gnunet-publish.c:505 +msgid "Meta data extraction has finished.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:512 +#, fuzzy +msgid "Internal error scanning directory.\n" +msgstr "=\tFel vid läsning av katalog.\n" + +#: src/fs/gnunet-publish.c:546 +#, c-format +msgid "Cannot extract metadata from a URI!\n" +msgstr "" + +#: src/fs/gnunet-publish.c:553 +#, fuzzy, c-format +msgid "You must specify one and only one filename for insertion.\n" +msgstr "Du mÃ¥ste ange en och endast en fil att avindexera.\n" + +#: src/fs/gnunet-publish.c:559 +#, fuzzy, c-format +msgid "You must NOT specify an URI and a filename.\n" +msgstr "Du mÃ¥ste ange en och endast en fil att avindexera.\n" + +#: src/fs/gnunet-publish.c:567 src/vpn/gnunet-vpn.c:214 +#, fuzzy, c-format +msgid "Option `%s' is required when using option `%s'.\n" +msgstr "Kommando \"%s\" kräver ett argument (\"%s\").\n" + +#: src/fs/gnunet-publish.c:577 src/fs/gnunet-publish.c:584 +#: src/transport/gnunet-transport.c:530 +#, c-format +msgid "Option `%s' makes no sense without option `%s'.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:606 +#, fuzzy, c-format +msgid "Could not create namespace `%s'\n" +msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" + +#: src/fs/gnunet-publish.c:639 +#, fuzzy, c-format +msgid "Failed to access `%s': %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/gnunet-publish.c:651 +msgid "" +"Failed to start meta directory scanner. Is gnunet-helper-publish-fs " +"installed?\n" +msgstr "" + +#: src/fs/gnunet-publish.c:676 +msgid "disable adding the creation time to the metadata of the uploaded file" +msgstr "" + +#: src/fs/gnunet-publish.c:679 +msgid "do not use libextractor to add keywords or metadata" +msgstr "" + +#: src/fs/gnunet-publish.c:683 +msgid "" +"print list of extracted keywords that would be used, but do not perform " +"upload" +msgstr "" + +#: src/fs/gnunet-publish.c:687 +msgid "" +"add an additional keyword for the top-level file or directory (this option " +"can be specified multiple times)" +msgstr "" + +#: src/fs/gnunet-publish.c:694 +msgid "" +"do not index, perform full insertion (stores entire file in encrypted form " +"in GNUnet database)" +msgstr "" + +#: src/fs/gnunet-publish.c:699 +msgid "" +"specify ID of an updated version to be published in the future (for " +"namespace insertions only)" +msgstr "" + +#: src/fs/gnunet-publish.c:703 +msgid "specify the priority of the content" +msgstr "ange prioritet för innehÃ¥llet" + +#: src/fs/gnunet-publish.c:707 +msgid "publish the files under the pseudonym NAME (place file into namespace)" +msgstr "" + +#: src/fs/gnunet-publish.c:713 +msgid "" +"only simulate the process but do not do any actual publishing (useful to " +"compute URIs)" +msgstr "" + +#: src/fs/gnunet-publish.c:717 +msgid "" +"set the ID of this version of the publication (for namespace insertions only)" +msgstr "" + +#: src/fs/gnunet-publish.c:721 +msgid "" +"URI to be published (can be used instead of passing a file to add keywords " +"to the file with the respective URI)" +msgstr "" + +#: src/fs/gnunet-publish.c:736 +msgid "Publish a file or directory on GNUnet" +msgstr "" + +#: src/fs/gnunet-search.c:111 +#, c-format +msgid "Failed to write directory with search results to `%s'\n" +msgstr "" + +#: src/fs/gnunet-search.c:181 +#, fuzzy, c-format +msgid "Error searching: %s.\n" +msgstr "Fel vid lämning av DHT.\n" + +#: src/fs/gnunet-search.c:231 +#, fuzzy +msgid "Could not create keyword URI from arguments.\n" +msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" + +#: src/fs/gnunet-search.c:255 +#, fuzzy +msgid "Could not start searching.\n" +msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" + +#: src/fs/gnunet-search.c:291 +msgid "write search results to file starting with PREFIX" +msgstr "" + +#: src/fs/gnunet-search.c:294 +msgid "automatically terminate search after VALUE ms" +msgstr "" + +#: src/fs/gnunet-search.c:301 +msgid "automatically terminate search after VALUE results are found" +msgstr "" + +#: src/fs/gnunet-search.c:308 +msgid "Search GNUnet for files that were published on GNUnet" +msgstr "" + +#: src/fs/gnunet-service-fs.c:240 +msgid "# running average P2P latency (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 +msgid "# Loopback routes suppressed" +msgstr "" + +#: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 +#: src/topology/gnunet-daemon-topology.c:1290 +#: src/topology/gnunet-daemon-topology.c:1297 +#, fuzzy, c-format +msgid "Failed to connect to `%s' service.\n" +msgstr "Misslyckades att initiera tjänsten \"%s\".\n" + +#: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 +#: src/topology/gnunet-daemon-topology.c:654 +#: src/topology/gnunet-daemon-topology.c:756 +#: src/transport/gnunet-service-transport_neighbours.c:960 +#: src/transport/gnunet-service-transport_neighbours.c:1289 +#: src/transport/gnunet-service-transport_neighbours.c:1841 +#: src/transport/gnunet-service-transport_neighbours.c:2499 +#: src/transport/gnunet-service-transport_neighbours.c:2566 +#, fuzzy +msgid "# peers connected" +msgstr "# av anslutna parter" + +#: src/fs/gnunet-service-fs_cp.c:696 +#, fuzzy +msgid "# migration stop messages received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/fs/gnunet-service-fs_cp.c:700 +#, c-format +msgid "Migration of content to peer `%s' blocked for %llu ms\n" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:735 +#, fuzzy +msgid "# replies transmitted to other peers" +msgstr "# byte skickade av typen %d" + +#: src/fs/gnunet-service-fs_cp.c:741 +msgid "# replies dropped" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 +msgid "# P2P searches active" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:858 +msgid "# artificial delays introduced (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:911 +#, fuzzy +msgid "# replies dropped due to type mismatch" +msgstr "# byte mottagna av typen %d" + +#: src/fs/gnunet-service-fs_cp.c:919 +#, fuzzy +msgid "# replies received for other peers" +msgstr "# byte mottagna av typen %d" + +#: src/fs/gnunet-service-fs_cp.c:933 +msgid "# replies dropped due to insufficient cover traffic" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:971 +msgid "# P2P searches destroyed due to ultimate reply" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1038 +msgid "# requests done for free (low load)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1062 +msgid "# request dropped, priority insufficient" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1072 +msgid "# requests done for a price (normal load)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1151 +msgid "# GET requests received (from other peers)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1185 +msgid "# requests dropped due to initiator not being connected" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1207 +msgid "# requests dropped due to missing reverse route" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1267 +msgid "# requests dropped due TTL underflow" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1293 +msgid "# requests dropped due to higher-TTL request" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1322 +#, fuzzy +msgid "# P2P query messages received and processed" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/fs/gnunet-service-fs_cp.c:1687 +#, fuzzy +msgid "# migration stop messages sent" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/fs/gnunet-service-fs_indexing.c:113 +#: src/fs/gnunet-service-fs_indexing.c:163 +#, fuzzy, c-format +msgid "Configuration option `%s' in section `%s' missing.\n" +msgstr "Konfigurationsfil \"%s\" skapad.\n" + +#: src/fs/gnunet-service-fs_indexing.c:121 +#: src/fs/gnunet-service-fs_indexing.c:177 +#, fuzzy, c-format +msgid "Could not open `%s'.\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/fs/gnunet-service-fs_indexing.c:137 +#, fuzzy, c-format +msgid "Error writing `%s'.\n" +msgstr "Fel vid skapandet av användare" + +#: src/fs/gnunet-service-fs_indexing.c:228 +#, c-format +msgid "" +"Index request received for file `%s' is already indexed as `%s'. Permitting " +"anyway.\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:266 +#, c-format +msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:481 +#, fuzzy, c-format +msgid "Failed to delete bogus block: %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/fs/gnunet-service-fs_indexing.c:539 +msgid "# index blocks removed: original file inaccessible" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:554 +#, fuzzy, c-format +msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/fs/gnunet-service-fs_indexing.c:556 +#, fuzzy +msgid "not indexed" +msgstr "Avindexering misslyckades." + +#: src/fs/gnunet-service-fs_indexing.c:571 +#, fuzzy, c-format +msgid "Indexed file `%s' changed at offset %llu\n" +msgstr "Indexering av data misslyckades vid position %i.\n" + +#: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 +#: src/fs/gnunet-service-fs_lc.c:488 +#, fuzzy +msgid "# client searches active" +msgstr "# klartext PONG-meddelanden mottagna" + +#: src/fs/gnunet-service-fs_lc.c:256 +#, fuzzy +msgid "# replies received for local clients" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/fs/gnunet-service-fs_lc.c:321 +#, fuzzy +msgid "# client searches received" +msgstr "# klartext PONG-meddelanden mottagna" + +#: src/fs/gnunet-service-fs_lc.c:356 +msgid "# client searches updated (merged content seen list)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:265 +msgid "# average retransmission delay (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:391 +#, fuzzy +msgid "# transmission failed (core has no bandwidth)" +msgstr "Ingen transport av typ %d är känd.\n" + +#: src/fs/gnunet-service-fs_pe.c:420 +#, fuzzy +msgid "# query messages sent to other peers" +msgstr "# byte skickade av typen %d" + +#: src/fs/gnunet-service-fs_pe.c:469 +msgid "# delay heap timeout" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:476 +msgid "# query plans executed" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:538 +#, fuzzy +msgid "# requests merged" +msgstr "# byte mottogs via TCP" + +#: src/fs/gnunet-service-fs_pe.c:544 +#, fuzzy +msgid "# requests refreshed" +msgstr "# byte mottogs via TCP" + +#: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 +#: src/fs/gnunet-service-fs_pe.c:748 +msgid "# query plan entries" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:285 +#, fuzzy +msgid "# Pending requests created" +msgstr "# byte mottogs via TCP" + +#: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 +msgid "# Pending requests active" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:779 +#, fuzzy +msgid "# replies received and matched" +msgstr "# byte mottagna av typen %d" + +#: src/fs/gnunet-service-fs_pr.c:808 +msgid "# duplicate replies discarded (bloomfilter)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:822 +#, c-format +msgid "Unsupported block type %u\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:835 +msgid "# results found locally" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:953 +msgid "# Datastore `PUT' failures" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:980 +#, fuzzy +msgid "# storage requests dropped due to high load" +msgstr "Nätverksannonsering avstängd i konfigurationen!\n" + +#: src/fs/gnunet-service-fs_pr.c:1015 +#, fuzzy +msgid "# Replies received from DHT" +msgstr "# byte mottagna via HTTP" + +#: src/fs/gnunet-service-fs_pr.c:1106 +#, c-format +msgid "Datastore lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1127 +#, c-format +msgid "On-demand lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1174 +msgid "# Datastore lookups concluded (no results)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1188 +msgid "# Datastore lookups concluded (seen all)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1197 +msgid "# Datastore lookups aborted (more than MAX_RESULTS)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1211 +msgid "# requested DBLOCK or IBLOCK not found" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1224 +msgid "# on-demand blocks matched requests" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1237 +msgid "# on-demand lookups performed successfully" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1242 +msgid "# on-demand lookups failed" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 +#: src/fs/gnunet-service-fs_pr.c:1447 +msgid "# Datastore lookups concluded (error queueing)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1327 +msgid "# Datastore lookups concluded (found last result)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1338 +msgid "# Datastore lookups concluded (load too high)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1424 +msgid "# Datastore lookups initiated" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1508 +#, fuzzy +msgid "# GAP PUT messages received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 +#, fuzzy, c-format +msgid "Configuration fails to specify `%s', assuming default value." +msgstr "Konfigurationsfil \"%s\" skapad.\n" + +#: src/fs/gnunet-service-fs_push.c:629 +#, c-format +msgid "" +"Invalid value specified for option `%s' in section `%s', content pushing " +"disabled\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:89 +#, c-format +msgid "Unindexing at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:96 +#, fuzzy, c-format +msgid "Error unindexing: %s.\n" +msgstr "" +"\n" +"Fel vid avindexering av fil: %s\n" + +#: src/fs/gnunet-unindex.c:101 +#, fuzzy +msgid "Unindexing done.\n" +msgstr "Avindexera filer." + +#: src/fs/gnunet-unindex.c:131 +#, fuzzy, c-format +msgid "You must specify one and only one filename for unindexing.\n" +msgstr "Du mÃ¥ste ange en och endast en fil att avindexera.\n" + +#: src/fs/gnunet-unindex.c:148 +#, fuzzy +msgid "Could not start unindex operation.\n" +msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" + +#: src/fs/gnunet-unindex.c:176 +msgid "Unindex a file that was previously indexed with gnunet-publish." +msgstr "" + +#: src/fs/plugin_block_fs.c:131 +msgid "Reply mismatched in terms of namespace. Discarded.\n" +msgstr "" + +#: src/gns/gns_api.c:221 +#, fuzzy +msgid "Failed to connect to the GNS service!\n" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/gns/gnunet-gns-lookup.c:210 +msgid "Issue a request to the GNUnet Naming System, prints results." +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:264 +msgid "" +"None of the functions for the hostlist daemon were enabled. I have no " +"reason to run!\n" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:317 +msgid "advertise our hostlist to other peers" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:322 +msgid "" +"bootstrap using hostlists (it is highly recommended that you always use this " +"option)" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:325 +msgid "enable learning about hostlist servers from other peers" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:329 +msgid "provide a hostlist server" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:341 +msgid "GNUnet hostlist server and client" +msgstr "" + +#: src/hostlist/hostlist-client.c:286 +msgid "# bytes downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:307 src/hostlist/hostlist-client.c:339 +msgid "# invalid HELLOs downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:342 +#, fuzzy, c-format +msgid "Invalid `%s' message received from hostlist at `%s'\n" +msgstr "Ogiltigt meddelande mottogs den %s:%d." + +#: src/hostlist/hostlist-client.c:330 +msgid "# valid HELLOs downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:374 src/hostlist/hostlist-client.c:395 +#, c-format +msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:472 src/hostlist/hostlist-client.c:682 +#: src/hostlist/hostlist-client.c:688 src/hostlist/hostlist-client.c:740 +#: src/hostlist/hostlist-client.c:749 src/hostlist/hostlist-client.c:877 +#: src/hostlist/hostlist-client.c:967 src/hostlist/hostlist-client.c:972 +#: src/transport/plugin_transport_http_client.c:108 +#: src/transport/plugin_transport_http_client.c:123 +#, fuzzy, c-format +msgid "%s failed at %s:%d: `%s'\n" +msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" + +#: src/hostlist/hostlist-client.c:592 src/hostlist/hostlist-client.c:1342 +msgid "# advertised hostlist URIs" +msgstr "" + +#: src/hostlist/hostlist-client.c:622 +#, c-format +msgid "# advertised URI `%s' downloaded" +msgstr "" + +#: src/hostlist/hostlist-client.c:663 +#, c-format +msgid "" +"Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " +"gets dismissed.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:805 +#, fuzzy, c-format +msgid "Timeout trying to download hostlist from `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/hostlist/hostlist-client.c:822 +#, c-format +msgid "Download limit of %u bytes exceeded, stopping download\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:842 +#, fuzzy, c-format +msgid "%s failed for `%s' at %s:%d: `%s'\n" +msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" + +#: src/hostlist/hostlist-client.c:848 +#, fuzzy, c-format +msgid "Download of hostlist `%s' completed.\n" +msgstr "" +"Uppladdning av \"%s\" klar, aktuell genomsnittshastighet är %8.3f kbps.\n" + +#: src/hostlist/hostlist-client.c:856 +#, c-format +msgid "Adding successfully tested hostlist `%s' datastore.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:909 +#, c-format +msgid "Bootstrapping using hostlist at `%s'.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:917 +msgid "# hostlist downloads initiated" +msgstr "" + +#: src/hostlist/hostlist-client.c:1045 src/hostlist/hostlist-client.c:1515 +msgid "# milliseconds between hostlist downloads" +msgstr "" + +#: src/hostlist/hostlist-client.c:1054 +#, c-format +msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1092 +msgid "Scheduled saving of hostlists\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1096 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1119 src/hostlist/hostlist-client.c:1135 +#, fuzzy +msgid "# active connections" +msgstr "Nätverksanslutning" + +#: src/hostlist/hostlist-client.c:1253 +#, c-format +msgid "Initial time between hostlist downloads is %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1284 +#, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1290 +#, fuzzy, c-format +msgid "Loading saved hostlist entries from file `%s' \n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/hostlist/hostlist-client.c:1294 +#, c-format +msgid "Hostlist file `%s' is not existing\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1305 +#, fuzzy, c-format +msgid "Could not open file `%s' for reading to load hostlists: %s\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/hostlist/hostlist-client.c:1338 +#, c-format +msgid "%u hostlist URIs loaded from file\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1340 +msgid "# hostlist URIs read from file" +msgstr "" + +#: src/hostlist/hostlist-client.c:1373 +#, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1387 +#, fuzzy, c-format +msgid "Could not open file `%s' for writing to save hostlists: %s\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/hostlist/hostlist-client.c:1392 +#, fuzzy, c-format +msgid "Writing %u hostlist URIs to `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/hostlist/hostlist-client.c:1416 src/hostlist/hostlist-client.c:1433 +#, c-format +msgid "Error writing hostlist URIs to file `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1428 +msgid "# hostlist URIs written to file" +msgstr "" + +#: src/hostlist/hostlist-client.c:1480 +msgid "Learning is enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1483 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1492 +msgid "Learning is not enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1504 +#, c-format +msgid "" +"Since learning is not enabled on this peer, hostlist file `%s' was removed\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1508 +#, c-format +msgid "Hostlist file `%s' could not be removed\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:134 +#, fuzzy +msgid "bytes in hostlist" +msgstr "# byte krypterade" + +#: src/hostlist/hostlist-server.c:157 +msgid "expired addresses encountered" +msgstr "" + +#: src/hostlist/hostlist-server.c:184 +#: src/topology/gnunet-daemon-topology.c:875 +#, fuzzy, c-format +msgid "Error in communication with PEERINFO service: %s\n" +msgstr "Skriv ut information om GNUnets motparter." + +#: src/hostlist/hostlist-server.c:205 +msgid "HELLOs without addresses encountered (ignored)" +msgstr "" + +#: src/hostlist/hostlist-server.c:221 +msgid "bytes not included in hostlist (size limit)" +msgstr "" + +#: src/hostlist/hostlist-server.c:269 +#, c-format +msgid "Refusing `%s' request to hostlist server\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:272 +msgid "hostlist requests refused (not HTTP GET)" +msgstr "" + +#: src/hostlist/hostlist-server.c:280 +msgid "Sending 100 CONTINUE reply\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:287 +#, c-format +msgid "Refusing `%s' request with %llu bytes of upload data\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:291 +msgid "hostlist requests refused (upload data)" +msgstr "" + +#: src/hostlist/hostlist-server.c:299 +msgid "Could not handle hostlist request since I do not have a response yet\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:302 +msgid "hostlist requests refused (not ready)" +msgstr "" + +#: src/hostlist/hostlist-server.c:306 +msgid "Received request for our hostlist\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:307 +msgid "hostlist requests processed" +msgstr "" + +#: src/hostlist/hostlist-server.c:350 +msgid "# hostlist advertisements send" +msgstr "" + +#: src/hostlist/hostlist-server.c:397 +msgid "Advertisement message could not be queued by core\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:565 +#, fuzzy, c-format +msgid "Invalid port number %llu. Exiting.\n" +msgstr "Ogiltiga argument. Avslutar.\n" + +#: src/hostlist/hostlist-server.c:574 +#, c-format +msgid "Hostlist service starts on %s:%llu\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:588 +#, fuzzy, c-format +msgid "Address to obtain hostlist: `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/hostlist/hostlist-server.c:626 +#, c-format +msgid "Could not start hostlist HTTP server on port %u\n" +msgstr "" + +#: src/mesh/gnunet-service-mesh.c:4595 +msgid "Wrong CORE service\n" +msgstr "" + +#: src/mesh/gnunet-service-mesh.c:4789 +#, fuzzy +msgid "Mesh service is lacking key configuration settings. Exiting.\n" +msgstr "GNUnet-konfiguration" + +#: src/mesh/gnunet-service-mesh.c:4798 +#, fuzzy +msgid "Mesh service could not access hostkey. Exiting.\n" +msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" + +#: src/namestore/namestore_api.c:272 src/namestore/namestore_api.c:313 +msgid "Namestore added record successfully" +msgstr "" + +#: src/namestore/namestore_api.c:281 src/namestore/namestore_api.c:322 +msgid "Namestore failed to add record" +msgstr "" + +#: src/nat/gnunet-nat-server.c:289 +#, c-format +msgid "Please pass valid port number as the first argument! (got `%s')\n" +msgstr "" + +#: src/nat/gnunet-nat-server.c:328 +msgid "GNUnet NAT traversal test helper daemon" +msgstr "" + +#: src/nat/nat.c:803 +#, c-format +msgid "gnunet-helper-nat-server generated malformed address `%s'\n" +msgstr "" + +#: src/nat/nat.c:852 +#, fuzzy, c-format +msgid "Failed to start %s\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/nat/nat.c:1121 +#, fuzzy, c-format +msgid "Malformed %s `%s' given in configuration!\n" +msgstr "Kunde inte spara konfiguration!" + +#: src/nat/nat.c:1187 src/nat/nat.c:1197 +#, c-format +msgid "" +"Configuration requires `%s', but binary is not installed properly (SUID bit " +"not set). Option disabled.\n" +msgstr "" + +#: src/nat/nat.c:1329 +msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" +msgstr "" + +#: src/nat/nat.c:1341 +#, c-format +msgid "Running gnunet-helper-nat-client %s %s %u\n" +msgstr "" + +#: src/nat/nat_test.c:348 +#, fuzzy +msgid "Failed to connect to `gnunet-nat-server'\n" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/nat/nat_test.c:418 +#, c-format +msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" +msgstr "" + +#: src/nse/gnunet-nse-profiler.c:926 +#, fuzzy +msgid "Measure quality and performance of the NSE service." +msgstr "Kan inte tillgÃ¥ tjänsten" + +#: src/nse/gnunet-service-nse.c:936 +#, c-format +msgid "Proof of work invalid: %llu!\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1391 src/nse/gnunet-service-nse.c:1410 +#: src/nse/gnunet-service-nse.c:1431 +msgid "NSE service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1398 +#, fuzzy +msgid "Invalid work requirement for NSE service. Exiting.\n" +msgstr "Ogiltiga argument. Avslutar.\n" + +#: src/nse/gnunet-service-nse.c:1419 +#, fuzzy +msgid "NSE service could not access hostkey. Exiting.\n" +msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:133 +#, fuzzy, c-format +msgid "Removing expired address of transport `%s'\n" +msgstr "Tillgängliga transport(er): %s\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:195 +msgid "# peers known" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:239 +#, c-format +msgid "" +"File `%s' in directory `%s' does not match naming convention. Removed.\n" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:305 +#, c-format +msgid "Still no peers found in `%s'!\n" +msgstr "" + +#: src/peerinfo/peerinfo_api.c:279 +#, fuzzy, c-format +msgid "Failed to transmit message to `%s' service.\n" +msgstr "Misslyckades att initiera tjänsten \"%s\".\n" + +#: src/peerinfo/peerinfo_api.c:435 +#, fuzzy +msgid "Failed to receive response from `PEERINFO' service." +msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" + +#: src/peerinfo/peerinfo_api.c:463 src/peerinfo/peerinfo_api.c:481 +#, fuzzy +msgid "Received invalid message from `PEERINFO' service.\n" +msgstr "mottog ogiltigt \"%s\" meddelande: %s.\n" + +#: src/peerinfo/peerinfo_api.c:523 +#, fuzzy +msgid "Failed to transmit iteration request to `PEERINFO' service\n" +msgstr "Misslyckades att initiera tjänsten \"%s\".\n" + +#: src/peerinfo/peerinfo_api.c:557 +msgid "Timeout transmitting iteration request to `PEERINFO' service.\n" +msgstr "" + +#: src/peerinfo/peerinfo_api_notify.c:258 +#, fuzzy, c-format +msgid "Could not connect to `%s' service.\n" +msgstr "Kunde inte ansluta till gnunetd.\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:216 +#, fuzzy, c-format +msgid "Could not find option `%s:%s' in configuration.\n" +msgstr "Kunde inte hitta motpart \"%s\" i routingtabell!\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:223 +#, fuzzy, c-format +msgid "Loading hostkey from `%s' failed.\n" +msgstr "Tolkning av HTTP-svar för URL \"%s\" misslyckades.\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:235 +#, c-format +msgid "I am peer `%s'.\n" +msgstr "Jag är ändpunkt \"%s\".\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:255 +msgid "output only the identity strings" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:258 +msgid "output our own identity only" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:264 +#, fuzzy +msgid "Print information about peers." +msgstr "Skriv ut information om GNUnets motparter." + +#: src/pt/gnunet-daemon-pt.c:264 +#, fuzzy +msgid "Failed to pack DNS request. Dropping.\n" +msgstr "Misslyckades att skicka HTTP-begäran till värd \"%s\": %s\n" + +#: src/pt/gnunet-daemon-pt.c:270 +#, fuzzy +msgid "# DNS requests mapped to VPN" +msgstr "# byte mottogs via TCP" + +#: src/pt/gnunet-daemon-pt.c:323 +msgid "# DNS records modified" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:500 +msgid "# DNS replies intercepted" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:506 +#, fuzzy +msgid "Failed to parse DNS request. Dropping.\n" +msgstr "Misslyckades att skicka HTTP-begäran till värd \"%s\": %s\n" + +#: src/pt/gnunet-daemon-pt.c:602 +#, fuzzy +msgid "# DNS requests dropped (timeout)" +msgstr "Nätverksannonsering avstängd i konfigurationen!\n" + +#: src/pt/gnunet-daemon-pt.c:632 +#, fuzzy +msgid "# DNS requests intercepted" +msgstr "# byte mottogs via TCP" + +#: src/pt/gnunet-daemon-pt.c:637 +msgid "# DNS requests dropped (DNS mesh tunnel down)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:645 +#, fuzzy +msgid "# DNS requests dropped (malformed)" +msgstr "# byte mottogs via TCP" + +#: src/pt/gnunet-daemon-pt.c:716 +#, fuzzy +msgid "# DNS replies received" +msgstr "# byte mottogs via TCP" + +#: src/pt/gnunet-daemon-pt.c:730 +#, fuzzy +msgid "# DNS replies dropped (too late?)" +msgstr "# byte mottagna av typen %d" + +#: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 +msgid "# DNS requests aborted (tunnel down)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 +#: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 +#, fuzzy, c-format +msgid "Failed to connect to %s service. Exiting.\n" +msgstr "Misslyckades att initiera tjänsten \"%s\".\n" + +#: src/pt/gnunet-daemon-pt.c:973 +msgid "Daemon to run to perform IP protocol translation to GNUnet" +msgstr "" + +#: src/statistics/gnunet-service-statistics.c:209 +#, fuzzy, c-format +msgid "Loading %llu bytes of statistics from `%s'\n" +msgstr "Ladda ner filer frÃ¥n GNUnet." + +#: src/statistics/gnunet-service-statistics.c:267 +#, fuzzy, c-format +msgid "Wrote %llu bytes of statistics to `%s'\n" +msgstr "Ladda ner filer frÃ¥n GNUnet." + +#: src/statistics/gnunet-statistics.c:98 +#, fuzzy +msgid "Failed to obtain statistics.\n" +msgstr "Misslyckades att binda till UDP-port %d.\n" + +#: src/statistics/gnunet-statistics.c:164 +msgid "limit output to statistics for the given NAME" +msgstr "" + +#: src/statistics/gnunet-statistics.c:167 +msgid "make the value being set persistent" +msgstr "" + +#: src/statistics/gnunet-statistics.c:170 +msgid "limit output to the given SUBSYSTEM" +msgstr "" + +#: src/statistics/gnunet-statistics.c:173 +msgid "just print the statistics value" +msgstr "" + +#: src/statistics/gnunet-statistics.c:180 +msgid "Print statistics about GNUnet operations." +msgstr "Skriv ut statistik om GNUnet-operationer." + +#: src/statistics/statistics_api.c:390 +#, fuzzy +msgid "Failed to connect to statistics service!\n" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/template/gnunet-template.c:68 +#, fuzzy +msgid "help text" +msgstr "hjälptext för -t" + +#: src/testing/gnunet-testing.c:157 +#, fuzzy +msgid "Could not read hostkeys file, specify hostkey file with -H!\n" +msgstr "Kunde inte skapa värdnyckel!\n" + +#: src/testing/gnunet-testing.c:159 +#, c-format +msgid "Specified hostkey file `%s' not found!\n" +msgstr "" + +#: src/testing/gnunet-testing.c:273 +#, fuzzy +msgid "create unique configuration files" +msgstr "skriv ut ett värde frÃ¥n konfigurationsfilen till standard ut" + +#: src/testing/gnunet-testing.c:275 +msgid "create hostkey files from pre-computed hostkey list" +msgstr "" + +#: src/testing/gnunet-testing.c:277 +msgid "host key file" +msgstr "" + +#: src/testing/gnunet-testing.c:279 +#, fuzzy +msgid "number of unique configuration files or hostkeys to create" +msgstr "skriv ut ett värde frÃ¥n konfigurationsfilen till standard ut" + +#: src/testing/gnunet-testing.c:281 +#, fuzzy +msgid "configuration template" +msgstr "Konfigurationsfil \"%s\" skapad.\n" + +#: src/testing/gnunet-testing.c:287 +msgid "Command line tool to access the testing library" +msgstr "" + +#: src/testing/helper.c:56 +#, fuzzy +msgid "Peer is lacking HOSTKEY configuration setting.\n" +msgstr "GNUnet-konfiguration" + +#: src/testing/helper.c:64 +#, fuzzy +msgid "Could not access hostkey.\n" +msgstr "Kunde inte tolka konfigurationsfil \"%s\".\n" + +#: src/testing/testing.c:204 +msgid "`scp' does not seem to terminate (timeout copying config).\n" +msgstr "" + +#: src/testing/testing.c:218 src/testing/testing.c:808 +#, fuzzy +msgid "`scp' did not complete cleanly.\n" +msgstr "\"%s\" är inte ansluten till nÃ¥gon ändpunkt.\n" + +#: src/testing/testing.c:239 +#, fuzzy +msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/testing/testing.c:240 +#, fuzzy +msgid "Failed to create pipe for `ssh' process.\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/testing/testing.c:292 +#, fuzzy, c-format +msgid "Could not start `%s' process to create hostkey.\n" +msgstr "Kunde inte skapa värdnyckel!\n" + +#: src/testing/testing.c:299 +#, fuzzy +msgid "Failed to start `gnunet-peerinfo' process.\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/testing/testing.c:300 src/testing/testing.c:488 +#, fuzzy +msgid "Failed to start `ssh' process.\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/testing/testing.c:360 +#, c-format +msgid "Error reading from gnunet-peerinfo: %s\n" +msgstr "" + +#: src/testing/testing.c:364 +#, fuzzy +msgid "Malformed output from gnunet-peerinfo!\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/testing/testing.c:374 +#, fuzzy +msgid "Failed to get hostkey!\n" +msgstr "Kunde inte skapa värdnyckel!\n" + +#: src/testing/testing.c:406 +msgid "`Failed while waiting for topology setup!\n" +msgstr "" + +#: src/testing/testing.c:480 +#, fuzzy, c-format +msgid "Could not start `%s' process to start GNUnet.\n" +msgstr "Kunde inte skapa värdnyckel!\n" + +#: src/testing/testing.c:487 +#, fuzzy +msgid "Failed to start `gnunet-arm' process.\n" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/testing/testing.c:509 src/testing/testing.c:612 +msgid "`gnunet-arm' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:510 src/testing/testing.c:613 +#: src/testing/testing.c:633 +msgid "`ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:582 +msgid "Unable to get HELLO for peer!\n" +msgstr "" + +#: src/testing/testing.c:632 +msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" +msgstr "" + +#: src/testing/testing.c:653 src/testing/testing.c:685 +msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:668 src/testing/testing.c:723 +#, fuzzy +msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" +msgstr "\"%s\" är inte ansluten till nÃ¥gon ändpunkt.\n" + +#: src/testing/testing.c:796 +msgid "`scp' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:966 +#, fuzzy, c-format +msgid "Starting service %s for peer `%4s'\n" +msgstr "Startade samling \"%s\".\n" + +#: src/testing/testing.c:1237 src/testing/testing_group.c:6278 +#, fuzzy, c-format +msgid "Could not start `%s' process to copy configuration directory.\n" +msgstr "Kunde inte skapa värdnyckel!\n" + +#: src/testing/testing.c:1322 src/testing/testing.c:1397 +#, fuzzy, c-format +msgid "Terminating peer `%4s'\n" +msgstr "Ã…tkomst nekad för \"%s\" vid %s:%d.\n" + +#: src/testing/testing.c:1480 +#, fuzzy, c-format +msgid "Setting d->dead on peer `%4s'\n" +msgstr "Startade samling \"%s\".\n" + +#: src/testing/testing.c:1610 +msgid "Peer not yet running, can not change configuration at this point." +msgstr "" + +#: src/testing/testing.c:1618 +#, fuzzy +msgid "Failed to write new configuration to disk." +msgstr "Kunde inte spara konfiguration!" + +#: src/testing/testing.c:1647 +#, fuzzy, c-format +msgid "Could not start `%s' process to copy configuration file.\n" +msgstr "Kunde inte skapa värdnyckel!\n" + +#: src/testing/testing.c:1650 +#, fuzzy +msgid "Failed to copy new configuration to remote machine." +msgstr "Kunde inte spara konfiguration!" + +#: src/testing/testing.c:1805 +#, fuzzy +msgid "Peers failed to connect" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/testing/testing.c:1933 +#, fuzzy +msgid "Failed to connect to core service of first peer!\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/testing/testing.c:2156 +msgid "Peers are not fully running yet, can not connect!\n" +msgstr "" + +#: src/testing/testing_group.c:1910 src/testing/testing_group.c:1922 +#: src/testing/testing_group.c:2023 src/testing/testing_group.c:2082 +#: src/testing/testing_group.c:2171 src/testing/testing_group.c:2191 +#: src/testing/testing_group.c:2328 src/testing/testing_peergroup.c:940 +#, fuzzy, c-format +msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" +msgstr "Konfigurationsfil \"%s\" hittades inte. Kör \"gnunet-setup -d\"!\n" + +#: src/testing/testing_group.c:1932 +#, fuzzy, c-format +msgid "Target is %d connections per peer." +msgstr "Misslyckades att starta samling.\n" + +#: src/testing/testing_group.c:2179 +#, c-format +msgid "" +"Invalid value `%s' for option `%s' in section `%s': got %f, needed value " +"greater than 0\n" +msgstr "" + +#: src/testing/testing_group.c:2209 src/testing/testing_group.c:2402 +#, c-format +msgid "Connecting nodes in 2d torus topology: %u rows %u columns\n" +msgstr "" + +#: src/testing/testing_group.c:2246 +#, c-format +msgid "natural log of %d is %d, will run %d iterations\n" +msgstr "" + +#: src/testing/testing_group.c:2249 +#, c-format +msgid "Total connections added thus far: %u!\n" +msgstr "" + +#: src/testing/testing_group.c:2290 +#, c-format +msgid "Total connections added for small world: %d!\n" +msgstr "" + +#: src/testing/testing_group.c:2342 +#, c-format +msgid "rand is %f probability is %f\n" +msgstr "" + +#: src/testing/testing_group.c:2919 src/testing/testing_group.c:3118 +#, c-format +msgid "" +"No `%s' specified in peer configuration in section `%s', cannot copy friends " +"file!\n" +msgstr "" + +#: src/testing/testing_group.c:3020 +msgid "Finished copying all friend files!\n" +msgstr "" + +#: src/testing/testing_group.c:3133 +#, fuzzy, c-format +msgid "Copying file with command cp %s %s\n" +msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" + +#: src/testing/testing_group.c:3156 +#, fuzzy, c-format +msgid "Copying file with command scp %s %s\n" +msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" + +#: src/testing/testing_group.c:3173 +#, c-format +msgid "Checking copy status of file %d\n" +msgstr "" + +#: src/testing/testing_group.c:3191 +#, c-format +msgid "File %d copied\n" +msgstr "" + +#: src/testing/testing_group.c:3206 +#, fuzzy +msgid "Finished copying all blacklist files!\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/testing/testing_group.c:3586 src/testing/testing_group.c:3723 +#: src/testing/testing_group.c:4884 src/testing/testing_group.c:5025 +msgid "Delaying connect, we have too many outstanding connections!\n" +msgstr "" + +#: src/testing/testing_group.c:3596 src/testing/testing_group.c:4894 +#: src/testing/testing_group.c:5035 +#, c-format +msgid "Creating connection, outstanding_connections is %d\n" +msgstr "" + +#: src/testing/testing_group.c:3608 +#, c-format +msgid "Offering HELLO of peer %s to peer %s\n" +msgstr "" + +#: src/testing/testing_group.c:3734 +#, c-format +msgid "Creating connection, outstanding_connections is %d (max %d)\n" +msgstr "" + +#: src/testing/testing_group.c:3988 +msgid "Creating clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:3993 +msgid "Creating small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:3998 +msgid "Creating small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4002 +msgid "Creating ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4006 +msgid "Creating 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4010 +msgid "Creating Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4014 +msgid "Creating InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4018 +msgid "Creating Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4023 +msgid "Creating straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4027 +msgid "Creating topology from file!\n" +msgstr "" + +#: src/testing/testing_group.c:4043 +msgid "Creating no allowed topology (all peers can connect at core level)\n" +msgstr "" + +#: src/testing/testing_group.c:4058 +msgid "Failed during friend file copying!\n" +msgstr "" + +#: src/testing/testing_group.c:4064 +msgid "Friend files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:4081 +msgid "Blacklisting all but clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:4087 +msgid "Blacklisting all but small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4093 +msgid "Blacklisting all but small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4099 +msgid "Blacklisting all but ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4105 +msgid "Blacklisting all but 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4111 +msgid "Blacklisting all but Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4117 +msgid "Blacklisting all but InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4152 +msgid "Blacklisting all but Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4158 +msgid "Blacklisting all but straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4173 +#, fuzzy +msgid "Failed during blacklist file copying!\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/testing/testing_group.c:4179 +msgid "Blacklist files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:5263 +msgid "Creating clique CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5270 +msgid "Creating small world (ring) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5277 +msgid "Creating small world (2d-torus) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5283 +msgid "Creating ring CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5290 +msgid "Creating 2d torus CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5297 +msgid "Creating Erdos-Renyi CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5304 +msgid "Creating InterNAT CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5311 +msgid "Creating Scale Free CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5318 +msgid "Creating straight line CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5324 +msgid "Creating no CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5330 +msgid "Unknown topology specification, can't connect peers!\n" +msgstr "" + +#: src/testing/testing_group.c:5340 +#, c-format +msgid "Connecting random subset (%'.2f percent) of possible peers\n" +msgstr "" + +#: src/testing/testing_group.c:5348 +#, c-format +msgid "Connecting a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5357 +#, c-format +msgid "Using DFS to connect a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5367 +#, c-format +msgid "Finding additional %u closest peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:6062 src/transport/transport-testing.c:650 +#, fuzzy +msgid "Could not read hostkeys file!\n" +msgstr "Kunde inte skapa värdnyckel!\n" + +#: src/testing/testing_group.c:6131 +#, fuzzy, c-format +msgid "Could not create configuration for peer number %u on `%s'!\n" +msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" + +#: src/topology/gnunet-daemon-topology.c:244 +msgid "# peers blacklisted" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:380 +#, fuzzy +msgid "# connect requests issued to transport" +msgstr "# byte mottogs via TCP" + +#: src/topology/gnunet-daemon-topology.c:675 +#: src/topology/gnunet-daemon-topology.c:761 +#, fuzzy +msgid "# friends connected" +msgstr "# av anslutna parter" + +#: src/topology/gnunet-daemon-topology.c:950 +msgid "Failed to connect to core service, can not manage topology!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:982 +#, c-format +msgid "Option `%s' in section `%s' not specified!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:994 +#, fuzzy, c-format +msgid "Could not read friends list `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/topology/gnunet-daemon-topology.c:1000 +#, c-format +msgid "Friends file `%s' is empty.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1009 +#, fuzzy, c-format +msgid "Failed to read friends list from `%s': out of memory\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/topology/gnunet-daemon-topology.c:1017 +#, c-format +msgid "Failed to read friends list from `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/topology/gnunet-daemon-topology.c:1037 +#, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1050 +#, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1060 +#, fuzzy, c-format +msgid "Found friend `%s' in configuration\n" +msgstr " gconfig\tGTK-konfiguration\n" + +#: src/topology/gnunet-daemon-topology.c:1066 +#, c-format +msgid "Found myself `%s' in friend list (useless, ignored)\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1076 +#, fuzzy +msgid "# friends in configuration" +msgstr " gconfig\tGTK-konfiguration\n" + +#: src/topology/gnunet-daemon-topology.c:1082 +msgid "" +"Fewer friends specified than required by minimum friend count. Will only " +"connect to friends.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1089 +msgid "" +"More friendly connections required than target total number of connections.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1126 +#, fuzzy +msgid "# HELLO messages received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/topology/gnunet-daemon-topology.c:1183 +msgid "# HELLO messages gossipped" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1323 +msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:247 +#, fuzzy, c-format +msgid "Could not read blacklist file `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/transport/gnunet-service-transport_blacklist.c:254 +#, c-format +msgid "Blacklist file `%s' is empty.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:266 +#, fuzzy, c-format +msgid "Failed to read blacklist from `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/transport/gnunet-service-transport_blacklist.c:287 +#: src/transport/gnunet-service-transport_blacklist.c:311 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, giving up!\n" +msgstr "Syntaxfel i konfigurationsfil \"%s\" pÃ¥ rad %d.\n" + +#: src/transport/gnunet-service-transport_blacklist.c:298 +#: src/transport/gnunet-service-transport_blacklist.c:336 +#, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:350 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" +msgstr "Syntaxfel i konfigurationsfil \"%s\" pÃ¥ rad %d.\n" + +#: src/transport/gnunet-service-transport_blacklist.c:364 +#, c-format +msgid "Found myself `%s' in blacklist (useless, ignored)\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:523 +#: src/transport/gnunet-service-transport_blacklist.c:764 +msgid "# disconnects due to blacklist" +msgstr "" + +#: src/transport/gnunet-service-transport.c:158 +#, fuzzy +msgid "# bytes payload discarded due to not connected peer " +msgstr "Nätverksannonsering avstängd i konfigurationen!\n" + +#: src/transport/gnunet-service-transport.c:572 +msgid "Transport service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport.c:581 +msgid "Transport service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:353 +#, c-format +msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:358 +msgid "# messages dropped due to slow client" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:510 +#, c-format +msgid "Rejecting control connection from peer `%s', which is not me!\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:628 +#, fuzzy +msgid "# bytes payload received for other peers" +msgstr "# byte mottagna av typen %d" + +#: src/transport/gnunet-service-transport_clients.c:645 +msgid "# bytes payload dropped (other peer was not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:696 +#, fuzzy +msgid "# REQUEST CONNECT messages received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/transport/gnunet-service-transport_hello.c:172 +msgid "# refreshed my HELLO" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:482 +msgid "# failed connection attempts due to timeout" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:883 +#, fuzzy +msgid "# peers disconnected due to external request" +msgstr "# av anslutna parter" + +#: src/transport/gnunet-service-transport_neighbours.c:966 +#, fuzzy +msgid "# fast reconnects failed" +msgstr "# av anslutna parter" + +#: src/transport/gnunet-service-transport_neighbours.c:1022 +#, fuzzy +msgid "# peers disconnected due to timeout" +msgstr "# av anslutna parter" + +#: src/transport/gnunet-service-transport_neighbours.c:1047 +#, fuzzy +msgid "# keepalives sent" +msgstr "# sessionsnycklar skickade" + +#: src/transport/gnunet-service-transport_neighbours.c:1088 +#, fuzzy +msgid "# peers disconnected due to global disconnect" +msgstr "Nätverksannonsering avstängd i konfigurationen!\n" + +#: src/transport/gnunet-service-transport_neighbours.c:1888 +#: src/transport/gnunet-service-transport_neighbours.c:1909 +msgid "# messages not sent (no such peer or not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1925 +msgid "# bytes in message queue for other peers" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1977 +#, fuzzy +msgid "# messages discarded due to lack of neighbour record" +msgstr "Nätverksannonsering avstängd i konfigurationen!\n" + +#: src/transport/gnunet-service-transport_neighbours.c:2013 +msgid "# bandwidth quota violations by other peers" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2031 +msgid "# ms throttling suggested" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2060 +msgid "# KEEPALIVE messages discarded (not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2113 +#, fuzzy +msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" +msgstr "Nätverksannonsering avstängd i konfigurationen!\n" + +#: src/transport/gnunet-service-transport_neighbours.c:2121 +#, fuzzy +msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" +msgstr "Nätverksannonsering avstängd i konfigurationen!\n" + +#: src/transport/gnunet-service-transport_neighbours.c:2187 +msgid "# SET QUOTA messages ignored (no such peer)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2205 +msgid "# disconnects due to quota of 0" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2323 +msgid "# disconnect messages ignored (old format)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2336 +msgid "# disconnect messages ignored (timestamp)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2411 +#, fuzzy +msgid "# unexpected CONNECT_ACK messages (no peer)" +msgstr "skicka ANTAL meddelanden" + +#: src/transport/gnunet-service-transport_neighbours.c:2453 +#, fuzzy +msgid "# unexpected CONNECT_ACK messages" +msgstr "skicka ANTAL meddelanden" + +#: src/transport/gnunet-service-transport_neighbours.c:2544 +#, fuzzy +msgid "# unexpected ACK messages" +msgstr "# krypterade PONG-meddelanden skickade" + +#: src/transport/gnunet-service-transport_plugins.c:111 +msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:118 +#, fuzzy, c-format +msgid "Starting transport plugins `%s'\n" +msgstr "Testar transport(er) %s\n" + +#: src/transport/gnunet-service-transport_plugins.c:122 +#, fuzzy, c-format +msgid "Loading `%s' transport plugin\n" +msgstr "Testar transport(er) %s\n" + +#: src/transport/gnunet-service-transport_plugins.c:150 +#, fuzzy, c-format +msgid "Failed to load transport plugin for `%s'\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/transport/gnunet-service-transport_validation.c:410 +msgid "# address records discarded" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:459 +#, c-format +msgid "" +"Not transmitting `%s' with `%s', message too big (%u bytes!). This should " +"not happen.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:508 +#, fuzzy +msgid "# PING without HELLO messages sent" +msgstr "# PING-meddelanden i klartext skickade" + +#: src/transport/gnunet-service-transport_validation.c:566 +msgid "# address revalidations started" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:798 +#, fuzzy +msgid "# PING message for different peer received" +msgstr "# PING-meddelanden skapade" + +#: src/transport/gnunet-service-transport_validation.c:833 +#, c-format +msgid "" +"Not confirming PING with address `%s' since I cannot confirm having this " +"address.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:919 +msgid "# PONGs unicast via reliable transport" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:928 +msgid "# PONGs multicast to all available addresses" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1050 +msgid "# PONGs dropped, no matching pending validation" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1075 +msgid "# PONGs dropped, signature expired" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1134 +#, fuzzy, c-format +msgid "Adding `%s' without addresses for peer `%s'\n" +msgstr "Motpart \"%s\" med pÃ¥litlighet %8u och adress \"%s\"\n" + +#: src/transport/gnunet-transport.c:256 +msgid "No transport plugins configured, peer will never communicate\n" +msgstr "" + +#: src/transport/gnunet-transport.c:269 +#, c-format +msgid "No port configured for plugin `%s', cannot test it\n" +msgstr "" + +#: src/transport/gnunet-transport.c:319 +#, c-format +msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:326 +#, c-format +msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:359 +#, fuzzy, c-format +msgid "Transmitting %u bytes to %s\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/transport/gnunet-transport.c:379 +#, fuzzy, c-format +msgid "Connected to %s\n" +msgstr "\"%s\" ansluten till \"%s\".\n" + +#: src/transport/gnunet-transport.c:410 +#, fuzzy, c-format +msgid "Disconnected from %s\n" +msgstr "\"%s\" ansluten till \"%s\".\n" + +#: src/transport/gnunet-transport.c:439 +#, c-format +msgid "Received %u bytes from %s\n" +msgstr "" + +#: src/transport/gnunet-transport.c:453 +#, fuzzy, c-format +msgid "Peer `%s': %s %s\n" +msgstr "Jag är ändpunkt \"%s\".\n" + +#: src/transport/gnunet-transport.c:483 +#, fuzzy, c-format +msgid "Peer `%s' disconnected\n" +msgstr "# av anslutna parter" + +#: src/transport/gnunet-transport.c:539 +#, fuzzy, c-format +msgid "Failed to parse peer identity `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/transport/gnunet-transport.c:587 +msgid "measure how fast we are receiving data (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:590 +#, fuzzy +msgid "try to connect to the given peer" +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/transport/gnunet-transport.c:593 +#, fuzzy +msgid "provide information about all current connections (once)" +msgstr "Skriv ut information om GNUnets motparter." + +#: src/transport/gnunet-transport.c:596 +#, fuzzy +msgid "provide information about all current connections (continuously)" +msgstr "Skriv ut information om GNUnets motparter." + +#: src/transport/gnunet-transport.c:599 +#, fuzzy +msgid "do not resolve hostnames" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/transport/gnunet-transport.c:603 +msgid "send data for benchmarking to the other peer (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:606 +msgid "test transport configuration (involves external server)" +msgstr "" + +#: src/transport/gnunet-transport.c:614 +#, fuzzy +msgid "Direct access to transport service." +msgstr "Misslyckades att ansluta till gnunetd.\n" + +#: src/transport/plugin_transport_http.c:981 +msgid "Disabling IPv6 since it is not supported on this system!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1029 +#, fuzzy +msgid "Require valid port number for service in configuration!\n" +msgstr "Inga applikationer definierade i konfiguration!\n" + +#: src/transport/plugin_transport_http.c:1054 src/util/service.c:986 +#, fuzzy, c-format +msgid "Failed to resolve `%s': %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/transport/plugin_transport_http.c:1071 src/util/service.c:1003 +#, fuzzy, c-format +msgid "Failed to find %saddress for `%s'.\n" +msgstr "Misslyckades att binda till UDP-port %d.\n" + +#: src/transport/plugin_transport_http.c:1176 +#, c-format +msgid "Found %u addresses to report to NAT service\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1189 +#, c-format +msgid "FREEING %s\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1264 +msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1277 +#, fuzzy +msgid "Port is required! Fix in configuration\n" +msgstr " gconfig\tGTK-konfiguration\n" + +#: src/transport/plugin_transport_http.c:1288 +msgid "Port 0, client only mode\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1308 +#, c-format +msgid "" +"Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1338 +#, c-format +msgid "" +"Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http_client.c:621 +#, c-format +msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:189 +msgid "" +"Could not create a new TLS certificate, program `gnunet-transport-" +"certificate-creation' could not be started!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:213 +msgid "No usable TLS certificate found and creating one failed!\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:370 +#, fuzzy, c-format +msgid "Received malformed message via %s. Ignored.\n" +msgstr "Mottog ogiltigt \"%s\" meddelande frÃ¥n \"%s\".\n" + +# capped är inte ett bra ord IMHO +#: src/transport/plugin_transport_smtp.c:457 +#, fuzzy +msgid "SMTP filter string to invalid, lacks ': '\n" +msgstr "SMTP-filtersträng för lÃ¥ng, kapad till \"%s\"\n" + +# capped är inte ett bra ord IMHO +#: src/transport/plugin_transport_smtp.c:466 +#, c-format +msgid "SMTP filter string to long, capped to `%s'\n" +msgstr "SMTP-filtersträng för lÃ¥ng, kapad till \"%s\"\n" + +#: src/transport/plugin_transport_smtp.c:561 +#: src/transport/plugin_transport_smtp.c:571 +#: src/transport/plugin_transport_smtp.c:584 +#: src/transport/plugin_transport_smtp.c:603 +#: src/transport/plugin_transport_smtp.c:626 +#: src/transport/plugin_transport_smtp.c:634 +#: src/transport/plugin_transport_smtp.c:647 +#: src/transport/plugin_transport_smtp.c:658 +#, fuzzy, c-format +msgid "SMTP: `%s' failed: %s.\n" +msgstr "\"%s\" %s misslyckades: %s\n" + +#: src/transport/plugin_transport_smtp.c:801 +msgid "No email-address specified, can not start SMTP transport.\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:813 +#, fuzzy +msgid "# bytes received via SMTP" +msgstr "# byte mottogs via TCP" + +#: src/transport/plugin_transport_smtp.c:814 +#, fuzzy +msgid "# bytes sent via SMTP" +msgstr "# byte skickades via TCP" + +#: src/transport/plugin_transport_smtp.c:816 +#, fuzzy +msgid "# bytes dropped by SMTP (outgoing)" +msgstr "# byte kastade via TCP (utgÃ¥ende)" + +#: src/transport/plugin_transport_tcp.c:512 +#, c-format +msgid "Unexpected address length: %u bytes\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:616 +#: src/transport/plugin_transport_tcp.c:705 +#: src/transport/plugin_transport_tcp.c:757 +#: src/transport/plugin_transport_tcp.c:830 +#: src/transport/plugin_transport_tcp.c:909 +#, fuzzy +msgid "# bytes currently in TCP buffers" +msgstr "# byte skickades via TCP" + +#: src/transport/plugin_transport_tcp.c:622 +#: src/transport/plugin_transport_tcp.c:856 +#: src/transport/plugin_transport_tcp.c:1561 +#, fuzzy +msgid "# TCP sessions active" +msgstr "# sessionsnycklar accepterade" + +#: src/transport/plugin_transport_tcp.c:709 +#, fuzzy +msgid "# bytes discarded by TCP (timeout)" +msgstr "# byte kastade via TCP (utgÃ¥ende)" + +#: src/transport/plugin_transport_tcp.c:760 +#, fuzzy +msgid "# bytes transmitted via TCP" +msgstr "# byte skickade av typen %d" + +#: src/transport/plugin_transport_tcp.c:834 +#, fuzzy +msgid "# bytes discarded by TCP (disconnect)" +msgstr "# byte kastade via TCP (utgÃ¥ende)" + +#: src/transport/plugin_transport_tcp.c:1081 +#, c-format +msgid "Address of unexpected length: %u\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1116 +msgid "Found valid IPv4 NAT address (creating session)!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1186 +msgid "# transport-service disconnect requests for TCP" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1603 +#, fuzzy +msgid "# TCP WELCOME messages received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/transport/plugin_transport_tcp.c:1756 +msgid "# bytes received via TCP" +msgstr "# byte mottogs via TCP" + +#: src/transport/plugin_transport_tcp.c:1823 +msgid "# network-level TCP disconnect events" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1962 src/util/service.c:889 +#, c-format +msgid "Require valid port number for service `%s' in configuration!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1976 +#, fuzzy +msgid "Failed to start service.\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/transport/plugin_transport_tcp.c:2039 +#, fuzzy, c-format +msgid "Failed to find option %s in section %s!\n" +msgstr "Misslyckades att binda till UDP-port %d.\n" + +#: src/transport/plugin_transport_tcp.c:2062 +#, c-format +msgid "TCP transport listening on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2066 +msgid "TCP transport not listening on any port (client only)\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2070 +#, c-format +msgid "TCP transport advertises itself as being on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_udp_broadcasting.c:130 +#, fuzzy +msgid "# IPv6 multicast HELLO beacons received via udp" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/transport/plugin_transport_udp_broadcasting.c:172 +#, fuzzy +msgid "# IPv4 broadcast HELLO beacons received via udp" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/transport/plugin_transport_udp_broadcasting.c:393 +#, c-format +msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:1985 +#, fuzzy +msgid "Failed to open UDP sockets\n" +msgstr "Misslyckades att binda till UDP6-port %d.\n" + +#: src/transport/plugin_transport_udp.c:2068 +#, c-format +msgid "Given `%s' option is out of range: %llu > %u\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:2112 +#, fuzzy, c-format +msgid "Invalid IPv6 address: `%s'\n" +msgstr "Ogiltigt svar pÃ¥ \"%s\".\n" + +#: src/transport/plugin_transport_unix.c:1051 +#, fuzzy +msgid "Failed to open UNIX sockets\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/transport/plugin_transport_wlan.c:875 +#, fuzzy +msgid "# wlan session timeouts" +msgstr "# sessionsnycklar accepterade" + +#: src/transport/plugin_transport_wlan.c:899 +#, fuzzy +msgid "# wlan session created" +msgstr "# sessionsnycklar accepterade" + +#: src/transport/plugin_transport_wlan.c:980 +#: src/transport/plugin_transport_wlan.c:1138 +#: src/transport/plugin_transport_wlan.c:1159 +#: src/transport/plugin_transport_wlan.c:1190 +#: src/transport/plugin_transport_wlan.c:2334 +#: src/transport/plugin_transport_wlan.c:3142 +msgid "# wlan pending sessions" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1233 +#: src/transport/plugin_transport_wlan.c:1888 +#, fuzzy +msgid "# wlan pending fragments" +msgstr "# byte mottogs via TCP" + +#: src/transport/plugin_transport_wlan.c:1388 +#, c-format +msgid "" +"Finished reading from gnunet-helper-transport-wlan stdout with code: %d\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1732 +msgid "# wlan hello beacons send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1765 +#: src/transport/plugin_transport_wlan.c:1968 +#: src/transport/plugin_transport_wlan.c:2059 +#, c-format +msgid "Error writing to wlan helper. errno == %d, ERROR: %s\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1954 +msgid "# wlan acks send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2025 +#, fuzzy +msgid "# wlan fragments send" +msgstr "# byte mottogs via TCP" + +#: src/transport/plugin_transport_wlan.c:2161 +#, c-format +msgid "Wlan Address len %d is wrong\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2295 +#: src/transport/plugin_transport_wlan.c:2919 +#: src/transport/plugin_transport_wlan.c:3145 +msgid "# wlan mac endpoints" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2517 +#, fuzzy +msgid "# wlan whole messages received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/transport/plugin_transport_wlan.c:2708 +#, fuzzy +msgid "# wlan hello messages received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/transport/plugin_transport_wlan.c:2742 +#, fuzzy +msgid "# wlan fragments received" +msgstr "# byte mottogs via TCP" + +#: src/transport/plugin_transport_wlan.c:2790 +#, fuzzy +msgid "# wlan acks received" +msgstr "# klartext PONG-meddelanden mottagna" + +#: src/transport/plugin_transport_wlan.c:2879 +msgid "# wlan mac endpoints timeouts" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2903 +#, fuzzy +msgid "# wlan mac endpoints created" +msgstr "# byte mottogs via TCP" + +#: src/transport/plugin_transport_wlan.c:2956 +msgid "# wlan WLAN_HELPER_DATA received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:3010 +#, fuzzy +msgid "# wlan messages for this client received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/transport/plugin_transport_wlan.c:3021 +#, fuzzy +msgid "# wlan messages inside WLAN_HELPER_DATA received" +msgstr "# krypterade PONG-meddelanden mottagna" + +#: src/transport/transport_api.c:588 +#, fuzzy, c-format +msgid "Received unexpected message of type %u in %s:%u\n" +msgstr "Mottog skadat meddelande frÃ¥n motpart \"%s\"i %s:%d.\n" + +#: src/util/bio.c:136 src/util/bio.c:142 +#, fuzzy, c-format +msgid "Error reading `%s': %s" +msgstr "Fel vid skapandet av användare" + +#: src/util/bio.c:143 +#, fuzzy +msgid "End of file" +msgstr "Läs in en konfigurationsfil" + +#: src/util/bio.c:195 +#, c-format +msgid "Error reading length of string `%s'" +msgstr "" + +#: src/util/bio.c:205 +#, c-format +msgid "String `%s' longer than allowed (%u > %u)" +msgstr "" + +#: src/util/bio.c:250 +#, c-format +msgid "Serialized metadata `%s' larger than allowed (%u>%u)" +msgstr "" + +#: src/util/bio.c:264 +#, c-format +msgid "Metadata `%s' failed to deserialize" +msgstr "" + +#: src/util/client.c:304 +#, c-format +msgid "" +"Could not determine valid hostname and port for service `%s' from " +"configuration.\n" +msgstr "" + +#: src/util/client.c:312 +#, c-format +msgid "Need a non-empty hostname for service `%s'.\n" +msgstr "" + +#: src/util/client.c:657 +msgid "Failure to transmit TEST request.\n" +msgstr "" + +#: src/util/client.c:717 src/util/service.c:919 +#, c-format +msgid "UNIXPATH `%s' too long, maximum length is %llu\n" +msgstr "" + +#: src/util/client.c:859 +#, fuzzy, c-format +msgid "Could not connect to service `%s', must not be running.\n" +msgstr "Kunde inte ansluta till gnunetd.\n" + +#: src/util/client.c:875 +#, fuzzy, c-format +msgid "Failure to transmit request to service `%s'\n" +msgstr "Misslyckades att skicka HTTP-begäran till värd \"%s\": %s\n" + +#: src/util/client.c:1143 +msgid "Could not submit request, not expecting to receive a response.\n" +msgstr "" + +#: src/util/common_logging.c:239 src/util/common_logging.c:889 +msgid "DEBUG" +msgstr "FELSÖKNING" + +#: src/util/common_logging.c:241 src/util/common_logging.c:887 +msgid "INFO" +msgstr "INFO" + +#: src/util/common_logging.c:243 src/util/common_logging.c:885 +msgid "WARNING" +msgstr "VARNING" + +#: src/util/common_logging.c:245 src/util/common_logging.c:883 +msgid "ERROR" +msgstr "FEL" + +#: src/util/common_logging.c:247 src/util/common_logging.c:891 +msgid "NONE" +msgstr "" + +#: src/util/common_logging.c:609 +#, fuzzy, c-format +msgid "Failed to create or access directory for log file `%s'\n" +msgstr "Kunde inte tolka konfigurationsfil \"%s\".\n" + +#: src/util/common_logging.c:724 +#, c-format +msgid "Message `%.*s' repeated %u times in the last %s\n" +msgstr "" + +#: src/util/common_logging.c:892 +msgid "INVALID" +msgstr "" + +#: src/util/common_logging.c:991 +msgid "unknown address" +msgstr "" + +#: src/util/common_logging.c:1029 +msgid "invalid address" +msgstr "" + +#: src/util/configuration.c:245 +#, fuzzy, c-format +msgid "Syntax error in configuration file `%s' at line %u.\n" +msgstr "Syntaxfel i konfigurationsfil \"%s\" pÃ¥ rad %d.\n" + +#: src/util/configuration.c:817 +#, c-format +msgid "" +"Configuration value '%s' for '%s' in section '%s' is not in set of legal " +"choices\n" +msgstr "" + +#: src/util/connection.c:460 +#, fuzzy, c-format +msgid "Access denied to `%s'\n" +msgstr "Ã…tkomst nekad för \"%s\" vid %s:%d.\n" + +#: src/util/connection.c:475 +#, c-format +msgid "Accepting connection from `%s': %p\n" +msgstr "" + +#: src/util/connection.c:629 +#, fuzzy, c-format +msgid "" +"Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" +msgstr "Misslyckades att starta samling.\n" + +#: src/util/connection.c:821 src/util/connection.c:992 +#, fuzzy, c-format +msgid "Trying to connect to `%s' (%p)\n" +msgstr "Kan inte ansluta till %u.%u.%u.%u:%u: %s\n" + +#: src/util/connection.c:830 +#, fuzzy, c-format +msgid "Failed to connect to `%s' (%p)\n" +msgstr "Kan inte ansluta till %u.%u.%u.%u:%u: %s\n" + +#: src/util/connection.c:983 +#, fuzzy, c-format +msgid "Attempt to connect to `%s' failed\n" +msgstr " Anslutning misslyckades\n" + +#: src/util/connection.c:1465 +#, c-format +msgid "" +"Could not satisfy pending transmission request, socket closed or connect " +"failed (%p).\n" +msgstr "" + +#: src/util/container_bloomfilter.c:507 +#, c-format +msgid "" +"Size of file on disk is incorrect for this Bloom filter (want %llu, have " +"%llu)\n" +msgstr "" + +#: src/util/crypto_random.c:280 +#, c-format +msgid "Starting `%s' process to generate entropy\n" +msgstr "" + +#: src/util/crypto_random.c:309 +#, c-format +msgid "libgcrypt has not the expected version (version %s is required).\n" +msgstr "libgcrypt har inte den förväntande versionen (version %s krävs).\n" + +#: src/util/crypto_rsa.c:618 src/util/crypto_rsa.c:665 +#, fuzzy, c-format +msgid "Could not aquire lock on file `%s': %s...\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/util/crypto_rsa.c:623 +#, fuzzy +msgid "Creating a new private key. This may take a while.\n" +msgstr "Skapar ny värdnyckel (det här kan ta en stund).\n" + +#: src/util/crypto_rsa.c:641 +#, c-format +msgid "I am host `%s'. Stored new private key in `%s'.\n" +msgstr "" + +#: src/util/crypto_rsa.c:669 src/util/crypto_rsa.c:705 +msgid "This may be ok if someone is currently generating a hostkey.\n" +msgstr "" + +#: src/util/crypto_rsa.c:700 +#, c-format +msgid "" +"When trying to read hostkey file `%s' I found %u bytes but I need at least " +"%u.\n" +msgstr "" + +#: src/util/crypto_rsa.c:720 +#, fuzzy, c-format +msgid "File `%s' does not contain a valid private key. Deleting it.\n" +msgstr "Filen \"%s\" innehÃ¥ller ingen pseudonym.\n" + +#: src/util/crypto_rsa.c:738 +#, fuzzy, c-format +msgid "I am host `%s'. Read private key from `%s'.\n" +msgstr "Anrop till \"%s\" med nyckel \"%s\".\n" + +#: src/util/crypto_rsa.c:959 +#, c-format +msgid "RSA signature verification failed at %s:%d: %s\n" +msgstr "" + +# drive = hard drive ? +#: src/util/disk.c:479 +#, fuzzy, c-format +msgid "`%s' failed for drive `%S': %u\n" +msgstr "\"%s\" misslyckades för enhet %s: %u\n" + +#: src/util/disk.c:1087 +#, fuzzy, c-format +msgid "Expected `%s' to be a directory!\n" +msgstr "\"%s\" förväntade att \"%s\" skulle vara en katalog!\n" + +#: src/util/disk.c:1441 src/util/service.c:1580 +#, fuzzy, c-format +msgid "Cannot obtain information about user `%s': %s\n" +msgstr "Kan inte öppna konfigurationsfil \"%s\".\n" + +#: src/util/disk.c:1759 +#, fuzzy, c-format +msgid "No `%s' specified for service `%s' in configuration.\n" +msgstr "Inga applikationer definierade i konfiguration!\n" + +#: src/util/getopt.c:672 +#, c-format +msgid "%s: option `%s' is ambiguous\n" +msgstr "%s: flagga \"%s\" är tvetydig\n" + +#: src/util/getopt.c:696 +#, c-format +msgid "%s: option `--%s' does not allow an argument\n" +msgstr "%s: flagga \"--%s\" tillÃ¥ter inte ett argument\n" + +#: src/util/getopt.c:701 +#, c-format +msgid "%s: option `%c%s' does not allow an argument\n" +msgstr "%s: flagga \"%c%s\" tillÃ¥ter inte ett argument\n" + +#: src/util/getopt.c:718 src/util/getopt.c:886 +#, c-format +msgid "%s: option `%s' requires an argument\n" +msgstr "%s: flagga \"%s\" kräver ett argument\n" + +#: src/util/getopt.c:747 +#, c-format +msgid "%s: unrecognized option `--%s'\n" +msgstr "%s: okänd flagga \"--%s\"\n" + +#: src/util/getopt.c:751 +#, c-format +msgid "%s: unrecognized option `%c%s'\n" +msgstr "%s: okänd flagga \"%c%s\"\n" + +#: src/util/getopt.c:776 +#, c-format +msgid "%s: illegal option -- %c\n" +msgstr "%s: otillÃ¥ten flagga -- %c\n" + +#: src/util/getopt.c:778 +#, c-format +msgid "%s: invalid option -- %c\n" +msgstr "%s: ogiltig flagga -- %c\n" + +#: src/util/getopt.c:806 src/util/getopt.c:934 +#, c-format +msgid "%s: option requires an argument -- %c\n" +msgstr "%s: flagga kräver ett argument -- %c\n" + +#: src/util/getopt.c:854 +#, c-format +msgid "%s: option `-W %s' is ambiguous\n" +msgstr "%s: flagga \"-W %s\" är tvetydig\n" + +#: src/util/getopt.c:872 +#, c-format +msgid "%s: option `-W %s' does not allow an argument\n" +msgstr "%s: flagga \"-W %s\" tillÃ¥ter inte ett argument\n" + +#: src/util/getopt.c:1038 +#, fuzzy, c-format +msgid "Use %s to get a list of options.\n" +msgstr "Använd --help för att fÃ¥ en lista pÃ¥ flaggor.\n" + +#: src/util/getopt_helpers.c:84 +#, c-format +msgid "" +"Arguments mandatory for long options are also mandatory for short options.\n" +msgstr "" +"Argument som är obligatoriska för lÃ¥nga flaggor är ocksÃ¥ obligatoriska för " +"korta flaggor.\n" + +#: src/util/getopt_helpers.c:255 src/util/getopt_helpers.c:283 +#, c-format +msgid "You must pass a number to the `%s' option.\n" +msgstr "Du mÃ¥ste skicka med ett nummer till flaggan \"%s\".\n" + +#: src/util/gnunet-resolver.c:148 +msgid "perform a reverse lookup" +msgstr "" + +#: src/util/gnunet-resolver.c:154 +msgid "Use build-in GNUnet stub resolver" +msgstr "" + +#: src/util/gnunet-service-resolver.c:288 +#, fuzzy, c-format +msgid "Could not resolve `%s' (%s): %s\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/util/gnunet-service-resolver.c:358 +#: src/util/gnunet-service-resolver.c:399 +#, c-format +msgid "Could not find IP of host `%s': %s\n" +msgstr "" + +#: src/util/gnunet-service-resolver.c:494 +#, c-format +msgid "Resolver asked to look up `%s'.\n" +msgstr "" + +#: src/util/gnunet-service-resolver.c:529 +#, c-format +msgid "Resolver asked to look up IP address `%s'.\n" +msgstr "" + +#: src/util/helper.c:239 +#, fuzzy, c-format +msgid "Error reading from `%s': %s\n" +msgstr "Fel vid skapandet av användare" + +#: src/util/helper.c:254 +#, c-format +msgid "Got 0 bytes from helper `%s' (EOF)\n" +msgstr "" + +#: src/util/helper.c:264 +#, c-format +msgid "Got %u bytes from helper `%s'\n" +msgstr "" + +#: src/util/helper.c:273 +#, fuzzy, c-format +msgid "Failed to parse inbound message from helper `%s'\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/util/helper.c:432 +#, fuzzy, c-format +msgid "Error writing to `%s': %s\n" +msgstr "Fel vid skapandet av användare" + +#: src/util/network.c:1196 +#, c-format +msgid "" +"Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" +msgstr "" + +#: src/util/os_installation.c:299 +#, c-format +msgid "" +"Could not determine installation path for %s. Set `%s' environment " +"variable.\n" +msgstr "" + +#: src/util/os_installation.c:486 +#, fuzzy, c-format +msgid "Could not find binary `%s' in PATH!\n" +msgstr "Kunde inte hitta motpart \"%s\" i routingtabell!\n" + +#: src/util/os_installation.c:492 +#, fuzzy, c-format +msgid "access (%s, X_OK) failed: %s\n" +msgstr "\"%s\" %s misslyckades: %s\n" + +#: src/util/os_installation.c:507 +#, fuzzy, c-format +msgid "stat (%s) failed: %s\n" +msgstr "\"%s\" %s misslyckades: %s\n" + +#: src/util/os_priority.c:304 +#, fuzzy, c-format +msgid "Failed to open named pipe `%s' for reading: %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/util/os_priority.c:305 +#, fuzzy, c-format +msgid "Failed to open named pipe `%s' for writing: %s\n" +msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#: src/util/plugin.c:89 +#, c-format +msgid "Initialization of plugin mechanism failed: %s!\n" +msgstr "Initiering av insticksmekanism misslyckades: %s!\n" + +#: src/util/plugin.c:146 +#, fuzzy, c-format +msgid "`%s' failed to resolve method '%s' with error: %s\n" +msgstr "\"%s\" misslyckades för fil \"%s\" vid %s:%d med fel: %s\n" + +#: src/util/plugin.c:219 +#, fuzzy, c-format +msgid "`%s' failed for library `%s' with error: %s\n" +msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" + +#: src/util/plugin.c:349 +#, fuzzy +msgid "Could not determine plugin installation path.\n" +msgstr "Kunde inte fastställa min publika IPv6-adress.\n" + +#: src/util/pseudonym.c:273 +#, fuzzy, c-format +msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/util/pseudonym.c:338 +#, fuzzy +msgid "no-name" +msgstr "Visa namn" + +#: src/util/resolver_api.c:202 +#, fuzzy, c-format +msgid "Must specify `%s' for `%s' in configuration!\n" +msgstr "Försöker använda fil \"%s\" för MySQL-konfiguration.\n" + +#: src/util/resolver_api.c:221 +#, fuzzy, c-format +msgid "" +"Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" +msgstr "" +"Du mÃ¥ste ange ett positivt nummer för \"%s\" i konfigurationen i sektion \"%s" +"\".\n" + +#: src/util/resolver_api.c:351 +#, c-format +msgid "Timeout trying to resolve IP address `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:355 +#, fuzzy, c-format +msgid "Timeout trying to resolve hostname `%s'.\n" +msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#: src/util/resolver_api.c:426 +#, c-format +msgid "Resolver returns `%s' for IP `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:807 +#, c-format +msgid "Resolver returns `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:901 +#, c-format +msgid "Resolving our FQDN `%s'\n" +msgstr "" + +#: src/util/resolver_api.c:906 +#, fuzzy, c-format +msgid "Could not resolve our FQDN : %s\n" +msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#: src/util/resolver_api.c:938 +#, c-format +msgid "Resolving our hostname `%s'\n" +msgstr "" + +#: src/util/scheduler.c:866 +msgid "Looks like we're busy waiting...\n" +msgstr "" + +#: src/util/scheduler.c:996 +#, c-format +msgid "Attempt to cancel dead task %llu!\n" +msgstr "" + +# drive = hard drive ? +#: src/util/server.c:397 +#, fuzzy, c-format +msgid "`%s' failed for port %d (%s).\n" +msgstr "\"%s\" misslyckades för enhet %s: %u\n" + +#: src/util/server.c:406 +#, fuzzy, c-format +msgid "`%s' failed for port %d (%s): address already in use\n" +msgstr "\"%s\" misslyckades för port %d: %s. Körs verkligen gnunetd?\n" + +#: src/util/server.c:411 +#, fuzzy, c-format +msgid "`%s' failed for `%s': address already in use\n" +msgstr "\"%s\" misslyckades för port %d: %s. Körs verkligen gnunetd?\n" + +#: src/util/server.c:640 +#, c-format +msgid "" +"Processing code for message of type %u did not call " +"GNUNET_SERVER_receive_done after %llums\n" +msgstr "" + +#: src/util/service.c:117 src/util/service.c:143 src/util/service.c:186 +#: src/util/service.c:207 src/util/service.c:214 +#, c-format +msgid "Invalid format for IP: `%s'\n" +msgstr "Ogiltigt format för IP: \"%s\"\n" + +#: src/util/service.c:170 +#, c-format +msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." +msgstr "Ogiltig nätverksnotation (\"/%d\" är inte giltig i IPv4 CIDR)." + +#: src/util/service.c:263 +#, c-format +msgid "Invalid network notation (does not end with ';': `%s')\n" +msgstr "Ogiltig nätverksnotation (slutar inte med \";\": \"%s\")\n" + +#: src/util/service.c:296 +#, fuzzy, c-format +msgid "Wrong format `%s' for netmask\n" +msgstr "Fel format \"%s\" för nätmask: %s\n" + +#: src/util/service.c:326 +#, fuzzy, c-format +msgid "Wrong format `%s' for network\n" +msgstr "Fel format \"%s\" för nätverk: %s\n" + +#: src/util/service.c:668 +#, c-format +msgid "Access denied to UID %d / GID %d\n" +msgstr "" + +#: src/util/service.c:673 +#, fuzzy, c-format +msgid "Unknown address family %d\n" +msgstr "Okänd operation \"%s\"\n" + +#: src/util/service.c:680 +#, c-format +msgid "Access from `%s' denied to service `%s'\n" +msgstr "" + +#: src/util/service.c:724 +#, c-format +msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:752 +#, c-format +msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:869 +#, c-format +msgid "" +"Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" +msgstr "" + +#: src/util/service.c:939 +#, c-format +msgid "" +"Disabling UNIX domain socket support for service `%s', failed to create UNIX " +"domain socket: %s\n" +msgstr "" + +#: src/util/service.c:956 +#, c-format +msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" +msgstr "" + +#: src/util/service.c:1191 +msgid "Could not access a pre-bound socket, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1242 src/util/service.c:1260 +#, c-format +msgid "Specified value for `%s' of service `%s' is invalid\n" +msgstr "" + +#: src/util/service.c:1287 +#, c-format +msgid "Could not access pre-bound socket %u, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1442 +#, fuzzy, c-format +msgid "Failed to start `%s' at `%s'\n" +msgstr "Fel vid %s:%d.\n" + +#: src/util/service.c:1475 +#, fuzzy, c-format +msgid "Service `%s' runs at %s\n" +msgstr "Motpart \"%s\" med pÃ¥litlighet %8u och adress \"%s\"\n" + +#: src/util/service.c:1521 +msgid "Service process failed to initialize\n" +msgstr "" + +#: src/util/service.c:1525 +msgid "Service process could not initialize server function\n" +msgstr "" + +#: src/util/service.c:1529 +msgid "Service process failed to report status\n" +msgstr "" + +#: src/util/service.c:1581 +msgid "No such user" +msgstr "" + +#: src/util/service.c:1594 +#, c-format +msgid "Cannot change user/group to `%s': %s\n" +msgstr "Kan inte ändra användare/grupp till \"%s\": %s\n" + +#: src/util/service.c:1657 +msgid "do daemonize (detach from terminal)" +msgstr "" + +#: src/util/signal.c:80 +#, fuzzy, c-format +msgid "signal (%d, %p) returned %d.\n" +msgstr "Anrop till \"%s\" returnerade %d.\n" + +#: src/util/strings.c:143 +msgid "b" +msgstr "b" + +#: src/util/strings.c:354 +#, c-format +msgid "Character sets requested were `%s'->`%s'\n" +msgstr "" + +#: src/util/strings.c:462 +msgid "Failed to expand `$HOME': environment variable `HOME' not set" +msgstr "" + +#: src/util/strings.c:554 +msgid "ms" +msgstr "ms" + +#: src/util/strings.c:559 +msgid "eternity" +msgstr "" + +#: src/util/strings.c:563 +msgid "s" +msgstr "s" + +#: src/util/strings.c:567 +msgid "m" +msgstr "m" + +#: src/util/strings.c:571 +msgid "h" +msgstr "h" + +#: src/util/strings.c:575 +msgid " days" +msgstr " dagar" + +#: src/util/strings.c:599 +msgid "end of time" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1065 +#, fuzzy +msgid "# Active tunnels" +msgstr "Nätverksanslutning" + +#: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 +#, fuzzy +msgid "# Peers connected to mesh tunnels" +msgstr "# av anslutna parter" + +#: src/vpn/gnunet-service-vpn.c:699 +#, fuzzy +msgid "# Bytes given to mesh for transmission" +msgstr "# PING-meddelanden skapade" + +#: src/vpn/gnunet-service-vpn.c:737 +#, fuzzy +msgid "# Bytes dropped in mesh queue (overflow)" +msgstr "# byte kastade via UDP (utgÃ¥ende)" + +#: src/vpn/gnunet-service-vpn.c:772 +#, fuzzy +msgid "# Mesh tunnels created" +msgstr "# PING-meddelanden skapade" + +#: src/vpn/gnunet-service-vpn.c:795 +#, fuzzy +msgid "Failed to setup mesh tunnel!\n" +msgstr "Kunde inte skapa värdnyckel!\n" + +#: src/vpn/gnunet-service-vpn.c:967 +#, c-format +msgid "Protocol %u not supported, dropping\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1285 +msgid "# ICMPv4 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1306 +msgid "# ICMPv6 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1511 +#, fuzzy +msgid "# Packets received from TUN interface" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/vpn/gnunet-service-vpn.c:1549 src/vpn/gnunet-service-vpn.c:1590 +#, c-format +msgid "Packet received for unmapped destination `%s' (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1600 +msgid "Received IPv4 packet with options (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1614 +#, c-format +msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1697 +#, fuzzy +msgid "# ICMP packets received from mesh" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/vpn/gnunet-service-vpn.c:2038 +#, fuzzy +msgid "# UDP packets received from mesh" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/vpn/gnunet-service-vpn.c:2196 +#, fuzzy +msgid "# TCP packets received from mesh" +msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" + +#: src/vpn/gnunet-service-vpn.c:2347 +msgid "Failed to find unallocated IPv4 address in VPN's range\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2402 +msgid "Failed to find unallocated IPv6 address in VPN's range\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2441 src/vpn/gnunet-service-vpn.c:2624 +#, fuzzy +msgid "# Active destinations" +msgstr "Nätverksanslutning" + +#: src/vpn/gnunet-service-vpn.c:2726 +msgid "Failed to allocate IP address for new destination\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3133 +msgid "IPv6 support disabled as this system does not support IPv6\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3165 +msgid "IPv4 support disabled as this system does not support IPv4\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:151 +#, fuzzy +msgid "Error creating tunnel\n" +msgstr "Klar med skapandet av värdnyckel.\n" + +#: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 +#, fuzzy, c-format +msgid "Option `%s' makes no sense with option `%s'.\n" +msgstr "Kommando \"%s\" kräver ett argument (\"%s\").\n" + +#: src/vpn/gnunet-vpn.c:208 +#, fuzzy, c-format +msgid "Option `%s' or `%s' is required.\n" +msgstr "%s: flagga \"%s\" är tvetydig\n" + +#: src/vpn/gnunet-vpn.c:220 +#, fuzzy, c-format +msgid "Option `%s' or `%s' is required when using option `%s'.\n" +msgstr "Kommando \"%s\" kräver ett argument (\"%s\").\n" + +#: src/vpn/gnunet-vpn.c:238 +#, fuzzy, c-format +msgid "`%s' is not a valid peer identifier.\n" +msgstr "\"%s\" är inte en vanlig fil.\n" + +#: src/vpn/gnunet-vpn.c:260 +#, fuzzy, c-format +msgid "`%s' is not a valid IP address.\n" +msgstr "\"%s\" är inte tillgänglig." + +#: src/vpn/gnunet-vpn.c:296 +msgid "request that result should be an IPv4 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:299 +msgid "request that result should be an IPv6 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:302 +msgid "print IP address only after mesh tunnel has been created" +msgstr "" + +#: src/vpn/gnunet-vpn.c:305 +msgid "how long should the mapping be valid for new tunnels?" +msgstr "" + +#: src/vpn/gnunet-vpn.c:308 +msgid "destination IP for the tunnel" +msgstr "" + +#: src/vpn/gnunet-vpn.c:311 +msgid "peer offering the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:314 +msgid "name of the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:317 +#, fuzzy +msgid "service is offered via TCP" +msgstr "# byte mottogs via TCP" + +#: src/vpn/gnunet-vpn.c:320 +#, fuzzy +msgid "service is offered via UDP" +msgstr "# byte mottagna via UDP" + +#: src/vpn/gnunet-vpn.c:329 +msgid "Setup tunnels via VPN." +msgstr "" + +#: src/include/gnunet_common.h:479 src/include/gnunet_common.h:484 +#: src/include/gnunet_common.h:490 +#, fuzzy, c-format +msgid "Assertion failed at %s:%d.\n" +msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" + +#: src/include/gnunet_common.h:500 +#, c-format +msgid "External protocol violation detected at %s:%d.\n" +msgstr "" + +#: src/include/gnunet_common.h:521 src/include/gnunet_common.h:528 +#, c-format +msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" +msgstr "\"%s\" misslyckades för fil \"%s\" vid %s:%d med fel: %s\n" + +#, fuzzy +#~ msgid "Failed to send to `%s': %s\n" +#~ msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#, fuzzy +#~ msgid "Could not access file: %s\n" +#~ msgstr "Kunde inte köra \"%s\": %s\n" + +# drive = hard drive ? +#, fuzzy +#~ msgid "`%s' failed on file `%s': %s" +#~ msgstr "\"%s\" misslyckades för enhet %s: %u\n" + +#, fuzzy +#~ msgid "# bytes TCP was asked to transmit" +#~ msgstr "# byte skickade av typen %d" + +#, fuzzy +#~ msgid "# bytes discarded by TCP (failed to connect)" +#~ msgstr "# byte kastade via TCP (utgÃ¥ende)" + +#, fuzzy +#~ msgid "# wlan messages queued" +#~ msgstr "# krypterade PONG-meddelanden mottagna" + +#~ msgid "print this help" +#~ msgstr "skriv ut denna hjälp" + +#~ msgid "print the version number" +#~ msgstr "skriv ut versionsnummer" + +#~ msgid "be verbose" +#~ msgstr "var informativ" + +#~ msgid "use configuration file FILENAME" +#~ msgstr "använd konfigurationsfil FILNAMN" + +#, fuzzy +#~ msgid "Failed to stop service `%s'!\n" +#~ msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#, fuzzy +#~ msgid "Failed to start service `%s'!\n" +#~ msgstr "Misslyckades att starta samling.\n" + +#, fuzzy +#~ msgid "Service `%s' stopped\n" +#~ msgstr "Tjänst borttagen.\n" + +#, fuzzy +#~ msgid "Unable to start service `%s': %s\n" +#~ msgstr "Kunde inte spara konfigurationsfil \"%s\":" + +#, fuzzy +#~ msgid "Unable to accept connection for service `%s': %s\n" +#~ msgstr "Kunde inte spara konfigurationsfil \"%s\":" + +#, fuzzy +#~ msgid "Service `%s' started\n" +#~ msgstr "Tjänst borttagen.\n" + +#, fuzzy +#~ msgid "Peer `%s' plugin: `%s' address `%s'\n" +#~ msgstr "Motpart \"%s\" med pÃ¥litlighet %8u och adress \"%s\"\n" + +#, fuzzy +#~ msgid "Failed to create IPv4 broadcast socket on port %d\n" +#~ msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#, fuzzy +#~ msgid "Failed to load block plugin `%s'\n" +#~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#, fuzzy +#~ msgid "Could not resolve our FQDN : %s %u\n" +#~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#, fuzzy +#~ msgid "Failed to load dhtlog plugin for `%s'\n" +#~ msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#, fuzzy +#~ msgid "Failed to get full path for `%s'\n" +#~ msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" + +#, fuzzy +#~ msgid "Failed to create file for dhtlog.\n" +#~ msgstr "Kunde inte skapa användarkonto:" + +#, fuzzy +#~ msgid "Found peer `%s'\n" +#~ msgstr "Jag är ändpunkt \"%s\".\n" + +#, fuzzy +#~ msgid "Loading udp transport plugin\n" +#~ msgstr "Testar transport(er) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for udp\n" +#~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#, fuzzy +#~ msgid "# SET QUOTA messages received" +#~ msgstr "# krypterade PONG-meddelanden mottagna" + +#, fuzzy +#~ msgid "curl failed for `%s' at %s:%d: `%s'\n" +#~ msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" + +#, fuzzy +#~ msgid "Phase 3: sending messages\n" +#~ msgstr "Misslyckades att leverera \"%s\" meddelande.\n" + +#, fuzzy +#~ msgid "Loading HTTPS transport plugin `%s'\n" +#~ msgstr "Testar transport(er) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for https\n" +#~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#, fuzzy +#~ msgid "Fail! Could not connect peers\n" +#~ msgstr "\"%s\": Kunde inte ansluta.\n" + +#, fuzzy +#~ msgid "Loading tcp transport plugin\n" +#~ msgstr "Testar transport(er) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for tcp\n" +#~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#, fuzzy +#~ msgid "Connection: %X: %s failed at %s:%d: `%s'\n" +#~ msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" + +#, fuzzy +#~ msgid "Misconfigured address to bind to in configuration!\n" +#~ msgstr "Inga applikationer definierade i konfiguration!\n" + +#, fuzzy +#~ msgid "Loading HTTP transport plugin `%s'\n" +#~ msgstr "Testar transport(er) %s\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for http\n" +#~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" + +#, fuzzy +#~ msgid "# PING messages decrypted" +#~ msgstr "# PING-meddelanden skapade" + +#, fuzzy +#~ msgid "Failed to connect to core service\n" +#~ msgstr "Misslyckades att ansluta till gnunetd.\n" + +#, fuzzy +#~ msgid "# bytes successfully transmitted by plugins" +#~ msgstr "# byte skickade av typen %d" + +#, fuzzy +#~ msgid "# connected addresses" +#~ msgstr "# av anslutna parter" + +#, fuzzy +#~ msgid "# transport failed to selected peer address" +#~ msgstr "Annonserar min transport %d till valda ändpunkter.\n" + +#, fuzzy +#~ msgid "# PING with HELLO messages sent" +#~ msgstr "# PING-meddelanden skapade" + +#, fuzzy +#~ msgid "Received `%s' message from `%s' destined for `%s' which is not me!\n" +#~ msgstr "Mottog PING som ej var ämnat för oss!\n" + +#, fuzzy +#~ msgid "Could not send PONG to `%s': no address available\n" +#~ msgstr "Kunde inte hitta motpart \"%s\" i routingtabell!\n" + +#~ msgid "Error" +#~ msgstr "Fel" + +#~ msgid "Help" +#~ msgstr "Hjälp" + +#, fuzzy +#~ msgid "Error!" +#~ msgstr "Fel" + +#~ msgid "No" +#~ msgstr "Nej" + +#~ msgid "Yes" +#~ msgstr "Ja" + +#, fuzzy +#~ msgid "Abort" +#~ msgstr "_Om" + +#, fuzzy +#~ msgid "Ok" +#~ msgstr "k" + +#~ msgid "GNUnet configuration" +#~ msgstr "GNUnet-konfiguration" + +#~ msgid "" +#~ "Welcome to GNUnet!\n" +#~ "\n" +#~ "This assistant will ask you a few basic questions in order to configure " +#~ "GNUnet.\n" +#~ "\n" +#~ "Please visit our homepage at\n" +#~ "\thttp://gnunet.org/\n" +#~ "and join our community at\n" +#~ "\thttp://gnunet.org/drupal/\n" +#~ "\n" +#~ "Have a lot of fun,\n" +#~ "\n" +#~ "the GNUnet team" +#~ msgstr "" +#~ "Välkommen till GNUnet!\n" +#~ "\n" +#~ "Denna assistant kommer att frÃ¥ga dig nÃ¥gra enkla frÃ¥gor för att " +#~ "konfigurera GNUnet.\n" +#~ "\n" +#~ "Vänligen besök pÃ¥ webbplats pÃ¥\n" +#~ "\thttp://gnunet.org/\n" +#~ "och gÃ¥ med i vÃ¥r gemenskap pÃ¥\n" +#~ "\thttp://gnunet.org/drupal/\n" +#~ "\n" +#~ "Ha det sÃ¥ kul,\n" +#~ "\n" +#~ "the GNUnet team" + +#, fuzzy +#~ msgid "Network configuration: interface" +#~ msgstr "Nätverksgränssnitt:" + +#, fuzzy +#~ msgid "Network configuration: IP" +#~ msgstr "GNUnet-konfiguration" + +#, fuzzy +#~ msgid "Bandwidth configuration: upload" +#~ msgstr "GNUnet-konfiguration" + +#, fuzzy +#~ msgid "How much upstream bandwidth (in bytes/s) may be used?" +#~ msgstr "Hur mycket CPU (i %) fÃ¥r användas?" + +#, fuzzy +#~ msgid "Bandwidth configuration: download" +#~ msgstr "GNUnet-konfiguration" + +#, fuzzy +#~ msgid "How much downstream bandwidth (in bytes/s) may be used?" +#~ msgstr "Hur mycket CPU (i %) fÃ¥r användas?" + +#, fuzzy +#~ msgid "Quota configuration" +#~ msgstr "GNUnet-konfiguration" + +#, fuzzy +#~ msgid "Daemon configuration: user account" +#~ msgstr "Kunde inte skapa användarkonto:" + +#, fuzzy +#~ msgid "Save configuration?" +#~ msgstr "GNUnet-konfiguration" + +#, fuzzy +#~ msgid "GNUnet Configuration" +#~ msgstr "GNUnet-konfiguration" + +#~ msgid "Back" +#~ msgstr "Tillbaka" + +#~ msgid "Up" +#~ msgstr "Upp" + +#~ msgid "Cancel" +#~ msgstr "Avbryt" + +#, fuzzy +#~ msgid "Configuration unchanged, no need to save.\n" +#~ msgstr "" +#~ "Konfiguration eller version av GNUnet ändrad. Du behöver köra \"%s\"!\n" + +#, fuzzy +#~ msgid "Do you wish to save your new configuration?" +#~ msgstr "Vill du spara dina inställningar?" + +#~ msgid "This version of Windows doesn't support services.\n" +#~ msgstr "Denna version av Windows har inte stöd för tjänster.\n" + +#~ msgid "Error: can't create service: %s\n" +#~ msgstr "Fel: kan inte skapa tjänst: %s\n" + +#~ msgid "Error: can't delete service: %s\n" +#~ msgstr "Fel: kan inte ta bort tjänst: %s\n" + +#, fuzzy +#~ msgid "Configuration changed. Save?" +#~ msgstr "Konfigurationsfil \"%s\" skapad.\n" + +#, fuzzy +#~ msgid "Error saving configuration." +#~ msgstr "Kunde inte spara konfiguration!" + +#, fuzzy +#~ msgid "(unknown connection)" +#~ msgstr "Nätverksanslutning" + +#, fuzzy +#~ msgid "Do you want to save the new configuration?" +#~ msgstr "Vill du spara dina inställningar?" + +#~ msgid "Tool to setup GNUnet." +#~ msgstr "Verktyg för att ställa in GNUnet." + +#, fuzzy +#~ msgid "Too many arguments.\n" +#~ msgstr "Ogiltiga kommandoradsargument.\n" + +#, fuzzy +#~ msgid "No interface specified, using default.\n" +#~ msgstr "Inget tabellnamn angivet, använder \"%s\".\n" + +#, fuzzy +#~ msgid "Configuration file `%s' must be a filename (but is a directory).\n" +#~ msgstr "Konfigurationsfil \"%s\" skapad.\n" + +#, fuzzy +#~ msgid "Unknown operation '%s'.\n" +#~ msgstr "Okänd operation \"%s\"\n" + +#, fuzzy +#~ msgid "yes" +#~ msgstr "Ja" + +#, fuzzy +#~ msgid "Yes\n" +#~ msgstr "Ja" + +#, fuzzy +#~ msgid "No\n" +#~ msgstr "Nej" + +#, fuzzy +#~ msgid "Help\n" +#~ msgstr "Hjälp" + +#, fuzzy +#~ msgid "Abort\n" +#~ msgstr "_Om" + +#, fuzzy +#~ msgid "Configuration was unchanged, no need to save.\n" +#~ msgstr "" +#~ "Konfiguration eller version av GNUnet ändrad. Du behöver köra \"%s\"!\n" + +#~ msgid "Can't create service" +#~ msgstr "Kan inte skapa tjänst" + +#~ msgid "Error changing the permissions of the GNUnet directory" +#~ msgstr "Fel vid ändring av rättigheterna pÃ¥ GNUnet-katalogen" + +#, fuzzy +#~ msgid "Cannot write to the registry" +#~ msgstr "Kan inte skriva till registret" + +#~ msgid "Can't delete the service" +#~ msgstr "Kan inte ta bort tjänsten" + +#~ msgid "This version of Windows does not support multiple users." +#~ msgstr "Denna version för Windows har inte stöd för flera användare." + +#~ msgid "Error accessing local security policy" +#~ msgstr "Fel vid Ã¥tkomst av lokal säkerhetspolicy" + +#~ msgid "Unknown error while creating a new user" +#~ msgstr "Okänt fel vid skapandet av ny användare" + +#~ msgid "FATAL" +#~ msgstr "ÖDESDIGER" + +#~ msgid "NOTHING" +#~ msgstr "INGET" + +#, fuzzy +#~ msgid "Syntax error in configuration entry HOST in section NETWORK: `%s'\n" +#~ msgstr "Syntaxfel i konfigurationsfil \"%s\" pÃ¥ rad %d.\n" + +#, fuzzy +#~ msgid "Reading result from gnunetd failed, reply invalid!\n" +#~ msgstr "\"%s\" misslyckades, svar ogiltigt!\n" + +#, fuzzy +#~ msgid "No interface specified in section `%s' under `%s'!\n" +#~ msgstr "" +#~ "Inga nätverksgränssnitt angivna i konfigurationssektionen \"%s\" under " +#~ "\"%s\"!\n" + +#, fuzzy +#~ msgid "`%s' returned with error code %u" +#~ msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" + +#~ msgid "Can't create semaphore: %i" +#~ msgstr "Kan inte skapa semafor: %i" + +#~ msgid "Cannot query the CPU usage (Windows NT).\n" +#~ msgstr "Kan inte frÃ¥ga efter CPU-användning (Windows NT).\n" + +#~ msgid "Cannot query the CPU usage (Win 9x)\n" +#~ msgstr "Kan inte frÃ¥ga efter CPU-användning (Win 9x).\n" + +#~ msgid "" +#~ "No network interfaces defined in configuration section `%s' under `%s'!\n" +#~ msgstr "" +#~ "Inga nätverksgränssnitt angivna i konfigurationssektionen \"%s\" under " +#~ "\"%s\"!\n" + +#, fuzzy +#~ msgid "Command `%s' failed with error code %u\n" +#~ msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" + +#, fuzzy +#~ msgid "Real-time delay violation (%llu ms) at %s:%u\n" +#~ msgstr "Icke-förväntad mycket stor allokering (%u byte) vid %s:%d!\n" + +#, fuzzy +#~ msgid "`%s' failed with error code %d: %s\n" +#~ msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" + +#, fuzzy +#~ msgid "GNUnet error log" +#~ msgstr "SpÃ¥ra GNUnets nätverkstopologi." + +#~ msgid "Availability test failed for `%s' at %s:%d.\n" +#~ msgstr "Tillgänglighetstest misslyckades för \"%s\" vid %s:%d.\n" + +#, fuzzy +#~ msgid "Starting datastore conversion (this may take a while).\n" +#~ msgstr "Skapar ny värdnyckel (det här kan ta en stund).\n" + +#, fuzzy +#~ msgid "" +#~ "%s:%d - RPC %s:%p could not be registered: another callback is already " +#~ "using this name (%p)\n" +#~ msgstr "%s::%s - RPC %s:%p kunde inte avregistreras: hittades inte\n" + +#, fuzzy +#~ msgid "%s:%d - async RPC %s:%p could not be unregistered: not found\n" +#~ msgstr "%s::%s - RPC %s:%p kunde inte avregistreras: hittades inte\n" + +#~ msgid "`%s' registering handlers %d %d %d\n" +#~ msgstr "\"%s\" registrerar handtag %d %d %d\n" + +#~ msgid "output in gnuplot format" +#~ msgstr "utdata i gnuplot-format" + +#~ msgid "number of iterations" +#~ msgstr "antal iterationer" + +#~ msgid "number of messages to use per iteration" +#~ msgstr "antal meddelanden att använda per iteration" + +#~ msgid "message size" +#~ msgstr "meddelandestorlek" + +#~ msgid "number of messages in a message block" +#~ msgstr "antal meddelanden i ett meddelandeblock" + +#~ msgid "You must specify a receiver!\n" +#~ msgstr "Du mÃ¥ste ange en mottagare!\n" + +#~ msgid "Time:\n" +#~ msgstr "Tid:\n" + +#~ msgid "\tmax %llums\n" +#~ msgstr "\tmax %llums\n" + +#~ msgid "\tmin %llums\n" +#~ msgstr "\tmin %llums\n" + +#~ msgid "\tmax %u\n" +#~ msgstr "\tmax %u\n" + +#~ msgid "\tmin %u\n" +#~ msgstr "\tmin %u\n" + +#~ msgid "Output format not known, this should not happen.\n" +#~ msgstr "Utdataformat är inte känt, detta bör inte hända.\n" + +#, fuzzy +#~ msgid "# bytes received in plaintext of type %d" +#~ msgstr "# byte mottagna av typen %d" + +#, fuzzy +#~ msgid "use PRIORITY for the priority of the trace request" +#~ msgstr "ange prioritet för innehÃ¥llet" + +#~ msgid "allows mapping of the network topology" +#~ msgstr "tillÃ¥ter kartläggning av nätverkstopologin" + +#, fuzzy +#~ msgid "HELLO message from `%s' has an invalid signature. Dropping.\n" +#~ msgstr "Meddelande frÃ¥n \"%s\" kastades bort: ogiltigt format.\n" + +#~ msgid "`%s' registering handler %d (plaintext and ciphertext)\n" +#~ msgstr "\"%s\" registrerar handtag %d (klartext och kryptotext)\n" + +#~ msgid "`%s' registering handler %d\n" +#~ msgstr "\"%s\" registrerar handtag %d\n" + +#, fuzzy +#~ msgid "`%s' registering CS handlers %d and %d\n" +#~ msgstr "\"%s\" registrerar handtagen %d och %d\n" + +#~ msgid "enables P2P-chat (incomplete)" +#~ msgstr "aktiverar P2P-chatt (ej komplett)" + +#, fuzzy +#~ msgid "Existing key in file `%s' failed format check, creating new key.\n" +#~ msgstr "" +#~ "Existerande värdnyckel i filen \"%s\" felade vid formatkontroll, skapar " +#~ "en ny värdnyckel.\n" + +#, fuzzy +#~ msgid "Creating new key for this nickname (this may take a while).\n" +#~ msgstr "Skapar ny värdnyckel (det här kan ta en stund).\n" + +#, fuzzy +#~ msgid "allow TIME ms to process a GET command" +#~ msgstr "tillÃ¥t TID ms för behandling av varje kommando" + +#, fuzzy +#~ msgid "Issuing `%s(%s,%s)' command.\n" +#~ msgstr "\"%s(%s,%s)\" misslyckades.\n" + +#~ msgid "Command `%s' requires an argument (`%s').\n" +#~ msgstr "Kommando \"%s\" kräver ett argument (\"%s\").\n" + +#~ msgid "Command `%s' requires two arguments (`%s' and `%s').\n" +#~ msgstr "Kommando \"%s\" kräver tvÃ¥ argument (\"%s\" och \"%s\").\n" + +#~ msgid "Unsupported command `%s'. Aborting.\n" +#~ msgstr "Kommando \"%s\" stöds ej. Avbryter.\n" + +#, fuzzy +#~ msgid "# dht discovery messages sent" +#~ msgstr "# krypterade PONG-meddelanden skickade" + +#, fuzzy +#~ msgid "`%s' registering p2p handlers: %d %d %d\n" +#~ msgstr "\"%s\" registrerar handtag %d %d %d\n" + +#~ msgid "`%s' failed. Terminating connection to client.\n" +#~ msgstr "\"%s\" misslyckades. Terminerar anslutning till klient.\n" + +#, fuzzy +#~ msgid "`%s' registering client handlers: %d %d\n" +#~ msgstr "\"%s\" registrerar klienthandtag %d\n" + +#~ msgid "" +#~ "Existing hostkey in file `%s' failed format check, creating new hostkey.\n" +#~ msgstr "" +#~ "Existerande värdnyckel i filen \"%s\" felade vid formatkontroll, skapar " +#~ "en ny värdnyckel.\n" + +#~ msgid "Done creating hostkey.\n" +#~ msgstr "Klar med skapandet av värdnyckel.\n" + +#~ msgid "Cannot create PING, table full. Try increasing MAX_PING_PONG.\n" +#~ msgstr "" +#~ "Kan inte skapa PING, tabell är full. Försök att öka MAX_PING_PONG.\n" + +#~ msgid "# plaintext PONG messages received" +#~ msgstr "# klartext PONG-meddelanden mottagna" + +#~ msgid "# encrypted PING messages received" +#~ msgstr "# krypterade PING-meddelanden mottagna" + +#~ msgid "# encrypted PING messages sent" +#~ msgstr "# krypterade PING-meddelanden skickade" + +#~ msgid "`%s' registering handlers %d %d (plaintext and ciphertext)\n" +#~ msgstr "\"%s\" registrerar handtag %d %d (klartext och kryptotext)\n" + +#, fuzzy +#~ msgid "Cannot encrypt sessionkey, peer `%s' not known!\n" +#~ msgstr "Kan inte kryptera sessionsnyckel, andra parten är inte känd!\n" + +#, fuzzy +#~ msgid "" +#~ "Session key received from peer `%s' has invalid format (discarded).\n" +#~ msgstr "Meddelande mottaget frÃ¥n motpart är ogiltig.\n" + +#~ msgid "# sessions established" +#~ msgstr "# sessioner etablerade" + +#~ msgid "create a new pseudonym under the given NICKNAME" +#~ msgstr "skapa en ny pseudonym under angivet SMEKNAMN" + +#~ msgid "delete the pseudonym with the given NICKNAME" +#~ msgstr "ta bort pseudonymen med angivet SMEKNAMN" + +#~ msgid "" +#~ "Create new pseudonyms, delete pseudonyms or list existing pseudonyms." +#~ msgstr "" +#~ "Skapa nya pseudonymer, ta bort pseudonymer eller lista existerande " +#~ "pseudonymer." + +#~ msgid "Collection stopped.\n" +#~ msgstr "Samling stoppad.\n" + +#~ msgid "Failed to stop collection (not active?).\n" +#~ msgstr "Misslyckades att stoppa samling (inte aktiv?).\n" + +#~ msgid "Pseudonym `%s' deleted.\n" +#~ msgstr "Pseudonym \"%s\" togs bort.\n" + +#~ msgid "Error deleting pseudonym `%s' (does not exist?).\n" +#~ msgstr "Fel vid borttagning av pseudonym \"%s\" (existerar den?).\n" + +#, fuzzy +#~ msgid "Started collection.\n" +#~ msgstr "Startade samling \"%s\".\n" + +#, fuzzy +#~ msgid "You must specify a name for the collection (`%s' option).\n" +#~ msgstr "" +#~ "Du mÃ¥ste ange ett namn för PID-filen i sektion \"%s\" under \"%s\".\n" + +#~ msgid "%d files found in directory.\n" +#~ msgstr "%d filer hittades i katalog.\n" + +#~ msgid "Perform directory related operations." +#~ msgstr "Genomför katalogrelaterade operationer." + +#~ msgid "Listed %d matching entries.\n" +#~ msgstr "Listade %d matchande poster.\n" + +#, fuzzy +#~ msgid "Upload of `%s' at %llu out of %llu bytes.\n" +#~ msgstr "Hämtning av fil \"%s\" vid %16llu av %16llu byte (%8.3f kbps)\n" + +#, fuzzy +#~ msgid "Upload aborted.\n" +#~ msgstr "Nedladdning avbruten." + +#, fuzzy +#~ msgid "Uploading suspended.\n" +#~ msgstr "Uppladdning misslyckades.\n" + +#, fuzzy +#~ msgid "" +#~ "do not use libextractor to add additional references to directory entries " +#~ "and/or the published file" +#~ msgstr "" +#~ "använd libextractor för att lägga till ytterligare direktreferenser till " +#~ "katalogposter" + +#~ msgid "Created entry `%s' in namespace `%s'\n" +#~ msgstr "Skapade post \"%s\" i namnrymd \"%s\"\n" + +#, fuzzy +#~ msgid "" +#~ "%16llu of %16llu bytes inserted (estimating %6s to completion) - %s\n" +#~ msgstr "%16llu av %16llu byte inlagda (uppskattar %s till färdigställd)\n" + +#, fuzzy +#~ msgid "" +#~ "Upload of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" +#~ msgstr "" +#~ "Uppladdning av \"%s\" klar, %llu byte tog %llu sekunder (%8.3f kbps).\n" + +#, fuzzy +#~ msgid "" +#~ "\n" +#~ "Upload aborted.\n" +#~ msgstr "Nedladdning avbruten." + +#, fuzzy +#~ msgid "" +#~ "\n" +#~ "Error uploading file: %s" +#~ msgstr "" +#~ "\n" +#~ "Fel vid uppladdning av fil: %s\n" + +#~ msgid "" +#~ "even if gnunetd is running on the local machine, force the creation of a " +#~ "copy instead of making a link to the GNUnet share directory" +#~ msgstr "" +#~ "även om gnunetd körs pÃ¥ den lokala maskinen, tvinga fram skapandet av en " +#~ "kopia istället för att göra en länk till GNUnets utdelade katalog" + +#~ msgid "Make files available to GNUnet for sharing." +#~ msgstr "Gör filer tillgängliga via utdelning till GNUnet." + +#~ msgid "Search GNUnet for files." +#~ msgstr "Sök GNUnet efter filer." + +#~ msgid "" +#~ "%16llu of %16llu bytes unindexed (estimating %llu seconds to " +#~ "completion) " +#~ msgstr "" +#~ "%16llu av %16llu byte avindexerat (uppskattar %llu sekunder till " +#~ "färdigställd) " + +#, fuzzy +#~ msgid "" +#~ "\n" +#~ "Unindexing of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" +#~ msgstr "" +#~ "\n" +#~ "Avindexering av \"%s\" klar, %llu byte tog %llu sekunder (%8.3f kbps).\n" + +#, fuzzy +#~ msgid "Not enough arguments. You must specify a filename.\n" +#~ msgstr "" +#~ "Inte tillräckligt med argument. Du mÃ¥ste ange en URI till en GNUnet-fil\n" + +#~ msgid "`%s' failed. Is `%s' a file?\n" +#~ msgstr "\"%s\" misslyckades. Är \"%s\" en fil?\n" + +#~ msgid "Download files from GNUnet." +#~ msgstr "Ladda ner filer frÃ¥n GNUnet." + +#, fuzzy +#~ msgid "Download of file `%s' at %16llu out of %16llu bytes (%8.3f KiB/s)\n" +#~ msgstr "Hämtning av fil \"%s\" vid %16llu av %16llu byte (%8.3f kbps)\n" + +#, fuzzy +#~ msgid "Download aborted.\n" +#~ msgstr "Nedladdning avbruten." + +#, fuzzy +#~ msgid "Download of file `%s' complete. Speed was %8.3f KiB per second.\n" +#~ msgstr "" +#~ "Hämtning av fil \"%s\" färdig. Hastigheten var %8.3f kilobyte per " +#~ "sekund.\n" + +#~ msgid "Not enough arguments. You must specify a GNUnet file URI\n" +#~ msgstr "" +#~ "Inte tillräckligt med argument. Du mÃ¥ste ange en URI till en GNUnet-fil\n" + +#~ msgid "URI `%s' invalid for gnunet-download.\n" +#~ msgstr "URI \"%s\" ogiltig för gnunet-download.\n" + +#, fuzzy +#~ msgid "No filename specified, using `%s' instead (for now).\n" +#~ msgstr "Inget tabellnamn angivet, använder \"%s\".\n" + +#, fuzzy +#~ msgid "Downloading %d files from directory `%s'.\n" +#~ msgstr "Ladda ner filer frÃ¥n GNUnet." + +#, fuzzy +#~ msgid "Did not find any files in directory `%s'\n" +#~ msgstr "%d filer hittades i katalog.\n" + +#~ msgid "File stored as `%s'.\n" +#~ msgstr "Fil lagrad som \"%s\".\n" + +#~ msgid "Cannot get size of file `%s'" +#~ msgstr "Kan inte hämta storlek pÃ¥ fil \"%s\"" + +#~ msgid "Initialization for indexing file `%s' failed.\n" +#~ msgstr "Initiering av indexering av fil \"%s\" misslyckades.\n" + +#, fuzzy +#~ msgid "Cannot open file `%s': `%s'" +#~ msgstr "Kan inte öppna konfigurationsfil \"%s\".\n" + +#~ msgid "Renaming of file `%s' to `%s' failed: %s\n" +#~ msgstr "Namnbyte pÃ¥ fil \"%s\" till \"%s\" misslyckades: %s\n" + +#~ msgid "Could not rename file `%s' to `%s': file exists\n" +#~ msgstr "Kunde inte byta namn pÃ¥ fil \"%s\" till \"%s\": filen existerar\n" + +#~ msgid "CHK URI not allowed for search.\n" +#~ msgstr "CHK URI tillÃ¥ts inte för sökning.\n" + +#~ msgid "LOC URI not allowed for search.\n" +#~ msgstr "LOC URI tillÃ¥ts inte för sökning.\n" + +#~ msgid "Format of pseudonym `%s' is invalid.\n" +#~ msgstr "Formatet pÃ¥ pseudonym \"%s\" är ogiltig.\n" + +#, fuzzy +#~ msgid "Format of file `%s' is invalid, trying to remove.\n" +#~ msgstr "Formatet pÃ¥ filen \"%s\" är ogiltig.\n" + +#~ msgid "" +#~ "Decrypted content does not match key. This is either a bug or a " +#~ "maliciously inserted file. Download aborted.\n" +#~ msgstr "" +#~ "Dekrypterat innehÃ¥ll stämmer inte med nyckeln. Det är antingen ett fel " +#~ "eller en fil inlagd med onda avsikter. Hämtning avbruten.\n" + +#, fuzzy +#~ msgid "" +#~ "`%s' registering client handlers %d %d %d %d %d %d %d %d and P2P handlers " +#~ "%d %d\n" +#~ msgstr "\"%s\" registrerar klienthandtagen %d och %d\n" + +#~ msgid "enables (anonymous) file-sharing" +#~ msgstr "aktiverar (anonym) fildelning" + +#, fuzzy +#~ msgid "Friend list of %s:%d\n" +#~ msgstr "Fel vid %s:%d.\n" + +#, fuzzy +#~ msgid "set number of daemons to start" +#~ msgstr "antal meddelanden att använda per iteration" + +#, fuzzy +#~ msgid "Waiting for peers to connect" +#~ msgstr "Väntar pÃ¥ att motparter ska ansluta (%u iterationer kvar)...\n" + +#, fuzzy +#~ msgid "Bootstrap data obtained from `%s' is invalid.\n" +#~ msgstr "Formatet pÃ¥ pseudonym \"%s\" är ogiltig.\n" + +#~ msgid "`%s' registering client handler %d\n" +#~ msgstr "\"%s\" registrerar klienthandtag %d\n" + +#~ msgid "allows clients to determine gnunetd's configuration" +#~ msgstr "tillÃ¥ter klienter att fastställa gnunetds konfiguration" + +#~ msgid "`%s' registering client handler %d and %d\n" +#~ msgstr "\"%s\" registrerar klienthandtagen %d och %d\n" + +#~ msgid "Uptime (seconds)" +#~ msgstr "Upptid (sekunder)" + +#, fuzzy +#~ msgid "`%s' registering client handlers %d %d %d and p2p handler %d\n" +#~ msgstr "\"%s\" registrerar klienthandtagen %d och %d\n" + +#~ msgid "keeps statistics about gnunetd's operation" +#~ msgstr "behÃ¥ller statistik om gnunetds operation" + +#~ msgid "prints supported protocol messages" +#~ msgstr "skriver ut stödda protokollmeddelanden" + +#, fuzzy +#~ msgid "Cannot open tunnel device: %s" +#~ msgstr "Kan inte öppna konfigurationsfil \"%s\".\n" + +#, fuzzy +#~ msgid "`%s' initialising RFC4913 module %d and %d\n" +#~ msgstr "\"%s\" registrerar handtagen %d och %d\n" + +#, fuzzy +#~ msgid "enables IPv6 over GNUnet (incomplete)" +#~ msgstr "aktiverar P2P-chatt (ej komplett)" + +#, fuzzy +#~ msgid "Core initialization failed.\n" +#~ msgstr " Anslutning misslyckades\n" + +#~ msgid "Updates GNUnet datastructures after version change." +#~ msgstr "Uppdaterar GNUnets datastruktur efter versionsändring." + +#~ msgid "run as user LOGIN" +#~ msgstr "kör som användare LOGIN" + +#~ msgid "run in client mode (for getting client configuration values)" +#~ msgstr "kör i klientläge (för att hämta värden frÃ¥n klientkonfiguration)" + +#~ msgid "Starts the gnunetd daemon." +#~ msgstr "Startar gnunetd-demonen." + +#, fuzzy +#~ msgid "specify username as which gnunetd should run" +#~ msgstr "ange värd pÃ¥ vilken gnunetd körs" + +#~ msgid "Configuration or GNUnet version changed. You need to run `%s'!\n" +#~ msgstr "" +#~ "Konfiguration eller version av GNUnet ändrad. Du behöver köra \"%s\"!\n" + +#, fuzzy +#~ msgid "Unable to obtain filesystem information for `%s': %u\n" +#~ msgstr "Kunde inte spara konfigurationsfil \"%s\":" + +#, fuzzy +#~ msgid "`%s' message invalid (signature invalid).\n" +#~ msgstr "\"%s\" misslyckades, svar ogiltigt!\n" + +#~ msgid "`%s' selected %d out of %d messages (MTU: %d).\n" +#~ msgstr "\"%s\" valda %d av %d meddelanden (MTU: %d).\n" + +#~ msgid "Message details: %u: length %d, priority: %d\n" +#~ msgstr "Detaljer om meddelande: %u: längd %d, prioritet: %d\n" + +#~ msgid "Message from `%s' discarded: invalid format.\n" +#~ msgstr "Meddelande frÃ¥n \"%s\" kastades bort: ogiltigt format.\n" + +#, fuzzy +#~ msgid "# total number of messages in send buffers" +#~ msgstr "antal meddelanden i ett meddelandeblock" + +#~ msgid "`%s': Could not send.\n" +#~ msgstr "\"%s\": Kunde inte skicka.\n" + +#~ msgid "`%s': Could not disconnect.\n" +#~ msgstr "\"%s\": Kunde inte koppla ned.\n" + +#, fuzzy +#~ msgid "" +#~ "`%s' transport OK. It took %ums to transmit %llu messages of %llu bytes " +#~ "each.\n" +#~ msgstr "" +#~ "\"%s\" transport OK. Det tog %ums att överföra %d meddelanden pÃ¥ %d byte " +#~ "styck.\n" + +#, fuzzy +#~ msgid " Transport %d is not being tested\n" +#~ msgstr " Transport %d ej tillgänglig\n" + +#~ msgid "" +#~ "\n" +#~ "Contacting `%s'." +#~ msgstr "" +#~ "\n" +#~ "Kontaktar \"%s\"." + +#~ msgid " Connection failed (bug?)\n" +#~ msgstr " Anslutning misslyckades (fel?)\n" + +#, fuzzy +#~ msgid "OK!\n" +#~ msgstr "OK" + +#~ msgid "send messages with SIZE bytes payload" +#~ msgstr "skicka meddelanden med STORLEK bytes nyttolast" + +#~ msgid "specifies which TRANSPORT should be tested" +#~ msgstr "anger vilken TRANSPORT som ska testas" + +#~ msgid "specifies after how many MS to time-out" +#~ msgstr "anger timeout efter antal MS" + +#~ msgid "Testing transport(s) %s\n" +#~ msgstr "Testar transport(er) %s\n" + +#~ msgid "Available transport(s): %s\n" +#~ msgstr "Tillgängliga transport(er): %s\n" + +#, fuzzy +#~ msgid "%s failed for url `%s' and post-data `%s' at %s:%d: `%s'\n" +#~ msgstr "\"%s\" misslyckades för fil \"%s\" vid %s:%d med fel: %s\n" + +#~ msgid "# bytes sent via HTTP" +#~ msgstr "# byte skickade via HTTP" + +#~ msgid "# bytes dropped by HTTP (outgoing)" +#~ msgstr "# byte kastade via HTTP (utgÃ¥ende)" + +#, fuzzy +#~ msgid "# HTTP connect calls" +#~ msgstr "# av anslutna parter" + +#~ msgid "specify host on which gnunetd is running" +#~ msgstr "ange värd pÃ¥ vilken gnunetd körs" + +#, fuzzy +#~ msgid "No help available." +#~ msgstr "\"%s\" är inte tillgänglig." + +#, fuzzy +#~ msgid "Show rarely used options" +#~ msgstr "Visa alla alternativ" + +#, fuzzy +#~ msgid "Meta-configuration" +#~ msgstr "GNUnet-konfiguration" + +#, fuzzy +#~ msgid "Full pathname of GNUnet HOME directory" +#~ msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" + +#, fuzzy +#~ msgid "Run gnunetd as this group." +#~ msgstr "Kör gnunet-update" + +#, fuzzy +#~ msgid "General settings" +#~ msgstr "Andra inställningar" + +#, fuzzy +#~ msgid "Settings for restricting connections to friends" +#~ msgstr "\"%s\" misslyckades. Terminerar anslutning till klient.\n" + +#, fuzzy +#~ msgid "Configuration of the MySQL database" +#~ msgstr "Konfigurationsfil \"%s\" skapad.\n" + +#, fuzzy +#~ msgid "Options for anonymous file sharing" +#~ msgstr "aktiverar (anonym) fildelning" + +#, fuzzy +#~ msgid "Applications" +#~ msgstr "_Alternativ" + +#, fuzzy +#~ msgid "Network interface" +#~ msgstr "Nätverksgränssnitt:" + +#, fuzzy +#~ msgid "Network interface to monitor" +#~ msgstr "Nätverksgränssnitt:" + +#, fuzzy +#~ msgid "What is the path to the configuration file for gnunetd?" +#~ msgstr "skriv ut ett värde frÃ¥n konfigurationsfilen till standard ut" + +#, fuzzy +#~ msgid "General options" +#~ msgstr "Visa alla alternativ" + +#, fuzzy +#~ msgid "Options related to gnunet-gtk" +#~ msgstr "Ej ansluten till gnunetd." + +#~ msgid "`%s' failed (%d, %u). Will not send PING.\n" +#~ msgstr "\"%s\" misslyckades (%d, %u). Kommer inte skicka PING.\n" + +#~ msgid "Could not resolve name of HTTP proxy `%s'. Trying without a proxy.\n" +#~ msgstr "" +#~ "Kunde inte slÃ¥ upp namn för HTTP-proxy \"%s\". Försöker utan proxy.\n" + +#~ msgid "Maximum number of chat clients reached.\n" +#~ msgstr "Maximalt antal chattklienter uppnÃ¥tt.\n" + +#~ msgid "Now %d of %d chat clients at this node.\n" +#~ msgstr "Nu är det %d av %d chattklienter pÃ¥ den här noden.\n" + +#~ msgid "specify nickname" +#~ msgstr "ange smeknamn" + +#~ msgid "Start GNUnet chat client." +#~ msgstr "Starta GNUnets chattklient." + +#~ msgid "You must specify a nickname (use option `%s').\n" +#~ msgstr "Du mÃ¥ste ange ett smeknamn (använd flagga \"%s\").\n" + +#~ msgid "Database failed to delete `%s'.\n" +#~ msgstr "Databas misslyckades att ta bort \"%s\".\n" + +#~ msgid "`%s' failed: table not found!\n" +#~ msgstr "\"%s\" misslyckades: tabell hittades inte!\n" + +#~ msgid "`%s' failed. Terminating connection to client.\n" +#~ msgstr "\"%s\" misslyckades. Terminerar anslutning till klient.\n" + +#~ msgid "sendAck failed. Terminating connection to client.\n" +#~ msgstr "sendAck misslyckades. Terminerar anslutning till klient.\n" + +#~ msgid "`%s' called with timeout above 1 hour (bug?)\n" +#~ msgstr "\"%s\" anropad med timeout över 1 timma (fel?)\n" + +#~ msgid "Received invalid RPC `%s'.\n" +#~ msgstr "Mottog ogiltig RPC \"%s\".\n" + +#~ msgid "allow SIZE bytes of memory for the local table" +#~ msgstr "tillÃ¥t STORLEK byte av minne för lokaltabellen" + +#~ msgid "Superflous arguments (ignored).\n" +#~ msgstr "Onödiga argument (ignorerade).\n" + +#~ msgid "Call to `%s' with value '%.*s' (%d bytes).\n" +#~ msgstr "Anrop till \"%s\" med värde \"%.*s\" (%d byte).\n" + +#~ msgid "query table called NAME" +#~ msgstr "frÃ¥ga tabell kallad NAME" + +#~ msgid "No commands specified.\n" +#~ msgstr "Inga kommandon angivna.\n" + +#~ msgid "'%s(%s,%s)' succeeded\n" +#~ msgstr "\"%s(%s,%s)\" lyckades\n" + +#~ msgid "Failed to send `%s'. Closing connection.\n" +#~ msgstr "Misslyckades att skicka \"%s\". Stänger anslutning.\n" + +#~ msgid "Received invalid `%s' request (size %d)\n" +#~ msgstr "Mottog ogiltig \"%s\" begäran (storlek %d)\n" + +#~ msgid "Received invalid `%s' request (wrong table)\n" +#~ msgstr "Mottog ogiltig \"%s\" begäran (fel tabell)\n" + +#~ msgid "Received unknown request type %d at %s:%d\n" +#~ msgstr "Mottog okänd typ av begäran %d vid %s:%d\n" + +#~ msgid "gnunetd signaled error in response to `%s' message\n" +#~ msgstr "gnunetd signalerade fel i svar till \"%s\" meddelande\n" + +#~ msgid "Failed to send `%s' message to gnunetd\n" +#~ msgstr "Misslyckades att skicka \"%s\" meddelande till gnunetd\n" + +#~ msgid "Unexpected reply to `%s' operation.\n" +#~ msgstr "Oväntat svar till \"%s\" operation.\n" + +#~ msgid "Waiting for gnunetd to start (%u iterations left)...\n" +#~ msgstr "Väntar pÃ¥ att gnunetd ska starta (%u iterationer kvar)...\n" + +#~ msgid "Write(%d, %p, %d) failed: %s\n" +#~ msgstr "Skrivning(%d, %p, %d) misslyckades: %s\n" + +#~ msgid "Cannot create pseudonym `%s', file `%s' exists.\n" +#~ msgstr "Kan inte skapa pseudonym \"%s\", filen \"%s\" existerar.\n" + +#~ msgid "AND" +#~ msgstr "OCH" + +#~ msgid "Publication interval for periodic publication changed." +#~ msgstr "Publiseringsintervall för periodisk publisering har ändrats." + +#~ msgid "Indexed file disappeared, deleting block for query `%s'\n" +#~ msgstr "Indexerad fil försvann, tar bort block för frÃ¥ga \"%s\"\n" + +#~ msgid "%8u of %8u bytes deleted." +#~ msgstr "%8u av %8u byte togs bort." + +#~ msgid "specify the file to delete from GNUnet (obligatory, file must exist)" +#~ msgstr "" +#~ "ange filen att ta bort frÃ¥n GNUnet (obligatorisk, filen mÃ¥ste existera)" + +#~ msgid "" +#~ "Remove file from GNUnet. The specified file is not removed\n" +#~ "from the filesystem but just from the local GNUnet datastore." +#~ msgstr "" +#~ "Ta bort fil frÃ¥n GNUnet. Den angivna filen tas inte bort frÃ¥n\n" +#~ "filsystemet utan bara frÃ¥n det lokala GNUnet-datalagret." + +#~ msgid "You must specify a filename (option -f)\n" +#~ msgstr "Du mÃ¥ste ange ett filnamn (flagga -f)\n" + +#~ msgid "gnunet-directory [OPTIONS] [FILENAMES]" +#~ msgstr "gnunet-directory [FLAGGOR] [FILNAMN]" + +#~ msgid "LEVEL" +#~ msgstr "NIVÃ…" + +#~ msgid "FILENAME" +#~ msgstr "FILNAMN" + +#~ msgid "process directories recursively" +#~ msgstr "bearbeta kataloger rekursivt" + +#~ msgid "Only one file or directory can be specified at a time.\n" +#~ msgstr "Endast en fil eller katalog kan anges samtidigt.\n" + +#~ msgid "You must specify a file or directory to upload.\n" +#~ msgstr "Du mÃ¥ste ange en fil eller katalog att ladda upp.\n" + +#~ msgid "Not enough arguments. You must specify a keyword or identifier.\n" +#~ msgstr "" +#~ "Inte tillräckligt med argument. Du mÃ¥ste ange ett nyckelord eller " +#~ "identifierare.\n" + +#~ msgid "`%s' registering handlers %d %d\n" +#~ msgstr "\"%s\" registrerar handtag %d %d\n" + +#~ msgid "" +#~ "Configuration file must specify a directory for GNUnet to store per-peer " +#~ "data under %s%s\n" +#~ msgstr "" +#~ "Konfigurationsfil mÃ¥ste ange en katalog för GNUnet att lagra motpartsdata " +#~ "under %s%s\n" + +#~ msgid "%s `%s' returned no known hosts!\n" +#~ msgstr "%s \"%s\" returnerade inga kända värdar!\n" + +#~ msgid "Template for gnunet-clients." +#~ msgstr "Mall för gnunet-clients." + +#~ msgid "Start GNUnet-testbed helper." +#~ msgstr "Starta hjälpprogrammet GNUnet-testbed." + +#~ msgid "size of `%s' message is wrong. Ignoring.\n" +#~ msgstr "storlek pÃ¥ \"%s\" meddelande är fel. Ignorerar.\n" + +#~ msgid "received invalid `%s' message\n" +#~ msgstr "mottog ogiltigt \"%s\" meddelande\n" + +#~ msgid "'..' is not allowed in file name (%s).\n" +#~ msgstr "\"..\" tillÃ¥ts inte i filnamn (%s).\n" + +#~ msgid "Could not resolve name of HTTP proxy `%s'.\n" +#~ msgstr "Kunde inte slÃ¥ upp namn för HTTP-proxy \"%s\".\n" + +#~ msgid "Failed so send HTTP request `%s' to host `%s': %s\n" +#~ msgstr "Misslyckades att skicka HTTP-begäran \"%s\" till värd \"%s\": %s\n" + +#~ msgid "Peer `%s' did not report back.\n" +#~ msgstr "Motpart \"%s\" rapporterade inte tillbaka.\n" + +#~ msgid "%s: symbol value `%s' invalid for %s\n" +#~ msgstr "%s: symbolvärde \"%s\" ogiltigt för %s\n" + +#~ msgid "Sorry, no help is available for this option.\n" +#~ msgstr "Tyvärr, ingen hjälp är tillgänglig för den här flaggan.\n" + +#~ msgid "_File" +#~ msgstr "_Fil" + +#~ msgid "_Load" +#~ msgstr "_Läs in" + +#~ msgid "_Save" +#~ msgstr "_Spara" + +#~ msgid "Save the config in .config" +#~ msgstr "Spara konfigurationen i .config" + +#~ msgid "_Quit" +#~ msgstr "_Avsluta" + +#~ msgid "Show _name" +#~ msgstr "Visa _namn" + +#~ msgid "Show _range" +#~ msgstr "Visa _omfÃ¥ng" + +#~ msgid "Show range (Y/M/N)" +#~ msgstr "Visa omfÃ¥ng (Y/M/N)" + +#~ msgid "Show _data" +#~ msgstr "Visa _data" + +#~ msgid "Show value of the option" +#~ msgstr "Visa värde av alternativet" + +#~ msgid "Show all _options" +#~ msgstr "Visa alla a_lternativ" + +#~ msgid "_Help" +#~ msgstr "_Hjälp" + +#~ msgid "_Introduction" +#~ msgstr "_Introduktion" + +#~ msgid "_License" +#~ msgstr "_Licens" + +#~ msgid "Goes up of one level (single view)" +#~ msgstr "GÃ¥r upp en nivÃ¥ (enkel vy)" + +#~ msgid "Load" +#~ msgstr "Läs in" + +#~ msgid "Save a config file" +#~ msgstr "Spara en konfigurationsfil" + +#~ msgid "Save" +#~ msgstr "Spara" + +#~ msgid "Single view" +#~ msgstr "Enkel vy" + +#~ msgid "Single" +#~ msgstr "Enkel" + +#~ msgid "Split view" +#~ msgstr "Dela vy" + +#~ msgid "Split" +#~ msgstr "Dela" + +#~ msgid "Full view" +#~ msgstr "Full vy" + +#~ msgid "Full" +#~ msgstr "Full" + +#~ msgid "Collapse" +#~ msgstr "Fäll in" + +#~ msgid "Expand" +#~ msgstr "Expandera" + +#~ msgid "Sorry, no help available for this option yet." +#~ msgstr "Tyvärr, ingen hjälp tillgänglig för den här flaggan ännu." + +#~ msgid "Couldn't find pixmap file: %s" +#~ msgstr "Kunde inte htta bildfil: %s" + +#~ msgid "Available MODEs:\n" +#~ msgstr "Tillgängliga lägen:\n" + +#~ msgid " config\t\ttext-based configuration\n" +#~ msgstr " config\t\ttextbaserad konfiguration\n" + +#~ msgid " menuconfig\ttext-based menu\n" +#~ msgstr " menuconfig\ttextbaserad meny\n" + +#~ msgid " wizard-curses\tBasic text-based graphical configuration\n" +#~ msgstr " wizard-curses\tEnkel textbaserad grafisk konfiguration\n" + +#~ msgid "" +#~ " wizard-gtk\tBasic GTK configuration\n" +#~ "\n" +#~ msgstr "" +#~ " wizard-gtk\tEnkel GTK-konfiguration\n" +#~ "\n" + +#~ msgid "gnunet-setup must have write-access to the configuration file `%s'\n" +#~ msgstr "" +#~ "gnunet-setup mÃ¥ste ha skrivrättighet till konfigurationsfilen \"%s\"\n" + +#~ msgid "" +#~ "Can only run wizard to configure gnunetd.\n" +#~ "Did you forget the `%s' option?\n" +#~ msgstr "" +#~ "Kan endast köra vägvisaren för att konfigurera gnunetd.\n" +#~ "Glömde du flaggan \"%s\"?\n" + +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "This is the percentage of processor time GNUnet is allowed to use." +#~ msgstr "" +#~ "Du kan begränsa GNUnets resursanvändning här.\n" +#~ "\n" +#~ "Det här är det procenttal som GNUnet tillÃ¥ts använda av processortiden." + +#~ msgid "" +#~ "Welcome to GNUnet!\n" +#~ "\n" +#~ "This assistant will ask you a few basic questions in order to configure " +#~ "GNUnet.\n" +#~ "\n" +#~ "Please visit our homepage at\n" +#~ "\thttp://www.gnunet.org\n" +#~ "and join our community at\n" +#~ "\thttp://www.gnunet.org/drupal/\n" +#~ "\n" +#~ "Have a lot of fun,\n" +#~ "\n" +#~ "the GNUnet team" +#~ msgstr "" +#~ "Välkommen till GNUnet!\n" +#~ "\n" +#~ "Denna assistant kommer att frÃ¥ga dig nÃ¥gra enkla frÃ¥gor för att " +#~ "konfigurera GNUnet.\n" +#~ "\n" +#~ "Besök pÃ¥ webbplats pÃ¥\n" +#~ "\thttp://gnunet.org/\n" +#~ "och gÃ¥ med i vÃ¥r gemenskap pÃ¥\n" +#~ "\thttp://www.gnunet.org/drupal/\n" +#~ "\n" +#~ "Ha det sÃ¥ kul,\n" +#~ "\n" +#~ "GNUnet-laget" + +#~ msgid "Next" +#~ msgstr "Nästa" + +#~ msgid "IP-Address/Hostname:" +#~ msgstr "IP-adress/Värdnamn:" + +#~ msgid "Bandwidth limitation" +#~ msgstr "Bandbreddsbegränsning" + +#~ msgid "Bandwidth sharing" +#~ msgstr "Bandbreddsdelning" + +#~ msgid "Max. CPU usage (%):" +#~ msgstr "Max. CPU-användning (%):" + +#~ msgid "CPU usage" +#~ msgstr "CPU-användning" + +#~ msgid "Finish" +#~ msgstr "Slutför" + +#~ msgid "Question" +#~ msgstr "FrÃ¥ga" + +#~ msgid "Group:" +#~ msgstr "Grupp:" + +#~ msgid "User account:" +#~ msgstr "Användarkonto:" + +#~ msgid "gnunet-update failed!" +#~ msgstr "gnunet-update misslyckades!" + +#~ msgid "You must specify a non-empty set of transports to test!\n" +#~ msgstr "Du mÃ¥ste ange en icke-tom uppsättning av transporter att testa!\n" + +#~ msgid "" +#~ "\n" +#~ "Exiting.\n" +#~ msgstr "" +#~ "\n" +#~ "Avslutar.\n" + +#~ msgid "Updated data for %d applications.\n" +#~ msgstr "Uppdaterade data för %d program.\n" + +#~ msgid "`%s' starting\n" +#~ msgstr "\"%s\" startar\n" + +#~ msgid "Argument %d: `%s'\n" +#~ msgstr "Argument %d: \"%s\"\n" + +#~ msgid "%s: Rejected connection from blacklisted address %u.%u.%u.%u.\n" +#~ msgstr "%s: Vägrade anslutning frÃ¥n svartlistad adress %u.%u.%u.%u.\n" + +#~ msgid "HTTP: Could not determine my public IP address.\n" +#~ msgstr "HTTP: Kunde inte fastställa min publika IP-adress.\n" + +#~ msgid "Could not resolve name of SMTP server `%s': %s" +#~ msgstr "Kunde inte slÃ¥ upp namnet för SMTP-server \"%s\": %s" + +#~ msgid "" +#~ "You must specify the name of a pipe for the SMTP transport in section `" +#~ "%s' under `%s'.\n" +#~ msgstr "" +#~ "Du mÃ¥ste ange ett namn pÃ¥ röret för SMTP-transporten i sektion \"%s\" " +#~ "under \"%s\".\n" + +#~ msgid "Sending E-mail to `%s' failed.\n" +#~ msgstr "Sändning av e-post till \"%s\" misslyckades.\n" + +#~ msgid "%.*s filter %s (SMTP)" +#~ msgstr "%.*s filter %s (SMTP)" + +#~ msgid "`%s': unknown service: %s\n" +#~ msgstr "\"%s\": okänd tjänst: %s\n" + +#~ msgid "Configuration file `%s' not found. Run gnunet-setup!\n" +#~ msgstr "Konfigurationsfil \"%s\" hittades inte. Kör gnunet-setup!\n" + +#~ msgid "" +#~ "Configuration file not found. Please run GNUnet Setup (Client " +#~ "Configuration) first." +#~ msgstr "" +#~ "Konfigurationsfil hittades inte. Vänligen kör konfigurationen för GNUnet " +#~ "(klientkonfiguration) först." + +#~ msgid "Cron stopped\n" +#~ msgstr "Cron stoppad\n" + +#~ msgid "Caught signal %d.\n" +#~ msgstr "FÃ¥ngade signal %d.\n" + +#~ msgid "Invalid network notation (additional characters: `%s')." +#~ msgstr "Ogiltig nätverksnotation (ytterligare tecken: \"%s\")." + +#~ msgid "FAILURE" +#~ msgstr "MISSLYCKANDE" + +#~ msgid "MESSAGE" +#~ msgstr "MEDDELANDE" + +#~ msgid "CRON" +#~ msgstr "CRON" + +#~ msgid "EVERYTHING" +#~ msgstr "ALLT" + +#~ msgid "Invalid LOGLEVEL `%s' specified.\n" +#~ msgstr "Ogiltig LOGGNIVÃ… \"%s\" angiven.\n" + +#~ msgid "" +#~ "Usage: %s\n" +#~ "%s\n" +#~ "\n" +#~ msgstr "" +#~ "Användning: %s\n" +#~ "%s\n" +#~ "\n" + +#~ msgid "" +#~ "Configuration file must specify a directory for GNUnet to store per-peer " +#~ "data under %s\\%s.\n" +#~ msgstr "" +#~ "Konfigurationsfil mÃ¥ste ange en katalog för GNUnet att lagra motpartsdata " +#~ "under %s\\%s.\n" + +#~ msgid "g" +#~ msgstr "g" + +#~ msgid "t" +#~ msgstr "t" + +#~ msgid "`%s' failed, other side closed connection.\n" +#~ msgstr "\"%s\" misslyckades, andra sidan har stängt anslutningen.\n" + +#~ msgid "Attempted path to `%s' was `%s'.\n" +#~ msgstr "Försökt sökväg till \"%s\" var \"%s\".\n" + +#~ msgid "set verbosity to LEVEL" +#~ msgstr "sätt informationsnivÃ¥ till NIVÃ…" diff --git a/po/vi.gmo b/po/vi.gmo new file mode 100644 index 0000000..e205a02 Binary files /dev/null and b/po/vi.gmo differ diff --git a/po/vi.po b/po/vi.po new file mode 100644 index 0000000..bfa7f9d --- /dev/null +++ b/po/vi.po @@ -0,0 +1,9287 @@ +# Vietnamese translation for GNUnet. +# Copyright © 2008 Christian Grothoff (msgids). +# This file is distributed under the same license as the gnunet package. +# Phan Vinh Thinh , 2005. +# Clytie Siddall , 2008. +# +msgid "" +msgstr "" +"Project-Id-Version: gnunet 0.8.0a\n" +"Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" +"POT-Creation-Date: 2012-02-28 18:30+0100\n" +"PO-Revision-Date: 2008-09-10 22:05+0930\n" +"Last-Translator: Clytie Siddall \n" +"Language-Team: Vietnamese \n" +"Language: vi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: LocFactoryEditor 1.7b3\n" + +#: src/arm/arm_api.c:187 +msgid "Failed to transmit shutdown request to client.\n" +msgstr "" + +#: src/arm/arm_api.c:378 +#, fuzzy, c-format +msgid "Configuration failes to specify option `%s' in section `%s'!\n" +msgstr "" +"Cấu hình không thá»a mãn các ràng buá»™c của tập tin đặc tả cấu hình « %s ».\n" + +#: src/arm/arm_api.c:392 +#, fuzzy, c-format +msgid "Configuration fails to specify option `%s' in section `%s'!\n" +msgstr "" +"Cấu hình không thá»a mãn các ràng buá»™c của tập tin đặc tả cấu hình « %s ».\n" + +#: src/arm/arm_api.c:467 +#, c-format +msgid "Error receiving response to `%s' request from ARM for service `%s'\n" +msgstr "" + +#: src/arm/arm_api.c:523 +#, c-format +msgid "Requesting start of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:524 +#, c-format +msgid "Requesting termination of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:546 +#, c-format +msgid "Error while trying to transmit request to start `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:548 +#, c-format +msgid "Error while trying to transmit request to stop `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:581 +#, fuzzy, c-format +msgid "Asked to start service `%s' within %llu ms\n" +msgstr "« %s »: ChÆ°a nhận thông báo sau %llu miligiây.\n" + +#: src/arm/arm_api.c:654 +#, c-format +msgid "Stopping service `%s' within %llu ms\n" +msgstr "" + +#: src/arm/gnunet-arm.c:149 +#, fuzzy, c-format +msgid "Service `%s' is unknown to ARM.\n" +msgstr "Không gian tên « %s » có đánh giá %d.\n" + +#: src/arm/gnunet-arm.c:154 +#, fuzzy, c-format +msgid "Service `%s' has been stopped.\n" +msgstr "Dịch vụ đã bị xoá.\n" + +#: src/arm/gnunet-arm.c:157 +#, fuzzy, c-format +msgid "Service `%s' was already running.\n" +msgstr "Không gian tên « %s » có đánh giá %d.\n" + +#: src/arm/gnunet-arm.c:162 +#, fuzzy, c-format +msgid "Service `%s' has been started.\n" +msgstr "Dịch vụ đã bị xoá.\n" + +#: src/arm/gnunet-arm.c:165 +#, fuzzy, c-format +msgid "Service `%s' was already being stopped.\n" +msgstr "Dịch vụ đã bị xoá.\n" + +#: src/arm/gnunet-arm.c:169 +#, fuzzy, c-format +msgid "Service `%s' was already not running.\n" +msgstr "« %s » không phải là má»™t tập tin.\n" + +#: src/arm/gnunet-arm.c:173 +#, fuzzy +msgid "Request ignored as ARM is shutting down.\n" +msgstr "« %s » Ä‘ang tắt.\n" + +#: src/arm/gnunet-arm.c:177 +#, fuzzy +msgid "Error communicating with ARM service.\n" +msgstr "Cổng để liên lạc vá»›i giao diện ngÆ°á»i dùng GNUnet" + +#: src/arm/gnunet-arm.c:181 +#, fuzzy +msgid "Timeout communicating with ARM service.\n" +msgstr "Cổng để liên lạc vá»›i giao diện ngÆ°á»i dùng GNUnet" + +#: src/arm/gnunet-arm.c:185 +#, fuzzy +msgid "Operation failed.\n" +msgstr "Lá»—i ná»™i bá»™ : khẳng định không thành công tại %s:%d.\n" + +#: src/arm/gnunet-arm.c:189 +msgid "Unknown response code from ARM.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:216 +#, c-format +msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:224 src/arm/gnunet-arm.c:324 +msgid "Fatal error initializing ARM API.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:247 +#, fuzzy, c-format +msgid "Failed to remove configuration file %s\n" +msgstr "Không thể lÆ°u tập tin cấu hình « %s »:" + +#: src/arm/gnunet-arm.c:253 +#, fuzzy, c-format +msgid "Failed to remove servicehome directory %s\n" +msgstr "Lá»—i truy cập đến thÆ° mục nhà GNUnet « %s »\n" + +#: src/arm/gnunet-arm.c:355 +#, fuzzy +msgid "stop all GNUnet services" +msgstr "hủy cài đặt dịch vụ GNUnet" + +#: src/arm/gnunet-arm.c:357 +msgid "start a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:359 +msgid "stop a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:361 +#, fuzzy +msgid "start all GNUnet default services" +msgstr "hủy cài đặt dịch vụ GNUnet" + +#: src/arm/gnunet-arm.c:364 +#, fuzzy +msgid "stop and start all GNUnet default services" +msgstr "hủy cài đặt dịch vụ GNUnet" + +#: src/arm/gnunet-arm.c:367 +msgid "delete config file and directory on exit" +msgstr "" + +#: src/arm/gnunet-arm.c:369 +msgid "don't print status messages" +msgstr "" + +#: src/arm/gnunet-arm.c:372 +#, fuzzy +msgid "timeout for completing current operation" +msgstr "thá»i gian chá» sá»± hoàn thành của má»™t lần lặp (theo miligiây)" + +#: src/arm/gnunet-arm.c:383 +msgid "Control services and the Automated Restart Manager (ARM)" +msgstr "" + +#: src/arm/gnunet-service-arm.c:328 +#, fuzzy, c-format +msgid "Failed to start service `%s'\n" +msgstr "Lá»—i bắt đầu thu thập.\n" + +#: src/arm/gnunet-service-arm.c:331 +#, fuzzy, c-format +msgid "Starting service `%s'\n" +msgstr "Äang bắt đầu tài vỠ« %s »\n" + +#: src/arm/gnunet-service-arm.c:357 +msgid "Could not send status result to client\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:484 +#, fuzzy, c-format +msgid "Unable to create socket for service `%s': %s\n" +msgstr "Không thể tạo tài khoản ngÆ°á»i dùng:" + +#: src/arm/gnunet-service-arm.c:506 +#, c-format +msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:520 +#, c-format +msgid "ARM now monitors connections to service `%s' at `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:628 +#, fuzzy, c-format +msgid "Preparing to stop `%s'\n" +msgstr "Äang bắt đầu tài lên « %s ».\n" + +#: src/arm/gnunet-service-arm.c:782 +#, fuzzy, c-format +msgid "Restarting service `%s'.\n" +msgstr "Äang nạp và khởi Ä‘á»™ng dùng « %s ».\n" + +#: src/arm/gnunet-service-arm.c:877 +msgid "exit" +msgstr "" + +#: src/arm/gnunet-service-arm.c:882 +msgid "signal" +msgstr "" + +#: src/arm/gnunet-service-arm.c:887 +#, fuzzy +msgid "unknown" +msgstr "Lá»—i không rõ" + +#: src/arm/gnunet-service-arm.c:921 +#, c-format +msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:967 src/arm/mockup-service.c:41 +#, fuzzy +msgid "Failed to transmit shutdown ACK.\n" +msgstr "Lá»—i bắt đầu thu thập.\n" + +#: src/arm/gnunet-service-arm.c:1067 +#, fuzzy, c-format +msgid "Configuration file `%s' for service `%s' not valid: %s\n" +msgstr "Tập tin cấu hình « %s » đã được ghi.\n" + +#: src/arm/gnunet-service-arm.c:1069 +msgid "option missing" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1152 +#, fuzzy, c-format +msgid "Starting default services `%s'\n" +msgstr "Äang bắt đầu tài vỠ« %s »\n" + +#: src/arm/gnunet-service-arm.c:1163 +#, c-format +msgid "Default service `%s' not configured correctly!\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1177 +msgid "" +"No default services configured, GNUnet will not really start right now.\n" +msgstr "" + +#: src/arm/mockup-service.c:46 +msgid "Transmitting shutdown ACK.\n" +msgstr "" + +#: src/arm/mockup-service.c:69 +msgid "Initiating shutdown as requested by client.\n" +msgstr "" + +#: src/block/block.c:105 +#, fuzzy, c-format +msgid "Loading block plugin `%s'\n" +msgstr "Äang nạp các truyá»n tải « %s »\n" + +#: src/chat/chat.c:175 +#, fuzzy +msgid "Could not transmit confirmation receipt\n" +msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" + +#: src/chat/chat.c:283 +msgid "The current user must be the the first one joined\n" +msgstr "" + +#: src/chat/chat.c:412 +#, fuzzy, c-format +msgid "Unknown message type: '%u'\n" +msgstr "\tKhông rõ miá»n tên « %s »\n" + +#: src/chat/chat.c:472 +#, fuzzy, c-format +msgid "Configuration option `%s' in section `%s' missing\n" +msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" + +#: src/chat/chat.c:480 +#, fuzzy, c-format +msgid "Failed to access chat home directory `%s'\n" +msgstr "Lá»—i truy cập đến thÆ° mục nhà GNUnet « %s »\n" + +#: src/chat/chat.c:498 +#, fuzzy, c-format +msgid "Failed to create/open key in file `%s'\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/chat/chat.c:559 +#, fuzzy +msgid "Could not serialize metadata\n" +msgstr "Không thể tạo miá»n tên.\n" + +#: src/chat/chat.c:674 +#, fuzzy +msgid "Failed to connect to the chat service\n" +msgstr "Lá»—i kết nối đến gnunetd.\n" + +#: src/chat/chat.c:680 +msgid "Undefined mandatory parameter: joinCallback\n" +msgstr "" + +#: src/chat/chat.c:686 +msgid "Undefined mandatory parameter: messageCallback\n" +msgstr "" + +#: src/chat/chat.c:692 +msgid "Undefined mandatory parameter: memberCallback\n" +msgstr "" + +#: src/chat/gnunet-chat.c:92 +msgid "Joined\n" +msgstr "" + +#: src/chat/gnunet-chat.c:124 +msgid "anonymous" +msgstr "nặc danh" + +#: src/chat/gnunet-chat.c:130 +#, fuzzy, c-format +msgid "(%s) `%s' said: %s\n" +msgstr "« %s » nói: %s\n" + +#: src/chat/gnunet-chat.c:133 src/chat/gnunet-chat.c:136 +#, fuzzy, c-format +msgid "(%s) `%s' said to you: %s\n" +msgstr "« %s » nói cho bạn: %s\n" + +#: src/chat/gnunet-chat.c:139 +#, fuzzy, c-format +msgid "(%s) `%s' said for sure: %s\n" +msgstr "« %s » nói thật: %s\n" + +#: src/chat/gnunet-chat.c:142 +#, fuzzy, c-format +msgid "(%s) `%s' said to you for sure: %s\n" +msgstr "« %s » nói thật cho bạn: %s\n" + +#: src/chat/gnunet-chat.c:145 +#, fuzzy, c-format +msgid "(%s) `%s' was confirmed that you received: %s\n" +msgstr "« %s » xác nhận bạn đã nhận được: %s\n" + +#: src/chat/gnunet-chat.c:148 +#, fuzzy, c-format +msgid "(%s) `%s' was confirmed that you and only you received: %s\n" +msgstr "« %s » xác nhận mà chỉ bạn đã nhận được: %s\n" + +#: src/chat/gnunet-chat.c:151 +#, fuzzy, c-format +msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" +msgstr "« %s » xác nhận mà bạn đã nhận được từ há» : %s\n" + +#: src/chat/gnunet-chat.c:156 +#, fuzzy, c-format +msgid "" +"(%s) `%s' was confirmed that you and only you received from him or her: %s\n" +msgstr "« %s » xác nhận mà chỉ bạn Ä‘a nhận được từ há» : %s\n" + +#: src/chat/gnunet-chat.c:159 +#, fuzzy, c-format +msgid "(%s) `%s' said off the record: %s\n" +msgstr "« %s » nói không chính thức: %s\n" + +#: src/chat/gnunet-chat.c:162 +#, fuzzy, c-format +msgid "(%s) <%s> said using an unknown message type: %s\n" +msgstr "<%s> đã nói bằng má»™t kiểu tin nhẳn không rõ : %s\n" + +#: src/chat/gnunet-chat.c:193 +#, c-format +msgid "'%s' acknowledged message #%d\n" +msgstr "" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' entered the room\n" +msgstr "« %s » vào phòng\n" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' left the room\n" +msgstr "« %s » rá»i phòng\n" + +#: src/chat/gnunet-chat.c:284 src/chat/gnunet-chat.c:316 +#, fuzzy +msgid "Could not change username\n" +msgstr "Không thể tạo miá»n tên.\n" + +#: src/chat/gnunet-chat.c:288 src/chat/gnunet-chat.c:630 +#, fuzzy, c-format +msgid "Joining room `%s' as user `%s'...\n" +msgstr "Äã vào phòng « %s » là ngÆ°á»i dùng « %s ».\n" + +#: src/chat/gnunet-chat.c:320 +#, fuzzy, c-format +msgid "Changed username to `%s'\n" +msgstr "Äã thay đổi tên ngÆ°á»i dùng thành « %s ».\n" + +#: src/chat/gnunet-chat.c:333 +#, c-format +msgid "Users in room `%s': " +msgstr "NgÆ°á»i dùng trong phòng « %s »:" + +#: src/chat/gnunet-chat.c:371 +msgid "Syntax: /msg USERNAME MESSAGE" +msgstr "Cú pháp: /msg TÊN_NGƯỜI_DÙNG TIN_NHẲN" + +#: src/chat/gnunet-chat.c:379 +#, c-format +msgid "Unknown user `%s'\n" +msgstr "Không rõ ngÆ°á»i dùng « %s »\n" + +#: src/chat/gnunet-chat.c:395 +#, c-format +msgid "User `%s' is currently not in the room!\n" +msgstr "NgÆ°á»i dùng « %s » hiện thá»i không có trong phòng này.\n" + +#: src/chat/gnunet-chat.c:448 +#, fuzzy, c-format +msgid "Unknown command `%s'\n" +msgstr "Không rõ câu lệnh « %s ».\n" + +#: src/chat/gnunet-chat.c:459 +msgid "" +"Use `/join #roomname' to join a chat room. Joining a room will cause you to " +"leave the current room" +msgstr "" +"Gõ chuá»—i « /join #tên_phòng » để vào má»™t phòng trò chuyện nào đó (việc này " +"cÅ©ng gây ra bạn ra khá»i phòng hiện tại)" + +#: src/chat/gnunet-chat.c:463 +msgid "" +"Use `/nick nickname' to change your nickname. This will cause you to leave " +"the current room and immediately rejoin it with the new name." +msgstr "" +"Gõ chuá»—i « /nick tên_hiệu » để thay đổi tên hiệu của mình (việc này cÅ©ng gây " +"ra bạn ra khá»i phòng hiện tại, sau đó vào lại ngay vá»›i tên má»›i)" + +#: src/chat/gnunet-chat.c:467 +msgid "" +"Use `/msg nickname message' to send a private message to the specified user" +msgstr "" +"Gõ chuá»—i « /msg tên_hiệu tin_nhẳn » để gá»­i má»™t tin nhẳn riêng cho ngÆ°á»i dùng " +"có tên đó" + +#: src/chat/gnunet-chat.c:470 +msgid "The `/notice' command is an alias for `/msg'" +msgstr "Lệnh « /notice » là má»™t biệt hiệu cho « /msg »" + +#: src/chat/gnunet-chat.c:472 +msgid "The `/query' command is an alias for `/msg'" +msgstr "Lệnh « /query » là má»™t biệt hiệu cho « /msg »" + +#: src/chat/gnunet-chat.c:474 +#, fuzzy +msgid "Use `/sig message' to send a signed public message" +msgstr "" +"Gõ chuá»—i « /msg tên_hiệu tin_nhẳn » để gá»­i má»™t tin nhẳn riêng cho ngÆ°á»i dùng " +"có tên đó" + +#: src/chat/gnunet-chat.c:477 +msgid "Use `/ack message' to require signed acknowledgment of the message" +msgstr "" + +#: src/chat/gnunet-chat.c:480 +msgid "Use `/anonymous message' to send a public anonymous message" +msgstr "" + +#: src/chat/gnunet-chat.c:482 +#, fuzzy +msgid "The `/anon' command is an alias for `/anonymous'" +msgstr "Lệnh « /notice » là má»™t biệt hiệu cho « /msg »" + +#: src/chat/gnunet-chat.c:484 +msgid "Use `/quit' to terminate gnunet-chat" +msgstr "Gõ chuá»—i « /quit » để thoát khá»i trình gnunet-chat" + +#: src/chat/gnunet-chat.c:486 +msgid "The `/leave' command is an alias for `/quit'" +msgstr "Lệnh « /leave » là má»™t biệt hiệu cho « /quit »" + +#: src/chat/gnunet-chat.c:489 +msgid "Use `/names' to list all of the current members in the chat room" +msgstr "" +"Gõ chuá»—i « /names » để liệt kê tất cả các thành viên hiện thá»i trong phòng " +"trò chuyện đó" + +#: src/chat/gnunet-chat.c:491 +msgid "Use `/help command' to get help for a specific command" +msgstr "Gõ chuá»—i « /help LỆNH » để xem trợ giúp vá» lệnh đó" + +#: src/chat/gnunet-chat.c:606 +msgid "You must specify a nickname\n" +msgstr "Phải ghi rõ tên hiệu\n" + +#: src/chat/gnunet-chat.c:622 +#, c-format +msgid "Failed to join room `%s'\n" +msgstr "Lá»—i vào phòng « %s »\n" + +#: src/chat/gnunet-chat.c:655 +msgid "set the nickname to use (required)" +msgstr "đặt tên hiệu cần dùng (cần thiết)" + +#: src/chat/gnunet-chat.c:658 +msgid "set the chat room to join" +msgstr "đặt phòng trò chuyện cần vào" + +#: src/chat/gnunet-chat.c:670 +msgid "Join a chat on GNUnet." +msgstr "Vào phòng trò chuyện trên GNUnet." + +#: src/chat/gnunet-service-chat.c:267 +#, fuzzy +msgid "Failed to queue a message notification\n" +msgstr "Lá»—i lÆ°u cấu hình." + +#: src/chat/gnunet-service-chat.c:546 +#, fuzzy +msgid "Failed to queue a join notification\n" +msgstr "Lá»—i lÆ°u cấu hình." + +#: src/chat/gnunet-service-chat.c:729 +#, fuzzy +msgid "Failed to queue a confirmation receipt\n" +msgstr "Lá»—i lÆ°u cấu hình." + +#: src/chat/gnunet-service-chat.c:907 +#, fuzzy +msgid "Failed to queue a leave notification\n" +msgstr "Lá»—i lÆ°u cấu hình." + +#: src/core/core_api.c:798 +msgid "Client was disconnected from core service, trying to reconnect.\n" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:77 +#: src/peerinfo-tool/gnunet-peerinfo.c:60 +#, fuzzy, c-format +msgid "Peer `%s'\n" +msgstr "Tôi là đồng đẳng « %s ».\n" + +#: src/core/gnunet-core-list-connections.c:175 +#: src/peerinfo-tool/gnunet-peerinfo.c:194 +#, fuzzy, c-format +msgid "Invalid command line argument `%s'\n" +msgstr "Äối số không hợp lệ cho « %s ».\n" + +#: src/core/gnunet-core-list-connections.c:196 +#: src/peerinfo-tool/gnunet-peerinfo.c:252 +msgid "don't resolve host names" +msgstr "không quyết định các tên máy" + +#: src/core/gnunet-core-list-connections.c:203 +#, fuzzy +msgid "Print information about connected peers." +msgstr "In ra thông tin vá» các đồng đẳng GNUnet." + +#: src/core/gnunet-service-core.c:99 +#, c-format +msgid "Core service of `%4s' ready.\n" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:360 +#, fuzzy +msgid "# send requests dropped (disconnected)" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/core/gnunet-service-core_clients.c:465 +#, fuzzy +msgid "# messages discarded (session disconnected)" +msgstr "# các thông báo được chắp liá»n" + +#: src/core/gnunet-service-core_clients.c:801 +#, fuzzy, c-format +msgid "# bytes of messages of type %u received" +msgstr "# các byte nhiá»…u được nhận" + +#: src/core/gnunet-service-core_kx.c:493 +msgid "# bytes encrypted" +msgstr "# các byte đã mã hoá" + +#: src/core/gnunet-service-core_kx.c:543 +msgid "# bytes decrypted" +msgstr "# các byte đã giải mã" + +#: src/core/gnunet-service-core_kx.c:604 src/dv/gnunet-service-dv.c:3002 +#: src/hostlist/hostlist-server.c:436 src/peerinfo-tool/gnunet-peerinfo.c:151 +#, fuzzy +msgid "Error in communication with PEERINFO service\n" +msgstr "Cổng để liên lạc vá»›i giao diện ngÆ°á»i dùng GNUnet" + +#: src/core/gnunet-service-core_kx.c:623 +msgid "# Delayed connecting due to lack of public key" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:673 +msgid "# key exchanges initiated" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:694 +msgid "# key exchanges stopped" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:746 +#, fuzzy +msgid "# session keys received" +msgstr "# các khoá phiên chạy bị từ chối" + +#: src/core/gnunet-service-core_kx.c:765 +#, c-format +msgid "`%s' is for `%s', not for me. Ignoring.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:803 +#, fuzzy +msgid "# SET_KEY messages decrypted" +msgstr "# các thông báo được chắp liá»n" + +#: src/core/gnunet-service-core_kx.c:883 +#: src/transport/gnunet-service-transport_validation.c:803 +#, fuzzy +msgid "# PING messages received" +msgstr "# các thông báo PING được tạo" + +#: src/core/gnunet-service-core_kx.c:917 +#, c-format +msgid "" +"Received PING from `%s' for different identity: I am `%s', PONG identity: `" +"%s'\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:938 +#, fuzzy +msgid "# PONG messages created" +msgstr "# các thông báo PING được tạo" + +#: src/core/gnunet-service-core_kx.c:1026 +#, fuzzy +msgid "# sessions terminated by timeout" +msgstr "# các byte loại Ä‘i bởi TCP (Ä‘i ra)" + +#: src/core/gnunet-service-core_kx.c:1037 +#, fuzzy +msgid "# keepalive messages sent" +msgstr "# các thông báo PING nhập thô được gá»­i" + +#: src/core/gnunet-service-core_kx.c:1095 +#: src/transport/gnunet-service-transport_validation.c:1026 +#, fuzzy +msgid "# PONG messages received" +msgstr "# các thông báo PONG đã mật mã được nhận" + +#: src/core/gnunet-service-core_kx.c:1125 +#, fuzzy +msgid "# PONG messages decrypted" +msgstr "# các thông báo PING được tạo" + +#: src/core/gnunet-service-core_kx.c:1157 +#, fuzzy +msgid "# session keys confirmed via PONG" +msgstr "# Các quảng cáo đồng đẳng được xác nhận qua PONG" + +#: src/core/gnunet-service-core_kx.c:1223 +#, fuzzy +msgid "# SET_KEY and PING messages created" +msgstr "# các thông báo PING được tạo" + +#: src/core/gnunet-service-core_kx.c:1364 +msgid "# failed to decrypt message (no session key)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1406 +#: src/core/gnunet-service-core_kx.c:1431 +#, fuzzy +msgid "# bytes dropped (duplicates)" +msgstr "# các byte loại bá» bởi UDP (Ä‘i ra)" + +#: src/core/gnunet-service-core_kx.c:1418 +#, fuzzy +msgid "# bytes dropped (out of sequence)" +msgstr "# các byte loại bá» bởi UDP (Ä‘i ra)" + +#: src/core/gnunet-service-core_kx.c:1455 +#, fuzzy, c-format +msgid "Message received far too old (%llu ms). Content ignored.\n" +msgstr "Thông báo nhận được cÅ© hÆ¡n má»™t ngày. Äã loại bá».\n" + +#: src/core/gnunet-service-core_kx.c:1459 +#, fuzzy +msgid "# bytes dropped (ancient message)" +msgstr "# các byte loại bá» bởi UDP (Ä‘i ra)" + +#: src/core/gnunet-service-core_kx.c:1467 +#, fuzzy +msgid "# bytes of payload decrypted" +msgstr "# các byte đã giải mã" + +#: src/core/gnunet-service-core_kx.c:1528 +#, fuzzy +msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" +msgstr "LÆ°u cấu hình ngay bây giá» không?" + +#: src/core/gnunet-service-core_kx.c:1536 +msgid "Core service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1546 src/hostlist/hostlist-server.c:555 +#: src/peerinfo-tool/gnunet-peerinfo.c:202 +#: src/transport/gnunet-service-transport.c:595 +#, fuzzy +msgid "Could not access PEERINFO service. Exiting.\n" +msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" + +#: src/core/gnunet-service-core_neighbours.c:163 +#, fuzzy +msgid "# sessions terminated by transport disconnect" +msgstr "# Các quảng cáo đồng đẳng bị hủy do trá»ng tải" + +#: src/core/gnunet-service-core_neighbours.c:180 +#: src/core/gnunet-service-core_neighbours.c:342 +msgid "# neighbour entries allocated" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:251 +msgid "# encrypted bytes given to transport" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:430 +#, c-format +msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:208 +#: src/core/gnunet-service-core_sessions.c:273 +msgid "# entries in session map" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:238 +#, fuzzy +msgid "# type map refreshes sent" +msgstr "# tổng số yêu cầu lá»— hổng được gá»­i" + +#: src/core/gnunet-service-core_sessions.c:414 +msgid "# messages discarded (expired prior to transmission)" +msgstr "" + +#: src/core/gnunet-service-core_typemap.c:110 +#: src/core/gnunet-service-core_typemap.c:121 +#, fuzzy +msgid "# type maps received" +msgstr "# các thông báo phát hiện dht được nhận" + +#: src/core/gnunet-service-core_typemap.c:151 +msgid "# updates to my type map" +msgstr "" + +#: src/datacache/datacache.c:118 src/datacache/datacache.c:255 +#: src/datastore/gnunet-service-datastore.c:854 +#, fuzzy +msgid "# bytes stored" +msgstr "# các byte trong kho dữ liệu" + +#: src/datacache/datacache.c:144 src/datacache/datacache.c:151 +#: src/datastore/gnunet-service-datastore.c:1531 +#: src/datastore/gnunet-service-datastore.c:1542 +#, c-format +msgid "No `%s' specified for `%s' in configuration!\n" +msgstr "" + +#: src/datacache/datacache.c:183 +#, c-format +msgid "Loading `%s' datacache plugin\n" +msgstr "" + +#: src/datacache/datacache.c:191 +#, fuzzy, c-format +msgid "Failed to load datacache plugin for `%s'\n" +msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" + +#: src/datacache/datacache.c:281 +#, fuzzy +msgid "# requests received" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/datacache/datacache.c:291 +msgid "# requests filtered by bloom filter" +msgstr "# các yêu cầu được lá»c theo bá»™ lá»c bloom" + +#: src/datacache/plugin_datacache_mysql.c:103 +#: src/datacache/plugin_datacache_mysql.c:110 +#: src/datacache/plugin_datacache_mysql.c:517 +#: src/datacache/plugin_datacache_mysql.c:526 +#: src/datacache/plugin_datacache_mysql.c:598 +#: src/datacache/plugin_datacache_mysql.c:614 +#: src/datacache/plugin_datacache_sqlite.c:71 +#: src/datacache/plugin_datacache_sqlite.c:74 +#: src/datastore/plugin_datastore_mysql.c:139 +#: src/datastore/plugin_datastore_mysql.c:146 +#: src/datastore/plugin_datastore_mysql.c:613 +#: src/datastore/plugin_datastore_mysql.c:673 +#: src/datastore/plugin_datastore_mysql.c:685 +#: src/datastore/plugin_datastore_mysql.c:1362 +#: src/datastore/plugin_datastore_mysql.c:1376 +#: src/datastore/plugin_datastore_sqlite.c:61 +#: src/namestore/plugin_namestore_sqlite.c:49 src/util/crypto_ksk.c:49 +#: src/util/crypto_rsa.c:92 src/include/gnunet_common.h:507 +#: src/include/gnunet_common.h:514 +#, c-format +msgid "`%s' failed at %s:%d with error: %s\n" +msgstr "« %s » bị lá»—i tại %s:%d vá»›i lá»—i: %s\n" + +#: src/datacache/plugin_datacache_mysql.c:224 +#: src/datastore/plugin_datastore_mysql.c:316 +#, c-format +msgid "Trying to use file `%s' for MySQL configuration.\n" +msgstr "Äang thá»­ dùng tập tin « %s » cho cấu hình MySQL.\n" + +#: src/datacache/plugin_datacache_mysql.c:230 +#: src/datastore/plugin_datastore_mysql.c:322 +#, fuzzy, c-format +msgid "Could not access file `%s': %s\n" +msgstr "Không thể truy cập đến « %s »: %s\n" + +#: src/datacache/plugin_datacache_mysql.c:979 +msgid "MySQL datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_postgres.c:79 +#: src/datastore/plugin_datastore_postgres.c:93 +#, fuzzy, c-format +msgid "`%s:%s' failed at %s:%d with error: %s" +msgstr "« %s » bị lá»—i tại %s:%d vá»›i lá»—i: %s" + +#: src/datacache/plugin_datacache_postgres.c:149 +#, fuzzy, c-format +msgid "Unable to initialize Postgres: %s" +msgstr "Không thể sÆ¡ khởi SQLite: %s.\n" + +#: src/datacache/plugin_datacache_postgres.c:499 +msgid "Postgres datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:424 +msgid "Sqlite datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:457 +#: src/datastore/plugin_datastore_sqlite.c:414 +#: src/namestore/plugin_namestore_sqlite.c:381 +msgid "Tried to close sqlite without finalizing all prepared statements.\n" +msgstr "" + +#: src/datacache/plugin_datacache_template.c:121 +msgid "Template datacache running\n" +msgstr "" + +#: src/datastore/datastore_api.c:289 +msgid "Failed to transmit request to drop database.\n" +msgstr "" + +#: src/datastore/datastore_api.c:372 +msgid "# queue entry timeouts" +msgstr "" + +#: src/datastore/datastore_api.c:418 +msgid "# queue overflows" +msgstr "" + +#: src/datastore/datastore_api.c:445 +#, fuzzy +msgid "# queue entries created" +msgstr "# các truy vấn lá»— hổng được định tuyến" + +#: src/datastore/datastore_api.c:465 +#, fuzzy +msgid "# Requests dropped from datastore queue" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/datastore/datastore_api.c:513 +#, fuzzy +msgid "# datastore connections (re)created" +msgstr "# các kết nối dht" + +#: src/datastore/datastore_api.c:540 +msgid "# reconnected to DATASTORE" +msgstr "" + +#: src/datastore/datastore_api.c:608 +#, fuzzy +msgid "# transmission request failures" +msgstr "# các sá»± truyá»n PONG bị lá»—i" + +#: src/datastore/datastore_api.c:631 +#, fuzzy +msgid "# bytes sent to datastore" +msgstr "# các byte trong kho dữ liệu" + +#: src/datastore/datastore_api.c:772 +#, fuzzy +msgid "Failed to receive status response from database." +msgstr "" +"\n" +"Không nhận được đáp ứng từ gnunetd.\n" + +#: src/datastore/datastore_api.c:786 +msgid "Error reading response from datastore service" +msgstr "" + +#: src/datastore/datastore_api.c:798 src/datastore/datastore_api.c:804 +#, fuzzy +msgid "Invalid error message received from datastore service" +msgstr "Nhận được thông báo « %s » sai từ đồng đẳng « %s ».\n" + +#: src/datastore/datastore_api.c:810 +#, fuzzy +msgid "# status messages received" +msgstr "# các thông báo phát hiện dht được nhận" + +#: src/datastore/datastore_api.c:883 +#, fuzzy +msgid "# PUT requests executed" +msgstr "# các yêu cầu dht được định tuyến" + +#: src/datastore/datastore_api.c:954 +#, fuzzy +msgid "# RESERVE requests executed" +msgstr "# các yêu cầu dht được định tuyến" + +#: src/datastore/datastore_api.c:1019 +msgid "# RELEASE RESERVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1080 +#, fuzzy +msgid "# UPDATE requests executed" +msgstr "# các yêu cầu dht được định tuyến" + +#: src/datastore/datastore_api.c:1148 +#, fuzzy +msgid "# REMOVE requests executed" +msgstr "# các yêu cầu dht được định tuyến" + +#: src/datastore/datastore_api.c:1193 +#, fuzzy +msgid "Failed to receive response from database.\n" +msgstr "" +"\n" +"Không nhận được đáp ứng từ gnunetd.\n" + +#: src/datastore/datastore_api.c:1253 +#, fuzzy +msgid "# Results received" +msgstr "# các kết quả dht được nhận" + +#: src/datastore/datastore_api.c:1324 +msgid "# GET REPLICATION requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1391 +msgid "# GET ZERO ANONYMITY requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1455 +#, fuzzy +msgid "# GET requests executed" +msgstr "# các yêu cầu dht được định tuyến" + +#: src/datastore/gnunet-service-datastore.c:351 +#, fuzzy +msgid "# bytes expired" +msgstr "# các byte được nhận" + +#: src/datastore/gnunet-service-datastore.c:426 +msgid "# bytes purged (low-priority)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:486 +msgid "Transmission to client failed!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:640 +msgid "# results found" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:685 +#, c-format +msgid "" +"Insufficient space (%llu bytes are available) to satisfy `%s' request for " +"%llu bytes\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:696 +#, c-format +msgid "" +"The requested amount (%llu bytes) is larger than the cache size (%llu " +"bytes)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:700 +msgid "" +"Insufficient space to satisfy request and requested amount is larger than " +"cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:706 +msgid "Insufficient space to satisfy request" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:711 +#: src/datastore/gnunet-service-datastore.c:765 +#: src/datastore/gnunet-service-datastore.c:986 +#: src/datastore/gnunet-service-datastore.c:1465 +msgid "# reserved" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:780 +msgid "Could not find matching reservation" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:868 +#, c-format +msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1034 +#, fuzzy +msgid "# GET requests received" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/datastore/gnunet-service-datastore.c:1048 +#, fuzzy +msgid "# requests filtered by bloomfilter" +msgstr "# các yêu cầu được lá»c theo bá»™ lá»c bloom" + +#: src/datastore/gnunet-service-datastore.c:1076 +#, fuzzy +msgid "# UPDATE requests received" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/datastore/gnunet-service-datastore.c:1110 +#, fuzzy +msgid "# GET REPLICATION requests received" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/datastore/gnunet-service-datastore.c:1145 +#, fuzzy +msgid "# GET ZERO ANONYMITY requests received" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/datastore/gnunet-service-datastore.c:1172 +msgid "Content not found" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1182 +msgid "# bytes removed (explicit request)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1216 +#, fuzzy +msgid "# REMOVE requests received" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/datastore/gnunet-service-datastore.c:1260 +#, c-format +msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1323 +#, c-format +msgid "Loading `%s' datastore plugin\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1332 +#, fuzzy, c-format +msgid "Failed to load datastore plugin for `%s'\n" +msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" + +#: src/datastore/gnunet-service-datastore.c:1536 +#, fuzzy, c-format +msgid "# bytes used in file-sharing datastore `%s'" +msgstr "# các byte được phép trong kho dữ liệu" + +#: src/datastore/gnunet-service-datastore.c:1547 +msgid "# quota" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1549 +msgid "# cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1562 +#, c-format +msgid "Could not use specified filename `%s' for bloomfilter.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1580 +#: src/datastore/gnunet-service-datastore.c:1596 +#, fuzzy, c-format +msgid "Failed to remove bogus bloomfilter file `%s'\n" +msgstr "Không thể lÆ°u tập tin cấu hình « %s »:" + +#: src/datastore/gnunet-service-datastore.c:1626 +#, fuzzy +msgid "Failed to initialize bloomfilter.\n" +msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" + +#: src/datastore/gnunet-service-datastore.c:1655 +msgid "Rebuilding bloomfilter. Please be patient.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1660 +msgid "Plugin does not support get_keys function. Please fix!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1663 +msgid "Bloomfilter construction complete.\n" +msgstr "" + +#: src/datastore/plugin_datastore_mysql.c:529 +#: src/datastore/plugin_datastore_mysql.c:1336 +#, fuzzy, c-format +msgid "Failed to prepare statement `%s'\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/datastore/plugin_datastore_mysql.c:622 +#: src/datastore/plugin_datastore_mysql.c:1346 +#, fuzzy, c-format +msgid "`%s' for `%s' failed at %s:%d with error: %s\n" +msgstr "« %s » bị lá»—i tại %s:%d vá»›i lá»—i: %s\n" + +#: src/datastore/plugin_datastore_mysql.c:1581 +msgid "Mysql database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_postgres.c:173 +#, fuzzy, c-format +msgid "Unable to initialize Postgres with configuration `%s': %s" +msgstr "Không thể lÆ°u tập tin cấu hình « %s »:" + +#: src/datastore/plugin_datastore_postgres.c:1017 +msgid "Postgres database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:61 +#, fuzzy, c-format +msgid "`%s' failed at %s:%u with error: %s" +msgstr "« %s » bị lá»—i tại %s:%d vá»›i lá»—i: %s" + +#: src/datastore/plugin_datastore_sqlite.c:239 +#: src/namestore/plugin_namestore_sqlite.c:223 +#, c-format +msgid "Option `%s' in section `%s' missing in configuration!\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:266 +#: src/namestore/plugin_namestore_sqlite.c:248 +#, c-format +msgid "Unable to initialize SQLite: %s.\n" +msgstr "Không thể sÆ¡ khởi SQLite: %s.\n" + +#: src/datastore/plugin_datastore_sqlite.c:669 +#, fuzzy +msgid "Invalid data in database. Trying to fix (by deletion).\n" +msgstr "Dữ liệu sai trong %s. Äang thá»­ sá»­a chữa (bằng cách xoá).\n" + +#: src/datastore/plugin_datastore_sqlite.c:1159 +msgid "sqlite version to old to determine size, assuming zero\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1178 +#, c-format +msgid "" +"Using sqlite page utilization to estimate payload (%llu pages of size %llu " +"bytes)\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1218 +#: src/namestore/plugin_namestore_sqlite.c:779 +#, fuzzy +msgid "Sqlite database running\n" +msgstr "kho dữ liệu sqlite" + +#: src/datastore/plugin_datastore_template.c:241 +msgid "Template database running\n" +msgstr "" + +#: src/dht/dht_api.c:280 +#, fuzzy +msgid "Failed to connect to the DHT service!\n" +msgstr "Lá»—i kết nối đến gnunetd.\n" + +#: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-put.c:172 +#: src/gns/gnunet-gns-lookup.c:179 +msgid "the query key" +msgstr "" + +#: src/dht/gnunet-dht-get.c:204 src/gns/gnunet-gns-lookup.c:182 +msgid "how many parallel requests (replicas) to create" +msgstr "" + +#: src/dht/gnunet-dht-get.c:207 src/gns/gnunet-gns-lookup.c:185 +msgid "the type of data to look for" +msgstr "" + +#: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:181 +#: src/gns/gnunet-gns-lookup.c:188 +msgid "how long to execute this query before giving up?" +msgstr "" + +#: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-put.c:184 +#: src/fs/gnunet-download.c:270 src/fs/gnunet-publish.c:725 +#: src/fs/gnunet-search.c:297 src/fs/gnunet-unindex.c:169 +#: src/gns/gnunet-gns-lookup.c:191 src/nse/gnunet-nse-profiler.c:908 +msgid "be verbose (print progress information)" +msgstr "" + +#: src/dht/gnunet-dht-get.c:232 +msgid "Issue a GET request to the GNUnet DHT, prints results." +msgstr "" + +#: src/dht/gnunet-dht-put.c:100 +#, fuzzy +msgid "PUT request sent!\n" +msgstr "# Ä‘á»™ tin cậy được tiêu phí" + +#: src/dht/gnunet-dht-put.c:124 +msgid "Must provide KEY and DATA for DHT put!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:132 +#, fuzzy, c-format +msgid "Could not connect to %s service!\n" +msgstr "Không thể kết nối tá»›i %s:%u: %s\n" + +#: src/dht/gnunet-dht-put.c:137 +#, fuzzy, c-format +msgid "Connected to %s service!\n" +msgstr "« %s » được kết nối tá»›i « %s ».\n" + +#: src/dht/gnunet-dht-put.c:152 +#, c-format +msgid "Issuing put request for `%s' with data `%s'!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:166 +msgid "the data to insert under the key" +msgstr "" + +#: src/dht/gnunet-dht-put.c:169 +msgid "how long to store this entry in the dht (in seconds)" +msgstr "" + +#: src/dht/gnunet-dht-put.c:175 +msgid "how many replicas to create" +msgstr "" + +#: src/dht/gnunet-dht-put.c:178 +msgid "the type to insert data as" +msgstr "" + +#: src/dht/gnunet-dht-put.c:203 +msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." +msgstr "" + +#: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:556 +#: src/testing/testing.c:1979 src/testing/testing.c:2009 +#, fuzzy +msgid "Failed to connect to transport service!\n" +msgstr "Lá»—i kết nối đến gnunetd.\n" + +#: src/dht/gnunet-service-dht_clients.c:371 +#, fuzzy +msgid "# GET requests from clients injected" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/dht/gnunet-service-dht_clients.c:462 +#, fuzzy +msgid "# PUT requests received from clients" +msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" + +#: src/dht/gnunet-service-dht_clients.c:529 +#, fuzzy +msgid "# GET requests received from clients" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/dht/gnunet-service-dht_clients.c:624 +#, fuzzy +msgid "# GET STOP requests received from clients" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/dht/gnunet-service-dht_clients.c:854 +msgid "# Key match, type mismatches in REPLY to CLIENT" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:869 +msgid "# Duplicate REPLIES to CLIENT request dropped" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:906 +#, c-format +msgid "Unsupported block type (%u) in request!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:928 +msgid "# RESULTS queued for clients" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:979 +#: src/dht/gnunet-service-dht_clients.c:1022 +msgid "# REPLIES ignored for CLIENTS (no match)" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:989 +msgid "Could not pass reply to client, message too big!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:93 +#, fuzzy, c-format +msgid "%s request received, but have no datacache!\n" +msgstr "# các byte kiểu %d được nhận" + +#: src/dht/gnunet-service-dht_datacache.c:103 +msgid "# ITEMS stored in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:209 +msgid "# Good RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:220 +msgid "# Duplicate RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:226 +msgid "# Invalid RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:238 +msgid "# Unsupported RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:241 +#, c-format +msgid "Unsupported block type (%u) in local response!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:271 +#, fuzzy +msgid "# GET requests given to datacache" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/dht/gnunet-service-dht_hello.c:82 +#, fuzzy +msgid "# HELLOs obtained from peerinfo" +msgstr "Nhận được thông báo « %s » sai từ đồng đẳng « %s ».\n" + +#: src/dht/gnunet-service-dht_neighbours.c:481 +msgid "# Preference updates given to core" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:573 +#, fuzzy +msgid "# FIND PEER messages initiated" +msgstr "# các thông báo PING được tạo" + +#: src/dht/gnunet-service-dht_neighbours.c:629 +#: src/dht/gnunet-service-dht_neighbours.c:689 +#, fuzzy +msgid "# Peers connected" +msgstr "# của các đồng đẳng đã kết nối" + +#: src/dht/gnunet-service-dht_neighbours.c:723 +#, fuzzy +msgid "# Queued messages discarded (peer disconnected)" +msgstr "# các thông báo được chắp liá»n" + +#: src/dht/gnunet-service-dht_neighbours.c:778 +#, fuzzy +msgid "# Bytes transmitted to other peers" +msgstr "# các byte kiểu %d được gá»­i " + +#: src/dht/gnunet-service-dht_neighbours.c:816 +#, fuzzy +msgid "# Bytes of bandwdith requested from core" +msgstr "# các yêu cầu máy/trình khách lá»— hổng được phun vào" + +#: src/dht/gnunet-service-dht_neighbours.c:1040 +#: src/dht/gnunet-service-dht_neighbours.c:1068 +msgid "# Peers excluded from routing due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1049 +#: src/dht/gnunet-service-dht_neighbours.c:1085 +#, fuzzy +msgid "# Peer selection failed" +msgstr "# các cuá»™c gá»i HTTP select (lá»±a chá»n)" + +#: src/dht/gnunet-service-dht_neighbours.c:1221 +#, fuzzy +msgid "# PUT requests routed" +msgstr "# các yêu cầu dht được định tuyến" + +#: src/dht/gnunet-service-dht_neighbours.c:1252 +#, fuzzy +msgid "# PUT messages queued for transmission" +msgstr "# các thông báo PING được tạo" + +#: src/dht/gnunet-service-dht_neighbours.c:1333 +#, fuzzy +msgid "# GET requests routed" +msgstr "# các yêu cầu dht được định tuyến" + +#: src/dht/gnunet-service-dht_neighbours.c:1364 +#, fuzzy +msgid "# GET messages queued for transmission" +msgstr "# các thông báo PING được tạo" + +#: src/dht/gnunet-service-dht_neighbours.c:1467 +#, fuzzy +msgid "# RESULT messages queued for transmission" +msgstr "# các thông báo PING được tạo" + +#: src/dht/gnunet-service-dht_neighbours.c:1555 +#, fuzzy +msgid "# P2P PUT requests received" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/dht/gnunet-service-dht_neighbours.c:1668 +#, fuzzy +msgid "# FIND PEER requests ignored due to Bloomfilter" +msgstr "# các yêu cầu được lá»c theo bá»™ lá»c bloom" + +#: src/dht/gnunet-service-dht_neighbours.c:1676 +msgid "# FIND PEER requests ignored due to lack of HELLO" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1767 +#, fuzzy +msgid "# P2P GET requests received" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/dht/gnunet-service-dht_neighbours.c:1811 +#, fuzzy +msgid "# P2P FIND PEER requests processed" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/dht/gnunet-service-dht_neighbours.c:1825 +#, fuzzy +msgid "# P2P GET requests ONLY routed" +msgstr "# các yêu cầu dht được định tuyến" + +#: src/dht/gnunet-service-dht_neighbours.c:1895 +#, fuzzy +msgid "# P2P RESULTS received" +msgstr "# Tín hiệu HTTP PUT được nhận" + +#: src/dht/gnunet-service-dht_nse.c:59 +#, fuzzy +msgid "# Network size estimates received" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/dht/gnunet-service-dht_routing.c:211 +msgid "# Good REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:220 +msgid "# Duplicate REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:226 +msgid "# Invalid REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:236 +msgid "# Unsupported REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:314 +#: src/dht/gnunet-service-dht_routing.c:368 +msgid "# Entries removed from routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:324 +msgid "# Entries added to routing table" +msgstr "" + +#: src/dht/plugin_block_dht.c:124 +#, fuzzy, c-format +msgid "Block not of type %u\n" +msgstr "Không biết truyá»n tải nào kiểu %d.\n" + +#: src/dht/plugin_block_dht.c:131 +msgid "Size mismatch for block\n" +msgstr "" + +#: src/dht/plugin_block_dht.c:140 +#, c-format +msgid "Block of type %u is malformed\n" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:337 +msgid "only monitor DNS queries" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:340 +msgid "only monitor DNS replies" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:348 +msgid "Monitor DNS queries." +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:236 +msgid "set A records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:239 +msgid "set AAAA records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:247 +msgid "Change DNS replies to point elsewhere." +msgstr "" + +#: src/dns/gnunet-service-dns.c:480 +#, fuzzy, c-format +msgid "Could not bind to any port: %s\n" +msgstr "Không tìm thấy địa chỉ IP của máy « %s »: %s\n" + +#: src/dns/gnunet-service-dns.c:634 +msgid "# DNS requests answered via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:818 +msgid "# DNS exit failed (failed to open socket)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1001 +#, c-format +msgid "Received DNS response that is too small (%u bytes)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1046 +msgid "# External DNS response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1165 +msgid "# Client response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1198 +msgid "Changing DNS reply according to client specifications\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1279 +msgid "Received malformed IPv4-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1294 +msgid "Received malformed IPv6-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1303 +#, c-format +msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1312 +msgid "# Non-DNS UDP packet received via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1377 +#, fuzzy +msgid "# DNS requests received via TUN interface" +msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" + +#: src/dns/gnunet-service-dns.c:1461 +#, c-format +msgid "Configured DNS exit `%s' is not working / valid.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1493 src/exit/gnunet-daemon-exit.c:2673 +msgid "# Inbound MESH tunnels created" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1567 +msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" +msgstr "" + +#: src/dv/dv_api.c:179 +#, fuzzy +msgid "Failed to connect to the dv service!\n" +msgstr "Lá»—i kết nối đến gnunetd.\n" + +#: src/dv/plugin_transport_dv.c:159 +#, fuzzy, c-format +msgid "%s Received message from %s of type %d, distance %u!\n" +msgstr "Nhận được thông báo bị há»ng từ đồng đẳng « %s » trong %s:%d.\n" + +#: src/exit/gnunet-daemon-exit.c:508 +#, c-format +msgid "Got duplicate service records for `%s:%u'\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:563 +#, fuzzy +msgid "# Bytes transmitted via mesh tunnels" +msgstr "# các byte được gá»­i" + +#: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2068 +#: src/exit/gnunet-daemon-exit.c:2318 src/vpn/gnunet-service-vpn.c:1388 +#: src/vpn/gnunet-service-vpn.c:1788 src/vpn/gnunet-service-vpn.c:1951 +msgid "# ICMPv4 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2127 +#: src/exit/gnunet-daemon-exit.c:2377 src/vpn/gnunet-service-vpn.c:1444 +#: src/vpn/gnunet-service-vpn.c:1847 src/vpn/gnunet-service-vpn.c:1984 +msgid "# ICMPv6 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:756 +msgid "# ICMP packets dropped (not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:763 +msgid "ICMP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:840 +msgid "UDP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:915 +msgid "TCP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:968 +#, fuzzy +msgid "# Packets received from TUN" +msgstr "# các byte đã nhận qua HTTP" + +#: src/exit/gnunet-daemon-exit.c:982 +#, fuzzy +msgid "# Bytes received from TUN" +msgstr "# các byte đã nhận qua HTTP" + +#: src/exit/gnunet-daemon-exit.c:1008 +msgid "IPv4 packet options received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1035 +#, c-format +msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1081 +#, c-format +msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1089 +#, c-format +msgid "Packet from unknown protocol %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1470 +#, fuzzy +msgid "# TCP packets sent via TUN" +msgstr "# các byte đã gá»­i qua UDP" + +#: src/exit/gnunet-daemon-exit.c:1570 +#, fuzzy +msgid "# TCP service creation requests received via mesh" +msgstr "# các yêu cầu danh sách máy được nhận" + +#: src/exit/gnunet-daemon-exit.c:1573 src/exit/gnunet-daemon-exit.c:1652 +#: src/exit/gnunet-daemon-exit.c:1762 src/exit/gnunet-daemon-exit.c:1992 +#: src/exit/gnunet-daemon-exit.c:2234 src/exit/gnunet-daemon-exit.c:2515 +#: src/exit/gnunet-daemon-exit.c:2615 +#, fuzzy +msgid "# Bytes received from MESH" +msgstr "# các byte đã nhận qua HTTP" + +#: src/exit/gnunet-daemon-exit.c:1606 src/exit/gnunet-daemon-exit.c:2637 +#, c-format +msgid "No service found for %s on port %d!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1610 +#, fuzzy +msgid "# TCP requests dropped (no such service)" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/exit/gnunet-daemon-exit.c:1655 +#, fuzzy +msgid "# TCP IP-exit creation requests received via mesh" +msgstr "# các yêu cầu danh sách máy được nhận" + +#: src/exit/gnunet-daemon-exit.c:1765 +#, fuzzy +msgid "# TCP data requests received via mesh" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/exit/gnunet-daemon-exit.c:1779 +#, fuzzy +msgid "# TCP DATA requests dropped (no session)" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/exit/gnunet-daemon-exit.c:1829 +#, fuzzy +msgid "# ICMP packets sent via TUN" +msgstr "# các byte đã gá»­i qua UDP" + +#: src/exit/gnunet-daemon-exit.c:1995 +#, fuzzy +msgid "# ICMP IP-exit requests received via mesh" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/exit/gnunet-daemon-exit.c:2237 +#, fuzzy +msgid "# ICMP service requests received via mesh" +msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" + +#: src/exit/gnunet-daemon-exit.c:2303 src/vpn/gnunet-service-vpn.c:1378 +#: src/vpn/gnunet-service-vpn.c:1945 +msgid "# ICMPv4 packets dropped (impossible PT to v6)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2362 src/vpn/gnunet-service-vpn.c:1414 +#: src/vpn/gnunet-service-vpn.c:1426 src/vpn/gnunet-service-vpn.c:1835 +msgid "# ICMPv6 packets dropped (impossible PT to v4)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2412 +#, fuzzy +msgid "# UDP packets sent via TUN" +msgstr "# các byte đã gá»­i qua UDP" + +#: src/exit/gnunet-daemon-exit.c:2518 +#, fuzzy +msgid "# UDP IP-exit requests received via mesh" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/exit/gnunet-daemon-exit.c:2618 +#, fuzzy +msgid "# UDP service requests received via mesh" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/exit/gnunet-daemon-exit.c:2641 +#, fuzzy +msgid "# UDP requests dropped (no such service)" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/exit/gnunet-daemon-exit.c:2881 +#, c-format +msgid "No addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2895 src/exit/gnunet-daemon-exit.c:2907 +#, c-format +msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2918 +#, c-format +msgid "No IP addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3047 +msgid "" +"This system does not support IPv4, will disable IPv4 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3055 +msgid "" +"This system does not support IPv6, will disable IPv6 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3062 +msgid "" +"Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " +"ENABLE_IPv4=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3068 +msgid "" +"Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " +"ENABLE_IPv6=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3074 src/pt/gnunet-daemon-pt.c:884 +msgid "No useful service enabled. Exiting.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3235 +msgid "Daemon to run to provide an IP exit node for the VPN" +msgstr "" + +#: src/fragmentation/defragmentation.c:270 +msgid "# acknowledgements sent for fragment" +msgstr "" + +#: src/fragmentation/defragmentation.c:454 +#, fuzzy +msgid "# fragments received" +msgstr "# các mảnh bị loại bá»" + +#: src/fragmentation/defragmentation.c:513 +#, fuzzy +msgid "# duplicate fragments received" +msgstr "# các kết quả dht được nhận" + +#: src/fragmentation/defragmentation.c:526 +msgid "# messages defragmented" +msgstr "# các thông báo được chắp liá»n" + +#: src/fragmentation/fragmentation.c:188 +#, fuzzy +msgid "# fragments transmitted" +msgstr "# Các tá»± quảng cáo được truyá»n" + +#: src/fragmentation/fragmentation.c:191 +#, fuzzy +msgid "# fragments retransmitted" +msgstr "# Các tá»± quảng cáo được truyá»n" + +#: src/fragmentation/fragmentation.c:255 +msgid "# messages fragmented" +msgstr "# các thông báo bị tế phân" + +#: src/fragmentation/fragmentation.c:258 +msgid "# total size of fragmented messages" +msgstr "" + +#: src/fragmentation/fragmentation.c:343 +#, fuzzy +msgid "# fragment acknowledgements received" +msgstr "# Các quảng cáo đồng đẳng được nhận" + +#: src/fragmentation/fragmentation.c:349 +msgid "# bits removed from fragmentation ACKs" +msgstr "" + +#: src/fragmentation/fragmentation.c:373 +#, fuzzy +msgid "# fragmentation transmissions completed" +msgstr "# các sá»± truyá»n PONG bị lá»—i" + +#: src/fs/fs_api.c:284 +#, fuzzy, c-format +msgid "Could not open file `%s': %s" +msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" + +#: src/fs/fs_api.c:293 +#, fuzzy, c-format +msgid "Could not read file `%s': %s" +msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" + +#: src/fs/fs_api.c:299 +#, c-format +msgid "Short read reading from file `%s'!" +msgstr "" + +#: src/fs/fs_api.c:877 +#, fuzzy, c-format +msgid "Failed to resume publishing information `%s': %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/fs/fs_api.c:1334 +#, c-format +msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" +msgstr "" + +#: src/fs/fs_api.c:1376 +#, c-format +msgid "Failure while resuming publishing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:1392 +#, fuzzy, c-format +msgid "Failed to resume publishing operation `%s': %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/fs/fs_api.c:2004 +#, c-format +msgid "Failure while resuming unindexing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2014 +#, fuzzy, c-format +msgid "Failed to resume unindexing operation `%s': %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/fs/fs_api.c:2139 src/fs/fs_api.c:2378 +#, fuzzy, c-format +msgid "Failed to resume sub-download `%s': %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/fs/fs_api.c:2156 +#, fuzzy, c-format +msgid "Failed to resume sub-search `%s': %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/fs/fs_api.c:2168 src/fs/fs_api.c:2187 src/fs/fs_api.c:2671 +#, c-format +msgid "Failure while resuming search operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2369 +#, c-format +msgid "Failed to resume sub-download `%s': could not open file `%s'\n" +msgstr "" + +#: src/fs/fs_api.c:2615 +msgid "Could not resume running search, will resume as paused search\n" +msgstr "" + +#: src/fs/fs_api.c:2709 +#, c-format +msgid "Failure while resuming download operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_directory.c:210 +#, fuzzy +msgid "MAGIC mismatch. This is not a GNUnet directory.\n" +msgstr "Lá»—i định dạng tập tin (không phải là thÆ° mục GNUnet ?)\n" + +#: src/fs/fs_download.c:310 +msgid "" +"Recursive downloads of directories larger than 4 GB are not supported on 32-" +"bit systems\n" +msgstr "" + +#: src/fs/fs_download.c:330 +msgid "Directory too large for system address space\n" +msgstr "" + +#: src/fs/fs_download.c:488 src/fs/fs_download.c:500 +#, fuzzy, c-format +msgid "Failed to open file `%s' for writing" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/fs/fs_download.c:870 +#, fuzzy, c-format +msgid "Failed to create directory for recursive download of `%s'\n" +msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" + +#: src/fs/fs_download.c:951 +#, c-format +msgid "" +"Internal error or bogus download URI (expected %u bytes at depth %u and " +"offset %llu/%llu, got %u bytes)\n" +msgstr "" + +#: src/fs/fs_download.c:977 +msgid "internal error decrypting content" +msgstr "" + +#: src/fs/fs_download.c:1000 +#, fuzzy, c-format +msgid "Download failed: could not open file `%s': %s\n" +msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" + +#: src/fs/fs_download.c:1010 +#, fuzzy, c-format +msgid "Failed to seek to offset %llu in file `%s': %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/fs/fs_download.c:1019 +#, c-format +msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s\n" +msgstr "" + +#: src/fs/fs_download.c:1835 +#, fuzzy +msgid "Invalid URI" +msgstr "Dữ liệu nhập không hợp lệ.\n" + +#: src/fs/fs_getopt.c:191 +#, c-format +msgid "" +"Unknown metadata type in metadata option `%s'. Using metadata type " +"`unknown' instead.\n" +msgstr "" +"Không rõ kiểu siêu dữ liệu trong tùy chá»n siêu dữ liệu « %s ». Äang ùng kiểu " +"siêu dữ liệu « không rõ » (unknown) để thay thế.\n" + +#: src/fs/fs_list_indexed.c:90 +#, fuzzy, c-format +msgid "Failed to receive response for `%s' request from `%s' service.\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/fs/fs_list_indexed.c:113 +#, fuzzy, c-format +msgid "Failed to receive valid response for `%s' request from `%s' service.\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/fs/fs_list_indexed.c:151 +#, fuzzy, c-format +msgid "Failed to not connect to `%s' service.\n" +msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" + +#: src/fs/fs_misc.c:126 +#, c-format +msgid "Did not find mime type `%s' in extension list.\n" +msgstr "" + +#: src/fs/fs_namespace_advertise.c:150 +#, fuzzy +msgid "Unknown error" +msgstr "Lá»—i không rõ.\n" + +#: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 +#, fuzzy +msgid "Failed to serialize meta data" +msgstr "Lá»—i lấy thông kê vá» truyá»n tải.\n" + +#: src/fs/fs_namespace_advertise.c:278 +#, fuzzy +msgid "Failed to connect to datastore service" +msgstr "Không kết nối được đến trình ná»n gnunetd." + +#: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 +#, fuzzy, c-format +msgid "Configuration fails to specify `%s' in section `%s'\n" +msgstr "Tập tin cấu hình « %s » đã được ghi.\n" + +#: src/fs/fs_namespace.c:112 +#, fuzzy, c-format +msgid "Failed to open `%s' for writing: %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 +#, fuzzy, c-format +msgid "Failed to write `%s': %s\n" +msgstr "Lá»—i chạy %s: %s %d\n" + +#: src/fs/fs_namespace.c:256 +#, fuzzy, c-format +msgid "Failed to create or read private key for namespace `%s'\n" +msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" + +#: src/fs/fs_namespace.c:371 +#, fuzzy, c-format +msgid "Failed to read namespace private key file `%s', deleting it!\n" +msgstr "Lá»—i thêm mục nhập vào không gian tên « %s » (có chÆ°a ?)\n" + +#: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 +#, fuzzy +msgid "Internal error." +msgstr "Lá»—i VR." + +#: src/fs/fs_namespace.c:631 +#, fuzzy +msgid "Failed to connect to datastore." +msgstr "Không kết nối được đến trình ná»n gnunetd." + +#: src/fs/fs_publish.c:129 src/fs/fs_publish.c:395 +#, fuzzy, c-format +msgid "Publishing failed: %s" +msgstr "Gặp lá»—i khi tải lên tập tin: %s\n" + +#: src/fs/fs_publish.c:616 src/fs/fs_publish.c:633 src/fs/fs_publish.c:672 +#: src/fs/fs_publish.c:692 src/fs/fs_publish.c:717 src/fs/fs_publish.c:857 +#, fuzzy, c-format +msgid "Can not index file `%s': %s. Will try to insert instead.\n" +msgstr "Lá»—i đánh chỉ mục tập tin « %s ». Äá» nghị: thá»­ chèn tập tin.\n" + +#: src/fs/fs_publish.c:618 +msgid "timeout on index-start request to `fs' service" +msgstr "" + +#: src/fs/fs_publish.c:630 +#, fuzzy +msgid "unknown error" +msgstr "Lá»—i không rõ" + +#: src/fs/fs_publish.c:673 +msgid "failed to compute hash" +msgstr "" + +#: src/fs/fs_publish.c:693 +#, fuzzy +msgid "filename too long" +msgstr "tên tập tin" + +#: src/fs/fs_publish.c:718 +msgid "could not connect to `fs' service" +msgstr "" + +#: src/fs/fs_publish.c:741 +#, fuzzy, c-format +msgid "Failed to get file identifiers for `%s'\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/fs/fs_publish.c:806 +#, fuzzy, c-format +msgid "Recursive upload failed at `%s': %s" +msgstr "%s bị lá»—i tại %s:%d: « %s »\n" + +#: src/fs/fs_publish.c:812 +#, fuzzy, c-format +msgid "Recursive upload failed: %s" +msgstr "Gặp lá»—i khi tải lên tập tin: %s\n" + +#: src/fs/fs_publish.c:858 +msgid "needs to be an actual file" +msgstr "" + +#: src/fs/fs_publish.c:1067 +#, fuzzy, c-format +msgid "Insufficient space for publishing: %s" +msgstr "Không đủ quyá»n truy cập cho « %s »: %s\n" + +#: src/fs/fs_publish.c:1138 +#, c-format +msgid "Reserving space for %u entries and %llu bytes for publication\n" +msgstr "" + +#: src/fs/fs_publish_ksk.c:258 +#, fuzzy +msgid "Could not connect to datastore." +msgstr "« %s »: Không thể kết nối.\n" + +#: src/fs/fs_search.c:810 +#, c-format +msgid "Got result with unknown block type `%d', ignoring" +msgstr "" + +#: src/fs/fs_test_lib.c:269 +#, fuzzy, c-format +msgid "Failed to start daemon: %s\n" +msgstr "Lá»—i bắt đầu thu thập.\n" + +#: src/fs/fs_unindex.c:57 +msgid "Failed to find given position in file" +msgstr "" + +#: src/fs/fs_unindex.c:62 +#, fuzzy +msgid "Failed to read file" +msgstr "Lá»—i gá»­i tin nhẳn.\n" + +#: src/fs/fs_unindex.c:231 +msgid "Unexpected time for a response from `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:239 +msgid "Timeout waiting for `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:247 +#, fuzzy +msgid "Invalid response from `fs' service." +msgstr "Äối số không hợp lệ cho « %s ».\n" + +#: src/fs/fs_unindex.c:292 +#, fuzzy +msgid "Failed to connect to FS service for unindexing." +msgstr "Không kết nối được đến trình ná»n gnunetd." + +#: src/fs/fs_unindex.c:325 +#, fuzzy +msgid "Failed to connect to `datastore' service." +msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" + +#: src/fs/fs_unindex.c:338 +#, fuzzy +msgid "Failed to open file for unindexing." +msgstr "Không kết nối được đến trình ná»n gnunetd." + +#: src/fs/fs_unindex.c:372 +#, fuzzy +msgid "Failed to compute hash of file." +msgstr "Không kết nối được đến trình ná»n gnunetd." + +#: src/fs/fs_uri.c:220 +#, c-format +msgid "`%' must be followed by HEX number" +msgstr "" + +#: src/fs/fs_uri.c:279 +msgid "Malformed KSK URI (must not begin or end with `+')" +msgstr "" + +#: src/fs/fs_uri.c:297 +msgid "`++' not allowed in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:304 +msgid "Quotes not balanced in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 +msgid "Malformed SKS URI" +msgstr "" + +#: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 +msgid "Malformed CHK URI" +msgstr "" + +#: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 +#: src/fs/fs_uri.c:621 +msgid "SKS URI malformed" +msgstr "" + +#: src/fs/fs_uri.c:603 +msgid "SKS URI malformed (could not decode public key)" +msgstr "" + +#: src/fs/fs_uri.c:609 +msgid "SKS URI malformed (could not find signature)" +msgstr "" + +#: src/fs/fs_uri.c:615 +msgid "SKS URI malformed (could not decode signature)" +msgstr "" + +#: src/fs/fs_uri.c:628 +msgid "SKS URI malformed (could not parse expiration time)" +msgstr "" + +#: src/fs/fs_uri.c:640 +msgid "SKS URI malformed (signature failed validation)" +msgstr "" + +#: src/fs/fs_uri.c:678 +msgid "Unrecognized URI type" +msgstr "" + +#: src/fs/fs_uri.c:903 +#, fuzzy +msgid "Lacking key configuration settings.\n" +msgstr "LÆ°u cấu hình ngay bây giá» không?" + +#: src/fs/fs_uri.c:910 +#, fuzzy, c-format +msgid "Could not access hostkey file `%s'.\n" +msgstr "Không thể truy cập đến tập tin gnunet-directory « %s »\n" + +#: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 +msgid "No keywords specified!\n" +msgstr "ChÆ°a ghi rõ từ khoá.\n" + +#: src/fs/fs_uri.c:1148 +msgid "Number of double-quotes not balanced!\n" +msgstr "Có dấu nháy kép thừa hay thiếu.\n" + +#: src/fs/gnunet-directory.c:49 +#, c-format +msgid "\t\n" +msgstr "" + +#: src/fs/gnunet-directory.c:94 +#, fuzzy, c-format +msgid "Directory `%s' meta data:\n" +msgstr "==> ThÆ° mục « %s »:\n" + +#: src/fs/gnunet-directory.c:97 +#, fuzzy, c-format +msgid "Directory `%s' contents:\n" +msgstr "==> ThÆ° mục « %s »:\n" + +#: src/fs/gnunet-directory.c:132 +#, fuzzy +msgid "You must specify a filename to inspect.\n" +msgstr "Phải ghi rõ chỉ má»™t tên tập tin để chèn.\n" + +#: src/fs/gnunet-directory.c:145 +#, fuzzy, c-format +msgid "Failed to read directory `%s'\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/fs/gnunet-directory.c:154 +#, fuzzy, c-format +msgid "`%s' is not a GNUnet directory\n" +msgstr "Lá»—i định dạng tập tin (không phải là thÆ° mục GNUnet ?)\n" + +#: src/fs/gnunet-directory.c:179 +#, fuzzy +msgid "Display contents of a GNUnet directory" +msgstr "Lá»—i định dạng tập tin (không phải là thÆ° mục GNUnet ?)\n" + +#: src/fs/gnunet-download.c:100 +#, fuzzy, c-format +msgid "Starting download `%s'.\n" +msgstr "Äang bắt đầu tài vỠ« %s »\n" + +#: src/fs/gnunet-download.c:109 +#, fuzzy +msgid "" +msgstr "Lá»—i không rõ" + +#: src/fs/gnunet-download.c:118 +#, c-format +msgid "" +"Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " +"download\n" +msgstr "" + +#: src/fs/gnunet-download.c:128 +#, fuzzy, c-format +msgid "Error downloading: %s.\n" +msgstr "Gặp lá»—i khi tải xuống: %s\n" + +#: src/fs/gnunet-download.c:136 +#, fuzzy, c-format +msgid "Downloading `%s' done (%s/s).\n" +msgstr "Tiến trình tải lên « %s » đã tiếp tục lại.\n" + +#: src/fs/gnunet-download.c:151 src/fs/gnunet-publish.c:190 +#: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 +#, fuzzy, c-format +msgid "Unexpected status: %d\n" +msgstr "Gặp sá»± kiện bất thÆ°á»ng: %d\n" + +#: src/fs/gnunet-download.c:176 +#, fuzzy +msgid "You need to specify a URI argument.\n" +msgstr "KHÔNG cho phép ghi rõ cả hai địa chỉ URI và tên tập tin.\n" + +#: src/fs/gnunet-download.c:182 src/fs/gnunet-publish.c:618 +#, fuzzy, c-format +msgid "Failed to parse URI: %s\n" +msgstr "Tập tin « %s » có URI: %s\n" + +#: src/fs/gnunet-download.c:189 +msgid "Only CHK or LOC URIs supported.\n" +msgstr "" + +#: src/fs/gnunet-download.c:196 +msgid "Target filename must be specified.\n" +msgstr "" + +#: src/fs/gnunet-download.c:210 src/fs/gnunet-publish.c:596 +#: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 +#, fuzzy, c-format +msgid "Could not initialize `%s' subsystem.\n" +msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" + +#: src/fs/gnunet-download.c:247 src/fs/gnunet-search.c:285 +#, fuzzy +msgid "set the desired LEVEL of receiver-anonymity" +msgstr "đặt CẤP mong muốn của tình trạng nặc danh của ngÆ°á»i gá»­i" + +#: src/fs/gnunet-download.c:250 +msgid "delete incomplete downloads (when aborted with CTRL-C)" +msgstr "xoá việc tải vá» không hoàn thành (khi hủy bở dùng CTRL-C)" + +#: src/fs/gnunet-download.c:253 src/fs/gnunet-search.c:288 +msgid "only search the local peer (no P2P network search)" +msgstr "" + +#: src/fs/gnunet-download.c:256 +msgid "write the file to FILENAME" +msgstr "ghi tập tin vào TÊN_TẬP_TIN" + +#: src/fs/gnunet-download.c:260 +#, fuzzy +msgid "set the maximum number of parallel downloads that is allowed" +msgstr "đặt số tối Ä‘a các việc tải xuống đồng thá»i được phép" + +#: src/fs/gnunet-download.c:264 +#, fuzzy +msgid "set the maximum number of parallel requests for blocks that is allowed" +msgstr "đặt số tối Ä‘a các việc tải xuống đồng thá»i được phép" + +#: src/fs/gnunet-download.c:267 +msgid "download a GNUnet directory recursively" +msgstr "tải xuống đệ quy má»™t thÆ° mục GNUnet" + +#: src/fs/gnunet-download.c:277 +msgid "" +"Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" +"chk/...)" +msgstr "" + +#: src/fs/gnunet-fs.c:117 +msgid "print a list of all indexed files" +msgstr "" + +#: src/fs/gnunet-fs.c:124 +#, fuzzy +msgid "Special file-sharing operations" +msgstr "Tùy chá»n chia sẻ tập tin" + +#: src/fs/gnunet-pseudonym.c:151 src/statistics/gnunet-statistics.c:126 +#, fuzzy, c-format +msgid "Invalid argument `%s'\n" +msgstr "Äối số không hợp lệ cho « %s ».\n" + +#: src/fs/gnunet-pseudonym.c:165 +#, fuzzy, c-format +msgid "Namespace `%s' unknown.\n" +msgstr "Không gian tên « %s » có đánh giá %d.\n" + +#: src/fs/gnunet-pseudonym.c:240 src/fs/gnunet-pseudonym.c:247 +#: src/fs/gnunet-pseudonym.c:249 +#, fuzzy, c-format +msgid "Option `%s' ignored\n" +msgstr "%s: tùy chá»n « %s » là mÆ¡ hồ\n" + +#: src/fs/gnunet-pseudonym.c:269 src/fs/gnunet-publish.c:672 +msgid "set the desired LEVEL of sender-anonymity" +msgstr "đặt CẤP mong muốn của tình trạng nặc danh của ngÆ°á»i gá»­i" + +#: src/fs/gnunet-pseudonym.c:272 +msgid "create or advertise namespace NAME" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:275 +msgid "delete namespace NAME " +msgstr "" + +#: src/fs/gnunet-pseudonym.c:278 +#, fuzzy +msgid "" +"add an additional keyword for the advertisment (this option can be specified " +"multiple times)" +msgstr "" +"thêm má»™t từ khóa bổ sung cho tất cả tập tin và thÆ° mục (có thể chỉ ra tùy " +"chá»n này nhiá»u lần)" + +#: src/fs/gnunet-pseudonym.c:282 src/fs/gnunet-publish.c:691 +msgid "set the meta-data for the given TYPE to the given VALUE" +msgstr "đặt siêu dữ liệu cho KIỂU Ä‘Æ°a ra thành GIÃ_TRỊ chỉ ra" + +#: src/fs/gnunet-pseudonym.c:285 +#, fuzzy +msgid "print names of local namespaces" +msgstr "đặt đánh giá của má»™t không gian tên" + +#: src/fs/gnunet-pseudonym.c:288 +msgid "use the given PRIORITY for the advertisments" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:291 +msgid "do not print names of remote namespaces" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:294 src/fs/gnunet-publish.c:710 +msgid "set the desired replication LEVEL" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:297 +#, fuzzy +msgid "specify ID of the root of the namespace" +msgstr "đặt đánh giá của má»™t không gian tên" + +#: src/fs/gnunet-pseudonym.c:300 +#, fuzzy +msgid "change rating of namespace ID by VALUE" +msgstr "đặt đánh giá của má»™t không gian tên" + +#: src/fs/gnunet-pseudonym.c:308 +msgid "Manage GNUnet pseudonyms." +msgstr "" + +#: src/fs/gnunet-publish.c:147 +#, c-format +msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-publish.c:155 +#, fuzzy, c-format +msgid "Error publishing: %s.\n" +msgstr "Gặp lá»—i khi tải xuống: %s\n" + +#: src/fs/gnunet-publish.c:165 +#, c-format +msgid "Publishing `%s' done.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:169 +#, fuzzy, c-format +msgid "URI is `%s'.\n" +msgstr "Tôi là đồng đẳng « %s ».\n" + +#: src/fs/gnunet-publish.c:187 +#, fuzzy +msgid "Cleanup after abort complete.\n" +msgstr "Hoàn thành khởi chạy « %s ».\n" + +#: src/fs/gnunet-publish.c:299 +#, fuzzy, c-format +msgid "Meta data for file `%s' (%s)\n" +msgstr "Äang cập nhật dữ liệu cho mô-Ä‘un « %s »\n" + +#: src/fs/gnunet-publish.c:301 +#, fuzzy, c-format +msgid "Keywords for file `%s' (%s)\n" +msgstr "Từ khoá cho tập tin « %s »:\n" + +#: src/fs/gnunet-publish.c:352 +#, fuzzy, c-format +msgid "Failed to create namespace `%s'\n" +msgstr "Không thể tạo miá»n tên.\n" + +#: src/fs/gnunet-publish.c:427 +#, fuzzy +msgid "Could not publish\n" +msgstr "Không thể truy cập đến « %s »: %s\n" + +#: src/fs/gnunet-publish.c:454 +#, fuzzy +msgid "Could not start publishing.\n" +msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" + +#: src/fs/gnunet-publish.c:485 +#, fuzzy, c-format +msgid "Scanning directory `%s'.\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/fs/gnunet-publish.c:487 +#, fuzzy, c-format +msgid "Scanning file `%s'.\n" +msgstr "Äang bắt đầu tài vỠ« %s »\n" + +#: src/fs/gnunet-publish.c:492 +#, c-format +msgid "There was trouble processing file `%s', skipping it.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:497 +msgid "Preprocessing complete.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:501 +#, fuzzy, c-format +msgid "Extracting meta data from file `%s' complete.\n" +msgstr "Äang cập nhật dữ liệu cho mô-Ä‘un « %s »\n" + +#: src/fs/gnunet-publish.c:505 +msgid "Meta data extraction has finished.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:512 +#, fuzzy +msgid "Internal error scanning directory.\n" +msgstr "=\tLá»—i Ä‘á»c thÆ° mục.\n" + +#: src/fs/gnunet-publish.c:546 +#, c-format +msgid "Cannot extract metadata from a URI!\n" +msgstr "Không thể trích siêu dữ liệu ra má»™t địa chỉ URI.\n" + +#: src/fs/gnunet-publish.c:553 +#, c-format +msgid "You must specify one and only one filename for insertion.\n" +msgstr "Phải ghi rõ chỉ má»™t tên tập tin để chèn.\n" + +#: src/fs/gnunet-publish.c:559 +#, c-format +msgid "You must NOT specify an URI and a filename.\n" +msgstr "KHÔNG cho phép ghi rõ cả hai địa chỉ URI và tên tập tin.\n" + +#: src/fs/gnunet-publish.c:567 src/vpn/gnunet-vpn.c:214 +#, c-format +msgid "Option `%s' is required when using option `%s'.\n" +msgstr "Tùy chá»n « %s » cần thiết khi dùng tùy chá»n « %s ».\n" + +#: src/fs/gnunet-publish.c:577 src/fs/gnunet-publish.c:584 +#: src/transport/gnunet-transport.c:530 +#, c-format +msgid "Option `%s' makes no sense without option `%s'.\n" +msgstr "Tùy chá»n « %s » không có nghÄ©a khi không có tùy chá»n « %s ».\n" + +#: src/fs/gnunet-publish.c:606 +#, fuzzy, c-format +msgid "Could not create namespace `%s'\n" +msgstr "Không thể tạo miá»n tên.\n" + +#: src/fs/gnunet-publish.c:639 +#, fuzzy, c-format +msgid "Failed to access `%s': %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/fs/gnunet-publish.c:651 +msgid "" +"Failed to start meta directory scanner. Is gnunet-helper-publish-fs " +"installed?\n" +msgstr "" + +#: src/fs/gnunet-publish.c:676 +msgid "disable adding the creation time to the metadata of the uploaded file" +msgstr "tắt thêm giá» tạo vào siêu dữ liệu của tập tin đã tải lên" + +#: src/fs/gnunet-publish.c:679 +msgid "do not use libextractor to add keywords or metadata" +msgstr "" + +#: src/fs/gnunet-publish.c:683 +msgid "" +"print list of extracted keywords that would be used, but do not perform " +"upload" +msgstr "" +"in ra danh sách các từ khóa đã giải phóng cần sá»­ dụng, nhÆ°ng không thá»±c hiện " +"tải lên" + +#: src/fs/gnunet-publish.c:687 +msgid "" +"add an additional keyword for the top-level file or directory (this option " +"can be specified multiple times)" +msgstr "" +"thêm má»™t từ khoá bổ sung cho tập tin hoặc thÆ° mục ở cấp đầu (có thể chỉ ra " +"tùy chá»n này nhiá»u lần)" + +#: src/fs/gnunet-publish.c:694 +msgid "" +"do not index, perform full insertion (stores entire file in encrypted form " +"in GNUnet database)" +msgstr "" +"không đánh chỉ mục, thá»±c hiện việc chèn đầy đủ (chứa toàn bá»™ tập tin ở dạng " +"mã hóa trong cÆ¡ sở dữ liệu GNUnet)" + +#: src/fs/gnunet-publish.c:699 +msgid "" +"specify ID of an updated version to be published in the future (for " +"namespace insertions only)" +msgstr "" +"chỉ ra mã số của má»™t phiên bản đã cập nhật để công bố trong tÆ°Æ¡ng lai (chỉ " +"cho sá»± chèn không gian tên)" + +#: src/fs/gnunet-publish.c:703 +msgid "specify the priority of the content" +msgstr "xác định mức Æ°u tiên của ná»™i dung" + +#: src/fs/gnunet-publish.c:707 +msgid "publish the files under the pseudonym NAME (place file into namespace)" +msgstr "" +"công bố các tập tin dÆ°á»›i biệt hiệu TÊN (đặt tập tin vào không gian tên)" + +#: src/fs/gnunet-publish.c:713 +#, fuzzy +msgid "" +"only simulate the process but do not do any actual publishing (useful to " +"compute URIs)" +msgstr "" +"chỉ mô phá»ng tiến trình, không thật công bố (có ích để tính địa chỉ URI)" + +#: src/fs/gnunet-publish.c:717 +msgid "" +"set the ID of this version of the publication (for namespace insertions only)" +msgstr "" +"đặt mã số của phiên bản này của sá»± công bố (chỉ cho chèn không gian tên)" + +#: src/fs/gnunet-publish.c:721 +msgid "" +"URI to be published (can be used instead of passing a file to add keywords " +"to the file with the respective URI)" +msgstr "" +"Äịa chỉ URI cần công bố (có thể được dùng thay vào gá»­i má»™t tập tin để thêm " +"từ khoá vào tập tin có địa chỉ URI tÆ°Æ¡ng ứng)" + +#: src/fs/gnunet-publish.c:736 +msgid "Publish a file or directory on GNUnet" +msgstr "" + +#: src/fs/gnunet-search.c:111 +#, c-format +msgid "Failed to write directory with search results to `%s'\n" +msgstr "" + +#: src/fs/gnunet-search.c:181 +#, fuzzy, c-format +msgid "Error searching: %s.\n" +msgstr "Gặp lá»—i khi tải xuống: %s\n" + +#: src/fs/gnunet-search.c:231 +#, fuzzy +msgid "Could not create keyword URI from arguments.\n" +msgstr "Không thể tạo miá»n tên.\n" + +#: src/fs/gnunet-search.c:255 +#, fuzzy +msgid "Could not start searching.\n" +msgstr "Không thể tạo miá»n tên.\n" + +#: src/fs/gnunet-search.c:291 +msgid "write search results to file starting with PREFIX" +msgstr "" + +#: src/fs/gnunet-search.c:294 +msgid "automatically terminate search after VALUE ms" +msgstr "" + +#: src/fs/gnunet-search.c:301 +msgid "automatically terminate search after VALUE results are found" +msgstr "" + +#: src/fs/gnunet-search.c:308 +#, fuzzy +msgid "Search GNUnet for files that were published on GNUnet" +msgstr "Không hiển thị kết quả tìm kiếm cho tập tin được chúng ta tải lên" + +#: src/fs/gnunet-service-fs.c:240 +msgid "# running average P2P latency (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 +#, fuzzy +msgid "# Loopback routes suppressed" +msgstr "# tổng số định tuyến lá»— hổng thành công" + +#: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 +#: src/topology/gnunet-daemon-topology.c:1290 +#: src/topology/gnunet-daemon-topology.c:1297 +#, fuzzy, c-format +msgid "Failed to connect to `%s' service.\n" +msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" + +#: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 +#: src/topology/gnunet-daemon-topology.c:654 +#: src/topology/gnunet-daemon-topology.c:756 +#: src/transport/gnunet-service-transport_neighbours.c:960 +#: src/transport/gnunet-service-transport_neighbours.c:1289 +#: src/transport/gnunet-service-transport_neighbours.c:1841 +#: src/transport/gnunet-service-transport_neighbours.c:2499 +#: src/transport/gnunet-service-transport_neighbours.c:2566 +#, fuzzy +msgid "# peers connected" +msgstr "# của các đồng đẳng đã kết nối" + +#: src/fs/gnunet-service-fs_cp.c:696 +#, fuzzy +msgid "# migration stop messages received" +msgstr "# các thông báo phát hiện dht được nhận" + +#: src/fs/gnunet-service-fs_cp.c:700 +#, c-format +msgid "Migration of content to peer `%s' blocked for %llu ms\n" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:735 +#, fuzzy +msgid "# replies transmitted to other peers" +msgstr "# các byte kiểu %d được gá»­i " + +#: src/fs/gnunet-service-fs_cp.c:741 +#, fuzzy +msgid "# replies dropped" +msgstr "# các đáp ứng dht được định tuyến" + +#: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 +msgid "# P2P searches active" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:858 +msgid "# artificial delays introduced (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:911 +#, fuzzy +msgid "# replies dropped due to type mismatch" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/fs/gnunet-service-fs_cp.c:919 +#, fuzzy +msgid "# replies received for other peers" +msgstr "# các byte kiểu %d được nhận" + +#: src/fs/gnunet-service-fs_cp.c:933 +msgid "# replies dropped due to insufficient cover traffic" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:971 +msgid "# P2P searches destroyed due to ultimate reply" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1038 +#, fuzzy +msgid "# requests done for free (low load)" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/fs/gnunet-service-fs_cp.c:1062 +msgid "# request dropped, priority insufficient" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1072 +#, fuzzy +msgid "# requests done for a price (normal load)" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/fs/gnunet-service-fs_cp.c:1151 +msgid "# GET requests received (from other peers)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1185 +#, fuzzy +msgid "# requests dropped due to initiator not being connected" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/fs/gnunet-service-fs_cp.c:1207 +#, fuzzy +msgid "# requests dropped due to missing reverse route" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/fs/gnunet-service-fs_cp.c:1267 +#, fuzzy +msgid "# requests dropped due TTL underflow" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/fs/gnunet-service-fs_cp.c:1293 +#, fuzzy +msgid "# requests dropped due to higher-TTL request" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/fs/gnunet-service-fs_cp.c:1322 +#, fuzzy +msgid "# P2P query messages received and processed" +msgstr "# các thông báo phát hiện dht được nhận" + +#: src/fs/gnunet-service-fs_cp.c:1687 +#, fuzzy +msgid "# migration stop messages sent" +msgstr "# các thông báo phát hiện dht được nhận" + +#: src/fs/gnunet-service-fs_indexing.c:113 +#: src/fs/gnunet-service-fs_indexing.c:163 +#, fuzzy, c-format +msgid "Configuration option `%s' in section `%s' missing.\n" +msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" + +#: src/fs/gnunet-service-fs_indexing.c:121 +#: src/fs/gnunet-service-fs_indexing.c:177 +#, fuzzy, c-format +msgid "Could not open `%s'.\n" +msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" + +#: src/fs/gnunet-service-fs_indexing.c:137 +#, fuzzy, c-format +msgid "Error writing `%s'.\n" +msgstr "Gặp lá»—i khi tạo ngÆ°á»i dùng" + +#: src/fs/gnunet-service-fs_indexing.c:228 +#, c-format +msgid "" +"Index request received for file `%s' is already indexed as `%s'. Permitting " +"anyway.\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:266 +#, c-format +msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:481 +#, fuzzy, c-format +msgid "Failed to delete bogus block: %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/fs/gnunet-service-fs_indexing.c:539 +msgid "# index blocks removed: original file inaccessible" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:554 +#, fuzzy, c-format +msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" +msgstr "Không thể giải quyết « %s » (%s): %s\n" + +#: src/fs/gnunet-service-fs_indexing.c:556 +msgid "not indexed" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:571 +#, fuzzy, c-format +msgid "Indexed file `%s' changed at offset %llu\n" +msgstr "Äánh chỉ mục dữ liệu của tập tin « %s » bị lá»—i tại vị tri %llu.\n" + +#: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 +#: src/fs/gnunet-service-fs_lc.c:488 +#, fuzzy +msgid "# client searches active" +msgstr "# các yêu cầu khách lá»— hổng được nhận" + +#: src/fs/gnunet-service-fs_lc.c:256 +#, fuzzy +msgid "# replies received for local clients" +msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" + +#: src/fs/gnunet-service-fs_lc.c:321 +#, fuzzy +msgid "# client searches received" +msgstr "# các yêu cầu khách lá»— hổng được nhận" + +#: src/fs/gnunet-service-fs_lc.c:356 +msgid "# client searches updated (merged content seen list)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:265 +#, fuzzy +msgid "# average retransmission delay (ms)" +msgstr "# thá»i gian trung bình còn kết nối (theo miligiây)" + +#: src/fs/gnunet-service-fs_pe.c:391 +#, fuzzy +msgid "# transmission failed (core has no bandwidth)" +msgstr "Lá»—i thá»­ gá»­i, kiểu truyá»n tải %d không được há»— trợ\n" + +#: src/fs/gnunet-service-fs_pe.c:420 +#, fuzzy +msgid "# query messages sent to other peers" +msgstr "# các byte thông báo gá»­i Ä‘i bị loại bá»" + +#: src/fs/gnunet-service-fs_pe.c:469 +msgid "# delay heap timeout" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:476 +#, fuzzy +msgid "# query plans executed" +msgstr "# các yêu cầu dht được định tuyến" + +#: src/fs/gnunet-service-fs_pe.c:538 +#, fuzzy +msgid "# requests merged" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/fs/gnunet-service-fs_pe.c:544 +#, fuzzy +msgid "# requests refreshed" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 +#: src/fs/gnunet-service-fs_pe.c:748 +msgid "# query plan entries" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:285 +#, fuzzy +msgid "# Pending requests created" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 +#, fuzzy +msgid "# Pending requests active" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/fs/gnunet-service-fs_pr.c:779 +#, fuzzy +msgid "# replies received and matched" +msgstr "# các byte kiểu %d được nhận" + +#: src/fs/gnunet-service-fs_pr.c:808 +msgid "# duplicate replies discarded (bloomfilter)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:822 +#, c-format +msgid "Unsupported block type %u\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:835 +#, fuzzy +msgid "# results found locally" +msgstr "# ná»™i dung lá»— hổng được tìm cục bá»™" + +#: src/fs/gnunet-service-fs_pr.c:953 +msgid "# Datastore `PUT' failures" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:980 +#, fuzzy +msgid "# storage requests dropped due to high load" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/fs/gnunet-service-fs_pr.c:1015 +#, fuzzy +msgid "# Replies received from DHT" +msgstr "# các byte đã nhận qua HTTP" + +#: src/fs/gnunet-service-fs_pr.c:1106 +#, c-format +msgid "Datastore lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1127 +#, c-format +msgid "On-demand lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1174 +msgid "# Datastore lookups concluded (no results)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1188 +msgid "# Datastore lookups concluded (seen all)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1197 +msgid "# Datastore lookups aborted (more than MAX_RESULTS)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1211 +msgid "# requested DBLOCK or IBLOCK not found" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1224 +msgid "# on-demand blocks matched requests" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1237 +msgid "# on-demand lookups performed successfully" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1242 +msgid "# on-demand lookups failed" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 +#: src/fs/gnunet-service-fs_pr.c:1447 +msgid "# Datastore lookups concluded (error queueing)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1327 +msgid "# Datastore lookups concluded (found last result)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1338 +msgid "# Datastore lookups concluded (load too high)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1424 +msgid "# Datastore lookups initiated" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1508 +#, fuzzy +msgid "# GAP PUT messages received" +msgstr "# các thông báo PONG đã mật mã được nhận" + +#: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 +#, fuzzy, c-format +msgid "Configuration fails to specify `%s', assuming default value." +msgstr "Tập tin cấu hình « %s » đã được ghi.\n" + +#: src/fs/gnunet-service-fs_push.c:629 +#, c-format +msgid "" +"Invalid value specified for option `%s' in section `%s', content pushing " +"disabled\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:89 +#, fuzzy, c-format +msgid "Unindexing at %llu/%llu (%s remaining)\n" +msgstr "Lá»—i bá» chỉ mục (không Ä‘Æ°a ra lý do)." + +#: src/fs/gnunet-unindex.c:96 +#, fuzzy, c-format +msgid "Error unindexing: %s.\n" +msgstr "" +"\n" +"Gặp lá»—i khi bá» chỉ mục tập tin: %s\n" + +#: src/fs/gnunet-unindex.c:101 +#, fuzzy +msgid "Unindexing done.\n" +msgstr "Bá» chỉ mục tập tin." + +#: src/fs/gnunet-unindex.c:131 +#, fuzzy, c-format +msgid "You must specify one and only one filename for unindexing.\n" +msgstr "Phải ghi rõ chỉ má»™t tên tập tin để chèn.\n" + +#: src/fs/gnunet-unindex.c:148 +#, fuzzy +msgid "Could not start unindex operation.\n" +msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" + +#: src/fs/gnunet-unindex.c:176 +msgid "Unindex a file that was previously indexed with gnunet-publish." +msgstr "" + +#: src/fs/plugin_block_fs.c:131 +msgid "Reply mismatched in terms of namespace. Discarded.\n" +msgstr "" + +#: src/gns/gns_api.c:221 +#, fuzzy +msgid "Failed to connect to the GNS service!\n" +msgstr "Lá»—i kết nối đến gnunetd.\n" + +#: src/gns/gnunet-gns-lookup.c:210 +msgid "Issue a request to the GNUnet Naming System, prints results." +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:264 +msgid "" +"None of the functions for the hostlist daemon were enabled. I have no " +"reason to run!\n" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:317 +#, fuzzy +msgid "advertise our hostlist to other peers" +msgstr "Tắt quảng cáo máy này cho đồng đẳng khác" + +#: src/hostlist/gnunet-daemon-hostlist.c:322 +msgid "" +"bootstrap using hostlists (it is highly recommended that you always use this " +"option)" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:325 +#, fuzzy +msgid "enable learning about hostlist servers from other peers" +msgstr "Tắt quảng cáo máy này cho đồng đẳng khác" + +#: src/hostlist/gnunet-daemon-hostlist.c:329 +#, fuzzy +msgid "provide a hostlist server" +msgstr "trình phục vụ danh sách máy HTTP hợp nhất" + +#: src/hostlist/gnunet-daemon-hostlist.c:341 +msgid "GNUnet hostlist server and client" +msgstr "" + +#: src/hostlist/hostlist-client.c:286 +#, fuzzy +msgid "# bytes downloaded from hostlist servers" +msgstr "trình phục vụ danh sách máy HTTP hợp nhất" + +#: src/hostlist/hostlist-client.c:307 src/hostlist/hostlist-client.c:339 +#, fuzzy +msgid "# invalid HELLOs downloaded from hostlist servers" +msgstr "# các HELLO tải xuống qua HTTP" + +#: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:342 +#, fuzzy, c-format +msgid "Invalid `%s' message received from hostlist at `%s'\n" +msgstr "Nhận được thông báo « %s » sai từ đồng đẳng « %s ».\n" + +#: src/hostlist/hostlist-client.c:330 +#, fuzzy +msgid "# valid HELLOs downloaded from hostlist servers" +msgstr "# các HELLO tải xuống qua HTTP" + +#: src/hostlist/hostlist-client.c:374 src/hostlist/hostlist-client.c:395 +#, fuzzy, c-format +msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" +msgstr "" +"ChÆ°a ghi rõ địa chỉ URL của danh sách các máy nên không nạp và khởi Ä‘á»™ng.\n" + +#: src/hostlist/hostlist-client.c:472 src/hostlist/hostlist-client.c:682 +#: src/hostlist/hostlist-client.c:688 src/hostlist/hostlist-client.c:740 +#: src/hostlist/hostlist-client.c:749 src/hostlist/hostlist-client.c:877 +#: src/hostlist/hostlist-client.c:967 src/hostlist/hostlist-client.c:972 +#: src/transport/plugin_transport_http_client.c:108 +#: src/transport/plugin_transport_http_client.c:123 +#, c-format +msgid "%s failed at %s:%d: `%s'\n" +msgstr "%s bị lá»—i tại %s:%d: « %s »\n" + +#: src/hostlist/hostlist-client.c:592 src/hostlist/hostlist-client.c:1342 +msgid "# advertised hostlist URIs" +msgstr "" + +#: src/hostlist/hostlist-client.c:622 +#, c-format +msgid "# advertised URI `%s' downloaded" +msgstr "" + +#: src/hostlist/hostlist-client.c:663 +#, c-format +msgid "" +"Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " +"gets dismissed.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:805 +#, fuzzy, c-format +msgid "Timeout trying to download hostlist from `%s'\n" +msgstr "Äang thá»­ tải danh sách các máy xuống « %s »\n" + +#: src/hostlist/hostlist-client.c:822 +#, c-format +msgid "Download limit of %u bytes exceeded, stopping download\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:842 +#, fuzzy, c-format +msgid "%s failed for `%s' at %s:%d: `%s'\n" +msgstr "%s bị lá»—i tại %s:%d: « %s »\n" + +#: src/hostlist/hostlist-client.c:848 +#, fuzzy, c-format +msgid "Download of hostlist `%s' completed.\n" +msgstr "Tải lên « %s » hoàn thành, địa chỉ URI là « %s ».\n" + +#: src/hostlist/hostlist-client.c:856 +#, c-format +msgid "Adding successfully tested hostlist `%s' datastore.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:909 +#, fuzzy, c-format +msgid "Bootstrapping using hostlist at `%s'.\n" +msgstr "Äang nạp và khởi Ä‘á»™ng dùng « %s ».\n" + +#: src/hostlist/hostlist-client.c:917 +msgid "# hostlist downloads initiated" +msgstr "" + +#: src/hostlist/hostlist-client.c:1045 src/hostlist/hostlist-client.c:1515 +msgid "# milliseconds between hostlist downloads" +msgstr "" + +#: src/hostlist/hostlist-client.c:1054 +#, c-format +msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1092 +msgid "Scheduled saving of hostlists\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1096 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1119 src/hostlist/hostlist-client.c:1135 +#, fuzzy +msgid "# active connections" +msgstr "# các kết nối dht" + +#: src/hostlist/hostlist-client.c:1253 +#, c-format +msgid "Initial time between hostlist downloads is %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1284 +#, fuzzy, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" +msgstr "" +"ChÆ°a ghi rõ địa chỉ URL của danh sách các máy nên không nạp và khởi Ä‘á»™ng.\n" + +#: src/hostlist/hostlist-client.c:1290 +#, fuzzy, c-format +msgid "Loading saved hostlist entries from file `%s' \n" +msgstr "Äang thá»­ tải danh sách các máy xuống « %s »\n" + +#: src/hostlist/hostlist-client.c:1294 +#, c-format +msgid "Hostlist file `%s' is not existing\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1305 +#, fuzzy, c-format +msgid "Could not open file `%s' for reading to load hostlists: %s\n" +msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" + +#: src/hostlist/hostlist-client.c:1338 +#, c-format +msgid "%u hostlist URIs loaded from file\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1340 +#, fuzzy +msgid "# hostlist URIs read from file" +msgstr "# các byte danh sách máy được trả vá»" + +#: src/hostlist/hostlist-client.c:1373 +#, fuzzy, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" +msgstr "" +"ChÆ°a ghi rõ địa chỉ URL của danh sách các máy nên không nạp và khởi Ä‘á»™ng.\n" + +#: src/hostlist/hostlist-client.c:1387 +#, fuzzy, c-format +msgid "Could not open file `%s' for writing to save hostlists: %s\n" +msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" + +#: src/hostlist/hostlist-client.c:1392 +#, fuzzy, c-format +msgid "Writing %u hostlist URIs to `%s'\n" +msgstr "Äang thá»­ tải danh sách các máy xuống « %s »\n" + +#: src/hostlist/hostlist-client.c:1416 src/hostlist/hostlist-client.c:1433 +#, c-format +msgid "Error writing hostlist URIs to file `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1428 +#, fuzzy +msgid "# hostlist URIs written to file" +msgstr "# các byte danh sách máy được trả vá»" + +#: src/hostlist/hostlist-client.c:1480 +msgid "Learning is enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1483 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1492 +msgid "Learning is not enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1504 +#, c-format +msgid "" +"Since learning is not enabled on this peer, hostlist file `%s' was removed\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1508 +#, fuzzy, c-format +msgid "Hostlist file `%s' could not be removed\n" +msgstr "Khoá phiên chạy từ đồng đẳng « %s » không thể được thẩm tra.\n" + +#: src/hostlist/hostlist-server.c:134 +#, fuzzy +msgid "bytes in hostlist" +msgstr "# các byte trong kho dữ liệu" + +#: src/hostlist/hostlist-server.c:157 +msgid "expired addresses encountered" +msgstr "" + +#: src/hostlist/hostlist-server.c:184 +#: src/topology/gnunet-daemon-topology.c:875 +#, fuzzy, c-format +msgid "Error in communication with PEERINFO service: %s\n" +msgstr "Cổng để liên lạc vá»›i giao diện ngÆ°á»i dùng GNUnet" + +#: src/hostlist/hostlist-server.c:205 +msgid "HELLOs without addresses encountered (ignored)" +msgstr "" + +#: src/hostlist/hostlist-server.c:221 +msgid "bytes not included in hostlist (size limit)" +msgstr "" + +#: src/hostlist/hostlist-server.c:269 +#, fuzzy, c-format +msgid "Refusing `%s' request to hostlist server\n" +msgstr "trình phục vụ danh sách máy HTTP hợp nhất" + +#: src/hostlist/hostlist-server.c:272 +#, fuzzy +msgid "hostlist requests refused (not HTTP GET)" +msgstr "# các yêu cầu danh sách máy được nhận" + +#: src/hostlist/hostlist-server.c:280 +msgid "Sending 100 CONTINUE reply\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:287 +#, c-format +msgid "Refusing `%s' request with %llu bytes of upload data\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:291 +#, fuzzy +msgid "hostlist requests refused (upload data)" +msgstr "# các yêu cầu danh sách máy được nhận" + +#: src/hostlist/hostlist-server.c:299 +msgid "Could not handle hostlist request since I do not have a response yet\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:302 +#, fuzzy +msgid "hostlist requests refused (not ready)" +msgstr "# các yêu cầu danh sách máy được nhận" + +#: src/hostlist/hostlist-server.c:306 +#, fuzzy +msgid "Received request for our hostlist\n" +msgstr "Nhận yêu cầu định tuyến\n" + +#: src/hostlist/hostlist-server.c:307 +#, fuzzy +msgid "hostlist requests processed" +msgstr "# các yêu cầu danh sách máy được nhận" + +#: src/hostlist/hostlist-server.c:350 +#, fuzzy +msgid "# hostlist advertisements send" +msgstr "# Các quảng cáo ngoại được chuyển tiếp" + +#: src/hostlist/hostlist-server.c:397 +msgid "Advertisement message could not be queued by core\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:565 +#, c-format +msgid "Invalid port number %llu. Exiting.\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:574 +#, c-format +msgid "Hostlist service starts on %s:%llu\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:588 +#, fuzzy, c-format +msgid "Address to obtain hostlist: `%s'\n" +msgstr "Äang thá»­ tải danh sách các máy xuống « %s »\n" + +#: src/hostlist/hostlist-server.c:626 +#, fuzzy, c-format +msgid "Could not start hostlist HTTP server on port %u\n" +msgstr "Cổng cho trình phục vụ HTTP danh sách máy chủ thống nhất" + +#: src/mesh/gnunet-service-mesh.c:4595 +msgid "Wrong CORE service\n" +msgstr "" + +#: src/mesh/gnunet-service-mesh.c:4789 +#, fuzzy +msgid "Mesh service is lacking key configuration settings. Exiting.\n" +msgstr "LÆ°u cấu hình ngay bây giá» không?" + +#: src/mesh/gnunet-service-mesh.c:4798 +#, fuzzy +msgid "Mesh service could not access hostkey. Exiting.\n" +msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" + +#: src/namestore/namestore_api.c:272 src/namestore/namestore_api.c:313 +msgid "Namestore added record successfully" +msgstr "" + +#: src/namestore/namestore_api.c:281 src/namestore/namestore_api.c:322 +msgid "Namestore failed to add record" +msgstr "" + +#: src/nat/gnunet-nat-server.c:289 +#, c-format +msgid "Please pass valid port number as the first argument! (got `%s')\n" +msgstr "" + +#: src/nat/gnunet-nat-server.c:328 +msgid "GNUnet NAT traversal test helper daemon" +msgstr "" + +#: src/nat/nat.c:803 +#, c-format +msgid "gnunet-helper-nat-server generated malformed address `%s'\n" +msgstr "" + +#: src/nat/nat.c:852 +#, fuzzy, c-format +msgid "Failed to start %s\n" +msgstr "Lá»—i bắt đầu thu thập.\n" + +#: src/nat/nat.c:1121 +#, fuzzy, c-format +msgid "Malformed %s `%s' given in configuration!\n" +msgstr "Lá»—i lÆ°u cấu hình." + +#: src/nat/nat.c:1187 src/nat/nat.c:1197 +#, c-format +msgid "" +"Configuration requires `%s', but binary is not installed properly (SUID bit " +"not set). Option disabled.\n" +msgstr "" + +#: src/nat/nat.c:1329 +msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" +msgstr "" + +#: src/nat/nat.c:1341 +#, c-format +msgid "Running gnunet-helper-nat-client %s %s %u\n" +msgstr "" + +#: src/nat/nat_test.c:348 +#, fuzzy +msgid "Failed to connect to `gnunet-nat-server'\n" +msgstr "Lá»—i kết nối đến gnunetd.\n" + +#: src/nat/nat_test.c:418 +#, c-format +msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" +msgstr "" + +#: src/nse/gnunet-nse-profiler.c:926 +#, fuzzy +msgid "Measure quality and performance of the NSE service." +msgstr "Không thể truy cập đến dịch vụ" + +#: src/nse/gnunet-service-nse.c:936 +#, c-format +msgid "Proof of work invalid: %llu!\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1391 src/nse/gnunet-service-nse.c:1410 +#: src/nse/gnunet-service-nse.c:1431 +msgid "NSE service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1398 +msgid "Invalid work requirement for NSE service. Exiting.\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1419 +#, fuzzy +msgid "NSE service could not access hostkey. Exiting.\n" +msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:133 +#, fuzzy, c-format +msgid "Removing expired address of transport `%s'\n" +msgstr "Äã nạp truyá»n tải « %s »\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:195 +msgid "# peers known" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:239 +#, c-format +msgid "" +"File `%s' in directory `%s' does not match naming convention. Removed.\n" +msgstr "" +"Tập tin « %s » trong thÆ° mục « %s » không tùy theo quy Æ°á»›c đặt tên. Bị gỡ " +"bá».\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:305 +#, c-format +msgid "Still no peers found in `%s'!\n" +msgstr "Vẫn còn không tìm thấy đồng đẳng trong « %s ».\n" + +#: src/peerinfo/peerinfo_api.c:279 +#, fuzzy, c-format +msgid "Failed to transmit message to `%s' service.\n" +msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" + +#: src/peerinfo/peerinfo_api.c:435 +#, fuzzy +msgid "Failed to receive response from `PEERINFO' service." +msgstr "" +"\n" +"Không nhận được đáp ứng từ gnunetd.\n" + +#: src/peerinfo/peerinfo_api.c:463 src/peerinfo/peerinfo_api.c:481 +msgid "Received invalid message from `PEERINFO' service.\n" +msgstr "" + +#: src/peerinfo/peerinfo_api.c:523 +#, fuzzy +msgid "Failed to transmit iteration request to `PEERINFO' service\n" +msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" + +#: src/peerinfo/peerinfo_api.c:557 +msgid "Timeout transmitting iteration request to `PEERINFO' service.\n" +msgstr "" + +#: src/peerinfo/peerinfo_api_notify.c:258 +#, fuzzy, c-format +msgid "Could not connect to `%s' service.\n" +msgstr "Không thể kết nối tá»›i %s:%u: %s\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:216 +#, fuzzy, c-format +msgid "Could not find option `%s:%s' in configuration.\n" +msgstr "Không tìm thấy phÆ°Æ¡ng pháp « %s%s » trong thÆ° viện « %s ».\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:223 +#, c-format +msgid "Loading hostkey from `%s' failed.\n" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:235 +#, c-format +msgid "I am peer `%s'.\n" +msgstr "Tôi là đồng đẳng « %s ».\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:255 +msgid "output only the identity strings" +msgstr "chỉ xuất những chuá»—i nhận diện" + +#: src/peerinfo-tool/gnunet-peerinfo.c:258 +msgid "output our own identity only" +msgstr "chỉ xuất nhận diện mình" + +#: src/peerinfo-tool/gnunet-peerinfo.c:264 +#, fuzzy +msgid "Print information about peers." +msgstr "In ra thông tin vá» các đồng đẳng GNUnet." + +#: src/pt/gnunet-daemon-pt.c:264 +msgid "Failed to pack DNS request. Dropping.\n" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:270 +#, fuzzy +msgid "# DNS requests mapped to VPN" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/pt/gnunet-daemon-pt.c:323 +msgid "# DNS records modified" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:500 +#, fuzzy +msgid "# DNS replies intercepted" +msgstr "# các đáp ứng dht được định tuyến" + +#: src/pt/gnunet-daemon-pt.c:506 +msgid "Failed to parse DNS request. Dropping.\n" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:602 +#, fuzzy +msgid "# DNS requests dropped (timeout)" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/pt/gnunet-daemon-pt.c:632 +#, fuzzy +msgid "# DNS requests intercepted" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/pt/gnunet-daemon-pt.c:637 +#, fuzzy +msgid "# DNS requests dropped (DNS mesh tunnel down)" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/pt/gnunet-daemon-pt.c:645 +#, fuzzy +msgid "# DNS requests dropped (malformed)" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/pt/gnunet-daemon-pt.c:716 +#, fuzzy +msgid "# DNS replies received" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/pt/gnunet-daemon-pt.c:730 +#, fuzzy +msgid "# DNS replies dropped (too late?)" +msgstr "# các đáp ứng dht được định tuyến" + +#: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 +msgid "# DNS requests aborted (tunnel down)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 +#: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 +#, fuzzy, c-format +msgid "Failed to connect to %s service. Exiting.\n" +msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" + +#: src/pt/gnunet-daemon-pt.c:973 +msgid "Daemon to run to perform IP protocol translation to GNUnet" +msgstr "" + +#: src/statistics/gnunet-service-statistics.c:209 +#, fuzzy, c-format +msgid "Loading %llu bytes of statistics from `%s'\n" +msgstr "Äã tải %llu byte xuống « %s ».\n" + +#: src/statistics/gnunet-service-statistics.c:267 +#, fuzzy, c-format +msgid "Wrote %llu bytes of statistics to `%s'\n" +msgstr "Äã tải %llu byte xuống « %s ».\n" + +#: src/statistics/gnunet-statistics.c:98 +#, fuzzy +msgid "Failed to obtain statistics.\n" +msgstr "Lá»—i lấy thông kê vá» truyá»n tải.\n" + +#: src/statistics/gnunet-statistics.c:164 +msgid "limit output to statistics for the given NAME" +msgstr "" + +#: src/statistics/gnunet-statistics.c:167 +msgid "make the value being set persistent" +msgstr "" + +#: src/statistics/gnunet-statistics.c:170 +msgid "limit output to the given SUBSYSTEM" +msgstr "" + +#: src/statistics/gnunet-statistics.c:173 +msgid "just print the statistics value" +msgstr "" + +#: src/statistics/gnunet-statistics.c:180 +msgid "Print statistics about GNUnet operations." +msgstr "In ra thống kê vá» các thao tác GNUnet." + +#: src/statistics/statistics_api.c:390 +#, fuzzy +msgid "Failed to connect to statistics service!\n" +msgstr "Lá»—i kết nối đến gnunetd.\n" + +#: src/template/gnunet-template.c:68 +msgid "help text" +msgstr "" + +#: src/testing/gnunet-testing.c:157 +#, fuzzy +msgid "Could not read hostkeys file, specify hostkey file with -H!\n" +msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" + +#: src/testing/gnunet-testing.c:159 +#, c-format +msgid "Specified hostkey file `%s' not found!\n" +msgstr "" + +#: src/testing/gnunet-testing.c:273 +#, fuzzy +msgid "create unique configuration files" +msgstr "cập nhật má»™t giá trị trong tập tin cấu hình" + +#: src/testing/gnunet-testing.c:275 +msgid "create hostkey files from pre-computed hostkey list" +msgstr "" + +#: src/testing/gnunet-testing.c:277 +msgid "host key file" +msgstr "" + +#: src/testing/gnunet-testing.c:279 +#, fuzzy +msgid "number of unique configuration files or hostkeys to create" +msgstr "in ra đầu ra tiêu chuẩn má»™t giá trị từ tập tin cấu hình" + +#: src/testing/gnunet-testing.c:281 +#, fuzzy +msgid "configuration template" +msgstr "Cấu hình đã được lÆ°u." + +#: src/testing/gnunet-testing.c:287 +msgid "Command line tool to access the testing library" +msgstr "" + +#: src/testing/helper.c:56 +#, fuzzy +msgid "Peer is lacking HOSTKEY configuration setting.\n" +msgstr "LÆ°u cấu hình ngay bây giá» không?" + +#: src/testing/helper.c:64 +#, fuzzy +msgid "Could not access hostkey.\n" +msgstr "Không thể truy cập đến tập tin gnunet-directory « %s »\n" + +#: src/testing/testing.c:204 +msgid "`scp' does not seem to terminate (timeout copying config).\n" +msgstr "" + +#: src/testing/testing.c:218 src/testing/testing.c:808 +#, fuzzy +msgid "`scp' did not complete cleanly.\n" +msgstr "« %s » không phải được kết nối tá»›i đồng đẳng nào.\n" + +#: src/testing/testing.c:239 +#, fuzzy +msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" +msgstr "Lá»—i bắt đầu thu thập.\n" + +#: src/testing/testing.c:240 +#, fuzzy +msgid "Failed to create pipe for `ssh' process.\n" +msgstr "Lá»—i tạo thÆ° mục tạm thá»i." + +#: src/testing/testing.c:292 +#, fuzzy, c-format +msgid "Could not start `%s' process to create hostkey.\n" +msgstr "Lá»—i bắt đầu thu thập.\n" + +#: src/testing/testing.c:299 +#, fuzzy +msgid "Failed to start `gnunet-peerinfo' process.\n" +msgstr "Lá»—i bắt đầu thu thập.\n" + +#: src/testing/testing.c:300 src/testing/testing.c:488 +#, fuzzy +msgid "Failed to start `ssh' process.\n" +msgstr "Lá»—i bắt đầu thu thập.\n" + +#: src/testing/testing.c:360 +#, fuzzy, c-format +msgid "Error reading from gnunet-peerinfo: %s\n" +msgstr "Gặp lá»—i khi Ä‘á»c thông tin từ gnunetd.\n" + +#: src/testing/testing.c:364 +#, fuzzy +msgid "Malformed output from gnunet-peerinfo!\n" +msgstr "Gặp lá»—i khi Ä‘á»c thông tin từ gnunetd.\n" + +#: src/testing/testing.c:374 +#, fuzzy +msgid "Failed to get hostkey!\n" +msgstr "Lá»—i lấy thông kê vá» truyá»n tải.\n" + +#: src/testing/testing.c:406 +msgid "`Failed while waiting for topology setup!\n" +msgstr "" + +#: src/testing/testing.c:480 +#, fuzzy, c-format +msgid "Could not start `%s' process to start GNUnet.\n" +msgstr "Không thể tạo miá»n tên.\n" + +#: src/testing/testing.c:487 +#, fuzzy +msgid "Failed to start `gnunet-arm' process.\n" +msgstr "Lá»—i dừng chạy gnunet-auto-share.\n" + +#: src/testing/testing.c:509 src/testing/testing.c:612 +msgid "`gnunet-arm' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:510 src/testing/testing.c:613 +#: src/testing/testing.c:633 +msgid "`ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:582 +msgid "Unable to get HELLO for peer!\n" +msgstr "" + +#: src/testing/testing.c:632 +msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" +msgstr "" + +#: src/testing/testing.c:653 src/testing/testing.c:685 +msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:668 src/testing/testing.c:723 +#, fuzzy +msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" +msgstr "« %s » không phải được kết nối tá»›i đồng đẳng nào.\n" + +#: src/testing/testing.c:796 +msgid "`scp' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:966 +#, fuzzy, c-format +msgid "Starting service %s for peer `%4s'\n" +msgstr "Äang bắt đầu tài vỠ« %s »\n" + +#: src/testing/testing.c:1237 src/testing/testing_group.c:6278 +#, fuzzy, c-format +msgid "Could not start `%s' process to copy configuration directory.\n" +msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" + +#: src/testing/testing.c:1322 src/testing/testing.c:1397 +#, fuzzy, c-format +msgid "Terminating peer `%4s'\n" +msgstr "Không đủ quyá»n cho « %s ».\n" + +#: src/testing/testing.c:1480 +#, fuzzy, c-format +msgid "Setting d->dead on peer `%4s'\n" +msgstr "Äang bắt đầu tài lên « %s ».\n" + +#: src/testing/testing.c:1610 +msgid "Peer not yet running, can not change configuration at this point." +msgstr "" + +#: src/testing/testing.c:1618 +#, fuzzy +msgid "Failed to write new configuration to disk." +msgstr "Lá»—i lÆ°u cấu hình." + +#: src/testing/testing.c:1647 +#, fuzzy, c-format +msgid "Could not start `%s' process to copy configuration file.\n" +msgstr "Không tìm thấy phÆ°Æ¡ng pháp « %s%s » trong thÆ° viện « %s ».\n" + +#: src/testing/testing.c:1650 +#, fuzzy +msgid "Failed to copy new configuration to remote machine." +msgstr "Lá»—i lÆ°u cấu hình." + +#: src/testing/testing.c:1805 +#, fuzzy +msgid "Peers failed to connect" +msgstr "Không kết nối được đến trình ná»n gnunetd." + +#: src/testing/testing.c:1933 +#, fuzzy +msgid "Failed to connect to core service of first peer!\n" +msgstr "Lá»—i nạp dịch vụ sqstore. Hãy kiểm tra lại cấu hình.\n" + +#: src/testing/testing.c:2156 +msgid "Peers are not fully running yet, can not connect!\n" +msgstr "" + +#: src/testing/testing_group.c:1910 src/testing/testing_group.c:1922 +#: src/testing/testing_group.c:2023 src/testing/testing_group.c:2082 +#: src/testing/testing_group.c:2171 src/testing/testing_group.c:2191 +#: src/testing/testing_group.c:2328 src/testing/testing_peergroup.c:940 +#, fuzzy, c-format +msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" +msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" + +#: src/testing/testing_group.c:1932 +#, fuzzy, c-format +msgid "Target is %d connections per peer." +msgstr "Lá»—i thiết lập kết nối vá»›i đồng đẳng.\n" + +#: src/testing/testing_group.c:2179 +#, fuzzy, c-format +msgid "" +"Invalid value `%s' for option `%s' in section `%s': got %f, needed value " +"greater than 0\n" +msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" + +#: src/testing/testing_group.c:2209 src/testing/testing_group.c:2402 +#, c-format +msgid "Connecting nodes in 2d torus topology: %u rows %u columns\n" +msgstr "" +"Äang kết nối các Ä‘iểm nút theo địa hình há»c hình xuyến hai chiá»u: %u hàng, " +"%u cá»™t\n" + +#: src/testing/testing_group.c:2246 +#, c-format +msgid "natural log of %d is %d, will run %d iterations\n" +msgstr "" + +#: src/testing/testing_group.c:2249 +#, c-format +msgid "Total connections added thus far: %u!\n" +msgstr "" + +#: src/testing/testing_group.c:2290 +#, c-format +msgid "Total connections added for small world: %d!\n" +msgstr "" + +#: src/testing/testing_group.c:2342 +#, c-format +msgid "rand is %f probability is %f\n" +msgstr "" + +#: src/testing/testing_group.c:2919 src/testing/testing_group.c:3118 +#, fuzzy, c-format +msgid "" +"No `%s' specified in peer configuration in section `%s', cannot copy friends " +"file!\n" +msgstr "" +"Äặc tả mạng dạng sai trong cấu hình phần « %s » cho mục nhập « %s »: %s\n" + +#: src/testing/testing_group.c:3020 +msgid "Finished copying all friend files!\n" +msgstr "" + +#: src/testing/testing_group.c:3133 +#, fuzzy, c-format +msgid "Copying file with command cp %s %s\n" +msgstr "« %s » thất bại vá»›i mã lá»—i %s: %s\n" + +#: src/testing/testing_group.c:3156 +#, fuzzy, c-format +msgid "Copying file with command scp %s %s\n" +msgstr "« %s » thất bại vá»›i mã lá»—i %s: %s\n" + +#: src/testing/testing_group.c:3173 +#, c-format +msgid "Checking copy status of file %d\n" +msgstr "" + +#: src/testing/testing_group.c:3191 +#, c-format +msgid "File %d copied\n" +msgstr "" + +#: src/testing/testing_group.c:3206 +#, fuzzy +msgid "Finished copying all blacklist files!\n" +msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" + +#: src/testing/testing_group.c:3586 src/testing/testing_group.c:3723 +#: src/testing/testing_group.c:4884 src/testing/testing_group.c:5025 +msgid "Delaying connect, we have too many outstanding connections!\n" +msgstr "" + +#: src/testing/testing_group.c:3596 src/testing/testing_group.c:4894 +#: src/testing/testing_group.c:5035 +#, c-format +msgid "Creating connection, outstanding_connections is %d\n" +msgstr "" + +#: src/testing/testing_group.c:3608 +#, fuzzy, c-format +msgid "Offering HELLO of peer %s to peer %s\n" +msgstr "Ä‘ang kết nối đồng đẳng %s:%d tá»›i đồng đẳng %s:%d\n" + +#: src/testing/testing_group.c:3734 +#, c-format +msgid "Creating connection, outstanding_connections is %d (max %d)\n" +msgstr "" + +#: src/testing/testing_group.c:3988 +msgid "Creating clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:3993 +msgid "Creating small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:3998 +msgid "Creating small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4002 +msgid "Creating ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4006 +msgid "Creating 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4010 +msgid "Creating Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4014 +msgid "Creating InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4018 +msgid "Creating Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4023 +msgid "Creating straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4027 +msgid "Creating topology from file!\n" +msgstr "" + +#: src/testing/testing_group.c:4043 +msgid "Creating no allowed topology (all peers can connect at core level)\n" +msgstr "" + +#: src/testing/testing_group.c:4058 +msgid "Failed during friend file copying!\n" +msgstr "" + +#: src/testing/testing_group.c:4064 +msgid "Friend files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:4081 +msgid "Blacklisting all but clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:4087 +msgid "Blacklisting all but small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4093 +msgid "Blacklisting all but small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4099 +msgid "Blacklisting all but ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4105 +msgid "Blacklisting all but 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4111 +msgid "Blacklisting all but Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4117 +msgid "Blacklisting all but InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4152 +msgid "Blacklisting all but Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4158 +msgid "Blacklisting all but straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4173 +#, fuzzy +msgid "Failed during blacklist file copying!\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/testing/testing_group.c:4179 +msgid "Blacklist files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:5263 +msgid "Creating clique CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5270 +msgid "Creating small world (ring) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5277 +msgid "Creating small world (2d-torus) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5283 +msgid "Creating ring CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5290 +msgid "Creating 2d torus CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5297 +msgid "Creating Erdos-Renyi CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5304 +msgid "Creating InterNAT CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5311 +msgid "Creating Scale Free CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5318 +msgid "Creating straight line CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5324 +msgid "Creating no CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5330 +#, fuzzy +msgid "Unknown topology specification, can't connect peers!\n" +msgstr "Lá»—i cú pháp trong sá»± xác định địa hình há»c, Ä‘ang bá» qua các byte.\n" + +#: src/testing/testing_group.c:5340 +#, c-format +msgid "Connecting random subset (%'.2f percent) of possible peers\n" +msgstr "" + +#: src/testing/testing_group.c:5348 +#, c-format +msgid "Connecting a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5357 +#, c-format +msgid "Using DFS to connect a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5367 +#, c-format +msgid "Finding additional %u closest peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:6062 src/transport/transport-testing.c:650 +#, fuzzy +msgid "Could not read hostkeys file!\n" +msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" + +#: src/testing/testing_group.c:6131 +#, fuzzy, c-format +msgid "Could not create configuration for peer number %u on `%s'!\n" +msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" + +#: src/topology/gnunet-daemon-topology.c:244 +msgid "# peers blacklisted" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:380 +#, fuzzy +msgid "# connect requests issued to transport" +msgstr "# các yêu cầu máy/trình khách lá»— hổng được phun vào" + +#: src/topology/gnunet-daemon-topology.c:675 +#: src/topology/gnunet-daemon-topology.c:761 +#, fuzzy +msgid "# friends connected" +msgstr "# của các đồng đẳng đã kết nối" + +#: src/topology/gnunet-daemon-topology.c:950 +msgid "Failed to connect to core service, can not manage topology!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:982 +#, fuzzy, c-format +msgid "Option `%s' in section `%s' not specified!\n" +msgstr "Bị từ chối đặt tùy chá»n « %s » trong phần « %s » thành « %s ».\n" + +#: src/topology/gnunet-daemon-topology.c:994 +#, c-format +msgid "Could not read friends list `%s'\n" +msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" + +#: src/topology/gnunet-daemon-topology.c:1000 +#, fuzzy, c-format +msgid "Friends file `%s' is empty.\n" +msgstr "Äịnh dạng của tập tin « %s » là không hợp lệ.\n" + +#: src/topology/gnunet-daemon-topology.c:1009 +#, fuzzy, c-format +msgid "Failed to read friends list from `%s': out of memory\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/topology/gnunet-daemon-topology.c:1017 +#, c-format +msgid "Failed to read friends list from `%s'\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/topology/gnunet-daemon-topology.c:1037 +#, fuzzy, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes.\n" +msgstr "Lá»—i cú pháp trong sá»± xác định địa hình há»c, Ä‘ang bá» qua các byte.\n" + +#: src/topology/gnunet-daemon-topology.c:1050 +#, fuzzy, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" +msgstr "" +"Lá»—i cú pháp trong sá»± xác định địa hình há»c, Ä‘ang bá» qua các byte « %s ».\n" + +#: src/topology/gnunet-daemon-topology.c:1060 +#, fuzzy, c-format +msgid "Found friend `%s' in configuration\n" +msgstr "" +"\n" +"Kết thúc cấu hình.\n" + +#: src/topology/gnunet-daemon-topology.c:1066 +#, c-format +msgid "Found myself `%s' in friend list (useless, ignored)\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1076 +#, fuzzy +msgid "# friends in configuration" +msgstr "" +"\n" +"Kết thúc cấu hình.\n" + +#: src/topology/gnunet-daemon-topology.c:1082 +msgid "" +"Fewer friends specified than required by minimum friend count. Will only " +"connect to friends.\n" +msgstr "" +"Xác định quá ít bạn bè (dÆ°á»›i số tối thiểu). Sẽ chỉ kết nối tá»›i bạn bè.\n" + +#: src/topology/gnunet-daemon-topology.c:1089 +msgid "" +"More friendly connections required than target total number of connections.\n" +msgstr "Cần thiết nhiá»u kết nối bạn bè hÆ¡n tổng số kết nối đích.\n" + +#: src/topology/gnunet-daemon-topology.c:1126 +#, fuzzy +msgid "# HELLO messages received" +msgstr "# các thông báo PONG đã mật mã được nhận" + +#: src/topology/gnunet-daemon-topology.c:1183 +#, fuzzy +msgid "# HELLO messages gossipped" +msgstr "# các thông báo gá»­i Ä‘i bị loại bá»" + +#: src/topology/gnunet-daemon-topology.c:1323 +msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:247 +#, fuzzy, c-format +msgid "Could not read blacklist file `%s'\n" +msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" + +#: src/transport/gnunet-service-transport_blacklist.c:254 +#, c-format +msgid "Blacklist file `%s' is empty.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:266 +#, fuzzy, c-format +msgid "Failed to read blacklist from `%s'\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/transport/gnunet-service-transport_blacklist.c:287 +#: src/transport/gnunet-service-transport_blacklist.c:311 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, giving up!\n" +msgstr "Gặp lá»—i cú pháp trong tập tin cấu hình « %s » tại dòng %d.\n" + +#: src/transport/gnunet-service-transport_blacklist.c:298 +#: src/transport/gnunet-service-transport_blacklist.c:336 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" +msgstr "Lá»—i cú pháp trong sá»± xác định địa hình há»c, Ä‘ang bá» qua các byte.\n" + +#: src/transport/gnunet-service-transport_blacklist.c:350 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" +msgstr "" +"Lá»—i cú pháp trong sá»± xác định địa hình há»c, Ä‘ang bá» qua các byte « %s ».\n" + +#: src/transport/gnunet-service-transport_blacklist.c:364 +#, c-format +msgid "Found myself `%s' in blacklist (useless, ignored)\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:523 +#: src/transport/gnunet-service-transport_blacklist.c:764 +msgid "# disconnects due to blacklist" +msgstr "" + +#: src/transport/gnunet-service-transport.c:158 +#, fuzzy +msgid "# bytes payload discarded due to not connected peer " +msgstr "# Các quảng cáo đồng đẳng bị hủy do trá»ng tải" + +#: src/transport/gnunet-service-transport.c:572 +msgid "Transport service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport.c:581 +msgid "Transport service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:353 +#, c-format +msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:358 +#, fuzzy +msgid "# messages dropped due to slow client" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/transport/gnunet-service-transport_clients.c:510 +#, c-format +msgid "Rejecting control connection from peer `%s', which is not me!\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:628 +#, fuzzy +msgid "# bytes payload received for other peers" +msgstr "# các byte kiểu %d được nhận" + +#: src/transport/gnunet-service-transport_clients.c:645 +msgid "# bytes payload dropped (other peer was not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:696 +#, fuzzy +msgid "# REQUEST CONNECT messages received" +msgstr "# các thông báo PONG đã mật mã được nhận" + +#: src/transport/gnunet-service-transport_hello.c:172 +msgid "# refreshed my HELLO" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:482 +msgid "# failed connection attempts due to timeout" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:883 +#, fuzzy +msgid "# peers disconnected due to external request" +msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" + +#: src/transport/gnunet-service-transport_neighbours.c:966 +#, fuzzy +msgid "# fast reconnects failed" +msgstr "# của các đồng đẳng đã kết nối" + +#: src/transport/gnunet-service-transport_neighbours.c:1022 +#, fuzzy +msgid "# peers disconnected due to timeout" +msgstr "# các kết nối bị đóng (vấn Ä‘á» truyá»n tải)" + +#: src/transport/gnunet-service-transport_neighbours.c:1047 +#, fuzzy +msgid "# keepalives sent" +msgstr "# các khoá phiên chạy được gá»­i" + +#: src/transport/gnunet-service-transport_neighbours.c:1088 +#, fuzzy +msgid "# peers disconnected due to global disconnect" +msgstr "# Các quảng cáo đồng đẳng bị hủy do trá»ng tải" + +#: src/transport/gnunet-service-transport_neighbours.c:1888 +#: src/transport/gnunet-service-transport_neighbours.c:1909 +#, fuzzy +msgid "# messages not sent (no such peer or not connected)" +msgstr "# các thông báo được chắp liá»n" + +#: src/transport/gnunet-service-transport_neighbours.c:1925 +#, fuzzy +msgid "# bytes in message queue for other peers" +msgstr "# các byte thông báo gá»­i Ä‘i bị loại bá»" + +#: src/transport/gnunet-service-transport_neighbours.c:1977 +#, fuzzy +msgid "# messages discarded due to lack of neighbour record" +msgstr "# các thông báo được chắp liá»n" + +#: src/transport/gnunet-service-transport_neighbours.c:2013 +#, fuzzy +msgid "# bandwidth quota violations by other peers" +msgstr "theo dõi gnunetd sá»­ dụng dải thông" + +#: src/transport/gnunet-service-transport_neighbours.c:2031 +msgid "# ms throttling suggested" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2060 +#, fuzzy +msgid "# KEEPALIVE messages discarded (not connected)" +msgstr "# các thông báo được chắp liá»n" + +#: src/transport/gnunet-service-transport_neighbours.c:2113 +#, fuzzy +msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" +msgstr "# các thông báo được chắp liá»n" + +#: src/transport/gnunet-service-transport_neighbours.c:2121 +#, fuzzy +msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" +msgstr "# các thông báo được chắp liá»n" + +#: src/transport/gnunet-service-transport_neighbours.c:2187 +msgid "# SET QUOTA messages ignored (no such peer)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2205 +msgid "# disconnects due to quota of 0" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2323 +msgid "# disconnect messages ignored (old format)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2336 +msgid "# disconnect messages ignored (timestamp)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2411 +#, fuzzy +msgid "# unexpected CONNECT_ACK messages (no peer)" +msgstr "gá»­i ÄẾM thông báo" + +#: src/transport/gnunet-service-transport_neighbours.c:2453 +#, fuzzy +msgid "# unexpected CONNECT_ACK messages" +msgstr "gá»­i ÄẾM thông báo" + +#: src/transport/gnunet-service-transport_neighbours.c:2544 +#, fuzzy +msgid "# unexpected ACK messages" +msgstr "# các thông báo PONG đã mật mã được gá»­i" + +#: src/transport/gnunet-service-transport_plugins.c:111 +msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:118 +#, fuzzy, c-format +msgid "Starting transport plugins `%s'\n" +msgstr "Äang nạp các truyá»n tải « %s »\n" + +#: src/transport/gnunet-service-transport_plugins.c:122 +#, fuzzy, c-format +msgid "Loading `%s' transport plugin\n" +msgstr "Äang nạp các truyá»n tải « %s »\n" + +#: src/transport/gnunet-service-transport_plugins.c:150 +#, fuzzy, c-format +msgid "Failed to load transport plugin for `%s'\n" +msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" + +#: src/transport/gnunet-service-transport_validation.c:410 +msgid "# address records discarded" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:459 +#, c-format +msgid "" +"Not transmitting `%s' with `%s', message too big (%u bytes!). This should " +"not happen.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:508 +#, fuzzy +msgid "# PING without HELLO messages sent" +msgstr "# các thông báo PONG nhập thô được gá»­i" + +#: src/transport/gnunet-service-transport_validation.c:566 +msgid "# address revalidations started" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:798 +#, fuzzy +msgid "# PING message for different peer received" +msgstr "# các thông báo PING được tạo" + +#: src/transport/gnunet-service-transport_validation.c:833 +#, c-format +msgid "" +"Not confirming PING with address `%s' since I cannot confirm having this " +"address.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:919 +msgid "# PONGs unicast via reliable transport" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:928 +msgid "# PONGs multicast to all available addresses" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1050 +msgid "# PONGs dropped, no matching pending validation" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1075 +msgid "# PONGs dropped, signature expired" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1134 +#, fuzzy, c-format +msgid "Adding `%s' without addresses for peer `%s'\n" +msgstr "Không thể lấy địa chỉ của đồng đẳng « %s ».\n" + +#: src/transport/gnunet-transport.c:256 +msgid "No transport plugins configured, peer will never communicate\n" +msgstr "" + +#: src/transport/gnunet-transport.c:269 +#, c-format +msgid "No port configured for plugin `%s', cannot test it\n" +msgstr "" + +#: src/transport/gnunet-transport.c:319 +#, c-format +msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:326 +#, c-format +msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:359 +#, fuzzy, c-format +msgid "Transmitting %u bytes to %s\n" +msgstr "Äang thá»­ tải danh sách các máy xuống « %s »\n" + +#: src/transport/gnunet-transport.c:379 +#, fuzzy, c-format +msgid "Connected to %s\n" +msgstr "« %s » được kết nối tá»›i « %s ».\n" + +#: src/transport/gnunet-transport.c:410 +#, fuzzy, c-format +msgid "Disconnected from %s\n" +msgstr "« %.*s » được kết nối tá»›i « %.*s ».\n" + +#: src/transport/gnunet-transport.c:439 +#, fuzzy, c-format +msgid "Received %u bytes from %s\n" +msgstr "Nhận yêu cầu định tuyến\n" + +#: src/transport/gnunet-transport.c:453 +#, fuzzy, c-format +msgid "Peer `%s': %s %s\n" +msgstr "Tôi là đồng đẳng « %s ».\n" + +#: src/transport/gnunet-transport.c:483 +#, fuzzy, c-format +msgid "Peer `%s' disconnected\n" +msgstr "# của các đồng đẳng đã kết nối" + +#: src/transport/gnunet-transport.c:539 +#, fuzzy, c-format +msgid "Failed to parse peer identity `%s'\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/transport/gnunet-transport.c:587 +msgid "measure how fast we are receiving data (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:590 +#, fuzzy +msgid "try to connect to the given peer" +msgstr "Lá»—i kết nối đến gnunetd.\n" + +#: src/transport/gnunet-transport.c:593 +#, fuzzy +msgid "provide information about all current connections (once)" +msgstr "In ra thông tin vá» các đồng đẳng GNUnet." + +#: src/transport/gnunet-transport.c:596 +#, fuzzy +msgid "provide information about all current connections (continuously)" +msgstr "In ra thông tin vá» các đồng đẳng GNUnet." + +#: src/transport/gnunet-transport.c:599 +#, fuzzy +msgid "do not resolve hostnames" +msgstr "không quyết định các tên máy" + +#: src/transport/gnunet-transport.c:603 +msgid "send data for benchmarking to the other peer (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:606 +msgid "test transport configuration (involves external server)" +msgstr "" + +#: src/transport/gnunet-transport.c:614 +#, fuzzy +msgid "Direct access to transport service." +msgstr "Lá»—i kết nối đến gnunetd.\n" + +#: src/transport/plugin_transport_http.c:981 +msgid "Disabling IPv6 since it is not supported on this system!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1029 +#, fuzzy +msgid "Require valid port number for service in configuration!\n" +msgstr "Lá»—i lÆ°u cấu hình." + +#: src/transport/plugin_transport_http.c:1054 src/util/service.c:986 +#, fuzzy, c-format +msgid "Failed to resolve `%s': %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/transport/plugin_transport_http.c:1071 src/util/service.c:1003 +#, fuzzy, c-format +msgid "Failed to find %saddress for `%s'.\n" +msgstr "Lá»—i đóng kết đến cổng %s %d.\n" + +#: src/transport/plugin_transport_http.c:1176 +#, c-format +msgid "Found %u addresses to report to NAT service\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1189 +#, c-format +msgid "FREEING %s\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1264 +msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1277 +#, fuzzy +msgid "Port is required! Fix in configuration\n" +msgstr "" +"\n" +"Kết thúc cấu hình.\n" + +#: src/transport/plugin_transport_http.c:1288 +msgid "Port 0, client only mode\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1308 +#, c-format +msgid "" +"Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1338 +#, c-format +msgid "" +"Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http_client.c:621 +#, c-format +msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:189 +msgid "" +"Could not create a new TLS certificate, program `gnunet-transport-" +"certificate-creation' could not be started!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:213 +msgid "No usable TLS certificate found and creating one failed!\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:370 +#, c-format +msgid "Received malformed message via %s. Ignored.\n" +msgstr "Nhận được thông báo dạng sai qua %s. Bị bá» qua.\n" + +#: src/transport/plugin_transport_smtp.c:457 +msgid "SMTP filter string to invalid, lacks ': '\n" +msgstr "Chuá»—i lá»c vào SMTP không hợp lệ, còn thiếu « : »\n" + +#: src/transport/plugin_transport_smtp.c:466 +#, c-format +msgid "SMTP filter string to long, capped to `%s'\n" +msgstr "Chuá»—i lá»c vào SMTP quá dài, tối Ä‘a « %s »\n" + +#: src/transport/plugin_transport_smtp.c:561 +#: src/transport/plugin_transport_smtp.c:571 +#: src/transport/plugin_transport_smtp.c:584 +#: src/transport/plugin_transport_smtp.c:603 +#: src/transport/plugin_transport_smtp.c:626 +#: src/transport/plugin_transport_smtp.c:634 +#: src/transport/plugin_transport_smtp.c:647 +#: src/transport/plugin_transport_smtp.c:658 +#, c-format +msgid "SMTP: `%s' failed: %s.\n" +msgstr "SMTP: « %s » bị lá»—i: %s\n" + +#: src/transport/plugin_transport_smtp.c:801 +msgid "No email-address specified, can not start SMTP transport.\n" +msgstr "ChÆ°a ghi rõ địa chỉ thÆ° Ä‘iện tá»­ nên không tạo được truyá»n tải SMTP.\n" + +#: src/transport/plugin_transport_smtp.c:813 +msgid "# bytes received via SMTP" +msgstr "# các byte đã nhận qua SMTP" + +#: src/transport/plugin_transport_smtp.c:814 +msgid "# bytes sent via SMTP" +msgstr "# các byte đã gá»­i qua SMTP" + +#: src/transport/plugin_transport_smtp.c:816 +msgid "# bytes dropped by SMTP (outgoing)" +msgstr "# các byte loại Ä‘i bởi SMTP (Ä‘i ra)" + +#: src/transport/plugin_transport_tcp.c:512 +#, fuzzy, c-format +msgid "Unexpected address length: %u bytes\n" +msgstr "Gặp sá»± kiện bất thÆ°á»ng: %d\n" + +#: src/transport/plugin_transport_tcp.c:616 +#: src/transport/plugin_transport_tcp.c:705 +#: src/transport/plugin_transport_tcp.c:757 +#: src/transport/plugin_transport_tcp.c:830 +#: src/transport/plugin_transport_tcp.c:909 +#, fuzzy +msgid "# bytes currently in TCP buffers" +msgstr "# các byte đã gừi qua TCP" + +#: src/transport/plugin_transport_tcp.c:622 +#: src/transport/plugin_transport_tcp.c:856 +#: src/transport/plugin_transport_tcp.c:1561 +#, fuzzy +msgid "# TCP sessions active" +msgstr "# các khoá phiên chạy được chấp nhận" + +#: src/transport/plugin_transport_tcp.c:709 +#, fuzzy +msgid "# bytes discarded by TCP (timeout)" +msgstr "# các byte loại Ä‘i bởi TCP (Ä‘i ra)" + +#: src/transport/plugin_transport_tcp.c:760 +#, fuzzy +msgid "# bytes transmitted via TCP" +msgstr "# các byte được gá»­i" + +#: src/transport/plugin_transport_tcp.c:834 +#, fuzzy +msgid "# bytes discarded by TCP (disconnect)" +msgstr "# các byte loại Ä‘i bởi TCP (Ä‘i ra)" + +#: src/transport/plugin_transport_tcp.c:1081 +#, fuzzy, c-format +msgid "Address of unexpected length: %u\n" +msgstr "Gặp sá»± kiện bất thÆ°á»ng: %d\n" + +#: src/transport/plugin_transport_tcp.c:1116 +msgid "Found valid IPv4 NAT address (creating session)!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1186 +msgid "# transport-service disconnect requests for TCP" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1603 +#, fuzzy +msgid "# TCP WELCOME messages received" +msgstr "# các thông báo PONG đã mật mã được nhận" + +#: src/transport/plugin_transport_tcp.c:1756 +msgid "# bytes received via TCP" +msgstr "# các byte đã nhận qua TCP" + +#: src/transport/plugin_transport_tcp.c:1823 +msgid "# network-level TCP disconnect events" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1962 src/util/service.c:889 +#, c-format +msgid "Require valid port number for service `%s' in configuration!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1976 +#, fuzzy +msgid "Failed to start service.\n" +msgstr "Lá»—i bắt đầu thu thập.\n" + +#: src/transport/plugin_transport_tcp.c:2039 +#, fuzzy, c-format +msgid "Failed to find option %s in section %s!\n" +msgstr "Lá»—i đóng kết đến cổng %s %d.\n" + +#: src/transport/plugin_transport_tcp.c:2062 +#, c-format +msgid "TCP transport listening on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2066 +msgid "TCP transport not listening on any port (client only)\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2070 +#, c-format +msgid "TCP transport advertises itself as being on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_udp_broadcasting.c:130 +#, fuzzy +msgid "# IPv6 multicast HELLO beacons received via udp" +msgstr "# các thông báo PONG đã mật mã được nhận" + +#: src/transport/plugin_transport_udp_broadcasting.c:172 +#, fuzzy +msgid "# IPv4 broadcast HELLO beacons received via udp" +msgstr "# các thông báo PONG đã mật mã được nhận" + +#: src/transport/plugin_transport_udp_broadcasting.c:393 +#, c-format +msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:1985 +#, fuzzy +msgid "Failed to open UDP sockets\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/transport/plugin_transport_udp.c:2068 +#, c-format +msgid "Given `%s' option is out of range: %llu > %u\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:2112 +#, fuzzy, c-format +msgid "Invalid IPv6 address: `%s'\n" +msgstr "Mức Æ°u tiên tiến trình không hợp lê « %s ».\n" + +#: src/transport/plugin_transport_unix.c:1051 +#, fuzzy +msgid "Failed to open UNIX sockets\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/transport/plugin_transport_wlan.c:875 +#, fuzzy +msgid "# wlan session timeouts" +msgstr "# các khoá phiên chạy được chấp nhận" + +#: src/transport/plugin_transport_wlan.c:899 +#, fuzzy +msgid "# wlan session created" +msgstr "# các khoá phiên chạy được chấp nhận" + +#: src/transport/plugin_transport_wlan.c:980 +#: src/transport/plugin_transport_wlan.c:1138 +#: src/transport/plugin_transport_wlan.c:1159 +#: src/transport/plugin_transport_wlan.c:1190 +#: src/transport/plugin_transport_wlan.c:2334 +#: src/transport/plugin_transport_wlan.c:3142 +msgid "# wlan pending sessions" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1233 +#: src/transport/plugin_transport_wlan.c:1888 +#, fuzzy +msgid "# wlan pending fragments" +msgstr "# các mảnh bị loại bá»" + +#: src/transport/plugin_transport_wlan.c:1388 +#, c-format +msgid "" +"Finished reading from gnunet-helper-transport-wlan stdout with code: %d\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1732 +msgid "# wlan hello beacons send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1765 +#: src/transport/plugin_transport_wlan.c:1968 +#: src/transport/plugin_transport_wlan.c:2059 +#, c-format +msgid "Error writing to wlan helper. errno == %d, ERROR: %s\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1954 +msgid "# wlan acks send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2025 +#, fuzzy +msgid "# wlan fragments send" +msgstr "# các mảnh bị loại bá»" + +#: src/transport/plugin_transport_wlan.c:2161 +#, c-format +msgid "Wlan Address len %d is wrong\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2295 +#: src/transport/plugin_transport_wlan.c:2919 +#: src/transport/plugin_transport_wlan.c:3145 +msgid "# wlan mac endpoints" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2517 +#, fuzzy +msgid "# wlan whole messages received" +msgstr "# các thông báo phát hiện dht được nhận" + +#: src/transport/plugin_transport_wlan.c:2708 +#, fuzzy +msgid "# wlan hello messages received" +msgstr "# các thông báo phát hiện dht được nhận" + +#: src/transport/plugin_transport_wlan.c:2742 +#, fuzzy +msgid "# wlan fragments received" +msgstr "# các mảnh bị loại bá»" + +#: src/transport/plugin_transport_wlan.c:2790 +#, fuzzy +msgid "# wlan acks received" +msgstr "# các yêu cầu khách lá»— hổng được nhận" + +#: src/transport/plugin_transport_wlan.c:2879 +msgid "# wlan mac endpoints timeouts" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2903 +#, fuzzy +msgid "# wlan mac endpoints created" +msgstr "# các yêu cầu get (lấy) dht được nhận" + +#: src/transport/plugin_transport_wlan.c:2956 +msgid "# wlan WLAN_HELPER_DATA received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:3010 +#, fuzzy +msgid "# wlan messages for this client received" +msgstr "# các thông báo phát hiện dht được nhận" + +#: src/transport/plugin_transport_wlan.c:3021 +#, fuzzy +msgid "# wlan messages inside WLAN_HELPER_DATA received" +msgstr "# các thông báo phát hiện dht được nhận" + +#: src/transport/transport_api.c:588 +#, fuzzy, c-format +msgid "Received unexpected message of type %u in %s:%u\n" +msgstr "Nhận được thông báo bị há»ng từ đồng đẳng « %s » trong %s:%d.\n" + +#: src/util/bio.c:136 src/util/bio.c:142 +#, fuzzy, c-format +msgid "Error reading `%s': %s" +msgstr "Gặp lá»—i khi tạo ngÆ°á»i dùng" + +#: src/util/bio.c:143 +msgid "End of file" +msgstr "" + +#: src/util/bio.c:195 +#, c-format +msgid "Error reading length of string `%s'" +msgstr "" + +#: src/util/bio.c:205 +#, c-format +msgid "String `%s' longer than allowed (%u > %u)" +msgstr "" + +#: src/util/bio.c:250 +#, c-format +msgid "Serialized metadata `%s' larger than allowed (%u>%u)" +msgstr "" + +#: src/util/bio.c:264 +#, c-format +msgid "Metadata `%s' failed to deserialize" +msgstr "" + +#: src/util/client.c:304 +#, c-format +msgid "" +"Could not determine valid hostname and port for service `%s' from " +"configuration.\n" +msgstr "" + +#: src/util/client.c:312 +#, c-format +msgid "Need a non-empty hostname for service `%s'.\n" +msgstr "" + +#: src/util/client.c:657 +msgid "Failure to transmit TEST request.\n" +msgstr "" + +#: src/util/client.c:717 src/util/service.c:919 +#, c-format +msgid "UNIXPATH `%s' too long, maximum length is %llu\n" +msgstr "" + +#: src/util/client.c:859 +#, c-format +msgid "Could not connect to service `%s', must not be running.\n" +msgstr "" + +#: src/util/client.c:875 +#, fuzzy, c-format +msgid "Failure to transmit request to service `%s'\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/util/client.c:1143 +msgid "Could not submit request, not expecting to receive a response.\n" +msgstr "" + +#: src/util/common_logging.c:239 src/util/common_logging.c:889 +msgid "DEBUG" +msgstr "Gá»  Lá»–I" + +#: src/util/common_logging.c:241 src/util/common_logging.c:887 +msgid "INFO" +msgstr "TIN" + +#: src/util/common_logging.c:243 src/util/common_logging.c:885 +msgid "WARNING" +msgstr "CẢNH BÃO" + +#: src/util/common_logging.c:245 src/util/common_logging.c:883 +msgid "ERROR" +msgstr "Lá»–I" + +#: src/util/common_logging.c:247 src/util/common_logging.c:891 +msgid "NONE" +msgstr "" + +#: src/util/common_logging.c:609 +#, fuzzy, c-format +msgid "Failed to create or access directory for log file `%s'\n" +msgstr "Không thể truy cập đến tập tin gnunet-directory « %s »\n" + +#: src/util/common_logging.c:724 +#, fuzzy, c-format +msgid "Message `%.*s' repeated %u times in the last %s\n" +msgstr "Thông Ä‘iệp « %.*s » đã lặp lại %u lần trong %llu giây trÆ°á»›c\n" + +#: src/util/common_logging.c:892 +msgid "INVALID" +msgstr "" + +#: src/util/common_logging.c:991 +msgid "unknown address" +msgstr "" + +#: src/util/common_logging.c:1029 +msgid "invalid address" +msgstr "" + +#: src/util/configuration.c:245 +#, fuzzy, c-format +msgid "Syntax error in configuration file `%s' at line %u.\n" +msgstr "Gặp lá»—i cú pháp trong tập tin cấu hình « %s » tại dòng %d.\n" + +#: src/util/configuration.c:817 +#, c-format +msgid "" +"Configuration value '%s' for '%s' in section '%s' is not in set of legal " +"choices\n" +msgstr "" +"Giá trị cấu hình « %s » cho « %s » trong phần « %s » không phải nằm trong " +"tập hợp các sá»± chá»n được phép\n" + +#: src/util/connection.c:460 +#, fuzzy, c-format +msgid "Access denied to `%s'\n" +msgstr "Không đủ quyá»n cho « %s ».\n" + +#: src/util/connection.c:475 +#, c-format +msgid "Accepting connection from `%s': %p\n" +msgstr "" + +#: src/util/connection.c:629 +#, fuzzy, c-format +msgid "" +"Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" +msgstr "Lá»—i thiết lập kết nối vá»›i đồng đẳng.\n" + +#: src/util/connection.c:821 src/util/connection.c:992 +#, fuzzy, c-format +msgid "Trying to connect to `%s' (%p)\n" +msgstr "Không thể kết nối tá»›i %s:%u: %s\n" + +#: src/util/connection.c:830 +#, fuzzy, c-format +msgid "Failed to connect to `%s' (%p)\n" +msgstr "Không thể kết nối tá»›i %s:%u: %s\n" + +#: src/util/connection.c:983 +#, fuzzy, c-format +msgid "Attempt to connect to `%s' failed\n" +msgstr " Lá»—i kết nối\n" + +#: src/util/connection.c:1465 +#, c-format +msgid "" +"Could not satisfy pending transmission request, socket closed or connect " +"failed (%p).\n" +msgstr "" + +#: src/util/container_bloomfilter.c:507 +#, c-format +msgid "" +"Size of file on disk is incorrect for this Bloom filter (want %llu, have " +"%llu)\n" +msgstr "" + +#: src/util/crypto_random.c:280 +#, c-format +msgid "Starting `%s' process to generate entropy\n" +msgstr "" + +#: src/util/crypto_random.c:309 +#, c-format +msgid "libgcrypt has not the expected version (version %s is required).\n" +msgstr "libgcrypt không có phiên bản mong đợi (yêu cầu phiên bản %s).\n" + +#: src/util/crypto_rsa.c:618 src/util/crypto_rsa.c:665 +#, fuzzy, c-format +msgid "Could not aquire lock on file `%s': %s...\n" +msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" + +#: src/util/crypto_rsa.c:623 +#, fuzzy +msgid "Creating a new private key. This may take a while.\n" +msgstr "Äang tạo khoá máy má»›i (có thể hÆ¡i lâu).\n" + +#: src/util/crypto_rsa.c:641 +#, c-format +msgid "I am host `%s'. Stored new private key in `%s'.\n" +msgstr "" + +#: src/util/crypto_rsa.c:669 src/util/crypto_rsa.c:705 +msgid "This may be ok if someone is currently generating a hostkey.\n" +msgstr "" + +#: src/util/crypto_rsa.c:700 +#, c-format +msgid "" +"When trying to read hostkey file `%s' I found %u bytes but I need at least " +"%u.\n" +msgstr "" + +#: src/util/crypto_rsa.c:720 +#, fuzzy, c-format +msgid "File `%s' does not contain a valid private key. Deleting it.\n" +msgstr "Tập tin « %s » không chứa biệt hiệu nên thá»­ gỡ bá».\n" + +#: src/util/crypto_rsa.c:738 +#, c-format +msgid "I am host `%s'. Read private key from `%s'.\n" +msgstr "" + +#: src/util/crypto_rsa.c:959 +#, c-format +msgid "RSA signature verification failed at %s:%d: %s\n" +msgstr "Lá»—i thẩm tra chữ ký RSA tại %s:%d: %s\n" + +#: src/util/disk.c:479 +#, fuzzy, c-format +msgid "`%s' failed for drive `%S': %u\n" +msgstr "« %s » thất bại cho ổ Ä‘Ä©a « %s »: %u\n" + +#: src/util/disk.c:1087 +#, c-format +msgid "Expected `%s' to be a directory!\n" +msgstr "Mong đợi « %s » là má»™t thÆ° mục.\n" + +#: src/util/disk.c:1441 src/util/service.c:1580 +#, c-format +msgid "Cannot obtain information about user `%s': %s\n" +msgstr "Không thể lấy thông tin vá» ngÆ°á»i dùng « %s »: %s\n" + +#: src/util/disk.c:1759 +#, c-format +msgid "No `%s' specified for service `%s' in configuration.\n" +msgstr "" + +#: src/util/getopt.c:672 +#, c-format +msgid "%s: option `%s' is ambiguous\n" +msgstr "%s: tùy chá»n « %s » là mÆ¡ hồ\n" + +#: src/util/getopt.c:696 +#, c-format +msgid "%s: option `--%s' does not allow an argument\n" +msgstr "%s: tùy chá»n « --%s » không cho phép đối số\n" + +#: src/util/getopt.c:701 +#, c-format +msgid "%s: option `%c%s' does not allow an argument\n" +msgstr "%s: tùy chá»n « %c%s » không cho phép đối số\n" + +#: src/util/getopt.c:718 src/util/getopt.c:886 +#, c-format +msgid "%s: option `%s' requires an argument\n" +msgstr "%s: tùy chá»n « %s » cần thiết đối số\n" + +#: src/util/getopt.c:747 +#, c-format +msgid "%s: unrecognized option `--%s'\n" +msgstr "%s: không nhận ra tùy chá»n « --%s »\n" + +#: src/util/getopt.c:751 +#, c-format +msgid "%s: unrecognized option `%c%s'\n" +msgstr "%s: không nhận ra tùy chá»n « %c%s »\n" + +#: src/util/getopt.c:776 +#, c-format +msgid "%s: illegal option -- %c\n" +msgstr "%s: tùy chá»n không được phép -- %c\n" + +#: src/util/getopt.c:778 +#, c-format +msgid "%s: invalid option -- %c\n" +msgstr "%s: tùy chá»n không hợp lệ -- %c\n" + +#: src/util/getopt.c:806 src/util/getopt.c:934 +#, c-format +msgid "%s: option requires an argument -- %c\n" +msgstr "%s: tùy chá»n cần thiết đối số -- %c\n" + +#: src/util/getopt.c:854 +#, c-format +msgid "%s: option `-W %s' is ambiguous\n" +msgstr "%s: tùy chá»n « -W %s » là mÆ¡ hồ\n" + +#: src/util/getopt.c:872 +#, c-format +msgid "%s: option `-W %s' does not allow an argument\n" +msgstr "%s: tùy chá»n « -W %s » không cho phép đối số\n" + +#: src/util/getopt.c:1038 +#, fuzzy, c-format +msgid "Use %s to get a list of options.\n" +msgstr "" +"Hãy sá»­ dụng câu lệnh trợ giúp « --help » để xem danh sách các tùy chá»n.\n" + +#: src/util/getopt_helpers.c:84 +#, c-format +msgid "" +"Arguments mandatory for long options are also mandatory for short options.\n" +msgstr "" +"Má»i đối số bắt buá»™c phải sá»­ dụng vá»›i tùy chá»n dài cÅ©ng bắt buá»™c vá»›i tùy chá»n " +"ngắn.\n" + +#: src/util/getopt_helpers.c:255 src/util/getopt_helpers.c:283 +#, c-format +msgid "You must pass a number to the `%s' option.\n" +msgstr "Phải gá»­i má»™t con số cho tùy chá»n « %s ».\n" + +#: src/util/gnunet-resolver.c:148 +msgid "perform a reverse lookup" +msgstr "" + +#: src/util/gnunet-resolver.c:154 +msgid "Use build-in GNUnet stub resolver" +msgstr "" + +#: src/util/gnunet-service-resolver.c:288 +#, c-format +msgid "Could not resolve `%s' (%s): %s\n" +msgstr "Không thể giải quyết « %s » (%s): %s\n" + +#: src/util/gnunet-service-resolver.c:358 +#: src/util/gnunet-service-resolver.c:399 +#, c-format +msgid "Could not find IP of host `%s': %s\n" +msgstr "Không tìm thấy địa chỉ IP của máy « %s »: %s\n" + +#: src/util/gnunet-service-resolver.c:494 +#, c-format +msgid "Resolver asked to look up `%s'.\n" +msgstr "" + +#: src/util/gnunet-service-resolver.c:529 +#, c-format +msgid "Resolver asked to look up IP address `%s'.\n" +msgstr "" + +#: src/util/helper.c:239 +#, fuzzy, c-format +msgid "Error reading from `%s': %s\n" +msgstr "Gặp lá»—i khi tạo ngÆ°á»i dùng" + +#: src/util/helper.c:254 +#, c-format +msgid "Got 0 bytes from helper `%s' (EOF)\n" +msgstr "" + +#: src/util/helper.c:264 +#, fuzzy, c-format +msgid "Got %u bytes from helper `%s'\n" +msgstr "Nhận yêu cầu định tuyến\n" + +#: src/util/helper.c:273 +#, fuzzy, c-format +msgid "Failed to parse inbound message from helper `%s'\n" +msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#: src/util/helper.c:432 +#, fuzzy, c-format +msgid "Error writing to `%s': %s\n" +msgstr "Gặp lá»—i khi tạo ngÆ°á»i dùng" + +#: src/util/network.c:1196 +#, c-format +msgid "" +"Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" +msgstr "" + +#: src/util/os_installation.c:299 +#, c-format +msgid "" +"Could not determine installation path for %s. Set `%s' environment " +"variable.\n" +msgstr "" + +#: src/util/os_installation.c:486 +#, fuzzy, c-format +msgid "Could not find binary `%s' in PATH!\n" +msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" + +#: src/util/os_installation.c:492 +#, fuzzy, c-format +msgid "access (%s, X_OK) failed: %s\n" +msgstr "SMTP: « %s » bị lá»—i: %s\n" + +#: src/util/os_installation.c:507 +#, fuzzy, c-format +msgid "stat (%s) failed: %s\n" +msgstr "SMTP: « %s » bị lá»—i: %s\n" + +#: src/util/os_priority.c:304 +#, fuzzy, c-format +msgid "Failed to open named pipe `%s' for reading: %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/util/os_priority.c:305 +#, fuzzy, c-format +msgid "Failed to open named pipe `%s' for writing: %s\n" +msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#: src/util/plugin.c:89 +#, c-format +msgid "Initialization of plugin mechanism failed: %s!\n" +msgstr "Lá»—i sÆ¡ khởi cÆ¡ chế phần bổ sung: %s\n" + +#: src/util/plugin.c:146 +#, c-format +msgid "`%s' failed to resolve method '%s' with error: %s\n" +msgstr "« %s » không giải quyết được phÆ°Æ¡ng pháp « %s », vá»›i lá»—i: %s\n" + +#: src/util/plugin.c:219 +#, c-format +msgid "`%s' failed for library `%s' with error: %s\n" +msgstr "« %s » thất bại cho thÆ° viện « %s » vá»›i lá»—i: %s\n" + +#: src/util/plugin.c:349 +#, fuzzy +msgid "Could not determine plugin installation path.\n" +msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" + +#: src/util/pseudonym.c:273 +#, fuzzy, c-format +msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" +msgstr "Lá»—i phân tích dữ liệu giao diện từ « %s ».\n" + +#: src/util/pseudonym.c:338 +msgid "no-name" +msgstr "không-tên" + +#: src/util/resolver_api.c:202 +#, fuzzy, c-format +msgid "Must specify `%s' for `%s' in configuration!\n" +msgstr "Äang thá»­ dùng tập tin « %s » cho cấu hình MySQL.\n" + +#: src/util/resolver_api.c:221 +#, c-format +msgid "" +"Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" +msgstr "" + +#: src/util/resolver_api.c:351 +#, fuzzy, c-format +msgid "Timeout trying to resolve IP address `%s'.\n" +msgstr "GNUnet bây giá» sá»­ dụng địa chỉ IP %s.\n" + +#: src/util/resolver_api.c:355 +#, fuzzy, c-format +msgid "Timeout trying to resolve hostname `%s'.\n" +msgstr "không quyết định các tên máy" + +#: src/util/resolver_api.c:426 +#, c-format +msgid "Resolver returns `%s' for IP `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:807 +#, c-format +msgid "Resolver returns `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:901 +#, c-format +msgid "Resolving our FQDN `%s'\n" +msgstr "" + +#: src/util/resolver_api.c:906 +#, fuzzy, c-format +msgid "Could not resolve our FQDN : %s\n" +msgstr "Không thể giải quyết « %s » (%s): %s\n" + +#: src/util/resolver_api.c:938 +#, c-format +msgid "Resolving our hostname `%s'\n" +msgstr "" + +#: src/util/scheduler.c:866 +msgid "Looks like we're busy waiting...\n" +msgstr "" + +#: src/util/scheduler.c:996 +#, c-format +msgid "Attempt to cancel dead task %llu!\n" +msgstr "" + +#: src/util/server.c:397 +#, fuzzy, c-format +msgid "`%s' failed for port %d (%s).\n" +msgstr "« %s » thất bại cho ổ Ä‘Ä©a « %s »: %u\n" + +#: src/util/server.c:406 +#, fuzzy, c-format +msgid "`%s' failed for port %d (%s): address already in use\n" +msgstr "« %s » bị lá»—i cho cổng %d. Trình gnunetd có chạy chÆ°a?\n" + +#: src/util/server.c:411 +#, fuzzy, c-format +msgid "`%s' failed for `%s': address already in use\n" +msgstr "« %s » bị lá»—i cho cổng %d. Trình gnunetd có chạy chÆ°a?\n" + +#: src/util/server.c:640 +#, c-format +msgid "" +"Processing code for message of type %u did not call " +"GNUNET_SERVER_receive_done after %llums\n" +msgstr "" + +#: src/util/service.c:117 src/util/service.c:143 src/util/service.c:186 +#: src/util/service.c:207 src/util/service.c:214 +#, c-format +msgid "Invalid format for IP: `%s'\n" +msgstr "Äịa chỉ IP định dạng sai: %s\n" + +#: src/util/service.c:170 +#, c-format +msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." +msgstr "Ký hiệu mạng sai (« /%d » không hợp lệ trong CIDR IPv4)." + +#: src/util/service.c:263 +#, c-format +msgid "Invalid network notation (does not end with ';': `%s')\n" +msgstr "Ký hiệu mạng sai (không kết thúc vá»›i « ; »: « %s »)\n" + +#: src/util/service.c:296 +#, fuzzy, c-format +msgid "Wrong format `%s' for netmask\n" +msgstr "Mặt nạ mạng có định dạng sai « %s »: %s\n" + +#: src/util/service.c:326 +#, fuzzy, c-format +msgid "Wrong format `%s' for network\n" +msgstr "Mạng có định dạng sai « %s »: %s\n" + +#: src/util/service.c:668 +#, c-format +msgid "Access denied to UID %d / GID %d\n" +msgstr "" + +#: src/util/service.c:673 +#, fuzzy, c-format +msgid "Unknown address family %d\n" +msgstr "\tKhông rõ miá»n tên « %s »\n" + +#: src/util/service.c:680 +#, c-format +msgid "Access from `%s' denied to service `%s'\n" +msgstr "" + +#: src/util/service.c:724 +#, c-format +msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:752 +#, c-format +msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:869 +#, c-format +msgid "" +"Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" +msgstr "" + +#: src/util/service.c:939 +#, c-format +msgid "" +"Disabling UNIX domain socket support for service `%s', failed to create UNIX " +"domain socket: %s\n" +msgstr "" + +#: src/util/service.c:956 +#, c-format +msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" +msgstr "" + +#: src/util/service.c:1191 +msgid "Could not access a pre-bound socket, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1242 src/util/service.c:1260 +#, c-format +msgid "Specified value for `%s' of service `%s' is invalid\n" +msgstr "" + +#: src/util/service.c:1287 +#, c-format +msgid "Could not access pre-bound socket %u, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1442 +#, fuzzy, c-format +msgid "Failed to start `%s' at `%s'\n" +msgstr "Lá»—i chạy %s: %s %d\n" + +#: src/util/service.c:1475 +#, fuzzy, c-format +msgid "Service `%s' runs at %s\n" +msgstr "Äồng đẳng « %s » có mức tin cậy %8u\n" + +#: src/util/service.c:1521 +msgid "Service process failed to initialize\n" +msgstr "" + +#: src/util/service.c:1525 +msgid "Service process could not initialize server function\n" +msgstr "" + +#: src/util/service.c:1529 +msgid "Service process failed to report status\n" +msgstr "" + +#: src/util/service.c:1581 +msgid "No such user" +msgstr "Không có ngÆ°á»i dùng nhÆ° vậy" + +#: src/util/service.c:1594 +#, c-format +msgid "Cannot change user/group to `%s': %s\n" +msgstr "Không thể thay đổi ngÆ°á»i dùng/nhóm thành « %s »: %s\n" + +#: src/util/service.c:1657 +msgid "do daemonize (detach from terminal)" +msgstr "" + +#: src/util/signal.c:80 +#, c-format +msgid "signal (%d, %p) returned %d.\n" +msgstr "" + +#: src/util/strings.c:143 +msgid "b" +msgstr "b" + +#: src/util/strings.c:354 +#, c-format +msgid "Character sets requested were `%s'->`%s'\n" +msgstr "" + +#: src/util/strings.c:462 +msgid "Failed to expand `$HOME': environment variable `HOME' not set" +msgstr "" +"Lá»—i mở rá»™ng biến môi trÆ°á»ng « $HOME »: chÆ°a đặt biến môi trÆ°á»ng « HOME »" + +#: src/util/strings.c:554 +msgid "ms" +msgstr "mg" + +#: src/util/strings.c:559 +msgid "eternity" +msgstr "" + +#: src/util/strings.c:563 +msgid "s" +msgstr "g" + +#: src/util/strings.c:567 +msgid "m" +msgstr "p" + +#: src/util/strings.c:571 +msgid "h" +msgstr "g" + +#: src/util/strings.c:575 +msgid " days" +msgstr " ngày" + +#: src/util/strings.c:599 +msgid "end of time" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1065 +#, fuzzy +msgid "# Active tunnels" +msgstr "# các kết nối dht" + +#: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 +#, fuzzy +msgid "# Peers connected to mesh tunnels" +msgstr "# của các đồng đẳng đã kết nối" + +#: src/vpn/gnunet-service-vpn.c:699 +#, fuzzy +msgid "# Bytes given to mesh for transmission" +msgstr "# các thông báo PING được tạo" + +#: src/vpn/gnunet-service-vpn.c:737 +#, fuzzy +msgid "# Bytes dropped in mesh queue (overflow)" +msgstr "# các byte loại bá» bởi UDP (Ä‘i ra)" + +#: src/vpn/gnunet-service-vpn.c:772 +#, fuzzy +msgid "# Mesh tunnels created" +msgstr "# các truy vấn lá»— hổng được định tuyến" + +#: src/vpn/gnunet-service-vpn.c:795 +#, fuzzy +msgid "Failed to setup mesh tunnel!\n" +msgstr "Lá»—i lấy thông kê vá» truyá»n tải.\n" + +#: src/vpn/gnunet-service-vpn.c:967 +#, c-format +msgid "Protocol %u not supported, dropping\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1285 +msgid "# ICMPv4 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1306 +msgid "# ICMPv6 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1511 +#, fuzzy +msgid "# Packets received from TUN interface" +msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" + +#: src/vpn/gnunet-service-vpn.c:1549 src/vpn/gnunet-service-vpn.c:1590 +#, c-format +msgid "Packet received for unmapped destination `%s' (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1600 +msgid "Received IPv4 packet with options (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1614 +#, c-format +msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1697 +#, fuzzy +msgid "# ICMP packets received from mesh" +msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" + +#: src/vpn/gnunet-service-vpn.c:2038 +#, fuzzy +msgid "# UDP packets received from mesh" +msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" + +#: src/vpn/gnunet-service-vpn.c:2196 +#, fuzzy +msgid "# TCP packets received from mesh" +msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" + +#: src/vpn/gnunet-service-vpn.c:2347 +msgid "Failed to find unallocated IPv4 address in VPN's range\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2402 +msgid "Failed to find unallocated IPv6 address in VPN's range\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2441 src/vpn/gnunet-service-vpn.c:2624 +#, fuzzy +msgid "# Active destinations" +msgstr "# các kết nối dht" + +#: src/vpn/gnunet-service-vpn.c:2726 +msgid "Failed to allocate IP address for new destination\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3133 +msgid "IPv6 support disabled as this system does not support IPv6\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3165 +msgid "IPv4 support disabled as this system does not support IPv4\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:151 +#, fuzzy +msgid "Error creating tunnel\n" +msgstr "Hoàn thành tạo khoá.\n" + +#: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 +#, fuzzy, c-format +msgid "Option `%s' makes no sense with option `%s'.\n" +msgstr "Tùy chá»n « %s » không có nghÄ©a khi không có tùy chá»n « %s ».\n" + +#: src/vpn/gnunet-vpn.c:208 +#, fuzzy, c-format +msgid "Option `%s' or `%s' is required.\n" +msgstr "Bị từ chối đặt tùy chá»n « %s » trong phần « %s » thành « %s ».\n" + +#: src/vpn/gnunet-vpn.c:220 +#, fuzzy, c-format +msgid "Option `%s' or `%s' is required when using option `%s'.\n" +msgstr "Tùy chá»n « %s » cần thiết khi dùng tùy chá»n « %s ».\n" + +#: src/vpn/gnunet-vpn.c:238 +#, fuzzy, c-format +msgid "`%s' is not a valid peer identifier.\n" +msgstr "« %s » không sẵn sàng.\n" + +#: src/vpn/gnunet-vpn.c:260 +#, fuzzy, c-format +msgid "`%s' is not a valid IP address.\n" +msgstr "« %s » không sẵn sàng.\n" + +#: src/vpn/gnunet-vpn.c:296 +msgid "request that result should be an IPv4 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:299 +msgid "request that result should be an IPv6 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:302 +msgid "print IP address only after mesh tunnel has been created" +msgstr "" + +#: src/vpn/gnunet-vpn.c:305 +msgid "how long should the mapping be valid for new tunnels?" +msgstr "" + +#: src/vpn/gnunet-vpn.c:308 +msgid "destination IP for the tunnel" +msgstr "" + +#: src/vpn/gnunet-vpn.c:311 +msgid "peer offering the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:314 +msgid "name of the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:317 +#, fuzzy +msgid "service is offered via TCP" +msgstr "# các byte đã nhận qua TCP" + +#: src/vpn/gnunet-vpn.c:320 +#, fuzzy +msgid "service is offered via UDP" +msgstr "# các byte đã nhận qua UDP" + +#: src/vpn/gnunet-vpn.c:329 +msgid "Setup tunnels via VPN." +msgstr "" + +#: src/include/gnunet_common.h:479 src/include/gnunet_common.h:484 +#: src/include/gnunet_common.h:490 +#, fuzzy, c-format +msgid "Assertion failed at %s:%d.\n" +msgstr "Lá»—i ná»™i bá»™ : khẳng định không thành công tại %s:%d.\n" + +#: src/include/gnunet_common.h:500 +#, fuzzy, c-format +msgid "External protocol violation detected at %s:%d.\n" +msgstr "Lá»—i ná»™i bá»™ : khẳng định không thành công tại %s:%d.\n" + +#: src/include/gnunet_common.h:521 src/include/gnunet_common.h:528 +#, c-format +msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" +msgstr "« %s » thất bại ở tập tin « %s » tại %s:%d vá»›i lá»—i: %s\n" + +#, fuzzy +#~ msgid "Failed to send to `%s': %s\n" +#~ msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" + +#, fuzzy +#~ msgid "Could not access file: %s\n" +#~ msgstr "Không thể truy cập đến « %s »: %s\n" + +#, fuzzy +#~ msgid "`%s' failed on file `%s': %s" +#~ msgstr "« %s » thất bại cho ổ Ä‘Ä©a « %s »: %u\n" + +#, fuzzy +#~ msgid "# bytes TCP was asked to transmit" +#~ msgstr "# các byte được gá»­i" + +#, fuzzy +#~ msgid "# bytes discarded by TCP (failed to connect)" +#~ msgstr "# các byte loại Ä‘i bởi TCP (Ä‘i ra)" + +#, fuzzy +#~ msgid "# wlan messages queued" +#~ msgstr "# các thông báo phát hiện dht được nhận" + +#~ msgid "print this help" +#~ msgstr "hiển thị trợ giúp này" + +#~ msgid "print the version number" +#~ msgstr "hiển thị số thứ tá»± phiên bản" + +#, fuzzy +#~ msgid "configure logging to write logs to LOGFILE" +#~ msgstr "cấu hình chức năng ghi sá»± kiện để dùng CẤP_GHI_LƯU" + +#~ msgid "configure logging to use LOGLEVEL" +#~ msgstr "cấu hình chức năng ghi sá»± kiện để dùng CẤP_GHI_LƯU" + +#~ msgid "be verbose" +#~ msgstr "xuất chi tiết" + +#~ msgid "use configuration file FILENAME" +#~ msgstr "dùng tập tin cấu hình TÊN_TẬP_TIN" + +#, fuzzy +#~ msgid "Failed to stop service `%s'!\n" +#~ msgstr "Lá»—i vào phòng « %s »\n" + +#, fuzzy +#~ msgid "Failed to start service `%s'!\n" +#~ msgstr "Lá»—i bắt đầu thu thập.\n" + +#, fuzzy +#~ msgid "Binary implementing service `%s' not known!\n" +#~ msgstr "Không thẩm tra được chữ ký: không rõ đồng đẳng « %s ».\n" + +#, fuzzy +#~ msgid "Service `%s' stopped\n" +#~ msgstr "Dịch vụ đã bị xoá.\n" + +#, fuzzy +#~ msgid "Unable to start service `%s': %s\n" +#~ msgstr "Không thể lÆ°u tập tin cấu hình « %s »:" + +#, fuzzy +#~ msgid "Unable to accept connection for service `%s': %s\n" +#~ msgstr "Không thể lÆ°u tập tin cấu hình « %s »:" + +#, fuzzy +#~ msgid "Service `%s' started\n" +#~ msgstr "Dịch vụ đã bị xoá.\n" + +#, fuzzy +#~ msgid "Peer `%s' plugin: `%s' address `%s'\n" +#~ msgstr "Äồng đẳng « %s » có mức tin cậy %8u và địa chỉ « %s »\n" + +#~ msgid "KiB" +#~ msgstr "KiB" + +#~ msgid "MiB" +#~ msgstr "MiB" + +#~ msgid "GiB" +#~ msgstr "GiB" + +#~ msgid "TiB" +#~ msgstr "TiB" + +#, fuzzy +#~ msgid "Failed to create IPv4 broadcast socket on port %d\n" +#~ msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" + +#, fuzzy +#~ msgid "Failed to load block plugin `%s'\n" +#~ msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" + +#, fuzzy +#~ msgid "Could not resolve our FQDN : %s %u\n" +#~ msgstr "Không thể giải quyết « %s » (%s): %s\n" + +#, fuzzy +#~ msgid "Failed to load dhtlog plugin for `%s'\n" +#~ msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" + +#, fuzzy +#~ msgid "Failed to get full path for `%s'\n" +#~ msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" + +#, fuzzy +#~ msgid "Failed to create file for dhtlog.\n" +#~ msgstr "Lá»—i tạo thÆ° mục tạm thá»i." + +#, fuzzy +#~ msgid "Found peer `%s'\n" +#~ msgstr "Tôi là đồng đẳng « %s ».\n" + +#, fuzzy +#~ msgid "Failed to initialize MySQL database connection for dhtlog.\n" +#~ msgstr "Lá»—i sÆ¡ khởi kết nối cÆ¡ sở dữ liệu MySQL cho kho dữ liệu.\n" + +#, fuzzy +#~ msgid "Loading udp transport plugin\n" +#~ msgstr "Äang nạp các truyá»n tải « %s »\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for udp\n" +#~ msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" + +#, fuzzy +#~ msgid "# SET QUOTA messages received" +#~ msgstr "# các thông báo PONG đã mật mã được nhận" + +#, fuzzy +#~ msgid "curl failed for `%s' at %s:%d: `%s'\n" +#~ msgstr "%s bị lá»—i tại %s:%d: « %s »\n" + +#, fuzzy +#~ msgid "Phase 3: sending messages\n" +#~ msgstr "Lá»—i gá»­i tin nhẳn.\n" + +#, fuzzy +#~ msgid "Loading HTTPS transport plugin `%s'\n" +#~ msgstr "Äang nạp các truyá»n tải « %s »\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for https\n" +#~ msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" + +#, fuzzy +#~ msgid "Fail! Could not connect peers\n" +#~ msgstr "Không thể kết nối tá»›i %s:%u: %s\n" + +#, fuzzy +#~ msgid "Loading tcp transport plugin\n" +#~ msgstr "Äang nạp các truyá»n tải « %s »\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for tcp\n" +#~ msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" + +#, fuzzy +#~ msgid "# HTTP peers active" +#~ msgstr "# Tín hiệu HTTP GET được nhận" + +#, fuzzy +#~ msgid "Connection: %X: %s failed at %s:%d: `%s'\n" +#~ msgstr "%s bị lá»—i tại %s:%d: « %s »\n" + +#, fuzzy +#~ msgid "Loading HTTP transport plugin `%s'\n" +#~ msgstr "Äang nạp các truyá»n tải « %s »\n" + +#, fuzzy +#~ msgid "Failed to load transport plugin for http\n" +#~ msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" + +#, fuzzy +#~ msgid "# PING messages decrypted" +#~ msgstr "# các thông báo PING được tạo" + +#, fuzzy +#~ msgid "Failed to connect to core service\n" +#~ msgstr "Lá»—i kết nối đến gnunetd.\n" + +#, fuzzy +#~ msgid "# bytes successfully transmitted by plugins" +#~ msgstr "# các byte được gá»­i" + +#, fuzzy +#~ msgid "# connected addresses" +#~ msgstr "# của các đồng đẳng đã kết nối" + +#, fuzzy +#~ msgid "# transport failed to selected peer address" +#~ msgstr "Äang quảng cáo truyá»n tải %d của mình tá»›i các đồng đẳng đã chá»n.\n" + +#, fuzzy +#~ msgid "# peer addresses considered valid" +#~ msgstr "# Các quảng cáo đồng đẳng được xác nhận qua PONG" + +#, fuzzy +#~ msgid "# PING with HELLO messages sent" +#~ msgstr "# các thông báo PING được tạo" + +#, fuzzy +#~ msgid "# HELLOs received for validation" +#~ msgstr "# các khối được lấy để nâng cấp" + +#, fuzzy +#~ msgid "Received `%s' message from `%s' destined for `%s' which is not me!\n" +#~ msgstr "Nhận được PING « %s » không dành cho chúng ta.\n" + +#~ msgid "Error" +#~ msgstr "Lá»—i" + +#~ msgid "Help" +#~ msgstr "Trợ giúp" + +#~ msgid "Error!" +#~ msgstr "Lá»—i !" + +#~ msgid "No" +#~ msgstr "Không" + +#~ msgid "Yes" +#~ msgstr "Có" + +#~ msgid "Internal error! (Choice invalid?)" +#~ msgstr "Lá»—i ná»™i bá»™ (sai chá»n ?)" + +#~ msgid "Abort" +#~ msgstr "Hủy" + +#~ msgid "Ok" +#~ msgstr "OK" + +#~ msgid "GNUnet configuration" +#~ msgstr "Cấu hình GNUnet" + +#~ msgid "" +#~ "Welcome to GNUnet!\n" +#~ "\n" +#~ "This assistant will ask you a few basic questions in order to configure " +#~ "GNUnet.\n" +#~ "\n" +#~ "Please visit our homepage at\n" +#~ "\thttp://gnunet.org/\n" +#~ "and join our community at\n" +#~ "\thttp://gnunet.org/drupal/\n" +#~ "\n" +#~ "Have a lot of fun,\n" +#~ "\n" +#~ "the GNUnet team" +#~ msgstr "" +#~ "Xin chào mừng tá»›i GNUnet !\n" +#~ "\n" +#~ "Trình giúp đỡ này sẽ há»i bạn vài câu cÆ¡ bản để cấu hình GNUnet.\n" +#~ "\n" +#~ "Xin hãy thăm trang chủ của chúng tôi tại\n" +#~ "\thttp://gnunet.org\n" +#~ "và tham gia cá»™ng đồng tại\n" +#~ "\thttp://www.gnunet.org/drupal/\n" +#~ "\n" +#~ "Chúc có nhiá»u niá»m vui,\n" +#~ "\n" +#~ "Ä‘á»™i GNUnet" + +#~ msgid "" +#~ "Choose the network interface that connects your computer to the internet " +#~ "from the list below." +#~ msgstr "" +#~ "Chá»n giao diện mạng kết nối máy tính tá»›i Internet từ danh sách dÆ°á»›i đây." + +#~ msgid "" +#~ "The \"Network interface\" is the device that connects your computer to " +#~ "the internet. This is usually a modem, an ISDN card or a network card in " +#~ "case you are using DSL." +#~ msgstr "" +#~ "« Giao diện mạng » là thiết bị kết nối máy tính vá»›i Internet. Äây thÆ°á»ng " +#~ "là má»™t bá»™ Ä‘iá»u giải, má»™t bo mạch ISDN hay má»™t bo mạch mạng nếu dùng DSL." + +#~ msgid "Network configuration: interface" +#~ msgstr "Cấu hình mạng: giao diện" + +#~ msgid "" +#~ "What is the name of the network interface that connects your computer to " +#~ "the Internet?" +#~ msgstr "Máy tính này kết nối tá»›i Internet qua giao diện mạng tên nào?" + +#~ msgid "Network configuration: IP" +#~ msgstr "Cấu hình mạng: IP" + +#~ msgid "What is this computer's public IP address or hostname?" +#~ msgstr "Äịa chỉ IP công cá»™ng hoặc tên của máy tính này là gì?" + +#~ msgid "" +#~ "If your provider always assigns the same IP-Address to you (a \"static\" " +#~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " +#~ "changes every now and then (\"dynamic\" IP-Address) but there's a " +#~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " +#~ "you can also enter it here.\n" +#~ "If left empty, GNUnet will try to automatically detect the IP.\n" +#~ "You can specify a hostname, GNUnet will then use DNS to resolve it.\n" +#~ "If in doubt, leave this empty." +#~ msgstr "" +#~ "Nếu nhà cung cấp luôn luôn gán cùng má»™t địa chỉ IP (má»™t địa chỉ IP « tÄ©nh " +#~ "»), thì hãy nhập địa chỉ đó vào vùng « Äịa chỉ IP ». Nếu địa chỉ IP thay " +#~ "đổi sau má»—i lần kết nối (địa chỉ IP « Ä‘á»™ng ») nhÆ°ng có má»™t tên máy luôn " +#~ "luôn chỉ tá»›i địa chỉ IP thá»±c của bạn (« DNS Ä‘á»™ng »), thì cÅ©ng có thể nhập " +#~ "nó ở đây.\n" +#~ "Nếu không biết phải làm gì, thì hãy để trống. GNUnet sẽ thá»­ tá»± Ä‘á»™ng phát " +#~ "hiện địa chỉ IP.\n" +#~ "Bạn cÅ©ng có thể ghi rõ tên máy. Vì thế GNUnet sẽ dùng dịch vụ DNS để giải " +#~ "quyết nó." + +#~ msgid "Bandwidth configuration: upload" +#~ msgstr "Cấu hình dải thông: tải lên" + +#~ msgid "How much upstream bandwidth (in bytes/s) may be used?" +#~ msgstr "Dòng ra có thể dùng bao nhiêu byte?" + +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "The \"upstream\" is the data channel through which data is *sent* to the " +#~ "internet. The limit is the maximum amount which GNUnet is allowed to use. " +#~ "If you have a flatrate, you can set it to the maximum speed of your " +#~ "internet connection. You should not use a value that is higher than what " +#~ "your actual connection allows." +#~ msgstr "" +#~ "Có thể giá»›i hạn sá»­ dụng tài nguyên của GNUnet ở đây.\n" +#~ "\n" +#~ "« Dòng ra » (upstream) là kênh dữ liệu qua đó _gá»­i_ dữ liệu tá»›i Internet. " +#~ "Giá»›i hạn là số tối Ä‘a được gán cho GNUnet. Nếu có tốc Ä‘á»™ Ä‘á»u, thì có thể " +#~ "đặt thành tốc Ä‘á»™ kết nối Internet lá»›n nhất. Không nên đặt giá trị lá»›n hÆ¡n " +#~ "số được gán cho kết nối Internet của bạn." + +#~ msgid "Bandwidth configuration: download" +#~ msgstr "Cấu hình dải thông: tải xuống" + +#~ msgid "How much downstream bandwidth (in bytes/s) may be used?" +#~ msgstr "Dòng vào có thể dùng bao nhiêu byte?" + +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "The \"downstream\" is the data channel through which data is *received* " +#~ "from the internet. The limit is the maximum amount which GNUnet is " +#~ "allowed to use. If you have a flatrate, you can set it to the maximum " +#~ "speed of your internet connection. You should not use a value that is " +#~ "higher than what your actual connection allows." +#~ msgstr "" +#~ "Có thể giá»›i hạn sá»­ dụng tài nguyên của GNUnet ở đây.\n" +#~ "\n" +#~ "« Dòng vào » (downstream) là kênh dữ liệu qua đó _nhận_ dữ liệu từ " +#~ "Internet. Giá»›i hạn là số tối Ä‘a được gán cho GNUnet. Nếu có tốc Ä‘á»™ Ä‘á»u, " +#~ "thì có thể đặt thành tốc Ä‘á»™ kết nối Internet lá»›n nhất. Không nên đặt giá " +#~ "trị lá»›n hÆ¡n số được gán cho kết nối Internet của bạn." + +#~ msgid "Quota configuration" +#~ msgstr "Cấu hình hạn ngạch" + +#~ msgid "What is the maximum size of the datastore in MB?" +#~ msgstr "Kho dữ liệu có kích cỡ tối Ä‘a (theo MB)?" + +#~ msgid "" +#~ "The GNUnet datastore contains all content that GNUnet needs to store " +#~ "(indexed, inserted and migrated content)." +#~ msgstr "" +#~ "Kho dữ liệu GNUnet chứa tất cả các dữ liệu GNUnet cần cất giữ (dữ liệu " +#~ "chỉ mục, ná»™i dung chèn và nhập vào)." + +#~ msgid "Daemon configuration: user account" +#~ msgstr "Cấu hình trình ná»n: tài khoản ngÆ°á»i dùng" + +#~ msgid "As which user should gnunetd be run?" +#~ msgstr "Trình ná»n gnunetd nên chạy vá»›i tÆ° cách ngÆ°á»i dùng nào?" + +#~ msgid "" +#~ "For security reasons, it is a good idea to let this setup create a new " +#~ "user account under which the GNUnet service is started at system " +#~ "startup.\n" +#~ "\n" +#~ "However, GNUnet may not be able to access files other than its own. This " +#~ "includes files you want to publish in GNUnet. You'll have to grant read " +#~ "permissions to the user specified below.\n" +#~ "\n" +#~ "Leave the field empty to run GNUnet with system privileges.\n" +#~ msgstr "" +#~ "Vì lý do bảo mật, nên cho phép thiết lập này tạo má»™t tài khoản ngÆ°á»i dùng " +#~ "má»›i sở hữu dịch vụ GNUnet chạy má»—i khi khởi Ä‘á»™ng máy tính.\n" +#~ "\n" +#~ "Tuy nhiên, GNUnet có thể không truy cập được tá»›i các tập tin mà nó không " +#~ "sở hữu, bao gồm các tập tin ngÆ°á»i dùng muốn Ä‘Æ°a ra chia sẻ trong GNUnet. " +#~ "Sẽ cần cho phép ngÆ°á»i dùng chỉ ra dÆ°á»›i đây quyá»n Ä‘á»c chúng.\n" +#~ "\n" +#~ "Äể trống để chạy GNUnet vá»›i quyá»n hệ thống.\n" + +#~ msgid "Daemon configuration: group account" +#~ msgstr "Cấu hình trình ná»n: tài khoản nhóm" + +#~ msgid "As which group should gnunetd be run?" +#~ msgstr "gnunetd nên chạy nhÆ° nhóm nào?" + +#~ msgid "" +#~ "For security reasons, it is a good idea to let this setup create a new " +#~ "group for the chosen user account.\n" +#~ "\n" +#~ "You can also specify a already existent group here.\n" +#~ "\n" +#~ "Only members of this group will be allowed to start and stop the the " +#~ "GNUnet server and have access to GNUnet server data.\n" +#~ msgstr "" +#~ "Vì lý do bảo mật, nên để thiết lập này tạo má»™t nhóm má»›i cho tài khoản " +#~ "ngÆ°á»i dùng đã chá»n\n" +#~ "\n" +#~ "CÅ©ng có thể chỉ ra má»™t nhóm đã có.\n" +#~ "\n" +#~ "Chỉ thành viên của nhóm này má»›i có quyá»n chạy và dừng trình phục vụ " +#~ "GNUnet và có truy cập tá»›i dữ liệu của trình phục vụ GNUnet.\n" + +#~ msgid "Do you want to automatically launch GNUnet as a system service?" +#~ msgstr "Bạn có muốn tá»± Ä‘á»™ng khởi chạy GNUnet nhÆ° là dịch vụ hệ thống không?" + +#~ msgid "" +#~ "If you say \"yes\" here, the GNUnet background process will be " +#~ "automatically started when you turn on your computer. If you say \"no\" " +#~ "here, you have to launch GNUnet yourself each time you want to use it." +#~ msgstr "" +#~ "Bật tùy chá»n này thì tiến trình GNUnet ná»n được tá»± Ä‘á»™ng khởi chạy má»—i lần " +#~ "mở máy tính. Không thì bạn cần phải tá»± khởi chạy GNUnet má»—i lần để sá»­ " +#~ "dụng nó." + +#~ msgid "Unable to create user account for daemon." +#~ msgstr "Không thể tạo tài khoản ngÆ°á»i dùng cho trình ná»n." + +#~ msgid "Unable to setup autostart for daemon." +#~ msgstr "Không thể thiết lập chức năng tá»± Ä‘á»™ng khởi chạy cho trình ná»n." + +#~ msgid "Save configuration?" +#~ msgstr "LÆ°u cấu hình không?" + +#~ msgid "GNUnet Configuration" +#~ msgstr "Cấu hình GNUnet" + +#~ msgid "Back" +#~ msgstr "Lùi" + +#~ msgid "Exit" +#~ msgstr "Thoát" + +#~ msgid "Up" +#~ msgstr "Lên" + +#~ msgid "Cancel" +#~ msgstr "Thôi" + +#~ msgid "Internal error! (Value invalid?)" +#~ msgstr "Lá»—i ná»™i bá»™ (giá trị sai ?)" + +#~ msgid "Invalid input, expecting floating point value." +#~ msgstr "Dữ liệu nhập sai, mong đợi giá trị chấm Ä‘á»™ng." + +#~ msgid "Invalid input, expecting integer." +#~ msgstr "Dữ liệu nhập sai, mong đợi số nguyên." + +#~ msgid "Value is not in legal range." +#~ msgstr "Giá trị không nằm trong phạm vi được phép." + +#~ msgid "Configuration unchanged, no need to save.\n" +#~ msgstr "Cấu hình chÆ°a thay đổi thì không cần lÆ°u lại.\n" + +#~ msgid "Do you wish to save your new configuration?" +#~ msgstr "Bạn có muốn lÆ°u cấu hình má»›i không?" + +#~ msgid "" +#~ "\n" +#~ "Your configuration changes were NOT saved.\n" +#~ msgstr "" +#~ "\n" +#~ "CHƯA lÆ°u các thay đổi trong cấu hình.\n" + +#~ msgid "list all network adapters" +#~ msgstr "liệt kê má»i bá»™ tiếp hợp mạng" + +#~ msgid "install GNUnet as Windows service" +#~ msgstr "cài đặt GNUnet nhÆ° là má»™t dịch vụ Windows" + +#~ msgid "increase the maximum number of TCP/IP connections" +#~ msgstr "tăng sổ tối Ä‘a các kết nối TCP/IP" + +#~ msgid "display a file's hash value" +#~ msgstr "hiển thị giá trị tổng kiểm của tập tin" + +#~ msgid "GNUnet service installed successfully.\n" +#~ msgstr "Dịch vụ GNUnet đã được cài đặt.\n" + +#~ msgid "This version of Windows doesn't support services.\n" +#~ msgstr "Phiên bản Windows này không há»— trợ dịch vụ.\n" + +#~ msgid "Error: can't open Service Control Manager: %s\n" +#~ msgstr "Lá»—i: không thể mở Bá»™ Quản lý Äiá»u khiển Dịch vụ : %s\n" + +#~ msgid "Error: can't create service: %s\n" +#~ msgstr "Lá»—i: không thể tạo dịch vụ : %s\n" + +#~ msgid "Error: can't access service: %s\n" +#~ msgstr "Lá»—i: không thể truy cập đến dịch vụ : %s\n" + +#~ msgid "Error: can't delete service: %s\n" +#~ msgstr "Lá»—i: không thể xoá dịch vụ : %s\n" + +#~ msgid "Configuration changed. Save?" +#~ msgstr "Cấu hình bị thay đổi. LÆ°u ?" + +#~ msgid "Error saving configuration." +#~ msgstr "Gặp lá»—i khi lÆ°u cấu hình." + +#~ msgid "(unknown connection)" +#~ msgstr "(không rõ kết nối)" + +#~ msgid "Do you want to save the new configuration?" +#~ msgstr "Bạn có muốn lÆ°u cấu hình má»›i này không?" + +#~ msgid "Unable to change startup process:" +#~ msgstr "Không thể thay đổi tiến trình khởi chạy:" + +#~ msgid "" +#~ "Running gnunet-update failed.\n" +#~ "This maybe due to insufficient permissions, please check your " +#~ "configuration.\n" +#~ "Finally, run gnunet-update manually." +#~ msgstr "" +#~ "Lá»—i chạy tiến trình cập nhật gnunet-update.\n" +#~ "Äây có thể do không đủ quyá»n, hãy kiểm tra cấu hình.\n" +#~ "Cuối cùng, chạy gnunet-update thủ công." + +#~ msgid "Can only set one option per invocation.\n" +#~ msgstr "Chỉ có thể đặt má»™t tùy chá»n trong má»—i cuá»™c gá»i.\n" + +#~ msgid "" +#~ "Invalid syntax, argument to 'set' must have the format SECTION:" +#~ "OPTION=VALUE.\n" +#~ msgstr "" +#~ "Cú pháp sai, đối số tá»›i « set » phải theo định dạng:\n" +#~ "PHẦN:TÙY_CHỌN­=GIÃ_TRỊ\n" + +#~ msgid "Can only display one option per invocation.\n" +#~ msgstr "Chỉ có thể hiển thị má»™t tùy chá»n trong má»—i cuá»™c gá»i.\n" + +#~ msgid "" +#~ "Invalid syntax, argument to 'get' must have the format SECTION:OPTION.\n" +#~ msgstr "" +#~ "Cú pháp sai, đối số tá»›i « get » phải theo định dạng:\n" +#~ "PHẦN:TÙY_CHỌN\n" + +#~ msgid "generate configuration for gnunetd, the GNUnet daemon" +#~ msgstr "tạo ra cấu hình cho gnunetd, trình ná»n GNUnet" + +#~ msgid "Tool to setup GNUnet." +#~ msgstr "Công cụ để thiết lập GNUnet." + +#~ msgid "Too many arguments.\n" +#~ msgstr "Quá nhiá»u đối số.\n" + +#~ msgid "No interface specified, using default.\n" +#~ msgstr "ChÆ°a xác định giao diện nên dùng mặc định.\n" + +#~ msgid "Undefined option.\n" +#~ msgstr "Tùy chá»n không xác định.\n" + +#~ msgid "Unknown operation '%s'.\n" +#~ msgstr "Không rõ thao tác « %s ».\n" + +#~ msgid "yes" +#~ msgstr "có" + +#~ msgid "no" +#~ msgstr "không" + +#~ msgid "\tEnter yes (%s), no (%s) or help (%s): " +#~ msgstr "\tNhập có (%s), không (%s) hoặc trợ giúp (%s): " + +#~ msgid "\tPossible choices:\n" +#~ msgstr "\tLá»±a chá»n có thể:\n" + +#~ msgid "\tUse single space prefix to avoid conflicts with hotkeys!\n" +#~ msgstr "\tHãy dùng tiá»n tố má»™t dấu cách để tránh xung Ä‘á»™t vá»›i phím nóng.\n" + +#~ msgid "\tEnter string (type '%s' for default value `%s'): " +#~ msgstr "\tNhập chuá»—i (gõ « %s » cho giá trị mặc định « %s »): " + +#~ msgid "\t Enter choice (default is %c): " +#~ msgstr "\t Nhập sá»± chá»n (mặc định là %c):" + +#~ msgid "\tEnter floating point (type '%s' for default value %f): " +#~ msgstr "\tNhập chấm Ä‘á»™ng (gõ « %s » cho giá trị mặc định %f): " + +#~ msgid "" +#~ "\tEnter unsigned integer in interval [%llu,%llu] (type '%s' for default " +#~ "value %llu): " +#~ msgstr "" +#~ "\tNhập số nguyên không có dấu trong khoảng [%llu,%llu] (gõ « %s » cho giá " +#~ "trị mặc định %llu): " + +#~ msgid "Yes\n" +#~ msgstr "Có\n" + +#~ msgid "No\n" +#~ msgstr "Không\n" + +#~ msgid "Help\n" +#~ msgstr "Trợ giúp\n" + +#~ msgid "Abort\n" +#~ msgstr "Hủy bá»\n" + +#~ msgid "" +#~ "\n" +#~ "Invalid entry, try again (use '?' for help): " +#~ msgstr "" +#~ "\n" +#~ "Dữ liệu nhập sai. Hãy thá»­ lại (dùng « ? » để xem trợ giúp): " + +#~ msgid "Unknown kind %x (internal error). Skipping option.\n" +#~ msgstr "Kiểu không rõ %x (lá»—i ná»™i bá»™). Äang bá» qua tùy chá»n.\n" + +#~ msgid "\tDescend? (y/n/?) " +#~ msgstr "\tGiảm dần ? (c/k?)" + +#~ msgid "Aborted.\n" +#~ msgstr "Bị hủy bá».\n" + +#~ msgid "Unknown kind %x (internal error). Aborting.\n" +#~ msgstr "Kiểu không rõ %x (lá»—i ná»™i bá»™). Äang hủy bá».\n" + +#~ msgid "You can always press ENTER to keep the current value.\n" +#~ msgstr "" +#~ "Lúc nào bạn cÅ©ng có thể bấm phím Enter để giữ lại giá trị hiện có.\n" + +#~ msgid "Use the '%s' key to abort.\n" +#~ msgstr "Dùng phím « %s » để hủy bá».\n" + +#~ msgid "" +#~ "Save configuration? Answer 'y' for yes, 'n' for no, 'r' to repeat " +#~ "configuration. " +#~ msgstr "" +#~ "LÆ°u lại cấu hình không?\n" +#~ " • y\t\tcó\n" +#~ " • n\t\tkhông\n" +#~ " • r\t\tlặp lại cấu hình." + +#~ msgid "Configuration was unchanged, no need to save.\n" +#~ msgstr "Cấu hình chÆ°a thay đổi thì không cần lÆ°u lại.\n" + +#~ msgid "" +#~ "Internal error: entry `%s' in section `%s' not found for visibility " +#~ "change!\n" +#~ msgstr "" +#~ "Lá»—i ná»™i bá»™ : mục nhập « %s » trong phần « %s » không tìm thấy để thay đổi " +#~ "tình trạng hiển rõ.\n" + +#~ msgid "Can't open Service Control Manager" +#~ msgstr "Không thể mở Bá»™ Quản lý Äiá»u khiển Dịch vụ" + +#~ msgid "Can't create service" +#~ msgstr "Không thể tạo dịch vụ" + +#~ msgid "Error changing the permissions of the GNUnet directory" +#~ msgstr "Gặp lá»—i khi thay đổi quyá»n hạn của thÆ° mục GNUnet" + +#~ msgid "Cannot write to the registry" +#~ msgstr "Không thể ghi vào sổ đăng ký" + +#~ msgid "Can't delete the service" +#~ msgstr "Không thể xoá dịch vụ" + +#~ msgid "This version of Windows does not support multiple users." +#~ msgstr "Phiên bản Windows này không có há»— trợ Ä‘a ngÆ°á»i dùng." + +#~ msgid "Error accessing local security policy" +#~ msgstr "Gặp lá»—i khi truy cập đến chính sách bảo mật cục bá»™" + +#~ msgid "Error granting service right to user" +#~ msgstr "Gặp lá»—i khi cấp quyá»n dịch vụ cho ngÆ°á»i dùng" + +#~ msgid "Unknown error while creating a new user" +#~ msgstr "Gặp lá»—i không rõ trong khi tạo má»™t ngÆ°á»i dùng má»›i" + +#~ msgid "" +#~ "\n" +#~ "Press any key to continue\n" +#~ msgstr "" +#~ "\n" +#~ "Hãy bấm bất cứ phím nào để tiếp tục.\n" + +#~ msgid "STATUS" +#~ msgstr "TRẠNG THÃI" + +#~ msgid "FATAL" +#~ msgstr "NGHIÊM TRỌNG" + +#~ msgid "USER" +#~ msgstr "NGƯỜI DÙNG" + +#~ msgid "ADMIN" +#~ msgstr "QUẢN TRỊ" + +#~ msgid "DEVELOPER" +#~ msgstr "NHÀ PHÃT TRIỂN" + +#~ msgid "REQUEST" +#~ msgstr "YÊU CẦU" + +#~ msgid "BULK" +#~ msgstr "HÀNG LOẠT" + +#~ msgid "IMMEDIATE" +#~ msgstr "NGAY" + +#~ msgid "ALL" +#~ msgstr "TẤT CẢ" + +#~ msgid "NOTHING" +#~ msgstr "KHÔNG GÃŒ" + +#, fuzzy +#~ msgid "Could not find valid value for HOST in section NETWORK.\n" +#~ msgstr "Không tìm thấy giá trị đúng cho MÃY trong phần MẠNG." + +#, fuzzy +#~ msgid "Syntax error in configuration entry HOST in section NETWORK: `%s'\n" +#~ msgstr "Gặp lá»—i cú pháp trong mục nhập cấu hình MÃY trong phần MẠNG: « %s »" + +#~ msgid "Error connecting to %s:%u. Is the daemon running?\n" +#~ msgstr "Gặp lá»—i khi kết nối tá»›i %s:%u. Trình ná»n Ä‘ang chạy không?\n" + +#~ msgid "Reading result from gnunetd failed, reply invalid!\n" +#~ msgstr "Lá»—i Ä‘á»c kết quả từ gnunetd, đáp ứng không hợp lệ.\n" + +#~ msgid "" +#~ "Setting option `%s' in section `%s' to `%s' when processing command line " +#~ "option `%s' was denied.\n" +#~ msgstr "" +#~ "Bị từ chối đặt tùy chá»n « %s » trong phần « %s » thành « %s » khi xá»­ lý " +#~ "tùy chá»n dòng lệnh « %s ».\n" + +#~ msgid "No interface specified in section `%s' under `%s'!\n" +#~ msgstr "" +#~ "Không có giao diện mạng được xác định trong cấu hình phần « %s » dÆ°á»›i « " +#~ "%s ».\n" + +#~ msgid "Could not obtain IP for interface `%s' using `%s'.\n" +#~ msgstr "Không thể lấy địa chỉ IP cho giao diện « %s », dùng « %s ».\n" + +#~ msgid "" +#~ "Could not find interface `%s' using `%s', trying to find another " +#~ "interface.\n" +#~ msgstr "" +#~ "Không tìm thấy giao diện « %s » trong « %s », Ä‘ang thá»­ tìm giao diện " +#~ "khác.\n" + +#~ msgid "Could not find an IP address for interface `%s'.\n" +#~ msgstr "Không tìm thấy má»™t địa chỉ IP cho giao diện « %s ».\n" + +#~ msgid "" +#~ "There is more than one IP address specified for interface `%s'.\n" +#~ "GNUnet will use %s.\n" +#~ msgstr "" +#~ "Có vài địa chỉ IP chỉ ra cho giao diện « %s ».\n" +#~ "GNUnet sẽ dùng %s.\n" + +#~ msgid "Could not resolve `%s' to determine our IP address: %s\n" +#~ msgstr "" +#~ "Không thể giải quyết « %s » để quyết định địa chỉ IP của chúng ta: %s\n" + +#~ msgid "Received malformed message (too small) from connection. Closing.\n" +#~ msgstr "Nhận được thông báo bị há»ng (quá nhá») từ kết nối. Äang đóng.\n" + +#~ msgid "select listen socket for `%s' not valid!\n" +#~ msgstr "sai chá»n ổ cắm lắng nghe cho « %s »\n" + +#~ msgid "" +#~ "Configuration value '%llu' for '%s' in section '%s' is out of legal " +#~ "bounds [%llu,%llu]\n" +#~ msgstr "" +#~ "Giá tri cấu hình « %llu » cho « %s » trong phần « %s » ở ngoại phạm vi " +#~ "được phép [%llu,%llu]\n" + +#~ msgid "`%s' returned with error code %u" +#~ msgstr "« %s » trả lại vá»›i mã lá»—i %u" + +#~ msgid "Can't create semaphore: %i" +#~ msgstr "Không thể tạo cá» hiệu : %i" + +#~ msgid "Cannot query the CPU usage (Windows NT).\n" +#~ msgstr "Không há»i được sá»± sá»­ dụng CPU (Windows NT).\n" + +#~ msgid "Cannot query the CPU usage (Win 9x)\n" +#~ msgstr "Không há»i được sá»± sá»­ dụng CPU (Windows 9x).\n" + +#~ msgid "" +#~ "No network interfaces defined in configuration section `%s' under `%s'!\n" +#~ msgstr "" +#~ "Không có giao diện mạng được xác định trong cấu hình phần « %s » dÆ°á»›i « " +#~ "%s ».\n" + +#~ msgid "Setting open descriptor limit not supported.\n" +#~ msgstr "Không há»— trợ chức năng đặt giá»›i hạn bá»™ mô tả còn mở.\n" + +#~ msgid "Command `%s' failed with error code %u\n" +#~ msgstr "Câu lệnh « %s » đã thất bại vá»›i mã lá»—i %u\n" + +#~ msgid "Real-time delay violation (%llu ms) at %s:%u\n" +#~ msgstr "Xâm phạm khoảng đợi thá»i gian thá»±c (%llu miligiây) tại %s:%u\n" + +#~ msgid "`%s' failed with error code %d: %s\n" +#~ msgstr "« %s » thất bại vá»›i mã lá»—i %d: %s\n" + +#~ msgid "Deadlock due to `%s'.\n" +#~ msgstr "Bế tắc do « %s ».\n" + +#~ msgid "Lock acquired for too long (%llu ms) at %s:%u\n" +#~ msgstr "Khoá đặt được quá lâu (%llu miligiây) tại %s:%u\n" + +#~ msgid "GNUnet error log" +#~ msgstr "Bản ghi lá»—i GNUnet" + +#~ msgid "Out of memory (for logging)\n" +#~ msgstr "Tràn bá»™ nhá»› (để ghi sá»± kiện)\n" + +#~ msgid "Availability test failed for `%s' at %s:%d.\n" +#~ msgstr "Lá»—i kiểm tra tình trạng sẵn sàng cho « %s » tại %s:%d.\n" + +#~ msgid "# bloom filter false positives" +#~ msgstr "# các dÆ°Æ¡ng giả của bá»™ lá»c bloom" + +#~ msgid "Failed to load state service. Trying to do without.\n" +#~ msgstr "Lá»—i nạp dịch vụ tình trạng. Không có nhÆ°ng vẫn Ä‘ang thá»­ tiếp tục.\n" + +#~ msgid "Datastore conversion at approximately %u%%\n" +#~ msgstr "Chuyển đổi kho dữ liệu theo xấp xỉ %u%%\n" + +#~ msgid "Starting datastore conversion (this may take a while).\n" +#~ msgstr "Äang bắt đầu chuyển đổi kho dữ liệu (có thể hÆ¡i lâu).\n" + +#~ msgid "Completed datastore conversion.\n" +#~ msgstr "Hoàn tất chuyển đổi kho dữ liệu.\n" + +#~ msgid "" +#~ "%s:%d - RPC %s:%p could not be registered: another callback is already " +#~ "using this name (%p)\n" +#~ msgstr "" +#~ "%s:%d - RPC %s:%p không đăng ký được: má»™t cuá»™c gá»i ngược lại khác Ä‘ang " +#~ "dùng tên này (%p)\n" + +#~ msgid "%s:%d - async RPC %s:%p could not be unregistered: not found\n" +#~ msgstr "" +#~ "%s:%d - RPC không đồng bá»™ %s:%p không hủy đăng ký được: không tìm thấy\n" + +#~ msgid "`%s' registering handlers %d %d %d\n" +#~ msgstr "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển %d %d %d\n" + +#~ msgid "Using %u messages of size %u for %u times.\n" +#~ msgstr "Sá»­ dụng %u thông báo vá»›i kích cỡ %u trong %u lần.\n" + +#~ msgid "Times: max %16llu min %16llu mean %12.3f variance %12.3f\n" +#~ msgstr "Thá»i gian: đại %16llu tiểu %16llu t.bình %12.3f ph.sai %12.3f\n" + +#~ msgid "Loss: max %16u min %16u mean %12.3f variance %12.3f\n" +#~ msgstr "Mất: đại %16u tiểu %16u t.bình %12.3f ph.sai %12.3f\n" + +#~ msgid "Running benchmark...\n" +#~ msgstr "Äang chạy tiến trình kiểm chuẩn...\n" + +#~ msgid "allows profiling of direct peer-to-peer connections" +#~ msgstr "cho phép Ä‘o hiệu năng sá»­ dụng của kết nối đồng đẳng trá»±c tiếp" + +#~ msgid "Start GNUnet transport benchmarking tool." +#~ msgstr "Khởi chạy công cụ kiểm chuẩn truyá»n tải của GNUnet." + +#~ msgid "output in gnuplot format" +#~ msgstr "kết xuất theo định dạng gnuplot" + +#~ msgid "number of iterations" +#~ msgstr "số lần lặp lại" + +#~ msgid "number of messages to use per iteration" +#~ msgstr "số tin nhắn cần dùng má»—i lần lặp" + +#~ msgid "receiver host identifier (ENC file name)" +#~ msgstr "đồ nhận diện máy nhận (tên tập tin mã hoá)" + +#~ msgid "message size" +#~ msgstr "kích cỡ tin nhắn" + +#~ msgid "sleep for SPACE ms after each a message block" +#~ msgstr "ngủ KHOẢNG miligiây sau má»—i khối tin nhắn" + +#~ msgid "number of messages in a message block" +#~ msgstr "số tin nhắn trong má»™t khối tin nhắn" + +#~ msgid "Error establishing connection with gnunetd.\n" +#~ msgstr "Lá»—i thiết lập kết nối đến gnunetd.\n" + +#~ msgid "You must specify a receiver!\n" +#~ msgstr "Phải ghi rõ má»™t máy nhận.\n" + +#~ msgid "Invalid receiver peer ID specified (`%s' is not valid name).\n" +#~ msgstr "" +#~ "Chỉ ra mã số đồng đẳng nhận sai (« %s » không phải là má»™t tên đúng).\n" + +#~ msgid "Time:\n" +#~ msgstr "Thá»i gian:\n" + +#~ msgid "\tmax %llums\n" +#~ msgstr "\tđại %llu mg\n" + +#~ msgid "\tmin %llums\n" +#~ msgstr "\ttiểu %llu mg\n" + +#~ msgid "\tmean %8.4fms\n" +#~ msgstr "\ttrung bình %8.4f mg\n" + +#~ msgid "\tvariance %8.4fms\n" +#~ msgstr "\tphÆ°Æ¡ng sai %8.4f mg\n" + +#~ msgid "Loss:\n" +#~ msgstr "Mất:\n" + +#~ msgid "\tmax %u\n" +#~ msgstr "\tđại %u\n" + +#~ msgid "\tmin %u\n" +#~ msgstr "\ttiểu %u\n" + +#~ msgid "\tmean %8.4f\n" +#~ msgstr "\tt.bình %8.4f\n" + +#~ msgid "\tvariance %8.4f\n" +#~ msgstr "\tph.sai %8.4f\n" + +#~ msgid "Output format not known, this should not happen.\n" +#~ msgstr "Äịnh dạng kết xuất không rõ, Ä‘iá»u này không nên xảy ra.\n" + +#~ msgid "" +#~ "\n" +#~ "Did not receive the message from gnunetd. Is gnunetd running?\n" +#~ msgstr "" +#~ "\n" +#~ "Không nhận được thông báo từ gnunetd. Trình ná»n gnunetd Ä‘ang chạy không?\n" + +#~ msgid "# bytes received in plaintext of type %d" +#~ msgstr "# các byte nhập thô kiểu %d được nhận" + +#, fuzzy +#~ msgid "# bytes allocated by SQLite" +#~ msgstr "# các byte được phép trong kho dữ liệu" + +#~ msgid "" +#~ "Failed to load MySQL database module. Check that MySQL is running and " +#~ "configured properly!\n" +#~ msgstr "" +#~ "Lá»—i nạp mô-Ä‘un cÆ¡ sở dữ liệu MySQL. Hãy kiểm tra lại MySQL Ä‘ang chạy và " +#~ "có cấu hình đúng.\n" + +#~ msgid "probe network to the given DEPTH" +#~ msgstr "dò mạng tá»›i Ä‘á»™ sâu SÂU Ä‘Æ°a ra" + +#~ msgid "" +#~ "specify output format; 0 for human readable output, 1 for dot, 2 for vcg" +#~ msgstr "" +#~ "chỉ ra định dạng kết quả;\n" +#~ " • 0\t\tkết xuất cho ngÆ°á»i Ä‘á»c được\n" +#~ " • 1\t\tdấu chấm\n" +#~ " • 2\t\tvcg" + +#~ msgid "use PRIORITY for the priority of the trace request" +#~ msgstr "dùng ƯU_TIÊN làm Æ°u tiên của yêu cầu tìm Ä‘Æ°á»ng" + +#~ msgid "wait DELAY seconds for replies" +#~ msgstr "đợi đáp ứng TRỄ giây" + +#~ msgid "" +#~ "Format specification invalid. Use 0 for user-readable, 1 for dot, 2 for " +#~ "vcg.\n" +#~ msgstr "" +#~ "Äặt tả định dạng sai. Dùng:\n" +#~ " • 0\t\tkết xuất cho ngÆ°á»i Ä‘á»c được\n" +#~ " • 1\t\tdấu chấm\n" +#~ " • 2\t\tvcg\n" + +#~ msgid "allows mapping of the network topology" +#~ msgstr "cho phép ánh xạ địa hình của mạng" + +#~ msgid "HELLO message from `%s' has an invalid signature. Dropping.\n" +#~ msgstr "Thông báo HELLO từ « %s » có chữ ký sai. Äang bá» Ä‘i.\n" + +#~ msgid "HELLO message has expiration too far in the future. Dropping.\n" +#~ msgstr "Thông báo HELLO hết hạn trong tÆ°Æ¡ng lai quá nhiá»u. Äang bá» Ä‘i.\n" + +#~ msgid "Could not send HELLO+PING, ping buffer full.\n" +#~ msgstr "Không gá»­i được tín hiệu HELLO+PING, đầy bá»™ đệm ping.\n" + +#~ msgid "" +#~ "Failed to create an advertisement for this peer. Will not send PING.\n" +#~ msgstr "" +#~ "Không tạo được quảng cáo cho đồng đẳng này. Sẽ không gá»­i tín hiệu PING.\n" + +#~ msgid "" +#~ "Announcing ourselves pointless: no other peers are known to us so far.\n" +#~ msgstr "Không có nghÄ©a khi tá»± thông báo : chÆ°a biết đồng đẳng khác.\n" + +#~ msgid "# Peer advertisements of type NAT received" +#~ msgstr "# Các quảng cáo đồng đẳng kiểu NAT được nhận" + +#~ msgid "# Peer advertisements updating earlier HELLOs" +#~ msgstr "# Các quảng cáo đồng đẳng cập nhật tin hiệu HELLO trÆ°á»›c" + +#~ msgid "# Peer advertisements for unsupported transport" +#~ msgstr "# Các quảng cáo đồng đẳng cho truyá»n tải không được há»— trợ" + +#~ msgid "# Peer advertisements not confirmed due to ping busy" +#~ msgstr "# Các quảng cáo đồng đẳng không được xác nhận do ping Ä‘ang bận" + +#~ msgid "# Peer advertisements not confirmed due to lack of self ad" +#~ msgstr "# Các quảng cáo đồng đẳng không được xác nhận do không tá»± quảng cáo" + +#~ msgid "# Peer advertisements not confirmed due to send error" +#~ msgstr "# Các quảng cáo đồng đẳng không được xác nhận do lá»—i gá»­i" + +#~ msgid "`%s' registering handler %d (plaintext and ciphertext)\n" +#~ msgstr "" +#~ "« %s » Ä‘ang đăng ký trình Ä‘iá»u khiển %d (nhập thô và văn bản mã hóa)\n" + +#~ msgid "" +#~ "ensures that this peer is known by other peers and discovers other peers" +#~ msgstr "" +#~ "đảm bảo là đồng đẳng này được biết bởi và phát hiện các đồng đẳng khác" + +#~ msgid "`%s' registering handler %d\n" +#~ msgstr "« %s » Ä‘ang đăng ký trình Ä‘iá»u khiển %d\n" + +#~ msgid "maintains GNUnet default mesh topology" +#~ msgstr "bảo quản định hình mắc lÆ°á»›i mặc định của GNUnet" + +#~ msgid "`%s' registering CS handlers %d and %d\n" +#~ msgstr "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển CS %d và %d\n" + +#~ msgid "enables P2P-chat (incomplete)" +#~ msgstr "hiệu lá»±c trò chuyện giữa các đồng đẳng (chÆ°a hoàn tất)" + +#~ msgid "Existing key in file `%s' failed format check, creating new key.\n" +#~ msgstr "" +#~ "Kiểm tra định dạng của chìa khóa đã có trong tập tin « %s » không thành " +#~ "công, Ä‘ang tạo chìa khóa máy má»›i.\n" + +#~ msgid "Creating new key for this nickname (this may take a while).\n" +#~ msgstr "Äang tạo khoá má»›i cho tên hiệu này (có thể hÆ¡i lâu).\n" + +#~ msgid "# max bytes allowed in dstore" +#~ msgstr "# các byte được phép trong kho dữ liệu dstore" + +#~ msgid "" +#~ "Converting peer address to string failed, transport type %d not " +#~ "supported\n" +#~ msgstr "" +#~ "Lá»—i chuyển đổi địa chỉ đồng đẳng sang chuá»—i, kiểu truyá»n tải %d không " +#~ "được há»— trợ\n" + +#~ msgid "" +#~ "Transport connection attempt failed, transport type %d not supported\n" +#~ msgstr "" +#~ "Lá»—i thá»­ kết nối truyá»n tải, kiểu cÆ¡ chế truyá»n %d không được há»— trợ\n" + +#~ msgid "" +#~ "Transport failed to connect to peer `%s' (%u HELLOs known, none worked)\n" +#~ msgstr "" +#~ "Truyá»n tải không kết nối được tá»›i đồng đẳng « %s » (đã biết %u tín hiệu " +#~ "HELLO, mà không có tín hiệu nào hoạt Ä‘á»™ng được)\n" + +#~ msgid "No transport succeeded in creating a hello!\n" +#~ msgstr "Không có truyá»n tải nào đã tạo được má»™t tín hiệu HELLO.\n" + +#~ msgid "Transport library `%s' did not provide required function '%s%s'.\n" +#~ msgstr "" +#~ "ThÆ° viện truyá»n tải « %s » không cung cấp chức năng yêu cầu « %s%s ».\n" + +#~ msgid "Query (get KEY, put KEY VALUE) DHT table." +#~ msgstr "Há»i (nhận KHOÃ, gá»­i GIÃ_TRỊ_KHOÃ) bảng DHT." + +#~ msgid "allow TIME ms to process a GET command" +#~ msgstr "cho phép THỜI_GIAN mili giây để xá»­ lý má»—i câu lệnh GET (lấy)" + +#~ msgid "Issuing `%s(%s,%s)' command.\n" +#~ msgstr "Äang cấp câu lệnh « %s(%s,%s) ».\n" + +#~ msgid "Command `%s' requires an argument (`%s').\n" +#~ msgstr "Câu lệnh « %s » cần đến má»™t đối số (« %s »).\n" + +#~ msgid "Command `%s' requires two arguments (`%s' and `%s').\n" +#~ msgstr "Câu lệnh « %s » cần đến hai đối số (« %s » và « %s »).\n" + +#~ msgid "Unsupported command `%s'. Aborting.\n" +#~ msgstr "Lệnh không được há»— trợ « %s ». Äang hủy bá».\n" + +#~ msgid "# dht route host lookups performed" +#~ msgstr "# các việc tra tìm Ä‘Æ°á»ng tá»›i máy dht được làm" + +#~ msgid "# dht discovery messages sent" +#~ msgstr "# các thông báo phát hiện dht được gá»­i" + +#~ msgid "# dht put requests received" +#~ msgstr "# các yêu cầu put (gá»­i) dht được nhận" + +#~ msgid "`%s' registering p2p handlers: %d %d %d\n" +#~ msgstr "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển p2p: %d %d %d\n" + +#~ msgid "`%s' failed. Terminating connection to client.\n" +#~ msgstr "« %s » bị lá»—i. Äang chấm dứt kết nối tá»›i máy khách.\n" + +#~ msgid "`%s' registering client handlers: %d %d\n" +#~ msgstr "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển máy khách: %d %d\n" + +#~ msgid "Enables efficient non-anonymous routing" +#~ msgstr "Hiệu lá»±c định tuyến khác nặc danh hiệu dụng" + +#~ msgid "" +#~ "Existing hostkey in file `%s' failed format check, creating new hostkey.\n" +#~ msgstr "" +#~ "Kiểm tra định dạng của chìa khóa máy trong tập tin « %s » không thành " +#~ "công, Ä‘ang tạo chìa khóa máy má»›i.\n" + +#~ msgid "Done creating hostkey.\n" +#~ msgstr "Hoàn thành tạo khoá máy.\n" + +#~ msgid "Removed file `%s' containing invalid HELLO data.\n" +#~ msgstr "Äã gỡ bá» tập tin « %s » chứa dữ liệu HELLO sai.\n" + +#~ msgid "Signature failed verification: signature invalid.\n" +#~ msgstr "Không thẩm tra được chữ ký: chữ ký sai.\n" + +#~ msgid "Peer `%s' is currently strictly blacklisted (for another %llums).\n" +#~ msgstr "" +#~ "Äồng đẳng « %s » hiện thá»i bị cấm hoàn toàn (trong %llu miligiây sau).\n" + +#~ msgid "Peer `%s' is currently blacklisted (for another %llums).\n" +#~ msgstr "Äồng đẳng « %s » hiện thá»i bị cấm (trong %llu miligiây sau).\n" + +#~ msgid "Received malformed `%s' message. Dropping.\n" +#~ msgstr "Nhận được thông báo « %s » bị há»ng. Äang bá» Ä‘i.\n" + +#~ msgid "Received ping for another peer. Dropping.\n" +#~ msgstr "Nhận được tin hiệu ping cho đồng đẳng khác. Äang bá» Ä‘i.\n" + +#~ msgid "" +#~ "Could not match PONG against any PING. Try increasing MAX_PING_PONG " +#~ "constant.\n" +#~ msgstr "" +#~ "Không tÆ°Æ¡ng ứng được PONG đối vá»›i bất kỳ PING. Hãy thá»­ tăng hằng số " +#~ "MAX_PING_PONG.\n" + +#~ msgid "Cannot create PING, table full. Try increasing MAX_PING_PONG.\n" +#~ msgstr "Không tạo được PING, bảng đầy. Hãy thá»­ tăng MAX_PING_PONG.\n" + +#~ msgid "# plaintext PONG messages received" +#~ msgstr "# các thông báo PONG nhập thô được nhận" + +#~ msgid "# encrypted PING messages received" +#~ msgstr "# các thông báo PING đã mật mã được nhận" + +#~ msgid "# encrypted PING messages sent" +#~ msgstr "# các thông báo PING đã mật mã được gá»­i" + +#~ msgid "`%s' registering handlers %d %d (plaintext and ciphertext)\n" +#~ msgstr "" +#~ "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển %d %d (nhập thô và văn bản mã " +#~ "hóa)\n" + +#~ msgid "# hostlist HELLOs returned" +#~ msgstr "# các lá»i chào mừng HELLO danh sách máy được trả vá»" + +#~ msgid "Cannot encrypt sessionkey, peer `%s' not known!\n" +#~ msgstr "Không thể mã hoá khoá phiên chạy, không rõ đồng đẳng « %s ».\n" + +#~ msgid "Could not create any HELLO for myself (have transports `%s')!\n" +#~ msgstr "Không thể tạo tín hiệu HELLO nào cho mình (có truyá»n tải « %s »).\n" + +#~ msgid "" +#~ "Session key received from peer `%s' has invalid format (discarded).\n" +#~ msgstr "" +#~ "Khoá phiên chạy được nhận từ đồng đẳng « %s » có định dạng sai (bị hủy).\n" + +#~ msgid "Session key received from peer `%s' is for `%s' and not for me!\n" +#~ msgstr "" +#~ "Khoá phiên chạy được nhận từ đồng đẳng « %s » dành cho « %s », không phải " +#~ "cho tôi.\n" + +#~ msgid "setkey `%s' from `%s' fails CRC check (have: %u, want %u).\n" +#~ msgstr "" +#~ "Kiểm tra CRC setkey « %s » từ « %s » không thành công (có %u, còn muốn " +#~ "%u).\n" + +#~ msgid "" +#~ "Error parsing encrypted session key from `%s', given message part size is " +#~ "invalid.\n" +#~ msgstr "" +#~ "Lá»—i phân tích chìa khóa phiên chạy đã mã hóa từ « %s », kích cỡ của phần " +#~ "thông báo Ä‘Æ°a ra là sai.\n" + +#~ msgid "Unknown type in embedded message from `%s': %u (size: %u)\n" +#~ msgstr "" +#~ "Gặp kiểu không rõ trong thông báo nhúng từ « %s »: %u (kích cỡ : %u)\n" + +#~ msgid "# sessions established" +#~ msgstr "# các phiên chạy được thiết lập" + +#~ msgid "automate creation of a namespace by starting a collection" +#~ msgstr "tá»± Ä‘á»™ng tạo má»™t không gian tên bằng cách bắt đầu má»™t thu thập" + +#~ msgid "create a new pseudonym under the given NICKNAME" +#~ msgstr "tạo má»™t biệt hiệu má»›i dÆ°á»›i TÊN_HIỆU Ä‘Æ°a ra" + +#~ msgid "delete the pseudonym with the given NICKNAME" +#~ msgstr "xoá biệt hiệu có TÊN_HIỆU đã cho" + +#~ msgid "end automated building of a namespace (ends collection)" +#~ msgstr "" +#~ "kết thúc việc tá»± Ä‘á»™ng xây dá»±ng má»™t không gian tên (kết thúc thu thập)" + +#~ msgid "" +#~ "Create new pseudonyms, delete pseudonyms or list existing pseudonyms." +#~ msgstr "Tạo biệt hiệu má»›i, xóa biệt hiệu hoặc liệt kê các biệt hiệu có." + +#~ msgid "" +#~ "use the given keyword to advertise the namespace (use when creating a new " +#~ "pseudonym)" +#~ msgstr "" +#~ "sá»­ dụng từ khóa Ä‘Æ°a ra để quảng cáo không gian tên (dùng khi tạo má»™t biệt " +#~ "hiệu má»›i)" + +#~ msgid "specify metadata describing the namespace or collection" +#~ msgstr "ghi rõ siêu dữ liệu mô tả không gian tên (hoặc thu thập)" + +#~ msgid "" +#~ "do not generate an advertisement for this namespace (use when creating a " +#~ "new pseudonym)" +#~ msgstr "" +#~ "đừng tạo ra má»™t quảng cáo cho không gian tên này (dùng khi tạo má»™t biệt " +#~ "hiệu má»›i)" + +#~ msgid "do not list the pseudonyms from the pseudonym database" +#~ msgstr "không liệt kê các biệt hiệu từ cÆ¡ sở dữ liệu biệt hiệu" + +#~ msgid "" +#~ "specify IDENTIFIER to be the address of the entrypoint to content in the " +#~ "namespace (use when creating a new pseudonym)" +#~ msgstr "" +#~ "ghi rõ BỘ_NHẬN_DIỆN là địa chỉ của Ä‘iểm vào ná»™i dung trong không gian tên " +#~ "(dùng khi tạo má»™t biệt hiệu má»›i)" + +#~ msgid "Namespace `%s' (%s) has rating %d.\n" +#~ msgstr "Không gian tên « %s » (%s) có đánh giá %d.\n" + +#~ msgid "\tRating (after update): %d\n" +#~ msgstr "\tÄánh giá (sau khi cập nhật): %d\n" + +#~ msgid "Collection stopped.\n" +#~ msgstr "Thu thập bị dừng.\n" + +#~ msgid "Failed to stop collection (not active?).\n" +#~ msgstr "Lá»—i dừng thu thập (không hoạt Ä‘á»™ng ?).\n" + +#~ msgid "Pseudonym `%s' deleted.\n" +#~ msgstr "Biệt hiệu « %s » bị xoá.\n" + +#~ msgid "Error deleting pseudonym `%s' (does not exist?).\n" +#~ msgstr "Lá»— xoá biệt hiệu « %s » (không tồn tại ?).\n" + +#~ msgid "Started collection.\n" +#~ msgstr "Äã bắt đầu thu thập.\n" + +#~ msgid "Namespace `%s' created (root: %s).\n" +#~ msgstr "Äã tạo không gian tên « %s » (gốc: %s).\n" + +#~ msgid "You must specify a name for the collection (`%s' option).\n" +#~ msgstr "Bạn phải ghi rõ má»™t tên cho thu thập (tùy chá»n « %s »).\n" + +#~ msgid "%d files found in directory.\n" +#~ msgstr "Tìm thấy %d tập tin trong thÆ° mục.\n" + +#~ msgid "Perform directory related operations." +#~ msgstr "Thá»±c hiện các thao tác liên quan đến thÆ° mục." + +#~ msgid "" +#~ "remove all entries from the directory database and stop tracking URIs" +#~ msgstr "" +#~ "gỡ bá» má»i mục nhập khá»i cÆ¡ sở dữ liệu thÆ° mục, và dừng theo dõi các địa " +#~ "chỉ URI" + +#~ msgid "list entries from the directory database" +#~ msgstr "liệt kê các mục nhập từ cÆ¡ sở dữ liệu thÆ° mục" + +#~ msgid "start tracking entries for the directory database" +#~ msgstr "bắt đầu theo dõi các mục nhập cho cÆ¡ sở dữ liệu thÆ° mục" + +#~ msgid "Listed %d matching entries.\n" +#~ msgstr "Äã liệt kê %d mục nhập tÆ°Æ¡ng ứng.\n" + +#~ msgid "Upload of `%s' at %llu out of %llu bytes.\n" +#~ msgstr "Tải lên tập tin « %s » tại %llu trên %llu byte.\n" + +#~ msgid "Upload aborted.\n" +#~ msgstr "Tải lên bị hủy bá».\n" + +#~ msgid "Uploading suspended.\n" +#~ msgstr "Tiến trình tải lên bị ngÆ°ng.\n" + +#~ msgid "" +#~ "run in debug mode; gnunet-auto-share will not daemonize and error " +#~ "messages will be written to stderr instead of a logfile" +#~ msgstr "" +#~ "chạy trong chế Ä‘á»™ tìm sá»­a lá»—i; gnunet-auto-share sẽ không trở thành trình " +#~ "ná»n và sẽ ghi thông báo lá»—i ra đầu lá»—i tiêu chuẩn thay vì vào má»™t tập tin " +#~ "ghi sá»± kiện." + +#~ msgid "" +#~ "do not use libextractor to add additional references to directory entries " +#~ "and/or the published file" +#~ msgstr "" +#~ "đừng dùng libextractor để thêm các tham chiếu bổ sung vào mục nhập thÆ° " +#~ "mục và/hay tập tin công bố" + +#~ msgid "Automatically share a directory." +#~ msgstr "Tá»± Ä‘á»™ng chia sẻ má»™t thÆ° mục." + +#~ msgid "Unknown keyword type `%s' in metadata configuration\n" +#~ msgstr "Không rõ kiểu từ khoá « %s » trong cấu hình siêu dữ liệu\n" + +#~ msgid "Directory `%s' is already on the list of shared directories.\n" +#~ msgstr "ThÆ° mục « %s » đã có trong danh sách các thÆ° mục dùng chung.\n" + +#~ msgid "" +#~ "The specified directories were added to the list of shared directories.\n" +#~ msgstr "" +#~ "Những thÆ° mục Ä‘Æ°a ra đã được thêm vào danh sách các thÆ° mục dùng chung.\n" + +#~ msgid "Created entry `%s' in namespace `%s'\n" +#~ msgstr "Äã tạo mục nhập « %s » trong không gian tên « %s »\n" + +#~ msgid "mimetype" +#~ msgstr "kiểu MIME" + +#~ msgid "" +#~ "%16llu of %16llu bytes inserted (estimating %6s to completion) - %s\n" +#~ msgstr "" +#~ "đã chèn %16llu trên %16llu byte (sẽ hoàn thành trong khoảng %6s giây) - " +#~ "%s\n" + +#~ msgid "" +#~ "Upload of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" +#~ msgstr "" +#~ "Hoàn thành tải lên « %s », %llu byte trong %llu giây (%8.3f KiB/giây).\n" + +#~ msgid "" +#~ "\n" +#~ "Upload aborted.\n" +#~ msgstr "" +#~ "\n" +#~ "Tải lên bị hủy bá».\n" + +#~ msgid "" +#~ "\n" +#~ "Error uploading file: %s" +#~ msgstr "" +#~ "\n" +#~ "Gặp lá»—i khi tải lên tập tin: %s" + +#~ msgid "" +#~ "\n" +#~ "Unexpected event: %d\n" +#~ msgstr "" +#~ "\n" +#~ "Gặp sá»± kiện bất thÆ°á»ng: %d\n" + +#~ msgid "" +#~ "even if gnunetd is running on the local machine, force the creation of a " +#~ "copy instead of making a link to the GNUnet share directory" +#~ msgstr "" +#~ "thậm chí nếu gnunetd Ä‘ang chạy trên máy cục bá»™, bắt buá»™c tạo má»™t bản sao " +#~ "thay vì tạo má»™t liên kết đến thÆ° mục chia sẻ của GNUnet" + +#~ msgid "Make files available to GNUnet for sharing." +#~ msgstr "Làm cho các tập tin sẵn sàng qua GNUnet để chia sẻ." + +#~ msgid "Could not access namespace `%s' (does not exist?).\n" +#~ msgstr "Không thể truy cập đến không gian tên « %s » (không tồn tại ?).\n" + +#~ msgid "Search GNUnet for files." +#~ msgstr "Tìm tập tin trong GNUnet." + +#~ msgid "write encountered (decrypted) search results to FILENAME" +#~ msgstr "ghi kết quả tìm kiếm tìm thấy (đã giải mã) vào tập tin TÊN_TẬP_TIN" + +#~ msgid "Error converting arguments to URI!\n" +#~ msgstr "Gặp lá»—i khi chuyển đổi các đối số sang URI.\n" + +#~ msgid "" +#~ "%16llu of %16llu bytes unindexed (estimating %llu seconds to " +#~ "completion) " +#~ msgstr "" +#~ "Äã bá» chỉ mục %16llu trên %16llu byte (sẽ hoàn thành sau khoảng %llu " +#~ "giây) " + +#~ msgid "" +#~ "\n" +#~ "Unindexing of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" +#~ msgstr "" +#~ "\n" +#~ "Hoàn thành bá» chỉ mục của « %s », %llu byte sau %llu giây (%8.3f KiB/" +#~ "giây).\n" + +#~ msgid "Not enough arguments. You must specify a filename.\n" +#~ msgstr "Không đủ đối số. Phải xác định má»™t tên tập tin.\n" + +#~ msgid "`%s' failed. Is `%s' a file?\n" +#~ msgstr "« %s » bị lá»—i. « %s » là má»™t tập tin phải không?\n" + +#~ msgid "" +#~ "download a GNUnet directory that has already been downloaded. Requires " +#~ "that a filename of an existing file is specified instead of the URI. The " +#~ "download will only download the top-level files in the directory unless " +#~ "the `-R' option is also specified." +#~ msgstr "" +#~ "tải xuống má»™t thÆ° mục GNUnet đã được tải vá» trÆ°á»›c. Cần thiết ghi rõ tên " +#~ "tập tin của má»™t tập tin đã có, thay cho địa chỉ URI. Việc tải vá» sẽ chỉ " +#~ "tải vá» các tập tin cấp đầu của thÆ° mục, nếu không cÅ©ng Ä‘Æ°a ra tùy chá»n « -" +#~ "R »." + +#~ msgid "Download files from GNUnet." +#~ msgstr "Tải tập tin xuống GNUnet." + +#~ msgid "Download of file `%s' at %16llu out of %16llu bytes (%8.3f KiB/s)\n" +#~ msgstr "" +#~ "Tải xuống tập tin « %s » tại %16llu trên %16llu byte (%8.3f KiB/giây)\n" + +#~ msgid "Download aborted.\n" +#~ msgstr "Tiến trình tải xuống bị hủy bá».\n" + +#~ msgid "Download of file `%s' complete. Speed was %8.3f KiB per second.\n" +#~ msgstr "" +#~ "Hoàn thành tải xuống tập tin « %s ». Tốc Ä‘á»™ là %8.3f KiB má»™t giây.\n" + +#~ msgid "no name given" +#~ msgstr "chÆ°a Ä‘Æ°a ra tên" + +#~ msgid "Not enough arguments. You must specify a GNUnet file URI\n" +#~ msgstr "Không đủ đối số. Phải ghi rõ má»™t địa chỉ URI tập tin GNUnet\n" + +#~ msgid "URI `%s' invalid for gnunet-download.\n" +#~ msgstr "Sai URI « %s » cho gnunet-download.\n" + +#~ msgid "No filename specified, using `%s' instead (for now).\n" +#~ msgstr "ChÆ°a ghi rõ tên tập tin, Ä‘ang dùng « %s » để thay thế (lúc này).\n" + +#~ msgid "Downloading %d files from directory `%s'.\n" +#~ msgstr "Äang tải %d tập tin xuống thÆ° mục « %s ».\n" + +#~ msgid "Did not find any files in directory `%s'\n" +#~ msgstr "Không tìm thấy tập tin nào trong thÆ° mục « %s »\n" + +#~ msgid "File stored as `%s'.\n" +#~ msgstr "Tập tin được lÆ°u dạng « %s ».\n" + +#~ msgid "Collecting file identifiers disabled.\n" +#~ msgstr "Chức năng thu thập các đồ nhận diện tập tin đã bị tắt.\n" + +#~ msgid "Deleted corrupt URI database in `%s'." +#~ msgstr "Äã xoá cÆ¡ sở dữ liệu địa chỉ URI bị há»ng trong « %s »." + +#~ msgid "Cannot get size of file `%s'" +#~ msgstr "Không thể lấy kích cỡ của tập tin « %s »" + +#~ msgid "Cannot hash `%s'.\n" +#~ msgstr "Không thể tạo mẫu duy nhất đại diện cho « %s ».\n" + +#~ msgid "Initialization for indexing file `%s' failed.\n" +#~ msgstr "Lá»—i sÆ¡ khởi tập tin đánh chỉ mục « %s ».\n" + +#~ msgid "Cannot open file `%s': `%s'" +#~ msgstr "Không thể mở tập tin « %s »: « %s »" + +#~ msgid "Renaming of file `%s' to `%s' failed: %s\n" +#~ msgstr "Lá»—i thay đổi tên của tập tin « %s » thành « %s »: %s\n" + +#~ msgid "Could not rename file `%s' to `%s': file exists\n" +#~ msgstr "Không thể thay đổi tên tập tin « %s » thành « %s »: tập tin đã có\n" + +#~ msgid "CHK URI not allowed for search.\n" +#~ msgstr "Không cho phép địa chỉ URI CHK khi tìm kiếm.\n" + +#~ msgid "LOC URI not allowed for search.\n" +#~ msgstr "Không cho phép địa chỉ URI LOC khi tìm kiếm.\n" + +#~ msgid "File `%s' does not contain a pseudonym.\n" +#~ msgstr "Tập tin « %s » không chứa biệt hiệu.\n" + +#~ msgid "Format of pseudonym `%s' is invalid.\n" +#~ msgstr "Äịnh dạng của biệt hiệu « %s » là không hợp lệ.\n" + +#~ msgid "Format of file `%s' is invalid, trying to remove.\n" +#~ msgstr "Äịnh dạng của tập tin « %s » là không hợp lệ nên thá»­ gỡ bá».\n" + +#~ msgid "" +#~ "Decrypted content does not match key. This is either a bug or a " +#~ "maliciously inserted file. Download aborted.\n" +#~ msgstr "" +#~ "Ná»™i dung đã giải mã không tÆ°Æ¡ng ứng chìa khóa. Äây là má»™t lá»—i hoặc má»™t " +#~ "tập tin chèn vào vá»›i ý xấu. Tiến trình tải xuống bị hủy bá».\n" + +#~ msgid "Revision %u" +#~ msgstr "Bản sá»­a đổi %u" + +#~ msgid "Application aborted." +#~ msgstr "Ứng dụng bị hủy bá»." + +#~ msgid "FSUI state file `%s' had syntax error at offset %u.\n" +#~ msgstr "Tập tin tình trạng FSUI « %s » có lá»—i cú pháp tại khoảng bù %u.\n" + +#~ msgid "# gap content total planned" +#~ msgstr "# tổng số ná»™i dung lá»— hổng dá»± định" + +#~ msgid "Datastore full.\n" +#~ msgstr "Kho dữ liệu đầy.\n" + +#~ msgid "# gap requests total received" +#~ msgstr "# tổng số yêu cầu lá»— hổng được nhận" + +#~ msgid "# gap content total received" +#~ msgstr "# tổng số ná»™i dung lá»— hổng được nhận" + +#~ msgid "# gap total trust awarded" +#~ msgstr "# tổng số tin cậy lá»— hổng được cấp" + +#~ msgid "" +#~ "`%s' registering client handlers %d %d %d %d %d %d %d %d and P2P handlers " +#~ "%d %d\n" +#~ msgstr "" +#~ "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển kiểu ứng dụng khách %d %d %d %d " +#~ "%d %d %d %d và kiểu P2P %d %d\n" + +#~ msgid "enables (anonymous) file-sharing" +#~ msgstr "hiệu lá»±c chia sẻ tập tin (nặc danh)" + +#~ msgid "" +#~ "Because the file `%s' has been unavailable for 3 days it got removed from " +#~ "your share. Please unindex files before deleting them as the index now " +#~ "contains invalid references!\n" +#~ msgstr "" +#~ "Vì không có tập tin « %s » trong 3 ngày nên đã xóa nó khá»i chia sẻ của " +#~ "bạn. Xin hãy bá» chỉ mục các tập tin trÆ°á»›c khi xoá chúng vì chỉ mục hiện " +#~ "thá»i chứa các tham chiếu sai.\n" + +#~ msgid "Indexed content changed (does not match its hash).\n" +#~ msgstr "" +#~ "Ná»™i dung đánh chỉ mục bị thay đổi (không tÆ°Æ¡ng ứng vá»›i tổng kiểm).\n" + +#~ msgid "" +#~ "Unindexed ODB block `%s' from offset %llu already missing from " +#~ "datastore.\n" +#~ msgstr "" +#~ "Khối ODB đã bá» chỉ mục « %s » từ khoảng bù %llu đã không có trong kho dữ " +#~ "liệu.\n" + +#~ msgid "# distinct interned peer IDs in pid table" +#~ msgstr "# các mã số đồng đẳng bị giam giữ riêng biệt trong bảng PID" + +#~ msgid "# total RC of interned peer IDs in pid table" +#~ msgstr "# tổng số RC của mã số đồng đẳng bị giam giữ trong bảng PID" + +#~ msgid "# gap client requests tracked" +#~ msgstr "# các yêu cầu máy/trình khách lá»— hổng được theo dõi" + +#~ msgid "# gap query bloomfilter resizing updates" +#~ msgstr "" +#~ "# các bản cập nhật thay đổi kích cỡ bá»™ lá»c bloomfilter truy vấn lá»— hổng" + +#~ msgid "# blocks migrated" +#~ msgstr "# các khối được nâng cấp" + +#~ msgid "# blocks injected for migration" +#~ msgstr "# các khối được phun vào để nâng cấp" + +#~ msgid "# on-demand fetches for migration" +#~ msgstr "# các lần lấy theo yêu cầu để nâng cấp" + +#~ msgid "# gap queries dropped (table full)" +#~ msgstr "# các truy vấn lá»— hổng bị bá» (bảng đầy)" + +#~ msgid "# gap queries dropped (redundant)" +#~ msgstr "# các truy vấn lá»— hổng bị bá» (thừa)" + +#~ msgid "# gap queries refreshed existing record" +#~ msgstr "# các truy vấn lá»— hổng đã cập nhật mục ghi đã có" + +#~ msgid "# trust earned" +#~ msgstr "# Ä‘á»™ tin cậy giành được" + +#~ msgid "# blocks pushed into DHT" +#~ msgstr "# các khối được đẩy vào DHT" + +#~ msgid "scp command is : %s \n" +#~ msgstr "Câu lệnh scp là: %s\n" + +#~ msgid "Friend list of %s:%d\n" +#~ msgstr "Danh sách bạn bè của %s:%d\n" + +#~ msgid "scp command for friend file copy is : %s \n" +#~ msgstr "Câu lệnh scp cho bản sao tập tin bạn bè là: %s\n" + +#~ msgid "Set up multiple gnunetd daemons across multiple hosts." +#~ msgstr "Thiết lập nhiá»u trình ná»n gnunetd qua nhiá»u máy khác nhau." + +#~ msgid "set number of daemons to start" +#~ msgstr "đặt số trình ná»n cần khởi chạy" + +#~ msgid "Waiting for peers to connect" +#~ msgstr "Äang đợi các đồng đẳng kết nối" + +#~ msgid "Bootstrap data obtained from `%s' is invalid.\n" +#~ msgstr "Sai dữ liệu nạp và khởi Ä‘á»™ng được lấy từ « %s ».\n" + +#~ msgid "`%s' registering client handler %d\n" +#~ msgstr "« %s » Ä‘ang đăng ký trình Ä‘iá»u khiển máy khách %d\n" + +#~ msgid "allows clients to determine gnunetd's configuration" +#~ msgstr "cho phép máy khách quyết định cấu hình của trình ná»n gnunetd." + +#~ msgid "`%s' registering client handler %d and %d\n" +#~ msgstr "« %s » Ä‘ang đăng ký trình Ä‘iá»u khiển máy khách %d và %d\n" + +#~ msgid "Template description." +#~ msgstr "Mô tả mẫu." + +#~ msgid "Uptime (seconds)" +#~ msgstr "Thá»i gian chạy (giây)" + +#~ msgid "# Any-Blocks" +#~ msgstr "# Khối bất kỳ" + +#~ msgid "# DBlocks" +#~ msgstr "# Khối D" + +#~ msgid "# SBlocks" +#~ msgstr "# Khối S" + +#~ msgid "# KBlocks" +#~ msgstr "# Khối K" + +#~ msgid "# NBlocks" +#~ msgstr "# Khối N" + +#~ msgid "# KNBlocks" +#~ msgstr "# Khối KN" + +#~ msgid "# OnDemand-Blocks" +#~ msgstr "# Khối theo yêu cầu" + +#~ msgid "# Unknown-Blocks" +#~ msgstr "# Khối không rõ" + +#~ msgid "# expired" +#~ msgstr "# đã hết hạn" + +#~ msgid "# expire in 1h" +#~ msgstr "# hết hạn trong 1 giá»" + +#~ msgid "# expire in 24h" +#~ msgstr "# hết hạn trong 24 giá»" + +#~ msgid "# expire in 1 week" +#~ msgstr "# hết hạn trong 1 tuần" + +#~ msgid "# expire in 1 month" +#~ msgstr "# hết hạn trong 1 tháng" + +#~ msgid "# zero priority" +#~ msgstr "# Æ°u tiên 0" + +#~ msgid "# priority one" +#~ msgstr "# Æ°u tiên 1" + +#~ msgid "# priority larger than one" +#~ msgstr "# Æ°u tiên >1" + +#~ msgid "# no anonymity" +#~ msgstr "# nặc danh 0" + +#~ msgid "# anonymity one" +#~ msgstr "# nặc danh 1" + +#~ msgid "# anonymity larger than one" +#~ msgstr "# nặc danh >1" + +#~ msgid "% of allowed network load (up)" +#~ msgstr "% trá»ng tải mạng được phép (chạy)" + +#~ msgid "% of allowed network load (down)" +#~ msgstr "% trá»ng tải mạng được phép (không chạy)" + +#~ msgid "% of allowed cpu load" +#~ msgstr "% trá»ng tải CPU được phép" + +#~ msgid "% of allowed io load" +#~ msgstr "% trá»ng tải V/R được phép" + +#~ msgid "# plibc handles" +#~ msgstr "# các bá»™ xá»­ lý plibc" + +#~ msgid "`%s' registering client handlers %d %d %d and p2p handler %d\n" +#~ msgstr "" +#~ "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển máy khách %d %d %d và trình Ä‘iá»u " +#~ "khiển đồng đẳng %d\n" + +#~ msgid "keeps statistics about gnunetd's operation" +#~ msgstr "tính thống kê vá» thao tác gnunetd" + +#~ msgid "Supported peer-to-peer messages:\n" +#~ msgstr "Thông báo đồng đẳng được há»— trợ :\n" + +#~ msgid "Supported client-server messages:\n" +#~ msgstr "Thông báo máy khách-chủ được há»— trợ :\n" + +#~ msgid "prints supported protocol messages" +#~ msgstr "in ra các thông báo giao thức được há»— trợ" + +#~ msgid "Suppress display of asynchronous log messages" +#~ msgstr "Thu hồi hiển thị các thông Ä‘iệp ghi sá»± kiện không đồng bá»™" + +#~ msgid "VPN IP src not anonymous. drop..\n" +#~ msgstr "VPN Nguồn địa chỉ IP không phải nặc danh, bá» Ä‘i.\n" + +#~ msgid "VPN IP not anonymous, drop.\n" +#~ msgstr "VPN Äịa chỉ IP không phải nặc danh, bá» Ä‘i.\n" + +#~ msgid "VPN Received, not anonymous, drop.\n" +#~ msgstr "VPN Nhận được, không phải nặc danh, bá» Ä‘i.\n" + +#~ msgid "VPN Received unknown IP version %d...\n" +#~ msgstr "VPN Nhận được phiên bản IP không rõ %d...\n" + +#~ msgid "<- GNUnet(%d) : %s\n" +#~ msgstr "<- GNUnet(%d) : %s\n" + +#~ msgid "" +#~ "Could not write the tunnelled IP to the OS... Did to setup a tunnel?\n" +#~ msgstr "" +#~ "Không thể ghi vào HÄH địa chỉ IP theo Ä‘Æ°á»ng hầm... Äã làm để thiết lập " +#~ "má»™t Ä‘Æ°á»ng hầm ?\n" + +#~ msgid "Prepare route announcement level %d\n" +#~ msgstr "Chuẩn bị thông cáo định tuyến cấp %d\n" + +#~ msgid "Send route announcement %d with route announce\n" +#~ msgstr "Gá»­i thông cáo định tuyến %d vá»›i Ä‘Æ°á»ng đã báo\n" + +#~ msgid "Send outside table info %d\n" +#~ msgstr "Gá»­i thông tin bảng bên ngoài %d\n" + +#~ msgid "Receive route announce.\n" +#~ msgstr "Nhận thông cáo định tuyến.\n" + +#~ msgid "Going to try insert route into local table.\n" +#~ msgstr "Sẽ thá»­ chèn Ä‘Æ°á»ng vào bảng cục bá»™.\n" + +#~ msgid "Inserting with hops %d\n" +#~ msgstr "Äang chèn vá»›i số bÆ°á»›c nhảy %d\n" + +#~ msgid "Request level %d from peer %d\n" +#~ msgstr "Yêu cầu cấp %d từ đồng đẳng %d\n" + +#~ msgid "Receive table limit on peer reached %d\n" +#~ msgstr "Giá»›i hạn bảng nhận trên đồng đẳng đã tá»›i %d\n" + +#~ msgid "Not storing route to myself from peer %d\n" +#~ msgstr "Không phải lÆ°u lại Ä‘Æ°á»ng đến máy này từ đồng đẳng %d\n" + +#~ msgid "Duplicate route to node from peer %d, choosing minimum hops" +#~ msgstr "" +#~ "ÄÆ°á»ng trùng đến nút từ đồng đẳng %d, Ä‘ang chá»n Ä‘Æ°á»ng có ít bÆ°á»›c nhảy hÆ¡n" + +#~ msgid "Inserting route from peer %d in route table at location %d\n" +#~ msgstr "Äang chèn Ä‘Æ°á»ng từ đồng đẳng %d vào bảng định tuyến tại vị trí %d\n" + +#~ msgid "RFC4193 Frame length %d is too big for GNUnet!\n" +#~ msgstr "RFC4193 Chiá»u dài khung %d quá lá»›n cho GNUnet!\n" + +#~ msgid "RFC4193 Frame length %d too small\n" +#~ msgstr "RFC4193 Chiá»u dài khung %d quá nhá»\n" + +#~ msgid "RFC4193 Ethertype %x and IP version %x do not match!\n" +#~ msgstr "RFC4193 Ethertype %x và phiên bản IP %x không tÆ°Æ¡ng ứng.\n" + +#~ msgid "RFC4193 Going to try and make a tunnel in slot %d\n" +#~ msgstr "RFC4193 Sẽ thá»­ tạo má»™t Ä‘Æ°á»ng hầm trong khoảng %d\n" + +#, fuzzy +#~ msgid "Cannot open tunnel device: %s" +#~ msgstr "Không thể mở thiết bị Ä‘Æ°á»ng hầm do %s" + +#~ msgid "RFC4193 Create skips gnu%d as we are already using it\n" +#~ msgstr "RFC4193 Chức năng tạo sẽ ná» qua gnu%d vì chúng ta Ä‘ang dùng nó\n" + +#~ msgid "Cannot set tunnel name to %s because of %s\n" +#~ msgstr "không thể đặt tên Ä‘Æ°á»ng hầm thành %s do %s\n" + +#~ msgid "Configured tunnel name to %s\n" +#~ msgstr "Tên Ä‘Æ°á»ng hầm đã được cấu hình thành %s\n" + +#~ msgid "Cannot get socket flags for gnu%d because %s\n" +#~ msgstr "Không thể lấy các cỠổ cắm cho gnu%d do %s\n" + +#~ msgid "Cannot set socket flags for gnu%d because %s\n" +#~ msgstr "Không thể đặt các cỠổ cắm cho gnu%d do %s\n" + +#~ msgid "Cannot set MTU for gnu%d because %s\n" +#~ msgstr "Không thể đặt MTU cho gnu%d do %s\n" + +#~ msgid "Cannot get interface index for gnu%d because %s\n" +#~ msgstr "Không thể lấy chủ mục giao diện cho gnu%d do %s\n" + +#~ msgid "IPv6 ifaddr gnu%d - %x:%x:%x:%x:%x:%x:%x:%x/%d\n" +#~ msgstr "IPv6 ifaddr gnu%d - %x:%x:%x:%x:%x:%x:%x:%x/%d\n" + +#~ msgid "Cannot set interface IPv6 address for gnu%d because %s\n" +#~ msgstr "Không thể đặt địa chỉ IPv6 của giao diện cho gnu%d do %s\n" + +#~ msgid "IPv6 route gnu%d - destination %x:%x:%x:%x:%x:%x:%x:%x/%d\n" +#~ msgstr "ÄÆ°á»ng IPv6 gnu%d - đích đến %x:%x:%x:%x:%x:%x:%x:%x/%d\n" + +#~ msgid "Cannot add route IPv6 address for gnu%s because %s\n" +#~ msgstr "Không thể thêm địa chỉ IPv6 của Ä‘Æ°á»ng cho gnu%s do %s\n" + +#~ msgid "" +#~ "RFC4193 We have run out of memory and so I can't store a tunnel for this " +#~ "peer.\n" +#~ msgstr "" +#~ "RFC4193 Tràn bá»™ nhá»› thì không thể cất giữ má»™t Ä‘Æ°á»ng hầm cho đồng đẳng " +#~ "này.\n" + +#~ msgid "RFC4193 Thread running (frame %d tunnel %d f2f %d) ...\n" +#~ msgstr "RFC4193 Mạch Ä‘ang chạy (khung %d Ä‘Æ°á»ng hầm %d f2f %d) ...\n" + +#~ msgid "VPN dropping connection %x\n" +#~ msgstr "VPN Ä‘ang bá» Ä‘i kết nối %x\n" + +#~ msgid "VPN cannot drop connection %x\n" +#~ msgstr "VPN không thể bá» Ä‘i kết nối %x\n" + +#~ msgid "RFC4193 Thread exiting\n" +#~ msgstr "RFC4193 Mạch Ä‘ang thoát\n" + +#~ msgid "realise alloc ram\n" +#~ msgstr "realise cấp phát bá»™ nhá»› RAM\n" + +#~ msgid "realise add routes\n" +#~ msgstr "realise thêm Ä‘Æ°á»ng\n" + +#~ msgid "realise copy table\n" +#~ msgstr "realise chép bảng\n" + +#~ msgid "`%s' initialising RFC4913 module %d and %d\n" +#~ msgstr "« %s » Ä‘ang sÆ¡ khởi mô-Ä‘un RFC4913 %d và %d\n" + +#~ msgid "RFC4193 my First 4 hex digits of host id are %x\n" +#~ msgstr "RFC4193 my 4 chữ số thập lúc đầu tiên của mã số máy là %x\n" + +#~ msgid "enables IPv6 over GNUnet (incomplete)" +#~ msgstr "hiệu lá»±c IPv6 qua GNUnet (chÆ°a hoàn tất)" + +#~ msgid "RFC4193 Waiting for tun thread to end\n" +#~ msgstr "RFC4193 Äang đợi kết thúc mạch tun\n" + +#~ msgid "RFC4193 The tun thread has ended\n" +#~ msgstr "RFC4193 Mạch tun đã kết thúc\n" + +#~ msgid "RFC4193 Closing tunnel %d fd %d\n" +#~ msgstr "RFC4193 Äang đóng Ä‘Æ°á»ng hầm %d fd %d\n" + +#~ msgid "Configuration value `%s' under [MODULES] for `%s' is invalid!\n" +#~ msgstr "Sai giá trị cấu hình « %s » dÆ°á»›i [MÔ-ÄUN] cho « %s ».\n" + +#~ msgid "Application module `%s' already initialized!\n" +#~ msgstr "Mô-Ä‘un ứng dụng « %s » đã được sở khởi.\n" + +#~ msgid "Failed to load plugin `%s' at %s:%d. Unloading plugin.\n" +#~ msgstr "Lá»—i nạp phần bổ sung « %s » tại %s:%d. Äang hủy nạp phần bổ sung.\n" + +#~ msgid "Could not shutdown `%s': application not loaded\n" +#~ msgstr "Không thể tắt « %s »: chÆ°a nạp ứng dụng\n" + +#~ msgid "Could not shutdown application `%s': not initialized\n" +#~ msgstr "Không thể tắt ứng dụng « %s »: chÆ°a được sÆ¡ khởi\n" + +#~ msgid "Could not release %p: service not loaded\n" +#~ msgstr "Không thể giải phóng %p: chÆ°a nạp dịch vụ\n" + +#~ msgid "Could not properly shutdown application `%s'.\n" +#~ msgstr "Không thể tắt đúng ứng dụng « %s ».\n" + +#~ msgid "Could not properly unload service `%s'!\n" +#~ msgstr "Không thể hủy nạp đúng dịch vụ « %s ».\n" + +#~ msgid "Core initialization failed.\n" +#~ msgstr "Lá»—i sÆ¡ khởi lõi.\n" + +#~ msgid "Updates GNUnet datastructures after version change." +#~ msgstr "Cập nhật cấu trúc dữ liệu GNUnet sau khi thay đổi phiên bản." + +#~ msgid "run as user LOGIN" +#~ msgstr "chạy dÆ°á»›i ngÆ°á»i dùng ÄÄ‚NG_NHẬP" + +#~ msgid "run in client mode (for getting client configuration values)" +#~ msgstr "chạy trong chế Ä‘á»™ khách (để lấy các giá trị cấu hình của máy khách)" + +#~ msgid "" +#~ "Failed to determine filename used to store GNUnet version information!\n" +#~ msgstr "" +#~ "Lá»—i quyết định tên tập tin được dùng để chứa thông tin vá» phiên bản " +#~ "GNUnet.\n" + +#~ msgid "" +#~ "run in debug mode; gnunetd will not daemonize and error messages will be " +#~ "written to stderr instead of a logfile" +#~ msgstr "" +#~ "chạy trong chế Ä‘á»™ tìm sá»­a lá»—i; gnunetd sẽ không trở thành trình ná»n và sẽ " +#~ "ghi thông báo lá»—i ra đầu lá»—i tiêu chuẩn thay vì vào má»™t tập tin ghi sá»± " +#~ "kiện." + +#~ msgid "Starts the gnunetd daemon." +#~ msgstr "Khởi chạy trình ná»n gnunetd." + +#~ msgid "disable padding with random data (experimental)" +#~ msgstr "tắt đệm lót vá»›i dữ liệu ngẫu nhiên (vẫn thá»±c nghiệm !)" + +#~ msgid "print all log messages to the console (only works together with -d)" +#~ msgstr "" +#~ "in má»i thông Ä‘iệp ghi sá»± kiện ra bàn giao tiếp (chỉ hoạt Ä‘á»™ng tổ hợp vá»›i " +#~ "« -d »)" + +#~ msgid "specify username as which gnunetd should run" +#~ msgstr "chỉ ra tên ngÆ°á»i dùng dÆ°á»›i đó cần chạy gnunetd" + +#~ msgid "Configuration or GNUnet version changed. You need to run `%s'!\n" +#~ msgstr "" +#~ "Cấu hình hoặc phiên bản GNUnet bị thay đổi. NgÆ°á»i dùng cần chạy « %s ».\n" + +#~ msgid "The `%s' request received from client is malformed.\n" +#~ msgstr "Nhận được yêu cầu « %s » dạng sai từ máy khách.\n" + +#~ msgid "Registering failed, message type %d already in use.\n" +#~ msgstr "Lá»—i đăng ký, thông Ä‘iệp kiểu %d Ä‘ang được dùng.\n" + +#~ msgid "Unable to obtain filesystem information for `%s': %u\n" +#~ msgstr "Không thể đại được thông tin vá» hệ thống tập tin cho « %s »: %u\n" + +#~ msgid "" +#~ "Filesystem `%s' of partition `%s' is unknown. Please contact gnunet-" +#~ "developers@gnu.org!" +#~ msgstr "" +#~ "Hệ thống tập tin « %s » của phân vùng « %s » không rõ. Hãy liên lạc vá»›i " +#~ "các nhà phát triển gnunet ở địa chỉ « gnunet-developers@gnu.org »." + +#~ msgid "" +#~ "Limiting datastore size to %llu GB, because the `%s' filesystem does not " +#~ "support larger files. Please consider storing the database on a NTFS " +#~ "partition!\n" +#~ msgstr "" +#~ "Äang hạn chế kích cỡ kho dữ liệu thành %llu GB, vì hệ thống tập tin « %s " +#~ "» không há»— trợ tập tin lá»›n hÆ¡n đó. Khuyên bạn cất giữ cÆ¡ sở dữ liệu trong " +#~ "má»™t phiên bản kiểu NTFS.\n" + +#~ msgid "`%s' message invalid (signature invalid).\n" +#~ msgstr "Thông báo « %s » không hợp lệ (chữ ký sai).\n" + +#~ msgid "`%s' selected %d out of %d messages (MTU: %d).\n" +#~ msgstr "« %s » đã chá»n %d trên %d thông báo (MTU: %d).\n" + +#~ msgid "Message details: %u: length %d, priority: %d\n" +#~ msgstr "Chi tiết vá» thông báo: %u: dài %d, Æ°u tiên: %d\n" + +#~ msgid "Message from `%s' discarded: invalid format.\n" +#~ msgstr "Thông báo từ « %s » bị hủy: định dạng sai.\n" + +#~ msgid "Invalid sequence number %u <= %u, dropping message.\n" +#~ msgstr "" +#~ "Sai số thứ tá»± dãy trong thông báo %u ≤ %u, Ä‘ang loại bá» thông báo.\n" + +#~ msgid "# connections closed (HANGUP sent)" +#~ msgstr "# các kết nối bị đóng (gá»­i tín hiệu ngừng nói HANGUP)" + +#~ msgid "# bytes noise sent" +#~ msgstr "# các byte nhiá»…u được gá»­i" + +#~ msgid "# total bytes per second send limit" +#~ msgstr "# giá»›i hạn tổng số byte má»—i giây" + +#~ msgid "# total bytes per second receive limit" +#~ msgstr "# giá»›i hạn nhận tổng số byte má»—i giây" + +#~ msgid "# total number of messages in send buffers" +#~ msgstr "# tổng số thông báo trong bá»™ đệm gá»­i" + +#~ msgid "# total number of bytes we were allowed to send but did not" +#~ msgstr "# tổng số byte được phép gá»­i mà chÆ°a" + +#~ msgid "# total number of bytes we were allowed to sent" +#~ msgstr "# tổng số byte được phép gá»­i" + +#~ msgid "# total number of bytes we are currently allowed to send" +#~ msgstr "# tổng số byte hiện thá»i được phép gá»­i" + +#~ msgid "# transports switched to stream transport" +#~ msgstr "# các truyá»n tải được chuyển sang truyá»n tải luồng" + +#~ msgid "# conn. shutdown: other peer sent too much" +#~ msgstr "# kết nối bị ngắt: đồng đẳng khác đã gá»­i quá nhiá»u" + +#~ msgid "# conn. shutdown: we lacked bandwidth" +#~ msgstr "# kết nối bị ngắt: không đủ băng thông." + +#~ msgid "# conn. shutdown: other peer timed out" +#~ msgstr "# kết nối bị ngắt: đồng đẳng khác quá hạn" + +#~ msgid "# conn. shutdown: timed out during connect" +#~ msgstr "# kết nối bị ngắt: quá hạn trong khi thiết lập kết nối" + +#~ msgid "# conn. shutdown: other peer requested it" +#~ msgstr "# kết nối bị ngắt: theo yêu cầu của đồng đẳng khác" + +#~ msgid "`%s': Could not create hello.\n" +#~ msgstr "« %s »: Không tạo được tín hiệu xin chào (hello).\n" + +#~ msgid "`%s': Could not send.\n" +#~ msgstr "« %s »: Không thể gá»­i.\n" + +#~ msgid "`%s': Could not disconnect.\n" +#~ msgstr "« %s »: Không thể ngắt kết nối.\n" + +#~ msgid "" +#~ "`%s' transport OK. It took %ums to transmit %llu messages of %llu bytes " +#~ "each.\n" +#~ msgstr "" +#~ "« %s » truyá»n tải OK. Cần %u miligiây để truyá»n Ä‘i %llu thông báo vá»›i " +#~ "%llu byte má»—i cái.\n" + +#~ msgid " Transport %d is not being tested\n" +#~ msgstr " Truyá»n tải %d không Ä‘ang thá»­\n" + +#~ msgid "" +#~ "\n" +#~ "Contacting `%s'." +#~ msgstr "" +#~ "\n" +#~ "Äang liên lạc vá»›i « %s »." + +#~ msgid " Connection failed (bug?)\n" +#~ msgstr " Không kết nối được (lá»—i ?)\n" + +#~ msgid "Timeout after %llums.\n" +#~ msgstr "Quá hạn sau %llu miligiây.\n" + +#~ msgid "OK!\n" +#~ msgstr "OK!\n" + +#~ msgid "Tool to test if GNUnet transport services are operational." +#~ msgstr "" +#~ "Công cụ để thá»­ nghiệm xem dịch vụ truyá»n tải GNUnet có hoạt Ä‘á»™ng không." + +#~ msgid "ping peers from HOSTLISTURL that match transports" +#~ msgstr "" +#~ "gá»­i tín hiệu ping cho các đồng đẳng từ HOSTLISTURL (danh sách máy theo " +#~ "URL) tÆ°Æ¡ng ứng vá»›i truyá»n tải" + +#~ msgid "send messages with SIZE bytes payload" +#~ msgstr "gá»­i thông báo có KÃCH_Cá»  byte tải trá»ng" + +#~ msgid "specifies which TRANSPORT should be tested" +#~ msgstr "chỉ ra TRUYỀN_TẢI nào cần được thá»­ nghiệm" + +#~ msgid "specifies after how many MS to time-out" +#~ msgstr "chỉ ra hết thá»i gian chá» sau bao nhiêu miligiay" + +#~ msgid "repeat each test X times" +#~ msgstr "lặp lại má»—i hàm thá»­ X lần" + +#~ msgid "Testing transport(s) %s\n" +#~ msgstr "Äang thá»­ nghiệm (các) truyá»n tải %s\n" + +#~ msgid "Available transport(s): %s\n" +#~ msgstr "Các truyá»n tải sẵn sàng: %s\n" + +#~ msgid "" +#~ "\n" +#~ "%d out of %d peers contacted successfully (%d times transport " +#~ "unavailable).\n" +#~ msgstr "" +#~ "\n" +#~ "Äã liên lạc thành công vá»›i %d trên %d đồng đẳng (truyá»n tải không sẵn " +#~ "sàng %d lần).\n" + +#~ msgid "Port is 0, will only send using %s.\n" +#~ msgstr "Cổng là 0, chỉ sẽ gá»­i dùng %s.\n" + +#~ msgid "%s failed for url `%s' and post-data `%s' at %s:%d: `%s'\n" +#~ msgstr "" +#~ "%s bị lá»—i đối vá»›i địa chỉ URL « %s » và dữ liệu cuối « %s » tại %s:%d: « " +#~ "%s »\n" + +#~ msgid "upnp: NAT Returned IP: %s\n" +#~ msgstr "upnp: địa chỉ IP được NAT trả vá»: %s\n" + +#~ msgid "" +#~ "The UPnP service could not be loaded. To disable UPnP, set the " +#~ "configuration option \"UPNP\" in section \"%s\" to \"NO\"\n" +#~ msgstr "" +#~ "Dịch vụ UPnP không thể nạp được. Äể tắt UPnP, đặt tùy chá»n cấu hình « " +#~ "UPNP » trong phần « %s » thành « NO » (không).\n" + +#~ msgid "# bytes sent via HTTP" +#~ msgstr "# các byte đã gá»­i qua HTTP" + +#~ msgid "# bytes dropped by HTTP (outgoing)" +#~ msgstr "# các byte loại bá» bởi HTTP (Ä‘i ra)" + +#~ msgid "# HTTP GET issued" +#~ msgstr "# Tín hiệu HTTP GET được gá»­i" + +#~ msgid "# HTTP PUT issued" +#~ msgstr "# Tín hiệu HTTP PUT được gá»­i" + +#~ msgid "# HTTP send calls" +#~ msgstr "# các cuá»™c gá»i HTTP send (gá»­i)" + +#~ msgid "# HTTP curl send callbacks" +#~ msgstr "# các cuá»™c gá»i ngược HTTP curl send (hàm curl gá»­i)" + +#~ msgid "# HTTP curl receive callbacks" +#~ msgstr "# các cuá»™c gá»i ngược HTTP curl receive (hàm curl nhận)" + +#~ msgid "# HTTP mhd access callbacks" +#~ msgstr "# các cuá»™c gá»i ngược HTTP mhd access (hàm mhd truy cập)" + +#~ msgid "# HTTP mhd read callbacks" +#~ msgstr "# các cuá»™c gá»i ngược HTTP mhd read (hàm mhd Ä‘á»c)" + +#~ msgid "# HTTP mhd close callbacks" +#~ msgstr "# các cuá»™c gá»i ngược HTTP mhd close (hàm mhd đóng)" + +#~ msgid "# HTTP connect calls" +#~ msgstr "# các cuá»™c gá»i HTTP connect (kết nối)" + +#~ msgid "Failed to obtain my (external) %s address!\n" +#~ msgstr "Lá»—i lấy địa chỉ %s (bên ngoài) của mình.\n" + +#~ msgid "MTU %llu for `%s' is probably too low!\n" +#~ msgstr "MTU %llu cho « %s » rất có thể quá thấp.\n" + +#~ msgid "# UDP connections (right now)" +#~ msgstr "# các kết nối UDP (lúc này)" + +#~ msgid "specify host on which gnunetd is running" +#~ msgstr "ghi rõ máy trên đó chạy trình ná»n gnunetd" + +#~ msgid "" +#~ "External protocol violation: assertion failed at %s:%d (no need to panic, " +#~ "we can handle this).\n" +#~ msgstr "" +#~ "Xâm phạm giao thức bên ngoài: khẳng định không thành công tại %s:%d (đừng " +#~ "lo, vẫn còn có thể sá»­a chữa).\n" + +#~ msgid "No help available." +#~ msgstr "Không có trợ giúp sẵn sàng." + +#~ msgid "" +#~ "You can use 'make check' in src/transports/upnp/ to find out if your NAT " +#~ "supports UPnP. You should disable this option if you are sure that you " +#~ "are not behind a NAT. If your NAT box does not support UPnP, having this " +#~ "on will not do much harm (only cost a small amount of resources)." +#~ msgstr "" +#~ "Bạn có thể dùng câu lệnh « make check » trong « src/transports/upnp » để " +#~ "tìm biết nếu NAT đó há»— trợ UPnP không. ChÆ°a chắc nếu máy này nằm sau má»™t " +#~ "NAT thì bạn nên tắt tùy chá»n này. Nếu máy NAT đó không há»— trợ UPnP, việc " +#~ "bật tùy chá»n này sẽ không rất vấn Ä‘á» gì (chỉ chiếm má»™t ít tài nguyên)." + +#~ msgid "Prompt for development and/or incomplete code" +#~ msgstr "Nhắc vá»›i mã vẫn phát triển và/hay mã chÆ°a hoàn toàn" + +#~ msgid "" +#~ "If EXPERIMENTAL is set to NO, options for experimental code are not " +#~ "shown. If in doubt, use NO.\n" +#~ "\n" +#~ "Some options apply to experimental code that maybe in a state of " +#~ "development where the functionality, stability, or the level of testing " +#~ "is not yet high enough for general use. These features are said to be of " +#~ "\"alpha\" quality. If a feature is currently in alpha, uninformed use is " +#~ "discouraged (since the developers then do not fancy \"Why doesn't this " +#~ "work?\" type messages).\n" +#~ "\n" +#~ "However, active testing and qualified feedback of these features is " +#~ "always welcome. Users should just be aware that alpha features may not " +#~ "meet the normal level of reliability or it may fail to work in some " +#~ "special cases. Bug reports are usually welcomed by the developers, but " +#~ "please read the documents and and use for how to report problems." +#~ msgstr "" +#~ "Nếu EXPERIMENTAL (thá»±c nghiệm) được đặt thành NO (không) thì không hiển " +#~ "thị tùy chá»n vá» mã vẫn thá»±c nghiệm. ChÆ°a chắc thì đặt NO.\n" +#~ "\n" +#~ "Má»™t số tùy chá»n nào đó có áp dụng cho mã thá»±c nghiệm, mà có thể vẫn còn " +#~ "được phát triển thì chÆ°a đầy đủ chức năng, ổn định hay đủ thá»­ để sá»­ dụng " +#~ "má»™t cách chung. Các tính năng này được nhãn là « alpha » (a). Nếu má»™t " +#~ "tính năng vẫn là alpha, khuyên ngÆ°á»i dùng bình thÆ°á»ng không dùng nó.\n" +#~ "\n" +#~ "Tùy nhiên, nếu bạn quen vá»›i tiến trình thá»­ và phản hồi, má»i bạn tham gia " +#~ "(miá»…n là bạn hiểu được rằng phần má»m này có thể chÆ°a sẵn sàng sá»­ dụng vá»›i " +#~ "dữ liệu quan trá»ng). Nhà phát triển má»i bạn gá»­i báo cáo lá»—i: xin hãy Ä‘á»c " +#~ "tài liệu và , sau đó dùng địa " +#~ "chỉ để thông báo vấn Ä‘á»." + +#~ msgid "Show options for advanced users" +#~ msgstr "Hiện tùy chá»n cấp cao" + +#~ msgid "" +#~ "These are options that maybe difficult to understand for the beginner. " +#~ "These options typically refer to features that allow tweaking of the " +#~ "installation. If in a hurry, say NO." +#~ msgstr "" +#~ "Tùy chá»n cấp này có thể khó hiểu cho ngÆ°á»i dùng bắt đầu sá»­ dụng máy tính. " +#~ "Tùy chá»n kiểu này thÆ°á»ng tham chiếu đến tính năng cho phép Ä‘iá»u chỉnh bản " +#~ "cài đặt. Vá»™i thì đặt NO (không)." + +#~ msgid "Show rarely used options" +#~ msgstr "Hiện tùy chá»n ít dùng" + +#~ msgid "" +#~ "These are options that hardly anyone actually needs. If you plan on " +#~ "doing development on GNUnet, you may want to look into these. If in " +#~ "doubt or in a hurry, say NO." +#~ msgstr "" +#~ "Tùy chá»n này cần bởi rất ít ngÆ°á»i. Nếu bạn định phát triển qua GNUnet, có " +#~ "lẽ tùy chá»n này có ích. Nếu không hay vá»™i, hãy đặt NO (không)." + +#~ msgid "Meta-configuration" +#~ msgstr "Siêu cấu hình" + +#~ msgid "Which level of configuration should be available" +#~ msgstr "Cấp cấu hình nên sẵn sàng" + +#~ msgid "Full pathname of GNUnet HOME directory" +#~ msgstr "Tên Ä‘Æ°á»ng dẫn đầy đủ đến thÆ° mục HOME GNUnet" + +#~ msgid "" +#~ "This gives the root-directory of the GNUnet installation. Make sure there " +#~ "is some space left in that directory. :-) Users inserting or indexing " +#~ "files will be able to store data in this directory up to the (global) " +#~ "quota specified below. Having a few gigabytes of free space is " +#~ "recommended." +#~ msgstr "" +#~ "Äây Ä‘Æ°a ra thÆ° mục gốc của bản cài đặt GNUnet. Hãy kiểm tra xem vẫn còn " +#~ "có sức chứa còn lại trong thÆ° mục đó. :-)\n" +#~ "NgÆ°á»i dùng cần chèn hay phụ lục tập tin thì có thể lÆ°u dữ liệu vào thÆ° " +#~ "mục này đến hạn ngạch (toàn cục) được ghi rõ dÆ°á»›i đây. Khuyên có vài GB " +#~ "sức chứa còn rảnh." + +#~ msgid "Full pathname of GNUnet directory for file-sharing data" +#~ msgstr "" +#~ "Tên Ä‘Æ°á»ng dẫn đầy đủ đến thÆ° mục GNUnet sẽ chứa dữ liệu chia sẻ tập tin" + +#~ msgid "Full pathname to the directory with the key-value database" +#~ msgstr "Tên Ä‘Æ°á»ng dẫn đầy đủ đến thÆ° mục có cÆ¡ sở dữ liệu khoá-giá_trị " + +#~ msgid "Note that the kvstore is currently not used." +#~ msgstr "Ghi chú rằng hiện thá»i không dùng kvstore. " + +#~ msgid "Full pathname of GNUnet directory for indexed files symbolic links" +#~ msgstr "" +#~ "Tên Ä‘Æ°á»ng dẫn đầy đủ đến thÆ° mục GNUnet sẽ chứa các liên kết tÆ°Æ¡ng trÆ°ng " +#~ "đến tập tin phụ lục" + +#~ msgid "How many minutes should peer advertisements last?" +#~ msgstr "Có nên quảng cáo đồng đẳnh trong mấy phút?" + +#~ msgid "" +#~ "How many minutes is the current IP valid? (GNUnet will sign HELLO " +#~ "messages with this expiration timeline. If you are on dialup, 60 (for 1 " +#~ "hour) is suggested. If you have a static IP address, you may want to set " +#~ "this to a large value (say 14400). The default is 1440 (1 day). If your " +#~ "IP changes periodically, you will want to choose an expiry period smaller " +#~ "than the frequency with which your IP changes." +#~ msgstr "" +#~ "Äịa chỉ IP hiện thá»i vẫn hợp lệ trong bao nhiêu phút? (GNUnet sẽ ký má»—i " +#~ "thông Ä‘iệp HELLO dùng thá»i hạn này. Nếu bạn quay số để kết nối, khuyên " +#~ "dùng 60 (1 giá»). Nếu máy này có má»™t địa chỉ IP tÄ©nh, má»™t giá trị lá»›n hÆ¡n " +#~ "(v.d. 14400) có ích. Mặc định là 1440 (1 ngày). Nếu máy này có má»™t địa " +#~ "chỉ IP thay đổi theo định kỳ, khuyên bạn chá»n má»™t thá»i hạn ngắn hÆ¡n " +#~ "khoảng thá»i gian giữa hai lần thay đổi địa chỉ IP." + +#~ msgid "Where can GNUnet find an initial list of peers?" +#~ msgstr "GNUnet có thể tìm má»™t danh sách các đồng đẳng đầu tiên ở đâu?" + +#~ msgid "" +#~ "GNUnet can automatically update the hostlist from the web. While GNUnet " +#~ "internally communicates which hosts are online, it is typically a good " +#~ "idea to get a fresh hostlist whenever gnunetd starts from the WEB. By " +#~ "setting this option, you can specify from which server gnunetd should try " +#~ "to download the hostlist. The default should be fine for now.\n" +#~ "\t\t\n" +#~ "The general format is a list of space-separated URLs. Each URL must have " +#~ "the format http://HOSTNAME/FILENAME\n" +#~ "\t\t\n" +#~ "If you want to setup an alternate hostlist server, you must run a " +#~ "permanent node and \"cat data/hosts/* > hostlist\" every few minutes to " +#~ "keep the list up-to-date.\n" +#~ "\t\t\n" +#~ "If you do not specify a HOSTLISTURL, you must copy valid hostkeys to data/" +#~ "hosts manually." +#~ msgstr "" +#~ "GNUnet có khả năng tá»± Ä‘á»™ng cập nhật danh sách các máy chủ từ Web. Dù " +#~ "GNUnet liên lạc ná»™i bá»™ những máy này hiện thá»i trá»±c tuyến, thÆ°á»ng có ích " +#~ "để lấy má»™t danh sách máy má»›i từ Web khi nào trình ná»n gnunetd khởi chạy. " +#~ "Bằng cách đặt tùy chá»n này, bạn có thể ghi rõ gnunetd nên thá»­ tải danh " +#~ "sách máy xuống máy phục vụ nào. Bây giá» giá trị mặc định vẫn ổn.\n" +#~ "\n" +#~ "Äịnh dạng chung là má»™t danh sách các địa chỉ URL định giá»›i bằng dấu cách. " +#~ "Má»—i địa chỉ URL nên có dạng « http://tên_máy/tên_tập_tin ».\n" +#~ "\n" +#~ "Muốn thiết lập má»™t máy phục vụ danh sách máy xen kẽ thì bạn cần phải chạy " +#~ "má»™t nút thông tin (node) bá»n bỉ, và chạy câu lệnh « cat data/hosts/* > " +#~ "hostlist » sau má»—i vài phút để cập nhật danh sách.\n" +#~ "\n" +#~ "Nếu bạn không ghi rõ má»™t HOSTLISTURL (địa chỉ URL của danh sách máy), bạn " +#~ "cÅ©ng cần phải tá»± sao chép má»—i khoá máy hợp lệ vào « data/hosts »." + +#~ msgid "HTTP Proxy Server" +#~ msgstr "Máy phục vụ ủy nhiệm HTTP" + +#~ msgid "" +#~ "If you have to use a proxy for outbound HTTP connections, specify the " +#~ "proxy configuration here. Default is no proxy." +#~ msgstr "" +#~ "Nếu bạn cần dùng má»™t máy phục vụ ủy nhiệm cho kết nối HTTP Ä‘i ra, hãy ghi " +#~ "rõ cấu hình ủy nhiệm ở đây. Mặc định là không dùng ủy nhiệm." + +#~ msgid "" +#~ "Name of the directory where gnunetd should store contact information " +#~ "about peers" +#~ msgstr "" +#~ "Tên của thÆ° mục vào đó gnunetd nên lÆ°u thông tin liên lạc vỠđồng đẳng" + +#~ msgid "" +#~ "Unless you want to share the directory directly using a webserver, the " +#~ "default is most likely just fine." +#~ msgstr "" +#~ "Nếu bạn không muốn chia sẻ thÆ° mục má»™t cách trá»±c tiếp dùng má»™t máy phục " +#~ "vụ Web, giá trị mặc định rất có thể ổn." + +#~ msgid "How long should logs be kept?" +#~ msgstr "Bao lâu nên giữ bản theo dõi?" + +#~ msgid "" +#~ "How long should logs be kept? If you specify a value greater than zero, a " +#~ "log is created each day with the date appended to its filename. These " +#~ "logs are deleted after $KEEPLOG days.\tTo keep logs forever, set this " +#~ "value to 0." +#~ msgstr "" +#~ "Bao lâu nên giữ sổ theo dõi (log)? Nếu bạn ghi rõ má»™t giá trị hÆ¡n số " +#~ "không, má»™t sổ theo dõi được tạo hàng ngày vá»›i ngày tháng được phụ thêm " +#~ "vào tên tập tin. Sổ theo dõi này bị xoá sau $KEEPLOG ngày.\tÄể không bao " +#~ "giá» xoá sổ theo dõi, hãy đặt giá trị này thành 0." + +#~ msgid "" +#~ "What maximum number of open file descriptors should be requested from the " +#~ "OS?" +#~ msgstr "" +#~ "Có nên yêu cầu từ hệ Ä‘iá»u hành bao nhiêu bá»™ mô tả tập tin còn mở (tối Ä‘a)?" + +#~ msgid "" +#~ "The default of 1024 should be fine for most systems. If your system can " +#~ "support more, increasing the number might help support additional clients " +#~ "on machines with plenty of bandwidth. For embedded systems, a smaller " +#~ "number might be acceptable. A value of 0 will leave the descriptor limit " +#~ "untouched. This option is mostly for OS X systems where the default is " +#~ "too low. Note that if gnunetd cannot obtain the desired number of file " +#~ "descriptors from the operating system, it will print a warning and try to " +#~ "run with what it is given." +#~ msgstr "" +#~ "Giá trị mặc định 1024 nên ổn cho phần lá»›n hệ thống. Nếu hệ thống này có " +#~ "khả năng há»— trợ nhiá»u bá»™ mô tả tập tin hÆ¡n, má»™t số lá»›n hÆ¡n có thể giúp há»— " +#~ "trợ các ứng dụng khách bổ sung trên máy có rất nhiá»u bảng thông. Äối vá»›i " +#~ "hệ thống nhúng, má»™t số nhá» hÆ¡n có thể ổn. Giá trị 0 sẽ không thay đổi " +#~ "giá»›i hạn. Tùy chá»n này thÆ°á»ng có ích trên hệ thống OSX (có giá trị mặc " +#~ "định quá thấp). Ghi chú rằng nếu gnunetd không thể lấy số các bá»™ mô tả " +#~ "tập tin yêu cầu từ hệ Ä‘iá»u hành, thì nó sẽ in ra má»™t cảnh báo và thá»­ chạy " +#~ "vá»›i số Ä‘Æ°a ra." + +#~ msgid "Where should gnunetd write the logs?" +#~ msgstr "gnunetd nên ghi sổ theo dõi vào đâu?" + +#~ msgid "Enable for extra-verbose logging." +#~ msgstr "Bật để theo dõi rất chi tiết hÆ¡n." + +#~ msgid "Logging" +#~ msgstr "Theo dõi" + +#~ msgid "Specify which system messages should be logged how" +#~ msgstr "Ghi rõ những thông Ä‘iệp hệ thống nào nên được theo dõi nhÆ° thế nào" + +#~ msgid "Logging of events for users" +#~ msgstr "Theo dõi sá»± kiện cho ngÆ°á»i dùng" + +#~ msgid "Logging of events for the system administrator" +#~ msgstr "Theo dõi sá»± kiện cho quản trị hệ thống" + +#~ msgid "Where should gnunetd write the PID?" +#~ msgstr "gnunetd nên ghi PID vào đâu?" + +#~ msgid "" +#~ "The default is no longer /var/run/gnunetd.pid since we could not delete " +#~ "the file on shutdown at that location." +#~ msgstr "" +#~ "Giá trị mặc định không còn là « /var/run/gnunetd.pid » lại, vì không thể " +#~ "xoá tập tin ở vị trí đó khi tắt máy." + +#~ msgid "As which user should gnunetd run?" +#~ msgstr "gnunetd nên chạy dÆ°á»›i ngÆ°á»i dùng nào?" + +#~ msgid "" +#~ "Empty means \"current user\". On computer startup, it is root/SYSTEM. " +#~ "Under Windows, this setting affects the creation of a new system service " +#~ "only." +#~ msgstr "" +#~ "Trống có nghÄ©a là « ngÆ°á»i dùng hiện thá»i ». Khi máy khởi Ä‘á»™ng, nó là « " +#~ "root/SYSTEM ». DÆ°á»›i Windows, thiết lập này chỉ ảnh hưởng đến việc tạo má»™t " +#~ "dịch vụ hệ thống." + +#~ msgid "Should gnunetd be automatically started when the system boots?" +#~ msgstr "Khi hệ thống khởi Ä‘á»™ng, có nên tá»± Ä‘á»™ng khởi chạy gnunetd không?" + +#~ msgid "" +#~ "Set to YES if gnunetd should be automatically started on boot. If this " +#~ "option is set, gnunet-setup will install a script to start the daemon " +#~ "upon completion. This option may not work on all systems." +#~ msgstr "" +#~ "Äặt thành YES (có) nếu trình ná»n gnunetd nên tá»± Ä‘á»™ng được khởi chạy khi " +#~ "hệ thống khởi Ä‘á»™ng. Nếu đặt tùy chá»n này thì tiến trình thiết lập gnunet-" +#~ "setup sẽ cài đặt má»™t văn lệnh để khởi chạy trình ná»n này má»™t khi hoàn " +#~ "tất. Tùy chá»n này có thể không hoạt Ä‘á»™ng đúng trên má»i hệ thống." + +#~ msgid "Which transport mechanisms should GNUnet use?" +#~ msgstr "GNUnet nên dùng những cÆ¡ chế truyá»n nào?" + +#~ msgid "" +#~ "Use a space-separated list of modules, e.g. \"udp smtp tcp\". The " +#~ "available transports are udp, tcp, http, smtp and nat.\n" +#~ "\t\t\n" +#~ "Loading the 'nat' and 'tcp' modules is required for peers behind NAT " +#~ "boxes that cannot directly be reached from the outside. Peers that are " +#~ "NOT behind a NAT box and that want to *allow* peers that ARE behind a NAT " +#~ "box to connect must ALSO load the 'nat' module. Note that the actual " +#~ "transfer will always be via tcp initiated by the peer behind the NAT " +#~ "box. The nat transport requires the use of tcp, http and/or smtp in " +#~ "addition to nat itself." +#~ msgstr "" +#~ "Dùng má»™t danh sách các mô-Ä‘un định giá»›i bằng dấu cách, v.d. « udp smtp " +#~ "tcp ». Những cÆ¡ chế truyá»n sẵn sàng: udp, tcp, http, smtp, nat.\n" +#~ "\n" +#~ "Nạp hai mô-Ä‘un « nat » và « tcp » cần thiết cho đồng đẳng nằm sau máy NAT " +#~ "mà không tá»›i được từ bên ngoài. Äồng đẳng KHÔNG phải nằm sau máy NAT và " +#~ "muốn _cho phép_ kết nối từ đồng đẳng mà CÓ phải nằm sau NAT thì CŨNG cần " +#~ "phải nạp mô-Ä‘un « nat ». Ghi chú rằng việc truyá»n thật lúc nào cÅ©ng chạy " +#~ "qua tcp, được sÆ¡ khởi bởi đồng đẳng nằm sau máy NAT. CÆ¡ chế truyá»n nat " +#~ "cÅ©ng cần thiết tcp, http và/hay smtp thêm vào nat chính nó." + +#~ msgid "Which applications should gnunetd support?" +#~ msgstr "gnunetd nên há»— trợ những ứng dụng nào?" + +#~ msgid "" +#~ "Whenever this option is changed, you MUST run gnunet-update. Currently, " +#~ "the available applications are:\n" +#~ "\n" +#~ "advertising: advertises your peer to other peers. Without it, your peer " +#~ "will not participate in informing peers about other peers. You should " +#~ "always load this module.\n" +#~ "\n" +#~ "getoption: allows clients to query gnunetd about the values of various " +#~ "configuration options. Many tools need this. You should always load " +#~ "this module.\n" +#~ "\n" +#~ "stats: allows tools like gnunet-stats and gnunet-gtk to query gnunetd " +#~ "about various statistics. This information is usually quite useful to " +#~ "diagnose errors, hence it is recommended that you load this module.\n" +#~ "\n" +#~ "traffic: keeps track of how many messages were recently received and " +#~ "transmitted. This information can then be used to establish how much " +#~ "cover traffic is currently available. The amount of cover traffic " +#~ "becomes important if you want to make anonymous requests with an " +#~ "anonymity level that is greater than one. It is recommended that you " +#~ "load this module.\n" +#~ "\n" +#~ "fs: needed for anonymous file sharing. You should always load this " +#~ "module.\n" +#~ "\n" +#~ "hostlist: integrated hostlist HTTP server. Useful if you want to offer a " +#~ "hostlist and running Apache would be overkill.\n" +#~ "\n" +#~ "chat: broadcast chat (demo-application, ALPHA quality).\tRequired for " +#~ "gnunet-chat. Note that the current implementation of chat is not " +#~ "considered to be secure.\n" +#~ "\n" +#~ "tbench: benchmark transport performance. Required for gnunet-tbench. " +#~ "Note that tbench allows other users to abuse your resources.\n" +#~ "\n" +#~ "tracekit: topology visualization toolkit. Required for gnunet-tracekit. " +#~ "Note that loading tracekit will make it slightly easier for an adversary " +#~ "to compromise your anonymity." +#~ msgstr "" +#~ "Khi nào tùy chá»n này bị thay đổi, bạn CẦN PHẢI chạy tiến trình cập nhật " +#~ "gnunet-update. Hiện thá»i có những ứng dụng sẵn sàng này:\n" +#~ "\n" +#~ " • advertising\tquảng cáo đồng đẳng này cho các đồng đẳng khác. Không có " +#~ "ứng dụng này thì đồng đẳng này sẽ không tham gia hoạt Ä‘á»™ng cho đồng đẳng " +#~ "biết vỠđồng đẳng khác. Lúc nào cÅ©ng nên nạp mô-Ä‘un này.\n" +#~ "\n" +#~ " • getoption\tcho phép ứng dụng khách há»i gnunetd vá» giá trị của má»™t số " +#~ "tùy chá»n cấu hình nào đó. Rất nhiá»u công cụ cần chức năng này. Lúc nào " +#~ "cÅ©ng nên nạp mô-Ä‘un này.\n" +#~ "\n" +#~ " • stats\tcho phép công cụ nhÆ° gnunet-stats và gnunet-gtk há»i gnunetd vá» " +#~ "má»™t số thống kê nào đó. Thông tin này thÆ°á»ng hÆ¡i hữu ích để chẩn Ä‘oán " +#~ "lá»—i, do đó khuyên bạn nạp mô-Ä‘un này.\n" +#~ "\n" +#~ " • traffic\ttheo dõi bao nhiêu tin nhẳn vừa nhận và gá»­i. Thông tin này " +#~ "thì có thể được dùng để tính bao nhiêu giao thông trải ra hiện thá»i sẵn " +#~ "sàng. Lượng giao thông trải ra trở thành quan trá»ng nếu bạn muốn gá»­i yêu " +#~ "cầu nặc danh vá»›i má»™t cấp nặc danh hÆ¡n má»™t. Khuyên bạn nạp mô-Ä‘un này.\n" +#~ "\n" +#~ " • fs\tcần để chia sẻ tập tin má»™t cách nặc danh. Lúc nào cÅ©ng nên nạp mô-" +#~ "Ä‘un này.\n" +#~ "\n" +#~ " • hostlist\ttrình phục vụ HTTP danh sách máy thống nhất. Có ích nếu bạn " +#~ "muốn cung cấp má»™t danh sách máy, nhÆ°ng không muốn chạy Apache cho má»™t " +#~ "công việc rất nhá» nhÆ° vậy.\n" +#~ "\n" +#~ " • chat\ttrò chuyện quảng bá (ứng dụng minh hoạ, vẫn ALPHA). Cần thiết " +#~ "cho ứng dụng trò chuyện gnunet-chat. Ghi chú rằng bản thá»±c hiện chat hiện " +#~ "thá»i chÆ°a được xem là bảo mật.\n" +#~ "\n" +#~ " • tbench\tkiểm chuẩn hiệu suất truyá»n. Cần thiết cho gnunet-tbench. Ghi " +#~ "chú rằng tbench cho phép ngÆ°á»i dùng khác lạm dụng các tài nguyên của " +#~ "bạn.\n" +#~ "\n" +#~ " • tracekit\tbá»™ công cụ mÆ°á»ng tượng địa hình. Cần thiết cho gnunet-" +#~ "tracekit. Ghi chú rằng việc nạp tracekit sẽ làm cho má»™t ít dá»… hÆ¡n khi " +#~ "ngÆ°á»i dùng muốn xâm nhập tình trạng nặc danh của bạn." + +#~ msgid "Disable client-server connections" +#~ msgstr "Tắt má»i kết nối kiểu khách-máy_phục_vụ" + +#~ msgid "" +#~ "This option can be used to tell gnunetd not to open the client port. " +#~ "When run like this, gnunetd will participate as a peer in the network but " +#~ "not support any user interfaces. This may be useful for headless systems " +#~ "that are never expected to have end-user interactions. Note that this " +#~ "will also prevent you from running diagnostic tools like gnunet-stats!" +#~ msgstr "" +#~ "Tùy chá»n này có thể được dùng để báo trình ná»n gnunetd không mở cổng cho " +#~ "ứng dụng khách. Khi chạy bằng cách này, gnunetd sẽ tham gia là má»™t đồng " +#~ "đẳng trên mạng, còn không há»— trợ giao diện ngÆ°á»i dùng nào. Có thể hữu ích " +#~ "cho hệ thống không cần màn hình mà không bao giá» nên tÆ°Æ¡ng tác vá»›i ngÆ°á»i " +#~ "dùng cuối cùng. Ghi chú rằng tùy chá»n này cÅ©ng ngăn cản bạn chạy công cụ " +#~ "chẩn Ä‘oán nhÆ° tiến trình thống kê gnunet-stats !" + +#~ msgid "YES disables IPv6 support, NO enables IPv6 support" +#~ msgstr "YES hay NO thì tắt hay bật há»— trợ IPv6" + +#~ msgid "" +#~ "This option may be useful on peers where the kernel does not support " +#~ "IPv6. You might also want to set this option if you do not have an IPv6 " +#~ "network connection." +#~ msgstr "" +#~ "Tùy chá»n này có thể hữu ích trên đồng đẳng không có hạt nhân há»— trợ IPv6. " +#~ "CÅ©ng có thể đặt tùy chá»n này nếu không có kết nối mạng kiểu IPv6." + +#~ msgid "Disable peer discovery" +#~ msgstr "Tắt khám phá đồng đẳng" + +#~ msgid "" +#~ "The option 'PRIVATE-NETWORK' can be used to limit the connections of this " +#~ "peer to peers of which the hostkey has been copied by hand to data/" +#~ "hosts; if this option is given, GNUnet will not accept advertisements of " +#~ "peers that the local node does not already know about. Note that in " +#~ "order for this option to work, HOSTLISTURL should either not be set at " +#~ "all or be set to a trusted peer that only advertises the private network. " +#~ "Also, the option does NOT work at the moment if the NAT transport is " +#~ "loaded; for that, a couple of lines above would need some minor " +#~ "editing :-)." +#~ msgstr "" +#~ "Tùy chá»n « PRIVATE-NETWORK » có thể được dùng để hạn chế kết nối của đồng " +#~ "đẳng này thành những đồng đẳng có khoá máy đã được sao chép bằng tay vào " +#~ "« data/hosts »; nếu bật tùy chá»n này thì GNUnet sẽ không chấp nhận quảng " +#~ "cáo vỠđồng đẳng không được nút cục bá»™ nhận ra. Ghi chú rằng tùy chá»n này " +#~ "cÅ©ng cần HOSTLISTURL không đặt bằng cách nào cả hay có đặt thành má»™t đồng " +#~ "đẳng tin cậy mà chỉ quảng cáo mạng riêng. HÆ¡n nữa, tùy chá»n này KHÔNG " +#~ "hoạt Ä‘á»™ng khi nào cÆ¡ chế trung NAT được nạp: để tránh trÆ°á»ng hợp đó, cÅ©ng " +#~ "cần phải chỉnh sá»­a vài dòng bên trên. :-)" + +#~ msgid "Disable automatic establishment of connections" +#~ msgstr "Tắt tá»± Ä‘á»™ng thiết lập kết nối" + +#~ msgid "" +#~ "If this option is enabled, GNUnet will not automatically establish " +#~ "connections to other peers, but instead wait for applications to " +#~ "specifically request connections to other peers (or for other peers to " +#~ "connect to us)." +#~ msgstr "" +#~ "Bật tùy chá»n này thì GNUnet sẽ không tá»± Ä‘á»™ng thiết lập kết nối tá»›i đồng " +#~ "đẳng khác, thay vào đó nó đợi ứng đụng yêu cầu dứt khoát kết nối tá»›i đồng " +#~ "đẳng khác (hoặc đợi đồng đẳng khác kết nối đến máy này)." + +#~ msgid "Enable advertising of other peers by this peer" +#~ msgstr "Bật máy này quảng cáo đồng đẳng khác" + +#~ msgid "" +#~ "This option may be useful during testing, but turning it off is " +#~ "dangerous! If in any doubt, set it to YES (which is the default)." +#~ msgstr "" +#~ "Tùy chá»n này có thể hữu ích trong khi thá»­: trong má»i trÆ°á»ng hợp Ä‘á»u không " +#~ "nên tắt nó ! ChÆ°a chắc thì đặt nó thành YES (có) mà mặc định." + +#~ msgid "" +#~ "Which is the client-server port that is used between gnunetd and the " +#~ "clients (TCP only). You may firewall this port for non-local machines " +#~ "(but you do not have to since GNUnet will perform access control and only " +#~ "allow connections from machines that are listed under TRUSTED)." +#~ msgstr "" +#~ "Trình ná»n gnunetd và các ứng dụng khách liên lạc (chỉ TCP) qua cổng khách-" +#~ "phục_vụ nào? Bạn cÅ©ng có thể đặt bức tÆ°á»ng lá»­a giữa cổng này và các máy " +#~ "khác cục bá»™, nhÆ°ng không cần phải vì GNUnet sẽ Ä‘iá»u khiển truy cập và chỉ " +#~ "cho phép kết nối từ máy được liệt kê dÆ°á»›i TRUSTED (tin cậy). " + +#~ msgid "IPv4 networks allowed to use gnunetd server" +#~ msgstr "Các mạng IPV4 được phép dùng trình phục vụ gnunetd" + +#~ msgid "" +#~ "This option specifies which hosts are trusted enough to connect as " +#~ "clients (to the TCP port). This is useful if you run gnunetd on one host " +#~ "of your network and want to allow all other hosts to use this node as " +#~ "their server. By default, this is set to 'loopback only'. The format is " +#~ "IP/NETMASK where the IP is specified in dotted-decimal and the netmask " +#~ "either in CIDR notation (/16) or in dotted decimal (255.255.0.0). Several " +#~ "entries must be separated by a semicolon, spaces are not allowed." +#~ msgstr "" +#~ "Tùy chá»n này ghi rõ những máy nào đủ tin cậy để kết nối là ứng dụng khách " +#~ "(đến cổng TCP). Có ích nếu bạn chạy trình nên gnunetd trên má»™t máy của " +#~ "mạng cục bá»™, cÅ©ng muốn các máy khác cùng mạng dùng nút này làm máy phục " +#~ "vụ. Mặc định là tùy chá»n này được đặt thành « loopback only » (chỉ mạch " +#~ "ná»™i bá»™). Äịnh dạng là IP/MẶT_NẠ_MẠNG mà địa chỉ IP được ghi rõ theo thập " +#~ "phân đánh chấm (v.d. 255.255.0.0), và mặt nạ mạng (netmask) theo hoặc " +#~ "cách ghi CIDR (v.d. 1/16) hoặc thập phân đánh chấm. Vài mục nhập nên định " +#~ "giá»›i bằng dấu hai chấm, cÅ©ng không cho phép khoảng cách." + +#~ msgid "IPv6 networks allowed to use gnunetd server" +#~ msgstr "Các mạng IPv6 được phép dùng trình phục vụ gnunetd" + +#~ msgid "Limit connections to the specfied set of peers." +#~ msgstr "Hạn chế kết nối thành tập hợp đồng đẳng được ghi rõ." + +#~ msgid "" +#~ "If this option is not set, any peer is allowed to connect. If it is set, " +#~ "only the specified peers are allowed. Specify the list of peer IDs (not " +#~ "IPs!)" +#~ msgstr "" +#~ "Không bật tùy chá»n này thì má»i đồng đẳng được phép kết nối. Nếu bật nó " +#~ "thì chỉ cho phép những đồng đẳng Ä‘Æ°a ra. Hãy ghi rõ danh sách các mã số " +#~ "đồng đẳng, không phải địa chỉ IP !" + +#~ msgid "Run gnunetd as this group." +#~ msgstr "Chạy gnunetd dÆ°á»›i nhóm này." + +#~ msgid "" +#~ "When started as root, gnunetd will change permissions to the given group." +#~ msgstr "" +#~ "Khi khởi chạy bởi ngÆ°á»i chủ, trình ná»n gnunetd sẽ chuyển đổi quyá»n truy " +#~ "cập sang nhóm Ä‘Æ°a ra." + +#~ msgid "Prevent the specfied set of peers from connecting." +#~ msgstr "Chặn kết nối từ tập hợp đồng đẳng được ghi rõ." + +#~ msgid "" +#~ "If this option is not set, any peer is allowed to connect. If the ID of " +#~ "a peer is listed here, connections from that peer will be refused. " +#~ "Specify the list of peer IDs (not IPs!)" +#~ msgstr "" +#~ "Không bật tùy chá»n này thì má»i đồng đẳng Ä‘á»u được phép kết nối. Nếu mã số " +#~ "của má»™t đồng đẳng nào đó được liệt kê ở đây, thì kết nối từ máy đó bị từ " +#~ "chối. Hãy ghi rõ danh sách các mã số đồng đẳng, không phải địa chỉ IP !" + +#~ msgid "Topology Maintenance" +#~ msgstr "Duy trì địa hình" + +#~ msgid "Rarely used settings for peer advertisements and connections" +#~ msgstr "Thiết lập ít dùng vá» quảng cáo và kết nối của đồng đẳng" + +#~ msgid "General settings" +#~ msgstr "Thiết lập chung" + +#~ msgid "Settings that change the behavior of GNUnet in general" +#~ msgstr "Thiết lập mà sá»­a đổi ứng xá»­ chung của GNUnet" + +#~ msgid "Modules" +#~ msgstr "Mô-Ä‘un" + +#~ msgid "Settings that select specific implementations for GNUnet modules" +#~ msgstr "Thiết lập mà chá»n bản thá»±c hiện riêng cho mô-Ä‘un GNUnet" + +#~ msgid "Fundamentals" +#~ msgstr "CÆ¡ bản" + +#~ msgid "Which database should be used?" +#~ msgstr "Có nên dùng cÆ¡ sở dữ liệu nào?" + +#, fuzzy +#~ msgid "" +#~ "Which database should be used? The options are \"sqstore_sqlite\", " +#~ "\"sqstore_postgres\" and \"sqstore_mysql\". You must run gnunet-update " +#~ "after changing this value!\n" +#~ "\t\t\t\n" +#~ "In order to use MySQL or Postgres, you must configure the respective " +#~ "database, which is relatively simple. Read the file doc/README.mysql or " +#~ "doc/README.postgres for how to setup the respective database." +#~ msgstr "" +#~ "Có nên dùng cÆ¡ sở dữ liệu nào? Hai tùy chá»n là « sqstore_sqlite » và « " +#~ "sqstore_mysql ». Sau khi thay đổi giá trị này thì cÅ©ng cần phải chạy tiến " +#~ "trình cập nhật gnunet-update !\n" +#~ "\n" +#~ "Äể sá»­ dụng sqstore_mysql, bạn cÅ©ng cần phải cấu hình cÆ¡ sở dữ liệu MySQL: " +#~ "má»™t công việc hÆ¡i Ä‘Æ¡n giản. Hãy Ä‘á»c tài liệu Äá»c Äi « doc/README.mysql » " +#~ "để tìm biết thiết lập MySQL nhÆ° thế nào." + +#~ msgid "Which topology should be used?" +#~ msgstr "Có nên địa hình nào?" + +#~ msgid "" +#~ "Which database should be used for the temporary datastore of the DHT?" +#~ msgstr "Có nên dùng cÆ¡ sở dữ liệu nào làm kho dữ liệu tạm thá»i của DHT?" + +#~ msgid "" +#~ "Which topology should be used? The only option at the moment is " +#~ "\"topology_default\"" +#~ msgstr "" +#~ "Có nên địa hình nào? Tùy chá»n duy nhất hiện thá»i là « topology_default »." + +#~ msgid "" +#~ "The minimum number of connected friends before this peer is allowed to " +#~ "connect to peers that are not listed as friends" +#~ msgstr "" +#~ "Số tối thiểu các bạn bè có kết nối trÆ°á»›c khi đồng đẳng nay được phép kết " +#~ "nối tá»›i đồng đẳng lạ (không phải được liệt kê là bạn bè)" + +#~ msgid "" +#~ "Note that this option does not guarantee that the peer will be able to " +#~ "connect to the specified number of friends. Also, if the peer had " +#~ "connected to a sufficient number of friends and then established non-" +#~ "friend connections, some of the friends may drop out of the network, " +#~ "temporarily resulting in having fewer than the specified number of " +#~ "friends connected while being connected to non-friends. However, it is " +#~ "guaranteed that the peer itself will never choose to drop a friend's " +#~ "connection if this would result in dropping below the specified number of " +#~ "friends (unless that number is higher than the overall connection target)." +#~ msgstr "" +#~ "Ghi chú rằng tùy chá»n này không đảm bảo rằng đồng đẳng sẽ kết nối được " +#~ "tá»›i số các bạn bè Ä‘Æ°a ra. HÆ¡n nữa, nếu đồng đẳng có kết nối tá»›i đủ bạn " +#~ "bè, sau đó thiết lập kết nối khác bạn bè, thì má»™t số bạn bè có thể dứt " +#~ "khá»i mạng, tạm thá»i có kết quả là quá ít bạn bè có kết nối trong khi kết " +#~ "nối tá»›i khác bạn bè. Tuy nhiên đảm bảo rằng đồng đẳng chính nó không bao " +#~ "giá» chá»n ngắt kết nối tá»›i bạn bè nếu việc đó có kết quả là quá ít bán bè " +#~ "có kết nối (nếu số đã đặt không phải lá»›n hÆ¡n đích kết nối toàn bá»™)." + +#~ msgid "" +#~ "If set to YES, the peer is only allowed to connect to other peers that " +#~ "are explicitly specified as friends" +#~ msgstr "" +#~ "Bật tùy chá»n này (đặt YES) thì đồng đẳng chỉ được phép tá»›i đồng đẳng được " +#~ "ghi rõ dứt khoát là bạn bè" + +#~ msgid "" +#~ "Use YES only if you have (trustworthy) friends that use GNUnet and are " +#~ "afraid of establishing (direct) connections to unknown peers" +#~ msgstr "" +#~ "Hãy đặt YES chỉ nếu bạn có bạn bè tin cậy có sá»­ dụng GNUnet và không muốn " +#~ "thiết lập kết nối trá»±c tiếp tá»›i đồng đẳng lạ" + +#~ msgid "List of friends for friend-to-friend topology" +#~ msgstr "Danh sách bạn bè cho địa hình bạn-đến-bạn" + +#~ msgid "" +#~ "Specifies the name of a file which contains a list of GNUnet peer IDs " +#~ "that are friends. If used with the friend-to-friend topology, this will " +#~ "ensure that GNUnet only connects to these peers (via any available " +#~ "transport)." +#~ msgstr "" +#~ "Ghi rõ tên của má»™t tập tin chứa danh sách các mã số đồng đẳng GNUnet cÅ©ng " +#~ "là bạn bè. Nếu dùng vá»›i địa hình bạn-đến-bạn, thì tùy chá»n này sẽ đảm bảo " +#~ "rằng GNUnet chỉ kết nối tá»›i những đồng đẳng đó (qua bất cứ cÆ¡ chế truyá»n " +#~ "hoạt Ä‘á»™ng nào)." + +#~ msgid "Friend-to-Friend Topology Specification" +#~ msgstr "Äặc tả địa hình bạn-đến-bạn" + +#~ msgid "Settings for restricting connections to friends" +#~ msgstr "Thiết lập để hạn chế kết nối thành bạn bè" + +#~ msgid "Name of the MySQL database GNUnet should use" +#~ msgstr "Tên của cÆ¡ sở dữ liệu MySQL mà GNUnet nên dùng" + +#~ msgid "Configuration file that specifies the MySQL username and password" +#~ msgstr "Tập tin cấu hình mà ghi rõ tên ngÆ°á»i dùng và mật khẩu MySQL" + +#~ msgid "Configuration of the MySQL database" +#~ msgstr "Cấu hình của cÆ¡ sở dữ liệu MySQL" + +#~ msgid "MB of diskspace GNUnet can use for anonymous file sharing" +#~ msgstr "MB sức chứa trên Ä‘Ä©a cho GNUnet dùng để chia sẻ tập tin nặc danh" + +#~ msgid "" +#~ "How much disk space (MB) is GNUnet allowed to use for anonymous file " +#~ "sharing? This does not take indexed files into account, only the space " +#~ "directly used by GNUnet is accounted for. GNUnet will gather content " +#~ "from the network if the current space-consumption is below the number " +#~ "given here (and if content migration is allowed below).\n" +#~ "\n" +#~ "Note that if you change the quota, you need to run gnunet-update " +#~ "afterwards." +#~ msgstr "" +#~ "Bao nhiêu sức chứa trên Ä‘Ä©a (theo MB) cho phép GNUnet dùng để chia sẻ tập " +#~ "tin má»™t cách nặc danh? Giá trị này không tính tập tin phụ lục, chỉ tính " +#~ "sức chứa được GNUnet dùng trá»±c tiếp. GNUnet sẽ tập hợp ná»™i dung từ mạng " +#~ "nếu tiêu thụ sức chứa hiện thá»i nhá» hÆ¡n số Ä‘Æ°a ra ở đây (và nếu chức năng " +#~ "nâng cấp ná»™i dung được phép bên dÆ°á»›i).\n" +#~ "\n" +#~ "Ghi chú rằng nếu bạn sá»­a đổi hạn ngạch này, sau đó cÅ©ng cần phải chạy " +#~ "tiến trình cập nhật gnunet-update." + +#~ msgid "Number of entries in the migration buffer" +#~ msgstr "Số các mục nhập trong vùng đệm nâng cấp" + +#~ msgid "" +#~ "Each entry uses about 32k of memory. More entries can reduce disk IO and " +#~ "CPU usage at the expense of having gnunetd use more memory. Very large " +#~ "values may again increase CPU usage. A value of 0 will prevent your peer " +#~ "from sending unsolicited responses." +#~ msgstr "" +#~ "Má»—i mục nhập chiếm khoảng 32k trong vùng nhá»›. Nhiá»u mục nhập hÆ¡n thì có " +#~ "thể giảm VR của Ä‘Ä©a và sá»­ dụng CPU, còn gnunetd chiếm vùng nhá»› lá»›n hÆ¡n. " +#~ "Giá trị rất lá»›n cÅ©ng có thể tăng sá»­ dụng CPU. Giá trị 0 sẽ ngăn cản máy " +#~ "này đáp ứng mà không yêu cầu." + +#~ msgid "Size of the routing table for anonymous routing." +#~ msgstr "Kích cỡ của bảng định tuyến đối vá»›i định tuyến nặc danh." + +#~ msgid "Size of the routing table for DHT routing." +#~ msgstr "Kích cỡ của bảng định tuyến đối vá»›i định tuyến DHT." + +#~ msgid "Allow migrating content to this peer." +#~ msgstr "Cho phép nâng cấp ná»™i dung lên máy này." + +#~ msgid "" +#~ "If you say yes here, GNUnet will migrate content to your server, and you " +#~ "will not be able to control what data is stored on your machine. \n" +#~ "\t\t\t\n" +#~ "If you activate it, you can claim for *all* the non-indexed (-n to gnunet-" +#~ "insert) content that you did not know what it was even if an adversary " +#~ "takes control of your machine. If you do not activate it, it is obvious " +#~ "that you have knowledge of all the content that is hosted on your machine " +#~ "and thus can be considered liable for it." +#~ msgstr "" +#~ "Bật tùy chá»n này thì GNUnet sẽ nâng cấp ná»™i dung đến máy phục vụ này, và " +#~ "bạn không thể Ä‘iá»u khiển dữ liệu nào được giữ trên máy này.\n" +#~ "\n" +#~ "Tùy chá»n này cho phép ngÆ°á»i dùng từ chối trách nhiệm vá» ná»™i dung không " +#~ "phụ lục (-n tá»›i gnunet-insert) nằm trong máy của mình, thậm chí nếu ngÆ°á»i " +#~ "khác xâm nhập hệ thống. Không bật tùy chá»n này thì ngÆ°á»i dùng chịu trách " +#~ "nhiệm vá» tất cả các ná»™i dung trên máy của mình." + +#~ msgid "" +#~ "MB of diskspace GNUnet can use for caching DHT index data (the data will " +#~ "be stored in /tmp)" +#~ msgstr "" +#~ "MB sức chứa trên Ä‘Ä©a cho GNUnet dùng để lÆ°u tạm dữ liệu phụ lục DHT (dữ " +#~ "liệu được giữ trong /tmp)" + +#~ msgid "" +#~ "DHT index data is inherently small and expires comparatively quickly. It " +#~ "is deleted whenever gnunetd is shut down.\n" +#~ "\n" +#~ "The size of the DSTORE QUOTA is specified in MB." +#~ msgstr "" +#~ "Dữ liệu phụ lục DHT vốn đã nhá» và hết hạn hÆ¡i nhanh. Nó bị xoá khi nào " +#~ "gnunetd bị thoát.\n" +#~ "\n" +#~ "Kích cỡ của hạn ngạch kho dữ liệu (DSTORE QUOTA) được ghi rõ theo MB." + +#~ msgid "Options for anonymous file sharing" +#~ msgstr "Tùy chá»n vá» chia sẻ tập tin nặc danh" + +#~ msgid "Applications" +#~ msgstr "Ứng dụng" + +#~ msgid "Is this machine unreachable behind a NAT?" +#~ msgstr "Máy này không tá»›i được ở sau NAT không?" + +#~ msgid "" +#~ "Set to YES if this machine is behind a NAT that limits connections from " +#~ "the outside to the GNUnet port and that cannot be traversed using UPnP. " +#~ "Note that if you have configured your NAT box to allow direct connections " +#~ "from other machines to the GNUnet ports or if GNUnet can open ports using " +#~ "UPnP, you should set the option to NO. Set this only to YES if other " +#~ "peers cannot contact you directly. You can use 'make check' in src/" +#~ "transports/upnp/ to find out if your NAT supports UPnP. You can also use " +#~ "gnunet-transport-check with the '-p' option in order to determine which " +#~ "setting results in more connections. Use YES only if you get no " +#~ "connections otherwise. Set to AUTO to use YES if the local IP is belongs " +#~ "to a private IP network and NO otherwise." +#~ msgstr "" +#~ "Äặt thành YES (có) nếu máy này nằm sau má»™t máy NAT mà hạn chế kết nối từ " +#~ "bên ngoài đến cổng GNUnet và không thể Ä‘i qua được dùng UPnP. Ghi chú " +#~ "rằng nếu bạn đã cấu hình máy NAT để cho phép kết nối trá»±c tiếp từ máy " +#~ "khác đến cổng GNUnet, hoặc nếu GNUnet có quyá»n mở cổng dùng UPnP, thì bạn " +#~ "nên đặt tùy chá»n này thành NO (không). Chỉ đặt thành YES nếu đồng đẳng " +#~ "khác không thể liên lạc vá»›i máy này má»™t cách trá»±c tiếp. Bạn cÅ©ng có thể " +#~ "sá»­ dụng câu lệnh « make check » (trong /src/transports/upnp) để tìm biết " +#~ "nếu NAT đó há»— trợ UPnP không. Bạn cÅ©ng có thể sá»­ dụng công cụ gnunet-" +#~ "transport-check vá»›i tùy chá»n « -p » để quyết định thiết lập nào gây ra " +#~ "nhiá»u kết nối hÆ¡n. Äặt YES chỉ nếu bạn không nhận kết nối bằng cách khác. " +#~ "Äặt thành AUTO (tá»± Ä‘á»™ng) để sá»­ dụng YES nếu địa chỉ IP cục bá»™ thuá»™c vá» " +#~ "má»™t mạng IP riêng, không thì NO." + +#~ msgid "Which port should be used by the TCP IPv4 transport?" +#~ msgstr "CÆ¡ chế truyá»n IPv4 TCP nên dùng cổng nào?" + +#~ msgid "Should we try to determine our external IP using UPnP?" +#~ msgstr "" +#~ "Có nên thá»­ quyết định địa chỉ IP bên ngoài của mình dùng UPnP không?" + +#~ msgid "Which IP(v4)s are not allowed to connect?" +#~ msgstr "Những địa chỉ IP(v4) nào không có quyá»n kết nối?" + +#~ msgid "" +#~ "Which IP(v4)s are allowed to connect? Leave empty to use the IP of your " +#~ "primary network interface." +#~ msgstr "" +#~ "Những địa chỉ IP(v4) nào có quyá»n kết nối? Bá» trống để sá»­ dụng địa chỉ IP " +#~ "của giao diện mạng chính." + +#~ msgid "Which IPv6s are not allowed to connect?" +#~ msgstr "Những địa chỉ IPv6 nào không có quyá»n kết nối?" + +#~ msgid "" +#~ "Which IPv6s are allowed to connect? Leave empty to allow any IP to " +#~ "connect." +#~ msgstr "" +#~ "Những địa chỉ IPv6 nào có quyá»n kết nối? Bá» trống để cho phép má»i địa chỉ " +#~ "IP kết nối." + +#~ msgid "TCP transport" +#~ msgstr "CÆ¡ chế truyá»n TCP" + +#~ msgid "Which port should be used by the HTTP transport?" +#~ msgstr "CÆ¡ chế truyá»n HTTP nên dùng cổng nào?" + +#~ msgid "Which is the external port of the HTTP transport?" +#~ msgstr "CÆ¡ chế truyá»n HTTP dùng cổng bên ngoài nào?" + +#~ msgid "" +#~ "Use this option if your firewall maps, say, port 80 to your real HTTP " +#~ "port. This can be useful in making the HTTP messages appear even more " +#~ "legit (without needing to run gnunetd as root due to the use of a " +#~ "privileged port)." +#~ msgstr "" +#~ "Hãy bật tùy chá»n này nếu bức tÆ°á»ng lá»­a ánh xạ, v.d. cổng 80 vá»›i cổng HTTP " +#~ "thật. Có thể hữu ích để làm cho các thông Ä‘iệp HTTP hình nhÆ° ngay cả " +#~ "chính đáng hÆ¡n (mà không cần chạy gnunetd dÆ°á»›i ngÆ°á»i chủ do dùng má»™t cổng " +#~ "có quyá»n đặc biệt)." + +#~ msgid "HTTP transport" +#~ msgstr "CÆ¡ chế truyá»n HTTP" + +#~ msgid "What is the maximum transfer unit for SMTP?" +#~ msgstr "Äối vá»›i SMTP, Ä‘Æ¡n vị truyá»n tối Ä‘a là gì?" + +#~ msgid "" +#~ "What is the maximum number of e-mails that gnunetd would be allowed to " +#~ "send per hour?" +#~ msgstr "gnunetd có quyá»n gá»­i má»—i giá» bao nhiêu thÆ° Ä‘iện tá»­ (tối Ä‘a)?" + +#~ msgid "Use 0 for unlimited" +#~ msgstr "0 = vô hạn" + +#~ msgid "Which e-mail address should be used to send e-mail to this peer?" +#~ msgstr "Äể gá»­i thÆ° cho đồng đẳng này, có nên dùng địa chỉ thÆ° Ä‘iện tá»­ nào?" + +#~ msgid "" +#~ "You must make sure that e-mail received at this address is forwarded to " +#~ "the PIPE which is read by gnunetd. Use the FILTER option to filter e-" +#~ "mail with procmail and the PIPE option to set the name of the pipe." +#~ msgstr "" +#~ "Bạn cần phải đảm bảo rằng thÆ° Ä‘iện tá»­ được nhận ở địa chỉ này thật được " +#~ "chuyển tiếp tá»›i PIPE (ống dẫn) được gnunetd Ä‘á»c. Hãy dùng tùy chá»n FILTER " +#~ "(lá»c) để lá»c thÆ° bằng procmail, và tùy chá»n PIPE để đặt tên của ống dẫn." + +#~ msgid "" +#~ "Which header line should other peers include in e-mails to enable " +#~ "filtering?" +#~ msgstr "Äể hiệu lá»±c lá»c thÆ°, đồng đẳng khác nên ghi dòng đầu nào?" + +#~ msgid "" +#~ "You can specify a header line here which can then be used by procmail to " +#~ "filter GNUnet e-mail from your inbox and forward it to gnunetd." +#~ msgstr "" +#~ "Ở đây thì bạn có dịp ghi rõ má»™t dòng đầu cho procmail dùng để lá»c thÆ° " +#~ "GNUnet từ há»™p ThÆ° Äến của bạn và chuyển tiếp nó tá»›i gnunetd." + +#~ msgid "What is the filename of the pipe where gnunetd can read its e-mail?" +#~ msgstr "gnunetd có thể Ä‘á»c thÆ° qua ống dẫn có tên tập tin nào?" + +#~ msgid "" +#~ "Have a look at contrib/dot-procmailrc for an example .procmailrc file." +#~ msgstr "" +#~ "Xem « contrib/dot-procmailrc » để tìm má»™t tập tin .procmailrc ví dụ." + +#~ msgid "What is the name and port of the server for outgoing e-mail?" +#~ msgstr "Máy phục vụ thÆ° gá»­i ra có tên và cổng nào?" + +#~ msgid "The basic format is HOSTNAME:PORT." +#~ msgstr "Äịnh dạng cÆ¡ bản là « TÊN_MÃY:Cá»”NG »." + +#~ msgid "SMTP transport" +#~ msgstr "CÆ¡ chế SMTP" + +#~ msgid "Which port should be used by the UDP IPv4 transport?" +#~ msgstr "CÆ¡ chế truyá»n IPv4 UDP nên dùng cổng nào?" + +#~ msgid "What is the maximum transfer unit for UDP?" +#~ msgstr "Äối vá»›i UDP, Ä‘Æ¡n vị truyá»n tối Ä‘a là gì?" + +#~ msgid "Which IPs are not allowed to connect?" +#~ msgstr "Những địa chỉ IP nào không có quyá»n kết nối?" + +#~ msgid "" +#~ "Which IPs are allowed to connect? Leave empty to allow connections from " +#~ "any IP." +#~ msgstr "" +#~ "Những địa chỉ IP nào có quyá»n kết nối? Bá» trống để cho phép kết nối từ " +#~ "má»i địa chỉ IP." + +#~ msgid "UDP transport" +#~ msgstr "CÆ¡ chế truyá»n UDP" + +#~ msgid "Network interface" +#~ msgstr "Giao diện mạng" + +#~ msgid "External IP address (leave empty to try auto-detection)" +#~ msgstr "Äịa chỉ IP bên ngoài (bá» trống để thá»­ tá»± Ä‘á»™ng phát hiện)" + +#~ msgid "External IPv6 address (leave empty to try auto-detection)" +#~ msgstr "Äịa chỉ IPv6 bên ngoài (bá» trống để thá»­ tá»± Ä‘á»™ng phát hiện)" + +#~ msgid "Transports" +#~ msgstr "CÆ¡ chế truyá»n" + +#~ msgid "What is the maximum number of bytes per second that we may receive?" +#~ msgstr "Có thể nhận bao nhiêu byte má»—i giây (tối Ä‘a)?" + +#~ msgid "What is the maximum number of bytes per second that we may send?" +#~ msgstr "Có thể gá»­i bao nhiêu byte má»—i giây (tối Ä‘a)?" + +#~ msgid "What is the maximum CPU load (percentage)?" +#~ msgstr "Tải trá»ng CPU tối Ä‘a là gì (theo phần trăm)?" + +#~ msgid "" +#~ "The highest tolerable CPU load. Load here always refers to the total " +#~ "system load, that is it includes CPU utilization by other processes. A " +#~ "value of 50 means that once your 1 minute-load average goes over 50% non-" +#~ "idle, GNUnet will try to reduce CPU consumption until the load goes under " +#~ "the threshold. Reasonable values are typically between 50 and 100. " +#~ "Multiprocessors may use values above 100." +#~ msgstr "" +#~ "Tải trá»ng CPU cao nhất có thể. Ở đây thì tải trá»ng tham chiếu đến tổng số " +#~ "tải trá»ng hệ thống, tức là nó cÅ©ng tính sá»­ dụng CPU của các tiến trình " +#~ "khác. Giá trị 50 có nghÄ©a là má»™t khi tải trá»ng trung bình má»—i phút vượt " +#~ "quá 50% không nghỉ, thì GNUnet thá»­ giảm sá»­ dụng CPU đến khi tải trá»ng nhá» " +#~ "hÆ¡n ngưỡng. Giá trị hợp lý thÆ°á»ng nằm giữa 50 và 100. Máy Ä‘a bá»™ xá»­ lý có " +#~ "khả năng sá»­ dụng giá trị hÆ¡n 100." + +#~ msgid "What is the maximum IO load (permille)?" +#~ msgstr "Tải trá»ng VR tối Ä‘a là gì (theo phần nghìn)?" + +#~ msgid "" +#~ "The highest tolerable IO load. Load here refers to the percentage of CPU " +#~ "cycles wasted waiting for IO for the entire system, that is it includes " +#~ "disk utilization by other processes. A value of 10 means that once the " +#~ "average number of cycles wasted waiting for IO is more than 10% non-idle, " +#~ "GNUnet will try to reduce IO until the load goes under the threshold. " +#~ "Reasonable values are typically between 10 and 75." +#~ msgstr "" +#~ "Tải trá»ng VR cao nhất có thể tha thứ được. Ở đây thì tải trá»ng tham chiếu " +#~ "đến tá»· lệ phần trăm chu kỳ CPU bị phí khi đợi VR đối vá»›i toàn hệ thống, " +#~ "tức là nó cÅ©ng tính sá»­ dụng Ä‘Ä©a của các tiến trình khác. Giá trị 10 có " +#~ "nghÄ©a là má»™t khi số các chu kỳ trung bình bị phí khi đợi VR hÆ¡n 10% không " +#~ "nghỉ, GNUnet sẽ thá»­ giảm VR đến khi tải trá»ng nhá» hÆ¡n ngưỡng. Giá trị hợp " +#~ "lý thÆ°á»ng nằm giữa 10 và 75." + +#~ msgid "What is the maximum CPU load (hard limit)?" +#~ msgstr "Tải trá»ng CPU tối Ä‘a là gì (giá»›i hạn cứng)?" + +#~ msgid "" +#~ "The highest tolerable CPU load. This is the hard limit, so once it is " +#~ "reached, gnunetd will start to massively drop data to reduce the load. " +#~ "Use with caution." +#~ msgstr "" +#~ "Tải trá»ng CPU cao nhất có thể tha thứ được. Äây là giá»›i hạn cứng, do đó " +#~ "má»™t khi tá»›i được, gnunetd sẽ bắt đầu bá» rất nhiá»u dữ liệu để giảm tải " +#~ "trá»ng. Hãy sá»­ dụng cẩn thận." + +#~ msgid "What is the maximum upstream bandwidth (hard limit)?" +#~ msgstr "Băng thông dòng ra tối Ä‘a là gì (giá»›i hạn cứng)?" + +#~ msgid "" +#~ "The limit is given as a percentage of the MAXNETUPBPS limit. Use 100 to " +#~ "have MAXNETUPBPS be the hard limit. Use zero for no limit." +#~ msgstr "" +#~ "Giá»›i hạn được ghi rõ theo phần trăm của giá»›i hạn MAXNETUPBPS. Dùng 100 để " +#~ "đặt MAXNETUPBPS là giá»›i hạn cứng. 0 = vô hạn." + +#, fuzzy +#~ msgid "What priority should gnunetd use to run?" +#~ msgstr "gnunetd nên chạy nhÆ° nhóm nào?" + +#~ msgid "Should we disable random padding (experimental option)?" +#~ msgstr "Có nên tắt đệm ngẫu nhiên (tùy chá»n vẫn thá»±c nghiệm) không?" + +#~ msgid "Use basic bandwidth limitation? (YES/NO). If in doubt, say YES." +#~ msgstr "" +#~ "Äặt giá»›i hạn băng thông cÆ¡ bản không? (YES/NO) ChÆ°a chắc thì đặt YES (có)." + +#~ msgid "" +#~ "Basic bandwidth limitation (YES) means simply that the bandwidth limits " +#~ "specified apply to GNUnet and only to GNUnet. If set to YES, you simply " +#~ "specify the maximum bandwidth (upstream and downstream) that GNUnet is " +#~ "allowed to use and GNUnet will stick to those limitations. This is " +#~ "useful if your overall bandwidth is so large that the limit is mostly " +#~ "used to ensure that enough capacity is left for other applications. Even " +#~ "if you want to dedicate your entire connection to GNUnet you should not " +#~ "set the limits to values higher than what you have since GNUnet uses " +#~ "those limits to determine for example the number of connections to " +#~ "establish (and it would be inefficient if that computation yields a " +#~ "number that is far too high). \n" +#~ "\n" +#~ "While basic bandwidth limitation is simple and always works, there are " +#~ "some situations where it is not perfect. Suppose you are running another " +#~ "application which performs a larger download. During that particular " +#~ "time, it would be nice if GNUnet would throttle its bandwidth consumption " +#~ "(automatically) and resume using more bandwidth after the download is " +#~ "complete. This is obviously advanced magic since GNUnet will have to " +#~ "monitor the behavior of other applications. Another scenario is a monthly " +#~ "cap on bandwidth imposed by your ISP, which you would want to ensure is " +#~ "obeyed. Here, you may want GNUnet to monitor the traffic from other " +#~ "applications to ensure that the combined long-term traffic is within the " +#~ "pre-set bounds. Note that you should probably not set the bounds tightly " +#~ "since GNUnet may observe that the bounds are about to be broken but would " +#~ "be unable to stop other applications from continuing to use bandwidth.\n" +#~ "\n" +#~ "If either of these two scenarios applies, set BASICLIMITING to NO. Then " +#~ "set the bandwidth limits to the COMBINED amount of traffic that is " +#~ "acceptable for both GNUnet and other applications. GNUnet will then " +#~ "immediately throttle bandwidth consumption if the short-term average is " +#~ "above the limit, and it will also try to ensure that the long-term " +#~ "average is below the limit. Note however that using NO can have the " +#~ "effect of GNUnet (almost) ceasing operations after other applications " +#~ "perform high-volume downloads that are beyond the defined limits. GNUnet " +#~ "would reduce consumption until the long-term limits are again within " +#~ "bounds.\n" +#~ "\n" +#~ "NO only works on platforms where GNUnet can monitor the amount of traffic " +#~ "that the local host puts out on the network. This is only implemented " +#~ "for Linux and Win32. In order for the code to work, GNUnet needs to know " +#~ "the specific network interface that is used for the external connection " +#~ "(after all, the amount of traffic on loopback or on the LAN should never " +#~ "be counted since it is irrelevant)." +#~ msgstr "" +#~ "Giá»›i hạn băng thông cÆ¡ bản (YES) có nghÄ©a Ä‘Æ¡n giản là má»—i giá»›i hạn băng " +#~ "thông Ä‘Æ°a ra chỉ áp dụng cho GNUnet. Nếu đặt thành YES (có) thì bạn Ä‘Æ¡n " +#~ "giản chỉ ghi rõ băng thông tối Ä‘a (dòng ra và dòng vào) cho phép GNUnet " +#~ "dùng, và GNUnet sẽ tuân theo những giá»›i hạn đó. Có ích nếu băng thông " +#~ "toàn bá»™ lá»›n quá đến mức là giá»›i hạn thÆ°á»ng dùng để đảm bảo đủ khả năng " +#~ "còn lại cho các ứng dụng khác. Thậm chí nếu bạn muốn dành kết nối hoàn " +#~ "toàn cho GNUnet, không nên đặt giá»›i hạn thành giá trị cao hÆ¡n khả năng, " +#~ "vì GNUnet dùng giá»›i hạn đó để quyết định, ví dụ, số các kết nối nên thiết " +#~ "lập (không có hiệu quả nếu phép tính có kết quả là quá lá»›n).\n" +#~ "\n" +#~ "Dù chức năng hạn chế băng thông cÆ¡ bản vẫn Ä‘Æ¡n giản và lúc nào cÅ©ng hoạt " +#~ "Ä‘á»™ng được, trong má»™t số trÆ°á»ng hợp nào đó nó không phải hoàn toàn. Giả sá»­ " +#~ "bạn Ä‘ang chạy má»™t ứng dụng khác mà thá»±c hiện má»™t công việc tải xuống lá»›n " +#~ "hÆ¡n. Trong khi làm công việc đó, có ích nếu GNUnet giảm tiêu thụ băng " +#~ "thông (má»™t cách tá»± Ä‘á»™ng), cÅ©ng tăng lại má»™t khi công việc tải xuống đó đã " +#~ "chạy xong. Chức năng này thá»±c sá»± phức tạp, vì GNUnet phải theo dõi ứng xá»­ " +#~ "của các ứng dụng khác. Má»™t trÆ°á»ng hợp khác là má»™t ngưỡng băng thông hàng " +#~ "tháng được nhà cung cấp dịch vụ Internet (ISP) Ä‘iá»u khiển: bạn muốn đảm " +#~ "bảo tuân theo nó. Trong trÆ°á»ng hợp đó, bạn có thể muốn theo dõi tải cho " +#~ "mạng từ các ứng dụng khác để đảm bảo rằng tổng số tải trá»ng lâu dài nằm " +#~ "dÆ°á»›i ngưỡng định sẵn. Ghi chú rằng không nên đặt ngưỡng quá chặt chẽ vì " +#~ "GNUnet có thể phát hiện ngưỡng sắp bị vượt quá nhÆ°ng không thể ngăn cản " +#~ "ứng dụng khác tiếp tục chiếm băng thông.\n" +#~ "\n" +#~ "Nếu có má»™t của hai trÆ°á»ng hợp này, hãy đặt BASICLIMITING thành NO " +#~ "(không). Sau đó thì đặt giá»›i hạn băng thông thành Tá»”NG Sá» tải trá»ng thoả " +#~ "đáng cho cả hai GNUnet và ứng dụng khác. GNUnet thì giảm ngay tiêu thụ " +#~ "băng thông nếu trung bình ngắn kỳ hÆ¡n giá»›i hạn, nó cÅ©ng thá»­ đảm bảo rằng " +#~ "trung bình lâu dài dÆ°á»›i giá»›i hạn. Tuy nhiên, ghi chú rằng việc đặt NO " +#~ "(không) có kết quả có thể là GNUnet gần dừng hoạt Ä‘á»™ng sau khi ứng dụng " +#~ "khác chạy công việc lá»›n mà vượt quá giá»›i hạn đã xác định. Lúc đó, GNUnet " +#~ "sẽ giảm tiêu thụ đến khi giá»›i hạn lâu dài lại nằm trong phạm vi Ä‘Æ°a ra.\n" +#~ "\n" +#~ "Giá trị NO chỉ hoạt Ä‘á»™ng được trên ná»n tảng thích hợp vá»›i GNUnet theo dõi " +#~ "tải cho mạng được máy cục bá»™ gá»­i. Chức năng này chỉ được thá»±c hiện cho " +#~ "Linux và Win32. Äể mà mã hoạt Ä‘á»™ng được, GNUnet cần biết giao diện mạng " +#~ "dứt khoát dùng cho kết nối bên ngoài (thôi, lượng tải trá»ng trên mạch ná»™i " +#~ "bá»™ hay LAN không bao giá» nên được đếm vì nó không thích đáng). " + +#~ msgid "Network interface to monitor" +#~ msgstr "Giao diện mạng cần theo dõi" + +#~ msgid "" +#~ "For which interfaces should we do accounting? GNUnet will evaluate the " +#~ "total traffic (not only the GNUnet related traffic) and adjust its " +#~ "bandwidth usage accordingly. You can currently only specify a single " +#~ "interface. GNUnet will also use this interface to determine the IP to " +#~ "use. Typical values are eth0, ppp0, eth1, wlan0, etc. 'ifconfig' will " +#~ "tell you what you have. Never use 'lo', that just won't work. Under " +#~ "Windows, specify the index number reported by 'gnunet-win-tool -n'." +#~ msgstr "" +#~ "Có nên tính đến những giao diện nào? GNUnet sẽ định giá tổng số tải trá»ng " +#~ "(không phải chỉ tải trá»ng liên quan đến GNUnet) và Ä‘iá»u chỉnh sá»­ dụng " +#~ "băng thông má»™t cách thích hợp. Hiện thá»i ngÆ°á»i dùng chỉ có thể ghi rõ má»™t " +#~ "giao diện riêng lẻ. GNUnet sẽ cÅ©ng sá»­ dụng giao doện này để quyết định " +#~ "địa chỉ IP cần dùng. Giá trị thÆ°á»ng dùng: eth0, ppp0, eth1, wlan0, v.v. " +#~ "Lệnh « ifconfig » sẽ hiển thị những giao diện sẵn sàng. Không bao giá» nên " +#~ "dùng « lo » vì nó không hoạt Ä‘á»™ng được. DÆ°á»›i Windows, hãy ghi rõ số chỉ " +#~ "mục trả lại bởi câu lệnh « gnunet-win-tool -n »." + +#~ msgid "Load management" +#~ msgstr "Quản lý tải trá»ng" + +#~ msgid "Root node" +#~ msgstr "Nút gốc" + +#~ msgid "Where should gnunet-clients write their logs?" +#~ msgstr "Ứng dụng khách gnunet-clients nên ghi sổ theo dõi vào đâu?" + +#~ msgid "On which machine and port is gnunetd running (for clients)?" +#~ msgstr "gnunetd Ä‘ang chạy trên máy và cổng nào (cho ứng dụng khách)?" + +#~ msgid "This is equivalent to the -H option. The format is IP:PORT." +#~ msgstr "Äây tÆ°Æ¡ng Ä‘Æ°Æ¡ng vá»›i tùy chá»n « -H ». Äịnh dạng là « IP:Cá»”NG »." + +#~ msgid "What is the path to the configuration file for gnunetd?" +#~ msgstr "Tập tin cấu hình gnunetd có Ä‘Æ°á»ng dẫn nào?" + +#~ msgid "This option is used when clients need to start gnunetd." +#~ msgstr "Tùy chá»n này dùng khi ứng dụng khách cần khởi chạy gnunetd." + +#~ msgid "General options" +#~ msgstr "Tùy chá»n chung" + +#~ msgid "Do not add metadata listing the creation time for inserted content" +#~ msgstr "" +#~ "Không nên thêm siêu dữ liệu mà ghi nhá»› giá» tạo của ná»™i dung được chèn vào" + +#~ msgid "" +#~ "Which non-default extractors should GNUnet use for keyword extractors" +#~ msgstr "" +#~ "Äối vá»›i bá»™ trích khác từ khoá, GNUnet nên dùng những bá»™ trích khác mặc " +#~ "định nào?" + +#~ msgid "" +#~ "Specify which additional extractor libraries should be used. gnunet-" +#~ "insert uses libextractor to extract keywords from files. libextractor can " +#~ "be dynamically extended to handle additional file formats. If you want to " +#~ "use more than the default set of extractors, specify additional extractor " +#~ "libraries here. The format is [[-]LIBRARYNAME[:[-]LIBRARYNAME]*].\n" +#~ "\n" +#~ "The default is to use filenames and to break larger words at spaces (and " +#~ "underscores, etc.). This should be just fine for most people. The '-' " +#~ "before a library name indicates that this should be executed last and " +#~ "makes only sense for the split-library." +#~ msgstr "" +#~ "Ghi rõ những thÆ° viện trích bổ sung nào nên dùng. Tiến trình chèn gnunet-" +#~ "insert sá»­ dụng libextractor để trích các từ khoá khá»i tập tin. " +#~ "libextractor cÅ©ng có thể mở rá»™ng Ä‘á»™ng để quản lý định dạng tập tin bổ " +#~ "sung. Muốn sá»­ dụng bá»™ trích bên ngoài tập hợp mặc định thì ghi rõ ở đây " +#~ "những thÆ° viện trích bổ sung. Äịnh dạng là « [[-]tên_thÆ°_viện[:[-]" +#~ "tên_thÆ°_viện]*] ».\n" +#~ "\n" +#~ "Mặc định là dùng tên tập tin, và ngắt từ lá»›n ở dấu cách, dấu gạch dÆ°á»›i v." +#~ "v. Äây nên ổn cho phần lá»›n ngÆ°á»i dùng. Dấu gạch nối « - » đằng trÆ°á»›c má»™t " +#~ "tên thÆ° viện có ngụ ý nó nên được thá»±c hiện cuối cùng, thích hợp chỉ cho " +#~ "split-library." + +#~ msgid "How many entries should the URI DB table have?" +#~ msgstr "Bảng DB URI nên chứa bao nhiêu mục nhập?" + +#~ msgid "" +#~ "GNUnet uses two bytes per entry on the disk. This database is used to " +#~ "keep track of how a particular URI has been used in the past. For " +#~ "example, GNUnet may remember that a particular URI has been found in a " +#~ "search previously or corresponds to a file uploaded by the user. This " +#~ "information can then be used by user-interfaces to filter URI lists, such " +#~ "as search results. If the database is full, older entries will be " +#~ "discarded. The default value should be sufficient without causing undue " +#~ "disk utilization." +#~ msgstr "" +#~ "GNUnet dùng hai byte cho má»—i mục nhập trên Ä‘Ä©a. CÆ¡ sở dữ liệu này dùng để " +#~ "theo dõi má»™t URI nào đó đã được sá»­ dụng nhÆ° thế nào. Ví dụ, GNUnet có thể " +#~ "nhá»› rằng má»™t URI nào đó đã được phát hiện bằng má»™t công việc tìm kiếm " +#~ "trÆ°á»›c, hay tÆ°Æ¡ng ứng vá»›i má»™t tập tin được ngÆ°á»i dùng tải lên. Thông tin " +#~ "này thì có thể được dùng bởi giao diện ngÆ°á»i dùng để lá»c danh sách các " +#~ "URI, nhÆ° kết quả tìm kiếm. Nếu cÆ¡ sở dữ liệu bị đầy thì hủy các mục nhập " +#~ "cÅ©. Giá trị mặc định nên ổn mà không gây ra sá»­ dụng Ä‘Ä©a má»™t cách quá " +#~ "chừng." + +#~ msgid "" +#~ "Location of the file specifying metadata for the auto-share directory" +#~ msgstr "Vị trí của tập tin ghi rõ siêu dữ liệu cho thÆ° mục tá»± Ä‘á»™ng chia sẻ" + +#~ msgid "" +#~ "Location of the file with the PID of any running gnunet-auto-share daemon " +#~ "process" +#~ msgstr "" +#~ "Vị trí của tập tin chứa PID của bất kỳ tiến trình ná»n gnunet-auto-share" + +#~ msgid "Location of the log file for gnunet-auto-share" +#~ msgstr "Vị trí của tập tin theo dõi cho gnunet-auto-share" + +#~ msgid "Which plugins should be loaded by gnunet-gtk?" +#~ msgstr "gnunet-gtk nên nạp những phần bổ sung nào?" + +#~ msgid "" +#~ "Load the about plugin for the about dialog. The daemon plugin allows " +#~ "starting and stopping of gnunetd and displays information about gnunetd. " +#~ "The fs plugin provides the file-sharing functionality. The stats plugin " +#~ "displays various statistics about gnunetd." +#~ msgstr "" +#~ "Nạp phần bổ sung about cho há»™p thoại giá»›i thiệu. Phần bổ sung daemon cho " +#~ "phép khởi chạy và dừng chạy trình ná»n gnunetd, và hiển thị thông tin vá» " +#~ "gnunetd. Phần bổ sung fs cung cấp chức năng chia sẻ tập tin. Phần bổ sung " +#~ "stats hiển thị thống kê khác nhau vá» gnunetd." + +#~ msgid "How frequently (in milli-seconds) should the statistics update?" +#~ msgstr "Thống kê có nên cập nhật thÆ°á»ng xuyên cỡ nào (theo mili-giây)?" + +#~ msgid "" +#~ "Each pixel in the stats dialog corresponds to the time interval specified " +#~ "here." +#~ msgstr "" +#~ "Má»—i Ä‘iểm ảnh trong há»™p thoại thống kê thì tÆ°Æ¡ng ứng vá»›i khoảng thá»i gian " +#~ "Ä‘Æ°a ra ở đây." + +#~ msgid "Do not show thumbnail previews from meta-data in search results" +#~ msgstr "" +#~ "Không hiển thị ô xem thá»­ ảnh mẫu từ siêu dữ liệu trong kết quả tìm kiếm" + +#~ msgid "" +#~ "This option is useful for people who maybe offended by some previews or " +#~ "use gnunet-gtk at work and would like to avoid bad surprises." +#~ msgstr "" +#~ "Tùy chá»n này có ích cho ngÆ°á»i dùng không thích má»™t số ô xem thá»­, hoặc sá»­ " +#~ "dụng gnunet-gtk ở chá»— làm và muốn tránh sá»± ngạc nhiên xấu." + +#~ msgid "" +#~ "This option is useful to eliminate files that the user already has from " +#~ "the search. Naturally, enabling this option maybe confusing because some " +#~ "obviously expected search results would no longer show up. This option " +#~ "only works if the URI_DB_SIZE option under FS is not zero (since the URI " +#~ "DB is used to determine which files the user is sharing)" +#~ msgstr "" +#~ "Tùy chá»n này có ích để loại ra việc tìm kiếm những tập tin đã có trên máy " +#~ "đó. Tất nhiên, bật tùy chá»n có thể gây ra bối rối vì má»™t số kết quả tìm " +#~ "kiếm mong đợi sẽ không được hiển thị. Tùy chá»n này chỉ hoạt Ä‘á»™ng được nếu " +#~ "tùy chá»n URI_DB_SIZE (kích cỡ cÆ¡ sở dữ liệu URI) dÆ°á»›i FS khác số không " +#~ "(vì cÆ¡ sở dữ liệu URI được dùng để quyết định những tập tin được ngÆ°á»i " +#~ "dùng chia sẻ)" + +#~ msgid "To which directory should gnunet-gtk save downloads to?" +#~ msgstr "gnunet-gtk nên lÆ°u tập tin tải vá» vào thÆ° mục nào?" + +#~ msgid "Options related to gnunet-gtk" +#~ msgstr "Tùy chá»n liên quan đến gnunet-gtk" + +#~ msgid "Full pathname of GNUnet client HOME directory" +#~ msgstr "Tên Ä‘Æ°á»ng dẫn đầy đủ đến thÆ° mục HOME khách GNUnet" + +#~ msgid "The directory for GNUnet files that belong to the user." +#~ msgstr "ThÆ° mục chứa những tập tin GNUnet mà thuá»™c vá» ngÆ°á»i dùng." + +#~ msgid "`%s' failed at %s:%d with error `%s' after %llums\n" +#~ msgstr "« %s » bị lá»—i tại %s:%d vá»›i lá»—i:« %s » đẳng sau %llu miligiây\n" + +#~ msgid "" +#~ "Directory `%s' in directory `%s' does not match naming convention. " +#~ "Removed.\n" +#~ msgstr "" +#~ "ThÆ° mục « %s » trong thÆ° mục « %s » không tùy theo quy Æ°á»›c đặt tên. Bị gỡ " +#~ "bá».\n" diff --git a/po/zh_CN.gmo b/po/zh_CN.gmo new file mode 100644 index 0000000..005c77e Binary files /dev/null and b/po/zh_CN.gmo differ diff --git a/po/zh_CN.po b/po/zh_CN.po new file mode 100644 index 0000000..cb4721c --- /dev/null +++ b/po/zh_CN.po @@ -0,0 +1,6312 @@ +# Chinese simplified translation for GNUnet. +# Copyright (C) 2011 Christian Grothoff +# This file is distributed under the same license as the GNUnet package. +# Wylmer Wang , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: gnunet-0.8.1\n" +"Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" +"POT-Creation-Date: 2012-02-28 18:30+0100\n" +"PO-Revision-Date: 2011-07-09 12:12+0800\n" +"Last-Translator: Wylmer Wang \n" +"Language-Team: Chinese (simplified) \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/arm/arm_api.c:187 +msgid "Failed to transmit shutdown request to client.\n" +msgstr "" + +#: src/arm/arm_api.c:378 +#, fuzzy, c-format +msgid "Configuration failes to specify option `%s' in section `%s'!\n" +msgstr "é…ç½®ä¸æ»¡è¶³é…置规范文件“%sâ€çš„约æŸï¼\n" + +#: src/arm/arm_api.c:392 +#, fuzzy, c-format +msgid "Configuration fails to specify option `%s' in section `%s'!\n" +msgstr "é…ç½®ä¸æ»¡è¶³é…置规范文件“%sâ€çš„约æŸï¼\n" + +#: src/arm/arm_api.c:467 +#, c-format +msgid "Error receiving response to `%s' request from ARM for service `%s'\n" +msgstr "" + +#: src/arm/arm_api.c:523 +#, c-format +msgid "Requesting start of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:524 +#, c-format +msgid "Requesting termination of service `%s'.\n" +msgstr "" + +#: src/arm/arm_api.c:546 +#, c-format +msgid "Error while trying to transmit request to start `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:548 +#, c-format +msgid "Error while trying to transmit request to stop `%s' to ARM\n" +msgstr "" + +#: src/arm/arm_api.c:581 +#, c-format +msgid "Asked to start service `%s' within %llu ms\n" +msgstr "" + +#: src/arm/arm_api.c:654 +#, c-format +msgid "Stopping service `%s' within %llu ms\n" +msgstr "" + +#: src/arm/gnunet-arm.c:149 +#, fuzzy, c-format +msgid "Service `%s' is unknown to ARM.\n" +msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" + +#: src/arm/gnunet-arm.c:154 +#, fuzzy, c-format +msgid "Service `%s' has been stopped.\n" +msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" + +#: src/arm/gnunet-arm.c:157 +#, fuzzy, c-format +msgid "Service `%s' was already running.\n" +msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" + +#: src/arm/gnunet-arm.c:162 +#, fuzzy, c-format +msgid "Service `%s' has been started.\n" +msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" + +#: src/arm/gnunet-arm.c:165 +#, fuzzy, c-format +msgid "Service `%s' was already being stopped.\n" +msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" + +#: src/arm/gnunet-arm.c:169 +#, fuzzy, c-format +msgid "Service `%s' was already not running.\n" +msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" + +#: src/arm/gnunet-arm.c:173 +msgid "Request ignored as ARM is shutting down.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:177 +msgid "Error communicating with ARM service.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:181 +msgid "Timeout communicating with ARM service.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:185 +msgid "Operation failed.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:189 +msgid "Unknown response code from ARM.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:216 +#, c-format +msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:224 src/arm/gnunet-arm.c:324 +msgid "Fatal error initializing ARM API.\n" +msgstr "" + +#: src/arm/gnunet-arm.c:247 +#, fuzzy, c-format +msgid "Failed to remove configuration file %s\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/arm/gnunet-arm.c:253 +#, c-format +msgid "Failed to remove servicehome directory %s\n" +msgstr "" + +#: src/arm/gnunet-arm.c:355 +#, fuzzy +msgid "stop all GNUnet services" +msgstr "å¸è½½ GNUnet æœåŠ¡" + +#: src/arm/gnunet-arm.c:357 +msgid "start a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:359 +msgid "stop a particular service" +msgstr "" + +#: src/arm/gnunet-arm.c:361 +#, fuzzy +msgid "start all GNUnet default services" +msgstr "å¸è½½ GNUnet æœåŠ¡" + +#: src/arm/gnunet-arm.c:364 +#, fuzzy +msgid "stop and start all GNUnet default services" +msgstr "å¸è½½ GNUnet æœåŠ¡" + +#: src/arm/gnunet-arm.c:367 +msgid "delete config file and directory on exit" +msgstr "" + +#: src/arm/gnunet-arm.c:369 +msgid "don't print status messages" +msgstr "" + +#: src/arm/gnunet-arm.c:372 +#, fuzzy +msgid "timeout for completing current operation" +msgstr "等待一次迭代完æˆçš„时间(毫秒)" + +#: src/arm/gnunet-arm.c:383 +msgid "Control services and the Automated Restart Manager (ARM)" +msgstr "" + +#: src/arm/gnunet-service-arm.c:328 +#, fuzzy, c-format +msgid "Failed to start service `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/arm/gnunet-service-arm.c:331 +#, c-format +msgid "Starting service `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:357 +msgid "Could not send status result to client\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:484 +#, fuzzy, c-format +msgid "Unable to create socket for service `%s': %s\n" +msgstr "无法创建用户账户:" + +#: src/arm/gnunet-service-arm.c:506 +#, c-format +msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:520 +#, c-format +msgid "ARM now monitors connections to service `%s' at `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:628 +#, c-format +msgid "Preparing to stop `%s'\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:782 +#, c-format +msgid "Restarting service `%s'.\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:877 +msgid "exit" +msgstr "" + +#: src/arm/gnunet-service-arm.c:882 +msgid "signal" +msgstr "" + +#: src/arm/gnunet-service-arm.c:887 +#, fuzzy +msgid "unknown" +msgstr "未知错误" + +#: src/arm/gnunet-service-arm.c:921 +#, c-format +msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:967 src/arm/mockup-service.c:41 +msgid "Failed to transmit shutdown ACK.\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1067 +#, fuzzy, c-format +msgid "Configuration file `%s' for service `%s' not valid: %s\n" +msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" + +#: src/arm/gnunet-service-arm.c:1069 +msgid "option missing" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1152 +#, fuzzy, c-format +msgid "Starting default services `%s'\n" +msgstr "å¸è½½ GNUnet æœåŠ¡" + +#: src/arm/gnunet-service-arm.c:1163 +#, c-format +msgid "Default service `%s' not configured correctly!\n" +msgstr "" + +#: src/arm/gnunet-service-arm.c:1177 +msgid "" +"No default services configured, GNUnet will not really start right now.\n" +msgstr "" + +#: src/arm/mockup-service.c:46 +msgid "Transmitting shutdown ACK.\n" +msgstr "" + +#: src/arm/mockup-service.c:69 +msgid "Initiating shutdown as requested by client.\n" +msgstr "" + +#: src/block/block.c:105 +#, fuzzy, c-format +msgid "Loading block plugin `%s'\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/chat/chat.c:175 +msgid "Could not transmit confirmation receipt\n" +msgstr "" + +#: src/chat/chat.c:283 +msgid "The current user must be the the first one joined\n" +msgstr "" + +#: src/chat/chat.c:412 +#, fuzzy, c-format +msgid "Unknown message type: '%u'\n" +msgstr "未知æ“作“%sâ€ã€‚\n" + +#: src/chat/chat.c:472 +#, fuzzy, c-format +msgid "Configuration option `%s' in section `%s' missing\n" +msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" + +#: src/chat/chat.c:480 +#, fuzzy, c-format +msgid "Failed to access chat home directory `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/chat/chat.c:498 +#, fuzzy, c-format +msgid "Failed to create/open key in file `%s'\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/chat/chat.c:559 +msgid "Could not serialize metadata\n" +msgstr "" + +#: src/chat/chat.c:674 +#, fuzzy +msgid "Failed to connect to the chat service\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/chat/chat.c:680 +msgid "Undefined mandatory parameter: joinCallback\n" +msgstr "" + +#: src/chat/chat.c:686 +msgid "Undefined mandatory parameter: messageCallback\n" +msgstr "" + +#: src/chat/chat.c:692 +msgid "Undefined mandatory parameter: memberCallback\n" +msgstr "" + +#: src/chat/gnunet-chat.c:92 +msgid "Joined\n" +msgstr "" + +#: src/chat/gnunet-chat.c:124 +msgid "anonymous" +msgstr "匿å" + +#: src/chat/gnunet-chat.c:130 +#, fuzzy, c-format +msgid "(%s) `%s' said: %s\n" +msgstr "“%sâ€è¯´ï¼š%s\n" + +#: src/chat/gnunet-chat.c:133 src/chat/gnunet-chat.c:136 +#, fuzzy, c-format +msgid "(%s) `%s' said to you: %s\n" +msgstr "“%sâ€å¯¹æ‚¨è¯´ï¼š%s\n" + +#: src/chat/gnunet-chat.c:139 +#, fuzzy, c-format +msgid "(%s) `%s' said for sure: %s\n" +msgstr "“%sâ€å¯¹æ‚¨è¯´ï¼š%s\n" + +#: src/chat/gnunet-chat.c:142 +#, fuzzy, c-format +msgid "(%s) `%s' said to you for sure: %s\n" +msgstr "“%sâ€å¯¹æ‚¨è¯´ï¼š%s\n" + +#: src/chat/gnunet-chat.c:145 +#, c-format +msgid "(%s) `%s' was confirmed that you received: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:148 +#, c-format +msgid "(%s) `%s' was confirmed that you and only you received: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:151 +#, c-format +msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:156 +#, c-format +msgid "" +"(%s) `%s' was confirmed that you and only you received from him or her: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:159 +#, fuzzy, c-format +msgid "(%s) `%s' said off the record: %s\n" +msgstr "“%sâ€å¯¹æ‚¨è¯´ï¼š%s\n" + +#: src/chat/gnunet-chat.c:162 +#, c-format +msgid "(%s) <%s> said using an unknown message type: %s\n" +msgstr "" + +#: src/chat/gnunet-chat.c:193 +#, c-format +msgid "'%s' acknowledged message #%d\n" +msgstr "" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' entered the room\n" +msgstr "“%sâ€è¿›å…¥äº†æˆ¿é—´\n" + +#: src/chat/gnunet-chat.c:224 +#, c-format +msgid "`%s' left the room\n" +msgstr "“%sâ€ç¦»å¼€äº†æˆ¿é—´\n" + +#: src/chat/gnunet-chat.c:284 src/chat/gnunet-chat.c:316 +#, fuzzy +msgid "Could not change username\n" +msgstr "已将用户å改为“%sâ€ã€‚\n" + +#: src/chat/gnunet-chat.c:288 src/chat/gnunet-chat.c:630 +#, c-format +msgid "Joining room `%s' as user `%s'...\n" +msgstr "" + +#: src/chat/gnunet-chat.c:320 +#, fuzzy, c-format +msgid "Changed username to `%s'\n" +msgstr "已将用户å改为“%sâ€ã€‚\n" + +#: src/chat/gnunet-chat.c:333 +#, c-format +msgid "Users in room `%s': " +msgstr "房间“%sâ€ä¸­çš„用户:" + +#: src/chat/gnunet-chat.c:371 +msgid "Syntax: /msg USERNAME MESSAGE" +msgstr "语法:/msg 用户å 消æ¯" + +#: src/chat/gnunet-chat.c:379 +#, c-format +msgid "Unknown user `%s'\n" +msgstr "未知的用户“%sâ€\n" + +#: src/chat/gnunet-chat.c:395 +#, c-format +msgid "User `%s' is currently not in the room!\n" +msgstr "用户“%sâ€å½“å‰ä¸åœ¨æˆ¿é—´é‡Œï¼\n" + +#: src/chat/gnunet-chat.c:448 +#, fuzzy, c-format +msgid "Unknown command `%s'\n" +msgstr "未知的命令“%sâ€ã€‚\n" + +#: src/chat/gnunet-chat.c:459 +msgid "" +"Use `/join #roomname' to join a chat room. Joining a room will cause you to " +"leave the current room" +msgstr "" + +#: src/chat/gnunet-chat.c:463 +msgid "" +"Use `/nick nickname' to change your nickname. This will cause you to leave " +"the current room and immediately rejoin it with the new name." +msgstr "" + +#: src/chat/gnunet-chat.c:467 +msgid "" +"Use `/msg nickname message' to send a private message to the specified user" +msgstr "" + +#: src/chat/gnunet-chat.c:470 +msgid "The `/notice' command is an alias for `/msg'" +msgstr "" + +#: src/chat/gnunet-chat.c:472 +msgid "The `/query' command is an alias for `/msg'" +msgstr "" + +#: src/chat/gnunet-chat.c:474 +msgid "Use `/sig message' to send a signed public message" +msgstr "" + +#: src/chat/gnunet-chat.c:477 +msgid "Use `/ack message' to require signed acknowledgment of the message" +msgstr "" + +#: src/chat/gnunet-chat.c:480 +msgid "Use `/anonymous message' to send a public anonymous message" +msgstr "" + +#: src/chat/gnunet-chat.c:482 +msgid "The `/anon' command is an alias for `/anonymous'" +msgstr "" + +#: src/chat/gnunet-chat.c:484 +msgid "Use `/quit' to terminate gnunet-chat" +msgstr "" + +#: src/chat/gnunet-chat.c:486 +msgid "The `/leave' command is an alias for `/quit'" +msgstr "" + +#: src/chat/gnunet-chat.c:489 +msgid "Use `/names' to list all of the current members in the chat room" +msgstr "" + +#: src/chat/gnunet-chat.c:491 +msgid "Use `/help command' to get help for a specific command" +msgstr "" + +#: src/chat/gnunet-chat.c:606 +msgid "You must specify a nickname\n" +msgstr "您必须指定一个昵称\n" + +#: src/chat/gnunet-chat.c:622 +#, c-format +msgid "Failed to join room `%s'\n" +msgstr "" + +#: src/chat/gnunet-chat.c:655 +msgid "set the nickname to use (required)" +msgstr "设置è¦ä½¿ç”¨çš„昵称(å¿…é¡»)" + +#: src/chat/gnunet-chat.c:658 +msgid "set the chat room to join" +msgstr "设置è¦åŠ å…¥çš„èŠå¤©å®¤" + +#: src/chat/gnunet-chat.c:670 +msgid "Join a chat on GNUnet." +msgstr "" + +#: src/chat/gnunet-service-chat.c:267 +#, fuzzy +msgid "Failed to queue a message notification\n" +msgstr "ä¿å­˜é…置失败。" + +#: src/chat/gnunet-service-chat.c:546 +#, fuzzy +msgid "Failed to queue a join notification\n" +msgstr "ä¿å­˜é…置失败。" + +#: src/chat/gnunet-service-chat.c:729 +#, fuzzy +msgid "Failed to queue a confirmation receipt\n" +msgstr "ä¿å­˜é…置失败。" + +#: src/chat/gnunet-service-chat.c:907 +#, fuzzy +msgid "Failed to queue a leave notification\n" +msgstr "ä¿å­˜é…置失败。" + +#: src/core/core_api.c:798 +msgid "Client was disconnected from core service, trying to reconnect.\n" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:77 +#: src/peerinfo-tool/gnunet-peerinfo.c:60 +#, c-format +msgid "Peer `%s'\n" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:175 +#: src/peerinfo-tool/gnunet-peerinfo.c:194 +#, fuzzy, c-format +msgid "Invalid command line argument `%s'\n" +msgstr "“%sâ€çš„å‚数无效。\n" + +#: src/core/gnunet-core-list-connections.c:196 +#: src/peerinfo-tool/gnunet-peerinfo.c:252 +msgid "don't resolve host names" +msgstr "" + +#: src/core/gnunet-core-list-connections.c:203 +msgid "Print information about connected peers." +msgstr "" + +#: src/core/gnunet-service-core.c:99 +#, c-format +msgid "Core service of `%4s' ready.\n" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:360 +msgid "# send requests dropped (disconnected)" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:465 +msgid "# messages discarded (session disconnected)" +msgstr "" + +#: src/core/gnunet-service-core_clients.c:801 +#, c-format +msgid "# bytes of messages of type %u received" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:493 +msgid "# bytes encrypted" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:543 +msgid "# bytes decrypted" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:604 src/dv/gnunet-service-dv.c:3002 +#: src/hostlist/hostlist-server.c:436 src/peerinfo-tool/gnunet-peerinfo.c:151 +msgid "Error in communication with PEERINFO service\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:623 +msgid "# Delayed connecting due to lack of public key" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:673 +msgid "# key exchanges initiated" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:694 +msgid "# key exchanges stopped" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:746 +msgid "# session keys received" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:765 +#, c-format +msgid "`%s' is for `%s', not for me. Ignoring.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:803 +msgid "# SET_KEY messages decrypted" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:883 +#: src/transport/gnunet-service-transport_validation.c:803 +msgid "# PING messages received" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:917 +#, c-format +msgid "" +"Received PING from `%s' for different identity: I am `%s', PONG identity: `" +"%s'\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:938 +msgid "# PONG messages created" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1026 +msgid "# sessions terminated by timeout" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1037 +msgid "# keepalive messages sent" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1095 +#: src/transport/gnunet-service-transport_validation.c:1026 +msgid "# PONG messages received" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1125 +msgid "# PONG messages decrypted" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1157 +msgid "# session keys confirmed via PONG" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1223 +msgid "# SET_KEY and PING messages created" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1364 +msgid "# failed to decrypt message (no session key)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1406 +#: src/core/gnunet-service-core_kx.c:1431 +msgid "# bytes dropped (duplicates)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1418 +msgid "# bytes dropped (out of sequence)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1455 +#, c-format +msgid "Message received far too old (%llu ms). Content ignored.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1459 +msgid "# bytes dropped (ancient message)" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1467 +msgid "# bytes of payload decrypted" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1528 +#, fuzzy +msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" +msgstr "ç«‹å³ä¿å­˜é…置?" + +#: src/core/gnunet-service-core_kx.c:1536 +msgid "Core service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/core/gnunet-service-core_kx.c:1546 src/hostlist/hostlist-server.c:555 +#: src/peerinfo-tool/gnunet-peerinfo.c:202 +#: src/transport/gnunet-service-transport.c:595 +msgid "Could not access PEERINFO service. Exiting.\n" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:163 +msgid "# sessions terminated by transport disconnect" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:180 +#: src/core/gnunet-service-core_neighbours.c:342 +msgid "# neighbour entries allocated" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:251 +msgid "# encrypted bytes given to transport" +msgstr "" + +#: src/core/gnunet-service-core_neighbours.c:430 +#, c-format +msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:208 +#: src/core/gnunet-service-core_sessions.c:273 +msgid "# entries in session map" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:238 +msgid "# type map refreshes sent" +msgstr "" + +#: src/core/gnunet-service-core_sessions.c:414 +msgid "# messages discarded (expired prior to transmission)" +msgstr "" + +#: src/core/gnunet-service-core_typemap.c:110 +#: src/core/gnunet-service-core_typemap.c:121 +msgid "# type maps received" +msgstr "" + +#: src/core/gnunet-service-core_typemap.c:151 +msgid "# updates to my type map" +msgstr "" + +#: src/datacache/datacache.c:118 src/datacache/datacache.c:255 +#: src/datastore/gnunet-service-datastore.c:854 +msgid "# bytes stored" +msgstr "" + +#: src/datacache/datacache.c:144 src/datacache/datacache.c:151 +#: src/datastore/gnunet-service-datastore.c:1531 +#: src/datastore/gnunet-service-datastore.c:1542 +#, c-format +msgid "No `%s' specified for `%s' in configuration!\n" +msgstr "" + +#: src/datacache/datacache.c:183 +#, c-format +msgid "Loading `%s' datacache plugin\n" +msgstr "" + +#: src/datacache/datacache.c:191 +#, c-format +msgid "Failed to load datacache plugin for `%s'\n" +msgstr "" + +#: src/datacache/datacache.c:281 +msgid "# requests received" +msgstr "" + +#: src/datacache/datacache.c:291 +msgid "# requests filtered by bloom filter" +msgstr "" + +#: src/datacache/plugin_datacache_mysql.c:103 +#: src/datacache/plugin_datacache_mysql.c:110 +#: src/datacache/plugin_datacache_mysql.c:517 +#: src/datacache/plugin_datacache_mysql.c:526 +#: src/datacache/plugin_datacache_mysql.c:598 +#: src/datacache/plugin_datacache_mysql.c:614 +#: src/datacache/plugin_datacache_sqlite.c:71 +#: src/datacache/plugin_datacache_sqlite.c:74 +#: src/datastore/plugin_datastore_mysql.c:139 +#: src/datastore/plugin_datastore_mysql.c:146 +#: src/datastore/plugin_datastore_mysql.c:613 +#: src/datastore/plugin_datastore_mysql.c:673 +#: src/datastore/plugin_datastore_mysql.c:685 +#: src/datastore/plugin_datastore_mysql.c:1362 +#: src/datastore/plugin_datastore_mysql.c:1376 +#: src/datastore/plugin_datastore_sqlite.c:61 +#: src/namestore/plugin_namestore_sqlite.c:49 src/util/crypto_ksk.c:49 +#: src/util/crypto_rsa.c:92 src/include/gnunet_common.h:507 +#: src/include/gnunet_common.h:514 +#, fuzzy, c-format +msgid "`%s' failed at %s:%d with error: %s\n" +msgstr "“%sâ€äºŽ %s:%d 处失败,错误为:%s\n" + +#: src/datacache/plugin_datacache_mysql.c:224 +#: src/datastore/plugin_datastore_mysql.c:316 +#, c-format +msgid "Trying to use file `%s' for MySQL configuration.\n" +msgstr "" + +#: src/datacache/plugin_datacache_mysql.c:230 +#: src/datastore/plugin_datastore_mysql.c:322 +#, fuzzy, c-format +msgid "Could not access file `%s': %s\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/datacache/plugin_datacache_mysql.c:979 +msgid "MySQL datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_postgres.c:79 +#: src/datastore/plugin_datastore_postgres.c:93 +#, fuzzy, c-format +msgid "`%s:%s' failed at %s:%d with error: %s" +msgstr "“%sâ€äºŽ %s:%d 处失败,错误为:%s\n" + +#: src/datacache/plugin_datacache_postgres.c:149 +#, fuzzy, c-format +msgid "Unable to initialize Postgres: %s" +msgstr "无法åˆå§‹åŒ– SQLite:%s。\n" + +#: src/datacache/plugin_datacache_postgres.c:499 +msgid "Postgres datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:424 +msgid "Sqlite datacache running\n" +msgstr "" + +#: src/datacache/plugin_datacache_sqlite.c:457 +#: src/datastore/plugin_datastore_sqlite.c:414 +#: src/namestore/plugin_namestore_sqlite.c:381 +msgid "Tried to close sqlite without finalizing all prepared statements.\n" +msgstr "" + +#: src/datacache/plugin_datacache_template.c:121 +msgid "Template datacache running\n" +msgstr "" + +#: src/datastore/datastore_api.c:289 +msgid "Failed to transmit request to drop database.\n" +msgstr "" + +#: src/datastore/datastore_api.c:372 +msgid "# queue entry timeouts" +msgstr "" + +#: src/datastore/datastore_api.c:418 +msgid "# queue overflows" +msgstr "" + +#: src/datastore/datastore_api.c:445 +msgid "# queue entries created" +msgstr "" + +#: src/datastore/datastore_api.c:465 +msgid "# Requests dropped from datastore queue" +msgstr "" + +#: src/datastore/datastore_api.c:513 +msgid "# datastore connections (re)created" +msgstr "" + +#: src/datastore/datastore_api.c:540 +msgid "# reconnected to DATASTORE" +msgstr "" + +#: src/datastore/datastore_api.c:608 +msgid "# transmission request failures" +msgstr "" + +#: src/datastore/datastore_api.c:631 +msgid "# bytes sent to datastore" +msgstr "" + +#: src/datastore/datastore_api.c:772 +msgid "Failed to receive status response from database." +msgstr "" + +#: src/datastore/datastore_api.c:786 +msgid "Error reading response from datastore service" +msgstr "" + +#: src/datastore/datastore_api.c:798 src/datastore/datastore_api.c:804 +msgid "Invalid error message received from datastore service" +msgstr "" + +#: src/datastore/datastore_api.c:810 +msgid "# status messages received" +msgstr "" + +#: src/datastore/datastore_api.c:883 +msgid "# PUT requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:954 +msgid "# RESERVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1019 +msgid "# RELEASE RESERVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1080 +msgid "# UPDATE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1148 +msgid "# REMOVE requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1193 +msgid "Failed to receive response from database.\n" +msgstr "" + +#: src/datastore/datastore_api.c:1253 +msgid "# Results received" +msgstr "" + +#: src/datastore/datastore_api.c:1324 +msgid "# GET REPLICATION requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1391 +msgid "# GET ZERO ANONYMITY requests executed" +msgstr "" + +#: src/datastore/datastore_api.c:1455 +msgid "# GET requests executed" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:351 +msgid "# bytes expired" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:426 +msgid "# bytes purged (low-priority)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:486 +msgid "Transmission to client failed!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:640 +msgid "# results found" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:685 +#, c-format +msgid "" +"Insufficient space (%llu bytes are available) to satisfy `%s' request for " +"%llu bytes\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:696 +#, c-format +msgid "" +"The requested amount (%llu bytes) is larger than the cache size (%llu " +"bytes)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:700 +msgid "" +"Insufficient space to satisfy request and requested amount is larger than " +"cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:706 +msgid "Insufficient space to satisfy request" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:711 +#: src/datastore/gnunet-service-datastore.c:765 +#: src/datastore/gnunet-service-datastore.c:986 +#: src/datastore/gnunet-service-datastore.c:1465 +msgid "# reserved" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:780 +msgid "Could not find matching reservation" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:868 +#, c-format +msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1034 +msgid "# GET requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1048 +msgid "# requests filtered by bloomfilter" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1076 +msgid "# UPDATE requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1110 +msgid "# GET REPLICATION requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1145 +msgid "# GET ZERO ANONYMITY requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1172 +msgid "Content not found" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1182 +msgid "# bytes removed (explicit request)" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1216 +msgid "# REMOVE requests received" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1260 +#, c-format +msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1323 +#, c-format +msgid "Loading `%s' datastore plugin\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1332 +#, fuzzy, c-format +msgid "Failed to load datastore plugin for `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/datastore/gnunet-service-datastore.c:1536 +#, c-format +msgid "# bytes used in file-sharing datastore `%s'" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1547 +msgid "# quota" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1549 +msgid "# cache size" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1562 +#, c-format +msgid "Could not use specified filename `%s' for bloomfilter.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1580 +#: src/datastore/gnunet-service-datastore.c:1596 +#, fuzzy, c-format +msgid "Failed to remove bogus bloomfilter file `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/datastore/gnunet-service-datastore.c:1626 +#, fuzzy +msgid "Failed to initialize bloomfilter.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/datastore/gnunet-service-datastore.c:1655 +msgid "Rebuilding bloomfilter. Please be patient.\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1660 +msgid "Plugin does not support get_keys function. Please fix!\n" +msgstr "" + +#: src/datastore/gnunet-service-datastore.c:1663 +msgid "Bloomfilter construction complete.\n" +msgstr "" + +#: src/datastore/plugin_datastore_mysql.c:529 +#: src/datastore/plugin_datastore_mysql.c:1336 +#, fuzzy, c-format +msgid "Failed to prepare statement `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/datastore/plugin_datastore_mysql.c:622 +#: src/datastore/plugin_datastore_mysql.c:1346 +#, fuzzy, c-format +msgid "`%s' for `%s' failed at %s:%d with error: %s\n" +msgstr "“%sâ€äºŽ %s:%d 处失败,错误为:%s\n" + +#: src/datastore/plugin_datastore_mysql.c:1581 +msgid "Mysql database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_postgres.c:173 +#, fuzzy, c-format +msgid "Unable to initialize Postgres with configuration `%s': %s" +msgstr "无法ä¿å­˜é…置文件“%sâ€ï¼š" + +#: src/datastore/plugin_datastore_postgres.c:1017 +msgid "Postgres database running\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:61 +#, fuzzy, c-format +msgid "`%s' failed at %s:%u with error: %s" +msgstr "“%sâ€äºŽ %s:%d 处失败,错误为:%s\n" + +#: src/datastore/plugin_datastore_sqlite.c:239 +#: src/namestore/plugin_namestore_sqlite.c:223 +#, c-format +msgid "Option `%s' in section `%s' missing in configuration!\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:266 +#: src/namestore/plugin_namestore_sqlite.c:248 +#, c-format +msgid "Unable to initialize SQLite: %s.\n" +msgstr "无法åˆå§‹åŒ– SQLite:%s。\n" + +#: src/datastore/plugin_datastore_sqlite.c:669 +#, fuzzy +msgid "Invalid data in database. Trying to fix (by deletion).\n" +msgstr "%s 中有无效数æ®ã€‚请å°è¯•ä¿®å¤(删除之)。\n" + +#: src/datastore/plugin_datastore_sqlite.c:1159 +msgid "sqlite version to old to determine size, assuming zero\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1178 +#, c-format +msgid "" +"Using sqlite page utilization to estimate payload (%llu pages of size %llu " +"bytes)\n" +msgstr "" + +#: src/datastore/plugin_datastore_sqlite.c:1218 +#: src/namestore/plugin_namestore_sqlite.c:779 +#, fuzzy +msgid "Sqlite database running\n" +msgstr "sqlite æ•°æ®ä»“库" + +#: src/datastore/plugin_datastore_template.c:241 +msgid "Template database running\n" +msgstr "" + +#: src/dht/dht_api.c:280 +#, fuzzy +msgid "Failed to connect to the DHT service!\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-put.c:172 +#: src/gns/gnunet-gns-lookup.c:179 +msgid "the query key" +msgstr "" + +#: src/dht/gnunet-dht-get.c:204 src/gns/gnunet-gns-lookup.c:182 +msgid "how many parallel requests (replicas) to create" +msgstr "" + +#: src/dht/gnunet-dht-get.c:207 src/gns/gnunet-gns-lookup.c:185 +msgid "the type of data to look for" +msgstr "" + +#: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:181 +#: src/gns/gnunet-gns-lookup.c:188 +msgid "how long to execute this query before giving up?" +msgstr "" + +#: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-put.c:184 +#: src/fs/gnunet-download.c:270 src/fs/gnunet-publish.c:725 +#: src/fs/gnunet-search.c:297 src/fs/gnunet-unindex.c:169 +#: src/gns/gnunet-gns-lookup.c:191 src/nse/gnunet-nse-profiler.c:908 +msgid "be verbose (print progress information)" +msgstr "" + +#: src/dht/gnunet-dht-get.c:232 +msgid "Issue a GET request to the GNUnet DHT, prints results." +msgstr "" + +#: src/dht/gnunet-dht-put.c:100 +msgid "PUT request sent!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:124 +msgid "Must provide KEY and DATA for DHT put!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:132 +#, fuzzy, c-format +msgid "Could not connect to %s service!\n" +msgstr "无法连接到 %s:%u:%s\n" + +#: src/dht/gnunet-dht-put.c:137 +#, fuzzy, c-format +msgid "Connected to %s service!\n" +msgstr "“%sâ€å·²è¿žæŽ¥åˆ°â€œ%sâ€ã€‚\n" + +#: src/dht/gnunet-dht-put.c:152 +#, c-format +msgid "Issuing put request for `%s' with data `%s'!\n" +msgstr "" + +#: src/dht/gnunet-dht-put.c:166 +msgid "the data to insert under the key" +msgstr "" + +#: src/dht/gnunet-dht-put.c:169 +msgid "how long to store this entry in the dht (in seconds)" +msgstr "" + +#: src/dht/gnunet-dht-put.c:175 +msgid "how many replicas to create" +msgstr "" + +#: src/dht/gnunet-dht-put.c:178 +msgid "the type to insert data as" +msgstr "" + +#: src/dht/gnunet-dht-put.c:203 +msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." +msgstr "" + +#: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:556 +#: src/testing/testing.c:1979 src/testing/testing.c:2009 +#, fuzzy +msgid "Failed to connect to transport service!\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/dht/gnunet-service-dht_clients.c:371 +msgid "# GET requests from clients injected" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:462 +msgid "# PUT requests received from clients" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:529 +msgid "# GET requests received from clients" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:624 +msgid "# GET STOP requests received from clients" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:854 +msgid "# Key match, type mismatches in REPLY to CLIENT" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:869 +msgid "# Duplicate REPLIES to CLIENT request dropped" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:906 +#, c-format +msgid "Unsupported block type (%u) in request!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:928 +msgid "# RESULTS queued for clients" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:979 +#: src/dht/gnunet-service-dht_clients.c:1022 +msgid "# REPLIES ignored for CLIENTS (no match)" +msgstr "" + +#: src/dht/gnunet-service-dht_clients.c:989 +msgid "Could not pass reply to client, message too big!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:93 +#, c-format +msgid "%s request received, but have no datacache!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:103 +msgid "# ITEMS stored in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:209 +msgid "# Good RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:220 +msgid "# Duplicate RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:226 +msgid "# Invalid RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:238 +msgid "# Unsupported RESULTS found in datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:241 +#, c-format +msgid "Unsupported block type (%u) in local response!\n" +msgstr "" + +#: src/dht/gnunet-service-dht_datacache.c:271 +msgid "# GET requests given to datacache" +msgstr "" + +#: src/dht/gnunet-service-dht_hello.c:82 +msgid "# HELLOs obtained from peerinfo" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:481 +msgid "# Preference updates given to core" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:573 +msgid "# FIND PEER messages initiated" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:629 +#: src/dht/gnunet-service-dht_neighbours.c:689 +#, fuzzy +msgid "# Peers connected" +msgstr "" +"\n" +"按任æ„键继续\n" + +#: src/dht/gnunet-service-dht_neighbours.c:723 +msgid "# Queued messages discarded (peer disconnected)" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:778 +msgid "# Bytes transmitted to other peers" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:816 +msgid "# Bytes of bandwdith requested from core" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1040 +#: src/dht/gnunet-service-dht_neighbours.c:1068 +msgid "# Peers excluded from routing due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1049 +#: src/dht/gnunet-service-dht_neighbours.c:1085 +msgid "# Peer selection failed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1221 +msgid "# PUT requests routed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1252 +msgid "# PUT messages queued for transmission" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1333 +msgid "# GET requests routed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1364 +msgid "# GET messages queued for transmission" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1467 +msgid "# RESULT messages queued for transmission" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1555 +msgid "# P2P PUT requests received" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1668 +msgid "# FIND PEER requests ignored due to Bloomfilter" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1676 +msgid "# FIND PEER requests ignored due to lack of HELLO" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1767 +msgid "# P2P GET requests received" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1811 +msgid "# P2P FIND PEER requests processed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1825 +msgid "# P2P GET requests ONLY routed" +msgstr "" + +#: src/dht/gnunet-service-dht_neighbours.c:1895 +msgid "# P2P RESULTS received" +msgstr "" + +#: src/dht/gnunet-service-dht_nse.c:59 +msgid "# Network size estimates received" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:211 +msgid "# Good REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:220 +msgid "# Duplicate REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:226 +msgid "# Invalid REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:236 +msgid "# Unsupported REPLIES matched against routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:314 +#: src/dht/gnunet-service-dht_routing.c:368 +msgid "# Entries removed from routing table" +msgstr "" + +#: src/dht/gnunet-service-dht_routing.c:324 +msgid "# Entries added to routing table" +msgstr "" + +#: src/dht/plugin_block_dht.c:124 +#, c-format +msgid "Block not of type %u\n" +msgstr "" + +#: src/dht/plugin_block_dht.c:131 +msgid "Size mismatch for block\n" +msgstr "" + +#: src/dht/plugin_block_dht.c:140 +#, c-format +msgid "Block of type %u is malformed\n" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:337 +msgid "only monitor DNS queries" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:340 +msgid "only monitor DNS replies" +msgstr "" + +#: src/dns/gnunet-dns-monitor.c:348 +msgid "Monitor DNS queries." +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:236 +msgid "set A records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:239 +msgid "set AAAA records" +msgstr "" + +#: src/dns/gnunet-dns-redirector.c:247 +msgid "Change DNS replies to point elsewhere." +msgstr "" + +#: src/dns/gnunet-service-dns.c:480 +#, fuzzy, c-format +msgid "Could not bind to any port: %s\n" +msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" + +#: src/dns/gnunet-service-dns.c:634 +msgid "# DNS requests answered via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:818 +msgid "# DNS exit failed (failed to open socket)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1001 +#, c-format +msgid "Received DNS response that is too small (%u bytes)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1046 +msgid "# External DNS response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1165 +msgid "# Client response discarded (no matching request)" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1198 +msgid "Changing DNS reply according to client specifications\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1279 +msgid "Received malformed IPv4-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1294 +msgid "Received malformed IPv6-UDP packet on TUN interface.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1303 +#, c-format +msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1312 +msgid "# Non-DNS UDP packet received via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1377 +msgid "# DNS requests received via TUN interface" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1461 +#, c-format +msgid "Configured DNS exit `%s' is not working / valid.\n" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1493 src/exit/gnunet-daemon-exit.c:2673 +msgid "# Inbound MESH tunnels created" +msgstr "" + +#: src/dns/gnunet-service-dns.c:1567 +msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" +msgstr "" + +#: src/dv/dv_api.c:179 +#, fuzzy +msgid "Failed to connect to the dv service!\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/dv/plugin_transport_dv.c:159 +#, c-format +msgid "%s Received message from %s of type %d, distance %u!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:508 +#, c-format +msgid "Got duplicate service records for `%s:%u'\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:563 +msgid "# Bytes transmitted via mesh tunnels" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2068 +#: src/exit/gnunet-daemon-exit.c:2318 src/vpn/gnunet-service-vpn.c:1388 +#: src/vpn/gnunet-service-vpn.c:1788 src/vpn/gnunet-service-vpn.c:1951 +msgid "# ICMPv4 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2127 +#: src/exit/gnunet-daemon-exit.c:2377 src/vpn/gnunet-service-vpn.c:1444 +#: src/vpn/gnunet-service-vpn.c:1847 src/vpn/gnunet-service-vpn.c:1984 +msgid "# ICMPv6 packets dropped (type not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:756 +msgid "# ICMP packets dropped (not allowed)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:763 +msgid "ICMP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:840 +msgid "UDP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:915 +msgid "TCP Packet dropped, have no matching connection information\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:968 +msgid "# Packets received from TUN" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:982 +msgid "# Bytes received from TUN" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1008 +msgid "IPv4 packet options received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1035 +#, c-format +msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1081 +#, c-format +msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1089 +#, c-format +msgid "Packet from unknown protocol %u received. Ignored.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1470 +msgid "# TCP packets sent via TUN" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1570 +msgid "# TCP service creation requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1573 src/exit/gnunet-daemon-exit.c:1652 +#: src/exit/gnunet-daemon-exit.c:1762 src/exit/gnunet-daemon-exit.c:1992 +#: src/exit/gnunet-daemon-exit.c:2234 src/exit/gnunet-daemon-exit.c:2515 +#: src/exit/gnunet-daemon-exit.c:2615 +msgid "# Bytes received from MESH" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1606 src/exit/gnunet-daemon-exit.c:2637 +#, c-format +msgid "No service found for %s on port %d!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1610 +msgid "# TCP requests dropped (no such service)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1655 +msgid "# TCP IP-exit creation requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1765 +msgid "# TCP data requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1779 +msgid "# TCP DATA requests dropped (no session)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1829 +msgid "# ICMP packets sent via TUN" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:1995 +msgid "# ICMP IP-exit requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2237 +msgid "# ICMP service requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2303 src/vpn/gnunet-service-vpn.c:1378 +#: src/vpn/gnunet-service-vpn.c:1945 +msgid "# ICMPv4 packets dropped (impossible PT to v6)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2362 src/vpn/gnunet-service-vpn.c:1414 +#: src/vpn/gnunet-service-vpn.c:1426 src/vpn/gnunet-service-vpn.c:1835 +msgid "# ICMPv6 packets dropped (impossible PT to v4)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2412 +msgid "# UDP packets sent via TUN" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2518 +msgid "# UDP IP-exit requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2618 +msgid "# UDP service requests received via mesh" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2641 +msgid "# UDP requests dropped (no such service)" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2881 +#, c-format +msgid "No addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2895 src/exit/gnunet-daemon-exit.c:2907 +#, c-format +msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:2918 +#, c-format +msgid "No IP addresses found for hostname `%s' of service `%s'!\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3047 +msgid "" +"This system does not support IPv4, will disable IPv4 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3055 +msgid "" +"This system does not support IPv6, will disable IPv6 functions despite them " +"being enabled in the configuration\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3062 +msgid "" +"Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " +"ENABLE_IPv4=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3068 +msgid "" +"Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " +"ENABLE_IPv6=YES\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3074 src/pt/gnunet-daemon-pt.c:884 +msgid "No useful service enabled. Exiting.\n" +msgstr "" + +#: src/exit/gnunet-daemon-exit.c:3235 +msgid "Daemon to run to provide an IP exit node for the VPN" +msgstr "" + +#: src/fragmentation/defragmentation.c:270 +msgid "# acknowledgements sent for fragment" +msgstr "" + +#: src/fragmentation/defragmentation.c:454 +msgid "# fragments received" +msgstr "" + +#: src/fragmentation/defragmentation.c:513 +msgid "# duplicate fragments received" +msgstr "" + +#: src/fragmentation/defragmentation.c:526 +msgid "# messages defragmented" +msgstr "" + +#: src/fragmentation/fragmentation.c:188 +msgid "# fragments transmitted" +msgstr "" + +#: src/fragmentation/fragmentation.c:191 +msgid "# fragments retransmitted" +msgstr "" + +#: src/fragmentation/fragmentation.c:255 +msgid "# messages fragmented" +msgstr "" + +#: src/fragmentation/fragmentation.c:258 +msgid "# total size of fragmented messages" +msgstr "" + +#: src/fragmentation/fragmentation.c:343 +msgid "# fragment acknowledgements received" +msgstr "" + +#: src/fragmentation/fragmentation.c:349 +msgid "# bits removed from fragmentation ACKs" +msgstr "" + +#: src/fragmentation/fragmentation.c:373 +msgid "# fragmentation transmissions completed" +msgstr "" + +#: src/fs/fs_api.c:284 +#, fuzzy, c-format +msgid "Could not open file `%s': %s" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/fs_api.c:293 +#, fuzzy, c-format +msgid "Could not read file `%s': %s" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/fs/fs_api.c:299 +#, c-format +msgid "Short read reading from file `%s'!" +msgstr "" + +#: src/fs/fs_api.c:877 +#, fuzzy, c-format +msgid "Failed to resume publishing information `%s': %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/fs_api.c:1334 +#, c-format +msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" +msgstr "" + +#: src/fs/fs_api.c:1376 +#, c-format +msgid "Failure while resuming publishing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:1392 +#, fuzzy, c-format +msgid "Failed to resume publishing operation `%s': %s\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/fs/fs_api.c:2004 +#, c-format +msgid "Failure while resuming unindexing operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2014 +#, fuzzy, c-format +msgid "Failed to resume unindexing operation `%s': %s\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/fs/fs_api.c:2139 src/fs/fs_api.c:2378 +#, fuzzy, c-format +msgid "Failed to resume sub-download `%s': %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/fs_api.c:2156 +#, fuzzy, c-format +msgid "Failed to resume sub-search `%s': %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/fs_api.c:2168 src/fs/fs_api.c:2187 src/fs/fs_api.c:2671 +#, c-format +msgid "Failure while resuming search operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_api.c:2369 +#, fuzzy, c-format +msgid "Failed to resume sub-download `%s': could not open file `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/fs/fs_api.c:2615 +msgid "Could not resume running search, will resume as paused search\n" +msgstr "" + +#: src/fs/fs_api.c:2709 +#, c-format +msgid "Failure while resuming download operation `%s': %s\n" +msgstr "" + +#: src/fs/fs_directory.c:210 +msgid "MAGIC mismatch. This is not a GNUnet directory.\n" +msgstr "" + +#: src/fs/fs_download.c:310 +msgid "" +"Recursive downloads of directories larger than 4 GB are not supported on 32-" +"bit systems\n" +msgstr "" + +#: src/fs/fs_download.c:330 +msgid "Directory too large for system address space\n" +msgstr "" + +#: src/fs/fs_download.c:488 src/fs/fs_download.c:500 +#, fuzzy, c-format +msgid "Failed to open file `%s' for writing" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/fs_download.c:870 +#, c-format +msgid "Failed to create directory for recursive download of `%s'\n" +msgstr "" + +#: src/fs/fs_download.c:951 +#, c-format +msgid "" +"Internal error or bogus download URI (expected %u bytes at depth %u and " +"offset %llu/%llu, got %u bytes)\n" +msgstr "" + +#: src/fs/fs_download.c:977 +msgid "internal error decrypting content" +msgstr "" + +#: src/fs/fs_download.c:1000 +#, fuzzy, c-format +msgid "Download failed: could not open file `%s': %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/fs_download.c:1010 +#, fuzzy, c-format +msgid "Failed to seek to offset %llu in file `%s': %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/fs_download.c:1019 +#, fuzzy, c-format +msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/fs/fs_download.c:1835 +#, fuzzy +msgid "Invalid URI" +msgstr "无效æ¡ç›®ã€‚\n" + +#: src/fs/fs_getopt.c:191 +#, c-format +msgid "" +"Unknown metadata type in metadata option `%s'. Using metadata type " +"`unknown' instead.\n" +msgstr "" + +#: src/fs/fs_list_indexed.c:90 +#, c-format +msgid "Failed to receive response for `%s' request from `%s' service.\n" +msgstr "" + +#: src/fs/fs_list_indexed.c:113 +#, c-format +msgid "Failed to receive valid response for `%s' request from `%s' service.\n" +msgstr "" + +#: src/fs/fs_list_indexed.c:151 +#, fuzzy, c-format +msgid "Failed to not connect to `%s' service.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/fs/fs_misc.c:126 +#, c-format +msgid "Did not find mime type `%s' in extension list.\n" +msgstr "" + +#: src/fs/fs_namespace_advertise.c:150 +#, fuzzy +msgid "Unknown error" +msgstr "未知错误" + +#: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 +#, fuzzy +msgid "Failed to serialize meta data" +msgstr "å‘é€æ¶ˆæ¯å¤±è´¥ã€‚\n" + +#: src/fs/fs_namespace_advertise.c:278 +#, fuzzy +msgid "Failed to connect to datastore service" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 +#, fuzzy, c-format +msgid "Configuration fails to specify `%s' in section `%s'\n" +msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" + +#: src/fs/fs_namespace.c:112 +#, fuzzy, c-format +msgid "Failed to open `%s' for writing: %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 +#, fuzzy, c-format +msgid "Failed to write `%s': %s\n" +msgstr "è¿è¡Œ %s失败:%s %d\n" + +#: src/fs/fs_namespace.c:256 +#, c-format +msgid "Failed to create or read private key for namespace `%s'\n" +msgstr "" + +#: src/fs/fs_namespace.c:371 +#, c-format +msgid "Failed to read namespace private key file `%s', deleting it!\n" +msgstr "" + +#: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 +#, fuzzy +msgid "Internal error." +msgstr "未知错误。\n" + +#: src/fs/fs_namespace.c:631 +msgid "Failed to connect to datastore." +msgstr "" + +#: src/fs/fs_publish.c:129 src/fs/fs_publish.c:395 +#, c-format +msgid "Publishing failed: %s" +msgstr "" + +#: src/fs/fs_publish.c:616 src/fs/fs_publish.c:633 src/fs/fs_publish.c:672 +#: src/fs/fs_publish.c:692 src/fs/fs_publish.c:717 src/fs/fs_publish.c:857 +#, c-format +msgid "Can not index file `%s': %s. Will try to insert instead.\n" +msgstr "" + +#: src/fs/fs_publish.c:618 +msgid "timeout on index-start request to `fs' service" +msgstr "" + +#: src/fs/fs_publish.c:630 +#, fuzzy +msgid "unknown error" +msgstr "未知错误" + +#: src/fs/fs_publish.c:673 +msgid "failed to compute hash" +msgstr "" + +#: src/fs/fs_publish.c:693 +msgid "filename too long" +msgstr "" + +#: src/fs/fs_publish.c:718 +msgid "could not connect to `fs' service" +msgstr "" + +#: src/fs/fs_publish.c:741 +#, fuzzy, c-format +msgid "Failed to get file identifiers for `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/fs/fs_publish.c:806 +#, c-format +msgid "Recursive upload failed at `%s': %s" +msgstr "" + +#: src/fs/fs_publish.c:812 +#, c-format +msgid "Recursive upload failed: %s" +msgstr "" + +#: src/fs/fs_publish.c:858 +msgid "needs to be an actual file" +msgstr "" + +#: src/fs/fs_publish.c:1067 +#, c-format +msgid "Insufficient space for publishing: %s" +msgstr "" + +#: src/fs/fs_publish.c:1138 +#, c-format +msgid "Reserving space for %u entries and %llu bytes for publication\n" +msgstr "" + +#: src/fs/fs_publish_ksk.c:258 +msgid "Could not connect to datastore." +msgstr "" + +#: src/fs/fs_search.c:810 +#, c-format +msgid "Got result with unknown block type `%d', ignoring" +msgstr "" + +#: src/fs/fs_test_lib.c:269 +#, fuzzy, c-format +msgid "Failed to start daemon: %s\n" +msgstr "è¿è¡Œ %s失败:%s %d\n" + +#: src/fs/fs_unindex.c:57 +msgid "Failed to find given position in file" +msgstr "" + +#: src/fs/fs_unindex.c:62 +#, fuzzy +msgid "Failed to read file" +msgstr "å‘é€æ¶ˆæ¯å¤±è´¥ã€‚\n" + +#: src/fs/fs_unindex.c:231 +msgid "Unexpected time for a response from `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:239 +msgid "Timeout waiting for `fs' service." +msgstr "" + +#: src/fs/fs_unindex.c:247 +#, fuzzy +msgid "Invalid response from `fs' service." +msgstr "“%sâ€çš„å‚数无效。\n" + +#: src/fs/fs_unindex.c:292 +msgid "Failed to connect to FS service for unindexing." +msgstr "" + +#: src/fs/fs_unindex.c:325 +#, fuzzy +msgid "Failed to connect to `datastore' service." +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/fs/fs_unindex.c:338 +#, fuzzy +msgid "Failed to open file for unindexing." +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/fs_unindex.c:372 +msgid "Failed to compute hash of file." +msgstr "" + +#: src/fs/fs_uri.c:220 +#, c-format +msgid "`%' must be followed by HEX number" +msgstr "" + +#: src/fs/fs_uri.c:279 +msgid "Malformed KSK URI (must not begin or end with `+')" +msgstr "" + +#: src/fs/fs_uri.c:297 +msgid "`++' not allowed in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:304 +msgid "Quotes not balanced in KSK URI" +msgstr "" + +#: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 +msgid "Malformed SKS URI" +msgstr "" + +#: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 +msgid "Malformed CHK URI" +msgstr "" + +#: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 +#: src/fs/fs_uri.c:621 +msgid "SKS URI malformed" +msgstr "" + +#: src/fs/fs_uri.c:603 +msgid "SKS URI malformed (could not decode public key)" +msgstr "" + +#: src/fs/fs_uri.c:609 +msgid "SKS URI malformed (could not find signature)" +msgstr "" + +#: src/fs/fs_uri.c:615 +msgid "SKS URI malformed (could not decode signature)" +msgstr "" + +#: src/fs/fs_uri.c:628 +msgid "SKS URI malformed (could not parse expiration time)" +msgstr "" + +#: src/fs/fs_uri.c:640 +msgid "SKS URI malformed (signature failed validation)" +msgstr "" + +#: src/fs/fs_uri.c:678 +msgid "Unrecognized URI type" +msgstr "" + +#: src/fs/fs_uri.c:903 +#, fuzzy +msgid "Lacking key configuration settings.\n" +msgstr "ç«‹å³ä¿å­˜é…置?" + +#: src/fs/fs_uri.c:910 +#, fuzzy, c-format +msgid "Could not access hostkey file `%s'.\n" +msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" + +#: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 +msgid "No keywords specified!\n" +msgstr "" + +#: src/fs/fs_uri.c:1148 +msgid "Number of double-quotes not balanced!\n" +msgstr "" + +#: src/fs/gnunet-directory.c:49 +#, c-format +msgid "\t\n" +msgstr "" + +#: src/fs/gnunet-directory.c:94 +#, c-format +msgid "Directory `%s' meta data:\n" +msgstr "" + +#: src/fs/gnunet-directory.c:97 +#, c-format +msgid "Directory `%s' contents:\n" +msgstr "" + +#: src/fs/gnunet-directory.c:132 +#, fuzzy +msgid "You must specify a filename to inspect.\n" +msgstr "您必须指定一个昵称\n" + +#: src/fs/gnunet-directory.c:145 +#, fuzzy, c-format +msgid "Failed to read directory `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/fs/gnunet-directory.c:154 +#, fuzzy, c-format +msgid "`%s' is not a GNUnet directory\n" +msgstr "更改 GNUnet 目录的æƒé™å‡ºé”™" + +#: src/fs/gnunet-directory.c:179 +#, fuzzy +msgid "Display contents of a GNUnet directory" +msgstr "更改 GNUnet 目录的æƒé™å‡ºé”™" + +#: src/fs/gnunet-download.c:100 +#, fuzzy, c-format +msgid "Starting download `%s'.\n" +msgstr "未知的命令“%sâ€ã€‚\n" + +#: src/fs/gnunet-download.c:109 +#, fuzzy +msgid "" +msgstr "未知错误" + +#: src/fs/gnunet-download.c:118 +#, c-format +msgid "" +"Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " +"download\n" +msgstr "" + +#: src/fs/gnunet-download.c:128 +#, c-format +msgid "Error downloading: %s.\n" +msgstr "" + +#: src/fs/gnunet-download.c:136 +#, c-format +msgid "Downloading `%s' done (%s/s).\n" +msgstr "" + +#: src/fs/gnunet-download.c:151 src/fs/gnunet-publish.c:190 +#: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 +#, c-format +msgid "Unexpected status: %d\n" +msgstr "" + +#: src/fs/gnunet-download.c:176 +#, fuzzy +msgid "You need to specify a URI argument.\n" +msgstr "您必须指定一个昵称\n" + +#: src/fs/gnunet-download.c:182 src/fs/gnunet-publish.c:618 +#, fuzzy, c-format +msgid "Failed to parse URI: %s\n" +msgstr "è¿è¡Œ %s失败:%s %d\n" + +#: src/fs/gnunet-download.c:189 +msgid "Only CHK or LOC URIs supported.\n" +msgstr "" + +#: src/fs/gnunet-download.c:196 +msgid "Target filename must be specified.\n" +msgstr "" + +#: src/fs/gnunet-download.c:210 src/fs/gnunet-publish.c:596 +#: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 +#, fuzzy, c-format +msgid "Could not initialize `%s' subsystem.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/fs/gnunet-download.c:247 src/fs/gnunet-search.c:285 +msgid "set the desired LEVEL of receiver-anonymity" +msgstr "" + +#: src/fs/gnunet-download.c:250 +msgid "delete incomplete downloads (when aborted with CTRL-C)" +msgstr "" + +#: src/fs/gnunet-download.c:253 src/fs/gnunet-search.c:288 +msgid "only search the local peer (no P2P network search)" +msgstr "" + +#: src/fs/gnunet-download.c:256 +msgid "write the file to FILENAME" +msgstr "" + +#: src/fs/gnunet-download.c:260 +msgid "set the maximum number of parallel downloads that is allowed" +msgstr "" + +#: src/fs/gnunet-download.c:264 +msgid "set the maximum number of parallel requests for blocks that is allowed" +msgstr "" + +#: src/fs/gnunet-download.c:267 +msgid "download a GNUnet directory recursively" +msgstr "" + +#: src/fs/gnunet-download.c:277 +msgid "" +"Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" +"chk/...)" +msgstr "" + +#: src/fs/gnunet-fs.c:117 +msgid "print a list of all indexed files" +msgstr "" + +#: src/fs/gnunet-fs.c:124 +msgid "Special file-sharing operations" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:151 src/statistics/gnunet-statistics.c:126 +#, fuzzy, c-format +msgid "Invalid argument `%s'\n" +msgstr "“%sâ€çš„å‚数无效。\n" + +#: src/fs/gnunet-pseudonym.c:165 +#, c-format +msgid "Namespace `%s' unknown.\n" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:240 src/fs/gnunet-pseudonym.c:247 +#: src/fs/gnunet-pseudonym.c:249 +#, fuzzy, c-format +msgid "Option `%s' ignored\n" +msgstr "%s:选项“%sâ€æœ‰æ­§ä¹‰\n" + +#: src/fs/gnunet-pseudonym.c:269 src/fs/gnunet-publish.c:672 +msgid "set the desired LEVEL of sender-anonymity" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:272 +msgid "create or advertise namespace NAME" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:275 +msgid "delete namespace NAME " +msgstr "" + +#: src/fs/gnunet-pseudonym.c:278 +msgid "" +"add an additional keyword for the advertisment (this option can be specified " +"multiple times)" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:282 src/fs/gnunet-publish.c:691 +msgid "set the meta-data for the given TYPE to the given VALUE" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:285 +msgid "print names of local namespaces" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:288 +msgid "use the given PRIORITY for the advertisments" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:291 +msgid "do not print names of remote namespaces" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:294 src/fs/gnunet-publish.c:710 +msgid "set the desired replication LEVEL" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:297 +msgid "specify ID of the root of the namespace" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:300 +msgid "change rating of namespace ID by VALUE" +msgstr "" + +#: src/fs/gnunet-pseudonym.c:308 +msgid "Manage GNUnet pseudonyms." +msgstr "" + +#: src/fs/gnunet-publish.c:147 +#, c-format +msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-publish.c:155 +#, c-format +msgid "Error publishing: %s.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:165 +#, c-format +msgid "Publishing `%s' done.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:169 +#, c-format +msgid "URI is `%s'.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:187 +msgid "Cleanup after abort complete.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:299 +#, fuzzy, c-format +msgid "Meta data for file `%s' (%s)\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/gnunet-publish.c:301 +#, fuzzy, c-format +msgid "Keywords for file `%s' (%s)\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/fs/gnunet-publish.c:352 +#, fuzzy, c-format +msgid "Failed to create namespace `%s'\n" +msgstr "å‘é€æ¶ˆæ¯å¤±è´¥ã€‚\n" + +#: src/fs/gnunet-publish.c:427 +#, fuzzy +msgid "Could not publish\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/fs/gnunet-publish.c:454 +msgid "Could not start publishing.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:485 +#, fuzzy, c-format +msgid "Scanning directory `%s'.\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/fs/gnunet-publish.c:487 +#, fuzzy, c-format +msgid "Scanning file `%s'.\n" +msgstr "未知的命令“%sâ€ã€‚\n" + +#: src/fs/gnunet-publish.c:492 +#, c-format +msgid "There was trouble processing file `%s', skipping it.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:497 +msgid "Preprocessing complete.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:501 +#, fuzzy, c-format +msgid "Extracting meta data from file `%s' complete.\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/gnunet-publish.c:505 +msgid "Meta data extraction has finished.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:512 +#, fuzzy +msgid "Internal error scanning directory.\n" +msgstr "未知错误。\n" + +#: src/fs/gnunet-publish.c:546 +#, c-format +msgid "Cannot extract metadata from a URI!\n" +msgstr "" + +#: src/fs/gnunet-publish.c:553 +#, c-format +msgid "You must specify one and only one filename for insertion.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:559 +#, c-format +msgid "You must NOT specify an URI and a filename.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:567 src/vpn/gnunet-vpn.c:214 +#, c-format +msgid "Option `%s' is required when using option `%s'.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:577 src/fs/gnunet-publish.c:584 +#: src/transport/gnunet-transport.c:530 +#, c-format +msgid "Option `%s' makes no sense without option `%s'.\n" +msgstr "" + +#: src/fs/gnunet-publish.c:606 +#, fuzzy, c-format +msgid "Could not create namespace `%s'\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/fs/gnunet-publish.c:639 +#, fuzzy, c-format +msgid "Failed to access `%s': %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/gnunet-publish.c:651 +msgid "" +"Failed to start meta directory scanner. Is gnunet-helper-publish-fs " +"installed?\n" +msgstr "" + +#: src/fs/gnunet-publish.c:676 +msgid "disable adding the creation time to the metadata of the uploaded file" +msgstr "" + +#: src/fs/gnunet-publish.c:679 +msgid "do not use libextractor to add keywords or metadata" +msgstr "" + +#: src/fs/gnunet-publish.c:683 +msgid "" +"print list of extracted keywords that would be used, but do not perform " +"upload" +msgstr "" + +#: src/fs/gnunet-publish.c:687 +msgid "" +"add an additional keyword for the top-level file or directory (this option " +"can be specified multiple times)" +msgstr "" + +#: src/fs/gnunet-publish.c:694 +msgid "" +"do not index, perform full insertion (stores entire file in encrypted form " +"in GNUnet database)" +msgstr "" + +#: src/fs/gnunet-publish.c:699 +msgid "" +"specify ID of an updated version to be published in the future (for " +"namespace insertions only)" +msgstr "" + +#: src/fs/gnunet-publish.c:703 +msgid "specify the priority of the content" +msgstr "" + +#: src/fs/gnunet-publish.c:707 +msgid "publish the files under the pseudonym NAME (place file into namespace)" +msgstr "" + +#: src/fs/gnunet-publish.c:713 +msgid "" +"only simulate the process but do not do any actual publishing (useful to " +"compute URIs)" +msgstr "" + +#: src/fs/gnunet-publish.c:717 +msgid "" +"set the ID of this version of the publication (for namespace insertions only)" +msgstr "" + +#: src/fs/gnunet-publish.c:721 +msgid "" +"URI to be published (can be used instead of passing a file to add keywords " +"to the file with the respective URI)" +msgstr "" + +#: src/fs/gnunet-publish.c:736 +msgid "Publish a file or directory on GNUnet" +msgstr "" + +#: src/fs/gnunet-search.c:111 +#, c-format +msgid "Failed to write directory with search results to `%s'\n" +msgstr "" + +#: src/fs/gnunet-search.c:181 +#, fuzzy, c-format +msgid "Error searching: %s.\n" +msgstr "创建用户出错" + +#: src/fs/gnunet-search.c:231 +msgid "Could not create keyword URI from arguments.\n" +msgstr "" + +#: src/fs/gnunet-search.c:255 +msgid "Could not start searching.\n" +msgstr "" + +#: src/fs/gnunet-search.c:291 +msgid "write search results to file starting with PREFIX" +msgstr "" + +#: src/fs/gnunet-search.c:294 +msgid "automatically terminate search after VALUE ms" +msgstr "" + +#: src/fs/gnunet-search.c:301 +msgid "automatically terminate search after VALUE results are found" +msgstr "" + +#: src/fs/gnunet-search.c:308 +msgid "Search GNUnet for files that were published on GNUnet" +msgstr "" + +#: src/fs/gnunet-service-fs.c:240 +msgid "# running average P2P latency (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 +msgid "# Loopback routes suppressed" +msgstr "" + +#: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 +#: src/topology/gnunet-daemon-topology.c:1290 +#: src/topology/gnunet-daemon-topology.c:1297 +#, fuzzy, c-format +msgid "Failed to connect to `%s' service.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 +#: src/topology/gnunet-daemon-topology.c:654 +#: src/topology/gnunet-daemon-topology.c:756 +#: src/transport/gnunet-service-transport_neighbours.c:960 +#: src/transport/gnunet-service-transport_neighbours.c:1289 +#: src/transport/gnunet-service-transport_neighbours.c:1841 +#: src/transport/gnunet-service-transport_neighbours.c:2499 +#: src/transport/gnunet-service-transport_neighbours.c:2566 +msgid "# peers connected" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:696 +msgid "# migration stop messages received" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:700 +#, c-format +msgid "Migration of content to peer `%s' blocked for %llu ms\n" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:735 +msgid "# replies transmitted to other peers" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:741 +msgid "# replies dropped" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 +msgid "# P2P searches active" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:858 +msgid "# artificial delays introduced (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:911 +msgid "# replies dropped due to type mismatch" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:919 +msgid "# replies received for other peers" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:933 +msgid "# replies dropped due to insufficient cover traffic" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:971 +msgid "# P2P searches destroyed due to ultimate reply" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1038 +msgid "# requests done for free (low load)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1062 +msgid "# request dropped, priority insufficient" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1072 +msgid "# requests done for a price (normal load)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1151 +msgid "# GET requests received (from other peers)" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1185 +msgid "# requests dropped due to initiator not being connected" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1207 +msgid "# requests dropped due to missing reverse route" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1267 +msgid "# requests dropped due TTL underflow" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1293 +msgid "# requests dropped due to higher-TTL request" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1322 +msgid "# P2P query messages received and processed" +msgstr "" + +#: src/fs/gnunet-service-fs_cp.c:1687 +msgid "# migration stop messages sent" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:113 +#: src/fs/gnunet-service-fs_indexing.c:163 +#, fuzzy, c-format +msgid "Configuration option `%s' in section `%s' missing.\n" +msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" + +#: src/fs/gnunet-service-fs_indexing.c:121 +#: src/fs/gnunet-service-fs_indexing.c:177 +#, fuzzy, c-format +msgid "Could not open `%s'.\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/fs/gnunet-service-fs_indexing.c:137 +#, fuzzy, c-format +msgid "Error writing `%s'.\n" +msgstr "创建用户出错" + +#: src/fs/gnunet-service-fs_indexing.c:228 +#, c-format +msgid "" +"Index request received for file `%s' is already indexed as `%s'. Permitting " +"anyway.\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:266 +#, c-format +msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:481 +#, fuzzy, c-format +msgid "Failed to delete bogus block: %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/fs/gnunet-service-fs_indexing.c:539 +msgid "# index blocks removed: original file inaccessible" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:554 +#, fuzzy, c-format +msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/fs/gnunet-service-fs_indexing.c:556 +msgid "not indexed" +msgstr "" + +#: src/fs/gnunet-service-fs_indexing.c:571 +#, c-format +msgid "Indexed file `%s' changed at offset %llu\n" +msgstr "" + +#: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 +#: src/fs/gnunet-service-fs_lc.c:488 +msgid "# client searches active" +msgstr "" + +#: src/fs/gnunet-service-fs_lc.c:256 +msgid "# replies received for local clients" +msgstr "" + +#: src/fs/gnunet-service-fs_lc.c:321 +msgid "# client searches received" +msgstr "" + +#: src/fs/gnunet-service-fs_lc.c:356 +msgid "# client searches updated (merged content seen list)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:265 +msgid "# average retransmission delay (ms)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:391 +msgid "# transmission failed (core has no bandwidth)" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:420 +msgid "# query messages sent to other peers" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:469 +msgid "# delay heap timeout" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:476 +msgid "# query plans executed" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:538 +msgid "# requests merged" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:544 +msgid "# requests refreshed" +msgstr "" + +#: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 +#: src/fs/gnunet-service-fs_pe.c:748 +msgid "# query plan entries" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:285 +msgid "# Pending requests created" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 +msgid "# Pending requests active" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:779 +msgid "# replies received and matched" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:808 +msgid "# duplicate replies discarded (bloomfilter)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:822 +#, c-format +msgid "Unsupported block type %u\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:835 +msgid "# results found locally" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:953 +msgid "# Datastore `PUT' failures" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:980 +msgid "# storage requests dropped due to high load" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1015 +msgid "# Replies received from DHT" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1106 +#, c-format +msgid "Datastore lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1127 +#, c-format +msgid "On-demand lookup already took %llu ms!\n" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1174 +msgid "# Datastore lookups concluded (no results)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1188 +msgid "# Datastore lookups concluded (seen all)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1197 +msgid "# Datastore lookups aborted (more than MAX_RESULTS)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1211 +msgid "# requested DBLOCK or IBLOCK not found" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1224 +msgid "# on-demand blocks matched requests" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1237 +msgid "# on-demand lookups performed successfully" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1242 +msgid "# on-demand lookups failed" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 +#: src/fs/gnunet-service-fs_pr.c:1447 +msgid "# Datastore lookups concluded (error queueing)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1327 +msgid "# Datastore lookups concluded (found last result)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1338 +msgid "# Datastore lookups concluded (load too high)" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1424 +msgid "# Datastore lookups initiated" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1508 +msgid "# GAP PUT messages received" +msgstr "" + +#: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 +#, fuzzy, c-format +msgid "Configuration fails to specify `%s', assuming default value." +msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" + +#: src/fs/gnunet-service-fs_push.c:629 +#, c-format +msgid "" +"Invalid value specified for option `%s' in section `%s', content pushing " +"disabled\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:89 +#, c-format +msgid "Unindexing at %llu/%llu (%s remaining)\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:96 +#, c-format +msgid "Error unindexing: %s.\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:101 +msgid "Unindexing done.\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:131 +#, c-format +msgid "You must specify one and only one filename for unindexing.\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:148 +msgid "Could not start unindex operation.\n" +msgstr "" + +#: src/fs/gnunet-unindex.c:176 +msgid "Unindex a file that was previously indexed with gnunet-publish." +msgstr "" + +#: src/fs/plugin_block_fs.c:131 +msgid "Reply mismatched in terms of namespace. Discarded.\n" +msgstr "" + +#: src/gns/gns_api.c:221 +#, fuzzy +msgid "Failed to connect to the GNS service!\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/gns/gnunet-gns-lookup.c:210 +msgid "Issue a request to the GNUnet Naming System, prints results." +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:264 +msgid "" +"None of the functions for the hostlist daemon were enabled. I have no " +"reason to run!\n" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:317 +msgid "advertise our hostlist to other peers" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:322 +msgid "" +"bootstrap using hostlists (it is highly recommended that you always use this " +"option)" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:325 +msgid "enable learning about hostlist servers from other peers" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:329 +msgid "provide a hostlist server" +msgstr "" + +#: src/hostlist/gnunet-daemon-hostlist.c:341 +msgid "GNUnet hostlist server and client" +msgstr "" + +#: src/hostlist/hostlist-client.c:286 +msgid "# bytes downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:307 src/hostlist/hostlist-client.c:339 +msgid "# invalid HELLOs downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:342 +#, c-format +msgid "Invalid `%s' message received from hostlist at `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:330 +msgid "# valid HELLOs downloaded from hostlist servers" +msgstr "" + +#: src/hostlist/hostlist-client.c:374 src/hostlist/hostlist-client.c:395 +#, c-format +msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:472 src/hostlist/hostlist-client.c:682 +#: src/hostlist/hostlist-client.c:688 src/hostlist/hostlist-client.c:740 +#: src/hostlist/hostlist-client.c:749 src/hostlist/hostlist-client.c:877 +#: src/hostlist/hostlist-client.c:967 src/hostlist/hostlist-client.c:972 +#: src/transport/plugin_transport_http_client.c:108 +#: src/transport/plugin_transport_http_client.c:123 +#, c-format +msgid "%s failed at %s:%d: `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:592 src/hostlist/hostlist-client.c:1342 +msgid "# advertised hostlist URIs" +msgstr "" + +#: src/hostlist/hostlist-client.c:622 +#, c-format +msgid "# advertised URI `%s' downloaded" +msgstr "" + +#: src/hostlist/hostlist-client.c:663 +#, c-format +msgid "" +"Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " +"gets dismissed.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:805 +#, c-format +msgid "Timeout trying to download hostlist from `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:822 +#, c-format +msgid "Download limit of %u bytes exceeded, stopping download\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:842 +#, fuzzy, c-format +msgid "%s failed for `%s' at %s:%d: `%s'\n" +msgstr "对驱动器“%2$sâ€çš„“%1$sâ€æ“作失败:%3$u\n" + +#: src/hostlist/hostlist-client.c:848 +#, c-format +msgid "Download of hostlist `%s' completed.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:856 +#, c-format +msgid "Adding successfully tested hostlist `%s' datastore.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:909 +#, c-format +msgid "Bootstrapping using hostlist at `%s'.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:917 +msgid "# hostlist downloads initiated" +msgstr "" + +#: src/hostlist/hostlist-client.c:1045 src/hostlist/hostlist-client.c:1515 +msgid "# milliseconds between hostlist downloads" +msgstr "" + +#: src/hostlist/hostlist-client.c:1054 +#, c-format +msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1092 +msgid "Scheduled saving of hostlists\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1096 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1119 src/hostlist/hostlist-client.c:1135 +msgid "# active connections" +msgstr "" + +#: src/hostlist/hostlist-client.c:1253 +#, c-format +msgid "Initial time between hostlist downloads is %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1284 +#, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1290 +#, c-format +msgid "Loading saved hostlist entries from file `%s' \n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1294 +#, c-format +msgid "Hostlist file `%s' is not existing\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1305 +#, fuzzy, c-format +msgid "Could not open file `%s' for reading to load hostlists: %s\n" +msgstr "无法解æžâ€œ%sâ€æ¥ç¡®å®šå·²æ–¹çš„ IP 地å€ï¼š%s\n" + +#: src/hostlist/hostlist-client.c:1338 +#, c-format +msgid "%u hostlist URIs loaded from file\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1340 +msgid "# hostlist URIs read from file" +msgstr "" + +#: src/hostlist/hostlist-client.c:1373 +#, c-format +msgid "" +"No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1387 +#, fuzzy, c-format +msgid "Could not open file `%s' for writing to save hostlists: %s\n" +msgstr "无法解æžâ€œ%sâ€æ¥ç¡®å®šå·²æ–¹çš„ IP 地å€ï¼š%s\n" + +#: src/hostlist/hostlist-client.c:1392 +#, c-format +msgid "Writing %u hostlist URIs to `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1416 src/hostlist/hostlist-client.c:1433 +#, c-format +msgid "Error writing hostlist URIs to file `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1428 +msgid "# hostlist URIs written to file" +msgstr "" + +#: src/hostlist/hostlist-client.c:1480 +msgid "Learning is enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1483 +#, c-format +msgid "Hostlists will be saved to file again in %llums\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1492 +msgid "Learning is not enabled on this peer\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1504 +#, c-format +msgid "" +"Since learning is not enabled on this peer, hostlist file `%s' was removed\n" +msgstr "" + +#: src/hostlist/hostlist-client.c:1508 +#, c-format +msgid "Hostlist file `%s' could not be removed\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:134 +msgid "bytes in hostlist" +msgstr "" + +#: src/hostlist/hostlist-server.c:157 +msgid "expired addresses encountered" +msgstr "" + +#: src/hostlist/hostlist-server.c:184 +#: src/topology/gnunet-daemon-topology.c:875 +#, c-format +msgid "Error in communication with PEERINFO service: %s\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:205 +msgid "HELLOs without addresses encountered (ignored)" +msgstr "" + +#: src/hostlist/hostlist-server.c:221 +msgid "bytes not included in hostlist (size limit)" +msgstr "" + +#: src/hostlist/hostlist-server.c:269 +#, c-format +msgid "Refusing `%s' request to hostlist server\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:272 +msgid "hostlist requests refused (not HTTP GET)" +msgstr "" + +#: src/hostlist/hostlist-server.c:280 +msgid "Sending 100 CONTINUE reply\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:287 +#, c-format +msgid "Refusing `%s' request with %llu bytes of upload data\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:291 +msgid "hostlist requests refused (upload data)" +msgstr "" + +#: src/hostlist/hostlist-server.c:299 +msgid "Could not handle hostlist request since I do not have a response yet\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:302 +msgid "hostlist requests refused (not ready)" +msgstr "" + +#: src/hostlist/hostlist-server.c:306 +msgid "Received request for our hostlist\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:307 +msgid "hostlist requests processed" +msgstr "" + +#: src/hostlist/hostlist-server.c:350 +msgid "# hostlist advertisements send" +msgstr "" + +#: src/hostlist/hostlist-server.c:397 +msgid "Advertisement message could not be queued by core\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:565 +#, c-format +msgid "Invalid port number %llu. Exiting.\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:574 +#, c-format +msgid "Hostlist service starts on %s:%llu\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:588 +#, c-format +msgid "Address to obtain hostlist: `%s'\n" +msgstr "" + +#: src/hostlist/hostlist-server.c:626 +#, c-format +msgid "Could not start hostlist HTTP server on port %u\n" +msgstr "" + +#: src/mesh/gnunet-service-mesh.c:4595 +msgid "Wrong CORE service\n" +msgstr "" + +#: src/mesh/gnunet-service-mesh.c:4789 +#, fuzzy +msgid "Mesh service is lacking key configuration settings. Exiting.\n" +msgstr "ç«‹å³ä¿å­˜é…置?" + +#: src/mesh/gnunet-service-mesh.c:4798 +#, fuzzy +msgid "Mesh service could not access hostkey. Exiting.\n" +msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" + +#: src/namestore/namestore_api.c:272 src/namestore/namestore_api.c:313 +msgid "Namestore added record successfully" +msgstr "" + +#: src/namestore/namestore_api.c:281 src/namestore/namestore_api.c:322 +msgid "Namestore failed to add record" +msgstr "" + +#: src/nat/gnunet-nat-server.c:289 +#, c-format +msgid "Please pass valid port number as the first argument! (got `%s')\n" +msgstr "" + +#: src/nat/gnunet-nat-server.c:328 +msgid "GNUnet NAT traversal test helper daemon" +msgstr "" + +#: src/nat/nat.c:803 +#, c-format +msgid "gnunet-helper-nat-server generated malformed address `%s'\n" +msgstr "" + +#: src/nat/nat.c:852 +#, fuzzy, c-format +msgid "Failed to start %s\n" +msgstr "è¿è¡Œ %s失败:%s %d\n" + +#: src/nat/nat.c:1121 +#, fuzzy, c-format +msgid "Malformed %s `%s' given in configuration!\n" +msgstr "ä¿å­˜é…置失败。" + +#: src/nat/nat.c:1187 src/nat/nat.c:1197 +#, c-format +msgid "" +"Configuration requires `%s', but binary is not installed properly (SUID bit " +"not set). Option disabled.\n" +msgstr "" + +#: src/nat/nat.c:1329 +msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" +msgstr "" + +#: src/nat/nat.c:1341 +#, c-format +msgid "Running gnunet-helper-nat-client %s %s %u\n" +msgstr "" + +#: src/nat/nat_test.c:348 +msgid "Failed to connect to `gnunet-nat-server'\n" +msgstr "" + +#: src/nat/nat_test.c:418 +#, c-format +msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" +msgstr "" + +#: src/nse/gnunet-nse-profiler.c:926 +#, fuzzy +msgid "Measure quality and performance of the NSE service." +msgstr "无法访问该æœåŠ¡" + +#: src/nse/gnunet-service-nse.c:936 +#, c-format +msgid "Proof of work invalid: %llu!\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1391 src/nse/gnunet-service-nse.c:1410 +#: src/nse/gnunet-service-nse.c:1431 +msgid "NSE service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1398 +msgid "Invalid work requirement for NSE service. Exiting.\n" +msgstr "" + +#: src/nse/gnunet-service-nse.c:1419 +#, fuzzy +msgid "NSE service could not access hostkey. Exiting.\n" +msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" + +#: src/peerinfo/gnunet-service-peerinfo.c:133 +#, c-format +msgid "Removing expired address of transport `%s'\n" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:195 +msgid "# peers known" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:239 +#, c-format +msgid "" +"File `%s' in directory `%s' does not match naming convention. Removed.\n" +msgstr "" + +#: src/peerinfo/gnunet-service-peerinfo.c:305 +#, c-format +msgid "Still no peers found in `%s'!\n" +msgstr "" + +#: src/peerinfo/peerinfo_api.c:279 +#, fuzzy, c-format +msgid "Failed to transmit message to `%s' service.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/peerinfo/peerinfo_api.c:435 +msgid "Failed to receive response from `PEERINFO' service." +msgstr "" + +#: src/peerinfo/peerinfo_api.c:463 src/peerinfo/peerinfo_api.c:481 +msgid "Received invalid message from `PEERINFO' service.\n" +msgstr "" + +#: src/peerinfo/peerinfo_api.c:523 +#, fuzzy +msgid "Failed to transmit iteration request to `PEERINFO' service\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/peerinfo/peerinfo_api.c:557 +msgid "Timeout transmitting iteration request to `PEERINFO' service.\n" +msgstr "" + +#: src/peerinfo/peerinfo_api_notify.c:258 +#, fuzzy, c-format +msgid "Could not connect to `%s' service.\n" +msgstr "无法连接到 %s:%u:%s\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:216 +#, fuzzy, c-format +msgid "Could not find option `%s:%s' in configuration.\n" +msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" + +#: src/peerinfo-tool/gnunet-peerinfo.c:223 +#, c-format +msgid "Loading hostkey from `%s' failed.\n" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:235 +#, c-format +msgid "I am peer `%s'.\n" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:255 +msgid "output only the identity strings" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:258 +msgid "output our own identity only" +msgstr "" + +#: src/peerinfo-tool/gnunet-peerinfo.c:264 +#, fuzzy +msgid "Print information about peers." +msgstr "无法获å–有关用户“%sâ€çš„ä¿¡æ¯ï¼š%s\n" + +#: src/pt/gnunet-daemon-pt.c:264 +msgid "Failed to pack DNS request. Dropping.\n" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:270 +msgid "# DNS requests mapped to VPN" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:323 +msgid "# DNS records modified" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:500 +msgid "# DNS replies intercepted" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:506 +msgid "Failed to parse DNS request. Dropping.\n" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:602 +msgid "# DNS requests dropped (timeout)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:632 +msgid "# DNS requests intercepted" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:637 +msgid "# DNS requests dropped (DNS mesh tunnel down)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:645 +msgid "# DNS requests dropped (malformed)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:716 +msgid "# DNS replies received" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:730 +msgid "# DNS replies dropped (too late?)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 +msgid "# DNS requests aborted (tunnel down)" +msgstr "" + +#: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 +#: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 +#, fuzzy, c-format +msgid "Failed to connect to %s service. Exiting.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/pt/gnunet-daemon-pt.c:973 +msgid "Daemon to run to perform IP protocol translation to GNUnet" +msgstr "" + +#: src/statistics/gnunet-service-statistics.c:209 +#, c-format +msgid "Loading %llu bytes of statistics from `%s'\n" +msgstr "" + +#: src/statistics/gnunet-service-statistics.c:267 +#, c-format +msgid "Wrote %llu bytes of statistics to `%s'\n" +msgstr "" + +#: src/statistics/gnunet-statistics.c:98 +#, fuzzy +msgid "Failed to obtain statistics.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/statistics/gnunet-statistics.c:164 +msgid "limit output to statistics for the given NAME" +msgstr "" + +#: src/statistics/gnunet-statistics.c:167 +msgid "make the value being set persistent" +msgstr "" + +#: src/statistics/gnunet-statistics.c:170 +msgid "limit output to the given SUBSYSTEM" +msgstr "" + +#: src/statistics/gnunet-statistics.c:173 +msgid "just print the statistics value" +msgstr "" + +#: src/statistics/gnunet-statistics.c:180 +msgid "Print statistics about GNUnet operations." +msgstr "" + +#: src/statistics/statistics_api.c:390 +#, fuzzy +msgid "Failed to connect to statistics service!\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/template/gnunet-template.c:68 +msgid "help text" +msgstr "" + +#: src/testing/gnunet-testing.c:157 +#, fuzzy +msgid "Could not read hostkeys file, specify hostkey file with -H!\n" +msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" + +#: src/testing/gnunet-testing.c:159 +#, c-format +msgid "Specified hostkey file `%s' not found!\n" +msgstr "" + +#: src/testing/gnunet-testing.c:273 +#, fuzzy +msgid "create unique configuration files" +msgstr "更改é…置文件中的一个值" + +#: src/testing/gnunet-testing.c:275 +msgid "create hostkey files from pre-computed hostkey list" +msgstr "" + +#: src/testing/gnunet-testing.c:277 +msgid "host key file" +msgstr "" + +#: src/testing/gnunet-testing.c:279 +#, fuzzy +msgid "number of unique configuration files or hostkeys to create" +msgstr "打å°é…置文件中的一个值到标准输出" + +#: src/testing/gnunet-testing.c:281 +#, fuzzy +msgid "configuration template" +msgstr "é…置已ä¿å­˜" + +#: src/testing/gnunet-testing.c:287 +msgid "Command line tool to access the testing library" +msgstr "" + +#: src/testing/helper.c:56 +#, fuzzy +msgid "Peer is lacking HOSTKEY configuration setting.\n" +msgstr "ç«‹å³ä¿å­˜é…置?" + +#: src/testing/helper.c:64 +#, fuzzy +msgid "Could not access hostkey.\n" +msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" + +#: src/testing/testing.c:204 +msgid "`scp' does not seem to terminate (timeout copying config).\n" +msgstr "" + +#: src/testing/testing.c:218 src/testing/testing.c:808 +msgid "`scp' did not complete cleanly.\n" +msgstr "" + +#: src/testing/testing.c:239 +#, fuzzy +msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/testing/testing.c:240 +#, fuzzy +msgid "Failed to create pipe for `ssh' process.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/testing/testing.c:292 +#, fuzzy, c-format +msgid "Could not start `%s' process to create hostkey.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/testing/testing.c:299 +#, fuzzy +msgid "Failed to start `gnunet-peerinfo' process.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/testing/testing.c:300 src/testing/testing.c:488 +#, fuzzy +msgid "Failed to start `ssh' process.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/testing/testing.c:360 +#, c-format +msgid "Error reading from gnunet-peerinfo: %s\n" +msgstr "" + +#: src/testing/testing.c:364 +msgid "Malformed output from gnunet-peerinfo!\n" +msgstr "" + +#: src/testing/testing.c:374 +#, fuzzy +msgid "Failed to get hostkey!\n" +msgstr "å‘é€æ¶ˆæ¯å¤±è´¥ã€‚\n" + +#: src/testing/testing.c:406 +msgid "`Failed while waiting for topology setup!\n" +msgstr "" + +#: src/testing/testing.c:480 +#, fuzzy, c-format +msgid "Could not start `%s' process to start GNUnet.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/testing/testing.c:487 +#, fuzzy +msgid "Failed to start `gnunet-arm' process.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/testing/testing.c:509 src/testing/testing.c:612 +msgid "`gnunet-arm' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:510 src/testing/testing.c:613 +#: src/testing/testing.c:633 +msgid "`ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:582 +msgid "Unable to get HELLO for peer!\n" +msgstr "" + +#: src/testing/testing.c:632 +msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" +msgstr "" + +#: src/testing/testing.c:653 src/testing/testing.c:685 +msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:668 src/testing/testing.c:723 +msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" +msgstr "" + +#: src/testing/testing.c:796 +msgid "`scp' does not seem to terminate.\n" +msgstr "" + +#: src/testing/testing.c:966 +#, fuzzy, c-format +msgid "Starting service %s for peer `%4s'\n" +msgstr "å¸è½½ GNUnet æœåŠ¡" + +#: src/testing/testing.c:1237 src/testing/testing_group.c:6278 +#, fuzzy, c-format +msgid "Could not start `%s' process to copy configuration directory.\n" +msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" + +#: src/testing/testing.c:1322 src/testing/testing.c:1397 +#, fuzzy, c-format +msgid "Terminating peer `%4s'\n" +msgstr "未知的用户“%sâ€\n" + +#: src/testing/testing.c:1480 +#, fuzzy, c-format +msgid "Setting d->dead on peer `%4s'\n" +msgstr "å¸è½½ GNUnet æœåŠ¡" + +#: src/testing/testing.c:1610 +msgid "Peer not yet running, can not change configuration at this point." +msgstr "" + +#: src/testing/testing.c:1618 +#, fuzzy +msgid "Failed to write new configuration to disk." +msgstr "ä¿å­˜é…置失败。" + +#: src/testing/testing.c:1647 +#, fuzzy, c-format +msgid "Could not start `%s' process to copy configuration file.\n" +msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" + +#: src/testing/testing.c:1650 +#, fuzzy +msgid "Failed to copy new configuration to remote machine." +msgstr "ä¿å­˜é…置失败。" + +#: src/testing/testing.c:1805 +#, fuzzy +msgid "Peers failed to connect" +msgstr "" +"\n" +"按任æ„键继续\n" + +#: src/testing/testing.c:1933 +#, fuzzy +msgid "Failed to connect to core service of first peer!\n" +msgstr "加载 sqstore æœåŠ¡å¤±è´¥ã€‚检查您的é…ç½®ï¼\n" + +#: src/testing/testing.c:2156 +msgid "Peers are not fully running yet, can not connect!\n" +msgstr "" + +#: src/testing/testing_group.c:1910 src/testing/testing_group.c:1922 +#: src/testing/testing_group.c:2023 src/testing/testing_group.c:2082 +#: src/testing/testing_group.c:2171 src/testing/testing_group.c:2191 +#: src/testing/testing_group.c:2328 src/testing/testing_peergroup.c:940 +#, fuzzy, c-format +msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" +msgstr "é…ç½®ä¸æ»¡è¶³é…置规范文件“%sâ€çš„约æŸï¼\n" + +#: src/testing/testing_group.c:1932 +#, c-format +msgid "Target is %d connections per peer." +msgstr "" + +#: src/testing/testing_group.c:2179 +#, c-format +msgid "" +"Invalid value `%s' for option `%s' in section `%s': got %f, needed value " +"greater than 0\n" +msgstr "" + +#: src/testing/testing_group.c:2209 src/testing/testing_group.c:2402 +#, c-format +msgid "Connecting nodes in 2d torus topology: %u rows %u columns\n" +msgstr "" + +#: src/testing/testing_group.c:2246 +#, c-format +msgid "natural log of %d is %d, will run %d iterations\n" +msgstr "" + +#: src/testing/testing_group.c:2249 +#, c-format +msgid "Total connections added thus far: %u!\n" +msgstr "" + +#: src/testing/testing_group.c:2290 +#, c-format +msgid "Total connections added for small world: %d!\n" +msgstr "" + +#: src/testing/testing_group.c:2342 +#, c-format +msgid "rand is %f probability is %f\n" +msgstr "" + +#: src/testing/testing_group.c:2919 src/testing/testing_group.c:3118 +#, c-format +msgid "" +"No `%s' specified in peer configuration in section `%s', cannot copy friends " +"file!\n" +msgstr "" + +#: src/testing/testing_group.c:3020 +msgid "Finished copying all friend files!\n" +msgstr "" + +#: src/testing/testing_group.c:3133 +#, fuzzy, c-format +msgid "Copying file with command cp %s %s\n" +msgstr "“%sâ€ä»¥é”™è¯¯ç  %s 失败:%s\n" + +#: src/testing/testing_group.c:3156 +#, fuzzy, c-format +msgid "Copying file with command scp %s %s\n" +msgstr "“%sâ€ä»¥é”™è¯¯ç  %s 失败:%s\n" + +#: src/testing/testing_group.c:3173 +#, c-format +msgid "Checking copy status of file %d\n" +msgstr "" + +#: src/testing/testing_group.c:3191 +#, c-format +msgid "File %d copied\n" +msgstr "" + +#: src/testing/testing_group.c:3206 +#, fuzzy +msgid "Finished copying all blacklist files!\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/testing/testing_group.c:3586 src/testing/testing_group.c:3723 +#: src/testing/testing_group.c:4884 src/testing/testing_group.c:5025 +msgid "Delaying connect, we have too many outstanding connections!\n" +msgstr "" + +#: src/testing/testing_group.c:3596 src/testing/testing_group.c:4894 +#: src/testing/testing_group.c:5035 +#, c-format +msgid "Creating connection, outstanding_connections is %d\n" +msgstr "" + +#: src/testing/testing_group.c:3608 +#, c-format +msgid "Offering HELLO of peer %s to peer %s\n" +msgstr "" + +#: src/testing/testing_group.c:3734 +#, c-format +msgid "Creating connection, outstanding_connections is %d (max %d)\n" +msgstr "" + +#: src/testing/testing_group.c:3988 +msgid "Creating clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:3993 +msgid "Creating small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:3998 +msgid "Creating small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4002 +msgid "Creating ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4006 +msgid "Creating 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4010 +msgid "Creating Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4014 +msgid "Creating InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4018 +msgid "Creating Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4023 +msgid "Creating straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4027 +msgid "Creating topology from file!\n" +msgstr "" + +#: src/testing/testing_group.c:4043 +msgid "Creating no allowed topology (all peers can connect at core level)\n" +msgstr "" + +#: src/testing/testing_group.c:4058 +msgid "Failed during friend file copying!\n" +msgstr "" + +#: src/testing/testing_group.c:4064 +msgid "Friend files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:4081 +msgid "Blacklisting all but clique topology\n" +msgstr "" + +#: src/testing/testing_group.c:4087 +msgid "Blacklisting all but small world (ring) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4093 +msgid "Blacklisting all but small world (2d-torus) topology\n" +msgstr "" + +#: src/testing/testing_group.c:4099 +msgid "Blacklisting all but ring topology\n" +msgstr "" + +#: src/testing/testing_group.c:4105 +msgid "Blacklisting all but 2d torus topology\n" +msgstr "" + +#: src/testing/testing_group.c:4111 +msgid "Blacklisting all but Erdos-Renyi topology\n" +msgstr "" + +#: src/testing/testing_group.c:4117 +msgid "Blacklisting all but InterNAT topology\n" +msgstr "" + +#: src/testing/testing_group.c:4152 +msgid "Blacklisting all but Scale Free topology\n" +msgstr "" + +#: src/testing/testing_group.c:4158 +msgid "Blacklisting all but straight line topology\n" +msgstr "" + +#: src/testing/testing_group.c:4173 +#, fuzzy +msgid "Failed during blacklist file copying!\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/testing/testing_group.c:4179 +msgid "Blacklist files created/copied successfully!\n" +msgstr "" + +#: src/testing/testing_group.c:5263 +msgid "Creating clique CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5270 +msgid "Creating small world (ring) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5277 +msgid "Creating small world (2d-torus) CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5283 +msgid "Creating ring CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5290 +msgid "Creating 2d torus CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5297 +msgid "Creating Erdos-Renyi CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5304 +msgid "Creating InterNAT CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5311 +msgid "Creating Scale Free CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5318 +msgid "Creating straight line CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5324 +msgid "Creating no CONNECT topology\n" +msgstr "" + +#: src/testing/testing_group.c:5330 +msgid "Unknown topology specification, can't connect peers!\n" +msgstr "" + +#: src/testing/testing_group.c:5340 +#, c-format +msgid "Connecting random subset (%'.2f percent) of possible peers\n" +msgstr "" + +#: src/testing/testing_group.c:5348 +#, c-format +msgid "Connecting a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5357 +#, c-format +msgid "Using DFS to connect a minimum of %u peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:5367 +#, c-format +msgid "Finding additional %u closest peers each (if possible)\n" +msgstr "" + +#: src/testing/testing_group.c:6062 src/transport/transport-testing.c:650 +#, fuzzy +msgid "Could not read hostkeys file!\n" +msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" + +#: src/testing/testing_group.c:6131 +#, fuzzy, c-format +msgid "Could not create configuration for peer number %u on `%s'!\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/topology/gnunet-daemon-topology.c:244 +msgid "# peers blacklisted" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:380 +msgid "# connect requests issued to transport" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:675 +#: src/topology/gnunet-daemon-topology.c:761 +msgid "# friends connected" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:950 +msgid "Failed to connect to core service, can not manage topology!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:982 +#, c-format +msgid "Option `%s' in section `%s' not specified!\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:994 +#, c-format +msgid "Could not read friends list `%s'\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1000 +#, c-format +msgid "Friends file `%s' is empty.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1009 +#, c-format +msgid "Failed to read friends list from `%s': out of memory\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1017 +#, c-format +msgid "Failed to read friends list from `%s'\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1037 +#, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1050 +#, c-format +msgid "" +"Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1060 +#, fuzzy, c-format +msgid "Found friend `%s' in configuration\n" +msgstr "" +"\n" +"结æŸé…置。\n" + +#: src/topology/gnunet-daemon-topology.c:1066 +#, c-format +msgid "Found myself `%s' in friend list (useless, ignored)\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1076 +#, fuzzy +msgid "# friends in configuration" +msgstr "" +"\n" +"结æŸé…置。\n" + +#: src/topology/gnunet-daemon-topology.c:1082 +msgid "" +"Fewer friends specified than required by minimum friend count. Will only " +"connect to friends.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1089 +msgid "" +"More friendly connections required than target total number of connections.\n" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1126 +msgid "# HELLO messages received" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1183 +msgid "# HELLO messages gossipped" +msgstr "" + +#: src/topology/gnunet-daemon-topology.c:1323 +msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:247 +#, fuzzy, c-format +msgid "Could not read blacklist file `%s'\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/transport/gnunet-service-transport_blacklist.c:254 +#, c-format +msgid "Blacklist file `%s' is empty.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:266 +#, fuzzy, c-format +msgid "Failed to read blacklist from `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/transport/gnunet-service-transport_blacklist.c:287 +#: src/transport/gnunet-service-transport_blacklist.c:311 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, giving up!\n" +msgstr "é…置文件“%sâ€ç¬¬ %d 行有语法错误。\n" + +#: src/transport/gnunet-service-transport_blacklist.c:298 +#: src/transport/gnunet-service-transport_blacklist.c:336 +#, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:350 +#, fuzzy, c-format +msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" +msgstr "é…置文件“%sâ€ç¬¬ %d 行有语法错误。\n" + +#: src/transport/gnunet-service-transport_blacklist.c:364 +#, c-format +msgid "Found myself `%s' in blacklist (useless, ignored)\n" +msgstr "" + +#: src/transport/gnunet-service-transport_blacklist.c:523 +#: src/transport/gnunet-service-transport_blacklist.c:764 +msgid "# disconnects due to blacklist" +msgstr "" + +#: src/transport/gnunet-service-transport.c:158 +msgid "# bytes payload discarded due to not connected peer " +msgstr "" + +#: src/transport/gnunet-service-transport.c:572 +msgid "Transport service is lacking key configuration settings. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport.c:581 +msgid "Transport service could not access hostkey. Exiting.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:353 +#, c-format +msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:358 +msgid "# messages dropped due to slow client" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:510 +#, c-format +msgid "Rejecting control connection from peer `%s', which is not me!\n" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:628 +msgid "# bytes payload received for other peers" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:645 +msgid "# bytes payload dropped (other peer was not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_clients.c:696 +msgid "# REQUEST CONNECT messages received" +msgstr "" + +#: src/transport/gnunet-service-transport_hello.c:172 +msgid "# refreshed my HELLO" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:482 +msgid "# failed connection attempts due to timeout" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:883 +msgid "# peers disconnected due to external request" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:966 +#, fuzzy +msgid "# fast reconnects failed" +msgstr "" +"\n" +"按任æ„键继续\n" + +#: src/transport/gnunet-service-transport_neighbours.c:1022 +msgid "# peers disconnected due to timeout" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1047 +msgid "# keepalives sent" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1088 +msgid "# peers disconnected due to global disconnect" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1888 +#: src/transport/gnunet-service-transport_neighbours.c:1909 +msgid "# messages not sent (no such peer or not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1925 +msgid "# bytes in message queue for other peers" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:1977 +msgid "# messages discarded due to lack of neighbour record" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2013 +msgid "# bandwidth quota violations by other peers" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2031 +msgid "# ms throttling suggested" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2060 +msgid "# KEEPALIVE messages discarded (not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2113 +msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2121 +msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2187 +msgid "# SET QUOTA messages ignored (no such peer)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2205 +msgid "# disconnects due to quota of 0" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2323 +msgid "# disconnect messages ignored (old format)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2336 +msgid "# disconnect messages ignored (timestamp)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2411 +msgid "# unexpected CONNECT_ACK messages (no peer)" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2453 +msgid "# unexpected CONNECT_ACK messages" +msgstr "" + +#: src/transport/gnunet-service-transport_neighbours.c:2544 +msgid "# unexpected ACK messages" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:111 +msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:118 +#, c-format +msgid "Starting transport plugins `%s'\n" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:122 +#, c-format +msgid "Loading `%s' transport plugin\n" +msgstr "" + +#: src/transport/gnunet-service-transport_plugins.c:150 +#, fuzzy, c-format +msgid "Failed to load transport plugin for `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/transport/gnunet-service-transport_validation.c:410 +msgid "# address records discarded" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:459 +#, c-format +msgid "" +"Not transmitting `%s' with `%s', message too big (%u bytes!). This should " +"not happen.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:508 +msgid "# PING without HELLO messages sent" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:566 +msgid "# address revalidations started" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:798 +msgid "# PING message for different peer received" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:833 +#, c-format +msgid "" +"Not confirming PING with address `%s' since I cannot confirm having this " +"address.\n" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:919 +msgid "# PONGs unicast via reliable transport" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:928 +msgid "# PONGs multicast to all available addresses" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1050 +msgid "# PONGs dropped, no matching pending validation" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1075 +msgid "# PONGs dropped, signature expired" +msgstr "" + +#: src/transport/gnunet-service-transport_validation.c:1134 +#, c-format +msgid "Adding `%s' without addresses for peer `%s'\n" +msgstr "" + +#: src/transport/gnunet-transport.c:256 +msgid "No transport plugins configured, peer will never communicate\n" +msgstr "" + +#: src/transport/gnunet-transport.c:269 +#, c-format +msgid "No port configured for plugin `%s', cannot test it\n" +msgstr "" + +#: src/transport/gnunet-transport.c:319 +#, c-format +msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:326 +#, c-format +msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" +msgstr "" + +#: src/transport/gnunet-transport.c:359 +#, c-format +msgid "Transmitting %u bytes to %s\n" +msgstr "" + +#: src/transport/gnunet-transport.c:379 +#, fuzzy, c-format +msgid "Connected to %s\n" +msgstr "“%sâ€å·²è¿žæŽ¥åˆ°â€œ%sâ€ã€‚\n" + +#: src/transport/gnunet-transport.c:410 +#, fuzzy, c-format +msgid "Disconnected from %s\n" +msgstr "“%sâ€å·²è¿žæŽ¥åˆ°â€œ%sâ€ã€‚\n" + +#: src/transport/gnunet-transport.c:439 +#, c-format +msgid "Received %u bytes from %s\n" +msgstr "" + +#: src/transport/gnunet-transport.c:453 +#, fuzzy, c-format +msgid "Peer `%s': %s %s\n" +msgstr "è¿è¡Œ %s失败:%s %d\n" + +#: src/transport/gnunet-transport.c:483 +#, fuzzy, c-format +msgid "Peer `%s' disconnected\n" +msgstr "" +"\n" +"按任æ„键继续\n" + +#: src/transport/gnunet-transport.c:539 +#, fuzzy, c-format +msgid "Failed to parse peer identity `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/transport/gnunet-transport.c:587 +msgid "measure how fast we are receiving data (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:590 +#, fuzzy +msgid "try to connect to the given peer" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/transport/gnunet-transport.c:593 +msgid "provide information about all current connections (once)" +msgstr "" + +#: src/transport/gnunet-transport.c:596 +msgid "provide information about all current connections (continuously)" +msgstr "" + +#: src/transport/gnunet-transport.c:599 +msgid "do not resolve hostnames" +msgstr "" + +#: src/transport/gnunet-transport.c:603 +msgid "send data for benchmarking to the other peer (until CTRL-C)" +msgstr "" + +#: src/transport/gnunet-transport.c:606 +msgid "test transport configuration (involves external server)" +msgstr "" + +#: src/transport/gnunet-transport.c:614 +#, fuzzy +msgid "Direct access to transport service." +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/transport/plugin_transport_http.c:981 +msgid "Disabling IPv6 since it is not supported on this system!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1029 +#, fuzzy +msgid "Require valid port number for service in configuration!\n" +msgstr "ä¿å­˜é…置失败。" + +#: src/transport/plugin_transport_http.c:1054 src/util/service.c:986 +#, fuzzy, c-format +msgid "Failed to resolve `%s': %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/transport/plugin_transport_http.c:1071 src/util/service.c:1003 +#, fuzzy, c-format +msgid "Failed to find %saddress for `%s'.\n" +msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" + +#: src/transport/plugin_transport_http.c:1176 +#, c-format +msgid "Found %u addresses to report to NAT service\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1189 +#, c-format +msgid "FREEING %s\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1264 +msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1277 +#, fuzzy +msgid "Port is required! Fix in configuration\n" +msgstr "" +"\n" +"结æŸé…置。\n" + +#: src/transport/plugin_transport_http.c:1288 +msgid "Port 0, client only mode\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1308 +#, c-format +msgid "" +"Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http.c:1338 +#, c-format +msgid "" +"Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " +"Binding to all addresses!\n" +msgstr "" + +#: src/transport/plugin_transport_http_client.c:621 +#, c-format +msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:189 +msgid "" +"Could not create a new TLS certificate, program `gnunet-transport-" +"certificate-creation' could not be started!\n" +msgstr "" + +#: src/transport/plugin_transport_http_server.c:213 +msgid "No usable TLS certificate found and creating one failed!\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:370 +#, c-format +msgid "Received malformed message via %s. Ignored.\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:457 +msgid "SMTP filter string to invalid, lacks ': '\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:466 +#, c-format +msgid "SMTP filter string to long, capped to `%s'\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:561 +#: src/transport/plugin_transport_smtp.c:571 +#: src/transport/plugin_transport_smtp.c:584 +#: src/transport/plugin_transport_smtp.c:603 +#: src/transport/plugin_transport_smtp.c:626 +#: src/transport/plugin_transport_smtp.c:634 +#: src/transport/plugin_transport_smtp.c:647 +#: src/transport/plugin_transport_smtp.c:658 +#, c-format +msgid "SMTP: `%s' failed: %s.\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:801 +msgid "No email-address specified, can not start SMTP transport.\n" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:813 +msgid "# bytes received via SMTP" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:814 +msgid "# bytes sent via SMTP" +msgstr "" + +#: src/transport/plugin_transport_smtp.c:816 +msgid "# bytes dropped by SMTP (outgoing)" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:512 +#, c-format +msgid "Unexpected address length: %u bytes\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:616 +#: src/transport/plugin_transport_tcp.c:705 +#: src/transport/plugin_transport_tcp.c:757 +#: src/transport/plugin_transport_tcp.c:830 +#: src/transport/plugin_transport_tcp.c:909 +msgid "# bytes currently in TCP buffers" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:622 +#: src/transport/plugin_transport_tcp.c:856 +#: src/transport/plugin_transport_tcp.c:1561 +msgid "# TCP sessions active" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:709 +msgid "# bytes discarded by TCP (timeout)" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:760 +msgid "# bytes transmitted via TCP" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:834 +msgid "# bytes discarded by TCP (disconnect)" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1081 +#, c-format +msgid "Address of unexpected length: %u\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1116 +msgid "Found valid IPv4 NAT address (creating session)!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1186 +msgid "# transport-service disconnect requests for TCP" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1603 +msgid "# TCP WELCOME messages received" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1756 +msgid "# bytes received via TCP" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1823 +msgid "# network-level TCP disconnect events" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1962 src/util/service.c:889 +#, c-format +msgid "Require valid port number for service `%s' in configuration!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:1976 +#, fuzzy +msgid "Failed to start service.\n" +msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#: src/transport/plugin_transport_tcp.c:2039 +#, c-format +msgid "Failed to find option %s in section %s!\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2062 +#, c-format +msgid "TCP transport listening on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2066 +msgid "TCP transport not listening on any port (client only)\n" +msgstr "" + +#: src/transport/plugin_transport_tcp.c:2070 +#, c-format +msgid "TCP transport advertises itself as being on port %llu\n" +msgstr "" + +#: src/transport/plugin_transport_udp_broadcasting.c:130 +msgid "# IPv6 multicast HELLO beacons received via udp" +msgstr "" + +#: src/transport/plugin_transport_udp_broadcasting.c:172 +msgid "# IPv4 broadcast HELLO beacons received via udp" +msgstr "" + +#: src/transport/plugin_transport_udp_broadcasting.c:393 +#, c-format +msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:1985 +#, fuzzy +msgid "Failed to open UDP sockets\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/transport/plugin_transport_udp.c:2068 +#, c-format +msgid "Given `%s' option is out of range: %llu > %u\n" +msgstr "" + +#: src/transport/plugin_transport_udp.c:2112 +#, fuzzy, c-format +msgid "Invalid IPv6 address: `%s'\n" +msgstr "无效的进程优先级“%sâ€\n" + +#: src/transport/plugin_transport_unix.c:1051 +#, fuzzy +msgid "Failed to open UNIX sockets\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/transport/plugin_transport_wlan.c:875 +msgid "# wlan session timeouts" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:899 +msgid "# wlan session created" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:980 +#: src/transport/plugin_transport_wlan.c:1138 +#: src/transport/plugin_transport_wlan.c:1159 +#: src/transport/plugin_transport_wlan.c:1190 +#: src/transport/plugin_transport_wlan.c:2334 +#: src/transport/plugin_transport_wlan.c:3142 +msgid "# wlan pending sessions" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1233 +#: src/transport/plugin_transport_wlan.c:1888 +msgid "# wlan pending fragments" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1388 +#, c-format +msgid "" +"Finished reading from gnunet-helper-transport-wlan stdout with code: %d\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1732 +msgid "# wlan hello beacons send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1765 +#: src/transport/plugin_transport_wlan.c:1968 +#: src/transport/plugin_transport_wlan.c:2059 +#, c-format +msgid "Error writing to wlan helper. errno == %d, ERROR: %s\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:1954 +msgid "# wlan acks send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2025 +msgid "# wlan fragments send" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2161 +#, c-format +msgid "Wlan Address len %d is wrong\n" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2295 +#: src/transport/plugin_transport_wlan.c:2919 +#: src/transport/plugin_transport_wlan.c:3145 +msgid "# wlan mac endpoints" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2517 +msgid "# wlan whole messages received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2708 +msgid "# wlan hello messages received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2742 +msgid "# wlan fragments received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2790 +msgid "# wlan acks received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2879 +msgid "# wlan mac endpoints timeouts" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2903 +msgid "# wlan mac endpoints created" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:2956 +msgid "# wlan WLAN_HELPER_DATA received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:3010 +msgid "# wlan messages for this client received" +msgstr "" + +#: src/transport/plugin_transport_wlan.c:3021 +msgid "# wlan messages inside WLAN_HELPER_DATA received" +msgstr "" + +#: src/transport/transport_api.c:588 +#, c-format +msgid "Received unexpected message of type %u in %s:%u\n" +msgstr "" + +#: src/util/bio.c:136 src/util/bio.c:142 +#, fuzzy, c-format +msgid "Error reading `%s': %s" +msgstr "创建用户出错" + +#: src/util/bio.c:143 +msgid "End of file" +msgstr "" + +#: src/util/bio.c:195 +#, c-format +msgid "Error reading length of string `%s'" +msgstr "" + +#: src/util/bio.c:205 +#, c-format +msgid "String `%s' longer than allowed (%u > %u)" +msgstr "" + +#: src/util/bio.c:250 +#, c-format +msgid "Serialized metadata `%s' larger than allowed (%u>%u)" +msgstr "" + +#: src/util/bio.c:264 +#, c-format +msgid "Metadata `%s' failed to deserialize" +msgstr "" + +#: src/util/client.c:304 +#, c-format +msgid "" +"Could not determine valid hostname and port for service `%s' from " +"configuration.\n" +msgstr "" + +#: src/util/client.c:312 +#, c-format +msgid "Need a non-empty hostname for service `%s'.\n" +msgstr "" + +#: src/util/client.c:657 +msgid "Failure to transmit TEST request.\n" +msgstr "" + +#: src/util/client.c:717 src/util/service.c:919 +#, c-format +msgid "UNIXPATH `%s' too long, maximum length is %llu\n" +msgstr "" + +#: src/util/client.c:859 +#, c-format +msgid "Could not connect to service `%s', must not be running.\n" +msgstr "" + +#: src/util/client.c:875 +#, c-format +msgid "Failure to transmit request to service `%s'\n" +msgstr "" + +#: src/util/client.c:1143 +msgid "Could not submit request, not expecting to receive a response.\n" +msgstr "" + +#: src/util/common_logging.c:239 src/util/common_logging.c:889 +msgid "DEBUG" +msgstr "调试" + +#: src/util/common_logging.c:241 src/util/common_logging.c:887 +msgid "INFO" +msgstr "ä¿¡æ¯" + +#: src/util/common_logging.c:243 src/util/common_logging.c:885 +msgid "WARNING" +msgstr "警告" + +#: src/util/common_logging.c:245 src/util/common_logging.c:883 +msgid "ERROR" +msgstr "错误" + +#: src/util/common_logging.c:247 src/util/common_logging.c:891 +msgid "NONE" +msgstr "" + +#: src/util/common_logging.c:609 +#, fuzzy, c-format +msgid "Failed to create or access directory for log file `%s'\n" +msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#: src/util/common_logging.c:724 +#, fuzzy, c-format +msgid "Message `%.*s' repeated %u times in the last %s\n" +msgstr "消æ¯â€œ%.*sâ€é‡å¤äº† %u 次,在最近 %llu 秒内\n" + +#: src/util/common_logging.c:892 +msgid "INVALID" +msgstr "" + +#: src/util/common_logging.c:991 +msgid "unknown address" +msgstr "" + +#: src/util/common_logging.c:1029 +msgid "invalid address" +msgstr "" + +#: src/util/configuration.c:245 +#, fuzzy, c-format +msgid "Syntax error in configuration file `%s' at line %u.\n" +msgstr "é…置文件“%sâ€ç¬¬ %d 行有语法错误。\n" + +#: src/util/configuration.c:817 +#, c-format +msgid "" +"Configuration value '%s' for '%s' in section '%s' is not in set of legal " +"choices\n" +msgstr "" + +#: src/util/connection.c:460 +#, fuzzy, c-format +msgid "Access denied to `%s'\n" +msgstr "“%sâ€å·²è¿žæŽ¥åˆ°â€œ%sâ€ã€‚\n" + +#: src/util/connection.c:475 +#, c-format +msgid "Accepting connection from `%s': %p\n" +msgstr "" + +#: src/util/connection.c:629 +#, c-format +msgid "" +"Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" +msgstr "" + +#: src/util/connection.c:821 src/util/connection.c:992 +#, fuzzy, c-format +msgid "Trying to connect to `%s' (%p)\n" +msgstr "无法连接到 %s:%u:%s\n" + +#: src/util/connection.c:830 +#, fuzzy, c-format +msgid "Failed to connect to `%s' (%p)\n" +msgstr "无法连接到 %s:%u:%s\n" + +#: src/util/connection.c:983 +#, c-format +msgid "Attempt to connect to `%s' failed\n" +msgstr "" + +#: src/util/connection.c:1465 +#, c-format +msgid "" +"Could not satisfy pending transmission request, socket closed or connect " +"failed (%p).\n" +msgstr "" + +#: src/util/container_bloomfilter.c:507 +#, c-format +msgid "" +"Size of file on disk is incorrect for this Bloom filter (want %llu, have " +"%llu)\n" +msgstr "" + +#: src/util/crypto_random.c:280 +#, c-format +msgid "Starting `%s' process to generate entropy\n" +msgstr "" + +#: src/util/crypto_random.c:309 +#, c-format +msgid "libgcrypt has not the expected version (version %s is required).\n" +msgstr "libgcrypt 的版本ä¸ç¬¦åˆé¢„期(è¦æ±‚版本 %s)。\n" + +#: src/util/crypto_rsa.c:618 src/util/crypto_rsa.c:665 +#, fuzzy, c-format +msgid "Could not aquire lock on file `%s': %s...\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/util/crypto_rsa.c:623 +#, fuzzy +msgid "Creating a new private key. This may take a while.\n" +msgstr "正在å¯åŠ¨æ•°æ®ä»“库转æ¢(å¯èƒ½éœ€è¦ä¸€æ®µæ—¶é—´)。\n" + +#: src/util/crypto_rsa.c:641 +#, c-format +msgid "I am host `%s'. Stored new private key in `%s'.\n" +msgstr "" + +#: src/util/crypto_rsa.c:669 src/util/crypto_rsa.c:705 +msgid "This may be ok if someone is currently generating a hostkey.\n" +msgstr "" + +#: src/util/crypto_rsa.c:700 +#, c-format +msgid "" +"When trying to read hostkey file `%s' I found %u bytes but I need at least " +"%u.\n" +msgstr "" + +#: src/util/crypto_rsa.c:720 +#, c-format +msgid "File `%s' does not contain a valid private key. Deleting it.\n" +msgstr "" + +#: src/util/crypto_rsa.c:738 +#, c-format +msgid "I am host `%s'. Read private key from `%s'.\n" +msgstr "" + +#: src/util/crypto_rsa.c:959 +#, c-format +msgid "RSA signature verification failed at %s:%d: %s\n" +msgstr "" + +#: src/util/disk.c:479 +#, fuzzy, c-format +msgid "`%s' failed for drive `%S': %u\n" +msgstr "对驱动器“%2$sâ€çš„“%1$sâ€æ“作失败:%3$u\n" + +#: src/util/disk.c:1087 +#, c-format +msgid "Expected `%s' to be a directory!\n" +msgstr "“%sâ€åº”为目录ï¼\n" + +#: src/util/disk.c:1441 src/util/service.c:1580 +#, c-format +msgid "Cannot obtain information about user `%s': %s\n" +msgstr "无法获å–有关用户“%sâ€çš„ä¿¡æ¯ï¼š%s\n" + +#: src/util/disk.c:1759 +#, c-format +msgid "No `%s' specified for service `%s' in configuration.\n" +msgstr "" + +#: src/util/getopt.c:672 +#, c-format +msgid "%s: option `%s' is ambiguous\n" +msgstr "%s:选项“%sâ€æœ‰æ­§ä¹‰\n" + +#: src/util/getopt.c:696 +#, c-format +msgid "%s: option `--%s' does not allow an argument\n" +msgstr "%s:选项“--%sâ€ä¸å…许有å‚æ•°\n" + +#: src/util/getopt.c:701 +#, c-format +msgid "%s: option `%c%s' does not allow an argument\n" +msgstr "%s:选项“%c%sâ€ä¸å…许有å‚æ•°\n" + +#: src/util/getopt.c:718 src/util/getopt.c:886 +#, c-format +msgid "%s: option `%s' requires an argument\n" +msgstr "%s:选项“%sâ€è¦æ±‚有一个å‚æ•°\n" + +#: src/util/getopt.c:747 +#, c-format +msgid "%s: unrecognized option `--%s'\n" +msgstr "%s:无法识别的选项“--%sâ€\n" + +#: src/util/getopt.c:751 +#, c-format +msgid "%s: unrecognized option `%c%s'\n" +msgstr "%s:无法识别的选项“%c%sâ€\n" + +#: src/util/getopt.c:776 +#, c-format +msgid "%s: illegal option -- %c\n" +msgstr "%s:éžæ³•é€‰é¡¹ -- %c\n" + +#: src/util/getopt.c:778 +#, c-format +msgid "%s: invalid option -- %c\n" +msgstr "%s:无效选项 -- %c\n" + +#: src/util/getopt.c:806 src/util/getopt.c:934 +#, c-format +msgid "%s: option requires an argument -- %c\n" +msgstr "%s:选项è¦æ±‚有一个å‚æ•° -- %c\n" + +#: src/util/getopt.c:854 +#, c-format +msgid "%s: option `-W %s' is ambiguous\n" +msgstr "%s:选项“-W %sâ€æœ‰æ­§ä¹‰\n" + +#: src/util/getopt.c:872 +#, c-format +msgid "%s: option `-W %s' does not allow an argument\n" +msgstr "%s:选项“-W %s†ä¸å…许有å‚æ•°\n" + +#: src/util/getopt.c:1038 +#, fuzzy, c-format +msgid "Use %s to get a list of options.\n" +msgstr "请使用 --help 获å–选项列表。\n" + +#: src/util/getopt_helpers.c:84 +#, c-format +msgid "" +"Arguments mandatory for long options are also mandatory for short options.\n" +msgstr "长选项的必选å‚数对短选项也是必选的。\n" + +#: src/util/getopt_helpers.c:255 src/util/getopt_helpers.c:283 +#, c-format +msgid "You must pass a number to the `%s' option.\n" +msgstr "您必须å‘“%sâ€é€‰é¡¹ä¼ é€’一个数字。\n" + +#: src/util/gnunet-resolver.c:148 +msgid "perform a reverse lookup" +msgstr "" + +#: src/util/gnunet-resolver.c:154 +msgid "Use build-in GNUnet stub resolver" +msgstr "" + +#: src/util/gnunet-service-resolver.c:288 +#, c-format +msgid "Could not resolve `%s' (%s): %s\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/util/gnunet-service-resolver.c:358 +#: src/util/gnunet-service-resolver.c:399 +#, c-format +msgid "Could not find IP of host `%s': %s\n" +msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" + +#: src/util/gnunet-service-resolver.c:494 +#, c-format +msgid "Resolver asked to look up `%s'.\n" +msgstr "" + +#: src/util/gnunet-service-resolver.c:529 +#, c-format +msgid "Resolver asked to look up IP address `%s'.\n" +msgstr "" + +#: src/util/helper.c:239 +#, fuzzy, c-format +msgid "Error reading from `%s': %s\n" +msgstr "创建用户出错" + +#: src/util/helper.c:254 +#, c-format +msgid "Got 0 bytes from helper `%s' (EOF)\n" +msgstr "" + +#: src/util/helper.c:264 +#, c-format +msgid "Got %u bytes from helper `%s'\n" +msgstr "" + +#: src/util/helper.c:273 +#, fuzzy, c-format +msgid "Failed to parse inbound message from helper `%s'\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/util/helper.c:432 +#, fuzzy, c-format +msgid "Error writing to `%s': %s\n" +msgstr "创建用户出错" + +#: src/util/network.c:1196 +#, c-format +msgid "" +"Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" +msgstr "" + +#: src/util/os_installation.c:299 +#, fuzzy, c-format +msgid "" +"Could not determine installation path for %s. Set `%s' environment " +"variable.\n" +msgstr "无法确定安装路径。请å°è¯•è®¾ç½®â€œ%sâ€\n" + +#: src/util/os_installation.c:486 +#, fuzzy, c-format +msgid "Could not find binary `%s' in PATH!\n" +msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" + +#: src/util/os_installation.c:492 +#, fuzzy, c-format +msgid "access (%s, X_OK) failed: %s\n" +msgstr "“%sâ€è¯´ï¼š%s\n" + +#: src/util/os_installation.c:507 +#, fuzzy, c-format +msgid "stat (%s) failed: %s\n" +msgstr "“%sâ€è¯´ï¼š%s\n" + +#: src/util/os_priority.c:304 +#, fuzzy, c-format +msgid "Failed to open named pipe `%s' for reading: %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/util/os_priority.c:305 +#, fuzzy, c-format +msgid "Failed to open named pipe `%s' for writing: %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/util/plugin.c:89 +#, c-format +msgid "Initialization of plugin mechanism failed: %s!\n" +msgstr "æ’件机构åˆå§‹åŒ–失败:%sï¼\n" + +#: src/util/plugin.c:146 +#, c-format +msgid "`%s' failed to resolve method '%s' with error: %s\n" +msgstr "" + +#: src/util/plugin.c:219 +#, c-format +msgid "`%s' failed for library `%s' with error: %s\n" +msgstr "" + +#: src/util/plugin.c:349 +#, fuzzy +msgid "Could not determine plugin installation path.\n" +msgstr "无法确定用户界é¢å®šä¹‰æ–‡ä»¶ã€‚" + +#: src/util/pseudonym.c:273 +#, fuzzy, c-format +msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" +msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#: src/util/pseudonym.c:338 +msgid "no-name" +msgstr "æ— å称" + +#: src/util/resolver_api.c:202 +#, c-format +msgid "Must specify `%s' for `%s' in configuration!\n" +msgstr "" + +#: src/util/resolver_api.c:221 +#, c-format +msgid "" +"Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" +msgstr "" + +#: src/util/resolver_api.c:351 +#, fuzzy, c-format +msgid "Timeout trying to resolve IP address `%s'.\n" +msgstr "GNUnet 现在使用 IP åœ°å€ %s。\n" + +#: src/util/resolver_api.c:355 +#, c-format +msgid "Timeout trying to resolve hostname `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:426 +#, c-format +msgid "Resolver returns `%s' for IP `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:807 +#, c-format +msgid "Resolver returns `%s'.\n" +msgstr "" + +#: src/util/resolver_api.c:901 +#, c-format +msgid "Resolving our FQDN `%s'\n" +msgstr "" + +#: src/util/resolver_api.c:906 +#, fuzzy, c-format +msgid "Could not resolve our FQDN : %s\n" +msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#: src/util/resolver_api.c:938 +#, c-format +msgid "Resolving our hostname `%s'\n" +msgstr "" + +#: src/util/scheduler.c:866 +msgid "Looks like we're busy waiting...\n" +msgstr "" + +#: src/util/scheduler.c:996 +#, c-format +msgid "Attempt to cancel dead task %llu!\n" +msgstr "" + +#: src/util/server.c:397 +#, fuzzy, c-format +msgid "`%s' failed for port %d (%s).\n" +msgstr "对驱动器“%2$sâ€çš„“%1$sâ€æ“作失败:%3$u\n" + +#: src/util/server.c:406 +#, c-format +msgid "`%s' failed for port %d (%s): address already in use\n" +msgstr "" + +#: src/util/server.c:411 +#, fuzzy, c-format +msgid "`%s' failed for `%s': address already in use\n" +msgstr "对驱动器“%2$sâ€çš„“%1$sâ€æ“作失败:%3$u\n" + +#: src/util/server.c:640 +#, c-format +msgid "" +"Processing code for message of type %u did not call " +"GNUNET_SERVER_receive_done after %llums\n" +msgstr "" + +#: src/util/service.c:117 src/util/service.c:143 src/util/service.c:186 +#: src/util/service.c:207 src/util/service.c:214 +#, c-format +msgid "Invalid format for IP: `%s'\n" +msgstr "IP æ ¼å¼æ— æ•ˆï¼šâ€œ%sâ€\n" + +#: src/util/service.c:170 +#, c-format +msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." +msgstr "网络表示法无效(“/%d†在 IPv4 CIDR 中是éžæ³•çš„)。" + +#: src/util/service.c:263 +#, c-format +msgid "Invalid network notation (does not end with ';': `%s')\n" +msgstr "无效的网络表示法(没有以“;â€ç»“尾:“%sâ€)\n" + +#: src/util/service.c:296 +#, c-format +msgid "Wrong format `%s' for netmask\n" +msgstr "网络掩ç çš„æ ¼å¼â€œ%sâ€é”™è¯¯\n" + +#: src/util/service.c:326 +#, c-format +msgid "Wrong format `%s' for network\n" +msgstr "网络的格å¼â€œ%sâ€é”™è¯¯\n" + +#: src/util/service.c:668 +#, c-format +msgid "Access denied to UID %d / GID %d\n" +msgstr "" + +#: src/util/service.c:673 +#, c-format +msgid "Unknown address family %d\n" +msgstr "" + +#: src/util/service.c:680 +#, c-format +msgid "Access from `%s' denied to service `%s'\n" +msgstr "" + +#: src/util/service.c:724 +#, c-format +msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:752 +#, c-format +msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" +msgstr "" + +#: src/util/service.c:869 +#, c-format +msgid "" +"Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" +msgstr "" + +#: src/util/service.c:939 +#, c-format +msgid "" +"Disabling UNIX domain socket support for service `%s', failed to create UNIX " +"domain socket: %s\n" +msgstr "" + +#: src/util/service.c:956 +#, c-format +msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" +msgstr "" + +#: src/util/service.c:1191 +msgid "Could not access a pre-bound socket, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1242 src/util/service.c:1260 +#, c-format +msgid "Specified value for `%s' of service `%s' is invalid\n" +msgstr "" + +#: src/util/service.c:1287 +#, c-format +msgid "Could not access pre-bound socket %u, will try to bind myself\n" +msgstr "" + +#: src/util/service.c:1442 +#, fuzzy, c-format +msgid "Failed to start `%s' at `%s'\n" +msgstr "è¿è¡Œ %s失败:%s %d\n" + +#: src/util/service.c:1475 +#, c-format +msgid "Service `%s' runs at %s\n" +msgstr "" + +#: src/util/service.c:1521 +msgid "Service process failed to initialize\n" +msgstr "" + +#: src/util/service.c:1525 +msgid "Service process could not initialize server function\n" +msgstr "" + +#: src/util/service.c:1529 +msgid "Service process failed to report status\n" +msgstr "" + +#: src/util/service.c:1581 +msgid "No such user" +msgstr "无此用户" + +#: src/util/service.c:1594 +#, c-format +msgid "Cannot change user/group to `%s': %s\n" +msgstr "无法更改用户/组为“%sâ€ï¼š%s\n" + +#: src/util/service.c:1657 +msgid "do daemonize (detach from terminal)" +msgstr "" + +#: src/util/signal.c:80 +#, c-format +msgid "signal (%d, %p) returned %d.\n" +msgstr "" + +#: src/util/strings.c:143 +msgid "b" +msgstr "b" + +#: src/util/strings.c:354 +#, c-format +msgid "Character sets requested were `%s'->`%s'\n" +msgstr "" + +#: src/util/strings.c:462 +msgid "Failed to expand `$HOME': environment variable `HOME' not set" +msgstr "扩展“$HOMEâ€å¤±è´¥ï¼šæ²¡æœ‰è®¾ç½®çŽ¯å¢ƒå˜é‡â€œHOMEâ€" + +#: src/util/strings.c:554 +msgid "ms" +msgstr "毫秒" + +#: src/util/strings.c:559 +msgid "eternity" +msgstr "" + +#: src/util/strings.c:563 +msgid "s" +msgstr "秒" + +#: src/util/strings.c:567 +msgid "m" +msgstr "分" + +#: src/util/strings.c:571 +msgid "h" +msgstr "æ—¶" + +#: src/util/strings.c:575 +msgid " days" +msgstr " 天" + +#: src/util/strings.c:599 +msgid "end of time" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1065 +msgid "# Active tunnels" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 +#, fuzzy +msgid "# Peers connected to mesh tunnels" +msgstr "" +"\n" +"按任æ„键继续\n" + +#: src/vpn/gnunet-service-vpn.c:699 +msgid "# Bytes given to mesh for transmission" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:737 +msgid "# Bytes dropped in mesh queue (overflow)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:772 +msgid "# Mesh tunnels created" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:795 +#, fuzzy +msgid "Failed to setup mesh tunnel!\n" +msgstr "å‘é€æ¶ˆæ¯å¤±è´¥ã€‚\n" + +#: src/vpn/gnunet-service-vpn.c:967 +#, c-format +msgid "Protocol %u not supported, dropping\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1285 +msgid "# ICMPv4 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1306 +msgid "# ICMPv6 packets dropped (not allowed)" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1511 +msgid "# Packets received from TUN interface" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1549 src/vpn/gnunet-service-vpn.c:1590 +#, c-format +msgid "Packet received for unmapped destination `%s' (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1600 +msgid "Received IPv4 packet with options (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1614 +#, c-format +msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:1697 +msgid "# ICMP packets received from mesh" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2038 +msgid "# UDP packets received from mesh" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2196 +msgid "# TCP packets received from mesh" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2347 +msgid "Failed to find unallocated IPv4 address in VPN's range\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2402 +msgid "Failed to find unallocated IPv6 address in VPN's range\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2441 src/vpn/gnunet-service-vpn.c:2624 +msgid "# Active destinations" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:2726 +msgid "Failed to allocate IP address for new destination\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3133 +msgid "IPv6 support disabled as this system does not support IPv6\n" +msgstr "" + +#: src/vpn/gnunet-service-vpn.c:3165 +msgid "IPv4 support disabled as this system does not support IPv4\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:151 +#, fuzzy +msgid "Error creating tunnel\n" +msgstr "创建用户出错" + +#: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 +#, c-format +msgid "Option `%s' makes no sense with option `%s'.\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:208 +#, fuzzy, c-format +msgid "Option `%s' or `%s' is required.\n" +msgstr "%s:选项“%sâ€æœ‰æ­§ä¹‰\n" + +#: src/vpn/gnunet-vpn.c:220 +#, c-format +msgid "Option `%s' or `%s' is required when using option `%s'.\n" +msgstr "" + +#: src/vpn/gnunet-vpn.c:238 +#, fuzzy, c-format +msgid "`%s' is not a valid peer identifier.\n" +msgstr "“%sâ€ä¸å¯ç”¨ã€‚\n" + +#: src/vpn/gnunet-vpn.c:260 +#, fuzzy, c-format +msgid "`%s' is not a valid IP address.\n" +msgstr "“%sâ€ä¸å¯ç”¨ã€‚\n" + +#: src/vpn/gnunet-vpn.c:296 +msgid "request that result should be an IPv4 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:299 +msgid "request that result should be an IPv6 address" +msgstr "" + +#: src/vpn/gnunet-vpn.c:302 +msgid "print IP address only after mesh tunnel has been created" +msgstr "" + +#: src/vpn/gnunet-vpn.c:305 +msgid "how long should the mapping be valid for new tunnels?" +msgstr "" + +#: src/vpn/gnunet-vpn.c:308 +msgid "destination IP for the tunnel" +msgstr "" + +#: src/vpn/gnunet-vpn.c:311 +msgid "peer offering the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:314 +msgid "name of the service we would like to access" +msgstr "" + +#: src/vpn/gnunet-vpn.c:317 +msgid "service is offered via TCP" +msgstr "" + +#: src/vpn/gnunet-vpn.c:320 +msgid "service is offered via UDP" +msgstr "" + +#: src/vpn/gnunet-vpn.c:329 +msgid "Setup tunnels via VPN." +msgstr "" + +#: src/include/gnunet_common.h:479 src/include/gnunet_common.h:484 +#: src/include/gnunet_common.h:490 +#, c-format +msgid "Assertion failed at %s:%d.\n" +msgstr "" + +#: src/include/gnunet_common.h:500 +#, c-format +msgid "External protocol violation detected at %s:%d.\n" +msgstr "" + +#: src/include/gnunet_common.h:521 src/include/gnunet_common.h:528 +#, c-format +msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" +msgstr "" + +#, fuzzy +#~ msgid "Failed to send to `%s': %s\n" +#~ msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#, fuzzy +#~ msgid "Could not access file: %s\n" +#~ msgstr "错误:无法访问æœåŠ¡ï¼š%s\n" + +#, fuzzy +#~ msgid "`%s' failed on file `%s': %s" +#~ msgstr "对驱动器“%2$sâ€çš„“%1$sâ€æ“作失败:%3$u\n" + +#, fuzzy +#~ msgid "Failed to stop service `%s'!\n" +#~ msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" + +#, fuzzy +#~ msgid "Failed to start service `%s'!\n" +#~ msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#, fuzzy +#~ msgid "Service `%s' stopped\n" +#~ msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" + +#, fuzzy +#~ msgid "Unable to start service `%s': %s\n" +#~ msgstr "无法ä¿å­˜é…置文件“%sâ€ï¼š" + +#, fuzzy +#~ msgid "Unable to accept connection for service `%s': %s\n" +#~ msgstr "无法ä¿å­˜é…置文件“%sâ€ï¼š" + +#~ msgid "KiB" +#~ msgstr "KiB" + +#~ msgid "MiB" +#~ msgstr "MiB" + +#~ msgid "GiB" +#~ msgstr "GiB" + +#~ msgid "TiB" +#~ msgstr "TiB" + +#, fuzzy +#~ msgid "Could not resolve our FQDN : %s %u\n" +#~ msgstr "无法解æžâ€œ%sâ€(%s):%s\n" + +#, fuzzy +#~ msgid "Failed to load dhtlog plugin for `%s'\n" +#~ msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#, fuzzy +#~ msgid "Failed to get full path for `%s'\n" +#~ msgstr "解æžé…置文件“%sâ€å¤±è´¥\n" + +#, fuzzy +#~ msgid "Failed to create file for dhtlog.\n" +#~ msgstr "无法为守护程åºåˆ›å»ºç”¨æˆ·è´¦æˆ·ã€‚" + +#, fuzzy +#~ msgid "Phase 3: sending messages\n" +#~ msgstr "å‘é€æ¶ˆæ¯å¤±è´¥ã€‚\n" + +#, fuzzy +#~ msgid "Fail! Could not connect peers\n" +#~ msgstr "无法连接到 %s:%u:%s\n" + +#, fuzzy +#~ msgid "Failed to connect to core service\n" +#~ msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" + +#~ msgid "Error" +#~ msgstr "错误" + +#~ msgid "Help" +#~ msgstr "帮助" + +#~ msgid "Error!" +#~ msgstr "错误ï¼" + +#~ msgid "No" +#~ msgstr "å¦" + +#~ msgid "Yes" +#~ msgstr "是" + +#~ msgid "Internal error! (Choice invalid?)" +#~ msgstr "内部错误ï¼(选择无效?)" + +#~ msgid "Abort" +#~ msgstr "中止" + +#~ msgid "Ok" +#~ msgstr "确定" + +#~ msgid "GNUnet configuration" +#~ msgstr "GNUnet é…ç½®" + +#~ msgid "" +#~ "Welcome to GNUnet!\n" +#~ "\n" +#~ "This assistant will ask you a few basic questions in order to configure " +#~ "GNUnet.\n" +#~ "\n" +#~ "Please visit our homepage at\n" +#~ "\thttp://gnunet.org/\n" +#~ "and join our community at\n" +#~ "\thttp://gnunet.org/drupal/\n" +#~ "\n" +#~ "Have a lot of fun,\n" +#~ "\n" +#~ "the GNUnet team" +#~ msgstr "" +#~ "欢迎使用 GNUnetï¼\n" +#~ "\n" +#~ "此助手将询问您几个基本问题,以é…ç½® GNUnet。\n" +#~ "\n" +#~ "请访问我们的主页\n" +#~ "\thttp://gnunet.org/\n" +#~ "并欢迎加入我们的社区\n" +#~ "\thttp://gnunet.org/drupal/\n" +#~ "\n" +#~ "ç¥æ‚¨ä½¿ç”¨æ„‰å¿«ï¼Œ\n" +#~ "\n" +#~ "GNUnet 团队" + +#~ msgid "" +#~ "Choose the network interface that connects your computer to the internet " +#~ "from the list below." +#~ msgstr "请从下é¢çš„列表中选择计算机è”网的网络接å£ã€‚" + +#~ msgid "" +#~ "The \"Network interface\" is the device that connects your computer to " +#~ "the internet. This is usually a modem, an ISDN card or a network card in " +#~ "case you are using DSL." +#~ msgstr "" +#~ "“网络接å£â€æ˜¯å°†æ‚¨çš„计算机连接到互è”网的设备。该设备通常为一å°è°ƒåˆ¶è§£è°ƒå™¨ã€ä¸€" +#~ "å¼  ISDN å¡æˆ–一张网å¡(若您使用 DSL 网络)。" + +#~ msgid "Network configuration: interface" +#~ msgstr "网络é…置:接å£" + +#~ msgid "" +#~ "What is the name of the network interface that connects your computer to " +#~ "the Internet?" +#~ msgstr "您的计算机è”网所使用的网络接å£çš„å称是什么?" + +#~ msgid "Network configuration: IP" +#~ msgstr "网络é…置:IP" + +#~ msgid "What is this computer's public IP address or hostname?" +#~ msgstr "è¿™å°è®¡ç®—机的公网 IP 地å€æˆ–主机å是什么?" + +#~ msgid "" +#~ "If your provider always assigns the same IP-Address to you (a \"static\" " +#~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " +#~ "changes every now and then (\"dynamic\" IP-Address) but there's a " +#~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " +#~ "you can also enter it here.\n" +#~ "If left empty, GNUnet will try to automatically detect the IP.\n" +#~ "You can specify a hostname, GNUnet will then use DNS to resolve it.\n" +#~ "If in doubt, leave this empty." +#~ msgstr "" +#~ "如果您的网络è¿è¥å•†æ€»æ˜¯åˆ†é…固定的 IP 地å€ç»™æ‚¨(“é™æ€â€ IP 地å€),请将它输" +#~ "入“IP 地å€â€å­—段。如果您的 IP 是ä¸æ—¶å˜åŒ–çš„(“动æ€â€ IP 地å€)但有一个总是指å‘" +#~ "您的实际 IP 地å€çš„主机å(â€œåŠ¨æ€ DNSâ€),也å¯ä»¥å°†è¿™ä¸ªä¸»æœºå填到这里。\n" +#~ "如果ä¸å¡«ï¼ŒGNUnet å°†å°è¯•è‡ªåŠ¨æ£€æµ‹æ­¤ IP。\n" +#~ "您å¯ä»¥æŒ‡å®šä¸€ä¸ªä¸»æœºå,GNUnet 将使用 DNS æ¥è§£æžå®ƒã€‚\n" +#~ "如果ä¸æ˜Žç™½ï¼Œè¯·ä¸å¡«ã€‚" + +#~ msgid "Bandwidth configuration: upload" +#~ msgstr "带宽é…置:上传" + +#~ msgid "How much upstream bandwidth (in bytes/s) may be used?" +#~ msgstr "å¯ä»¥ä½¿ç”¨å¤šå°‘上行带宽(å•ä½ä¸ºå­—节/秒)?" + +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "The \"upstream\" is the data channel through which data is *sent* to the " +#~ "internet. The limit is the maximum amount which GNUnet is allowed to use. " +#~ "If you have a flatrate, you can set it to the maximum speed of your " +#~ "internet connection. You should not use a value that is higher than what " +#~ "your actual connection allows." +#~ msgstr "" +#~ "您å¯ä»¥åœ¨æ­¤é™åˆ¶ GNUnet 的资æºå ç”¨ã€‚\n" +#~ "\n" +#~ "“上行â€æ˜¯å‘互è”网“å‘é€â€æ•°æ®çš„æ•°æ®é€šé“。é™åˆ¶æ˜¯ GNUnet å¯ä½¿ç”¨çš„最大数æ®æµé‡ã€‚" +#~ "如果您的网速很平稳,您å¯ä»¥å°†è¯¥é™åˆ¶è®¾ç½®ä¸ºç½‘速的最大值。您ä¸åº”该使用超过实际" +#~ "连接速度æžé™çš„值。" + +#~ msgid "Bandwidth configuration: download" +#~ msgstr "带宽é…置:下载" + +#~ msgid "How much downstream bandwidth (in bytes/s) may be used?" +#~ msgstr "å¯ä»¥ä½¿ç”¨å¤šå°‘下行带宽(å•ä½ä¸ºå­—节/秒)?" + +#~ msgid "" +#~ "You can limit GNUnet's resource usage here.\n" +#~ "\n" +#~ "The \"downstream\" is the data channel through which data is *received* " +#~ "from the internet. The limit is the maximum amount which GNUnet is " +#~ "allowed to use. If you have a flatrate, you can set it to the maximum " +#~ "speed of your internet connection. You should not use a value that is " +#~ "higher than what your actual connection allows." +#~ msgstr "" +#~ "您å¯ä»¥åœ¨æ­¤é™åˆ¶ GNUnet 的资æºå ç”¨ã€‚\n" +#~ "\n" +#~ "“下行â€æ˜¯æ•°æ®ä»Žäº’è”网“接收â€æ•°æ®çš„æ•°æ®é€šé“。é™åˆ¶æ˜¯ GNUnet å¯ä½¿ç”¨çš„最大数æ®æµ" +#~ "é‡ã€‚如果您的网速很平稳,您å¯ä»¥å°†è¯¥é™åˆ¶è®¾ç½®ä¸ºç½‘速的最大值。您ä¸åº”该使用超过" +#~ "实际连接速度æžé™çš„值。" + +#~ msgid "Quota configuration" +#~ msgstr "é…é¢é…ç½®" + +#~ msgid "What is the maximum size of the datastore in MB?" +#~ msgstr "æ•°æ®ä»“库的最大尺寸是多少(MB)?" + +#~ msgid "" +#~ "The GNUnet datastore contains all content that GNUnet needs to store " +#~ "(indexed, inserted and migrated content)." +#~ msgstr "" +#~ "GNUnet æ•°æ®ä»“库包å«äº† GNUnet 需è¦ä¿å­˜çš„所有内容(索引的ã€æ’入的和åˆå¹¶çš„内" +#~ "容)。" + +#~ msgid "Daemon configuration: user account" +#~ msgstr "守护程åºé…置:用户账户" + +#~ msgid "As which user should gnunetd be run?" +#~ msgstr "以什么用户身份è¿è¡Œ gnunetd?" + +#, fuzzy +#~ msgid "" +#~ "For security reasons, it is a good idea to let this setup create a new " +#~ "user account under which the GNUnet service is started at system " +#~ "startup.\n" +#~ "\n" +#~ "However, GNUnet may not be able to access files other than its own. This " +#~ "includes files you want to publish in GNUnet. You'll have to grant read " +#~ "permissions to the user specified below.\n" +#~ "\n" +#~ "Leave the field empty to run GNUnet with system privileges.\n" +#~ msgstr "" +#~ "出于安全考虑,让设置助手创建一个专门用于在系统å¯åŠ¨æ—¶å¯åŠ¨ GNUnet æœåŠ¡çš„账户" +#~ "是个ä¸é”™çš„主æ„。\n" +#~ "\n" +#~ "但是,GNUnet å¯èƒ½æ— æ³•è®¿é—®ä¸å±žäºŽè‡ªå·±è´¦æˆ·çš„文件。这包括您想通过 GNUnet å‘布" +#~ "的文件。您必须对以下用户赋予读æƒé™ã€‚\n" +#~ "\n" +#~ "ä¸å¡«æ­¤å­—段则以系统æƒé™è¿è¡Œ GNUnet。\n" + +#~ msgid "Daemon configuration: group account" +#~ msgstr "守护程åºé…置:组账户" + +#~ msgid "As which group should gnunetd be run?" +#~ msgstr "以什么用户组身份è¿è¡Œ gnunetd?" + +#~ msgid "" +#~ "For security reasons, it is a good idea to let this setup create a new " +#~ "group for the chosen user account.\n" +#~ "\n" +#~ "You can also specify a already existent group here.\n" +#~ "\n" +#~ "Only members of this group will be allowed to start and stop the the " +#~ "GNUnet server and have access to GNUnet server data.\n" +#~ msgstr "" +#~ "出于安全考虑,让设置助手为选择的用户创建一个新组是个ä¸é”™çš„主æ„。\n" +#~ "\n" +#~ "您也å¯ä»¥åœ¨æ­¤æŒ‡å®šä¸€ä¸ªçŽ°æœ‰çš„组。\n" +#~ "\n" +#~ "åªæœ‰è¯¥ç»„çš„æˆå‘˜å¯ä»¥å¯åŠ¨å’Œåœæ­¢ GNUnet æœåŠ¡å™¨å’Œè®¿é—® GNUnet æœåŠ¡å™¨æ•°æ®ã€‚\n" + +#~ msgid "Do you want to automatically launch GNUnet as a system service?" +#~ msgstr "您想将 GNUnet 作为系统æœåŠ¡è‡ªåŠ¨å¯åŠ¨å—?" + +#~ msgid "" +#~ "If you say \"yes\" here, the GNUnet background process will be " +#~ "automatically started when you turn on your computer. If you say \"no\" " +#~ "here, you have to launch GNUnet yourself each time you want to use it." +#~ msgstr "" +#~ "如果您回答“是â€ï¼ŒGNUnet åŽå°è¿›ç¨‹å°†åœ¨å¼€æœºæ—¶è‡ªåŠ¨å¯åŠ¨ã€‚如果您回答“å¦â€ï¼Œåˆ™éœ€è¦" +#~ "在æ¯æ¬¡ä½¿ç”¨ GNUnet 时自己å¯åŠ¨å®ƒã€‚" + +#~ msgid "Unable to setup autostart for daemon." +#~ msgstr "无法将守护进程设置为自动å¯åŠ¨ã€‚" + +#~ msgid "Save configuration?" +#~ msgstr "ä¿å­˜é…置?" + +#~ msgid "GNUnet Configuration" +#~ msgstr "GNUnet é…ç½®" + +#~ msgid "Back" +#~ msgstr "åŽé€€" + +#~ msgid "Exit" +#~ msgstr "退出" + +#~ msgid "Up" +#~ msgstr "å‘上" + +#~ msgid "Cancel" +#~ msgstr "å–消" + +#~ msgid "Internal error! (Value invalid?)" +#~ msgstr "内部错误ï¼(值无效?)" + +#~ msgid "Invalid input, expecting floating point value." +#~ msgstr "无效输入,应为浮点值。" + +#~ msgid "Invalid input, expecting integer." +#~ msgstr "无效输入,应为整数。" + +#~ msgid "Value is not in legal range." +#~ msgstr "值ä¸åœ¨åˆæ³•èŒƒå›´å†…。" + +#~ msgid "Configuration unchanged, no need to save.\n" +#~ msgstr "é…置未更改,无须ä¿å­˜ã€‚\n" + +#~ msgid "Do you wish to save your new configuration?" +#~ msgstr "您想ä¿å­˜æ–°é…ç½®å—?" + +#~ msgid "" +#~ "\n" +#~ "Your configuration changes were NOT saved.\n" +#~ msgstr "" +#~ "\n" +#~ "您的é…置更改没有ä¿å­˜ã€‚\n" + +#~ msgid "list all network adapters" +#~ msgstr "列出所有网络适é…器" + +#~ msgid "install GNUnet as Windows service" +#~ msgstr "以 Windows æœåŠ¡æ–¹å¼å®‰è£… GNUnet" + +#~ msgid "increase the maximum number of TCP/IP connections" +#~ msgstr "增加 TCP/IP 的最大连接数" + +#~ msgid "display a file's hash value" +#~ msgstr "显示一个文件的散列值" + +#~ msgid "GNUnet service installed successfully.\n" +#~ msgstr "GNUnet æœåŠ¡å®‰è£…æˆåŠŸã€‚\n" + +#~ msgid "This version of Windows doesn't support services.\n" +#~ msgstr "此版本的 Windows ä¸æ”¯æŒæœåŠ¡ã€‚\n" + +#~ msgid "Error: can't open Service Control Manager: %s\n" +#~ msgstr "错误:无法打开æœåŠ¡æŽ§åˆ¶ç®¡ç†å™¨ï¼š%s\n" + +#~ msgid "Error: can't create service: %s\n" +#~ msgstr "错误:无法创建æœåŠ¡ï¼š%s\n" + +#~ msgid "Error: can't delete service: %s\n" +#~ msgstr "错误:无法删除æœåŠ¡ï¼š%s\n" + +#~ msgid "Configuration changed. Save?" +#~ msgstr "é…置已更改。ä¿å­˜å—?" + +#~ msgid "Error saving configuration." +#~ msgstr "ä¿å­˜é…置出错。" + +#~ msgid "(unknown connection)" +#~ msgstr "(未知连接)" + +#~ msgid "Do you want to save the new configuration?" +#~ msgstr "您想ä¿å­˜æ–°é…ç½®å—?" + +#~ msgid "Unable to change startup process:" +#~ msgstr "无法更改å¯åŠ¨è¿›ç¨‹ï¼š" + +#~ msgid "" +#~ "Running gnunet-update failed.\n" +#~ "This maybe due to insufficient permissions, please check your " +#~ "configuration.\n" +#~ "Finally, run gnunet-update manually." +#~ msgstr "" +#~ "è¿è¡Œ gnunet-update 失败。\n" +#~ "è¿™å¯èƒ½æ˜¯æƒé™ä¸è¶³é€ æˆçš„,请检查您的é…置。\n" +#~ "最åŽï¼Œæ‰‹åŠ¨è¿è¡Œ gnunet-update。" + +#~ msgid "Can only set one option per invocation.\n" +#~ msgstr "æ¯æ¬¡è°ƒç”¨åªèƒ½è®¾ç½®ä¸€ä¸ªé€‰é¡¹ã€‚\n" + +#~ msgid "" +#~ "Invalid syntax, argument to 'set' must have the format SECTION:" +#~ "OPTION=VALUE.\n" +#~ msgstr "语法无效,“setâ€çš„å‚数必须为 SECTION:OPTION=VALUE çš„æ ¼å¼ã€‚\n" + +#~ msgid "Can only display one option per invocation.\n" +#~ msgstr "æ¯æ¬¡è°ƒç”¨åªèƒ½æ˜¾ç¤ºä¸€ä¸ªé€‰é¡¹ã€‚\n" + +#~ msgid "" +#~ "Invalid syntax, argument to 'get' must have the format SECTION:OPTION.\n" +#~ msgstr "语法无效,“getâ€çš„å‚数必须为 SECTION:OPTION çš„æ ¼å¼ã€‚\n" + +#~ msgid "generate configuration for gnunetd, the GNUnet daemon" +#~ msgstr "为 GNUnet å®ˆæŠ¤ç¨‹åº gnunetd 生æˆé…ç½®" + +#~ msgid "Tool to setup GNUnet." +#~ msgstr "设置 GNUnet 的工具。" + +#~ msgid "Too many arguments.\n" +#~ msgstr "å‚数过多。\n" + +#~ msgid "No interface specified, using default.\n" +#~ msgstr "没有指定接å£ï¼Œå°†ä½¿ç”¨é»˜è®¤ã€‚\n" + +#~ msgid "Configuration file `%s' must be a filename (but is a directory).\n" +#~ msgstr "é…置文件“%sâ€å¿…须是一个文件å(但是一个目录)。\n" + +#~ msgid "Undefined option.\n" +#~ msgstr "未定义的选项。\n" + +#~ msgid "yes" +#~ msgstr "是" + +#~ msgid "no" +#~ msgstr "å¦" + +#~ msgid "\tEnter yes (%s), no (%s) or help (%s): " +#~ msgstr "\t输入 yes (%s)ã€no (%s) 或 help (%s):" + +#~ msgid "\tPossible choices:\n" +#~ msgstr "\tå¯ç”¨é€‰é¡¹ï¼š\n" + +#~ msgid "\tUse single space prefix to avoid conflicts with hotkeys!\n" +#~ msgstr "\t使用一个空格å‰ç¼€æ¥é¿å…与快æ·é”®å†²çªï¼\n" + +#~ msgid "\tEnter string (type '%s' for default value `%s'): " +#~ msgstr "\t输入字符串(输入“%sâ€ä»¥ä½¿ç”¨é»˜è®¤å€¼â€œ%sâ€):" + +#~ msgid "\t Enter choice (default is %c): " +#~ msgstr "\t 输入选择(默认为 %c):" + +#~ msgid "\tEnter floating point (type '%s' for default value %f): " +#~ msgstr "\t输入浮点数(输入“%sâ€ä»¥ä½¿ç”¨é»˜è®¤å€¼ %f):" + +#~ msgid "" +#~ "\tEnter unsigned integer in interval [%llu,%llu] (type '%s' for default " +#~ "value %llu): " +#~ msgstr "\t输入区间 [%llu,%llu] 内的无符å·æ•´æ•°(输入“%sâ€ä»¥ä½¿ç”¨é»˜è®¤å€¼ %llu):" + +#~ msgid "Yes\n" +#~ msgstr "是\n" + +#~ msgid "No\n" +#~ msgstr "å¦\n" + +#~ msgid "Help\n" +#~ msgstr "帮助\n" + +#~ msgid "Abort\n" +#~ msgstr "中止\n" + +#~ msgid "" +#~ "\n" +#~ "Invalid entry, try again (use '?' for help): " +#~ msgstr "" +#~ "\n" +#~ "无效æ¡ç›®ï¼Œè¯·é‡è¯•(使用“?â€èŽ·å–帮助):" + +#~ msgid "Unknown kind %x (internal error). Skipping option.\n" +#~ msgstr "未知的类型 %x (内部错误)。将跳过选项。\n" + +#, fuzzy +#~ msgid "\tDescend? (y/n/?) " +#~ msgstr "\t下é™(y/n/?) " + +#~ msgid "Aborted.\n" +#~ msgstr "已中止。\n" + +#~ msgid "Unknown kind %x (internal error). Aborting.\n" +#~ msgstr "未知的类型 %x (内部错误)。将中止。\n" + +#~ msgid "You can always press ENTER to keep the current value.\n" +#~ msgstr "您å¯ä»¥éšä¾¿æŒ‰ ENTER é”®æ¥ä¿æŒå½“å‰å€¼ã€‚\n" + +#~ msgid "Use the '%s' key to abort.\n" +#~ msgstr "使用“%sâ€é”®æ¥ä¸­æ­¢ã€‚\n" + +#~ msgid "" +#~ "Save configuration? Answer 'y' for yes, 'n' for no, 'r' to repeat " +#~ "configuration. " +#~ msgstr "ä¿å­˜é…置?回答“yâ€è¡¨ç¤ºæ˜¯ï¼Œâ€œnâ€è¡¨ç¤ºå¦ï¼Œâ€œrâ€è¡¨ç¤ºé‡å¤é…置。" + +#~ msgid "Configuration was unchanged, no need to save.\n" +#~ msgstr "é…置未更改,无须ä¿å­˜ã€‚\n" + +#~ msgid "" +#~ "Internal error: entry `%s' in section `%s' not found for visibility " +#~ "change!\n" +#~ msgstr "内部错误:找ä¸åˆ°â€œ%2$sâ€èŠ‚çš„æ¡ç›®â€œ%1$sâ€ä»¥è¿›è¡Œå¯è§†åŒ–更改ï¼\n" + +#~ msgid "Can't open Service Control Manager" +#~ msgstr "无法打开æœåŠ¡æŽ§åˆ¶ç®¡ç†å™¨" + +#~ msgid "Can't create service" +#~ msgstr "无法创建æœåŠ¡" + +#~ msgid "Cannot write to the registry" +#~ msgstr "无法写入该注册表" + +#~ msgid "Can't delete the service" +#~ msgstr "无法删除该æœåŠ¡" + +#~ msgid "This version of Windows does not support multiple users." +#~ msgstr "此版本的 Windows ä¸æ”¯æŒå¤šç”¨æˆ·ã€‚" + +#~ msgid "Error accessing local security policy" +#~ msgstr "访问本地安全策略出错" + +#~ msgid "Error granting service right to user" +#~ msgstr "å‘用户授予æœåŠ¡æƒé™å‡ºé”™" + +#~ msgid "Unknown error while creating a new user" +#~ msgstr "在创建新用户时å‘生未知错误" + +#~ msgid "STATUS" +#~ msgstr "状æ€" + +#~ msgid "FATAL" +#~ msgstr "致命" + +#~ msgid "USER" +#~ msgstr "用户" + +#~ msgid "ADMIN" +#~ msgstr "管ç†å‘˜" + +#~ msgid "DEVELOPER" +#~ msgstr "å¼€å‘者" + +#~ msgid "REQUEST" +#~ msgstr "请求" + +#~ msgid "BULK" +#~ msgstr "批é‡" + +#~ msgid "IMMEDIATE" +#~ msgstr "ç«‹å³" + +#~ msgid "ALL" +#~ msgstr "所有" + +#~ msgid "NOTHING" +#~ msgstr "æ— " + +#~ msgid "Could not find valid value for HOST in section NETWORK.\n" +#~ msgstr "在 NETWORK(网络) 节中找ä¸åˆ° HOST(主机) 的有效值。\n" + +#~ msgid "Syntax error in configuration entry HOST in section NETWORK: `%s'\n" +#~ msgstr "在 NETWORK 节的é…ç½®æ¡ç›® HOST 中有语法错误:“%sâ€\n" + +#~ msgid "Error connecting to %s:%u. Is the daemon running?\n" +#~ msgstr "连接 %s:%u 出错。守护程åºåœ¨è¿è¡Œå—?\n" + +#~ msgid "Reading result from gnunetd failed, reply invalid!\n" +#~ msgstr "从 gnunetd 读å–结果失败,应答无效ï¼\n" + +#~ msgid "" +#~ "Setting option `%s' in section `%s' to `%s' when processing command line " +#~ "option `%s' was denied.\n" +#~ msgstr "" +#~ "在处ç†å‘½ä»¤è¡Œé€‰é¡¹â€œ%4$sâ€æ—¶ï¼Œå°†â€œ%2$sâ€èŠ‚的选项“%1$sâ€è®¾ç½®ä¸ºâ€œ%3$sâ€è¢«æ‹’ç»ã€‚\n" + +#~ msgid "No interface specified in section `%s' under `%s'!\n" +#~ msgstr "“%2$sâ€ä¸‹çš„“%1$sâ€èŠ‚中没有指定接å£ï¼\n" + +#~ msgid "Could not obtain IP for interface `%s' using `%s'.\n" +#~ msgstr "无法利用“%2$sâ€èŽ·å–接å£â€œ%1$sâ€çš„ IP。\n" + +#~ msgid "" +#~ "Could not find interface `%s' using `%s', trying to find another " +#~ "interface.\n" +#~ msgstr "无法利用“%2$sâ€æ‰¾åˆ°æŽ¥å£â€œ%1$sâ€ï¼Œå°è¯•æŸ¥æ‰¾å¦ä¸€ä¸ªæŽ¥å£ã€‚\n" + +#~ msgid "" +#~ "There is more than one IP address specified for interface `%s'.\n" +#~ "GNUnet will use %s.\n" +#~ msgstr "" +#~ "为“%sâ€æŽ¥å£æŒ‡å®šäº†è¶…过一个 IP 地å€ã€‚\n" +#~ "GNUnet 将使用 %s。\n" + +#~ msgid "Received malformed message (too small) from connection. Closing.\n" +#~ msgstr "从连接收到æŸå的消æ¯(过å°)。关闭。\n" + +#, fuzzy +#~ msgid "select listen socket for `%s' not valid!\n" +#~ msgstr "选择“%sâ€çš„监å¬å¥—接字无效ï¼\n" + +#~ msgid "`%s' returned with error code %u" +#~ msgstr "“%sâ€è¿”å›žäº†é”™è¯¯ç  %u" + +#~ msgid "Can't create semaphore: %i" +#~ msgstr "无法创建信å·é‡ï¼š%i" + +#~ msgid "Cannot query the CPU usage (Windows NT).\n" +#~ msgstr "无法查询 CPU 使用率(Windows NT)。\n" + +#~ msgid "Cannot query the CPU usage (Win 9x)\n" +#~ msgstr "无法查询 CPU 使用率(Windows 9x)。\n" + +#~ msgid "Setting open descriptor limit not supported.\n" +#~ msgstr "ä¸æ”¯æŒè®¾ç½®æ‰“å¼€æ述符é™åˆ¶ã€‚\n" + +#~ msgid "Command `%s' failed with error code %u\n" +#~ msgstr "命令“%sâ€å¤±è´¥ï¼Œé”™è¯¯ç  %u\n" + +#~ msgid "Real-time delay violation (%llu ms) at %s:%u\n" +#~ msgstr "实时延迟冲çª(%llu 毫秒),于 %s:%u\n" + +#~ msgid "`%s' failed with error code %d: %s\n" +#~ msgstr "“%sâ€ä»¥é”™è¯¯ç  %d 失败:%s\n" + +#~ msgid "Deadlock due to `%s'.\n" +#~ msgstr "“%sâ€é€ æˆäº†æ­»é”。\n" + +#~ msgid "GNUnet error log" +#~ msgstr "GNUnet 错误日志" + +#, fuzzy +#~ msgid "Out of memory (for logging)\n" +#~ msgstr "(用于日志的)内存耗尽\n" + +#~ msgid "Completed datastore conversion.\n" +#~ msgstr "已完æˆæ•°æ®ä»“库轮æ¢ã€‚\n" + +#~ msgid "" +#~ "%s:%d - RPC %s:%p could not be registered: another callback is already " +#~ "using this name (%p)\n" +#~ msgstr "%s:%d - 无法注册 RPC %s:%p:å¦ä¸€è°ƒç”¨æ­£åœ¨ä½¿ç”¨æ­¤å称(%p)\n" + +#~ msgid "%s:%d - async RPC %s:%p could not be unregistered: not found\n" +#~ msgstr "%s:%d - 异步 RPC %s:%p 无法解除注册:找ä¸åˆ°\n" + +#~ msgid "output in gnuplot format" +#~ msgstr "以 gnuplot æ ¼å¼è¾“出" + +#~ msgid "number of iterations" +#~ msgstr "迭代次数" + +#~ msgid "number of messages to use per iteration" +#~ msgstr "æ¯æ¬¡è¿­ä»£æ‰€ä½¿ç”¨çš„消æ¯æ•°é‡" + +#~ msgid "receiver host identifier (ENC file name)" +#~ msgstr "接收方主机标识(ENC 文件å)" + +#~ msgid "message size" +#~ msgstr "消æ¯å°ºå¯¸" + +#~ msgid "number of messages in a message block" +#~ msgstr "一个消æ¯å—中的消æ¯æ•°é‡" + +#~ msgid "Error establishing connection with gnunetd.\n" +#~ msgstr "通过 gnunetd 建立连接失败。\n" + +#~ msgid "You must specify a receiver!\n" +#~ msgstr "您必须指定一个接收方ï¼\n" + +#~ msgid "Time:\n" +#~ msgstr "时间:\n" + +#~ msgid "\tmax %llums\n" +#~ msgstr "\t最长 %llu毫秒\n" + +#~ msgid "\tmin %llums\n" +#~ msgstr "\t最短 %llu毫秒\n" + +#~ msgid "\tmean %8.4fms\n" +#~ msgstr "\tå¹³å‡ %8.4f毫秒\n" + +#, fuzzy +#~ msgid "\tvariance %8.4fms\n" +#~ msgstr "\t波动 %8.4f毫秒\n" + +#~ msgid "Loss:\n" +#~ msgstr "丢失:\n" + +#~ msgid "\tmax %u\n" +#~ msgstr "\t最多 %u\n" + +#~ msgid "\tmin %u\n" +#~ msgstr "\t最少 %u\n" + +#~ msgid "\tmean %8.4f\n" +#~ msgstr "\tå¹³å‡ %8.4f\n" + +#, fuzzy +#~ msgid "\tvariance %8.4f\n" +#~ msgstr "\t波动 %8.4f\n" + +#~ msgid "Output format not known, this should not happen.\n" +#~ msgstr "输出格å¼æœªçŸ¥ï¼Œä¸åº”出现这ç§æƒ…况。\n" + +#~ msgid "" +#~ "\n" +#~ "Did not receive the message from gnunetd. Is gnunetd running?\n" +#~ msgstr "" +#~ "\n" +#~ "没有从 gnunetd 接收到消æ¯ã€‚gnunetd 在è¿è¡Œå—?\n" + +#~ msgid "" +#~ "Failed to load MySQL database module. Check that MySQL is running and " +#~ "configured properly!\n" +#~ msgstr "加载 MySQL æ•°æ®åº“模å—失败。请检查 MySQL 是å¦è¿è¡Œå’Œæ˜¯å¦é…置正确ï¼\n" + +#, fuzzy +#~ msgid "Command `%s' requires an argument (`%s').\n" +#~ msgstr "%s:选项“%sâ€è¦æ±‚有一个å‚æ•°\n" + +#, fuzzy +#~ msgid "Command `%s' requires two arguments (`%s' and `%s').\n" +#~ msgstr "%s:选项“%sâ€è¦æ±‚有一个å‚æ•°\n" + +#, fuzzy +#~ msgid "Unsupported command `%s'. Aborting.\n" +#~ msgstr "未知的命令“%sâ€ã€‚\n" + +#~ msgid "" +#~ "OS tells us about very large message (%u bytes) pending on UDP socket, " +#~ "truncating at 64k\n" +#~ msgstr "" +#~ "æ“作系统通知,在 UPnP 套接字上有大é‡æ¶ˆæ¯å¾…处ç†(%u 字节),将截短为64k\n" + +#~ msgid "Error while parsing dscl output.\n" +#~ msgstr "è§£æž dscl 输出时出错。\n" + +#~ msgid "" +#~ "Couldn't find a group (`%s') for the new user and none was specified.\n" +#~ msgstr "找ä¸åˆ°æ–°ç”¨æˆ·çš„组(“%sâ€)且没有指定用户组。\n" + +#~ msgid "Failed to find a free system id for the new group.\n" +#~ msgstr "无法为新组找到一个空闲的系统标识。\n" + +#~ msgid "Failed to find a free system id for the new user.\n" +#~ msgstr "无法为新用户找到一个个空闲的系统标识。\n" diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..c3474d5 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,43 @@ +#if WANT_FRAMEWORK +# INTLEMU_SUBDIRS = intlemu +#endif + +if HAVE_EXPERIMENTAL + EXP_DIR = chat dv gns stream +endif + +if LINUX +# All of these currently only work on GNU/Linux + LINUX_DIR = dns exit vpn pt +endif + + +SUBDIRS = \ + include $(INTLEMU_SUBDIRS) \ + util \ + hello \ + tun \ + block \ + statistics \ + arm \ + peerinfo \ + datacache \ + datastore \ + namestore \ + template \ + ats \ + nat \ + fragmentation \ + transport \ + peerinfo-tool \ + core \ + testing \ + nse \ + dht \ + hostlist \ + topology \ + fs \ + mesh \ + $(LINUX_DIR) \ + integration-tests \ + $(EXP_DIR) diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..a819026 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,701 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +#if WANT_FRAMEWORK +# INTLEMU_SUBDIRS = intlemu +#endif +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = include util hello tun block statistics arm peerinfo \ + datacache datastore namestore template ats nat fragmentation \ + transport peerinfo-tool core testing nse dht hostlist topology \ + fs mesh dns exit vpn pt integration-tests chat dv gns stream +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +@HAVE_EXPERIMENTAL_TRUE@EXP_DIR = chat dv gns stream + +# All of these currently only work on GNU/Linux +@LINUX_TRUE@LINUX_DIR = dns exit vpn pt +SUBDIRS = \ + include $(INTLEMU_SUBDIRS) \ + util \ + hello \ + tun \ + block \ + statistics \ + arm \ + peerinfo \ + datacache \ + datastore \ + namestore \ + template \ + ats \ + nat \ + fragmentation \ + transport \ + peerinfo-tool \ + core \ + testing \ + nse \ + dht \ + hostlist \ + topology \ + fs \ + mesh \ + $(LINUX_DIR) \ + integration-tests \ + $(EXP_DIR) + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/arm/Makefile.am b/src/arm/Makefile.am new file mode 100644 index 0000000..7da1e2c --- /dev/null +++ b/src/arm/Makefile.am @@ -0,0 +1,91 @@ +INCLUDES = -I$(top_srcdir)/src/include + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + arm.conf + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +lib_LTLIBRARIES = libgnunetarm.la + +libgnunetarm_la_SOURCES = \ + arm_api.c arm.h +libgnunetarm_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) +libgnunetarm_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 1:1:0 + + +bin_PROGRAMS = \ + gnunet-arm \ + gnunet-service-arm \ + mockup-service + +gnunet_arm_SOURCES = \ + gnunet-arm.c +gnunet_arm_LDADD = \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_arm_DEPENDENCIES = \ + libgnunetarm.la + +gnunet_service_arm_SOURCES = \ + gnunet-service-arm.c +gnunet_service_arm_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_service_arm_DEPENDENCIES = \ + libgnunetarm.la + + +mockup_service_SOURCES = \ + mockup-service.c + mockup_service_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + + +check_PROGRAMS = \ + test_arm_api \ + test_exponential_backoff \ + test_gnunet_service_manager + +check_SCRIPTS = \ + test_gnunet_arm.sh + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +endif + +test_arm_api_SOURCES = \ + test_arm_api.c +test_arm_api_LDADD = \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_exponential_backoff_SOURCES = \ + test_exponential_backoff.c +test_exponential_backoff_LDADD = \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_service_manager_SOURCES = \ + test_gnunet_service_manager.c + test_gnunet_service_manager_LDADD = \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_arm_api_data.conf \ + do_start_process.c \ + $(check_SCRIPTS) diff --git a/src/arm/Makefile.in b/src/arm/Makefile.in new file mode 100644 index 0000000..584cc06 --- /dev/null +++ b/src/arm/Makefile.in @@ -0,0 +1,960 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-arm$(EXEEXT) gnunet-service-arm$(EXEEXT) \ + mockup-service$(EXEEXT) +check_PROGRAMS = test_arm_api$(EXEEXT) \ + test_exponential_backoff$(EXEEXT) \ + test_gnunet_service_manager$(EXEEXT) +subdir = src/arm +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/arm.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = arm.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunetarm_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgnunetarm_la_OBJECTS = arm_api.lo +libgnunetarm_la_OBJECTS = $(am_libgnunetarm_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetarm_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetarm_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_arm_OBJECTS = gnunet-arm.$(OBJEXT) +gnunet_arm_OBJECTS = $(am_gnunet_arm_OBJECTS) +am_gnunet_service_arm_OBJECTS = gnunet-service-arm.$(OBJEXT) +gnunet_service_arm_OBJECTS = $(am_gnunet_service_arm_OBJECTS) +am_mockup_service_OBJECTS = mockup-service.$(OBJEXT) +mockup_service_OBJECTS = $(am_mockup_service_OBJECTS) +mockup_service_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_arm_api_OBJECTS = test_arm_api.$(OBJEXT) +test_arm_api_OBJECTS = $(am_test_arm_api_OBJECTS) +test_arm_api_DEPENDENCIES = $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_exponential_backoff_OBJECTS = \ + test_exponential_backoff.$(OBJEXT) +test_exponential_backoff_OBJECTS = \ + $(am_test_exponential_backoff_OBJECTS) +test_exponential_backoff_DEPENDENCIES = \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_gnunet_service_manager_OBJECTS = \ + test_gnunet_service_manager.$(OBJEXT) +test_gnunet_service_manager_OBJECTS = \ + $(am_test_gnunet_service_manager_OBJECTS) +test_gnunet_service_manager_DEPENDENCIES = \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetarm_la_SOURCES) $(gnunet_arm_SOURCES) \ + $(gnunet_service_arm_SOURCES) $(mockup_service_SOURCES) \ + $(test_arm_api_SOURCES) $(test_exponential_backoff_SOURCES) \ + $(test_gnunet_service_manager_SOURCES) +DIST_SOURCES = $(libgnunetarm_la_SOURCES) $(gnunet_arm_SOURCES) \ + $(gnunet_service_arm_SOURCES) $(mockup_service_SOURCES) \ + $(test_arm_api_SOURCES) $(test_exponential_backoff_SOURCES) \ + $(test_gnunet_service_manager_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + arm.conf + +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +lib_LTLIBRARIES = libgnunetarm.la +libgnunetarm_la_SOURCES = \ + arm_api.c arm.h + +libgnunetarm_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) + +libgnunetarm_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 1:1:0 + +gnunet_arm_SOURCES = \ + gnunet-arm.c + +gnunet_arm_LDADD = \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_arm_DEPENDENCIES = \ + libgnunetarm.la + +gnunet_service_arm_SOURCES = \ + gnunet-service-arm.c + +gnunet_service_arm_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_service_arm_DEPENDENCIES = \ + libgnunetarm.la + +mockup_service_SOURCES = \ + mockup-service.c + +mockup_service_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +check_SCRIPTS = \ + test_gnunet_arm.sh + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +test_arm_api_SOURCES = \ + test_arm_api.c + +test_arm_api_LDADD = \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_exponential_backoff_SOURCES = \ + test_exponential_backoff.c + +test_exponential_backoff_LDADD = \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_service_manager_SOURCES = \ + test_gnunet_service_manager.c + +test_gnunet_service_manager_LDADD = \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_arm_api_data.conf \ + do_start_process.c \ + $(check_SCRIPTS) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/arm/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/arm/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +arm.conf: $(top_builddir)/config.status $(srcdir)/arm.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetarm.la: $(libgnunetarm_la_OBJECTS) $(libgnunetarm_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetarm_la_LINK) -rpath $(libdir) $(libgnunetarm_la_OBJECTS) $(libgnunetarm_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-arm$(EXEEXT): $(gnunet_arm_OBJECTS) $(gnunet_arm_DEPENDENCIES) + @rm -f gnunet-arm$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_arm_OBJECTS) $(gnunet_arm_LDADD) $(LIBS) +gnunet-service-arm$(EXEEXT): $(gnunet_service_arm_OBJECTS) $(gnunet_service_arm_DEPENDENCIES) + @rm -f gnunet-service-arm$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_arm_OBJECTS) $(gnunet_service_arm_LDADD) $(LIBS) +mockup-service$(EXEEXT): $(mockup_service_OBJECTS) $(mockup_service_DEPENDENCIES) + @rm -f mockup-service$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(mockup_service_OBJECTS) $(mockup_service_LDADD) $(LIBS) +test_arm_api$(EXEEXT): $(test_arm_api_OBJECTS) $(test_arm_api_DEPENDENCIES) + @rm -f test_arm_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_arm_api_OBJECTS) $(test_arm_api_LDADD) $(LIBS) +test_exponential_backoff$(EXEEXT): $(test_exponential_backoff_OBJECTS) $(test_exponential_backoff_DEPENDENCIES) + @rm -f test_exponential_backoff$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_exponential_backoff_OBJECTS) $(test_exponential_backoff_LDADD) $(LIBS) +test_gnunet_service_manager$(EXEEXT): $(test_gnunet_service_manager_OBJECTS) $(test_gnunet_service_manager_DEPENDENCIES) + @rm -f test_gnunet_service_manager$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_service_manager_OBJECTS) $(test_gnunet_service_manager_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-arm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-arm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mockup-service.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_arm_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_exponential_backoff.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_service_manager.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/arm/arm.conf.in b/src/arm/arm.conf.in new file mode 100644 index 0000000..c1f408f --- /dev/null +++ b/src/arm/arm.conf.in @@ -0,0 +1,23 @@ + +[arm] +@UNIXONLY@ PORT = 2087 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-arm +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DEFAULTSERVICES = topology hostlist +UNIXPATH = /tmp/gnunet-service-arm.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +# GLOBAL_POSTFIX = -l $SERVICEHOME/{}-logs +# GLOBAL_PREFIX = +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = diff --git a/src/arm/arm.h b/src/arm/arm.h new file mode 100644 index 0000000..4b9da6f --- /dev/null +++ b/src/arm/arm.h @@ -0,0 +1,56 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Christian Grothoff + * @file arm/arm.h + */ +#ifndef ARM_H +#define ARM_H + +#include "gnunet_common.h" + +/** + * This option will turn on the DEBUG loglevel for + * all processes controlled by this ARM! + */ +#define DEBUG_ARM GNUNET_EXTRA_LOGGING + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Reply from ARM to client. + */ +struct GNUNET_ARM_ResultMessage +{ + + /** + * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_RESULT. + */ + struct GNUNET_MessageHeader header; + + /** + * Status from the 'enum GNUNET_ARM_ProcessStatus' + */ + uint32_t status; +}; +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c new file mode 100644 index 0000000..0f4ae6a --- /dev/null +++ b/src/arm/arm_api.c @@ -0,0 +1,681 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file arm/arm_api.c + * @brief API for accessing the ARM service + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_arm_service.h" +#include "gnunet_client_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_server_lib.h" +#include "arm.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "arm-api",__VA_ARGS__) + +/** + * Handle for interacting with ARM. + */ +struct GNUNET_ARM_Handle +{ + + /** + * Our connection to the ARM service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * The configuration that we are using. + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + +}; + + +/** + * Context for handling the shutdown of a service. + */ +struct ShutdownContext +{ + /** + * Connection to the service that is being shutdown. + */ + struct GNUNET_CLIENT_Connection *sock; + + /** + * Time allowed for shutdown to happen. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Task set up to cancel the shutdown request on timeout. + */ + GNUNET_SCHEDULER_TaskIdentifier cancel_task; + + /** + * Task to call once shutdown complete + */ + GNUNET_CLIENT_ShutdownTask cont; + + /** + * Closure for shutdown continuation + */ + void *cont_cls; + + /** + * Result of the operation + */ + enum GNUNET_ARM_ProcessStatus confirmed; + +}; + + +/** + * Handler receiving response to service shutdown requests. + * First call with NULL: service misbehaving, or something. + * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK: + * - service will shutdown + * Second call with NULL: + * - service has now really shut down. + * + * @param cls closure + * @param msg NULL, indicating socket closure. + */ +static void +service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct ShutdownContext *shutdown_ctx = cls; + const struct GNUNET_ARM_ResultMessage *rmsg; + + if (msg == NULL) + { + if (shutdown_ctx->cont != NULL) + { + if (shutdown_ctx->confirmed == GNUNET_ARM_PROCESS_SHUTDOWN) + { + /* shutdown is now complete, as we waited for the network disconnect... */ + shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_DOWN); + } + else + { + /* communication error */ + shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); + } + } + GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); + GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); + GNUNET_free (shutdown_ctx); + return; + } + if (ntohs (msg->size) == + sizeof (struct GNUNET_ARM_ResultMessage)) + { + rmsg = (const struct GNUNET_ARM_ResultMessage*) msg; + shutdown_ctx->confirmed = (enum GNUNET_ARM_ProcessStatus) ntohl (rmsg->status); + if (shutdown_ctx->confirmed != GNUNET_ARM_PROCESS_SHUTDOWN) + { + /* ARM is not shutting down, well, report the error and be done with it... */ + shutdown_ctx->cont (shutdown_ctx->cont_cls, shutdown_ctx->confirmed); + GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); + GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); + GNUNET_free (shutdown_ctx); + return; + } + } + GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, + shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Shutting down took too long, cancel receive and return error. + * + * @param cls closure + * @param tc context information (why was this task triggered now) + */ +static void +service_shutdown_cancel (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ShutdownContext *shutdown_ctx = cls; + + shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT); + GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); + GNUNET_free (shutdown_ctx); +} + + +/** + * If possible, write a shutdown message to the target + * buffer and destroy the client connection. + * + * @param cls the "struct GNUNET_CLIENT_Connection" to destroy + * @param size number of bytes available in buf + * @param buf NULL on error, otherwise target buffer + * @return number of bytes written to buf + */ +static size_t +write_shutdown (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg; + struct ShutdownContext *shutdown_ctx = cls; + + if (size < sizeof (struct GNUNET_MessageHeader)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Failed to transmit shutdown request to client.\n")); + shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); + GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); + GNUNET_free (shutdown_ctx); + return 0; /* client disconnected */ + } + + GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, + shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); + shutdown_ctx->cancel_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (shutdown_ctx->timeout), + &service_shutdown_cancel, shutdown_ctx); + msg = (struct GNUNET_MessageHeader *) buf; + msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + return sizeof (struct GNUNET_MessageHeader); +} + + +/** + * Request that the service should shutdown. + * Afterwards, the connection will automatically be + * disconnected. Hence the "sock" should not + * be used by the caller after this call + * (calling this function frees "sock" after a while). + * + * @param sock the socket connected to the service + * @param timeout how long to wait before giving up on transmission + * @param cont continuation to call once the service is really down + * @param cont_cls closure for continuation + * + */ +static void +arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock, + struct GNUNET_TIME_Relative timeout, + GNUNET_CLIENT_ShutdownTask cont, void *cont_cls) +{ + struct ShutdownContext *shutdown_ctx; + + shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); + shutdown_ctx->cont = cont; + shutdown_ctx->cont_cls = cont_cls; + shutdown_ctx->sock = sock; + shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); + shutdown_ctx->confirmed = GNUNET_ARM_PROCESS_COMMUNICATION_ERROR; + /* FIXME: store return value? */ + GNUNET_CLIENT_notify_transmit_ready (sock, + sizeof (struct GNUNET_MessageHeader), + timeout, GNUNET_YES, &write_shutdown, + shutdown_ctx); +} + + +/** + * Setup a context for communicating with ARM. Note that this + * can be done even if the ARM service is not yet running. + * + * @param cfg configuration to use (needed to contact ARM; + * the ARM service may internally use a different + * configuration to determine how to start the service). + * @param service service that *this* process is implementing/providing, can be NULL + * @return context to use for further ARM operations, NULL on error + */ +struct GNUNET_ARM_Handle * +GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *service) +{ + struct GNUNET_ARM_Handle *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_ARM_Handle)); + ret->cfg = GNUNET_CONFIGURATION_dup (cfg); + return ret; +} + + +/** + * Disconnect from the ARM service. + * + * @param h the handle that was being used + */ +void +GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h) +{ + if (h->client != NULL) + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + GNUNET_CONFIGURATION_destroy (h->cfg); + GNUNET_free (h); +} + + +struct ARM_ShutdownContext +{ + /** + * Callback to call once shutdown complete. + */ + GNUNET_ARM_Callback cb; + + /** + * Closure for callback. + */ + void *cb_cls; +}; + + +/** + * Internal state for a request with ARM. + */ +struct RequestContext +{ + + /** + * Pointer to our handle with ARM. + */ + struct GNUNET_ARM_Handle *h; + + /** + * Function to call with a status code for the requested operation. + */ + GNUNET_ARM_Callback callback; + + /** + * Closure for "callback". + */ + void *cls; + + /** + * Timeout for the operation. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Type of the request expressed as a message type (start or stop). + */ + uint16_t type; + +}; + +#include "do_start_process.c" + + +/** + * A client specifically requested starting of ARM itself. + * This function is called with information about whether + * or not ARM is running; if it is, report success. If + * it is not, start the ARM process. + * + * @param cls the context for the request that we will report on (struct RequestContext*) + * @param tc why were we called (reason says if ARM is running) + */ +static void +arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct RequestContext *pos = cls; + struct GNUNET_OS_Process *proc; + char *binary; + char *config; + char *loprefix; + char *lopostfix; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { +#if DEBUG_ARM + LOG (GNUNET_ERROR_TYPE_DEBUG, "Looks like `%s' is already running.\n", + "gnunet-service-arm"); +#endif + /* arm is running! */ + if (pos->callback != NULL) + pos->callback (pos->cls, GNUNET_ARM_PROCESS_ALREADY_RUNNING); + GNUNET_free (pos); + return; + } +#if DEBUG_ARM + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Looks like `%s' is not running, will start it.\n", + "gnunet-service-arm"); +#endif + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "PREFIX", + &loprefix)) + loprefix = GNUNET_strdup (""); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "OPTIONS", + &lopostfix)) + lopostfix = GNUNET_strdup (""); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "BINARY", + &binary)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _ + ("Configuration failes to specify option `%s' in section `%s'!\n"), + "BINARY", "arm"); + if (pos->callback != NULL) + pos->callback (pos->cls, GNUNET_ARM_PROCESS_UNKNOWN); + GNUNET_free (pos); + GNUNET_free (loprefix); + GNUNET_free (lopostfix); + return; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (pos->h->cfg, "arm", "CONFIG", + &config)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Configuration fails to specify option `%s' in section `%s'!\n"), + "CONFIG", "arm"); + if (pos->callback != NULL) + pos->callback (pos->cls, GNUNET_ARM_PROCESS_UNKNOWN); + GNUNET_free (binary); + GNUNET_free (pos); + GNUNET_free (loprefix); + GNUNET_free (lopostfix); + return; + } + if ((GNUNET_YES == + GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING", "WEAKRANDOM")) + && (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (pos->h->cfg, "TESTING", + "WEAKRANDOM")) + && (GNUNET_NO == + GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING", + "HOSTFILE"))) + { + /* Means we are ONLY running locally */ + /* we're clearly running a test, don't daemonize */ + proc = do_start_process (GNUNET_NO, + NULL, loprefix, binary, "-c", config, +#if DEBUG_ARM + "-L", "DEBUG", +#endif + /* no daemonization! */ + lopostfix, NULL); + } + else + { + proc = do_start_process (GNUNET_NO, + NULL, loprefix, binary, "-c", config, +#if DEBUG_ARM + "-L", "DEBUG", +#endif + "-d", lopostfix, NULL); + } + GNUNET_free (binary); + GNUNET_free (config); + GNUNET_free (loprefix); + GNUNET_free (lopostfix); + if (proc == NULL) + { + if (pos->callback != NULL) + pos->callback (pos->cls, GNUNET_ARM_PROCESS_FAILURE); + GNUNET_free (pos); + return; + } + if (pos->callback != NULL) + pos->callback (pos->cls, GNUNET_ARM_PROCESS_STARTING); + GNUNET_free (proc); + GNUNET_free (pos); +} + + +/** + * Process a response from ARM to a request for a change in service + * status. + * + * @param cls the request context + * @param msg the response + */ +static void +handle_response (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct RequestContext *sc = cls; + const struct GNUNET_ARM_ResultMessage *res; + enum GNUNET_ARM_ProcessStatus status; + + if ((msg == NULL) || + (ntohs (msg->size) != sizeof (struct GNUNET_ARM_ResultMessage))) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _ + ("Error receiving response to `%s' request from ARM for service `%s'\n"), + (sc->type == GNUNET_MESSAGE_TYPE_ARM_START) ? "START" : "STOP", + (const char *) &sc[1]); + GNUNET_CLIENT_disconnect (sc->h->client, GNUNET_NO); + sc->h->client = GNUNET_CLIENT_connect ("arm", sc->h->cfg); + GNUNET_assert (NULL != sc->h->client); + if (sc->callback != NULL) + sc->callback (sc->cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); + GNUNET_free (sc); + return; + } + res = (const struct GNUNET_ARM_ResultMessage *) msg; +#if DEBUG_ARM + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received response from ARM for service `%s': %u\n", + (const char *) &sc[1], ntohs (msg->type)); +#endif + status = (enum GNUNET_ARM_ProcessStatus) ntohl (res->status); + if (sc->callback != NULL) + sc->callback (sc->cls, status); + GNUNET_free (sc); +} + + +/** + * Start or stop a service. + * + * @param h handle to ARM + * @param service_name name of the service + * @param timeout how long to wait before failing for good + * @param cb callback to invoke when service is ready + * @param cb_cls closure for callback + * @param type type of the request + */ +static void +change_service (struct GNUNET_ARM_Handle *h, const char *service_name, + struct GNUNET_TIME_Relative timeout, GNUNET_ARM_Callback cb, + void *cb_cls, uint16_t type) +{ + struct RequestContext *sctx; + size_t slen; + struct GNUNET_MessageHeader *msg; + + slen = strlen (service_name) + 1; + if (slen + sizeof (struct GNUNET_MessageHeader) >= + GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + if (cb != NULL) + cb (cb_cls, GNUNET_NO); + return; + } +#if DEBUG_ARM + LOG (GNUNET_ERROR_TYPE_DEBUG, + (type == + GNUNET_MESSAGE_TYPE_ARM_START) ? + _("Requesting start of service `%s'.\n") : + _("Requesting termination of service `%s'.\n"), service_name); +#endif + sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen); + sctx->h = h; + sctx->callback = cb; + sctx->cls = cb_cls; + sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); + sctx->type = type; + memcpy (&sctx[1], service_name, slen); + msg = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader) + slen); + msg->size = htons (sizeof (struct GNUNET_MessageHeader) + slen); + msg->type = htons (sctx->type); + memcpy (&msg[1], service_name, slen); + if (GNUNET_OK != + GNUNET_CLIENT_transmit_and_get_response (sctx->h->client, msg, + GNUNET_TIME_absolute_get_remaining + (sctx->timeout), GNUNET_YES, + &handle_response, sctx)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + (type == + GNUNET_MESSAGE_TYPE_ARM_START) ? + _("Error while trying to transmit request to start `%s' to ARM\n") + : + _("Error while trying to transmit request to stop `%s' to ARM\n"), + (const char *) &service_name); + if (cb != NULL) + cb (cb_cls, GNUNET_SYSERR); + GNUNET_free (sctx); + GNUNET_free (msg); + return; + } + GNUNET_free (msg); +} + + +/** + * Start a service. + * + * @param h handle to ARM + * @param service_name name of the service + * @param timeout how long to wait before failing for good + * @param cb callback to invoke when service is ready + * @param cb_cls closure for callback + */ +void +GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h, + const char *service_name, + struct GNUNET_TIME_Relative timeout, + GNUNET_ARM_Callback cb, void *cb_cls) +{ + struct RequestContext *sctx; + struct GNUNET_CLIENT_Connection *client; + size_t slen; + +#if DEBUG_ARM + LOG (GNUNET_ERROR_TYPE_DEBUG, + _("Asked to start service `%s' within %llu ms\n"), service_name, + (unsigned long long) timeout.rel_value); +#endif + if (0 == strcasecmp ("arm", service_name)) + { + slen = strlen ("arm") + 1; + sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen); + sctx->h = h; + sctx->callback = cb; + sctx->cls = cb_cls; + sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); + memcpy (&sctx[1], service_name, slen); + GNUNET_CLIENT_service_test ("arm", h->cfg, timeout, &arm_service_report, + sctx); + return; + } + if (h->client == NULL) + { + client = GNUNET_CLIENT_connect ("arm", h->cfg); + if (client == NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "arm_api, GNUNET_CLIENT_connect returned NULL\n"); + cb (cb_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "arm_api, GNUNET_CLIENT_connect returned non-NULL\n"); + h->client = client; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, h->client non-NULL\n"); + change_service (h, service_name, timeout, cb, cb_cls, + GNUNET_MESSAGE_TYPE_ARM_START); +} + + +/** + * Callback from the arm stop service call, indicates that the arm service + * is well and truly dead, won't die, or an error occurred. + * + * @param cls closure for the callback + * @param reason reason for callback + */ +static void +arm_shutdown_callback (void *cls, enum GNUNET_ARM_ProcessStatus reason) +{ + struct ARM_ShutdownContext *arm_shutdown_ctx = cls; + + if (arm_shutdown_ctx->cb != NULL) + arm_shutdown_ctx->cb (arm_shutdown_ctx->cb_cls, reason); + + GNUNET_free (arm_shutdown_ctx); +} + + +/** + * Stop a service. + * + * @param h handle to ARM + * @param service_name name of the service + * @param timeout how long to wait before failing for good + * @param cb callback to invoke when service is ready + * @param cb_cls closure for callback + */ +void +GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, + const char *service_name, + struct GNUNET_TIME_Relative timeout, + GNUNET_ARM_Callback cb, void *cb_cls) +{ + struct ARM_ShutdownContext *arm_shutdown_ctx; + struct GNUNET_CLIENT_Connection *client; + + LOG (GNUNET_ERROR_TYPE_INFO, _("Stopping service `%s' within %llu ms\n"), + service_name, (unsigned long long) timeout.rel_value); + if (h->client == NULL) + { + client = GNUNET_CLIENT_connect ("arm", h->cfg); + if (client == NULL) + { + cb (cb_cls, GNUNET_SYSERR); + return; + } + h->client = client; + } + if (0 == strcasecmp ("arm", service_name)) + { + arm_shutdown_ctx = GNUNET_malloc (sizeof (struct ARM_ShutdownContext)); + arm_shutdown_ctx->cb = cb; + arm_shutdown_ctx->cb_cls = cb_cls; + arm_service_shutdown (h->client, timeout, &arm_shutdown_callback, + arm_shutdown_ctx); + h->client = NULL; + return; + } + change_service (h, service_name, timeout, cb, cb_cls, + GNUNET_MESSAGE_TYPE_ARM_STOP); +} + + +/* end of arm_api.c */ diff --git a/src/arm/do_start_process.c b/src/arm/do_start_process.c new file mode 100644 index 0000000..865ea8e --- /dev/null +++ b/src/arm/do_start_process.c @@ -0,0 +1,104 @@ +/** + * Actually start a process. All of the arguments given to this + * function are strings that are used for the "argv" array. However, + * if those strings contain spaces, the given argument is split into + * multiple argv entries without spaces. Similarly, if an argument is + * the empty string, it is skipped. This function has the inherent + * limitation that it does NOT allow passing command line arguments + * with spaces to the new process. + * + * @param lsocks array of listen sockets to dup starting at fd3 (systemd-style), or NULL + * @param first_arg first argument for argv (may be an empty string) + * @param ... more arguments, NULL terminated + * @return handle of the started process, NULL on error + */ +static struct GNUNET_OS_Process * +do_start_process (int pipe_control, + const SOCKTYPE * lsocks, const char *first_arg, ...) +{ + va_list ap; + char **argv; + unsigned int argv_size; + const char *arg; + const char *rpos; + char *pos; + char *cp; + const char *last; + struct GNUNET_OS_Process *proc; + + argv_size = 1; + va_start (ap, first_arg); + arg = first_arg; + last = NULL; +/* *INDENT-OFF* */ + do + { +/* *INDENT-ON* */ + rpos = arg; + while ('\0' != *rpos) + { + if (' ' == *rpos) + { + if (last != NULL) + argv_size++; + last = NULL; + while (' ' == *rpos) + rpos++; + } + if ((last == NULL) && (*rpos != '\0')) + last = rpos; + if (*rpos != '\0') + rpos++; + } + if (last != NULL) + argv_size++; +/* *INDENT-OFF* */ + } + while (NULL != (arg = (va_arg (ap, const char*)))); +/* *INDENT-ON* */ + va_end (ap); + + argv = GNUNET_malloc (argv_size * sizeof (char *)); + argv_size = 0; + va_start (ap, first_arg); + arg = first_arg; + last = NULL; +/* *INDENT-OFF* */ + do + { +/* *INDENT-ON* */ + cp = GNUNET_strdup (arg); + pos = cp; + while ('\0' != *pos) + { + if (' ' == *pos) + { + *pos = '\0'; + if (last != NULL) + argv[argv_size++] = GNUNET_strdup (last); + last = NULL; + pos++; + while (' ' == *pos) + pos++; + } + if ((last == NULL) && (*pos != '\0')) + last = pos; + if (*pos != '\0') + pos++; + } + if (last != NULL) + argv[argv_size++] = GNUNET_strdup (last); + last = NULL; + GNUNET_free (cp); +/* *INDENT-OFF* */ + } + while (NULL != (arg = (va_arg (ap, const char*)))); +/* *INDENT-ON* */ + va_end (ap); + argv[argv_size] = NULL; + proc = GNUNET_OS_start_process_v (pipe_control, lsocks, argv[0], argv); + while (argv_size > 0) + GNUNET_free (argv[--argv_size]); + GNUNET_free (argv); + return proc; +} diff --git a/src/arm/gnunet-arm.c b/src/arm/gnunet-arm.c new file mode 100644 index 0000000..65700ee --- /dev/null +++ b/src/arm/gnunet-arm.c @@ -0,0 +1,392 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file arm/gnunet-arm.c + * @brief arm for writing a tool + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_arm_service.h" +#include "gnunet_client_lib.h" +#include "gnunet_constants.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_time_lib.h" + +/** + * Timeout for stopping services. Long to give some services a real chance. + */ +#define STOP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1) + +/** + * Timeout for stopping ARM. Extra-long since ARM needs to stop everyone else. + */ +#define STOP_TIMEOUT_ARM GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) + +/** + * Timeout for starting services, very short because of the strange way start works + * (by checking if running before starting, so really this time is always waited on + * startup (annoying)). + */ +#define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * Set if we are to shutdown all services (including ARM). + */ +static int end; + +/** + * Set if we are to start default services (including ARM). + */ +static int start; + +/** + * Set if we are to stop/start default services (including ARM). + */ +static int restart; + +/** + * Set if we should delete configuration and temp directory on exit. + */ +static int delete; + +/** + * Set if we should not print status messages. + */ +static int quiet; + +/** + * Set to the name of a service to start. + */ +static char *init; + +/** + * Set to the name of a service to kill. + */ +static char *term; + +/** + * Set to the name of the config file used. + */ +static const char *config_file; + +/** + * Set to the directory where runtime files are stored. + */ +static char *dir; + +/** + * Final status code. + */ +static int ret; + +/** + * Connection with ARM. + */ +static struct GNUNET_ARM_Handle *h; + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Processing stage that we are in. Simple counter. + */ +static unsigned int phase; + +/** + * User defined timestamp for completing operations. + */ +static struct GNUNET_TIME_Relative timeout; + + +/** + * Main continuation-passing-style loop. Runs the various + * jobs that we've been asked to do in order. + * + * @param cls closure, unused + * @param tc context, unused + */ +static void +cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Callback invoked with the status of the last operation. Reports to the + * user and then runs the next phase in the FSM. + * + * @param cls pointer to "const char*" identifying service that was manipulated + * @param result result of the operation + */ +static void +confirm_cb (void *cls, + enum GNUNET_ARM_ProcessStatus result) +{ + const char *service = cls; + + switch (result) + { + case GNUNET_ARM_PROCESS_UNKNOWN: + FPRINTF (stderr, _("Service `%s' is unknown to ARM.\n"), service); + ret = 1; + break; + case GNUNET_ARM_PROCESS_DOWN: + if (quiet != GNUNET_YES) + FPRINTF (stdout, _("Service `%s' has been stopped.\n"), service); + break; + case GNUNET_ARM_PROCESS_ALREADY_RUNNING: + FPRINTF (stderr, _("Service `%s' was already running.\n"), service); + ret = 1; + break; + case GNUNET_ARM_PROCESS_STARTING: + if (quiet != GNUNET_YES) + FPRINTF (stdout, _("Service `%s' has been started.\n"), service); + break; + case GNUNET_ARM_PROCESS_ALREADY_STOPPING: + FPRINTF (stderr, _("Service `%s' was already being stopped.\n"), service); + ret = 1; + break; + case GNUNET_ARM_PROCESS_ALREADY_DOWN: + FPRINTF (stderr, _("Service `%s' was already not running.\n"), service); + ret = 1; + break; + case GNUNET_ARM_PROCESS_SHUTDOWN: + FPRINTF (stderr, "%s", _("Request ignored as ARM is shutting down.\n")); + ret = 1; + break; + case GNUNET_ARM_PROCESS_COMMUNICATION_ERROR: + FPRINTF (stderr, "%s", _("Error communicating with ARM service.\n")); + ret = 1; + break; + case GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT: + FPRINTF (stderr, "%s", _("Timeout communicating with ARM service.\n")); + ret = 1; + break; + case GNUNET_ARM_PROCESS_FAILURE: + FPRINTF (stderr, "%s", _("Operation failed.\n")); + ret = 1; + break; + default: + FPRINTF (stderr, "%s", _("Unknown response code from ARM.\n")); + break; + } + GNUNET_SCHEDULER_add_continuation (&cps_loop, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + config_file = cfgfile; + if (GNUNET_CONFIGURATION_get_value_string + (cfg, "PATHS", "SERVICEHOME", &dir) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Fatal configuration error: `%s' option in section `%s' missing.\n"), + "SERVICEHOME", "PATHS"); + return; + } + h = GNUNET_ARM_connect (cfg, NULL); + if (h == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Fatal error initializing ARM API.\n")); + ret = 1; + return; + } + GNUNET_SCHEDULER_add_continuation (&cps_loop, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + +/** + * Attempts to delete configuration file and SERVICEHOME + * on arm shutdown provided the end and delete options + * were specified when gnunet-arm was run. + */ +static void +delete_files () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Will attempt to remove configuration file %s and service directory %s\n", + config_file, dir); + + if (UNLINK (config_file) != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to remove configuration file %s\n"), config_file); + } + + if (GNUNET_DISK_directory_remove (dir) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to remove servicehome directory %s\n"), dir); + + } +} + +/** + * Main continuation-passing-style loop. Runs the various + * jobs that we've been asked to do in order. + * + * @param cls closure, unused + * @param tc context, unused + */ +static void +cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + while (1) + { + switch (phase++) + { + case 0: + if (term != NULL) + { + GNUNET_ARM_stop_service (h, term, + (0 == + timeout.rel_value) ? STOP_TIMEOUT : + timeout, &confirm_cb, term); + return; + } + break; + case 1: + if ((end) || (restart)) + { + GNUNET_ARM_stop_service (h, "arm", + (0 == + timeout.rel_value) ? STOP_TIMEOUT_ARM + : timeout, &confirm_cb, "arm"); + return; + } + break; + case 2: + if (start) + { + GNUNET_ARM_start_service (h, "arm", + (0 == + timeout.rel_value) ? START_TIMEOUT : + timeout, &confirm_cb, "arm"); + return; + } + break; + case 3: + if (init != NULL) + { + GNUNET_ARM_start_service (h, init, + (0 == + timeout.rel_value) ? START_TIMEOUT : + timeout, &confirm_cb, init); + return; + } + break; + case 4: + if (restart) + { + GNUNET_ARM_disconnect (h); + phase = 0; + end = 0; + start = 1; + restart = 0; + h = GNUNET_ARM_connect (cfg, NULL); + if (h == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Fatal error initializing ARM API.\n")); + ret = 1; + return; + } + GNUNET_SCHEDULER_add_now (&cps_loop, NULL); + return; + } + /* Fall through */ + default: /* last phase */ + GNUNET_ARM_disconnect (h); + if ((end == GNUNET_YES) && (delete == GNUNET_YES)) + delete_files (); + return; + } + } +} + + +/** + * The main function to obtain arm from gnunetd. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static unsigned long long temp_timeout_ms; + + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'e', "end", NULL, gettext_noop ("stop all GNUnet services"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &end}, + {'i', "init", "SERVICE", gettext_noop ("start a particular service"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &init}, + {'k', "kill", "SERVICE", gettext_noop ("stop a particular service"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &term}, + {'s', "start", NULL, gettext_noop ("start all GNUnet default services"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &start}, + {'r', "restart", NULL, + gettext_noop ("stop and start all GNUnet default services"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &restart}, + {'d', "delete", NULL, + gettext_noop ("delete config file and directory on exit"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &delete}, + {'q', "quiet", NULL, gettext_noop ("don't print status messages"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &quiet}, + {'T', "timeout", NULL, + gettext_noop ("timeout for completing current operation"), + GNUNET_YES, &GNUNET_GETOPT_set_ulong, &temp_timeout_ms}, + GNUNET_GETOPT_OPTION_END + }; + + if (temp_timeout_ms > 0) + timeout.rel_value = temp_timeout_ms; + + if (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-arm", + gettext_noop + ("Control services and the Automated Restart Manager (ARM)"), + options, &run, NULL)) + { + return ret; + } + + return 1; +} + +/* end of gnunet-arm.c */ diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c new file mode 100644 index 0000000..f4430ed --- /dev/null +++ b/src/arm/gnunet-service-arm.c @@ -0,0 +1,1228 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file arm/gnunet-service-arm.c + * @brief the automated restart manager service + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_protocols.h" +#include "arm.h" + +/** + * Threshold after which exponential backoff shouldn't increase (in ms); 30m + */ +#define EXPONENTIAL_BACKOFF_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) + + +/** + * List of our services. + */ +struct ServiceList; + + +/** + * Record with information about a listen socket we have open. + */ +struct ServiceListeningInfo +{ + /** + * This is a linked list. + */ + struct ServiceListeningInfo *next; + + /** + * This is a linked list. + */ + struct ServiceListeningInfo *prev; + + /** + * Address this socket is listening on. + */ + struct sockaddr *service_addr; + + /** + * Service this listen socket is for. + */ + struct ServiceList *sl; + + /** + * Number of bytes in 'service_addr' + */ + socklen_t service_addr_len; + + /** + * Our listening socket. + */ + struct GNUNET_NETWORK_Handle *listen_socket; + + /** + * Task doing the accepting. + */ + GNUNET_SCHEDULER_TaskIdentifier accept_task; + +}; + + +/** + * List of our services. + */ +struct ServiceList +{ + /** + * This is a doubly-linked list. + */ + struct ServiceList *next; + + /** + * This is a doubly-linked list. + */ + struct ServiceList *prev; + + /** + * Linked list of listen sockets associated with this service. + */ + struct ServiceListeningInfo *listen_head; + + /** + * Linked list of listen sockets associated with this service. + */ + struct ServiceListeningInfo *listen_tail; + + /** + * Name of the service. + */ + char *name; + + /** + * Name of the binary used. + */ + char *binary; + + /** + * Name of the configuration file used. + */ + char *config; + + /** + * Client to notify upon kill completion (waitpid), NULL + * if we should simply restart the process. + */ + struct GNUNET_SERVER_Client *killing_client; + + /** + * Process structure pointer of the child. + */ + struct GNUNET_OS_Process *proc; + + /** + * Process exponential backoff time + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Absolute time at which the process is scheduled to restart in case of death + */ + struct GNUNET_TIME_Absolute restart_at; + + /** + * Is this service to be started by default (or did a client tell us explicitly + * to start it)? GNUNET_NO if the service is started only upon 'accept' on a + * listen socket or possibly explicitly by a client changing the value. + */ + int is_default; + + /** + * Should we use pipes to signal this process? (YES for Java binaries and if we + * are on Windoze). + */ + int pipe_control; +}; + +/** + * List of running services. + */ +static struct ServiceList *running_head; + +/** + * List of running services. + */ +static struct ServiceList *running_tail; + +/** + * Our configuration + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Command to prepend to each actual command. + */ +static char *prefix_command; + +/** + * Option to append to each actual command. + */ +static char *final_option; + +/** + * ID of task called whenever we get a SIGCHILD. + */ +static GNUNET_SCHEDULER_TaskIdentifier child_death_task; + +/** + * ID of task called whenever the timeout for restarting a child + * expires. + */ +static GNUNET_SCHEDULER_TaskIdentifier child_restart_task; + +/** + * Pipe used to communicate shutdown via signal. + */ +static struct GNUNET_DISK_PipeHandle *sigpipe; + +/** + * Are we in shutdown mode? + */ +static int in_shutdown; + +/** + * Handle to our server instance. Our server is a bit special in that + * its service is not immediately stopped once we get a shutdown + * request (since we need to continue service until all of our child + * processes are dead). This handle is used to shut down the server + * (and thus trigger process termination) once all child processes are + * also dead. A special option in the ARM configuration modifies the + * behaviour of the service implementation to not do the shutdown + * immediately. + */ +static struct GNUNET_SERVER_Handle *server; + + +#include "do_start_process.c" + + +/** + * Actually start the process for the given service. + * + * @param sl identifies service to start + */ +static void +start_process (struct ServiceList *sl) +{ + char *loprefix; + char *options; + char *optpos; + char *optend; + const char *next; + int use_debug; + char b; + char *val; + struct ServiceListeningInfo *sli; + SOCKTYPE *lsocks; + unsigned int ls; + + /* calculate listen socket list */ + lsocks = NULL; + ls = 0; + for (sli = sl->listen_head; NULL != sli; sli = sli->next) + { + GNUNET_array_append (lsocks, ls, + GNUNET_NETWORK_get_fd (sli->listen_socket)); + if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (sli->accept_task); + sli->accept_task = GNUNET_SCHEDULER_NO_TASK; + } + } +#if WINDOWS + GNUNET_array_append (lsocks, ls, INVALID_SOCKET); +#else + GNUNET_array_append (lsocks, ls, -1); +#endif + + /* obtain configuration */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX", + &loprefix)) + loprefix = GNUNET_strdup (prefix_command); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS", + &options)) + { + options = GNUNET_strdup (final_option); + if (NULL == strstr (options, "%")) + { + /* replace '{}' with service name */ + while (NULL != (optpos = strstr (options, "{}"))) + { + optpos[0] = '%'; + optpos[1] = 's'; + GNUNET_asprintf (&optpos, options, sl->name); + GNUNET_free (options); + options = optpos; + } + /* replace '$PATH' with value associated with "PATH" */ + while (NULL != (optpos = strstr (options, "$"))) + { + optend = optpos + 1; + while (isupper ((unsigned char) *optend)) + optend++; + b = *optend; + if ('\0' == b) + next = ""; + else + next = optend + 1; + *optend = '\0'; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", + optpos + 1, &val)) + val = GNUNET_strdup (""); + *optpos = '\0'; + GNUNET_asprintf (&optpos, "%s%s%c%s", options, val, b, next); + GNUNET_free (options); + GNUNET_free (val); + options = optpos; + } + } + } + use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG"); + + /* actually start process */ +#if DEBUG_ARM + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting service `%s' using binary `%s' and configuration `%s'\n", + sl->name, sl->binary, sl->config); +#endif + GNUNET_assert (NULL == sl->proc); + if (GNUNET_YES == use_debug) + sl->proc = + do_start_process (sl->pipe_control, + lsocks, loprefix, sl->binary, "-c", sl->config, "-L", + "DEBUG", options, NULL); + else + sl->proc = + do_start_process (sl->pipe_control, + lsocks, loprefix, sl->binary, "-c", sl->config, + options, NULL); + if (sl->proc == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"), + sl->name); + else + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"), + sl->name); + /* clean up */ + GNUNET_free (loprefix); + GNUNET_free (options); + GNUNET_array_grow (lsocks, ls, 0); +} + + +/** + * Transmit a status result message. + * + * @param cls pointer to "unit16_t*" with message type + * @param size number of bytes available in buf + * @param buf where to copy the message, NULL on error + * @return number of bytes copied to buf + */ +static size_t +write_result (void *cls, size_t size, void *buf) +{ + enum GNUNET_ARM_ProcessStatus *res = cls; + struct GNUNET_ARM_ResultMessage *msg; + + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Could not send status result to client\n")); + return 0; /* error, not much we can do */ + } +#if DEBUG_ARM + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending status response %u to client\n", (unsigned int) *res); +#endif + GNUNET_assert (size >= sizeof (struct GNUNET_ARM_ResultMessage)); + msg = buf; + msg->header.size = htons (sizeof (struct GNUNET_ARM_ResultMessage)); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_RESULT); + msg->status = htonl ((uint32_t) (*res)); + GNUNET_free (res); + return sizeof (struct GNUNET_ARM_ResultMessage); +} + + +/** + * Signal our client that we will start or stop the + * service. + * + * @param client who is being signalled + * @param name name of the service + * @param result message type to send + * @return NULL if it was not found + */ +static void +signal_result (struct GNUNET_SERVER_Client *client, const char *name, + enum GNUNET_ARM_ProcessStatus result) +{ + enum GNUNET_ARM_ProcessStatus *res; + + if (NULL == client) + return; + /* FIXME: this is not super-clean yet... */ + res = GNUNET_malloc (sizeof (enum GNUNET_ARM_ProcessStatus)); + *res = result; + GNUNET_SERVER_notify_transmit_ready (client, + sizeof (struct + GNUNET_ARM_ResultMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + &write_result, res); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Find the process with the given service + * name in the given list and return it. + * + * @param name which service entry to look up + * @return NULL if it was not found + */ +static struct ServiceList * +find_service (const char *name) +{ + struct ServiceList *sl; + + sl = running_head; + while (sl != NULL) + { + if (0 == strcasecmp (sl->name, name)) + return sl; + sl = sl->next; + } + return NULL; +} + + +/** + * First connection has come to the listening socket associated with the service, + * create the service in order to relay the incoming connection to it + * + * @param cls callback data, struct ServiceListeningInfo describing a listen socket + * @param tc context + */ +static void +accept_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ServiceListeningInfo *sli = cls; + struct ServiceList *sl = sli->sl; + + sli->accept_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + return; + start_process (sl); +} + + +/** + * Creating a listening socket for each of the service's addresses and + * wait for the first incoming connection to it + * + * @param sa address associated with the service + * @param addr_len length of sa + * @param sl service entry for the service in question + */ +static void +create_listen_socket (struct sockaddr *sa, socklen_t addr_len, + struct ServiceList *sl) +{ + const static int on = 1; + struct GNUNET_NETWORK_Handle *sock; + struct ServiceListeningInfo *sli; + + switch (sa->sa_family) + { + case AF_INET: + sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0); + break; + case AF_INET6: + sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); + break; + case AF_UNIX: + if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */ + return; + sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); + break; + default: + GNUNET_break (0); + sock = NULL; + errno = EAFNOSUPPORT; + break; + } + if (NULL == sock) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unable to create socket for service `%s': %s\n"), + sl->name, STRERROR (errno)); + GNUNET_free (sa); + return; + } + if (GNUNET_NETWORK_socket_setsockopt + (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "setsockopt"); +#ifdef IPV6_V6ONLY + if ((sa->sa_family == AF_INET6) && + (GNUNET_NETWORK_socket_setsockopt + (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "setsockopt"); +#endif + + if (GNUNET_NETWORK_socket_bind + (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Unable to bind listening socket for service `%s' to address `%s': %s\n"), + sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno)); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); + GNUNET_free (sa); + return; + } + if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen"); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); + GNUNET_free (sa); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("ARM now monitors connections to service `%s' at `%s'\n"), + sl->name, GNUNET_a2s (sa, addr_len)); + sli = GNUNET_malloc (sizeof (struct ServiceListeningInfo)); + sli->service_addr = sa; + sli->service_addr_len = addr_len; + sli->listen_socket = sock; + sli->sl = sl; + sli->accept_task = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock, + &accept_connection, sli); + GNUNET_CONTAINER_DLL_insert (sl->listen_head, sl->listen_tail, sli); +} + + +/** + * Remove and free an entry in the service list. Listen sockets + * must have already been cleaned up. Only to be called during shutdown. + * + * @param sl entry to free + */ +static void +free_service (struct ServiceList *sl) +{ + GNUNET_assert (GNUNET_YES == in_shutdown); + GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl); + GNUNET_assert (NULL == sl->listen_head); + GNUNET_free_non_null (sl->config); + GNUNET_free_non_null (sl->binary); + GNUNET_free (sl->name); + GNUNET_free (sl); +} + + +/** + * Handle START-message. + * + * @param cls closure (always NULL) + * @param client identification of the client + * @param message the actual message + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static void +handle_start (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const char *servicename; + struct ServiceList *sl; + uint16_t size; + + size = ntohs (message->size); + size -= sizeof (struct GNUNET_MessageHeader); + servicename = (const char *) &message[1]; + if ((size == 0) || (servicename[size - 1] != '\0')) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if (GNUNET_YES == in_shutdown) + { + signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN); + return; + } + sl = find_service (servicename); + if (NULL == sl) + { + signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN); + return; + } + sl->is_default = GNUNET_YES; + if (sl->proc != NULL) + { + signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_RUNNING); + return; + } + start_process (sl); + signal_result (client, servicename, GNUNET_ARM_PROCESS_STARTING); +} + + +/** + * Handle STOP-message. + * + * @param cls closure (always NULL) + * @param client identification of the client + * @param message the actual message + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static void +handle_stop (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct ServiceList *sl; + const char *servicename; + uint16_t size; + + size = ntohs (message->size); + size -= sizeof (struct GNUNET_MessageHeader); + servicename = (const char *) &message[1]; + if ((size == 0) || (servicename[size - 1] != '\0')) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Preparing to stop `%s'\n"), servicename); + sl = find_service (servicename); + if (sl == NULL) + { + signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN); + return; + } + sl->is_default = GNUNET_NO; + if (GNUNET_YES == in_shutdown) + { + /* shutdown in progress */ + signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN); + return; + } + if (sl->killing_client != NULL) + { + /* killing already in progress */ + signal_result (client, servicename, + GNUNET_ARM_PROCESS_ALREADY_STOPPING); + return; + } + if (sl->proc == NULL) + { + /* process is down */ + signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_DOWN); + return; + } +#if DEBUG_ARM + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending kill signal to service `%s', waiting for process to die.\n", + servicename); +#endif + if (0 != GNUNET_OS_process_kill (sl->proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + sl->killing_client = client; + GNUNET_SERVER_client_keep (client); +} + + +/** + * We are done with everything. Stop remaining + * tasks, signal handler and the server. + */ +static void +do_shutdown () +{ + if (NULL != server) + { + GNUNET_SERVER_destroy (server); + server = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != child_death_task) + { + GNUNET_SCHEDULER_cancel (child_death_task); + child_death_task = GNUNET_SCHEDULER_NO_TASK; + } +} + + +/** + * Task run for shutdown. + * + * @param cls closure, NULL if we need to self-restart + * @param tc context + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ServiceList *pos; + struct ServiceList *nxt; + struct ServiceListeningInfo *sli; + + if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) + { + GNUNET_SCHEDULER_cancel (child_restart_task); + child_restart_task = GNUNET_SCHEDULER_NO_TASK; + } + in_shutdown = GNUNET_YES; + /* first, stop listening */ + for (pos = running_head; NULL != pos; pos = pos->next) + { + while (NULL != (sli = pos->listen_head)) + { + GNUNET_CONTAINER_DLL_remove (pos->listen_head, + pos->listen_tail, sli); + if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (sli->accept_task); + sli->accept_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (sli->listen_socket)); + GNUNET_free (sli->service_addr); + GNUNET_free (sli); + } + } + /* then, shutdown all existing service processes */ + nxt = running_head; + while (NULL != (pos = nxt)) + { + nxt = pos->next; + if (pos->proc != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n", + pos->name); + if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + } + else + { + free_service (pos); + } + } + /* finally, should all service processes be already gone, terminate for real */ + if (running_head == NULL) + do_shutdown (); +} + + +/** + * Task run whenever it is time to restart a child that died. + * + * @param cls closure, always NULL + * @param tc context + */ +static void +delayed_restart_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ServiceList *sl; + struct GNUNET_TIME_Relative lowestRestartDelay; + struct ServiceListeningInfo *sli; + + child_restart_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + GNUNET_assert (GNUNET_NO == in_shutdown); + lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL; + + /* check for services that need to be restarted due to + * configuration changes or because the last restart failed */ + for (sl = running_head; NULL != sl; sl = sl->next) + { + if (sl->proc == NULL) + { + /* service is currently not running */ + if (GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value == + 0) + { + /* restart is now allowed */ + if (sl->is_default) + { + /* process should run by default, start immediately */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Restarting service `%s'.\n"), sl->name); + start_process (sl); + } + else + { + /* process is run on-demand, ensure it is re-started if there is demand */ + for (sli = sl->listen_head; NULL != sli; sli = sli->next) + if (GNUNET_SCHEDULER_NO_TASK == sli->accept_task) + { + /* accept was actually paused, so start it again */ + sli->accept_task = + GNUNET_SCHEDULER_add_read_net + (GNUNET_TIME_UNIT_FOREVER_REL, sli->listen_socket, + &accept_connection, sli); + } + } + } + else + { + /* update calculation for earliest time to reactivate a service */ + lowestRestartDelay = + GNUNET_TIME_relative_min (lowestRestartDelay, + GNUNET_TIME_absolute_get_remaining + (sl->restart_at)); + } + } + } + if (lowestRestartDelay.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) + { +#if DEBUG_ARM + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Will restart process in %llums\n", + (unsigned long long) lowestRestartDelay.rel_value); +#endif + child_restart_task = + GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay, + GNUNET_SCHEDULER_PRIORITY_IDLE, + &delayed_restart_task, NULL); + } +} + + +/** + * Task triggered whenever we receive a SIGCHLD (child + * process died). + * + * @param cls closure, NULL if we need to self-restart + * @param tc context + */ +static void +maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ServiceList *pos; + struct ServiceList *next; + struct ServiceListeningInfo *sli; + const char *statstr; + int statcode; + int ret; + char c[16]; + enum GNUNET_OS_ProcessStatusType statusType; + unsigned long statusCode; + const struct GNUNET_DISK_FileHandle *pr; + + pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); + child_death_task = GNUNET_SCHEDULER_NO_TASK; + if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) + { + /* shutdown scheduled us, ignore! */ + child_death_task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + pr, &maint_child_death, NULL); + return; + } + /* consume the signal */ + GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c))); + + /* check for services that died (WAITPID) */ + next = running_head; + while (NULL != (pos = next)) + { + next = pos->next; + + if (pos->proc == NULL) + { + if (GNUNET_YES == in_shutdown) + free_service (pos); + continue; + } + if ((GNUNET_SYSERR == + (ret = + GNUNET_OS_process_status (pos->proc, &statusType, &statusCode))) + || ((ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED) + || (statusType == GNUNET_OS_PROCESS_RUNNING))) + continue; + if (statusType == GNUNET_OS_PROCESS_EXITED) + { + statstr = _( /* process termination method */ "exit"); + statcode = statusCode; + } + else if (statusType == GNUNET_OS_PROCESS_SIGNALED) + { + statstr = _( /* process termination method */ "signal"); + statcode = statusCode; + } + else + { + statstr = _( /* process termination method */ "unknown"); + statcode = 0; + } + GNUNET_OS_process_close (pos->proc); + pos->proc = NULL; + if (NULL != pos->killing_client) + { + signal_result (pos->killing_client, pos->name, + GNUNET_ARM_PROCESS_DOWN); + GNUNET_SERVER_client_drop (pos->killing_client); + pos->killing_client = NULL; + /* process can still be re-started on-demand, ensure it is re-started if there is demand */ + for (sli = pos->listen_head; NULL != sli; sli = sli->next) + { + GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task); + sli->accept_task = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + sli->listen_socket, + &accept_connection, sli); + } + continue; + } + if (GNUNET_YES != in_shutdown) + { + if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0)) + { + /* process terminated normally, allow restart at any time */ + pos->restart_at.abs_value = 0; + } + else + { + if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Service `%s' terminated with status %s/%d, will restart in %llu ms\n"), + pos->name, statstr, statcode, pos->backoff.rel_value); + /* schedule restart */ + pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff); + pos->backoff = + GNUNET_TIME_relative_min (EXPONENTIAL_BACKOFF_THRESHOLD, + GNUNET_TIME_relative_multiply + (pos->backoff, 2)); + } + if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) + GNUNET_SCHEDULER_cancel (child_restart_task); + child_restart_task = + GNUNET_SCHEDULER_add_with_priority + (GNUNET_SCHEDULER_PRIORITY_IDLE, + &delayed_restart_task, NULL); + } + else + { + free_service (pos); + } + } + child_death_task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + pr, &maint_child_death, NULL); + if ((NULL == running_head) && (GNUNET_YES == in_shutdown)) + do_shutdown (); +} + + +/** + * Transmit our shutdown acknowledgement to the client. + * + * @param cls the 'struct GNUNET_SERVER_Client' + * @param size number of bytes available in buf + * @param buf where to write the message + * @return number of bytes written + */ +static size_t +transmit_shutdown_ack (void *cls, size_t size, void *buf) +{ + struct GNUNET_SERVER_Client *client = cls; + struct GNUNET_ARM_ResultMessage *msg; + + if (size < sizeof (struct GNUNET_ARM_ResultMessage)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Failed to transmit shutdown ACK.\n")); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return 0; /* client disconnected */ + } + /* Make the connection flushing for the purpose of ACK transmitting, + * needed on W32 to ensure that the message is even received, harmless + * on other platforms... */ + GNUNET_break (GNUNET_OK == GNUNET_SERVER_client_disable_corking (client)); + msg = (struct GNUNET_ARM_ResultMessage *) buf; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_RESULT); + msg->header.size = htons (sizeof (struct GNUNET_ARM_ResultMessage)); + msg->status = htonl ((uint32_t) GNUNET_ARM_PROCESS_SHUTDOWN); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + GNUNET_SERVER_client_drop (client); + return sizeof (struct GNUNET_ARM_ResultMessage); +} + + +/** + * Handler for SHUTDOWN message. + * + * @param cls closure (refers to service) + * @param client identification of the client + * @param message the actual message + */ +static void +handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + GNUNET_SCHEDULER_shutdown (); + GNUNET_SERVER_client_keep (client); + GNUNET_SERVER_notify_transmit_ready (client, + sizeof (struct GNUNET_ARM_ResultMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_shutdown_ack, client); + GNUNET_SERVER_client_persist_ (client); +} + + +/** + * Signal handler called for SIGCHLD. Triggers the + * respective handler by writing to the trigger pipe. + */ +static void +sighandler_child_death () +{ + static char c; + int old_errno = errno; /* back-up errno */ + + GNUNET_break (1 == + GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle + (sigpipe, GNUNET_DISK_PIPE_END_WRITE), + &c, sizeof (c))); + errno = old_errno; /* restore errno */ +} + + +/** + * Setup our service record for the given section in the configuration file + * (assuming the section is for a service). + * + * @param cls unused + * @param section a section in the configuration file + * @return GNUNET_OK (continue) + */ +static void +setup_service (void *cls, const char *section) +{ + struct ServiceList *sl; + char *binary; + char *config; + struct stat sbuf; + struct sockaddr **addrs; + socklen_t *addr_lens; + int ret; + unsigned int i; + + if (strcasecmp (section, "arm") == 0) + return; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary)) + { + /* not a service section */ + return; + } + sl = find_service (section); + if (NULL != sl) + { + /* got the same section twice!? */ + GNUNET_break (0); + return; + } + config = NULL; + if ((GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, section, "CONFIG", + &config)) || + (0 != STAT (config, &sbuf))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Configuration file `%s' for service `%s' not valid: %s\n"), + config, section, + (config == NULL) ? _("option missing") : STRERROR (errno)); + GNUNET_free (binary); + GNUNET_free_non_null (config); + return; + } + sl = GNUNET_malloc (sizeof (struct ServiceList)); + sl->name = GNUNET_strdup (section); + sl->binary = binary; + sl->config = config; + sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS; + sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS; +#if WINDOWS + sl->pipe_control = GNUNET_YES; +#else + if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL")) + sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL"); +#endif + GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl); + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART")) + return; + if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg, + &addrs, &addr_lens))) + return; + /* this will free (or capture) addrs[i] */ + for (i = 0; i < ret; i++) + create_listen_socket (addrs[i], addr_lens[i], sl); + GNUNET_free (addrs); + GNUNET_free (addr_lens); +} + + +/** + * Process arm requests. + * + * @param cls closure + * @param serv the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *serv, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0}, + {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0}, + {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN, + sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} + }; + char *defaultservices; + const char *pos; + struct ServiceList *sl; + + cfg = c; + server = serv; + GNUNET_assert (serv != NULL); + GNUNET_SERVER_ignore_shutdown (serv, GNUNET_YES); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + child_death_task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_DISK_pipe_handle (sigpipe, + GNUNET_DISK_PIPE_END_READ), + &maint_child_death, NULL); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_PREFIX", + &prefix_command)) + prefix_command = GNUNET_strdup (""); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX", + &final_option)) + final_option = GNUNET_strdup (""); + + GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL); + + /* start default services... */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "DEFAULTSERVICES", + &defaultservices)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Starting default services `%s'\n"), defaultservices); + if (0 < strlen (defaultservices)) + { + for (pos = strtok (defaultservices, " "); NULL != pos; + pos = strtok (NULL, " ")) + { + sl = find_service (pos); + if (NULL == sl) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Default service `%s' not configured correctly!\n"), + pos); + continue; + } + sl->is_default = GNUNET_YES; + start_process (sl); + } + } + GNUNET_free (defaultservices); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("No default services configured, GNUnet will not really start right now.\n")); + } + + /* process client requests */ + GNUNET_SERVER_add_handlers (server, handlers); +} + + +/** + * The main function for the arm service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + int ret; + struct GNUNET_SIGNAL_Context *shc_chld; + + sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); + GNUNET_assert (sigpipe != NULL); + shc_chld = + GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); + ret = + (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "arm", GNUNET_YES, &run, NULL)) ? 0 : 1; + GNUNET_SIGNAL_handler_uninstall (shc_chld); + shc_chld = NULL; + GNUNET_DISK_pipe_close (sigpipe); + sigpipe = NULL; + return ret; +} + + +#ifdef LINUX +#include + +/** + * MINIMIZE heap size (way below 128k) since this process doesn't need much. + */ +void __attribute__ ((constructor)) GNUNET_ARM_memory_init () +{ + mallopt (M_TRIM_THRESHOLD, 4 * 1024); + mallopt (M_TOP_PAD, 1 * 1024); + malloc_trim (0); +} +#endif + + +/* end of gnunet-service-arm.c */ diff --git a/src/arm/mockup-service.c b/src/arm/mockup-service.c new file mode 100644 index 0000000..1e97488 --- /dev/null +++ b/src/arm/mockup-service.c @@ -0,0 +1,105 @@ +/* + This file is part of GNUnet. + (C) 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include +#include "platform.h" +#include "gnunet_disk_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_service_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_strings_lib.h" +#include "gnunet_time_lib.h" + + +static size_t +transmit_shutdown_ack (void *cls, size_t size, void *buf) +{ + struct GNUNET_SERVER_Client *client = cls; + struct GNUNET_MessageHeader *msg; + + if (size < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Failed to transmit shutdown ACK.\n")); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return 0; /* client disconnected */ + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting shutdown ACK.\n")); + + msg = (struct GNUNET_MessageHeader *) buf; + msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + GNUNET_SERVER_client_drop (client); + return sizeof (struct GNUNET_MessageHeader); +} + +/** + * Handler for SHUTDOWN message. + * + * @param cls closure (refers to service) + * @param client identification of the client + * @param message the actual message + */ +static void +handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + GNUNET_SERVER_client_keep (client); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Initiating shutdown as requested by client.\n")); + + GNUNET_SERVER_notify_transmit_ready (client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_shutdown_ack, client); + GNUNET_SERVER_client_persist_ (client); + GNUNET_SCHEDULER_shutdown (); +} + + +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN, + sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} + }; + /* process client requests */ + GNUNET_SERVER_ignore_shutdown (server, GNUNET_YES); + GNUNET_SERVER_add_handlers (server, handlers); +} + + +int +main (int argc, char *const *argv) +{ + int ret; + + ret = + (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "do-nothing", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; + return ret; +} diff --git a/src/arm/test_arm_api.c b/src/arm/test_arm_api.c new file mode 100644 index 0000000..086cfc2 --- /dev/null +++ b/src/arm/test_arm_api.c @@ -0,0 +1,173 @@ +/* + This file is part of GNUnet. + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file arm/test_arm_api.c + * @brief testcase for arm_api.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_arm_service.h" +#include "gnunet_client_lib.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_resolver_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +#define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 1500) + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_ARM_Handle *arm; + +static int ok = 1; + +static void +arm_stopped (void *cls, enum GNUNET_ARM_ProcessStatus success) +{ + GNUNET_break (success == GNUNET_ARM_PROCESS_DOWN); + if (success != GNUNET_ARM_PROCESS_DOWN) + ok = 3; + else if (ok == 1) + ok = 0; +} + + +static void +arm_notify_stop (void *cls, enum GNUNET_ARM_ProcessStatus success) +{ + GNUNET_break (success == GNUNET_ARM_PROCESS_DOWN); +#if START_ARM + GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); +#endif +} + + +static void +dns_notify (void *cls, const struct sockaddr *addr, socklen_t addrlen) +{ + if (addr == NULL) + { + if (ok != 0) + { + GNUNET_break (0); + ok = 2; + } + GNUNET_ARM_stop_service (arm, "resolver", TIMEOUT, &arm_notify_stop, + NULL); + return; + } + GNUNET_break (addr != NULL); + ok = 0; +} + + +static void +resolver_notify (void *cls, enum GNUNET_ARM_ProcessStatus success) +{ + if (success != GNUNET_ARM_PROCESS_STARTING) + { + GNUNET_break (0); + ok = 2; +#if START_ARM + GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); +#endif + return; + } + GNUNET_RESOLVER_ip_get ("localhost", AF_INET, TIMEOUT, &dns_notify, NULL); +} + + +static void +arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus success) +{ + if (success != GNUNET_ARM_PROCESS_STARTING) + { + GNUNET_break (0); + ok = 2; +#if START_ARM + GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); +#endif + } + GNUNET_ARM_start_service (arm, "resolver", START_TIMEOUT, &resolver_notify, + NULL); +} + + +static void +task (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + arm = GNUNET_ARM_connect (cfg, NULL); +#if START_ARM + GNUNET_ARM_start_service (arm, "arm", START_TIMEOUT, &arm_notify, NULL); +#else + arm_notify (NULL, GNUNET_YES); +#endif +} + + + +static int +check () +{ + char *const argv[] = { + "test-arm-api", + "-c", "test_arm_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_assert (GNUNET_OK == + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, + argv, "test-arm-api", "nohelp", options, + &task, NULL)); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + + GNUNET_log_setup ("test-arm-api", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + return ret; +} + +/* end of test_arm_api.c */ diff --git a/src/arm/test_arm_api_data.conf b/src/arm/test_arm_api_data.conf new file mode 100644 index 0000000..7d56e65 --- /dev/null +++ b/src/arm/test_arm_api_data.conf @@ -0,0 +1,58 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunetd-arm/ +DEFAULTCONFIG = test_arm_api_data.conf + +[arm] +PORT = 23354 +DEFAULTSERVICES = +BINARY = gnunet-service-arm +OPTIONS = -L ERROR +# DEBUG = YES +#PREFIX = valgrind --tool=memcheck --leak-check=yes + +[resolver] +# DEBUG = YES +PORT = 23355 +# PREFIX = valgrind + +[do-nothing] +#DEBUG = YES +AUTOSTART = NO +PORT = 2223 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = mockup-service +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; + + +[fs] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[core] +AUTOSTART = NO + +[transport] +AUTOSTART = NO + +[peerinfo] +AUTOSTART = NO + +[statistics] +AUTOSTART = YES +# DEBUG = NO + + +[dns] +AUTOSTART = NO + + + +[nse] +AUTOSTART = NO + + diff --git a/src/arm/test_exponential_backoff.c b/src/arm/test_exponential_backoff.c new file mode 100644 index 0000000..edd5cbf --- /dev/null +++ b/src/arm/test_exponential_backoff.c @@ -0,0 +1,459 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file arm/test_exponential_backoff.c + * @brief testcase for gnunet-service-arm.c + */ +#include "platform.h" +#include "gnunet_arm_service.h" +#include "gnunet_client_lib.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_protocols.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +#define LOG_BACKOFF GNUNET_NO + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) + +#define SERVICE_TEST_TIMEOUT GNUNET_TIME_UNIT_FOREVER_REL + +#define FIVE_MILLISECONDS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 5) + + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_ARM_Handle *arm; + +static int ok = 1; + +static int trialCount; + +static struct GNUNET_TIME_Absolute startedWaitingAt; + +struct GNUNET_TIME_Relative waitedFor; + +#if LOG_BACKOFF +static FILE *killLogFilePtr; + +static char *killLogFileName; +#endif + + +/** + * Context for handling the shutdown of a service. + */ +struct ShutdownContext +{ + /** + * Connection to the service that is being shutdown. + */ + struct GNUNET_CLIENT_Connection *sock; + + /** + * Time allowed for shutdown to happen. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Task set up to cancel the shutdown request on timeout. + */ + GNUNET_SCHEDULER_TaskIdentifier cancel_task; + + /** + * Task to call once shutdown complete + */ + GNUNET_CLIENT_ShutdownTask cont; + + /** + * Closure for shutdown continuation + */ + void *cont_cls; + + /** + * We received a confirmation that the service will shut down. + */ + int confirmed; + +}; + +/** + * Handler receiving response to service shutdown requests. + * First call with NULL: service misbehaving, or something. + * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN: + * - service will shutdown + * Second call with NULL: + * - service has now really shut down. + * + * @param cls closure + * @param msg NULL, indicating socket closure. + */ +static void +service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct ShutdownContext *shutdown_ctx = cls; + + if ((msg == NULL) && (shutdown_ctx->confirmed != GNUNET_YES)) + { + /* Means the other side closed the connection and never confirmed a shutdown */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Service handle shutdown before ACK!\n"); + if (shutdown_ctx->cont != NULL) + shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); + GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); + GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); + GNUNET_free (shutdown_ctx); + } + else if ((msg == NULL) && (shutdown_ctx->confirmed == GNUNET_YES)) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n"); +#endif + if (shutdown_ctx->cont != NULL) + shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_NO); + + GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); + GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); + GNUNET_free (shutdown_ctx); + } + else + { + GNUNET_assert (ntohs (msg->size) == + sizeof (struct GNUNET_MessageHeader)); + switch (ntohs (msg->type)) + { + case GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN: +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received confirmation for service shutdown.\n"); +#endif + shutdown_ctx->confirmed = GNUNET_YES; + GNUNET_CLIENT_receive (shutdown_ctx->sock, + &service_shutdown_handler, shutdown_ctx, + GNUNET_TIME_UNIT_FOREVER_REL); + break; + default: /* Fall through */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Service shutdown refused!\n"); + if (shutdown_ctx->cont != NULL) + shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_YES); + + GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); + GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); + GNUNET_free (shutdown_ctx); + break; + } + } +} + +/** + * Shutting down took too long, cancel receive and return error. + * + * @param cls closure + * @param tc context information (why was this task triggered now) + */ +void +service_shutdown_cancel (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ShutdownContext *shutdown_ctx = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "service_shutdown_cancel called!\n"); + shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); + GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); + GNUNET_free (shutdown_ctx); +} + + +/** + * If possible, write a shutdown message to the target + * buffer and destroy the client connection. + * + * @param cls the "struct GNUNET_CLIENT_Connection" to destroy + * @param size number of bytes available in buf + * @param buf NULL on error, otherwise target buffer + * @return number of bytes written to buf + */ +static size_t +write_shutdown (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg; + struct ShutdownContext *shutdown_ctx = cls; + + if (size < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Failed to transmit shutdown request to client.\n")); + shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); + GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO); + GNUNET_free (shutdown_ctx); + return 0; /* client disconnected */ + } + + GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, + shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); + shutdown_ctx->cancel_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (shutdown_ctx->timeout), + &service_shutdown_cancel, shutdown_ctx); + msg = (struct GNUNET_MessageHeader *) buf; + msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + return sizeof (struct GNUNET_MessageHeader); +} + + +/** + * Request that the service should shutdown. + * Afterwards, the connection will automatically be + * disconnected. Hence the "sock" should not + * be used by the caller after this call + * (calling this function frees "sock" after a while). + * + * @param sock the socket connected to the service + * @param timeout how long to wait before giving up on transmission + * @param cont continuation to call once the service is really down + * @param cont_cls closure for continuation + * + */ +static void +arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock, + struct GNUNET_TIME_Relative timeout, + GNUNET_CLIENT_ShutdownTask cont, void *cont_cls) +{ + struct ShutdownContext *shutdown_ctx; + + shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); + shutdown_ctx->cont = cont; + shutdown_ctx->cont_cls = cont_cls; + shutdown_ctx->sock = sock; + shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); + GNUNET_CLIENT_notify_transmit_ready (sock, + sizeof (struct GNUNET_MessageHeader), + timeout, GNUNET_NO, &write_shutdown, + shutdown_ctx); +} + + +static void +arm_notify_stop (void *cls, enum GNUNET_ARM_ProcessStatus status) +{ + GNUNET_assert ( (status == GNUNET_ARM_PROCESS_DOWN) || + (status == GNUNET_ARM_PROCESS_ALREADY_DOWN) ); +#if START_ARM + GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, NULL, NULL); +#endif +} + + +static void +kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +static void +do_nothing_notify (void *cls, enum GNUNET_ARM_ProcessStatus status) +{ + GNUNET_assert (status == GNUNET_ARM_PROCESS_STARTING); + ok = 1; + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &kill_task, NULL); +} + +static void +arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus status) +{ + GNUNET_assert (status == GNUNET_ARM_PROCESS_STARTING); + GNUNET_ARM_start_service (arm, "do-nothing", TIMEOUT, &do_nothing_notify, + NULL); +} + + +static void +kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +static void +do_nothing_restarted_notify_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext + *tc) +{ + static char a; + + trialCount++; + +#if LOG_BACKOFF + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + FPRINTF (killLogFilePtr, "%d.Reason is shutdown!\n", trialCount); + } + else if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0) + { + FPRINTF (killLogFilePtr, "%d.Reason is timeout!\n", trialCount); + } + else if ((tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE) != 0) + { + FPRINTF (killLogFilePtr, "%d.Service is running!\n", trialCount); + } +#endif + GNUNET_SCHEDULER_add_now (&kill_task, &a); +} + + +static void +do_test (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_CLIENT_service_test ("do-nothing", cfg, TIMEOUT, + &do_nothing_restarted_notify_task, NULL); +} + + +static void +shutdown_cont (void *cls, int reason) +{ + trialCount++; + startedWaitingAt = GNUNET_TIME_absolute_get (); + GNUNET_SCHEDULER_add_delayed (waitedFor, &do_test, NULL); +} + + +static void +kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static struct GNUNET_CLIENT_Connection *doNothingConnection = NULL; + + if (NULL != cbData) + { + waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt); + +#if LOG_BACKOFF + FPRINTF (killLogFilePtr, "Waited for: %llu ms\n", + (unsigned long long) waitedFor.rel_value); +#endif + } + else + { + waitedFor.rel_value = 0; + } + /* Connect to the doNothing task */ + doNothingConnection = GNUNET_CLIENT_connect ("do-nothing", cfg); + GNUNET_assert (doNothingConnection != NULL); + if (trialCount == 12) + { + GNUNET_CLIENT_disconnect (doNothingConnection, GNUNET_NO); + GNUNET_ARM_stop_service (arm, "do-nothing", TIMEOUT, &arm_notify_stop, + NULL); + ok = 0; + return; + } + /* Use the created connection to kill the doNothingTask */ + arm_service_shutdown (doNothingConnection, TIMEOUT, &shutdown_cont, NULL); +} + + +static void +task (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + + arm = GNUNET_ARM_connect (cfg, NULL); +#if START_ARM + GNUNET_ARM_start_service (arm, "arm", GNUNET_TIME_UNIT_ZERO, &arm_notify, + NULL); +#else + arm_do_nothing (NULL, GNUNET_YES); +#endif +} + + +static int +check () +{ + char *const argv[] = { + "test-exponential-backoff", + "-c", "test_arm_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + /* Running ARM and running the do_nothing task */ + GNUNET_assert (GNUNET_OK == + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, + argv, "test-exponential-backoff", + "nohelp", options, &task, NULL)); + + + return ok; +} + +static int +init () +{ +#if LOG_BACKOFF + killLogFileName = GNUNET_DISK_mktemp ("exponential-backoff-waiting.log"); + if (NULL == (killLogFilePtr = FOPEN (killLogFileName, "w"))) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", + killLogFileName); + GNUNET_free (killLogFileName); + return GNUNET_SYSERR; + } +#endif + return GNUNET_OK; +} + + +static void +houseKeep () +{ +#if LOG_BACKOFF + GNUNET_assert (0 == fclose (killLogFilePtr)); + GNUNET_free (killLogFileName); +#endif +} + + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-exponential-backoff", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + init (); + ret = check (); + houseKeep (); + return ret; +} + +/* end of test_exponential_backoff.c */ diff --git a/src/arm/test_gnunet_arm.sh b/src/arm/test_gnunet_arm.sh new file mode 100755 index 0000000..4a5b726 --- /dev/null +++ b/src/arm/test_gnunet_arm.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +exe="./gnunet-arm -c test_arm_api_data.conf" +out=`mktemp /tmp/test-gnunet-arm-logXXXXXXXX` +#DEBUG="-L DEBUG" + + +# ---------------------------------------------------------------------------------- +echo -n "TEST: Bad argument checking... " + +if $exe -x 2> /dev/null; then + echo "FAIL: error running $exe" + exit 1 +fi +echo "PASS" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: Start ARM..." + +if ! $exe $DEBUG -s > $out ; then + echo "FAIL: error running $exe" + echo "Command output was:" + cat $out + exit 1 +fi +echo "PASS" +sleep 1 + +# ---------------------------------------------------------------------------------- +echo -n "TEST: Start another service... " + +if ! $exe $DEBUG -i resolver > $out ; then + echo "FAIL: error running $exe" + echo "Command output was:" + cat $out + kill %% + exit 1 +fi +sleep 1 +echo "PASS" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: Stop a service... " + +if ! $exe $DEBUG -k resolver > $out; then + echo "FAIL: error running $exe" + $exe -e + exit 1 +fi +sleep 1 +echo "PASS" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: Stop ARM... " + +if ! $exe $DEBUG -e > $out; then + echo "FAIL: error running $exe" + exit 1 +fi +sleep 1 +echo "PASS" + +rm -rf /tmp/test-gnunetd-arm/ +rm -f $out + diff --git a/src/arm/test_gnunet_service_manager.c b/src/arm/test_gnunet_service_manager.c new file mode 100644 index 0000000..fe33571 --- /dev/null +++ b/src/arm/test_gnunet_service_manager.c @@ -0,0 +1,185 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file arm/test_gnunet_service_manager.c (A mockup testcase, not functionally complete) + * @brief testcase for gnunet-service-manager.c + */ + +#include "platform.h" +#include "gnunet_arm_service.h" +#include "gnunet_resolver_service.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" + +/** + * Timeout for starting services, very short because of the strange way start works + * (by checking if running before starting, so really this time is always waited on + * startup (annoying)). + */ +#define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 50) + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) + +#define START_ARM GNUNET_YES + +#define VERBOSE GNUNET_NO + +static int ret = 1; + + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +#if START_ARM +static struct GNUNET_ARM_Handle *arm; +#endif + +static void +arm_stopped (void *cls, enum GNUNET_ARM_ProcessStatus success) +{ + if (success != GNUNET_ARM_PROCESS_DOWN) + { + GNUNET_break (0); + ret = 4; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM stopped\n"); + } +#if START_ARM + GNUNET_ARM_disconnect (arm); + arm = NULL; +#endif +} + +static void +hostNameResolveCB (void *cls, const struct sockaddr *addr, socklen_t addrlen) +{ + if ((ret == 0) || (ret == 4)) + return; + if (NULL == addr) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Name not resolved!\n"); +#if START_ARM + GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); +#endif + ret = 3; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Resolved hostname, now stopping ARM\n"); + ret = 0; +#if START_ARM + GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); +#endif +} + + +static void +arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus success) +{ + if (success != GNUNET_ARM_PROCESS_STARTING) + { + GNUNET_break (0); + ret = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying to resolve our own hostname!\n"); + /* connect to the resolver service */ + if (NULL == + GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, TIMEOUT, + &hostNameResolveCB, NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable initiate connection to resolver service\n"); + ret = 2; +#if START_ARM + GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); +#endif + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; +#if START_ARM + arm = GNUNET_ARM_connect (cfg, NULL); + GNUNET_ARM_start_service (arm, "arm", START_TIMEOUT, &arm_notify, NULL); +#else + arm_notify (NULL, GNUNET_YES); +#endif +} + + +static void +check () +{ + char *const argv[] = { + "test-gnunet-service-manager", + "-c", "test_arm_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_assert (GNUNET_OK == + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, + argv, "test-gnunet-service-manager", + "nohelp", options, &run, NULL)); +} + + +int +main (int argc, char *argv[]) +{ + char hostname[GNUNET_OS_get_hostname_max_length () + 1]; + + if (0 != gethostname (hostname, sizeof (hostname) - 1)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "gethostname"); + FPRINTF (stderr, + "%s", "Failed to determine my own hostname, testcase not run.\n"); + return 0; + } + if (NULL == gethostbyname (hostname)) + { + FPRINTF (stderr, + "Failed to resolve my hostname `%s', testcase not run.\n", + hostname); + return 0; + } + + GNUNET_log_setup ("test-gnunet-service-manager", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + check (); + return ret; +} diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am new file mode 100644 index 0000000..f4056fa --- /dev/null +++ b/src/ats/Makefile.am @@ -0,0 +1,121 @@ +INCLUDES = -I$(top_srcdir)/src/include + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + ats.conf + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + +if HAVE_LIBGLPK + GN_LIBGLPK = -lglpk + GN_MLP_SRC = gnunet-service-ats_addresses_mlp.c gnunet-service-ats_addresses_mlp.h + GN_MLP_TEST = test_ats_mlp + GN_MLP_TEST_AVG = test_ats_mlp_averaging + GN_MLP_PERF = perf_ats_mlp +endif + +lib_LTLIBRARIES = libgnunetats.la + +libgnunetats_la_SOURCES = \ + ats_api_scheduling.c \ + ats_api_performance.c + +libgnunetats_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunetats_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 1:0:1 + + +bin_PROGRAMS = \ + gnunet-service-ats + +gnunet_service_ats_SOURCES = \ + gnunet-service-ats.c gnunet-service-ats.h\ + gnunet-service-ats_addresses.c gnunet-service-ats_addresses.h \ + $(GN_MLP_SRC) \ + gnunet-service-ats_performance.c gnunet-service-ats_performance.h \ + gnunet-service-ats_scheduling.c gnunet-service-ats_scheduling.h \ + gnunet-service-ats_reservations.c gnunet-service-ats_reservations.h +gnunet_service_ats_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBGLPK) \ + $(GN_LIBINTL) + + +check_PROGRAMS = \ + test_ats_api_scheduling \ + $(GN_MLP_TEST) \ + $(GN_MLP_TEST_AVG) \ + $(GN_MLP_PERF) +# test_ats_api_scheduling_get_type +# test_ats_api_bandwidth_consumption + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +if HAVE_LIBGLPK +test_ats_mlp_SOURCES = \ + $(GN_MLP_SRC) \ + test_ats_mlp.c +test_ats_mlp_LDADD = \ + $(GN_LIBGLPK) \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la + +test_ats_mlp_averaging_SOURCES = \ + $(GN_MLP_SRC) \ + test_ats_mlp_averaging.c +test_ats_mlp_averaging_LDADD = \ + $(GN_LIBGLPK) \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la + +perf_ats_mlp_SOURCES = \ + $(GN_MLP_SRC) \ + perf_ats_mlp.c +perf_ats_mlp_LDADD = \ + $(GN_LIBGLPK) \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la +endif + +test_ats_api_scheduling_SOURCES = \ + test_ats_api_scheduling.c +test_ats_api_scheduling_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/ats/libgnunetats.la + +#test_ats_api_scheduling_get_type_SOURCES = \ +# test_ats_api_scheduling_get_type.c +#test_ats_api_scheduling_get_type_LDADD = \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(top_builddir)/src/ats/libgnunetats.la + +#test_ats_api_bandwidth_consumption_SOURCES = \ +# test_ats_api_bandwidth_consumption.c +#test_ats_api_bandwidth_consumption_LDADD = \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(top_builddir)/src/ats/libgnunetats.la + +#test_ats_api_update_address_SOURCES = \ +# test_ats_api_update_address.c +#test_ats_api_update_address_LDADD = \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(top_builddir)/src/ats/libgnunetats.la + + +EXTRA_DIST = \ + ats.h \ + test_ats_api.conf + diff --git a/src/ats/Makefile.in b/src/ats/Makefile.in new file mode 100644 index 0000000..26610e1 --- /dev/null +++ b/src/ats/Makefile.in @@ -0,0 +1,1015 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-ats$(EXEEXT) +check_PROGRAMS = test_ats_api_scheduling$(EXEEXT) $(am__EXEEXT_1) \ + $(am__EXEEXT_2) $(am__EXEEXT_3) +subdir = src/ats +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/ats.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = ats.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libgnunetats_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunetats_la_OBJECTS = ats_api_scheduling.lo \ + ats_api_performance.lo +libgnunetats_la_OBJECTS = $(am_libgnunetats_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetats_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetats_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +@HAVE_LIBGLPK_TRUE@am__EXEEXT_1 = test_ats_mlp$(EXEEXT) +@HAVE_LIBGLPK_TRUE@am__EXEEXT_2 = test_ats_mlp_averaging$(EXEEXT) +@HAVE_LIBGLPK_TRUE@am__EXEEXT_3 = perf_ats_mlp$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) +am__gnunet_service_ats_SOURCES_DIST = gnunet-service-ats.c \ + gnunet-service-ats.h gnunet-service-ats_addresses.c \ + gnunet-service-ats_addresses.h \ + gnunet-service-ats_addresses_mlp.c \ + gnunet-service-ats_addresses_mlp.h \ + gnunet-service-ats_performance.c \ + gnunet-service-ats_performance.h \ + gnunet-service-ats_scheduling.c \ + gnunet-service-ats_scheduling.h \ + gnunet-service-ats_reservations.c \ + gnunet-service-ats_reservations.h +@HAVE_LIBGLPK_TRUE@am__objects_1 = \ +@HAVE_LIBGLPK_TRUE@ gnunet-service-ats_addresses_mlp.$(OBJEXT) +am_gnunet_service_ats_OBJECTS = gnunet-service-ats.$(OBJEXT) \ + gnunet-service-ats_addresses.$(OBJEXT) $(am__objects_1) \ + gnunet-service-ats_performance.$(OBJEXT) \ + gnunet-service-ats_scheduling.$(OBJEXT) \ + gnunet-service-ats_reservations.$(OBJEXT) +gnunet_service_ats_OBJECTS = $(am_gnunet_service_ats_OBJECTS) +am__DEPENDENCIES_1 = +gnunet_service_ats_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am__perf_ats_mlp_SOURCES_DIST = gnunet-service-ats_addresses_mlp.c \ + gnunet-service-ats_addresses_mlp.h perf_ats_mlp.c +@HAVE_LIBGLPK_TRUE@am_perf_ats_mlp_OBJECTS = $(am__objects_1) \ +@HAVE_LIBGLPK_TRUE@ perf_ats_mlp.$(OBJEXT) +perf_ats_mlp_OBJECTS = $(am_perf_ats_mlp_OBJECTS) +@HAVE_LIBGLPK_TRUE@perf_ats_mlp_DEPENDENCIES = $(am__DEPENDENCIES_1) \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la +am_test_ats_api_scheduling_OBJECTS = \ + test_ats_api_scheduling.$(OBJEXT) +test_ats_api_scheduling_OBJECTS = \ + $(am_test_ats_api_scheduling_OBJECTS) +test_ats_api_scheduling_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/ats/libgnunetats.la +am__test_ats_mlp_SOURCES_DIST = gnunet-service-ats_addresses_mlp.c \ + gnunet-service-ats_addresses_mlp.h test_ats_mlp.c +@HAVE_LIBGLPK_TRUE@am_test_ats_mlp_OBJECTS = $(am__objects_1) \ +@HAVE_LIBGLPK_TRUE@ test_ats_mlp.$(OBJEXT) +test_ats_mlp_OBJECTS = $(am_test_ats_mlp_OBJECTS) +@HAVE_LIBGLPK_TRUE@test_ats_mlp_DEPENDENCIES = $(am__DEPENDENCIES_1) \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la +am__test_ats_mlp_averaging_SOURCES_DIST = \ + gnunet-service-ats_addresses_mlp.c \ + gnunet-service-ats_addresses_mlp.h test_ats_mlp_averaging.c +@HAVE_LIBGLPK_TRUE@am_test_ats_mlp_averaging_OBJECTS = \ +@HAVE_LIBGLPK_TRUE@ $(am__objects_1) \ +@HAVE_LIBGLPK_TRUE@ test_ats_mlp_averaging.$(OBJEXT) +test_ats_mlp_averaging_OBJECTS = $(am_test_ats_mlp_averaging_OBJECTS) +@HAVE_LIBGLPK_TRUE@test_ats_mlp_averaging_DEPENDENCIES = \ +@HAVE_LIBGLPK_TRUE@ $(am__DEPENDENCIES_1) \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetats_la_SOURCES) $(gnunet_service_ats_SOURCES) \ + $(perf_ats_mlp_SOURCES) $(test_ats_api_scheduling_SOURCES) \ + $(test_ats_mlp_SOURCES) $(test_ats_mlp_averaging_SOURCES) +DIST_SOURCES = $(libgnunetats_la_SOURCES) \ + $(am__gnunet_service_ats_SOURCES_DIST) \ + $(am__perf_ats_mlp_SOURCES_DIST) \ + $(test_ats_api_scheduling_SOURCES) \ + $(am__test_ats_mlp_SOURCES_DIST) \ + $(am__test_ats_mlp_averaging_SOURCES_DIST) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + ats.conf + +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage +@HAVE_LIBGLPK_TRUE@GN_LIBGLPK = -lglpk +@HAVE_LIBGLPK_TRUE@GN_MLP_SRC = gnunet-service-ats_addresses_mlp.c gnunet-service-ats_addresses_mlp.h +@HAVE_LIBGLPK_TRUE@GN_MLP_TEST = test_ats_mlp +@HAVE_LIBGLPK_TRUE@GN_MLP_TEST_AVG = test_ats_mlp_averaging +@HAVE_LIBGLPK_TRUE@GN_MLP_PERF = perf_ats_mlp +lib_LTLIBRARIES = libgnunetats.la +libgnunetats_la_SOURCES = \ + ats_api_scheduling.c \ + ats_api_performance.c + +libgnunetats_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunetats_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 1:0:1 + +gnunet_service_ats_SOURCES = \ + gnunet-service-ats.c gnunet-service-ats.h\ + gnunet-service-ats_addresses.c gnunet-service-ats_addresses.h \ + $(GN_MLP_SRC) \ + gnunet-service-ats_performance.c gnunet-service-ats_performance.h \ + gnunet-service-ats_scheduling.c gnunet-service-ats_scheduling.h \ + gnunet-service-ats_reservations.c gnunet-service-ats_reservations.h + +gnunet_service_ats_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBGLPK) \ + $(GN_LIBINTL) + +# test_ats_api_scheduling_get_type +# test_ats_api_bandwidth_consumption +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +@HAVE_LIBGLPK_TRUE@test_ats_mlp_SOURCES = \ +@HAVE_LIBGLPK_TRUE@ $(GN_MLP_SRC) \ +@HAVE_LIBGLPK_TRUE@ test_ats_mlp.c + +@HAVE_LIBGLPK_TRUE@test_ats_mlp_LDADD = \ +@HAVE_LIBGLPK_TRUE@ $(GN_LIBGLPK) \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la + +@HAVE_LIBGLPK_TRUE@test_ats_mlp_averaging_SOURCES = \ +@HAVE_LIBGLPK_TRUE@ $(GN_MLP_SRC) \ +@HAVE_LIBGLPK_TRUE@ test_ats_mlp_averaging.c + +@HAVE_LIBGLPK_TRUE@test_ats_mlp_averaging_LDADD = \ +@HAVE_LIBGLPK_TRUE@ $(GN_LIBGLPK) \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la + +@HAVE_LIBGLPK_TRUE@perf_ats_mlp_SOURCES = \ +@HAVE_LIBGLPK_TRUE@ $(GN_MLP_SRC) \ +@HAVE_LIBGLPK_TRUE@ perf_ats_mlp.c + +@HAVE_LIBGLPK_TRUE@perf_ats_mlp_LDADD = \ +@HAVE_LIBGLPK_TRUE@ $(GN_LIBGLPK) \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ +@HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la + +test_ats_api_scheduling_SOURCES = \ + test_ats_api_scheduling.c + +test_ats_api_scheduling_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/ats/libgnunetats.la + + +#test_ats_api_scheduling_get_type_SOURCES = \ +# test_ats_api_scheduling_get_type.c +#test_ats_api_scheduling_get_type_LDADD = \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(top_builddir)/src/ats/libgnunetats.la + +#test_ats_api_bandwidth_consumption_SOURCES = \ +# test_ats_api_bandwidth_consumption.c +#test_ats_api_bandwidth_consumption_LDADD = \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(top_builddir)/src/ats/libgnunetats.la + +#test_ats_api_update_address_SOURCES = \ +# test_ats_api_update_address.c +#test_ats_api_update_address_LDADD = \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(top_builddir)/src/ats/libgnunetats.la +EXTRA_DIST = \ + ats.h \ + test_ats_api.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/ats/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/ats/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +ats.conf: $(top_builddir)/config.status $(srcdir)/ats.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetats.la: $(libgnunetats_la_OBJECTS) $(libgnunetats_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetats_la_LINK) -rpath $(libdir) $(libgnunetats_la_OBJECTS) $(libgnunetats_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-service-ats$(EXEEXT): $(gnunet_service_ats_OBJECTS) $(gnunet_service_ats_DEPENDENCIES) + @rm -f gnunet-service-ats$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_ats_OBJECTS) $(gnunet_service_ats_LDADD) $(LIBS) +perf_ats_mlp$(EXEEXT): $(perf_ats_mlp_OBJECTS) $(perf_ats_mlp_DEPENDENCIES) + @rm -f perf_ats_mlp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_ats_mlp_OBJECTS) $(perf_ats_mlp_LDADD) $(LIBS) +test_ats_api_scheduling$(EXEEXT): $(test_ats_api_scheduling_OBJECTS) $(test_ats_api_scheduling_DEPENDENCIES) + @rm -f test_ats_api_scheduling$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_ats_api_scheduling_OBJECTS) $(test_ats_api_scheduling_LDADD) $(LIBS) +test_ats_mlp$(EXEEXT): $(test_ats_mlp_OBJECTS) $(test_ats_mlp_DEPENDENCIES) + @rm -f test_ats_mlp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_ats_mlp_OBJECTS) $(test_ats_mlp_LDADD) $(LIBS) +test_ats_mlp_averaging$(EXEEXT): $(test_ats_mlp_averaging_OBJECTS) $(test_ats_mlp_averaging_DEPENDENCIES) + @rm -f test_ats_mlp_averaging$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_ats_mlp_averaging_OBJECTS) $(test_ats_mlp_averaging_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ats_api_performance.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ats_api_scheduling.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_addresses.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_addresses_mlp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_performance.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_reservations.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_scheduling.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_ats_mlp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ats_api_scheduling.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ats_mlp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ats_mlp_averaging.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/ats/ats.conf.in b/src/ats/ats.conf.in new file mode 100644 index 0000000..6ea0d41 --- /dev/null +++ b/src/ats/ats.conf.in @@ -0,0 +1,24 @@ +[ats] +AUTOSTART = YES +@UNIXONLY@ PORT = 2098 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-ats +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-ats.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +MLP = NO +WAN_QUOTA_IN = 65536 +WAN_QUOTA_OUT = 65536 +# ATS options +DUMP_MLP = NO +DUMP_SOLUTION = NO +DUMP_OVERWRITE = NO +DUMP_MIN_PEERS = 0 +DUMP_MIN_ADDRS = 0 +DUMP_OVERWRITE = NO +ATS_MIN_INTERVAL = 15000 +ATS_EXEC_INTERVAL = 30000 diff --git a/src/ats/ats.h b/src/ats/ats.h new file mode 100644 index 0000000..30ca295 --- /dev/null +++ b/src/ats/ats.h @@ -0,0 +1,243 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file ats/ats.h + * @brief automatic transport selection messages + * @author Christian Grothoff + * @author Matthias Wachs + */ +#ifndef ATS_H +#define ATS_H + +#include "gnunet_util_lib.h" + + +enum StartFlag +{ + + START_FLAG_SCHEDULING = 0, + + START_FLAG_PERFORMANCE_WITH_PIC = 1, + + START_FLAG_PERFORMANCE_NO_PIC = 2 +}; + +GNUNET_NETWORK_STRUCT_BEGIN + +struct ClientStartMessage +{ + struct GNUNET_MessageHeader header; + + /** + * NBO value of an 'enum StartFlag'. + */ + uint32_t start_flag GNUNET_PACKED; +}; + + +struct RequestAddressMessage +{ + struct GNUNET_MessageHeader header; + + uint32_t reserved GNUNET_PACKED; + + struct GNUNET_PeerIdentity peer; +}; + + +struct AddressUpdateMessage +{ + struct GNUNET_MessageHeader header; + + uint32_t ats_count GNUNET_PACKED; + + struct GNUNET_PeerIdentity peer; + + uint16_t address_length GNUNET_PACKED; + + uint16_t plugin_name_length GNUNET_PACKED; + + uint32_t session_id GNUNET_PACKED; + + /* followed by: + * - struct GNUNET_ATS_Information [ats_count]; + * - char address[address_length] + * - char plugin_name[plugin_name_length] (including '\0'-termination). + */ + +}; + +struct AddressUseMessage +{ + struct GNUNET_MessageHeader header; + + struct GNUNET_PeerIdentity peer; + + uint16_t in_use GNUNET_PACKED; + + uint16_t address_length GNUNET_PACKED; + + uint16_t plugin_name_length GNUNET_PACKED; + + uint32_t session_id GNUNET_PACKED; + + /* followed by: + * - char address[address_length] + * - char plugin_name[plugin_name_length] (including '\0'-termination). + */ + +}; + + +struct AddressDestroyedMessage +{ + struct GNUNET_MessageHeader header; + + uint32_t reserved GNUNET_PACKED; + + struct GNUNET_PeerIdentity peer; + + uint16_t address_length GNUNET_PACKED; + + uint16_t plugin_name_length GNUNET_PACKED; + + uint32_t session_id GNUNET_PACKED; + + /* followed by: + * - char address[address_length] + * - char plugin_name[plugin_name_length] (including '\0'-termination). + */ + +}; + + +struct AddressSuggestionMessage +{ + struct GNUNET_MessageHeader header; + + uint32_t ats_count GNUNET_PACKED; + + struct GNUNET_PeerIdentity peer; + + uint16_t address_length GNUNET_PACKED; + + uint16_t plugin_name_length GNUNET_PACKED; + + uint32_t session_id GNUNET_PACKED; + + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; + + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; + + /* followed by: + * - struct GNUNET_ATS_Information [ats_count]; + * - char address[address_length] + * - char plugin_name[plugin_name_length] (including '\0'-termination). + */ + +}; + + +struct PeerInformationMessage +{ + struct GNUNET_MessageHeader header; + + uint32_t ats_count GNUNET_PACKED; + + struct GNUNET_PeerIdentity peer; + + uint16_t address_length GNUNET_PACKED; + + uint16_t plugin_name_length GNUNET_PACKED; + + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; + + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; + + /* followed by: + * - struct GNUNET_ATS_Information [ats_count]; + * - char address[address_length] + * - char plugin_name[plugin_name_length] (including '\0'-termination). + */ + +}; + + +struct ReservationRequestMessage +{ + struct GNUNET_MessageHeader header; + + int32_t amount GNUNET_PACKED; + + struct GNUNET_PeerIdentity peer; +}; + + +/** + * Message sent by ATS service to client to confirm that it is done + * using the given session ID. + */ +struct SessionReleaseMessage +{ + struct GNUNET_MessageHeader header; + + uint32_t session_id GNUNET_PACKED; + + struct GNUNET_PeerIdentity peer; +}; + + +struct ReservationResultMessage +{ + struct GNUNET_MessageHeader header; + + int32_t amount GNUNET_PACKED; + + struct GNUNET_PeerIdentity peer; + + struct GNUNET_TIME_RelativeNBO res_delay; +}; + +struct PreferenceInformation +{ + + uint32_t preference_kind GNUNET_PACKED; + + float preference_value GNUNET_PACKED; + +}; + + +struct ChangePreferenceMessage +{ + struct GNUNET_MessageHeader header; + + uint32_t num_preferences GNUNET_PACKED; + + struct GNUNET_PeerIdentity peer; + + /* followed by 'num_preferences' + * struct PreferenceInformation values */ +}; +GNUNET_NETWORK_STRUCT_END + + + +#endif diff --git a/src/ats/ats_api_performance.c b/src/ats/ats_api_performance.c new file mode 100644 index 0000000..848c7ec --- /dev/null +++ b/src/ats/ats_api_performance.c @@ -0,0 +1,645 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file ats/ats_api_performance.c + * @brief automatic transport selection and outbound bandwidth determination + * @author Christian Grothoff + * @author Matthias Wachs + */ +#include "platform.h" +#include "gnunet_ats_service.h" +#include "ats.h" + + +/** + * Message in linked list we should send to the ATS service. The + * actual binary message follows this struct. + */ +struct PendingMessage +{ + + /** + * Kept in a DLL. + */ + struct PendingMessage *next; + + /** + * Kept in a DLL. + */ + struct PendingMessage *prev; + + /** + * Size of the message. + */ + size_t size; + + /** + * Is this the 'ATS_START' message? + */ + int is_init; +}; + + +/** + * Linked list of pending reservations. + */ +struct GNUNET_ATS_ReservationContext +{ + + /** + * Kept in a DLL. + */ + struct GNUNET_ATS_ReservationContext *next; + + /** + * Kept in a DLL. + */ + struct GNUNET_ATS_ReservationContext *prev; + + /** + * Target peer. + */ + struct GNUNET_PeerIdentity peer; + + /** + * Desired reservation + */ + int32_t size; + + /** + * Function to call on result. + */ + GNUNET_ATS_ReservationCallback rcb; + + /** + * Closure for 'rcb' + */ + void *rcb_cls; + + /** + * Do we need to undo this reservation if it succeeded? Set to + * GNUNET_YES if a reservation is cancelled. (at that point, 'info' + * is also set to NULL; however, info will ALSO be NULL for the + * reservation context that is created to undo the original request, + * so 'info' being NULL cannot be used to check if undo is + * required). + */ + int undo; +}; + + +/** + * ATS Handle to obtain and/or modify performance information. + */ +struct GNUNET_ATS_PerformanceHandle +{ + + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Callback to invoke on performance changes. + */ + GNUNET_ATS_PeerInformationCallback infocb; + + /** + * Closure for 'infocb'. + */ + void *infocb_cls; + + /** + * Connection to ATS service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Head of list of messages for the ATS service. + */ + struct PendingMessage *pending_head; + + /** + * Tail of list of messages for the ATS service + */ + struct PendingMessage *pending_tail; + + /** + * Head of linked list of pending reservation requests. + */ + struct GNUNET_ATS_ReservationContext *reservation_head; + + /** + * Tail of linked list of pending reservation requests. + */ + struct GNUNET_ATS_ReservationContext *reservation_tail; + + /** + * Current request for transmission to ATS. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Task to trigger reconnect. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + +}; + + +/** + * Re-establish the connection to the ATS service. + * + * @param ph handle to use to re-connect. + */ +static void +reconnect (struct GNUNET_ATS_PerformanceHandle *ph); + + +/** + * Re-establish the connection to the ATS service. + * + * @param cls handle to use to re-connect. + * @param tc scheduler context + */ +static void +reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_ATS_PerformanceHandle *ph = cls; + + ph->task = GNUNET_SCHEDULER_NO_TASK; + reconnect (ph); +} + + +/** + * Transmit messages from the message queue to the service + * (if there are any, and if we are not already trying). + * + * @param ph handle to use + */ +static void +do_transmit (struct GNUNET_ATS_PerformanceHandle *ph); + + +/** + * We can now transmit a message to ATS. Do it. + * + * @param cls the 'struct GNUNET_ATS_SchedulingHandle' + * @param size number of bytes we can transmit to ATS + * @param buf where to copy the messages + * @return number of bytes copied into buf + */ +static size_t +transmit_message_to_ats (void *cls, size_t size, void *buf) +{ + struct GNUNET_ATS_PerformanceHandle *ph = cls; + struct PendingMessage *p; + size_t ret; + char *cbuf; + + ph->th = NULL; + ret = 0; + cbuf = buf; + while ((NULL != (p = ph->pending_head)) && (p->size <= size)) + { + memcpy (&cbuf[ret], &p[1], p->size); + ret += p->size; + size -= p->size; + GNUNET_CONTAINER_DLL_remove (ph->pending_head, ph->pending_tail, p); + GNUNET_free (p); + } + do_transmit (ph); + return ret; +} + + +/** + * Transmit messages from the message queue to the service + * (if there are any, and if we are not already trying). + * + * @param ph handle to use + */ +static void +do_transmit (struct GNUNET_ATS_PerformanceHandle *ph) +{ + struct PendingMessage *p; + + if (NULL != ph->th) + return; + if (NULL == (p = ph->pending_head)) + return; + if (NULL == ph->client) + return; /* currently reconnecting */ + ph->th = + GNUNET_CLIENT_notify_transmit_ready (ph->client, p->size, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &transmit_message_to_ats, + ph); +} + + +/** + * We received a peer information message. Validate and process it. + * + * @param ph our context with the callback + * @param msg the message + * @return GNUNET_OK if the message was well-formed + */ +static int +process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph, + const struct GNUNET_MessageHeader *msg) +{ + const struct PeerInformationMessage *pi; + const struct GNUNET_ATS_Information *atsi; + const char *plugin_address; + const char *plugin_name; + struct GNUNET_HELLO_Address address; + uint16_t plugin_address_length; + uint16_t plugin_name_length; + uint32_t ats_count; + + if (ph->infocb == NULL) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (ntohs (msg->size) < sizeof (struct PeerInformationMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + pi = (const struct PeerInformationMessage *) msg; + ats_count = ntohl (pi->ats_count); + plugin_address_length = ntohs (pi->address_length); + plugin_name_length = ntohs (pi->plugin_name_length); + atsi = (const struct GNUNET_ATS_Information *) &pi[1]; + plugin_address = (const char *) &atsi[ats_count]; + plugin_name = &plugin_address[plugin_address_length]; + if ((plugin_address_length + plugin_name_length + + ats_count * sizeof (struct GNUNET_ATS_Information) + + sizeof (struct PeerInformationMessage) != ntohs (msg->size)) || + (ats_count > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)) + || (plugin_name[plugin_name_length - 1] != '\0')) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + address.peer = pi->peer; + address.address = plugin_address; + address.address_length = plugin_address_length; + address.transport_name = plugin_name; + ph->infocb (ph->infocb_cls, &address, pi->bandwidth_out, pi->bandwidth_in, + atsi, ats_count); + return GNUNET_OK; +} + + +/** + * We received a reservation result message. Validate and process it. + * + * @param ph our context with the callback + * @param msg the message + * @return GNUNET_OK if the message was well-formed + */ +static int +process_rr_message (struct GNUNET_ATS_PerformanceHandle *ph, + const struct GNUNET_MessageHeader *msg) +{ + const struct ReservationResultMessage *rr; + struct GNUNET_ATS_ReservationContext *rc; + int32_t amount; + + if (ntohs (msg->size) < sizeof (struct ReservationResultMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + rr = (const struct ReservationResultMessage *) msg; + amount = ntohl (rr->amount); + rc = ph->reservation_head; + if (0 != memcmp (&rr->peer, &rc->peer, sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + GNUNET_CONTAINER_DLL_remove (ph->reservation_head, ph->reservation_tail, rc); + if ((amount == 0) || (rc->rcb != NULL)) + { + /* tell client if not cancelled */ + if (rc->rcb != NULL) + rc->rcb (rc->rcb_cls, &rr->peer, amount, + GNUNET_TIME_relative_ntoh (rr->res_delay)); + GNUNET_free (rc); + return GNUNET_OK; + } + /* amount non-zero, but client cancelled, consider undo! */ + if (GNUNET_YES != rc->undo) + { + GNUNET_free (rc); + return GNUNET_OK; /* do not try to undo failed undos or negative amounts */ + } + GNUNET_free (rc); + (void) GNUNET_ATS_reserve_bandwidth (ph, &rr->peer, -amount, NULL, NULL); + return GNUNET_OK; +} + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls the 'struct GNUNET_ATS_SchedulingHandle' + * @param msg message received, NULL on timeout or fatal error + */ +static void +process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_ATS_PerformanceHandle *ph = cls; + + if (NULL == msg) + goto reconnect; + switch (ntohs (msg->type)) + { + case GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION: + if (GNUNET_OK != process_pi_message (ph, msg)) + goto reconnect; + break; + case GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT: + if (GNUNET_OK != process_rr_message (ph, msg)) + goto reconnect; + break; + default: + GNUNET_break (0); + goto reconnect; + } + GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph, + GNUNET_TIME_UNIT_FOREVER_REL); + return; +reconnect: + GNUNET_CLIENT_disconnect (ph->client, GNUNET_NO); + ph->client = NULL; + ph->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task, + ph); +} + + +/** + * Re-establish the connection to the ATS service. + * + * @param ph handle to use to re-connect. + */ +static void +reconnect (struct GNUNET_ATS_PerformanceHandle *ph) +{ + struct PendingMessage *p; + struct ClientStartMessage *init; + + GNUNET_assert (NULL == ph->client); + ph->client = GNUNET_CLIENT_connect ("ats", ph->cfg); + GNUNET_assert (NULL != ph->client); + GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph, + GNUNET_TIME_UNIT_FOREVER_REL); + if ((NULL == (p = ph->pending_head)) || (GNUNET_YES != p->is_init)) + { + p = GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct ClientStartMessage)); + p->size = sizeof (struct ClientStartMessage); + p->is_init = GNUNET_YES; + init = (struct ClientStartMessage *) &p[1]; + init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START); + init->header.size = htons (sizeof (struct ClientStartMessage)); + init->start_flag = + htonl ((ph->infocb == + NULL) ? START_FLAG_PERFORMANCE_NO_PIC : + START_FLAG_PERFORMANCE_WITH_PIC); + GNUNET_CONTAINER_DLL_insert (ph->pending_head, ph->pending_tail, p); + } + do_transmit (ph); +} + + + +/** + * Get handle to access performance API of the ATS subsystem. + * + * @param cfg configuration to use + * @param infocb function to call on allocation changes, can be NULL + * @param infocb_cls closure for infocb + * @return ats performance context + */ +struct GNUNET_ATS_PerformanceHandle * +GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_ATS_PeerInformationCallback infocb, + void *infocb_cls) +{ + struct GNUNET_ATS_PerformanceHandle *ph; + + ph = GNUNET_malloc (sizeof (struct GNUNET_ATS_PerformanceHandle)); + ph->cfg = cfg; + ph->infocb = infocb; + ph->infocb_cls = infocb_cls; + reconnect (ph); + return ph; +} + + +/** + * Client is done using the ATS performance subsystem, release resources. + * + * @param ph handle + */ +void +GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph) +{ + struct PendingMessage *p; + struct GNUNET_ATS_ReservationContext *rc; + + while (NULL != (p = ph->pending_head)) + { + GNUNET_CONTAINER_DLL_remove (ph->pending_head, ph->pending_tail, p); + GNUNET_free (p); + } + while (NULL != (rc = ph->reservation_head)) + { + GNUNET_CONTAINER_DLL_remove (ph->reservation_head, ph->reservation_tail, + rc); + GNUNET_break (NULL == rc->rcb); + GNUNET_free (rc); + } + if (GNUNET_SCHEDULER_NO_TASK != ph->task) + { + GNUNET_SCHEDULER_cancel (ph->task); + ph->task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != ph->client) + { + GNUNET_CLIENT_disconnect (ph->client, GNUNET_NO); + ph->client = NULL; + } + GNUNET_free (ph); +} + + +/** + * Reserve inbound bandwidth from the given peer. ATS will look at + * the current amount of traffic we receive from the peer and ensure + * that the peer could add 'amount' of data to its stream. + * + * @param ph performance handle + * @param peer identifies the peer + * @param amount reserve N bytes for receiving, negative + * amounts can be used to undo a (recent) reservation; + * @param rcb function to call with the resulting reservation information + * @param rcb_cls closure for info + * @return NULL on error + * @deprecated will be replaced soon + */ +struct GNUNET_ATS_ReservationContext * +GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph, + const struct GNUNET_PeerIdentity *peer, + int32_t amount, + GNUNET_ATS_ReservationCallback rcb, void *rcb_cls) +{ + struct GNUNET_ATS_ReservationContext *rc; + struct PendingMessage *p; + struct ReservationRequestMessage *m; + + rc = GNUNET_malloc (sizeof (struct GNUNET_ATS_ReservationContext)); + rc->size = amount; + rc->peer = *peer; + rc->rcb = rcb; + rc->rcb_cls = rcb_cls; + if ((rcb != NULL) && (amount > 0)) + rc->undo = GNUNET_YES; + GNUNET_CONTAINER_DLL_insert_tail (ph->reservation_head, ph->reservation_tail, + rc); + + p = GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct ReservationRequestMessage)); + p->size = sizeof (struct ReservationRequestMessage); + p->is_init = GNUNET_NO; + m = (struct ReservationRequestMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST); + m->header.size = htons (sizeof (struct ReservationRequestMessage)); + m->amount = htonl (amount); + m->peer = *peer; + GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p); + do_transmit (ph); + return rc; +} + + +/** + * Cancel request for reserving bandwidth. + * + * @param rc context returned by the original GNUNET_ATS_reserve_bandwidth call + */ +void +GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc) +{ + rc->rcb = NULL; +} + + +/** + * Change preferences for the given peer. Preference changes are forgotten if peers + * disconnect. + * + * @param ph performance handle + * @param peer identifies the peer + * @param ... 0-terminated specification of the desired changes + */ +void +GNUNET_ATS_change_preference (struct GNUNET_ATS_PerformanceHandle *ph, + const struct GNUNET_PeerIdentity *peer, ...) +{ + struct PendingMessage *p; + struct ChangePreferenceMessage *m; + size_t msize; + uint32_t count; + struct PreferenceInformation *pi; + va_list ap; + enum GNUNET_ATS_PreferenceKind kind; + + count = 0; + va_start (ap, peer); + while (GNUNET_ATS_PREFERENCE_END != + (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind))) + { + switch (kind) + { + case GNUNET_ATS_PREFERENCE_BANDWIDTH: + count++; + (void) va_arg (ap, double); + + break; + case GNUNET_ATS_PREFERENCE_LATENCY: + count++; + (void) va_arg (ap, double); + + break; + default: + GNUNET_assert (0); + } + } + va_end (ap); + msize = + count * sizeof (struct PreferenceInformation) + + sizeof (struct ChangePreferenceMessage); + p = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + p->size = msize; + p->is_init = GNUNET_NO; + m = (struct ChangePreferenceMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE); + m->header.size = htons (msize); + m->num_preferences = htonl (count); + m->peer = *peer; + pi = (struct PreferenceInformation *) &m[1]; + count = 0; + va_start (ap, peer); + while (GNUNET_ATS_PREFERENCE_END != + (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind))) + { + pi[count].preference_kind = htonl (kind); + switch (kind) + { + case GNUNET_ATS_PREFERENCE_BANDWIDTH: + pi[count].preference_value = (float) va_arg (ap, double); + + count++; + break; + case GNUNET_ATS_PREFERENCE_LATENCY: + pi[count].preference_value = (float) va_arg (ap, double); + + count++; + break; + default: + GNUNET_assert (0); + } + } + va_end (ap); + GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p); + do_transmit (ph); +} + +/* end of ats_api_performance.c */ diff --git a/src/ats/ats_api_scheduling.c b/src/ats/ats_api_scheduling.c new file mode 100644 index 0000000..78e8d61 --- /dev/null +++ b/src/ats/ats_api_scheduling.c @@ -0,0 +1,1177 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file ats/ats_api_scheduling.c + * @brief automatic transport selection and outbound bandwidth determination + * @author Christian Grothoff + * @author Matthias Wachs + */ +#include "platform.h" +#include "gnunet_ats_service.h" +#include "ats.h" + +#define DEBUG_ATS GNUNET_EXTRA_LOGGING + +#define INTERFACE_PROCESSING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * Message in linked list we should send to the ATS service. The + * actual binary message follows this struct. + */ +struct PendingMessage +{ + + /** + * Kept in a DLL. + */ + struct PendingMessage *next; + + /** + * Kept in a DLL. + */ + struct PendingMessage *prev; + + /** + * Size of the message. + */ + size_t size; + + /** + * Is this the 'ATS_START' message? + */ + int is_init; +}; + + +/** + * Information we track per session. + */ +struct SessionRecord +{ + /** + * Identity of the peer (just needed for error checking). + */ + struct GNUNET_PeerIdentity peer; + + /** + * Session handle. + */ + struct Session *session; + + /** + * Set to GNUNET_YES if the slot is used. + */ + int slot_used; +}; + + +struct ATS_Network +{ + struct ATS_Network * next; + + struct ATS_Network * prev; + + struct sockaddr *network; + struct sockaddr *netmask; + socklen_t length; +}; + + + +/** + * Handle to the ATS subsystem for bandwidth/transport scheduling information. + */ +struct GNUNET_ATS_SchedulingHandle +{ + + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Callback to invoke on suggestions. + */ + GNUNET_ATS_AddressSuggestionCallback suggest_cb; + + /** + * Closure for 'suggest_cb'. + */ + void *suggest_cb_cls; + + /** + * Connection to ATS service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Head of list of messages for the ATS service. + */ + struct PendingMessage *pending_head; + + /** + * Tail of list of messages for the ATS service + */ + struct PendingMessage *pending_tail; + + /** + * Current request for transmission to ATS. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Head of network list + */ + struct ATS_Network * net_head; + + /** + * Tail of network list + */ + struct ATS_Network * net_tail; + + + /** + * Array of session objects (we need to translate them to numbers and back + * for the protocol; the offset in the array is the session number on the + * network). Index 0 is always NULL and reserved to represent the NULL pointer. + * Unused entries are also NULL. + */ + struct SessionRecord *session_array; + + /** + * Task to trigger reconnect. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Task retrieving interfaces from the system + */ + + GNUNET_SCHEDULER_TaskIdentifier interface_task; + + + /** + * Size of the session array. + */ + unsigned int session_array_size; + + /** + * Should we reconnect to ATS due to some serious error? + */ + int reconnect; +}; + + +/** + * Re-establish the connection to the ATS service. + * + * @param sh handle to use to re-connect. + */ +static void +reconnect (struct GNUNET_ATS_SchedulingHandle *sh); + + +/** + * Re-establish the connection to the ATS service. + * + * @param cls handle to use to re-connect. + * @param tc scheduler context + */ +static void +reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_ATS_SchedulingHandle *sh = cls; + + sh->task = GNUNET_SCHEDULER_NO_TASK; + reconnect (sh); +} + + +/** + * Disconnect from ATS and then reconnect. + * + * @param sh our handle + */ +static void +force_reconnect (struct GNUNET_ATS_SchedulingHandle *sh) +{ + sh->reconnect = GNUNET_NO; + GNUNET_CLIENT_disconnect (sh->client, GNUNET_NO); + sh->client = NULL; + sh->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task, + sh); +} + + +/** + * Transmit messages from the message queue to the service + * (if there are any, and if we are not already trying). + * + * @param sh handle to use + */ +static void +do_transmit (struct GNUNET_ATS_SchedulingHandle *sh); + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls the 'struct GNUNET_ATS_SchedulingHandle' + * @param msg message received, NULL on timeout or fatal error + */ +static void +process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg); + + +/** + * We can now transmit a message to ATS. Do it. + * + * @param cls the 'struct GNUNET_ATS_SchedulingHandle' + * @param size number of bytes we can transmit to ATS + * @param buf where to copy the messages + * @return number of bytes copied into buf + */ +static size_t +transmit_message_to_ats (void *cls, size_t size, void *buf) +{ + struct GNUNET_ATS_SchedulingHandle *sh = cls; + struct PendingMessage *p; + size_t ret; + char *cbuf; + + sh->th = NULL; + if ((size == 0) || (buf == NULL)) + { + force_reconnect (sh); + return 0; + } + ret = 0; + cbuf = buf; + while ((NULL != (p = sh->pending_head)) && (p->size <= size)) + { + memcpy (&cbuf[ret], &p[1], p->size); + ret += p->size; + size -= p->size; + GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p); + if (GNUNET_YES == p->is_init) + GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh, + GNUNET_TIME_UNIT_FOREVER_REL); + GNUNET_free (p); + } + do_transmit (sh); + return ret; +} + + +/** + * Transmit messages from the message queue to the service + * (if there are any, and if we are not already trying). + * + * @param sh handle to use + */ +static void +do_transmit (struct GNUNET_ATS_SchedulingHandle *sh) +{ + struct PendingMessage *p; + + if (NULL != sh->th) + return; + if (NULL == (p = sh->pending_head)) + return; + if (NULL == sh->client) + return; /* currently reconnecting */ + sh->th = + GNUNET_CLIENT_notify_transmit_ready (sh->client, p->size, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, &transmit_message_to_ats, + sh); +} + + +/** + * Find the session object corresponding to the given session ID. + * + * @param sh our handle + * @param session_id current session ID + * @param peer peer the session belongs to + * @return the session object (or NULL) + */ +static struct Session * +find_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id, + const struct GNUNET_PeerIdentity *peer) +{ +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Find session %u from peer %s in %p\n", + (unsigned int) session_id, GNUNET_i2s (peer), sh); +#endif + if (session_id >= sh->session_array_size) + { + GNUNET_break (0); + return NULL; + } + if (0 == session_id) + return NULL; + if (sh->session_array[session_id].session == NULL) + { + GNUNET_break (0 == + memcmp (peer, &sh->session_array[session_id].peer, + sizeof (struct GNUNET_PeerIdentity))); + return NULL; + } + + if (0 != + memcmp (peer, &sh->session_array[session_id].peer, + sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break (0); + sh->reconnect = GNUNET_YES; + return NULL; + } + return sh->session_array[session_id].session; +} + + +/** + * Get the ID for the given session object. If we do not have an ID for + * the given session object, allocate one. + * + * @param sh our handle + * @param session session object + * @param peer peer the session belongs to + * @return the session id + */ +static uint32_t +get_session_id (struct GNUNET_ATS_SchedulingHandle *sh, struct Session *session, + const struct GNUNET_PeerIdentity *peer) +{ + unsigned int i; + unsigned int f; + +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Get session ID for session %p from peer %s in %p\n", session, + GNUNET_i2s (peer), sh); +#endif + if (NULL == session) + return 0; + f = 0; + for (i = 1; i < sh->session_array_size; i++) + { + if (session == sh->session_array[i].session) + { + GNUNET_assert (0 == + memcmp (peer, &sh->session_array[i].peer, + sizeof (struct GNUNET_PeerIdentity))); + return i; + } + if ((f == 0) && (sh->session_array[i].slot_used == GNUNET_NO)) + f = i; + } + if (f == 0) + { + f = sh->session_array_size; + GNUNET_array_grow (sh->session_array, sh->session_array_size, + sh->session_array_size * 2); + } + GNUNET_assert (f > 0); + sh->session_array[f].session = session; + sh->session_array[f].peer = *peer; + sh->session_array[f].slot_used = GNUNET_YES; +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Assigning session ID %u for session %p of peer %s in %p\n", f, + session, GNUNET_i2s (peer), sh); +#endif + return f; +} + + +/** + * Remove the session of the given session ID from the session + * table (it is no longer valid). + * + * @param sh our handle + * @param session_id identifies session that is no longer valid + * @param peer peer the session belongs to + */ +static void +remove_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id, + const struct GNUNET_PeerIdentity *peer) +{ +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Remove sessionID %u from peer %s in %p\n", + (unsigned int) session_id, GNUNET_i2s (peer), sh); +#endif + if (0 == session_id) + return; + GNUNET_assert (session_id < sh->session_array_size); + GNUNET_assert (GNUNET_YES == sh->session_array[session_id].slot_used); + GNUNET_assert (0 == + memcmp (peer, &sh->session_array[session_id].peer, + sizeof (struct GNUNET_PeerIdentity))); + sh->session_array[session_id].session = NULL; +} + + +/** + * Release the session slot from the session table (ATS service is + * also done using it). + * + * @param sh our handle + * @param session_id identifies session that is no longer valid + * @param peer peer the session belongs to + */ +static void +release_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id, + const struct GNUNET_PeerIdentity *peer) +{ +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Release sessionID %u from peer %s in %p\n", + (unsigned int) session_id, GNUNET_i2s (peer), sh); +#endif + if (session_id >= sh->session_array_size) + { + GNUNET_break (0); + sh->reconnect = GNUNET_YES; + return; + } + + /* this slot should have been removed from remove_session before */ + GNUNET_assert (sh->session_array[session_id].session == NULL); + + if (0 != + memcmp (peer, &sh->session_array[session_id].peer, + sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break (0); + sh->reconnect = GNUNET_YES; + return; + } + sh->session_array[session_id].slot_used = GNUNET_NO; + memset (&sh->session_array[session_id].peer, 0, + sizeof (struct GNUNET_PeerIdentity)); +} + + +static void +process_release_message (struct GNUNET_ATS_SchedulingHandle *sh, + const struct SessionReleaseMessage *srm) +{ + release_session (sh, ntohl (srm->session_id), &srm->peer); +} + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls the 'struct GNUNET_ATS_SchedulingHandle' + * @param msg message received, NULL on timeout or fatal error + */ +static void +process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_ATS_SchedulingHandle *sh = cls; + const struct AddressSuggestionMessage *m; + const struct GNUNET_ATS_Information *atsi; + const char *plugin_address; + const char *plugin_name; + uint16_t plugin_address_length; + uint16_t plugin_name_length; + uint32_t ats_count; + struct GNUNET_HELLO_Address address; + struct Session *s; + + if (NULL == msg) + { + force_reconnect (sh); + return; + } + if ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE) && + (ntohs (msg->size) == sizeof (struct SessionReleaseMessage))) + { + process_release_message (sh, (const struct SessionReleaseMessage *) msg); + GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh, + GNUNET_TIME_UNIT_FOREVER_REL); + if (GNUNET_YES == sh->reconnect) + force_reconnect (sh); + return; + } + if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION) || + (ntohs (msg->size) <= sizeof (struct AddressSuggestionMessage))) + { + GNUNET_break (0); + force_reconnect (sh); + return; + } + m = (const struct AddressSuggestionMessage *) msg; + ats_count = ntohl (m->ats_count); + plugin_address_length = ntohs (m->address_length); + atsi = (const struct GNUNET_ATS_Information *) &m[1]; + plugin_address = (const char *) &atsi[ats_count]; + plugin_name = &plugin_address[plugin_address_length]; + plugin_name_length = ntohs (m->plugin_name_length); + if ((plugin_address_length + plugin_name_length + + ats_count * sizeof (struct GNUNET_ATS_Information) + + sizeof (struct AddressSuggestionMessage) != ntohs (msg->size)) || + (ats_count > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)) + || (plugin_name[plugin_name_length - 1] != '\0')) + { + GNUNET_break (0); + force_reconnect (sh); + return; + } + uint32_t session_id = ntohl (m->session_id); + + if (session_id == 0) + s = NULL; + else + { + s = find_session (sh, session_id, &m->peer); + if (s == NULL) + { +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "ATS tries to use outdated session `%s'\n", + GNUNET_i2s (&m->peer)); +#endif + GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh, + GNUNET_TIME_UNIT_FOREVER_REL); + return; + } + } + address.peer = m->peer; + address.address = plugin_address; + address.address_length = plugin_address_length; + address.transport_name = plugin_name; + + if ((s == NULL) && (0 == address.address_length)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "ATS returned invalid address for peer `%s' transport `%s' address length %i, session_id %i\n", + GNUNET_i2s (&address.peer), address.transport_name, + plugin_address_length, session_id); + GNUNET_break_op (0); + GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh, + GNUNET_TIME_UNIT_FOREVER_REL); + return; + } + + sh->suggest_cb (sh->suggest_cb_cls, &address, s, m->bandwidth_out, + m->bandwidth_in, atsi, ats_count); + + GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh, + GNUNET_TIME_UNIT_FOREVER_REL); + if (GNUNET_YES == sh->reconnect) + force_reconnect (sh); +} + + +/** + * Re-establish the connection to the ATS service. + * + * @param sh handle to use to re-connect. + */ +static void +reconnect (struct GNUNET_ATS_SchedulingHandle *sh) +{ + struct PendingMessage *p; + struct ClientStartMessage *init; + + GNUNET_assert (NULL == sh->client); + sh->client = GNUNET_CLIENT_connect ("ats", sh->cfg); + GNUNET_assert (NULL != sh->client); + if ((NULL == (p = sh->pending_head)) || (GNUNET_YES != p->is_init)) + { + p = GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct ClientStartMessage)); + p->size = sizeof (struct ClientStartMessage); + p->is_init = GNUNET_YES; + init = (struct ClientStartMessage *) &p[1]; + init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START); + init->header.size = htons (sizeof (struct ClientStartMessage)); + init->start_flag = htonl (START_FLAG_SCHEDULING); + GNUNET_CONTAINER_DLL_insert (sh->pending_head, sh->pending_tail, p); + } + do_transmit (sh); +} + +/** + * delete the current network list + */ + +static void +delete_networks (struct GNUNET_ATS_SchedulingHandle *sh) +{ + struct ATS_Network * cur = sh->net_head; + while (cur != NULL) + { + GNUNET_CONTAINER_DLL_remove(sh->net_head, sh->net_tail, cur); + GNUNET_free (cur); + cur = sh->net_head; + } +} + + +static int +interface_proc (void *cls, const char *name, + int isDefault, + const struct sockaddr * + addr, + const struct sockaddr * + broadcast_addr, + const struct sockaddr * + netmask, socklen_t addrlen) +{ + struct GNUNET_ATS_SchedulingHandle * sh = cls; + /* Calculate network */ + struct ATS_Network *net = NULL; + + /* Skipping IPv4 loopback addresses since we have special check */ + if (addr->sa_family == AF_INET) + { + struct sockaddr_in * a4 = (struct sockaddr_in *) addr; + + if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000)) + return GNUNET_OK; + } + /* Skipping IPv6 loopback addresses since we have special check */ + if (addr->sa_family == AF_INET6) + { + struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; + if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) + return GNUNET_OK; + } + + if (addr->sa_family == AF_INET) + { + struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; + struct sockaddr_in *netmask4 = (struct sockaddr_in *) netmask; + struct sockaddr_in *tmp = NULL; + struct sockaddr_in network4; + + net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in)); + tmp = (struct sockaddr_in *) &net[1]; + net->network = (struct sockaddr *) &tmp[0]; + net->netmask = (struct sockaddr *) &tmp[1]; + net->length = addrlen; + + memset (&network4, 0, sizeof (network4)); + network4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + network4.sin_len = sizeof (network4); +#endif + network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr); + + memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in)); + memcpy (net->network, &network4, sizeof (struct sockaddr_in)); + } + + if (addr->sa_family == AF_INET6) + { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; + struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) netmask; + struct sockaddr_in6 * tmp = NULL; + struct sockaddr_in6 network6; + + net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6)); + tmp = (struct sockaddr_in6 *) &net[1]; + net->network = (struct sockaddr *) &tmp[0]; + net->netmask = (struct sockaddr *) &tmp[1]; + net->length = addrlen; + + memset (&network6, 0, sizeof (network6)); + network6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + network6.sin6_len = sizeof (network6); +#endif + int c = 0; + uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr; + uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr; + uint32_t *net_elem = (uint32_t *) &network6.sin6_addr; + for (c = 0; c < 4; c++) + net_elem[c] = addr_elem[c] & mask_elem[c]; + + memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6)); + memcpy (net->network, &network6, sizeof (struct sockaddr_in6)); + } + + /* Store in list */ + if (net != NULL) + { +#if VERBOSE_ATS + char * netmask = GNUNET_strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding network `%s', netmask `%s'\n", + GNUNET_a2s((struct sockaddr *) net->network, addrlen), + netmask); + GNUNET_free (netmask); +# endif + GNUNET_CONTAINER_DLL_insert(sh->net_head, sh->net_tail, net); + } + return GNUNET_OK; +} + + + +/** + * Periodically get list of addresses + * @param cls closure + * @param tc Task context + */ +static void +get_addresses (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_ATS_SchedulingHandle * sh = cls; + sh->interface_task = GNUNET_SCHEDULER_NO_TASK; + delete_networks (sh); + GNUNET_OS_network_interfaces_list(interface_proc, sh); + sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVALL, + get_addresses, + sh); +} + +/** + * Returns where the address is located: LAN or WAN or ... + * @param sh the scheduling handle + * @param addr address + * @param addrlen address length + * @return location as GNUNET_ATS_Information + */ + +const struct GNUNET_ATS_Information +GNUNET_ATS_address_get_type (struct GNUNET_ATS_SchedulingHandle * sh, const struct sockaddr * addr, socklen_t addrlen) +{ + GNUNET_assert (sh != NULL); + struct GNUNET_ATS_Information ats; + struct ATS_Network * cur = sh->net_head; + int type = GNUNET_ATS_NET_UNSPECIFIED; + + if (addr->sa_family == AF_UNIX) + { + type = GNUNET_ATS_NET_LOOPBACK; + } + + /* IPv4 loopback check */ + if (addr->sa_family == AF_INET) + { + struct sockaddr_in * a4 = (struct sockaddr_in *) addr; + + if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000)) + type = GNUNET_ATS_NET_LOOPBACK; + } + /* IPv6 loopback check */ + if (addr->sa_family == AF_INET6) + { + struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; + if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) + type = GNUNET_ATS_NET_LOOPBACK; + } + + /* Check local networks */ + while ((cur != NULL) && (type == GNUNET_ATS_NET_UNSPECIFIED)) + { + if (addrlen != cur->length) + { + cur = cur->next; + continue; + } + + if (addr->sa_family == AF_INET) + { + struct sockaddr_in * a4 = (struct sockaddr_in *) addr; + struct sockaddr_in * net4 = (struct sockaddr_in *) cur->network; + struct sockaddr_in * mask4 = (struct sockaddr_in *) cur->netmask; + + if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) == net4->sin_addr.s_addr) + { + char * net = GNUNET_strdup (GNUNET_a2s ((const struct sockaddr *) net4, addrlen)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n", + GNUNET_a2s ((const struct sockaddr *)a4, addrlen), + net); + GNUNET_free (net); + type = GNUNET_ATS_NET_LAN; + } + } + if (addr->sa_family == AF_INET6) + { + struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; + struct sockaddr_in6 * net6 = (struct sockaddr_in6 *) cur->network; + struct sockaddr_in6 * mask6 = (struct sockaddr_in6 *) cur->netmask; + + int res = GNUNET_YES; + int c = 0; + uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr; + uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr; + uint32_t *net_elem = (uint32_t *) &net6->sin6_addr; + for (c = 0; c < 4; c++) + if ((addr_elem[c] & mask_elem[c]) != net_elem[c]) + res = GNUNET_NO; + + if (res == GNUNET_YES) + { + char * net = GNUNET_strdup (GNUNET_a2s ((const struct sockaddr *) net6, addrlen)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n", + GNUNET_a2s ((const struct sockaddr *) a6, addrlen), + net); + GNUNET_free (net); + type = GNUNET_ATS_NET_LAN; + } + } + cur = cur->next; + } + + /* no local network found for this address, default: WAN */ + if (type == GNUNET_ATS_NET_UNSPECIFIED) + type = GNUNET_ATS_NET_WAN; + +#if VERBOSE + const char * range; + switch (type) { + case GNUNET_ATS_NET_WAN: + range = "WAN"; + break; + case GNUNET_ATS_NET_LAN: + range = "LAN"; + break; + case GNUNET_ATS_NET_LOOPBACK: + range = "LOOPBACK"; + break; + default: + + break; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "`%s' is in network `%s'\n", + GNUNET_a2s ((const struct sockaddr *) addr, addrlen), + range); +#endif + + ats.type = htonl (GNUNET_ATS_NETWORK_TYPE); + ats.value = htonl (type); + return (const struct GNUNET_ATS_Information) ats; +} + +/** + * Initialize the ATS subsystem. + * + * @param cfg configuration to use + * @param suggest_cb notification to call whenever the suggestation changed + * @param suggest_cb_cls closure for 'suggest_cb' + * @return ats context + */ +struct GNUNET_ATS_SchedulingHandle * +GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_ATS_AddressSuggestionCallback suggest_cb, + void *suggest_cb_cls) +{ + struct GNUNET_ATS_SchedulingHandle *sh; + + sh = GNUNET_malloc (sizeof (struct GNUNET_ATS_SchedulingHandle)); + sh->cfg = cfg; + sh->suggest_cb = suggest_cb; + sh->suggest_cb_cls = suggest_cb_cls; + GNUNET_array_grow (sh->session_array, sh->session_array_size, 4); + GNUNET_OS_network_interfaces_list(interface_proc, sh); + sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVALL, + get_addresses, + sh); + reconnect (sh); + return sh; +} + + +/** + * Client is done with ATS scheduling, release resources. + * + * @param sh handle to release + */ +void +GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh) +{ + struct PendingMessage *p; + + while (NULL != (p = sh->pending_head)) + { + GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p); + GNUNET_free (p); + } + if (NULL != sh->client) + { + GNUNET_CLIENT_disconnect (sh->client, GNUNET_NO); + sh->client = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != sh->task) + { + GNUNET_SCHEDULER_cancel (sh->task); + sh->task = GNUNET_SCHEDULER_NO_TASK; + } + + delete_networks (sh); + if (sh->interface_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel(sh->interface_task); + sh->interface_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_array_grow (sh->session_array, sh->session_array_size, 0); + GNUNET_free (sh); + sh = NULL; +} + + +/** + * We would like to establish a new connection with a peer. ATS + * should suggest a good address to begin with. + * + * @param sh handle + * @param peer identity of the peer we need an address for + */ +void +GNUNET_ATS_suggest_address (struct GNUNET_ATS_SchedulingHandle *sh, + const struct GNUNET_PeerIdentity *peer) +{ + struct PendingMessage *p; + struct RequestAddressMessage *m; + + p = GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct RequestAddressMessage)); + p->size = sizeof (struct RequestAddressMessage); + p->is_init = GNUNET_NO; + m = (struct RequestAddressMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS); + m->header.size = htons (sizeof (struct RequestAddressMessage)); + m->reserved = htonl (0); + m->peer = *peer; + GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); + do_transmit (sh); +} + + +/** + * We would like to stop receiving address updates for this peer + * + * @param sh handle + * @param peer identity of the peer + */ +void +GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SchedulingHandle *sh, + const struct GNUNET_PeerIdentity *peer) +{ + struct PendingMessage *p; + struct RequestAddressMessage *m; + + p = GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct RequestAddressMessage)); + p->size = sizeof (struct RequestAddressMessage); + p->is_init = GNUNET_NO; + m = (struct RequestAddressMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL); + m->header.size = htons (sizeof (struct RequestAddressMessage)); + m->reserved = htonl (0); + m->peer = *peer; + GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); + do_transmit (sh); +} + +/** + * We have updated performance statistics for a given address. Note + * that this function can be called for addresses that are currently + * in use as well as addresses that are valid but not actively in use. + * Furthermore, the peer may not even be connected to us right now (in + * which case the call may be ignored or the information may be stored + * for later use). Update bandwidth assignments. + * + * @param sh handle + * @param address the address + * @param session session handle (if available) + * @param ats performance data for the address + * @param ats_count number of performance records in 'ats' + */ +void +GNUNET_ATS_address_update (struct GNUNET_ATS_SchedulingHandle *sh, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) +{ + struct PendingMessage *p; + struct AddressUpdateMessage *m; + struct GNUNET_ATS_Information *am; + char *pm; + size_t namelen; + size_t msize; + + if (address == NULL) + { + GNUNET_break (0); + return; + } + if ((address == NULL) && (session == NULL)) + { + GNUNET_break (0); + return; + } + + namelen = + (address->transport_name == + NULL) ? 0 : strlen (address->transport_name) + 1; + msize = + sizeof (struct AddressUpdateMessage) + address->address_length + + ats_count * sizeof (struct GNUNET_ATS_Information) + namelen; + if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || + (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || + (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || + (ats_count >= + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))) + { + GNUNET_break (0); + return; + } + + p = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + p->size = msize; + p->is_init = GNUNET_NO; + m = (struct AddressUpdateMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE); + m->header.size = htons (msize); + m->ats_count = htonl (ats_count); + m->peer = address->peer; + m->address_length = htons (address->address_length); + m->plugin_name_length = htons (namelen); + m->session_id = htonl (get_session_id (sh, session, &address->peer)); + am = (struct GNUNET_ATS_Information *) &m[1]; + memcpy (am, ats, ats_count * sizeof (struct GNUNET_ATS_Information)); + pm = (char *) &am[ats_count]; + memcpy (pm, address->address, address->address_length); + memcpy (&pm[address->address_length], address->transport_name, namelen); + GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); + do_transmit (sh); +} + + +/** + * An address is now in use or not used any more. + * + * @param sh handle + * @param address the address + * @param session session handle + * @param in_use GNUNET_YES if this address is now used, GNUNET_NO + * if address is not used any more + */ +void +GNUNET_ATS_address_in_use (struct GNUNET_ATS_SchedulingHandle *sh, + const struct GNUNET_HELLO_Address *address, + struct Session *session, int in_use) +{ + struct PendingMessage *p; + struct AddressUseMessage *m; + char *pm; + size_t namelen; + size_t msize; + + GNUNET_assert (NULL != address); + namelen = + (address->transport_name == + NULL) ? 0 : strlen (address->transport_name) + 1; + msize = sizeof (struct AddressUseMessage) + address->address_length + namelen; + if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || + (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || + (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) + { + GNUNET_break (0); + return; + } + + p = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + p->size = msize; + p->is_init = GNUNET_NO; + m = (struct AddressUseMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE); + m->header.size = htons (msize); + m->peer = address->peer; + m->in_use = htons (in_use); + m->address_length = htons (address->address_length); + m->plugin_name_length = htons (namelen); + m->session_id = htonl (get_session_id (sh, session, &address->peer)); + pm = (char *) &m[1]; + memcpy (pm, address->address, address->address_length); + memcpy (&pm[address->address_length], address->transport_name, namelen); + GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); + + do_transmit (sh); +} + +/** + * A session got destroyed, stop including it as a valid address. + * + * @param sh handle + * @param address the address + * @param session session handle that is no longer valid + */ +void +GNUNET_ATS_address_destroyed (struct GNUNET_ATS_SchedulingHandle *sh, + const struct GNUNET_HELLO_Address *address, + struct Session *session) +{ + struct PendingMessage *p; + struct AddressDestroyedMessage *m; + char *pm; + size_t namelen; + size_t msize; + uint32_t session_id; + + GNUNET_assert (address->transport_name != NULL); + namelen = strlen (address->transport_name) + 1; + GNUNET_assert (namelen > 1); + msize = + sizeof (struct AddressDestroyedMessage) + address->address_length + + namelen; + if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || + (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || + (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) + { + GNUNET_break (0); + return; + } + + p = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + p->size = msize; + p->is_init = GNUNET_NO; + m = (struct AddressDestroyedMessage *) &p[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED); + m->header.size = htons (msize); + m->reserved = htonl (0); + m->peer = address->peer; + m->address_length = htons (address->address_length); + m->plugin_name_length = htons (namelen); + session_id = get_session_id (sh, session, &address->peer); + m->session_id = htonl (session_id); + pm = (char *) &m[1]; + memcpy (pm, address->address, address->address_length); + memcpy (&pm[address->address_length], address->transport_name, namelen); + GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); + do_transmit (sh); + remove_session (sh, session_id, &address->peer); +} + +/* end of ats_api_scheduling.c */ diff --git a/src/ats/gnunet-service-ats.c b/src/ats/gnunet-service-ats.c new file mode 100644 index 0000000..7deca0b --- /dev/null +++ b/src/ats/gnunet-service-ats.c @@ -0,0 +1,182 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats.c + * @brief ats service + * @author Matthias Wachs + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_ats_service.h" +#include "gnunet-service-ats.h" +#include "gnunet-service-ats_addresses.h" +#include "gnunet-service-ats_performance.h" +#include "gnunet-service-ats_scheduling.h" +#include "gnunet-service-ats_reservations.h" +#include "ats.h" + +/** + * Handle for statistics. + */ +struct GNUNET_STATISTICS_Handle *GSA_stats; + +/** + * We have received a 'ClientStartMessage' from a client. Find out which + * type of client it is and notify the respective subsystem. + * + * @param cls closure, unused + * @param client handle to the client + * @param message the start message + */ +static void +handle_ats_start (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct ClientStartMessage *msg = + (const struct ClientStartMessage *) message; + enum StartFlag flag; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ATS_START"); + flag = ntohl (msg->start_flag); + switch (flag) + { + case START_FLAG_SCHEDULING: + if (GNUNET_OK != GAS_scheduling_add_client (client)) + { + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + break; + case START_FLAG_PERFORMANCE_WITH_PIC: + GAS_performance_add_client (client, flag); + break; + case START_FLAG_PERFORMANCE_NO_PIC: + GAS_performance_add_client (client, flag); + break; + default: + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * A client disconnected from us. Tear down the local client + * record. + * + * @param cls unused + * @param client handle of the client + */ +static void +client_disconnect_handler (void *cls, struct GNUNET_SERVER_Client *client) +{ + if (NULL == client) + return; + GAS_scheduling_remove_client (client); + GAS_performance_remove_client (client); +} + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GAS_addresses_done (); + GAS_scheduling_done (); + GAS_performance_done (); + GAS_reservations_done (); + if (NULL != GSA_stats) + { + GNUNET_STATISTICS_destroy (GSA_stats, GNUNET_NO); + GSA_stats = NULL; + } +} + + +/** + * Process template requests. + * + * @param cls closure + * @param server the initialized server + * @param cfg configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_ats_start, NULL, + GNUNET_MESSAGE_TYPE_ATS_START, sizeof (struct ClientStartMessage)}, + {&GAS_handle_request_address, NULL, + GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS, + sizeof (struct RequestAddressMessage)}, + {&GAS_handle_request_address_cancel, NULL, + GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL, + sizeof (struct RequestAddressMessage)}, + {&GAS_handle_address_update, NULL, + GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE, 0}, + {&GAS_handle_address_in_use, NULL, + GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE, 0}, + {&GAS_handle_address_destroyed, NULL, + GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED, 0}, + {&GAS_handle_reservation_request, NULL, + GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST, + sizeof (struct ReservationRequestMessage)}, + {&GAS_handle_preference_change, NULL, + GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE, 0}, + {NULL, NULL, 0, 0} + }; + GSA_stats = GNUNET_STATISTICS_create ("ats", cfg); + GAS_reservations_init (); + GAS_performance_init (server); + GAS_scheduling_init (server); + GAS_addresses_init (cfg, GSA_stats); + GNUNET_SERVER_disconnect_notify (server, &client_disconnect_handler, NULL); + GNUNET_SERVER_add_handlers (server, handlers); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, + NULL); +} + + +/** + * The main function for the ats service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "ats", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-service-ats.c */ diff --git a/src/ats/gnunet-service-ats.h b/src/ats/gnunet-service-ats.h new file mode 100644 index 0000000..b60332d --- /dev/null +++ b/src/ats/gnunet-service-ats.h @@ -0,0 +1,38 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats.h + * @brief ats service + * @author Matthias Wachs + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_ATS_H +#define GNUNET_SERVICE_ATS_H + +#include "gnunet_statistics_service.h" + +/** + * Handle for statistics. + */ +extern struct GNUNET_STATISTICS_Handle *GSA_stats; + + +#endif diff --git a/src/ats/gnunet-service-ats_addresses.c b/src/ats/gnunet-service-ats_addresses.c new file mode 100644 index 0000000..fb9bad0 --- /dev/null +++ b/src/ats/gnunet-service-ats_addresses.c @@ -0,0 +1,805 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats_addresses.c + * @brief ats service address management + * @author Matthias Wachs + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_ats_service.h" +#include "gnunet-service-ats.h" +#include "gnunet-service-ats_addresses.h" +#include "gnunet-service-ats_performance.h" +#include "gnunet-service-ats_scheduling.h" +#include "gnunet-service-ats_reservations.h" +#if HAVE_LIBGLPK +#include "gnunet-service-ats_addresses_mlp.h" +#endif + +#define VERBOSE GNUNET_NO + +enum ATS_Mode +{ + /* + * Assign each peer an equal amount of bandwidth (bw) + * + * bw_per_peer = bw_total / #active addresses + */ + SIMPLE, + + /* + * Use MLP solver to assign bandwidth + */ + MLP +}; + +static struct GNUNET_CONTAINER_MultiHashMap *addresses; + +#if HAVE_LIBGLPK +static struct GAS_MLP_Handle *mlp; +#endif + +static unsigned long long wan_quota_in; + +static unsigned long long wan_quota_out; + +static unsigned int active_addr_count; + +static int ats_mode; + + +/** + * Update a bandwidth assignment for a peer. This trivial method currently + * simply assigns the same share to all active connections. + * + * @param cls unused + * @param key unused + * @param value the 'struct ATS_Address' + * @return GNUNET_OK (continue to iterate) + */ +static int +update_bw_simple_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ATS_Address *aa = value; + + if (GNUNET_YES != aa->active) + return GNUNET_OK; + GNUNET_assert (active_addr_count > 0); + + + /* Simple method */ + aa->assigned_bw_in.value__ = htonl (wan_quota_in / active_addr_count); + aa->assigned_bw_out.value__ = htonl (wan_quota_out / active_addr_count); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New bandwidth for peer %s is %u/%u\n", + GNUNET_i2s (&aa->peer), ntohl (aa->assigned_bw_in.value__), + ntohl (aa->assigned_bw_out.value__)); + GAS_scheduling_transmit_address_suggestion (&aa->peer, aa->plugin, aa->addr, + aa->addr_len, aa->session_id, + aa->ats, aa->ats_count, + aa->assigned_bw_out, + aa->assigned_bw_in); + GAS_reservations_set_bandwidth (&aa->peer, aa->assigned_bw_in); + GAS_performance_notify_clients (&aa->peer, aa->plugin, aa->addr, aa->addr_len, + aa->ats, aa->ats_count, aa->assigned_bw_out, + aa->assigned_bw_in); + return GNUNET_OK; +} + + +/** + * Some (significant) input changed, recalculate bandwidth assignment + * for all peers. + */ +static void +recalculate_assigned_bw () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Recalculating bandwidth for all active connections\n"); + GNUNET_STATISTICS_update (GSA_stats, "# bandwidth recalculations performed", + 1, GNUNET_NO); + GNUNET_STATISTICS_set (GSA_stats, "# active addresses", active_addr_count, + GNUNET_NO); + + GNUNET_CONTAINER_multihashmap_iterate (addresses, &update_bw_simple_it, NULL); +} + +/** + * Free the given address + * @param addr address to destroy + */ +static void +free_address (struct ATS_Address *addr) +{ + GNUNET_free_non_null (addr->ats); + GNUNET_free (addr->plugin); + GNUNET_free (addr); +} + +/** + * Create a ATS_address with the given information + * @param peer peer + * @param plugin_name plugin + * @param plugin_addr address + * @param plugin_addr_len address length + * @param session_id session + * @return the ATS_Address + */ +static struct ATS_Address * +create_address (const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, + const void *plugin_addr, size_t plugin_addr_len, + uint32_t session_id) +{ + struct ATS_Address *aa = NULL; + + aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len); + aa->peer = *peer; + aa->addr_len = plugin_addr_len; + aa->addr = &aa[1]; + memcpy (&aa[1], plugin_addr, plugin_addr_len); + aa->plugin = GNUNET_strdup (plugin_name); + aa->session_id = session_id; + aa->mlp_information = NULL; + aa->next = NULL; + aa->prev = NULL; + return aa; +} + + +/** + * Destroy the given address. + * + * @param addr address to destroy + * @return GNUNET_YES if bandwidth allocations should be recalcualted + */ +static int +destroy_address (struct ATS_Address *addr) +{ + int ret; + + ret = GNUNET_NO; + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (addresses, + &addr->peer.hashPubKey, + addr)); + +#if HAVE_LIBGLPK + if (ats_mode == MLP) + GAS_mlp_address_delete (mlp, addresses, addr); +#endif + + if (GNUNET_YES == addr->active) + { + active_addr_count--; + addr->active = GNUNET_NO; + ret = GNUNET_YES; + } + free_address (addr); + return ret; +} + + +struct CompareAddressContext +{ + const struct ATS_Address *search; + + /* exact_address != NULL if address and session is equal */ + struct ATS_Address *exact_address; + /* exact_address != NULL if address and session is 0 */ + struct ATS_Address *base_address; +}; + + +static int +compare_address_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct CompareAddressContext *cac = cls; + struct ATS_Address *aa = value; +/* + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Comparing to: %s %s %u session %u\n", + GNUNET_i2s (&aa->peer), aa->plugin, aa->addr_len, aa->session_id); + +*/ + /* find an exact matching address: aa->addr == cac->search->addr && aa->session == cac->search->session */ + if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin))) + { + if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id)) + { + cac->exact_address = aa; + } + } + + /* find an matching address: aa->addr == cac->search->addr && aa->session == 0 */ + /* this address can be used to be updated */ + if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin))) + { + if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == 0)) + { + cac->base_address = aa; + } + } + + if (cac->exact_address == NULL) + return GNUNET_YES; + else + return GNUNET_NO; +} + + +/** + * Find an existing equivalent address record. + * Compares by peer identity and network address OR by session ID + * (one of the two must match). + * + * @param peer peer to lookup addresses for + * @param addr existing address record + * @return existing address record, NULL for none + */ +struct ATS_Address * +find_address (const struct GNUNET_PeerIdentity *peer, + const struct ATS_Address *addr) +{ + struct CompareAddressContext cac; + + cac.exact_address = NULL; + cac.base_address = NULL; + cac.search = addr; + GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, + &compare_address_it, &cac); + +/* + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "exact address: %s base address: %s\n", + (cac.exact_address != NULL) ? "YES" : "NO", + (cac.base_address != NULL) ? "YES" : "NO"); +*/ + if (cac.exact_address == NULL) + return cac.base_address; + return cac.exact_address; +} + + +static int +compare_address_session_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct CompareAddressContext *cac = cls; + struct ATS_Address *aa = value; + + if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin))) + { + if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id)) + { + cac->exact_address = aa; + return GNUNET_NO; + } + } + return GNUNET_YES; +} + + +/** + * Find an existing equivalent address record. + * Compares by peer identity and network address AND by session ID + * (one of the two must match). + * + * @param peer peer to lookup addresses for + * @param addr existing address record + * @return existing address record, NULL for none + */ +struct ATS_Address * +find_exact_address (const struct GNUNET_PeerIdentity *peer, + const struct ATS_Address *addr) +{ + struct CompareAddressContext cac; + + cac.exact_address = NULL; + cac.search = addr; + GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, + &compare_address_session_it, &cac); + return cac.exact_address; +} + + +void +GAS_addresses_update (const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, const void *plugin_addr, + size_t plugin_addr_len, uint32_t session_id, + const struct GNUNET_ATS_Information *atsi, + uint32_t atsi_count) +{ + struct ATS_Address *aa; + struct ATS_Address *old; + uint32_t i; + + aa = create_address (peer, + plugin_name, + plugin_addr, plugin_addr_len, + session_id); + + aa->mlp_information = NULL; + aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information)); + aa->ats_count = atsi_count; + memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information)); + +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' %u\n", + GNUNET_i2s (peer), + session_id); +#endif + /* Get existing address or address with session == 0 */ + old = find_address (peer, aa); + if (old == NULL) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (addresses, + &peer->hashPubKey, aa, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' %X\n", + GNUNET_i2s (peer), aa); +#endif + old = aa; + } + else + { +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Updated existing address for peer `%s' %p old session %u new session %u\n", + GNUNET_i2s (peer), old, + old->session_id, session_id); +#endif + GNUNET_free_non_null (old->ats); + old->session_id = session_id; + old->ats = NULL; + old->ats_count = 0; + old->ats = aa->ats; + old->ats_count = aa->ats_count; + GNUNET_free (aa->plugin); + GNUNET_free (aa); + } + for (i = 0; i < atsi_count; i++) + switch (ntohl (atsi[i].type)) + { + case GNUNET_ATS_UTILIZATION_UP: + old->atsp_utilization_out.value__ = atsi[i].value; + break; + case GNUNET_ATS_UTILIZATION_DOWN: + old->atsp_utilization_in.value__ = atsi[i].value; + break; + case GNUNET_ATS_QUALITY_NET_DELAY: + old->atsp_latency.rel_value = ntohl (atsi[i].value); + break; + case GNUNET_ATS_QUALITY_NET_DISTANCE: + old->atsp_distance = ntohl (atsi[i].value); + break; + case GNUNET_ATS_COST_WAN: + old->atsp_cost_wan = ntohl (atsi[i].value); + break; + case GNUNET_ATS_COST_LAN: + old->atsp_cost_lan = ntohl (atsi[i].value); + break; + case GNUNET_ATS_COST_WLAN: + old->atsp_cost_wlan = ntohl (atsi[i].value); + break; + case GNUNET_ATS_NETWORK_TYPE: + old->atsp_network_type = ntohl (atsi[i].value); + break; + + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Received unsupported ATS type %u\n", ntohl (atsi[i].type)); + GNUNET_break (0); + break; + } +#if HAVE_LIBGLPK + if (ats_mode == MLP) + GAS_mlp_address_update (mlp, addresses, old); +#endif +} + + +/** + * Delete an address + * + * If session != 0, just the session is deleted, the address itself still exists + * If session == 0, remove full address + * If session == 0 and addrlen == 0, destroy inbound address + * + * @param cls unused + * @param key unused + * @param value the 'struct ATS_Address' + * @return GNUNET_OK (continue to iterate) + */ +static int +destroy_by_session_id (void *cls, const GNUNET_HashCode * key, void *value) +{ + const struct ATS_Address *info = cls; + struct ATS_Address *aa = value; + + GNUNET_assert (0 == + memcmp (&aa->peer, &info->peer, + sizeof (struct GNUNET_PeerIdentity))); + /* session == 0, remove full address */ + if ((info->session_id == 0) && (0 == strcmp (info->plugin, aa->plugin)) && + (aa->addr_len == info->addr_len) && + (0 == memcmp (info->addr, aa->addr, aa->addr_len))) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Deleting address for peer `%s': `%s' %u\n", + GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id); +#endif + if (GNUNET_YES == destroy_address (aa)) + recalculate_assigned_bw (); + return GNUNET_OK; + } + /* session != 0, just remove session */ + if (aa->session_id != info->session_id) + return GNUNET_OK; /* irrelevant */ + if (aa->session_id != 0) + GNUNET_break (0 == strcmp (info->plugin, aa->plugin)); + /* session died */ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Deleting session for peer `%s': `%s' %u\n", + GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id); +#endif + aa->session_id = 0; + + if (GNUNET_YES == aa->active) + { + aa->active = GNUNET_NO; + active_addr_count--; + recalculate_assigned_bw (); + } + + /* session == 0 and addrlen == 0 : destroy address */ + if (aa->addr_len == 0) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Deleting session and address for peer `%s': `%s' %u\n", + GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id); +#endif + (void) destroy_address (aa); + } + else + { + /* session was set to 0, update address */ +#if HAVE_LIBGLPK + if (ats_mode == MLP) + GAS_mlp_address_update (mlp, addresses, aa); +#endif + } + + return GNUNET_OK; +} + +void +GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, const void *plugin_addr, + size_t plugin_addr_len, uint32_t session_id) +{ + struct ATS_Address *aa; + + GNUNET_break (0 < strlen (plugin_name)); + aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id); + + GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, + &destroy_by_session_id, aa); + + free_address (aa); +} + + +/** + * Find a "good" address to use for a peer. If we already have an existing + * address, we stick to it. Otherwise, we pick by lowest distance and then + * by lowest latency. + * + * @param cls the 'struct ATS_Address**' where we store the result + * @param key unused + * @param value another 'struct ATS_Address*' to consider using + * @return GNUNET_OK (continue to iterate) + */ +static int +find_address_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ATS_Address **ap = cls; + struct ATS_Address *aa = (struct ATS_Address *) value; + struct ATS_Address *ab = *ap; + + if (NULL == ab) + { + *ap = aa; + return GNUNET_OK; + } + if ((ntohl (ab->assigned_bw_in.value__) == 0) && + (ntohl (aa->assigned_bw_in.value__) > 0)) + { + /* stick to existing connection */ + *ap = aa; + return GNUNET_OK; + } + if (ab->atsp_distance > aa->atsp_distance) + { + /* user shorter distance */ + *ap = aa; + return GNUNET_OK; + } + if (ab->atsp_latency.rel_value > aa->atsp_latency.rel_value) + { + /* user lower latency */ + *ap = aa; + return GNUNET_OK; + } + /* don't care */ + return GNUNET_OK; +} + + +void +GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, const void *plugin_addr, + size_t plugin_addr_len, uint32_t session_id, int in_use) +{ +#if DEBUG_ATS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received `%s' message for peer `%s': %i\n", "ADDRESS_IN_USE", + GNUNET_i2s (peer), in_use); +#endif + + struct ATS_Address *aa; + struct ATS_Address *old; + + + aa = create_address(peer, plugin_name, plugin_addr, plugin_addr_len, session_id); + old = find_exact_address (peer, aa); + free_address (aa); + + GNUNET_assert (old != NULL); + GNUNET_assert (old->used != in_use); + old->used = in_use; + +#if HAVE_LIBGLPK + if (ats_mode == MLP) + GAS_mlp_address_update (mlp, addresses, old); +#endif +} + + +void request_address_mlp (const struct GNUNET_PeerIdentity *peer) +{ + struct ATS_Address *aa; + aa = NULL; + +#if HAVE_GLPK + /* Get preferred address from MLP */ + struct ATS_PreferedAddress * paddr = NULL; + paddr = GAS_mlp_get_preferred_address (mlp, addresses, peer); + aa = paddr->address; + aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init(paddr->bandwidth_out); + /* FIXME use bw in value */ + paddr->bandwidth_in = paddr->bandwidth_out; + aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init (paddr->bandwidth_in); + GNUNET_free (paddr); +#endif + + if (aa == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer)); + return; + } + if (aa->active == GNUNET_NO) + { + aa->active = GNUNET_YES; + active_addr_count++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New bandwidth for peer %s is %u/%u\n", + GNUNET_i2s (&aa->peer), ntohl (aa->assigned_bw_in.value__), + ntohl (aa->assigned_bw_out.value__)); + GAS_scheduling_transmit_address_suggestion (&aa->peer, aa->plugin, aa->addr, + aa->addr_len, aa->session_id, + aa->ats, aa->ats_count, + aa->assigned_bw_out, + aa->assigned_bw_in); + GAS_reservations_set_bandwidth (&aa->peer, aa->assigned_bw_in); + GAS_performance_notify_clients (&aa->peer, aa->plugin, aa->addr, aa->addr_len, + aa->ats, aa->ats_count, aa->assigned_bw_out, + aa->assigned_bw_in); + } + else + { + /* just to be sure... */ + GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr, + aa->addr_len, aa->session_id, + aa->ats, aa->ats_count, + aa->assigned_bw_out, + aa->assigned_bw_in); + } + +} + +void request_address_simple (const struct GNUNET_PeerIdentity *peer) +{ + struct ATS_Address *aa; + aa = NULL; + + /* Get address with: stick to current address, lower distance, lower latency */ + GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, + &find_address_it, &aa); + if (aa == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer)); + return; + } + + if (aa->active == GNUNET_NO) + { + aa->active = GNUNET_YES; + active_addr_count++; + if (ats_mode == SIMPLE) + { + recalculate_assigned_bw (); + } + } + else + { + /* just to be sure... */ + GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr, + aa->addr_len, aa->session_id, + aa->ats, aa->ats_count, + aa->assigned_bw_out, + aa->assigned_bw_in); + } +} + + +void +GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer) +{ + if (ats_mode == SIMPLE) + { + request_address_simple (peer); + } + if (ats_mode == MLP) + { + request_address_mlp(peer); + } +} + + +// FIXME: this function should likely end up in the LP-subsystem and +// not with 'addresses' in the future... +void +GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer, + enum GNUNET_ATS_PreferenceKind kind, + float score) +{ +#if HAVE_LIBGLPK + if (ats_mode == MLP) + GAS_mlp_address_change_preference (mlp, peer, kind, score); +#endif +} + + + +/** + * Initialize address subsystem. + * + * @param cfg configuration to use + * @param stats the statistics handle to use + */ +void +GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_STATISTICS_Handle *stats) +{ + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_size (cfg, "ats", + "WAN_QUOTA_IN", + &wan_quota_in)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_size (cfg, "ats", + "WAN_QUOTA_OUT", + &wan_quota_out)); + + switch (GNUNET_CONFIGURATION_get_value_yesno (cfg, "ats", "MLP")) + { + /* MLP = YES */ + case GNUNET_YES: +#if HAVE_LIBGLPK + ats_mode = MLP; + /* Init the MLP solver with default values */ + mlp = GAS_mlp_init (cfg, stats, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS); + break; +#else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP mode was configured, but libglpk is not installed, switching to simple mode"); + ats_mode = SIMPLE; + break; +#endif + /* MLP = NO */ + case GNUNET_NO: + ats_mode = SIMPLE; + break; + /* No configuration value */ + case GNUNET_SYSERR: + ats_mode = SIMPLE; + break; + default: + break; + } + + addresses = GNUNET_CONTAINER_multihashmap_create (128); +} + + +/** + * Free memory of address. + * + * @param cls NULL + * @param key peer identity (unused) + * @param value the 'struct ATS_Address' to free + * @return GNUNET_OK (continue to iterate) + */ +static int +free_address_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ATS_Address *aa = value; + + destroy_address (aa); + return GNUNET_OK; +} + + +void +GAS_addresses_destroy_all () +{ + if (addresses != NULL) + GNUNET_CONTAINER_multihashmap_iterate (addresses, &free_address_it, NULL); + GNUNET_assert (active_addr_count == 0); +} + + +/** + * Shutdown address subsystem. + */ +void +GAS_addresses_done () +{ + GAS_addresses_destroy_all (); + GNUNET_CONTAINER_multihashmap_destroy (addresses); + addresses = NULL; +#if HAVE_LIBGLPK + if (ats_mode == MLP) + { + GAS_mlp_done (mlp); + } +#endif + +} + + +/* end of gnunet-service-ats_addresses.c */ diff --git a/src/ats/gnunet-service-ats_addresses.h b/src/ats/gnunet-service-ats_addresses.h new file mode 100644 index 0000000..33ff586 --- /dev/null +++ b/src/ats/gnunet-service-ats_addresses.h @@ -0,0 +1,151 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats_addresses.h + * @brief ats service address management + * @author Matthias Wachs + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_ATS_ADDRESSES_H +#define GNUNET_SERVICE_ATS_ADDRESSES_H + +#include "gnunet_util_lib.h" +#include "gnunet_ats_service.h" +#include "gnunet_statistics_service.h" +#include "ats.h" + +struct ATS_Address +{ + struct ATS_Address *next; + + struct ATS_Address *prev; + + struct GNUNET_PeerIdentity peer; + + size_t addr_len; + + uint32_t session_id; + + uint32_t ats_count; + + const void *addr; + + char *plugin; + + void *mlp_information; + + struct GNUNET_ATS_Information *ats; + + struct GNUNET_TIME_Relative atsp_latency; + + struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_in; + + struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_out; + + uint32_t atsp_distance; + + uint32_t atsp_cost_wan; + + uint32_t atsp_cost_lan; + + uint32_t atsp_cost_wlan; + + uint32_t atsp_network_type; + + struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_in; + + struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_out; + + /** + * Is this the active address for this peer? + */ + int active; + + /** + * Is this the address for this peer in use? + */ + int used; +}; + +/** + * Initialize address subsystem. + * + * @param cfg configuration to use + * @param stats the statistics handle to use + */ +void +GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_STATISTICS_Handle *stats); + + +/** + * Shutdown address subsystem. + */ +void +GAS_addresses_done (void); + +/** + * This address is now used or not used anymore + */ +void +GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, const void *plugin_addr, + size_t plugin_addr_len, uint32_t session_id, int in_use); + +void +GAS_addresses_update (const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, const void *plugin_addr, + size_t plugin_addr_len, uint32_t session_id, + const struct GNUNET_ATS_Information *atsi, + uint32_t atsi_count); + + +void +GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, const void *plugin_addr, + size_t plugin_addr_len, uint32_t session_id); + + +void +GAS_addresses_destroy_all (void); + + +// FIXME: this function should likely end up in the LP-subsystem and +// not with 'addresses' in the future... +// Note: this call should trigger an address suggestion +// (GAS_scheduling_transmit_address_suggestion) +void +GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer); + + +// FIXME: this function should likely end up in the LP-subsystem and +// not with 'addresses' in the future... +void +GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer, + enum GNUNET_ATS_PreferenceKind kind, + float score); + + +/* FIXME: add performance request API */ + +#endif + +/* end of gnunet-service-ats_addresses.h */ diff --git a/src/ats/gnunet-service-ats_addresses_mlp.c b/src/ats/gnunet-service-ats_addresses_mlp.c new file mode 100644 index 0000000..61aa733 --- /dev/null +++ b/src/ats/gnunet-service-ats_addresses_mlp.c @@ -0,0 +1,1736 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats_addresses_mlp.c + * @brief ats mlp problem solver + * @author Matthias Wachs + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet-service-ats_addresses.h" +#include "gnunet-service-ats_addresses_mlp.h" +#include "gnunet_statistics_service.h" +#include "glpk.h" + +#define WRITE_MLP GNUNET_NO +#define DEBUG_ATS GNUNET_NO +#define VERBOSE_GLPK GNUNET_NO + +#define ENABLE_C8 GNUNET_YES +#define ENABLE_C9 GNUNET_YES +/** + * Translate glpk solver error codes to text + * @param retcode return code + * @return string with result + */ +const char * +mlp_solve_to_string (int retcode) +{ + switch (retcode) { + case 0: + return "ok"; + break; + case GLP_EBADB: + return "invalid basis"; + break; + case GLP_ESING: + return "singular matrix"; + break; + case GLP_ECOND: + return "ill-conditioned matrix"; + break; + case GLP_EBOUND: + return "invalid bounds"; + break; + case GLP_EFAIL: + return "solver failed"; + break; + case GLP_EOBJLL: + return "objective lower limit reached"; + break; + case GLP_EOBJUL: + return "objective upper limit reached"; + break; + case GLP_EITLIM: + return "iteration limit exceeded"; + break; + case GLP_ETMLIM: + return "time limit exceeded"; + break; + case GLP_ENOPFS: + return "no primal feasible solution"; + break; + case GLP_EROOT: + return "root LP optimum not provided"; + break; + case GLP_ESTOP: + return "search terminated by application"; + break; + case GLP_EMIPGAP: + return "relative mip gap tolerance reached"; + break; + case GLP_ENOFEAS: + return "no dual feasible solution"; + break; + case GLP_ENOCVG: + return "no convergence"; + break; + case GLP_EINSTAB: + return "numerical instability"; + break; + case GLP_EDATA: + return "invalid data"; + break; + case GLP_ERANGE: + return "result out of range"; + break; + default: + GNUNET_break (0); + return "unknown error"; + break; + } + GNUNET_break (0); + return "unknown error"; +} + + +/** + * Translate glpk status error codes to text + * @param retcode return code + * @return string with result + */ +const char * +mlp_status_to_string (int retcode) +{ + switch (retcode) { + case GLP_UNDEF: + return "solution is undefined"; + break; + case GLP_FEAS: + return "solution is feasible"; + break; + case GLP_INFEAS: + return "solution is infeasible"; + break; + case GLP_NOFEAS: + return "no feasible solution exists"; + break; + case GLP_OPT: + return "solution is optimal"; + break; + case GLP_UNBND: + return "solution is unbounded"; + break; + default: + GNUNET_break (0); + return "unknown error"; + break; + } + GNUNET_break (0); + return "unknown error"; +} + +/** + * Translate ATS properties to text + * Just intended for debugging + * + * @param ats_index the ATS index + * @return string with result + */ +const char * +mlp_ats_to_string (int ats_index) +{ + switch (ats_index) { + case GNUNET_ATS_ARRAY_TERMINATOR: + return "GNUNET_ATS_ARRAY_TERMINATOR"; + break; + case GNUNET_ATS_UTILIZATION_UP: + return "GNUNET_ATS_UTILIZATION_UP"; + break; + case GNUNET_ATS_UTILIZATION_DOWN: + return "GNUNET_ATS_UTILIZATION_DOWN"; + break; + case GNUNET_ATS_COST_LAN: + return "GNUNET_ATS_COST_LAN"; + break; + case GNUNET_ATS_COST_WAN: + return "GNUNET_ATS_COST_LAN"; + break; + case GNUNET_ATS_COST_WLAN: + return "GNUNET_ATS_COST_WLAN"; + break; + case GNUNET_ATS_NETWORK_TYPE: + return "GNUNET_ATS_NETWORK_TYPE"; + break; + case GNUNET_ATS_QUALITY_NET_DELAY: + return "GNUNET_ATS_QUALITY_NET_DELAY"; + break; + case GNUNET_ATS_QUALITY_NET_DISTANCE: + return "GNUNET_ATS_QUALITY_NET_DISTANCE"; + break; + default: + return "unknown"; + break; + } + GNUNET_break (0); + return "unknown error"; +} + +/** + * Find a peer in the DLL + * + * @param mlp the mlp handle + * @param peer the peer to find + * @return the peer struct + */ +static struct ATS_Peer * +mlp_find_peer (struct GAS_MLP_Handle *mlp, const struct GNUNET_PeerIdentity *peer) +{ + struct ATS_Peer *res = mlp->peer_head; + while (res != NULL) + { + if (0 == memcmp (peer, &res->id, sizeof (struct GNUNET_PeerIdentity))) + break; + res = res->next; + } + return res; +} + +/** + * Intercept GLPK terminal output + * @param info the mlp handle + * @param s the string to print + * @return 0: glpk prints output on terminal, 0 != surpress output + */ +static int +mlp_term_hook (void *info, const char *s) +{ + /* Not needed atm struct MLP_information *mlp = info; */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s", s); + return 1; +} + +/** + * Delete the MLP problem and free the constrain matrix + * + * @param mlp the MLP handle + */ +static void +mlp_delete_problem (struct GAS_MLP_Handle *mlp) +{ + if (mlp != NULL) + { + if (mlp->prob != NULL) + glp_delete_prob(mlp->prob); + + /* delete row index */ + if (mlp->ia != NULL) + { + GNUNET_free (mlp->ia); + mlp->ia = NULL; + } + + /* delete column index */ + if (mlp->ja != NULL) + { + GNUNET_free (mlp->ja); + mlp->ja = NULL; + } + + /* delete coefficients */ + if (mlp->ar != NULL) + { + GNUNET_free (mlp->ar); + mlp->ar = NULL; + } + mlp->ci = 0; + mlp->prob = NULL; + } +} + +/** + * Add constraints that are iterating over "forall addresses" + * and collects all existing peers for "forall peers" constraints + * + * @param cls GAS_MLP_Handle + * @param key Hashcode + * @param value ATS_Address + * + * @return GNUNET_OK to continue + */ +static int +create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GAS_MLP_Handle *mlp = cls; + struct ATS_Address *address = value; + struct MLP_information *mlpi; + unsigned int row_index; + char *name; + + GNUNET_assert (address->mlp_information != NULL); + mlpi = (struct MLP_information *) address->mlp_information; + + /* c 1) bandwidth capping + * b_t + (-M) * n_t <= 0 + */ + row_index = glp_add_rows (mlp->prob, 1); + mlpi->r_c1 = row_index; + /* set row name */ + GNUNET_asprintf(&name, "c1_%s_%s", GNUNET_i2s(&address->peer), address->plugin); + glp_set_row_name (mlp->prob, row_index, name); + GNUNET_free (name); + /* set row bounds: <= 0 */ + glp_set_row_bnds (mlp->prob, row_index, GLP_UP, 0.0, 0.0); + mlp->ia[mlp->ci] = row_index; + mlp->ja[mlp->ci] = mlpi->c_b; + mlp->ar[mlp->ci] = 1; + mlp->ci++; + + mlp->ia[mlp->ci] = row_index; + mlp->ja[mlp->ci] = mlpi->c_n; + mlp->ar[mlp->ci] = -mlp->BIG_M; + mlp->ci++; + + /* c 3) minimum bandwidth + * b_t + (-n_t * b_min) >= 0 + */ + + row_index = glp_add_rows (mlp->prob, 1); + /* set row name */ + GNUNET_asprintf(&name, "c3_%s_%s", GNUNET_i2s(&address->peer), address->plugin); + glp_set_row_name (mlp->prob, row_index, name); + GNUNET_free (name); + mlpi->r_c3 = row_index; + /* set row bounds: >= 0 */ + glp_set_row_bnds (mlp->prob, row_index, GLP_LO, 0.0, 0.0); + + mlp->ia[mlp->ci] = row_index; + mlp->ja[mlp->ci] = mlpi->c_b; + mlp->ar[mlp->ci] = 1; + mlp->ci++; + + mlp->ia[mlp->ci] = row_index; + mlp->ja[mlp->ci] = mlpi->c_n; + mlp->ar[mlp->ci] = - (double) mlp->b_min; + mlp->ci++; + + /* c 4) minimum connections + * (1)*n_1 + ... + (1)*n_m >= n_min + */ + mlp->ia[mlp->ci] = mlp->r_c4; + mlp->ja[mlp->ci] = mlpi->c_n; + mlp->ar[mlp->ci] = 1; + mlp->ci++; + + /* c 6) maximize diversity + * (1)*n_1 + ... + (1)*n_m - d == 0 + */ + mlp->ia[mlp->ci] = mlp->r_c6; + mlp->ja[mlp->ci] = mlpi->c_n; + mlp->ar[mlp->ci] = 1; + mlp->ci++; + + /* c 10) obey network specific quotas + * (1)*b_1 + ... + (1)*b_m <= quota_n + */ + + int cur_row = 0; + int c; + for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++) + { + if (mlp->quota_index[c] == address->atsp_network_type) + { + cur_row = mlp->r_quota[c]; + break; + } + } + + if (cur_row != 0) + { + mlp->ia[mlp->ci] = cur_row; + mlp->ja[mlp->ci] = mlpi->c_b; + mlp->ar[mlp->ci] = 1; + mlp->ci++; + } + else + { + GNUNET_break (0); + } + + return GNUNET_OK; +} + +/** + * Find the required ATS information for an address + * + * @param addr the address + * @param ats_index the desired ATS index + * + * @return the index on success, otherwise GNUNET_SYSERR + */ + +static int +mlp_lookup_ats (struct ATS_Address *addr, int ats_index) +{ + struct GNUNET_ATS_Information * ats = addr->ats; + int c = 0; + int found = GNUNET_NO; + for (c = 0; c < addr->ats_count; c++) + { + if (ats[c].type == ats_index) + { + found = GNUNET_YES; + break; + } + } + if (found == GNUNET_YES) + return c; + else + return GNUNET_SYSERR; +} + +/** + * Adds the problem constraints for all addresses + * Required for problem recreation after address deletion + * + * @param mlp the mlp handle + * @param addresses all addresses + */ + +static void +mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses) +{ + unsigned int n_addresses; + int c; + char *name; + + /* Problem matrix*/ + n_addresses = GNUNET_CONTAINER_multihashmap_size(addresses); + + /* Required indices in the constrain matrix + * + * feasibility constraints: + * + * c 1) bandwidth capping + * #rows: |n_addresses| + * #indices: 2 * |n_addresses| + * + * c 2) one active address per peer + * #rows: |peers| + * #indices: |n_addresses| + * + * c 3) minium bandwidth assigned + * #rows: |n_addresses| + * #indices: 2 * |n_addresses| + * + * c 4) minimum number of active connections + * #rows: 1 + * #indices: |n_addresses| + * + * c 5) maximum ressource consumption + * #rows: |ressources| + * #indices: |n_addresses| + * + * c 10) obey network specific quota + * #rows: |network types + * #indices: |n_addresses| + * + * Sum for feasibility constraints: + * #rows: 3 * |n_addresses| + |ressources| + |peers| + 1 + * #indices: 7 * |n_addresses| + * + * optimality constraints: + * + * c 6) diversity + * #rows: 1 + * #indices: |n_addresses| + 1 + * + * c 7) quality + * #rows: |quality properties| + * #indices: |n_addresses| + |quality properties| + * + * c 8) utilization + * #rows: 1 + * #indices: |n_addresses| + 1 + * + * c 9) relativity + * #rows: |peers| + * #indices: |n_addresses| + |peers| + * */ + + /* last +1 caused by glpk index starting with one: [1..pi]*/ + int pi = ((7 * n_addresses) + (5 * n_addresses + mlp->m_q + mlp->c_p + 2) + 1); + mlp->cm_size = pi; + mlp->ci = 1; + + /* row index */ + int *ia = GNUNET_malloc (pi * sizeof (int)); + mlp->ia = ia; + + /* column index */ + int *ja = GNUNET_malloc (pi * sizeof (int)); + mlp->ja = ja; + + /* coefficient */ + double *ar= GNUNET_malloc (pi * sizeof (double)); + mlp->ar = ar; + + /* Adding constraint rows + * This constraints are kind of "for all addresses" + * Feasibility constraints: + * + * c 1) bandwidth capping + * c 3) minimum bandwidth + * c 4) minimum number of connections + * c 6) maximize diversity + * c 10) obey network specific quota + */ + + int min = mlp->n_min; + if (mlp->n_min > mlp->c_p) + min = mlp->c_p; + + mlp->r_c4 = glp_add_rows (mlp->prob, 1); + glp_set_row_name (mlp->prob, mlp->r_c4, "c4"); + glp_set_row_bnds (mlp->prob, mlp->r_c4, GLP_LO, min, min); + + /* Add row for c6) */ + + mlp->r_c6 = glp_add_rows (mlp->prob, 1); + /* Set type type to fix */ + glp_set_row_bnds (mlp->prob, mlp->r_c6, GLP_FX, 0.0, 0.0); + /* Setting -D */ + ia[mlp->ci] = mlp->r_c6 ; + ja[mlp->ci] = mlp->c_d; + ar[mlp->ci] = -1; + mlp->ci++; + + /* Add rows for c 10) */ + for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++) + { + mlp->r_quota[c] = glp_add_rows (mlp->prob, 1); + char * text; + GNUNET_asprintf(&text, "quota_ats_%i", mlp->quota_index[c]); + glp_set_row_name (mlp->prob, mlp->r_quota[c], text); + GNUNET_free (text); + /* Set bounds to 0 <= x <= quota_out */ + glp_set_row_bnds (mlp->prob, mlp->r_quota[c], GLP_UP, 0.0, mlp->quota_out[c]); + } + + GNUNET_CONTAINER_multihashmap_iterate (addresses, create_constraint_it, mlp); + + /* Adding constraint rows + * This constraints are kind of "for all peers" + * Feasibility constraints: + * + * c 2) 1 address per peer + * sum (n_p1_1 + ... + n_p1_n) = 1 + * + * c 8) utilization + * sum (f_p * b_p1_1 + ... + f_p * b_p1_n) - u = 0 + * + * c 9) relativity + * V p : sum (bt_1 + ... +bt_n) - f_p * r = 0 + * */ + + /* Adding rows for c 8) */ + mlp->r_c8 = glp_add_rows (mlp->prob, mlp->c_p); + glp_set_row_name (mlp->prob, mlp->r_c8, "c8"); + /* Set row bound == 0 */ + glp_set_row_bnds (mlp->prob, mlp->r_c8, GLP_FX, 0.0, 0.0); + /* -u */ + + ia[mlp->ci] = mlp->r_c8; + ja[mlp->ci] = mlp->c_u; + ar[mlp->ci] = -1; + mlp->ci++; + + struct ATS_Peer * peer = mlp->peer_head; + while (peer != NULL) + { + struct ATS_Address *addr = peer->head; + struct MLP_information *mlpi = NULL; + + /* Adding rows for c 2) */ + peer->r_c2 = glp_add_rows (mlp->prob, 1); + GNUNET_asprintf(&name, "c2_%s", GNUNET_i2s(&peer->id)); + glp_set_row_name (mlp->prob, peer->r_c2, name); + GNUNET_free (name); + /* Set row bound == 1 */ + glp_set_row_bnds (mlp->prob, peer->r_c2, GLP_FX, 1.0, 1.0); + + /* Adding rows for c 9) */ +#if ENABLE_C9 + peer->r_c9 = glp_add_rows (mlp->prob, 1); + GNUNET_asprintf(&name, "c9_%s", GNUNET_i2s(&peer->id)); + glp_set_row_name (mlp->prob, peer->r_c9, name); + GNUNET_free (name); + /* Set row bound == 0 */ + glp_set_row_bnds (mlp->prob, peer->r_c9, GLP_LO, 0.0, 0.0); + + /* Set -r */ + ia[mlp->ci] = peer->r_c9; + ja[mlp->ci] = mlp->c_r; + ar[mlp->ci] = -1; + mlp->ci++; +#endif + + while (addr != NULL) + { + mlpi = (struct MLP_information *) addr->mlp_information; + + /* coefficient for c 2) */ + + ia[mlp->ci] = peer->r_c2; + ja[mlp->ci] = mlpi->c_n; + ar[mlp->ci] = 1; + mlp->ci++; + + /* coefficient for c 8) */ + ia[mlp->ci] = mlp->r_c8; + ja[mlp->ci] = mlpi->c_b; + ar[mlp->ci] = peer->f; + mlp->ci++; + +#if ENABLE_C9 + /* coefficient for c 9) */ + ia[mlp->ci] = peer->r_c9; + ja[mlp->ci] = mlpi->c_b; + ar[mlp->ci] = 1; + mlp->ci++; +#endif + + addr = addr->next; + } + peer = peer->next; + } + + /* c 7) For all quality metrics */ + + + for (c = 0; c < mlp->m_q; c++) + { + struct ATS_Peer *tp; + struct ATS_Address *ta; + struct MLP_information * mlpi; + double value = 1.0; + + /* Adding rows for c 7) */ + mlp->r_q[c] = glp_add_rows (mlp->prob, 1); + GNUNET_asprintf(&name, "c7_q%i_%s", c, mlp_ats_to_string(mlp->q[c])); + glp_set_row_name (mlp->prob, mlp->r_q[c], name); + GNUNET_free (name); + /* Set row bound == 0 */ + glp_set_row_bnds (mlp->prob, mlp->r_q[c], GLP_LO, 0.0, 0.0); + + ia[mlp->ci] = mlp->r_q[c]; + ja[mlp->ci] = mlp->c_q[c]; + ar[mlp->ci] = -1; + mlp->ci++; + + for (tp = mlp->peer_head; tp != NULL; tp = tp->next) + for (ta = tp->head; ta != NULL; ta = ta->next) + { + mlpi = ta->mlp_information; + value = mlpi->q_averaged[c]; + + mlpi->r_q[c] = mlp->r_q[c]; + + ia[mlp->ci] = mlp->r_q[c]; + ja[mlp->ci] = mlpi->c_b; + ar[mlp->ci] = tp->f * value; + mlp->ci++; + } + } +} + + +/** + * Add columns for all addresses + * + * @param cls GAS_MLP_Handle + * @param key Hashcode + * @param value ATS_Address + * + * @return GNUNET_OK to continue + */ +static int +create_columns_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GAS_MLP_Handle *mlp = cls; + struct ATS_Address *address = value; + struct MLP_information *mlpi; + unsigned int col; + char *name; + + GNUNET_assert (address->mlp_information != NULL); + mlpi = address->mlp_information; + + /* Add bandwidth column */ + col = glp_add_cols (mlp->prob, 2); + mlpi->c_b = col; + mlpi->c_n = col + 1; + + + GNUNET_asprintf (&name, "b_%s_%s", GNUNET_i2s (&address->peer), address->plugin); + glp_set_col_name (mlp->prob, mlpi->c_b , name); + GNUNET_free (name); + /* Lower bound == 0 */ + glp_set_col_bnds (mlp->prob, mlpi->c_b , GLP_LO, 0.0, 0.0); + /* Continuous value*/ + glp_set_col_kind (mlp->prob, mlpi->c_b , GLP_CV); + /* Objective function coefficient == 0 */ + glp_set_obj_coef (mlp->prob, mlpi->c_b , 0); + + + /* Add usage column */ + GNUNET_asprintf (&name, "n_%s_%s", GNUNET_i2s (&address->peer), address->plugin); + glp_set_col_name (mlp->prob, mlpi->c_n, name); + GNUNET_free (name); + /* Limit value : 0 <= value <= 1 */ + glp_set_col_bnds (mlp->prob, mlpi->c_n, GLP_DB, 0.0, 1.0); + /* Integer value*/ + glp_set_col_kind (mlp->prob, mlpi->c_n, GLP_IV); + /* Objective function coefficient == 0 */ + glp_set_obj_coef (mlp->prob, mlpi->c_n, 0); + + return GNUNET_OK; +} + + + +/** + * Create the MLP problem + * + * @param mlp the MLP handle + * @param addresses the hashmap containing all adresses + * @return GNUNET_OK or GNUNET_SYSERR + */ +static int +mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses) +{ + int res = GNUNET_OK; + int col; + int c; + char *name; + + GNUNET_assert (mlp->prob == NULL); + + /* create the glpk problem */ + mlp->prob = glp_create_prob (); + + /* Set a problem name */ + glp_set_prob_name (mlp->prob, "gnunet ats bandwidth distribution"); + + /* Set optimization direction to maximize */ + glp_set_obj_dir (mlp->prob, GLP_MAX); + + /* Adding invariant columns */ + + /* Diversity d column */ + + col = glp_add_cols (mlp->prob, 1); + mlp->c_d = col; + /* Column name */ + glp_set_col_name (mlp->prob, col, "d"); + /* Column objective function coefficient */ + glp_set_obj_coef (mlp->prob, col, mlp->co_D); + /* Column lower bound = 0.0 */ + glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0); + + /* Utilization u column */ + + col = glp_add_cols (mlp->prob, 1); + mlp->c_u = col; + /* Column name */ + glp_set_col_name (mlp->prob, col, "u"); + /* Column objective function coefficient */ + glp_set_obj_coef (mlp->prob, col, mlp->co_U); + /* Column lower bound = 0.0 */ + glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0); + +#if ENABLE_C9 + /* Relativity r column */ + col = glp_add_cols (mlp->prob, 1); + mlp->c_r = col; + /* Column name */ + glp_set_col_name (mlp->prob, col, "r"); + /* Column objective function coefficient */ + glp_set_obj_coef (mlp->prob, col, mlp->co_R); + /* Column lower bound = 0.0 */ + glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0); +#endif + + /* Quality metric columns */ + col = glp_add_cols(mlp->prob, mlp->m_q); + for (c = 0; c < mlp->m_q; c++) + { + mlp->c_q[c] = col + c; + GNUNET_asprintf (&name, "q_%u", mlp->q[c]); + glp_set_col_name (mlp->prob, col + c, name); + /* Column lower bound = 0.0 */ + glp_set_col_bnds (mlp->prob, col + c, GLP_LO, 0.0, 0.0); + GNUNET_free (name); + /* Coefficient == Qm */ + glp_set_obj_coef (mlp->prob, col + c, mlp->co_Q[c]); + } + + /* Add columns for addresses */ + GNUNET_CONTAINER_multihashmap_iterate (addresses, create_columns_it, mlp); + + /* Add constraints */ + mlp_add_constraints_all_addresses (mlp, addresses); + + /* Load the matrix */ + glp_load_matrix(mlp->prob, (mlp->ci-1), mlp->ia, mlp->ja, mlp->ar); + + return res; +} + +/** + * Solves the LP problem + * + * @param mlp the MLP Handle + * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure + */ +static int +mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp) +{ + int res; + struct GNUNET_TIME_Relative duration; + struct GNUNET_TIME_Absolute end; + struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get(); + + /* LP presolver? + * Presolver is required if the problem was modified and an existing + * valid basis is now invalid */ + if (mlp->presolver_required == GNUNET_YES) + mlp->control_param_lp.presolve = GLP_ON; + else + mlp->control_param_lp.presolve = GLP_OFF; + + /* Solve LP problem to have initial valid solution */ +lp_solv: + res = glp_simplex(mlp->prob, &mlp->control_param_lp); + if (res == 0) + { + /* The LP problem instance has been successfully solved. */ + } + else if (res == GLP_EITLIM) + { + /* simplex iteration limit has been exceeded. */ + // TODO Increase iteration limit? + } + else if (res == GLP_ETMLIM) + { + /* Time limit has been exceeded. */ + // TODO Increase time limit? + } + else + { + /* Problem was ill-defined, retry with presolver */ + if (mlp->presolver_required == GNUNET_NO) + { + mlp->presolver_required = GNUNET_YES; + goto lp_solv; + } + else + { + /* Problem was ill-defined, no way to handle that */ + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "ats-mlp", + "Solving LP problem failed: %i %s\n", res, mlp_solve_to_string(res)); + return GNUNET_SYSERR; + } + } + + end = GNUNET_TIME_absolute_get (); + duration = GNUNET_TIME_absolute_get_difference (start, end); + mlp->lp_solved++; + mlp->lp_total_duration =+ duration.rel_value; + + GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO); + GNUNET_STATISTICS_set (mlp->stats,"# LP execution time", duration.rel_value, GNUNET_NO); + GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average", + mlp->lp_total_duration / mlp->lp_solved, GNUNET_NO); + + + /* Analyze problem status */ + res = glp_get_status (mlp->prob); + switch (res) { + /* solution is optimal */ + case GLP_OPT: + /* solution is feasible */ + case GLP_FEAS: + break; + + /* Problem was ill-defined, no way to handle that */ + default: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "ats-mlp", + "Solving LP problem failed, no solution: %s\n", mlp_status_to_string(res)); + return GNUNET_SYSERR; + break; + } + + /* solved sucessfully, no presolver required next time */ + mlp->presolver_required = GNUNET_NO; + + return GNUNET_OK; +} + + +/** + * Solves the MLP problem + * + * @param mlp the MLP Handle + * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure + */ +int +mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp) +{ + int res; + struct GNUNET_TIME_Relative duration; + struct GNUNET_TIME_Absolute end; + struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get(); + + /* solve MLP problem */ + res = glp_intopt(mlp->prob, &mlp->control_param_mlp); + + if (res == 0) + { + /* The MLP problem instance has been successfully solved. */ + } + else if (res == GLP_EITLIM) + { + /* simplex iteration limit has been exceeded. */ + // TODO Increase iteration limit? + } + else if (res == GLP_ETMLIM) + { + /* Time limit has been exceeded. */ + // TODO Increase time limit? + } + else + { + /* Problem was ill-defined, no way to handle that */ + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "ats-mlp", + "Solving MLP problem failed: %s\n", mlp_solve_to_string(res)); + return GNUNET_SYSERR; + } + + end = GNUNET_TIME_absolute_get (); + duration = GNUNET_TIME_absolute_get_difference (start, end); + mlp->mlp_solved++; + mlp->mlp_total_duration =+ duration.rel_value; + + GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO); + GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time", duration.rel_value, GNUNET_NO); + GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average", + mlp->mlp_total_duration / mlp->mlp_solved, GNUNET_NO); + + /* Analyze problem status */ + res = glp_mip_status(mlp->prob); + switch (res) { + /* solution is optimal */ + case GLP_OPT: + /* solution is feasible */ + case GLP_FEAS: + break; + + /* Problem was ill-defined, no way to handle that */ + default: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "ats-mlp", + "Solving MLP problem failed, %s\n\n", mlp_status_to_string(res)); + return GNUNET_SYSERR; + break; + } + + return GNUNET_OK; +} + +int GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp); + +static void +mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GAS_MLP_Handle *mlp = cls; + + mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduled problem solving\n"); + + if (mlp->addr_in_problem != 0) + GAS_mlp_solve_problem(mlp); +} + + +/** + * Solves the MLP problem + * + * @param mlp the MLP Handle + * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure + */ +int +GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp) +{ + int res; + mlp->last_execution = GNUNET_TIME_absolute_get (); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solving\n"); + + +#if WRITE_MLP + char * name; + static int i; + i++; + GNUNET_asprintf(&name, "problem_%i", i); + glp_write_lp (mlp->prob, 0, name); + GNUNET_free (name); +# endif + + res = mlp_solve_lp_problem (mlp); + +#if WRITE_MLP + GNUNET_asprintf(&name, "problem_%i_lp_solution", i); + glp_print_sol (mlp->prob, name); + GNUNET_free (name); +# endif + + if (res != GNUNET_OK) + { + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LP Problem solving failed\n"); + + return GNUNET_SYSERR; + } + + res = mlp_solve_mlp_problem (mlp); + +#if WRITE_MLP + GNUNET_asprintf(&name, "problem_%i_mlp_solution", i); + glp_print_mip (mlp->prob, name); + GNUNET_free (name); +# endif + if (res != GNUNET_OK) + { + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MLP Problem solving failed\n"); + + return GNUNET_SYSERR; + } + + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved\n"); + /* Process result */ + struct ATS_Peer *p = NULL; + struct ATS_Address *a = NULL; + struct MLP_information *mlpi = NULL; + + for (p = mlp->peer_head; p != NULL; p = p->next) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s'\n", GNUNET_i2s (&p->id)); + for (a = p->head; a != NULL; a = a->next) + { + double b = 0.0; + double n = 0.0; + + mlpi = a->mlp_information; + + b = glp_mip_col_val(mlp->prob, mlpi->c_b); + mlpi->b = b; + + n = glp_mip_col_val(mlp->prob, mlpi->c_n); + if (n == 1.0) + mlpi->n = GNUNET_YES; + else + mlpi->n = GNUNET_NO; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tAddress %s %f\n", + (n == 1.0) ? "[x]" : "[ ]", b); + } + } + + if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel(mlp->mlp_task); + mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK; + } + mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp); + return res; +} + +/** + * Init the MLP problem solving component + * + * @param cfg the GNUNET_CONFIGURATION_Handle handle + * @param stats the GNUNET_STATISTICS handle + * @param max_duration maximum numbers of iterations for the LP/MLP Solver + * @param max_iterations maximum time limit for the LP/MLP Solver + * @return struct GAS_MLP_Handle * on success, NULL on fail + */ +struct GAS_MLP_Handle * +GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_STATISTICS_Handle *stats, + struct GNUNET_TIME_Relative max_duration, + unsigned int max_iterations) +{ + struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle)); + + double D; + double R; + double U; + long long unsigned int tmp; + unsigned int b_min; + unsigned int n_min; + struct GNUNET_TIME_Relative i_exec; + int c; + + /* Init GLPK environment */ + GNUNET_assert (glp_init_env() == 0); + + /* Create initial MLP problem */ + mlp->prob = glp_create_prob(); + GNUNET_assert (mlp->prob != NULL); + + mlp->BIG_M = (double) (UINT32_MAX) /10; + + /* Get diversity coefficient from configuration */ + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", + "COEFFICIENT_D", + &tmp)) + D = (double) tmp / 100; + else + D = 1.0; + + /* Get proportionality coefficient from configuration */ + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", + "COEFFICIENT_R", + &tmp)) + R = (double) tmp / 100; + else + R = 1.0; + + /* Get utilization coefficient from configuration */ + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", + "COEFFICIENT_U", + &tmp)) + U = (double) tmp / 100; + else + U = 1.0; + + /* Get quality metric coefficients from configuration */ + int i_delay = -1; + int i_distance = -1; + int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties; + for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++) + { + /* initialize quality coefficients with default value 1.0 */ + mlp->co_Q[c] = 1.0; + + mlp->q[c] = q[c]; + if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY) + i_delay = c; + if (q[c] == GNUNET_ATS_QUALITY_NET_DISTANCE) + i_distance = c; + } + + if ((i_delay != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", + "COEFFICIENT_QUALITY_DELAY", + &tmp))) + + mlp->co_Q[i_delay] = (double) tmp / 100; + else + mlp->co_Q[i_delay] = 1.0; + + if ((i_distance != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", + "COEFFICIENT_QUALITY_DISTANCE", + &tmp))) + mlp->co_Q[i_distance] = (double) tmp / 100; + else + mlp->co_Q[i_distance] = 1.0; + + /* Get minimum bandwidth per used address from configuration */ + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", + "MIN_BANDWIDTH", + &tmp)) + b_min = tmp; + else + { + b_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__); + } + + /* Get minimum number of connections from configuration */ + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", + "MIN_CONNECTIONS", + &tmp)) + n_min = tmp; + else + n_min = 4; + + /* Init network quotas */ + int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType; + for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++) + { + mlp->quota_index[c] = quotas[c]; + static char * entry_in = NULL; + static char * entry_out = NULL; + unsigned long long quota_in = 0; + unsigned long long quota_out = 0; + + switch (quotas[c]) { + case GNUNET_ATS_NET_UNSPECIFIED: + entry_out = "UNSPECIFIED_QUOTA_OUT"; + entry_in = "UNSPECIFIED_QUOTA_IN"; + break; + case GNUNET_ATS_NET_LOOPBACK: + entry_out = "LOOPBACK_QUOTA_OUT"; + entry_in = "LOOPBACK_QUOTA_IN"; + break; + case GNUNET_ATS_NET_LAN: + entry_out = "LAN_QUOTA_OUT"; + entry_in = "LAN_QUOTA_IN"; + break; + case GNUNET_ATS_NET_WAN: + entry_out = "WAN_QUOTA_OUT"; + entry_in = "WAN_QUOTA_IN"; + break; + case GNUNET_ATS_NET_WLAN: + entry_out = "WLAN_QUOTA_OUT"; + entry_in = "WLAN_QUOTA_IN"; + break; + default: + break; + } + + if ((entry_in == NULL) || (entry_out == NULL)) + continue; + + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", entry_out, "a_out)) + { + quota_out = mlp->BIG_M; + } + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", entry_in, "a_in)) + { + quota_in = mlp->BIG_M; + } + /* Check if defined quota could make problem unsolvable */ + if ((n_min * b_min) > quota_out) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Inconsistent quota configuration value `%s': " \ + "outbound quota (%u Bps) too small for combination of minimum connections and minimum bandwidth per peer (%u * %u Bps = %u)\n", entry_out, quota_out, n_min, b_min, n_min * b_min); + unsigned int default_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__); + if ((quota_out / n_min) > default_min) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Reducing minimum bandwidth per peer to %u Bps\n", + (quota_out / n_min)); + b_min = (quota_out / n_min); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Reducing minimum bandwidth per peer to %u Bps and minimum connections to %u \n", + default_min, (quota_out / default_min)); + b_min = default_min; + n_min = (quota_out / default_min); + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found `%s' quota %llu and `%s' quota %llu\n", + entry_out, quota_out, entry_in, quota_in); + mlp->quota_out[c] = quota_out; + mlp->quota_in[c] = quota_in; + } + + /* Get minimum number of connections from configuration */ + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg, "ats", + "ATS_EXEC_INTERVAL", + &i_exec)) + mlp->exec_interval = i_exec; + else + mlp->exec_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30); + + mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats; + mlp->max_iterations = max_iterations; + mlp->max_exec_duration = max_duration; + mlp->auto_solve = GNUNET_YES; + + /* Redirect GLPK output to GNUnet logging */ + glp_error_hook((void *) mlp, &mlp_term_hook); + + /* Init LP solving parameters */ + glp_init_smcp(&mlp->control_param_lp); + + mlp->control_param_lp.msg_lev = GLP_MSG_OFF; +#if VERBOSE_GLPK + mlp->control_param_lp.msg_lev = GLP_MSG_ALL; +#endif + + mlp->control_param_lp.it_lim = max_iterations; + mlp->control_param_lp.tm_lim = max_duration.rel_value; + + /* Init MLP solving parameters */ + glp_init_iocp(&mlp->control_param_mlp); + + mlp->control_param_mlp.msg_lev = GLP_MSG_OFF; +#if VERBOSE_GLPK + mlp->control_param_mlp.msg_lev = GLP_MSG_ALL; +#endif + mlp->control_param_mlp.tm_lim = max_duration.rel_value; + + mlp->last_execution = GNUNET_TIME_absolute_get_forever(); + + mlp->co_D = D; + mlp->co_R = R; + mlp->co_U = U; + mlp->b_min = b_min; + mlp->n_min = n_min; + mlp->m_q = GNUNET_ATS_QualityPropertiesCount; + + return mlp; +} + +static void +update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating quality metrics for peer `%s'\n", + GNUNET_i2s (&address->peer)); + + struct MLP_information *mlpi = address->mlp_information; + struct GNUNET_ATS_Information *ats = address->ats; + GNUNET_assert (mlpi != NULL); + + int c; + + for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++) + { + int index = mlp_lookup_ats(address, mlp->q[c]); + + if (index == GNUNET_SYSERR) + continue; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' value `%s': %f\n", + GNUNET_i2s (&address->peer), + mlp_ats_to_string(mlp->q[c]), + (double) ats[index].value); + + int i = mlpi->q_avg_i[c]; + double * qp = mlpi->q[c]; + qp[i] = (double) ats[index].value; + + int t; + for (t = 0; t < MLP_AVERAGING_QUEUE_LENGTH; t++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' queue[%u]: %f\n", + GNUNET_i2s (&address->peer), + mlp_ats_to_string(mlp->q[c]), + t, + qp[t]); + } + + if (mlpi->q_avg_i[c] + 1 < (MLP_AVERAGING_QUEUE_LENGTH)) + mlpi->q_avg_i[c] ++; + else + mlpi->q_avg_i[c] = 0; + + + int c2; + int c3; + double avg = 0.0; + switch (mlp->q[c]) + { + case GNUNET_ATS_QUALITY_NET_DELAY: + c3 = 0; + for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++) + { + if (mlpi->q[c][c2] != -1) + { + double * t2 = mlpi->q[c] ; + avg += t2[c2]; + c3 ++; + } + } + if (c3 > 0) + /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/ + mlpi->q_averaged[c] = (double) c3 / avg; + else + mlpi->q_averaged[c] = 0.0; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' average sum: %f, average: %f, weight: %f\n", + GNUNET_i2s (&address->peer), + mlp_ats_to_string(mlp->q[c]), + avg, + avg / (double) c3, + mlpi->q_averaged[c]); + + break; + case GNUNET_ATS_QUALITY_NET_DISTANCE: + c3 = 0; + for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++) + { + if (mlpi->q[c][c2] != -1) + { + double * t2 = mlpi->q[c] ; + avg += t2[c2]; + c3 ++; + } + } + if (c3 > 0) + /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/ + mlpi->q_averaged[c] = (double) c3 / avg; + else + mlpi->q_averaged[c] = 0.0; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' average sum: %f, average: %f, weight: %f\n", + GNUNET_i2s (&address->peer), + mlp_ats_to_string(mlp->q[c]), + avg, + avg / (double) c3, + mlpi->q_averaged[c]); + + break; + default: + break; + } + + if ((mlpi->c_b != 0) && (mlpi->r_q[c] != 0)) + { + + /* Get current number of columns */ + int found = GNUNET_NO; + int cols = glp_get_num_cols(mlp->prob); + int *ind = GNUNET_malloc (cols * sizeof (int) + 1); + double *val = GNUNET_malloc (cols * sizeof (double) + 1); + + /* Get the matrix row of quality */ + int length = glp_get_mat_row(mlp->prob, mlp->r_q[c], ind, val); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "cols %i, length %i c_b %i\n", cols, length, mlpi->c_b); + int c4; + /* Get the index if matrix row of quality */ + for (c4 = 1; c4 <= length; c4++ ) + { + if (mlpi->c_b == ind[c4]) + { + /* Update the value */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating quality `%s' column `%s' row `%s' : %f -> %f\n", + mlp_ats_to_string(mlp->q[c]), + glp_get_col_name (mlp->prob, ind[c4]), + glp_get_row_name (mlp->prob, mlp->r_q[c]), + val[c4], + mlpi->q_averaged[c]); + val[c4] = mlpi->q_averaged[c]; + found = GNUNET_YES; + break; + } + } + + if (found == GNUNET_NO) + { + + ind[length+1] = mlpi->c_b; + val[length+1] = mlpi->q_averaged[c]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%i ind[%i] val[%i]: %i %f\n", length+1, length+1, length+1, mlpi->c_b, mlpi->q_averaged[c]); + glp_set_mat_row (mlp->prob, mlpi->r_q[c], length+1, ind, val); + } + else + { + /* Get the index if matrix row of quality */ + glp_set_mat_row (mlp->prob, mlpi->r_q[c], length, ind, val); + } + + GNUNET_free (ind); + GNUNET_free (val); + } + } +} + +/** + * Updates a single address in the MLP problem + * + * If the address did not exist before in the problem: + * The MLP problem has to be recreated and the problem has to be resolved + * + * Otherwise the addresses' values can be updated and the existing base can + * be reused + * + * @param mlp the MLP Handle + * @param addresses the address hashmap + * the address has to be already removed from the hashmap + * @param address the address to update + */ +void +GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address) +{ + int new; + struct MLP_information *mlpi; + + GNUNET_STATISTICS_update (mlp->stats,"# LP address updates", 1, GNUNET_NO); + + /* We add a new address */ + if (address->mlp_information == NULL) + new = GNUNET_YES; + else + new = GNUNET_NO; + + /* Do the update */ + if (new == GNUNET_YES) + { + mlpi = GNUNET_malloc (sizeof (struct MLP_information)); + + int c; + for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++) + { + int c2; + mlpi->r_q[c] = 0; + for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++) + mlpi->q[c][c2] = -1.0; /* -1.0: invalid value */ + mlpi->q_avg_i[c] = 0; + mlpi->q_averaged[c] = 0.0; + } + + address->mlp_information = mlpi; + mlp->addr_in_problem ++; + + /* Check for and add peer */ + struct ATS_Peer *peer = mlp_find_peer (mlp, &address->peer); + if (peer == NULL) + { + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding new peer `%s'\n", + GNUNET_i2s (&address->peer)); + + peer = GNUNET_malloc (sizeof (struct ATS_Peer)); + peer->head = NULL; + peer->tail = NULL; + + int c; + for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++) + { + peer->f_q[c] = 1.0; + } + peer->f = 1.0; + + memcpy (&peer->id, &address->peer, sizeof (struct GNUNET_PeerIdentity)); + GNUNET_assert(address->prev == NULL); + GNUNET_assert(address->next == NULL); + GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address); + GNUNET_CONTAINER_DLL_insert (mlp->peer_head, mlp->peer_tail, peer); + mlp->c_p ++; + } + else + { + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding address to peer `%s'\n", + GNUNET_i2s (&address->peer)); + + GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address); + } + + update_quality (mlp, address); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating existing address to peer `%s'\n", + GNUNET_i2s (&address->peer)); + + update_quality (mlp, address); + } + + /* Recalculate */ + if (new == GNUNET_YES) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recreating problem: new address\n"); + + mlp_delete_problem (mlp); + mlp_create_problem (mlp, addresses); + mlp->presolver_required = GNUNET_YES; + } + if (mlp->auto_solve == GNUNET_YES) + GAS_mlp_solve_problem (mlp); +} + +/** + * Deletes a single address in the MLP problem + * + * The MLP problem has to be recreated and the problem has to be resolved + * + * @param mlp the MLP Handle + * @param addresses the address hashmap + * the address has to be already removed from the hashmap + * @param address the address to delete + */ +void +GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address) +{ + GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO); + + /* Free resources */ + if (address->mlp_information != NULL) + { + GNUNET_free (address->mlp_information); + address->mlp_information = NULL; + + mlp->addr_in_problem --; + } + + /* Remove from peer list */ + struct ATS_Peer *head = mlp_find_peer (mlp, &address->peer); + GNUNET_assert (head != NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for `%s'\n", GNUNET_i2s (&address->peer)); + + GNUNET_CONTAINER_DLL_remove (head->head, head->tail, address); + if ((head->head == NULL) && (head->tail == NULL)) + { + /* No address for peer left, remove peer */ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting peer `%s'\n", GNUNET_i2s (&address->peer)); + + GNUNET_CONTAINER_DLL_remove (mlp->peer_head, mlp->peer_tail, head); + GNUNET_free (head); + mlp->c_p --; + } + + /* Update problem */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recreating problem: new address\n"); + + mlp_delete_problem (mlp); + if ((GNUNET_CONTAINER_multihashmap_size (addresses) > 0) && (mlp->c_p > 0)) + { + mlp_create_problem (mlp, addresses); + + /* Recalculate */ + mlp->presolver_required = GNUNET_YES; + if (mlp->auto_solve == GNUNET_YES) + GAS_mlp_solve_problem (mlp); + } +} + +static int +mlp_get_preferred_address_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + + struct ATS_PreferedAddress *aa = (struct ATS_PreferedAddress *) cls; + struct ATS_Address *addr = value; + struct MLP_information *mlpi = addr->mlp_information; + if (mlpi == NULL) + return GNUNET_YES; + if (mlpi->n == GNUNET_YES) + { + aa->address = addr; + if (mlpi->b > (double) UINT32_MAX) + aa->bandwidth_out = UINT32_MAX; + else + aa->bandwidth_out = (uint32_t) mlpi->b; + aa->bandwidth_in = 0; + return GNUNET_NO; + } + return GNUNET_YES; +} + + +/** + * Get the preferred address for a specific peer + * + * @param mlp the MLP Handle + * @param addresses address hashmap + * @param peer the peer + * @return suggested address + */ +struct ATS_PreferedAddress * +GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp, + struct GNUNET_CONTAINER_MultiHashMap * addresses, + const struct GNUNET_PeerIdentity *peer) +{ + struct ATS_PreferedAddress * aa = GNUNET_malloc (sizeof (struct ATS_PreferedAddress)); + aa->address = NULL; + aa->bandwidth_in = 0; + aa->bandwidth_out = 0; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting preferred address for `%s'\n", GNUNET_i2s (peer)); + GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, mlp_get_preferred_address_it, aa); + return aa; +} + + +/** + * Changes the preferences for a peer in the MLP problem + * + * @param mlp the MLP Handle + * @param peer the peer + * @param kind the kind to change the preference + * @param score the score + */ +void +GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp, + const struct GNUNET_PeerIdentity *peer, + enum GNUNET_ATS_PreferenceKind kind, + float score) +{ + GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO); + + struct ATS_Peer *p = mlp_find_peer (mlp, peer); + p = p; + /* Here we have to do the matching */ +} + +/** + * Shutdown the MLP problem solving component + * @param mlp the MLP handle + */ +void +GAS_mlp_done (struct GAS_MLP_Handle *mlp) +{ + struct ATS_Peer * peer; + struct ATS_Peer * tmp; + + GNUNET_assert (mlp != NULL); + + if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel(mlp->mlp_task); + mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK; + } + + /* clean up peer list */ + peer = mlp->peer_head; + while (peer != NULL) + { + GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer); + tmp = peer->next; + GNUNET_free (peer); + peer = tmp; + } + mlp_delete_problem (mlp); + + /* Clean up GLPK environment */ + glp_free_env(); + + GNUNET_free (mlp); +} + + +/* end of gnunet-service-ats_addresses_mlp.c */ diff --git a/src/ats/gnunet-service-ats_addresses_mlp.h b/src/ats/gnunet-service-ats_addresses_mlp.h new file mode 100644 index 0000000..8f60a85 --- /dev/null +++ b/src/ats/gnunet-service-ats_addresses_mlp.h @@ -0,0 +1,394 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats_addresses_mlp.h + * @brief ats mlp problem solver + * @author Matthias Wachs + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_statistics_service.h" +#include "gnunet-service-ats_addresses.h" +#if HAVE_LIBGLPK +#include "glpk.h" +#endif + +#ifndef GNUNET_SERVICE_ATS_ADDRESSES_MLP_H +#define GNUNET_SERVICE_ATS_ADDRESSES_MLP_H + +#define DEBUG_MLP GNUNET_EXTRA_LOGGING + +#define MLP_AVERAGING_QUEUE_LENGTH 3 + +#define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3) +#define MLP_MAX_ITERATIONS INT_MAX + +struct ATS_Peer +{ + struct ATS_Peer *next; + struct ATS_Peer *prev; + + struct GNUNET_PeerIdentity id; + + /* Array of quality preferences */ + double f_q[GNUNET_ATS_QualityPropertiesCount]; + /* Legacy preference value */ + double f; + + /* constraint 2: 1 address per peer*/ + unsigned int r_c2; + + /* constraint 9: relativity */ + unsigned int r_c9; + + struct ATS_Address *head; + struct ATS_Address *tail; +}; + +struct ATS_PreferedAddress +{ + uint32_t bandwidth_out; + uint32_t bandwidth_in; + struct ATS_Address *address; +}; + +/** + * MLP Handle + */ +struct GAS_MLP_Handle +{ + /** + * Statistics handle + */ + struct GNUNET_STATISTICS_Handle *stats; + + /** + * GLPK (MLP) problem object + */ +#if HAVE_LIBGLPK + glp_prob *prob; +#else + void *prob; +#endif + + double BIG_M; + + /** + * GLPK LP control parameter + */ + glp_smcp control_param_lp; + + /** + * GLPK LP control parameter + */ + glp_iocp control_param_mlp; + + /** + * Solves the task in an regular interval + */ + GNUNET_SCHEDULER_TaskIdentifier mlp_task; + + /** + * Interval between scheduled problem solving + */ + struct GNUNET_TIME_Relative exec_interval; + + /** + * Maximum execution time per problem solving + */ + struct GNUNET_TIME_Relative max_exec_duration; + + /** + * Maximum number of LP iterations per problem solving + */ + unsigned int max_iterations; + + /** + * Solve the problem automatically when updates occur? + * Default: GNUNET_YES + * Can be disabled for test and measurements + */ + int auto_solve; + + /* state information */ + + /** + * Do we need to use the LP presolver? + * + * If the problem addresses were added or removed and the last basis was we + * need to use the presolver. + * presolver_required == GNUNET_YES + * + * If values were modified, we can reuse a valid basis + * presolver_required == GNUNET_NO + */ + int presolver_required; + + /* statistics */ + + /** + * Time of last execution + */ + struct GNUNET_TIME_Absolute last_execution; + + + /** + * How often was the LP problem solved + */ + unsigned int lp_solved; + + /** + * total duration of all lp solver executions + */ + uint64_t lp_total_duration; + + /** + * How often was the MLP problem solved + */ + unsigned int mlp_solved; + + /** + * total duration of all mlp solver executions + */ + uint64_t mlp_total_duration; + + unsigned int addr_in_problem; + + /* Information about the problem */ + + struct ATS_Peer *peer_head; + struct ATS_Peer *peer_tail; + + /* Number of peers */ + unsigned int c_p; + + /* current problem matrix */ + /* row index array */ + int *ia; + /* column index array */ + int *ja; + /* column index array */ + double *ar; + /* current size of the constraint matrix |indices| */ + unsigned int cm_size; + unsigned int ci; + + /* Row index constraint 2: */ + unsigned int r_c2; + /* Row index constraint 4: minimum connections */ + unsigned int r_c4; + /* Row index constraint 6: maximize diversity */ + unsigned int r_c6; + /* Row index constraint 8: utilization*/ + unsigned int r_c8; + /* Row index constraint 9: relativity*/ + unsigned int r_c9; + + /* column index Diversity (D) column */ + int c_d; + double co_D; + + /* column index Utilization (U) column */ + int c_u; + double co_U; + + /* column index Proportionality (R) column */ + int c_r; + double co_R; + + /* ATS Quality metrics + * + * array with GNUNET_ATS_QualityPropertiesCount elements + * contains mapping to GNUNET_ATS_Property*/ + int q[GNUNET_ATS_QualityPropertiesCount]; + + /* column index quality metrics */ + int c_q[GNUNET_ATS_QualityPropertiesCount]; + + /* column index quality metrics */ + int r_q[GNUNET_ATS_QualityPropertiesCount]; + + /* quality metric coefficients*/ + double co_Q[GNUNET_ATS_QualityPropertiesCount]; + + /* number of quality metrics */ + int m_q; + + /* ATS network quotas */ + int c_quota[GNUNET_ATS_NetworkTypeCount]; + int r_quota[GNUNET_ATS_NetworkTypeCount]; + int quota_index [GNUNET_ATS_NetworkTypeCount]; + unsigned long long quota_out[GNUNET_ATS_NetworkTypeCount]; + unsigned long long quota_in[GNUNET_ATS_NetworkTypeCount]; + + /* ATS ressource costs + * + * array with GNUNET_ATS_QualityPropertiesCount elements + * contains mapping to GNUNET_ATS_Property*/ + int rc[GNUNET_ATS_QualityPropertiesCount]; + + /* column index ressource costs */ + int c_rc[GNUNET_ATS_QualityPropertiesCount]; + + /* ressource costs coefficients*/ + double co_RC[GNUNET_ATS_QualityPropertiesCount]; + + /* number of quality metrics */ + int m_rc; + + /* minimum bandwidth assigned to an address */ + unsigned int b_min; + + /* minimum number of addresses with bandwidth assigned */ + unsigned int n_min; +}; + + +/** + * Address specific MLP information + */ +struct MLP_information +{ + double b; + + int n; + + /* bandwidth column index */ + signed int c_b; + + /* address usage column */ + signed int c_n; + + /* row indexes */ + + /* constraint 1: bandwidth capping */ + unsigned int r_c1; + + /* constraint 3: minimum bandwidth */ + unsigned int r_c3; + + /* Quality information row indices */ + unsigned int r_q[GNUNET_ATS_QualityPropertiesCount]; + + /* Quality information */ + double q[GNUNET_ATS_QualityPropertiesCount][MLP_AVERAGING_QUEUE_LENGTH]; + + /* Quality information averaged */ + double q_averaged[GNUNET_ATS_QualityPropertiesCount]; + + /* Averaging index */ + int q_avg_i[GNUNET_ATS_QualityPropertiesCount]; +}; + + +/** + * Init the MLP problem solving component + * + * @param cfg configuration handle + * @param stats the GNUNET_STATISTICS handle + * @param max_duration maximum numbers of iterations for the LP/MLP Solver + * @param max_iterations maximum time limit for the LP/MLP Solver + * @return struct GAS_MLP_Handle * on success, NULL on fail + */ +struct GAS_MLP_Handle * +GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_STATISTICS_Handle *stats, + struct GNUNET_TIME_Relative max_duration, + unsigned int max_iterations); + +/** + * Solves the MLP problem on demand + * + * @param mlp the MLP Handle + * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure + */ +int +GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp); + + +/** + * Updates a single address in the MLP problem + * + * If the address did not exist before in the problem: + * The MLP problem has to be recreated and the problem has to be resolved + * + * Otherwise the addresses' values can be updated and the existing base can + * be reused + * + * @param mlp the MLP Handle + * @param addresses the address hashmap + * the address has to be already added from the hashmap + * @param address the address to update + */ +void +GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address); + + +/** + * Deletes a single address in the MLP problem + * + * The MLP problem has to be recreated and the problem has to be resolved + * + * @param mlp the MLP Handle + * @param addresses the address hashmap + * the address has to be already removed from the hashmap + * @param address the address to delete + */ +void +GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address); + + +/** + * Changes the preferences for a peer in the MLP problem + * + * @param mlp the MLP Handle + * @param peer the peer + * @param kind the kind to change the preference + * @param score the score + */ +void +GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp, + const struct GNUNET_PeerIdentity *peer, + enum GNUNET_ATS_PreferenceKind kind, + float score); + + +/** + * Get the preferred address for a specific peer + * + * @param mlp the MLP Handle + * @param addresses address hashmap + * @param peer the peer + * @return suggested address + */ +struct ATS_PreferedAddress * +GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp, + struct GNUNET_CONTAINER_MultiHashMap * addresses, + const struct GNUNET_PeerIdentity *peer); + +/** + * Shutdown the MLP problem solving component + */ +void +GAS_mlp_done (); + +#endif +/* end of gnunet-service-ats_addresses_mlp.h */ diff --git a/src/ats/gnunet-service-ats_performance.c b/src/ats/gnunet-service-ats_performance.c new file mode 100644 index 0000000..b127656 --- /dev/null +++ b/src/ats/gnunet-service-ats_performance.c @@ -0,0 +1,316 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats_performance.c + * @brief ats service, interaction with 'performance' API + * @author Matthias Wachs + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-ats.h" +#include "gnunet-service-ats_addresses.h" +#include "gnunet-service-ats_performance.h" +#include "gnunet-service-ats_reservations.h" +#include "ats.h" + + +/** + * We keep clients that are interested in performance in a linked list. + */ +struct PerformanceClient +{ + /** + * Next in doubly-linked list. + */ + struct PerformanceClient *next; + + /** + * Previous in doubly-linked list. + */ + struct PerformanceClient *prev; + + /** + * Actual handle to the client. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Options for the client. + */ + enum StartFlag flag; + +}; + + +/** + * Head of linked list of all clients to this service. + */ +static struct PerformanceClient *pc_head; + +/** + * Tail of linked list of all clients to this service. + */ +static struct PerformanceClient *pc_tail; + +/** + * Context for sending messages to performance clients. + */ +static struct GNUNET_SERVER_NotificationContext *nc; + + +/** + * Find the performance client associated with the given handle. + * + * @param client server handle + * @return internal handle + */ +static struct PerformanceClient * +find_client (struct GNUNET_SERVER_Client *client) +{ + struct PerformanceClient *pc; + + for (pc = pc_head; pc != NULL; pc = pc->next) + if (pc->client == client) + return pc; + return NULL; +} + + +/** + * Register a new performance client. + * + * @param client handle of the new client + * @param flag flag specifying the type of the client + */ +void +GAS_performance_add_client (struct GNUNET_SERVER_Client *client, + enum StartFlag flag) +{ + struct PerformanceClient *pc; + + GNUNET_break (NULL == find_client (client)); + pc = GNUNET_malloc (sizeof (struct PerformanceClient)); + pc->client = client; + pc->flag = flag; + GNUNET_SERVER_notification_context_add (nc, client); + GNUNET_SERVER_client_keep (client); + GNUNET_CONTAINER_DLL_insert (pc_head, pc_tail, pc); +} + + +/** + * Unregister a client (which may have been a performance client, + * but this is not assured). + * + * @param client handle of the (now dead) client + */ +void +GAS_performance_remove_client (struct GNUNET_SERVER_Client *client) +{ + struct PerformanceClient *pc; + + pc = find_client (client); + if (NULL == pc) + return; + GNUNET_CONTAINER_DLL_remove (pc_head, pc_tail, pc); + GNUNET_SERVER_client_drop (client); + GNUNET_free (pc); +} + + +/** + * Transmit the given performance information to all performance + * clients. + * + * @param peer peer for which this is an address suggestion + * @param plugin_name 0-termintated string specifying the transport plugin + * @param plugin_addr binary address for the plugin to use + * @param plugin_addr_len number of bytes in plugin_addr + * @param atsi performance data for the address + * @param atsi_count number of performance records in 'ats' + * @param bandwidth_out assigned outbound bandwidth + * @param bandwidth_in assigned inbound bandwidth + */ +void +GAS_performance_notify_clients (const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, + const void *plugin_addr, size_t plugin_addr_len, + const struct GNUNET_ATS_Information *atsi, + uint32_t atsi_count, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_out, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in) +{ + struct PerformanceClient *pc; + struct PeerInformationMessage *msg; + size_t plugin_name_length = strlen (plugin_name) + 1; + size_t msize = + sizeof (struct PeerInformationMessage) + + atsi_count * sizeof (struct GNUNET_ATS_Information) + plugin_addr_len + + plugin_name_length; + char buf[msize]; + struct GNUNET_ATS_Information *atsp; + char *addrp; + + GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); + GNUNET_assert (atsi_count < + GNUNET_SERVER_MAX_MESSAGE_SIZE / + sizeof (struct GNUNET_ATS_Information)); + msg = (struct PeerInformationMessage *) buf; + msg->header.size = htons (msize); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION); + msg->ats_count = htonl (atsi_count); + msg->peer = *peer; + msg->address_length = htons (plugin_addr_len); + msg->plugin_name_length = htons (plugin_name_length); + msg->bandwidth_out = bandwidth_out; + msg->bandwidth_in = bandwidth_in; + atsp = (struct GNUNET_ATS_Information *) &msg[1]; + memcpy (atsp, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count); + addrp = (char *) &atsp[atsi_count]; + memcpy (addrp, plugin_addr, plugin_addr_len); + strcpy (&addrp[plugin_addr_len], plugin_name); + for (pc = pc_head; pc != NULL; pc = pc->next) + if (pc->flag == START_FLAG_PERFORMANCE_WITH_PIC) + { + GNUNET_SERVER_notification_context_unicast (nc, pc->client, &msg->header, + GNUNET_YES); + GNUNET_STATISTICS_update (GSA_stats, + "# performance updates given to clients", 1, + GNUNET_NO); + } +} + + +/** + * Handle 'reservation request' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_reservation_request (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct ReservationRequestMessage *msg = + (const struct ReservationRequestMessage *) message; + struct ReservationResultMessage result; + int32_t amount; + struct GNUNET_TIME_Relative res_delay; + + if (NULL == find_client (client)) + { + /* missing start message! */ + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", + "RESERVATION_REQUEST"); + amount = (int32_t) ntohl (msg->amount); + res_delay = GAS_reservations_reserve (&msg->peer, amount); + if (res_delay.rel_value > 0) + amount = 0; + result.header.size = htons (sizeof (struct ReservationResultMessage)); + result.header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT); + result.amount = htonl (amount); + result.peer = msg->peer; + result.res_delay = GNUNET_TIME_relative_hton (res_delay); + GNUNET_STATISTICS_update (GSA_stats, "# reservation requests processed", 1, + GNUNET_NO); + GNUNET_SERVER_notification_context_unicast (nc, client, &result.header, + GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handle 'preference change' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_preference_change (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct ChangePreferenceMessage *msg; + const struct PreferenceInformation *pi; + uint16_t msize; + uint32_t nump; + uint32_t i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", + "PREFERENCE_CHANGE"); + msize = ntohs (message->size); + if (msize < sizeof (struct ChangePreferenceMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msg = (const struct ChangePreferenceMessage *) message; + nump = ntohl (msg->num_preferences); + if (msize != + sizeof (struct ChangePreferenceMessage) + + nump * sizeof (struct PreferenceInformation)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_STATISTICS_update (GSA_stats, "# preference change requests processed", + 1, GNUNET_NO); + pi = (const struct PreferenceInformation *) &msg[1]; + for (i = 0; i < nump; i++) + GAS_addresses_change_preference (&msg->peer, + (enum GNUNET_ATS_PreferenceKind) + ntohl (pi[i].preference_kind), + pi[i].preference_value); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Initialize performance subsystem. + * + * @param server handle to our server + */ +void +GAS_performance_init (struct GNUNET_SERVER_Handle *server) +{ + nc = GNUNET_SERVER_notification_context_create (server, 128); +} + + +/** + * Shutdown performance subsystem. + */ +void +GAS_performance_done () +{ + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; +} + +/* end of gnunet-service-ats_performance.c */ diff --git a/src/ats/gnunet-service-ats_performance.h b/src/ats/gnunet-service-ats_performance.h new file mode 100644 index 0000000..75d555a --- /dev/null +++ b/src/ats/gnunet-service-ats_performance.h @@ -0,0 +1,123 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats_performance.h + * @brief ats service, interaction with 'performance' API + * @author Matthias Wachs + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_ATS_PERFORMANCE_H +#define GNUNET_SERVICE_ATS_PERFORMANCE_H + +#include "gnunet_util_lib.h" +#include "gnunet_ats_service.h" +#include "ats.h" + +/** + * Register a new performance client. + * + * @param client handle of the new client + * @param flag flag specifying the type of the client + */ +void +GAS_performance_add_client (struct GNUNET_SERVER_Client *client, + enum StartFlag flag); + + +/** + * Unregister a client (which may have been a performance client, + * but this is not assured). + * + * @param client handle of the (now dead) client + */ +void +GAS_performance_remove_client (struct GNUNET_SERVER_Client *client); + + +/** + * Transmit the given performance information to all performance + * clients. + * + * @param peer peer for which this is an address suggestion + * @param plugin_name 0-termintated string specifying the transport plugin + * @param plugin_addr binary address for the plugin to use + * @param plugin_addr_len number of bytes in plugin_addr + * @param atsi performance data for the address + * @param atsi_count number of performance records in 'ats' + * @param bandwidth_out assigned outbound bandwidth + * @param bandwidth_in assigned inbound bandwidth + */ +void +GAS_performance_notify_clients (const struct GNUNET_PeerIdentity *peer, + const char *plugin_name, + const void *plugin_addr, size_t plugin_addr_len, + const struct GNUNET_ATS_Information *atsi, + uint32_t atsi_count, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_out, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_in); + + +/** + * Handle 'reservation request' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_reservation_request (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + + +/** + * Handle 'preference change' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_preference_change (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + + +/** + * Initialize performance subsystem. + * + * @param server handle to our server + */ +void +GAS_performance_init (struct GNUNET_SERVER_Handle *server); + + +/** + * Shutdown performance subsystem. + */ +void +GAS_performance_done (void); + + +/* FIXME: add API to broadcast performance updates! */ + +#endif +/* end of gnunet-service-ats_performance.h */ diff --git a/src/ats/gnunet-service-ats_reservations.c b/src/ats/gnunet-service-ats_reservations.c new file mode 100644 index 0000000..d1212dd --- /dev/null +++ b/src/ats/gnunet-service-ats_reservations.c @@ -0,0 +1,157 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats_reservations.c + * @brief ats service, inbound bandwidth reservation management + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-ats_reservations.h" + +/** + * Number of seconds that available bandwidth carries over + * (can accumulate). + */ +#define MAX_BANDWIDTH_CARRY_S 5 + + +/** + * Map of peer identities to 'struct GNUNET_BANDWIDTH_Tracker *'s + */ +static struct GNUNET_CONTAINER_MultiHashMap *trackers; + + +/** + * Reserve the given amount of incoming bandwidth (in bytes) from the + * given peer. If a reservation is not possible right now, return how + * long the client should wait before trying again. + * + * @param peer peer to reserve bandwidth from + * @param amount number of bytes to reserve + * @return 0 if the reservation was successful, FOREVER if the + * peer is not connected, otherwise the time to wait + * until the reservation might succeed + */ +struct GNUNET_TIME_Relative +GAS_reservations_reserve (const struct GNUNET_PeerIdentity *peer, + int32_t amount) +{ + struct GNUNET_BANDWIDTH_Tracker *tracker; + struct GNUNET_TIME_Relative ret; + + tracker = GNUNET_CONTAINER_multihashmap_get (trackers, &peer->hashPubKey); + if (NULL == tracker) + return GNUNET_TIME_UNIT_ZERO; /* not connected, satisfy now */ + if (amount >= 0) + { + ret = GNUNET_BANDWIDTH_tracker_get_delay (tracker, amount); + if (ret.rel_value > 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Delay to satisfy reservation for %d bytes is %llu ms\n", + (int) amount, (unsigned long long) ret.rel_value); + return ret; + } + } + (void) GNUNET_BANDWIDTH_tracker_consume (tracker, amount); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reserved %d bytes\n", (int) amount); + return GNUNET_TIME_UNIT_ZERO; +} + + +/** + * Set the amount of bandwidth the other peer could currently transmit + * to us (as far as we know) to the given value. + * + * @param peer identity of the peer + * @param bandwidth_in currently available bandwidth from that peer to + * this peer (estimate) + */ +void +GAS_reservations_set_bandwidth (const struct GNUNET_PeerIdentity *peer, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in) +{ + struct GNUNET_BANDWIDTH_Tracker *tracker; + + tracker = GNUNET_CONTAINER_multihashmap_get (trackers, &peer->hashPubKey); + if (0 == ntohl (bandwidth_in.value__)) + { + if (NULL == tracker) + return; + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (trackers, + &peer->hashPubKey, + tracker)); + GNUNET_free (tracker); + return; + } + if (NULL == tracker) + { + tracker = GNUNET_malloc (sizeof (struct GNUNET_BANDWIDTH_Tracker)); + GNUNET_BANDWIDTH_tracker_init (tracker, bandwidth_in, + MAX_BANDWIDTH_CARRY_S); + GNUNET_CONTAINER_multihashmap_put (trackers, &peer->hashPubKey, tracker, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + return; + } + GNUNET_BANDWIDTH_tracker_update_quota (tracker, bandwidth_in); +} + + +/** + * Initialize reservations subsystem. + */ +void +GAS_reservations_init () +{ + trackers = GNUNET_CONTAINER_multihashmap_create (128); +} + + +/** + * Free memory of bandwidth tracker. + * + * @param cls NULL + * @param key peer identity (unused) + * @param value the 'struct GNUNET_BANDWIDTH_Tracker' to free + * @return GNUNET_OK (continue to iterate) + */ +static int +free_tracker (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_BANDWIDTH_Tracker *tracker = value; + + GNUNET_free (tracker); + return GNUNET_OK; +} + + +/** + * Shutdown reservations subsystem. + */ +void +GAS_reservations_done () +{ + GNUNET_CONTAINER_multihashmap_iterate (trackers, &free_tracker, NULL); + GNUNET_CONTAINER_multihashmap_destroy (trackers); +} + +/* end of gnunet-service-ats_reservations.c */ diff --git a/src/ats/gnunet-service-ats_reservations.h b/src/ats/gnunet-service-ats_reservations.h new file mode 100644 index 0000000..5ddec9b --- /dev/null +++ b/src/ats/gnunet-service-ats_reservations.h @@ -0,0 +1,75 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats_reservations.h + * @brief ats service, inbound bandwidth reservation management + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_ATS_RESERVATIONS_H +#define GNUNET_SERVICE_ATS_RESERVATIONS_H + +#include "gnunet_util_lib.h" + + +/** + * Set the amount of bandwidth the other peer could currently transmit + * to us (as far as we know) to the given value. + * + * @param peer identity of the peer + * @param bandwidth_in currently available bandwidth from that peer to + * this peer (estimate) + */ +void +GAS_reservations_set_bandwidth (const struct GNUNET_PeerIdentity *peer, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_in); + + +/** + * Reserve the given amount of incoming bandwidth (in bytes) from the + * given peer. If a reservation is not possible right now, return how + * long the client should wait before trying again. + * + * @param peer peer to reserve bandwidth from + * @param amount number of bytes to reserve + * @return 0 if the reservation was successful, FOREVER if the + * peer is not connected, otherwise the time to wait + * until the reservation might succeed + */ +struct GNUNET_TIME_Relative +GAS_reservations_reserve (const struct GNUNET_PeerIdentity *peer, + int32_t amount); + + +/** + * Initialize reservations subsystem. + */ +void +GAS_reservations_init (void); + + +/** + * Shutdown reservations subsystem. + */ +void +GAS_reservations_done (void); + +#endif diff --git a/src/ats/gnunet-service-ats_scheduling.c b/src/ats/gnunet-service-ats_scheduling.c new file mode 100644 index 0000000..72b72cd --- /dev/null +++ b/src/ats/gnunet-service-ats_scheduling.c @@ -0,0 +1,409 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats_scheduling.c + * @brief ats service, interaction with 'scheduling' API + * @author Matthias Wachs + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-ats.h" +#include "gnunet-service-ats_addresses.h" +#include "gnunet-service-ats_scheduling.h" +#include "ats.h" + + +/** + * Context for sending messages to clients. + */ +static struct GNUNET_SERVER_NotificationContext *nc; + +/** + * Actual handle to the client. + */ +static struct GNUNET_SERVER_Client *my_client; + + +/** + * Register a new scheduling client. + * + * @param client handle of the new client + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GAS_scheduling_add_client (struct GNUNET_SERVER_Client *client) +{ + if (my_client != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "This ATS already has a scheduling client, refusing new scheduling client for now.\n"); + return GNUNET_SYSERR; + } + my_client = client; + GNUNET_SERVER_notification_context_add (nc, client); + GNUNET_SERVER_client_keep (client); + return GNUNET_OK; +} + + +/** + * Unregister a client (which may have been a scheduling client, + * but this is not assured). + * + * @param client handle of the (now dead) client + */ +void +GAS_scheduling_remove_client (struct GNUNET_SERVER_Client *client) +{ + if (my_client != client) + return; + GAS_addresses_destroy_all (); + GNUNET_SERVER_client_drop (client); + my_client = NULL; +} + + +/** + * Transmit the given address suggestion and bandwidth update to all scheduling + * clients. + * + * @param peer peer for which this is an address suggestion + * @param plugin_name 0-termintated string specifying the transport plugin + * @param plugin_addr binary address for the plugin to use + * @param plugin_addr_len number of bytes in plugin_addr + * @param session_id session ID to use for the given client (other clients will see 0) + * @param atsi performance data for the address + * @param atsi_count number of performance records in 'ats' + * @param bandwidth_out assigned outbound bandwidth + * @param bandwidth_in assigned inbound bandwidth + */ +void +GAS_scheduling_transmit_address_suggestion (const struct GNUNET_PeerIdentity + *peer, const char *plugin_name, + const void *plugin_addr, + size_t plugin_addr_len, + uint32_t session_id, + const struct GNUNET_ATS_Information + *atsi, uint32_t atsi_count, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_out, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_in) +{ + struct AddressSuggestionMessage *msg; + size_t plugin_name_length = strlen (plugin_name) + 1; + size_t msize = + sizeof (struct AddressSuggestionMessage) + + atsi_count * sizeof (struct GNUNET_ATS_Information) + plugin_addr_len + + plugin_name_length; + char buf[msize]; + struct GNUNET_ATS_Information *atsp; + char *addrp; + + if (my_client == NULL) + return; + GNUNET_STATISTICS_update (GSA_stats, "# address suggestions made", 1, + GNUNET_NO); + GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); + GNUNET_assert (atsi_count < + GNUNET_SERVER_MAX_MESSAGE_SIZE / + sizeof (struct GNUNET_ATS_Information)); + msg = (struct AddressSuggestionMessage *) buf; + msg->header.size = htons (msize); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION); + msg->ats_count = htonl (atsi_count); + msg->peer = *peer; + msg->address_length = htons (plugin_addr_len); + msg->plugin_name_length = htons (plugin_name_length); + msg->session_id = htonl (session_id); + msg->bandwidth_out = bandwidth_out; + msg->bandwidth_in = bandwidth_in; + atsp = (struct GNUNET_ATS_Information *) &msg[1]; + memcpy (atsp, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count); + addrp = (char *) &atsp[atsi_count]; + memcpy (addrp, plugin_addr, plugin_addr_len); + strcpy (&addrp[plugin_addr_len], plugin_name); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "ATS sends quota for peer `%s': (in/out) %u/%u\n", + GNUNET_i2s (peer), ntohl (bandwidth_in.value__), + ntohl (bandwidth_out.value__)); + + GNUNET_SERVER_notification_context_unicast (nc, my_client, &msg->header, + GNUNET_YES); +} + + +/** + * Handle 'request address' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_request_address (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct RequestAddressMessage *msg = + (const struct RequestAddressMessage *) message; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", + "REQUEST_ADDRESS"); + GNUNET_STATISTICS_update (GSA_stats, "# address requests received", 1, + GNUNET_NO); + GNUNET_break (0 == ntohl (msg->reserved)); + GAS_addresses_request_address (&msg->peer); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handle 'request address' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_request_address_cancel (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct RequestAddressMessage *msg = + (const struct RequestAddressMessage *) message; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", + "REQUEST_ADDRESS_CANCEL"); + GNUNET_break (0 == ntohl (msg->reserved)); + + /* TODO */ + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handle 'address update' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_address_update (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct AddressUpdateMessage *m; + const struct GNUNET_ATS_Information *atsi; + const char *address; + const char *plugin_name; + uint16_t address_length; + uint16_t plugin_name_length; + uint32_t ats_count; + uint16_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", + "ADDRESS_UPDATE"); + size = ntohs (message->size); + if (size < sizeof (struct AddressUpdateMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + m = (const struct AddressUpdateMessage *) message; + ats_count = ntohl (m->ats_count); + address_length = ntohs (m->address_length); + plugin_name_length = ntohs (m->plugin_name_length); + atsi = (const struct GNUNET_ATS_Information *) &m[1]; + address = (const char *) &atsi[ats_count]; + if (plugin_name_length != 0) + plugin_name = &address[address_length]; + else + plugin_name = ""; + + if ((address_length + plugin_name_length + + ats_count * sizeof (struct GNUNET_ATS_Information) + + sizeof (struct AddressUpdateMessage) != ntohs (message->size)) || + (ats_count > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)) || + ((plugin_name_length > 0) && (plugin_name[plugin_name_length - 1] != '\0'))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_STATISTICS_update (GSA_stats, "# address updates received", 1, + GNUNET_NO); + GAS_addresses_update (&m->peer, plugin_name, address, address_length, + ntohl (m->session_id), atsi, ats_count); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handle 'address in use' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_address_in_use (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct AddressUseMessage *m; + const char *address; + const char *plugin_name; + uint16_t address_length; + uint16_t plugin_name_length; + + uint16_t size; + uint16_t in_use; + + size = ntohs (message->size); + if (size < sizeof (struct AddressUseMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + m = (const struct AddressUseMessage *) message; + + address_length = ntohs (m->address_length); + plugin_name_length = ntohs (m->plugin_name_length); + + address = (const char *) &m[1]; + if (plugin_name_length != 0) + plugin_name = &address[address_length]; + else + plugin_name = ""; + + if ((address_length + plugin_name_length + + sizeof (struct AddressUseMessage) != ntohs (message->size)) || + ((plugin_name_length > 0) && + (plugin_name[plugin_name_length - 1] != '\0'))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + in_use = ntohs (m->in_use); + GAS_addresses_in_use (&m->peer, plugin_name, address, address_length, + ntohl (m->session_id), in_use); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + +/** + * Handle 'address destroyed' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_address_destroyed (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct AddressDestroyedMessage *m; + struct SessionReleaseMessage srm; + const char *address; + const char *plugin_name; + uint16_t address_length; + uint16_t plugin_name_length; + uint16_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message of size %u %u\n", + "ADDRESS_DESTROYED", ntohs (message->size), + sizeof (struct AddressDestroyedMessage)); + size = ntohs (message->size); + if ((size < sizeof (struct AddressDestroyedMessage)) || (client != my_client)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + m = (const struct AddressDestroyedMessage *) message; + GNUNET_break (0 == ntohl (m->reserved)); + address_length = ntohs (m->address_length); + plugin_name_length = ntohs (m->plugin_name_length); + address = (const char *) &m[1]; + if (plugin_name_length != 0) + plugin_name = &address[address_length]; + else + plugin_name = ""; + if ((address_length + plugin_name_length + + sizeof (struct AddressDestroyedMessage) != ntohs (message->size))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if ((plugin_name_length == 0) || + (plugin_name[plugin_name_length - 1] != '\0')) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_STATISTICS_update (GSA_stats, "# addresses destroyed", 1, GNUNET_NO); + GAS_addresses_destroy (&m->peer, plugin_name, address, address_length, + ntohl (m->session_id)); + if (0 != ntohl (m->session_id)) + { + srm.header.type = ntohs (GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE); + srm.header.size = ntohs (sizeof (struct SessionReleaseMessage)); + srm.session_id = m->session_id; + srm.peer = m->peer; + GNUNET_SERVER_notification_context_unicast (nc, client, &srm.header, + GNUNET_NO); + } + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Initialize scheduling subsystem. + * + * @param server handle to our server + */ +void +GAS_scheduling_init (struct GNUNET_SERVER_Handle *server) +{ + nc = GNUNET_SERVER_notification_context_create (server, 128); +} + + +/** + * Shutdown scheduling subsystem. + */ +void +GAS_scheduling_done () +{ + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; +} + + +/* end of gnunet-service-ats_scheduling.c */ diff --git a/src/ats/gnunet-service-ats_scheduling.h b/src/ats/gnunet-service-ats_scheduling.h new file mode 100644 index 0000000..45fca2f --- /dev/null +++ b/src/ats/gnunet-service-ats_scheduling.h @@ -0,0 +1,158 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file ats/gnunet-service-ats_scheduling.h + * @brief ats service, interaction with 'scheduling' API + * @author Matthias Wachs + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_ATS_SCHEDULING_H +#define GNUNET_SERVICE_ATS_SCHEDULING_H + +#include "gnunet_util_lib.h" + + +/** + * Register a new scheduling client. + * + * @param client handle of the new client + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GAS_scheduling_add_client (struct GNUNET_SERVER_Client *client); + + +/** + * Unregister a client (which may have been a scheduling client, + * but this is not assured). + * + * @param client handle of the (now dead) client + */ +void +GAS_scheduling_remove_client (struct GNUNET_SERVER_Client *client); + + +/** + * Transmit the given address suggestion and bandwidth update to all scheduling + * clients. + * + * @param peer peer for which this is an address suggestion + * @param plugin_name 0-termintated string specifying the transport plugin + * @param plugin_addr binary address for the plugin to use + * @param plugin_addr_len number of bytes in plugin_addr + * @param session_id session ID to use + * @param atsi performance data for the address + * @param atsi_count number of performance records in 'ats' + * @param bandwidth_out assigned outbound bandwidth + * @param bandwidth_in assigned inbound bandwidth + */ +void +GAS_scheduling_transmit_address_suggestion (const struct GNUNET_PeerIdentity + *peer, const char *plugin_name, + const void *plugin_addr, + size_t plugin_addr_len, + uint32_t session_id, + const struct GNUNET_ATS_Information + *atsi, uint32_t atsi_count, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_out, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_in); + + +/** + * Handle 'request address' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_request_address (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + + +/** + * Cancel 'request address' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_request_address_cancel (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + +/** + * Handle 'address update' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_address_update (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + + +/** + * Handle 'address in use' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_address_in_use (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + + +/** + * Handle 'address destroyed' messages from clients. + * + * @param cls unused, NULL + * @param client client that sent the request + * @param message the request message + */ +void +GAS_handle_address_destroyed (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + + +/** + * Initialize scheduling subsystem. + * + * @param server handle to our server + */ +void +GAS_scheduling_init (struct GNUNET_SERVER_Handle *server); + + +/** + * Shutdown scheduling subsystem. + */ +void +GAS_scheduling_done (void); + + +#endif +/* end of gnunet-service-ats_scheduling.h */ diff --git a/src/ats/perf_ats_mlp.c b/src/ats/perf_ats_mlp.c new file mode 100644 index 0000000..a15e4b4 --- /dev/null +++ b/src/ats/perf_ats_mlp.c @@ -0,0 +1,138 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file ats/test_ats_mlp.c + * @brief test for the MLP solver + * @author Christian Grothoff + * @author Matthias Wachs + + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet-service-ats_addresses_mlp.h" + +#define VERBOSE GNUNET_YES +#define VERBOSE_ARM GNUNET_NO + +#define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3) +#define MLP_MAX_ITERATIONS INT_MAX + + +static int ret; + +struct GNUNET_STATISTICS_Handle * stats; + +struct GNUNET_CONTAINER_MultiHashMap * addresses; + +struct GAS_MLP_Handle *mlp; + +static void +check (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ +#if !HAVE_LIBGLPK + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed!"); + ret = 1; + return; +#endif + struct ATS_Address addr[10]; + + stats = GNUNET_STATISTICS_create("ats", cfg); + + addresses = GNUNET_CONTAINER_multihashmap_create (10); + + GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &addr[0].peer.hashPubKey); + addr[0].mlp_information = NULL; + addr[0].next = NULL; + addr[0].prev = NULL; + addr[0].plugin = strdup ("dummy"); + + addr[1].peer = addr[0].peer; + addr[1].mlp_information = NULL; + addr[1].next = NULL; + addr[1].prev = NULL; + addr[1].plugin = strdup ("dummy2"); + + GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[0], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + + mlp = GAS_mlp_init (cfg, NULL, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS); + + /* Add a new address */ +#if 0 + GAS_mlp_address_update (mlp, addresses, &addr[0]); + + GNUNET_assert (mlp != NULL); + GNUNET_assert (mlp->addr_in_problem == 1); + + /* Update an new address */ + GAS_mlp_address_update (mlp, addresses, &addr[0]); + GNUNET_assert (mlp->addr_in_problem == 1); + + /* Add a second address for same peer */ + GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[1], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + GAS_mlp_address_update (mlp, addresses, &addr[1]); + GNUNET_assert (mlp->addr_in_problem == 2); + + /* Delete an address */ + GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[0].peer.hashPubKey, &addr[0]); + GAS_mlp_address_delete (mlp, addresses, &addr[0]); + GAS_mlp_address_delete (mlp, addresses, &addr[1]); +#endif + GAS_mlp_done (mlp); + + GNUNET_free (addr[0].plugin); + GNUNET_free (addr[1].plugin); + GNUNET_CONTAINER_multihashmap_destroy (addresses); + GNUNET_STATISTICS_destroy(stats, GNUNET_NO); + + ret = 0; + return; +} + + +int +main (int argc, char *argv[]) +{ + + static char *const argv2[] = { "test_ats_mlp", + "-c", + "test_ats_api.conf", +#if VERBOSE + "-L", "DEBUG", +#else + "-L", "WARNING", +#endif + NULL + }; + + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test_ats_mlp", "nohelp", options, + &check, NULL); + + + return ret; +} + +/* end of file test_ats_api_bandwidth_consumption.c */ diff --git a/src/ats/test_ats_api.conf b/src/ats/test_ats_api.conf new file mode 100644 index 0000000..fa379c9 --- /dev/null +++ b/src/ats/test_ats_api.conf @@ -0,0 +1,24 @@ +[PATHS] +SERVICEHOME = /tmp/test-ats-api-scheduling/ + +[arm] +PORT = 12001 +DEFAULTSERVICES = ats +UNIXPATH = /tmp/test-ats-scheduling-arm.sock + +[ats] +#DEBUG = YES +#PREFIX = valgrind --leak-check=full +#WAN_QUOTA_OUT = 4294967295 +#WAN_QUOTA_IN = 4294967295 +AUTOSTART = YES +PORT = 12002 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-ats +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-ats-scheduling-ats.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES \ No newline at end of file diff --git a/src/ats/test_ats_api_scheduling.c b/src/ats/test_ats_api_scheduling.c new file mode 100644 index 0000000..892186c --- /dev/null +++ b/src/ats/test_ats_api_scheduling.c @@ -0,0 +1,264 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file ats/test_ats_api_scheduling.c + * @brief test automatic transport selection scheduling API + * @author Christian Grothoff + * @author Matthias Wachs + * + * TODO: + * - write test case + * - extend API to get performance data + * - implement simplistic strategy based on say 'lowest latency' or strict ordering + * - extend API to get peer preferences, implement proportional bandwidth assignment + * - re-implement API against a real ATS service (!) + */ +#include "platform.h" +#include "gnunet_ats_service.h" +#include "ats.h" + +#define VERBOSE GNUNET_NO + +#define VERBOSE_ARM GNUNET_NO + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static struct GNUNET_ATS_SchedulingHandle *ats; + +struct GNUNET_OS_Process *arm_proc; + + + +static int ret; + +struct Address +{ + char *plugin; + size_t plugin_len; + + void *addr; + size_t addr_len; + + struct GNUNET_ATS_Information *ats; + int ats_count; + + void *session; +}; + +struct PeerContext +{ + struct GNUNET_PeerIdentity id; + + struct Address *addr; +}; + +struct Address addr[2]; +struct PeerContext p[2]; +struct GNUNET_ATS_Information atsi[2]; + +static void +stop_arm () +{ + if (0 != GNUNET_OS_process_kill (arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + GNUNET_OS_process_wait (arm_proc); + GNUNET_OS_process_close (arm_proc); + arm_proc = NULL; +} + + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + if (ats != NULL) + GNUNET_ATS_scheduling_done (ats); + + ret = GNUNET_SYSERR; + + stop_arm (); +} + + +static void +end () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + } + + GNUNET_ATS_scheduling_done (ats); + + ret = 0; + + stop_arm (); +} + + +static void +address_suggest_cb (void *cls, const struct GNUNET_HELLO_Address *address, + struct Session *session, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS suggests address `%s'\n", + GNUNET_i2s (&address->peer)); + + GNUNET_assert (0 == + memcmp (&address->peer, &p[0].id, + sizeof (struct GNUNET_PeerIdentity))); + GNUNET_assert (0 == strcmp (address->transport_name, addr[0].plugin)); + GNUNET_assert (address->address_length == addr[0].addr_len); + GNUNET_assert (0 == + memcmp (address->address, addr[0].plugin, + address->address_length)); + GNUNET_assert (addr[0].session == session); + + + /* TODO ats merge + * GNUNET_assert (ats_count == 2); + * GNUNET_assert (atsi[0].type == htons (1)); + * GNUNET_assert (atsi[0].type == htons (2)); + * GNUNET_assert (atsi[1].type == htons (2)); + * GNUNET_assert (atsi[1].type == htons (2)); + */ + + ret = 0; + + GNUNET_SCHEDULER_add_now (&end, NULL); +} + +void +start_arm (const char *cfgname) +{ + arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE_ARM + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +} + +static void +check (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_HELLO_Address address0; + + ret = GNUNET_SYSERR; + + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + start_arm (cfgfile); + + ats = GNUNET_ATS_scheduling_init (cfg, &address_suggest_cb, NULL); + + if (ats == NULL) + { + ret = GNUNET_SYSERR; + end (); + return; + } + + /* set up peer */ + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, + &p[0].id.hashPubKey); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created peer `%s'\n", + GNUNET_i2s (&p[0].id)); + + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, + &p[1].id.hashPubKey); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created peer `%s'\n", + GNUNET_i2s (&p[1].id)); + + addr[0].plugin = "test"; + addr[0].session = NULL; + addr[0].addr = GNUNET_strdup ("test"); + addr[0].addr_len = 4; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing address creation\n"); + + address0.peer = p[0].id; + address0.transport_name = addr[0].plugin; + address0.address = addr[0].addr; + address0.address_length = addr[0].addr_len; + GNUNET_ATS_address_update (ats, &address0, addr[0].session, NULL, 0); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing ATS info creation\n"); + + atsi[0].type = htonl (GNUNET_ATS_UTILIZATION_UP); + atsi[0].value = htonl (1024); + + GNUNET_ATS_address_update (ats, &address0, addr[0].session, atsi, 1); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing ATS info update\n"); + + atsi[0].type = htonl (GNUNET_ATS_UTILIZATION_UP); + atsi[0].value = htonl (2048); + + atsi[1].type = htonl (GNUNET_ATS_UTILIZATION_DOWN); + atsi[1].value = htonl (1024); + + GNUNET_ATS_address_update (ats, &address0, addr[0].session, atsi, 2); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing manual address deletion \n"); + address0.peer = p[1].id; // FIXME: why? typo in old code? + GNUNET_ATS_address_update (ats, &address0, addr[0].session, NULL, 0); + GNUNET_ATS_address_destroyed (ats, &address0, addr[0].session); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting peer `%s'\n", + GNUNET_i2s (&p[0].id)); + GNUNET_ATS_suggest_address (ats, &p[0].id); +} + +int +main (int argc, char *argv[]) +{ + static char *const argv2[] = { "test_ats_api_scheduling", + "-c", + "test_ats_api.conf", +#if VERBOSE + "-L", "DEBUG", +#else + "-L", "WARNING", +#endif + NULL + }; + + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test_ats_api_scheduling", "nohelp", options, &check, + NULL); + + + return ret; +} + +/* end of file test_ats_api_scheduling.c */ diff --git a/src/ats/test_ats_mlp.c b/src/ats/test_ats_mlp.c new file mode 100644 index 0000000..14df2d0 --- /dev/null +++ b/src/ats/test_ats_mlp.c @@ -0,0 +1,199 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file ats/test_ats_mlp.c + * @brief test for the MLP solver + * @author Christian Grothoff + * @author Matthias Wachs + + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_ats_service.h" +#include "gnunet-service-ats_addresses_mlp.h" + +#define VERBOSE GNUNET_YES +#define VERBOSE_ARM GNUNET_NO + +#define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3) +#define MLP_MAX_ITERATIONS INT_MAX + + +static int ret; + +struct GNUNET_STATISTICS_Handle * stats; + +struct GNUNET_CONTAINER_MultiHashMap * addresses; + +struct GAS_MLP_Handle *mlp; + + +static void +create_address (struct ATS_Address *addr, char * plugin, int ats_count, struct GNUNET_ATS_Information *ats) +{ + addr->mlp_information = NULL; + addr->next = NULL; + addr->prev = NULL; + addr->plugin = strdup (plugin); + addr->ats_count = ats_count; + addr->ats = ats; +} + +static void +set_ats (struct GNUNET_ATS_Information *ats, uint32_t type, uint32_t value) +{ + ats->type = type; + ats->value = value; +} + +static void +check (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ +#if !HAVE_LIBGLPK + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed!"); + ret = 1; + return; +#endif + struct ATS_Address addr[10]; + struct ATS_PreferedAddress *res[10]; + + stats = GNUNET_STATISTICS_create("ats", cfg); + + addresses = GNUNET_CONTAINER_multihashmap_create (10); + + mlp = GAS_mlp_init (cfg, NULL, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS); + mlp->auto_solve = GNUNET_NO; + + struct GNUNET_PeerIdentity p[10]; + + /* Creating peer 1 */ + GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &p[0].hashPubKey); + /* Creating peer 2 */ + GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &p[1].hashPubKey); + + /* Creating peer 1 address 1 */ + addr[0].peer.hashPubKey = p[0].hashPubKey; + struct GNUNET_ATS_Information a1_ats[3]; + set_ats (&a1_ats[0], GNUNET_ATS_QUALITY_NET_DISTANCE, 1); + set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 1); + set_ats (&a1_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0); + create_address (&addr[0], "dummy", 3, &a1_ats[0]); + addr[0].atsp_network_type = GNUNET_ATS_NET_WAN; + + /* Creating peer 1 address 2 */ + addr[1].peer.hashPubKey = p[0].hashPubKey; + struct GNUNET_ATS_Information a2_ats[3]; + set_ats (&a2_ats[1], GNUNET_ATS_QUALITY_NET_DISTANCE, 1); + set_ats (&a2_ats[0], GNUNET_ATS_QUALITY_NET_DELAY, 1); + set_ats (&a2_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0); + create_address (&addr[1], "dummy2", 3, &a2_ats[0]); + addr[1].atsp_network_type = GNUNET_ATS_NET_LAN; + + /* Creating peer 2 address 1 */ + addr[2].peer.hashPubKey = p[1].hashPubKey; + struct GNUNET_ATS_Information a3_ats[3]; + set_ats (&a3_ats[1], GNUNET_ATS_QUALITY_NET_DISTANCE, 1); + set_ats (&a3_ats[0], GNUNET_ATS_QUALITY_NET_DELAY, 1); + set_ats (&a3_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0); + create_address (&addr[2], "dummy3", 3, &a3_ats[0]); + addr[2].atsp_network_type = GNUNET_ATS_NET_LAN; + + GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[0], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + + /* Add peer 1 address 1 */ + GAS_mlp_address_update (mlp, addresses, &addr[0]); + + GNUNET_assert (mlp != NULL); + GNUNET_assert (mlp->addr_in_problem == 1); + + /* Update an peer 1 address 1 */ + set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 1); + GAS_mlp_address_update (mlp, addresses, &addr[0]); + GNUNET_assert (mlp->addr_in_problem == 1); + + /* Add peer 1 address 2 */ + GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[1], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + GAS_mlp_address_update (mlp, addresses, &addr[1]); + GNUNET_assert (mlp->addr_in_problem == 2); + + /* Add peer 2 address 1 */ + GNUNET_CONTAINER_multihashmap_put(addresses, &addr[2].peer.hashPubKey, &addr[2], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + GAS_mlp_address_update (mlp, addresses, &addr[2]); + GNUNET_assert (mlp->addr_in_problem == 3); + + GNUNET_assert (GNUNET_OK == GAS_mlp_solve_problem(mlp)); + + res[0] = GAS_mlp_get_preferred_address(mlp, addresses, &p[0]); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Preferred address `%s' outbound bandwidth: %u Bps\n",res[0]->address->plugin, res[0]->bandwidth_out); + res[1] = GAS_mlp_get_preferred_address(mlp, addresses, &p[1]); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Preferred address `%s' outbound bandwidth: %u Bps\n",res[1]->address->plugin, res[1]->bandwidth_out); + + /* Delete an address */ + GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[0].peer.hashPubKey, &addr[0]); + GAS_mlp_address_delete (mlp, addresses, &addr[0]); + GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[1].peer.hashPubKey, &addr[1]); + GAS_mlp_address_delete (mlp, addresses, &addr[1]); + GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[2].peer.hashPubKey, &addr[2]); + GAS_mlp_address_delete (mlp, addresses, &addr[2]); + + GNUNET_assert (mlp->addr_in_problem == 0); + + GAS_mlp_done (mlp); + + GNUNET_free (addr[0].plugin); + GNUNET_free (addr[1].plugin); + GNUNET_CONTAINER_multihashmap_destroy (addresses); + GNUNET_STATISTICS_destroy(stats, GNUNET_NO); + + ret = 0; + return; +} + + +int +main (int argc, char *argv[]) +{ + + static char *const argv2[] = { "test_ats_mlp", + "-c", + "test_ats_api.conf", +#if VERBOSE + "-L", "DEBUG", +#else + "-L", "WARNING", +#endif + NULL + }; + + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test_ats_mlp", "nohelp", options, + &check, NULL); + + + return ret; +} + +/* end of file test_ats_api_bandwidth_consumption.c */ diff --git a/src/ats/test_ats_mlp_averaging.c b/src/ats/test_ats_mlp_averaging.c new file mode 100644 index 0000000..f7b7b1d --- /dev/null +++ b/src/ats/test_ats_mlp_averaging.c @@ -0,0 +1,182 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file ats/test_ats_mlp.c + * @brief test for the MLP solver + * @author Christian Grothoff + * @author Matthias Wachs + + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_ats_service.h" +#include "gnunet-service-ats_addresses_mlp.h" + +#define VERBOSE GNUNET_YES +#define VERBOSE_ARM GNUNET_NO + +#define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3) +#define MLP_MAX_ITERATIONS INT_MAX + + +static int ret; + +struct GNUNET_STATISTICS_Handle * stats; + +struct GNUNET_CONTAINER_MultiHashMap * addresses; + +struct GAS_MLP_Handle *mlp; + + +static void +create_address (struct ATS_Address *addr, char * plugin, int ats_count, struct GNUNET_ATS_Information *ats) +{ + addr->mlp_information = NULL; + addr->next = NULL; + addr->prev = NULL; + addr->plugin = strdup (plugin); + addr->ats_count = ats_count; + addr->ats = ats; +} + +static void +set_ats (struct GNUNET_ATS_Information *ats, uint32_t type, uint32_t value) +{ + ats->type = type; + ats->value = value; +} + +static void +check (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ +#if !HAVE_LIBGLPK + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed!"); + ret = 1; + return; +#endif + struct ATS_Address addr[10]; + struct ATS_PreferedAddress *res[10]; + struct MLP_information *mlpi; + + stats = GNUNET_STATISTICS_create("ats", cfg); + + addresses = GNUNET_CONTAINER_multihashmap_create (10); + + mlp = GAS_mlp_init (cfg, NULL, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS); + mlp->auto_solve = GNUNET_NO; + + struct GNUNET_PeerIdentity p[10]; + + /* Creating peer 1 */ + GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &p[0].hashPubKey); + + /* Creating peer 1 address 1 */ + addr[0].peer.hashPubKey = p[0].hashPubKey; + struct GNUNET_ATS_Information a1_ats[3]; + set_ats (&a1_ats[0], GNUNET_ATS_QUALITY_NET_DISTANCE, 1); + set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 0); + set_ats (&a1_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0); + create_address (&addr[0], "dummy", 3, &a1_ats[0]); + addr[0].atsp_network_type = GNUNET_ATS_NET_LAN; + + GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[0], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + + /* Add peer 1 address 1 */ + GAS_mlp_address_update (mlp, addresses, &addr[0]); + mlpi = addr[0].mlp_information; + + GNUNET_assert (mlp != NULL); + GNUNET_assert (mlp->addr_in_problem == 1); + + /* Update an peer 1 address 1 */ + set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 20); + GAS_mlp_address_update (mlp, addresses, &addr[0]); + GNUNET_assert (mlp->addr_in_problem == 1); + + + /* Update an peer 1 address 1 */ + set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 10); + GAS_mlp_address_update (mlp, addresses, &addr[0]); + GNUNET_assert (mlp->addr_in_problem == 1); + + /* Update an peer 1 address 1 */ + set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 10); + GAS_mlp_address_update (mlp, addresses, &addr[0]); + GNUNET_assert (mlp->addr_in_problem == 1); + + /* Update an peer 1 address 1 */ + set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 30); + GAS_mlp_address_update (mlp, addresses, &addr[0]); + GNUNET_assert (mlp->addr_in_problem == 1); + + + GNUNET_assert (GNUNET_OK == GAS_mlp_solve_problem(mlp)); + + res[0] = GAS_mlp_get_preferred_address(mlp, addresses, &p[0]); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Preferred address `%s' outbound bandwidth: %u Bps\n",res[0]->address->plugin, res[0]->bandwidth_out); + GNUNET_free (res[0]); + + /* Delete an address */ + GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[0].peer.hashPubKey, &addr[0]); + GAS_mlp_address_delete (mlp, addresses, &addr[0]); + + GNUNET_assert (mlp->addr_in_problem == 0); + + GAS_mlp_done (mlp); + + GNUNET_free (addr[0].plugin); + GNUNET_CONTAINER_multihashmap_destroy (addresses); + GNUNET_STATISTICS_destroy(stats, GNUNET_NO); + + ret = 0; + return; +} + + +int +main (int argc, char *argv[]) +{ + + static char *const argv2[] = { "test_ats_mlp", + "-c", + "test_ats_api.conf", +#if VERBOSE + "-L", "DEBUG", +#else + "-L", "WARNING", +#endif + NULL + }; + + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test_ats_mlp", "nohelp", options, + &check, NULL); + + + return ret; +} + +/* end of file test_ats_api_bandwidth_consumption.c */ diff --git a/src/block/Makefile.am b/src/block/Makefile.am new file mode 100644 index 0000000..78680ee --- /dev/null +++ b/src/block/Makefile.am @@ -0,0 +1,58 @@ +INCLUDES = -I$(top_srcdir)/src/include + +plugindir = $(libdir)/gnunet + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage +endif + +lib_LTLIBRARIES = libgnunetblock.la + +plugin_LTLIBRARIES = \ + libgnunet_plugin_block_template.la \ + libgnunet_plugin_block_test.la + + +libgnunet_plugin_block_template_la_SOURCES = \ + plugin_block_template.c +libgnunet_plugin_block_template_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_block_template_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_block_test_la_SOURCES = \ + plugin_block_test.c +libgnunet_plugin_block_test_la_LIBADD = \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_block_test_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) +libgnunet_plugin_block_test_la_DEPENDENCIES = \ + libgnunetblock.la + + +libgnunetblock_la_SOURCES = \ + block.c +libgnunetblock_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunetblock_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunetblock_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +check_PROGRAMS = \ + test_block + +#TESTS = $(check_PROGRAMS) + +test_block_SOURCES = \ + test_block.c +test_block_LDADD = \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/util/libgnunetutil.la + diff --git a/src/block/Makefile.in b/src/block/Makefile.in new file mode 100644 index 0000000..b494dfa --- /dev/null +++ b/src/block/Makefile.in @@ -0,0 +1,768 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +check_PROGRAMS = test_block$(EXEEXT) +subdir = src/block +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) +libgnunet_plugin_block_template_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunet_plugin_block_template_la_OBJECTS = \ + plugin_block_template.lo +libgnunet_plugin_block_template_la_OBJECTS = \ + $(am_libgnunet_plugin_block_template_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_block_template_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_block_template_la_LDFLAGS) $(LDFLAGS) -o $@ +am_libgnunet_plugin_block_test_la_OBJECTS = plugin_block_test.lo +libgnunet_plugin_block_test_la_OBJECTS = \ + $(am_libgnunet_plugin_block_test_la_OBJECTS) +libgnunet_plugin_block_test_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_block_test_la_LDFLAGS) $(LDFLAGS) -o $@ +am_libgnunetblock_la_OBJECTS = block.lo +libgnunetblock_la_OBJECTS = $(am_libgnunetblock_la_OBJECTS) +libgnunetblock_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetblock_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +am_test_block_OBJECTS = test_block.$(OBJEXT) +test_block_OBJECTS = $(am_test_block_OBJECTS) +test_block_DEPENDENCIES = $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunet_plugin_block_template_la_SOURCES) \ + $(libgnunet_plugin_block_test_la_SOURCES) \ + $(libgnunetblock_la_SOURCES) $(test_block_SOURCES) +DIST_SOURCES = $(libgnunet_plugin_block_template_la_SOURCES) \ + $(libgnunet_plugin_block_test_la_SOURCES) \ + $(libgnunetblock_la_SOURCES) $(test_block_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +plugindir = $(libdir)/gnunet +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage +lib_LTLIBRARIES = libgnunetblock.la +plugin_LTLIBRARIES = \ + libgnunet_plugin_block_template.la \ + libgnunet_plugin_block_test.la + +libgnunet_plugin_block_template_la_SOURCES = \ + plugin_block_template.c + +libgnunet_plugin_block_template_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_block_template_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_block_test_la_SOURCES = \ + plugin_block_test.c + +libgnunet_plugin_block_test_la_LIBADD = \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_block_test_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_block_test_la_DEPENDENCIES = \ + libgnunetblock.la + +libgnunetblock_la_SOURCES = \ + block.c + +libgnunetblock_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunetblock_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunetblock_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + + +#TESTS = $(check_PROGRAMS) +test_block_SOURCES = \ + test_block.c + +test_block_LDADD = \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/util/libgnunetutil.la + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/block/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/block/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_block_template.la: $(libgnunet_plugin_block_template_la_OBJECTS) $(libgnunet_plugin_block_template_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_block_template_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_template_la_OBJECTS) $(libgnunet_plugin_block_template_la_LIBADD) $(LIBS) +libgnunet_plugin_block_test.la: $(libgnunet_plugin_block_test_la_OBJECTS) $(libgnunet_plugin_block_test_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_block_test_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_test_la_OBJECTS) $(libgnunet_plugin_block_test_la_LIBADD) $(LIBS) +libgnunetblock.la: $(libgnunetblock_la_OBJECTS) $(libgnunetblock_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetblock_la_LINK) -rpath $(libdir) $(libgnunetblock_la_OBJECTS) $(libgnunetblock_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +test_block$(EXEEXT): $(test_block_OBJECTS) $(test_block_DEPENDENCIES) + @rm -f test_block$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_block_OBJECTS) $(test_block_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/block.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_template.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_test.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_block.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean \ + clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-libLTLIBRARIES uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/block/block.c b/src/block/block.c new file mode 100644 index 0000000..7c447f0 --- /dev/null +++ b/src/block/block.c @@ -0,0 +1,308 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file block/block.c + * @brief library for data block manipulation + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_signatures.h" +#include "gnunet_block_lib.h" +#include "gnunet_block_plugin.h" + + +/** + * Handle for a plugin. + */ +struct Plugin +{ + /** + * Name of the shared library. + */ + char *library_name; + + /** + * Plugin API. + */ + struct GNUNET_BLOCK_PluginFunctions *api; +}; + + +/** + * Handle to an initialized block library. + */ +struct GNUNET_BLOCK_Context +{ + /** + * Array of our plugins. + */ + struct Plugin **plugins; + + /** + * Size of the 'plugins' array. + */ + unsigned int num_plugins; + + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + + +/** + * Mingle hash with the mingle_number to produce different bits. + * + * @param in original hash code + * @param mingle_number number for hash permutation + * @param hc where to store the result. + */ +void +GNUNET_BLOCK_mingle_hash (const GNUNET_HashCode * in, uint32_t mingle_number, + GNUNET_HashCode * hc) +{ + GNUNET_HashCode m; + + GNUNET_CRYPTO_hash (&mingle_number, sizeof (uint32_t), &m); + GNUNET_CRYPTO_hash_xor (&m, in, hc); +} + + +/** + * Add a plugin to the list managed by the block library. + * + * @param cls the block context + * @param library_name name of the plugin + * @param lib_ret the plugin API + */ +static void +add_plugin (void *cls, const char *library_name, void *lib_ret) +{ + struct GNUNET_BLOCK_Context *ctx = cls; + struct GNUNET_BLOCK_PluginFunctions *api = lib_ret; + struct Plugin *plugin; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading block plugin `%s'\n"), + library_name); + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->api = api; + plugin->library_name = GNUNET_strdup (library_name); + GNUNET_array_append (ctx->plugins, ctx->num_plugins, plugin); +} + + + +/** + * Create a block context. Loads the block plugins. + * + * @param cfg configuration to use + * @return NULL on error + */ +struct GNUNET_BLOCK_Context * +GNUNET_BLOCK_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_BLOCK_Context *ctx; + + ctx = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_Context)); + ctx->cfg = cfg; + GNUNET_PLUGIN_load_all ("libgnunet_plugin_block_", NULL, &add_plugin, ctx); + return ctx; +} + + +/** + * Destroy the block context. + * + * @param ctx context to destroy + */ +void +GNUNET_BLOCK_context_destroy (struct GNUNET_BLOCK_Context *ctx) +{ + unsigned int i; + struct Plugin *plugin; + + for (i = 0; i < ctx->num_plugins; i++) + { + plugin = ctx->plugins[i]; + GNUNET_break (NULL == + GNUNET_PLUGIN_unload (plugin->library_name, plugin->api)); + GNUNET_free (plugin->library_name); + GNUNET_free (plugin); + } + GNUNET_free (ctx->plugins); + GNUNET_free (ctx); +} + + +/** + * Find a plugin for the given type. + * + * @param ctx context to search + * @param type type to look for + * @return NULL if no matching plugin exists + */ +static struct GNUNET_BLOCK_PluginFunctions * +find_plugin (struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type) +{ + struct Plugin *plugin; + unsigned int i; + unsigned int j; + + for (i = 0; i < ctx->num_plugins; i++) + { + plugin = ctx->plugins[i]; + j = 0; + while (0 != (plugin->api->types[j])) + { + if (type == plugin->api->types[j]) + return plugin->api; + j++; + } + } + return NULL; +} + + +/** + * Function called to validate a reply or a request. For + * request evaluation, simply pass "NULL" for the reply_block. + * Note that it is assumed that the reply has already been + * matched to the key (and signatures checked) as it would + * be done with the "get_key" function. + * + * @param ctx block contxt + * @param type block type + * @param query original query (hash) + * @param bf pointer to bloom filter associated with query; possibly updated (!) + * @param bf_mutator mutation value for bf + * @param xquery extended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in reply block + * @return characterization of result + */ +enum GNUNET_BLOCK_EvaluationResult +GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx, + enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode * query, + struct GNUNET_CONTAINER_BloomFilter **bf, + int32_t bf_mutator, const void *xquery, + size_t xquery_size, const void *reply_block, + size_t reply_block_size) +{ + struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx, type); + + if (plugin == NULL) + return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; + return plugin->evaluate (plugin->cls, type, query, bf, bf_mutator, xquery, + xquery_size, reply_block, reply_block_size); +} + + +/** + * Function called to obtain the key for a block. + * + * @param ctx block context + * @param type block type + * @param block block to get the key for + * @param block_size number of bytes in block + * @param key set to the key (query) for the given block + * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported + * (or if extracting a key from a block of this type does not work) + */ +int +GNUNET_BLOCK_get_key (struct GNUNET_BLOCK_Context *ctx, + enum GNUNET_BLOCK_Type type, const void *block, + size_t block_size, GNUNET_HashCode * key) +{ + struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx, type); + + if (plugin == NULL) + return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; + return plugin->get_key (plugin->cls, type, block, block_size, key); +} + + +/** + * How many bytes should a bloomfilter be if we have already seen + * entry_count responses? Note that GNUNET_CONSTANTS_BLOOMFILTER_K gives us the number + * of bits set per entry. Furthermore, we should not re-size the + * filter too often (to keep it cheap). + * + * Since other peers will also add entries but not resize the filter, + * we should generally pick a slightly larger size than what the + * strict math would suggest. + * + * @return must be a power of two and smaller or equal to 2^15. + */ +static size_t +compute_bloomfilter_size (unsigned int entry_count) +{ + size_t size; + unsigned int ideal = (entry_count * GNUNET_CONSTANTS_BLOOMFILTER_K) / 4; + uint16_t max = 1 << 15; + + if (entry_count > max) + return max; + size = 8; + while ((size < max) && (size < ideal)) + size *= 2; + if (size > max) + return max; + return size; +} + + +/** + * Construct a bloom filter that would filter out the given + * results. + * + * @param bf_mutator mutation value to use + * @param seen_results results already seen + * @param seen_results_count number of entries in 'seen_results' + * @return NULL if seen_results_count is 0, otherwise a BF + * that would match the given results. + */ +struct GNUNET_CONTAINER_BloomFilter * +GNUNET_BLOCK_construct_bloomfilter (int32_t bf_mutator, + const GNUNET_HashCode * seen_results, + unsigned int seen_results_count) +{ + struct GNUNET_CONTAINER_BloomFilter *bf; + GNUNET_HashCode mhash; + unsigned int i; + size_t nsize; + + nsize = compute_bloomfilter_size (seen_results_count); + bf = GNUNET_CONTAINER_bloomfilter_init (NULL, nsize, + GNUNET_CONSTANTS_BLOOMFILTER_K); + for (i = 0; i < seen_results_count; i++) + { + GNUNET_BLOCK_mingle_hash (&seen_results[i], bf_mutator, &mhash); + GNUNET_CONTAINER_bloomfilter_add (bf, &mhash); + } + return bf; +} + + +/* end of block.c */ diff --git a/src/block/plugin_block_template.c b/src/block/plugin_block_template.c new file mode 100644 index 0000000..6ed675d --- /dev/null +++ b/src/block/plugin_block_template.c @@ -0,0 +1,113 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file block/plugin_block_template.c + * @brief template for a block plugin + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_block_plugin.h" + +#define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING + + +/** + * Function called to validate a reply or a request. For + * request evaluation, simply pass "NULL" for the reply_block. + * + * @param cls closure + * @param type block type + * @param query original query (hash) + * @param bf pointer to bloom filter associated with query; possibly updated (!) + * @param bf_mutator mutation value for bf + * @param xquery extrended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in reply block + * @return characterization of result + */ +static enum GNUNET_BLOCK_EvaluationResult +block_plugin_template_evaluate (void *cls, enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode * query, + struct GNUNET_CONTAINER_BloomFilter **bf, + int32_t bf_mutator, const void *xquery, + size_t xquery_size, const void *reply_block, + size_t reply_block_size) +{ + return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; +} + + +/** + * Function called to obtain the key for a block. + * + * @param cls closure + * @param type block type + * @param block block to get the key for + * @param block_size number of bytes in block + * @param key set to the key (query) for the given block + * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported + * (or if extracting a key from a block of this type does not work) + */ +static int +block_plugin_template_get_key (void *cls, enum GNUNET_BLOCK_Type type, + const void *block, size_t block_size, + GNUNET_HashCode * key) +{ + return GNUNET_SYSERR; +} + + +/** + * Entry point for the plugin. + */ +void * +libgnunet_plugin_block_template_init (void *cls) +{ + static enum GNUNET_BLOCK_Type types[] = + { + /* FIXME: insert supported block types here */ + GNUNET_BLOCK_TYPE_ANY /* end of list */ + }; + struct GNUNET_BLOCK_PluginFunctions *api; + + api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); + api->evaluate = &block_plugin_template_evaluate; + api->get_key = &block_plugin_template_get_key; + api->types = types; + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +libgnunet_plugin_block_template_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + +/* end of plugin_block_template.c */ diff --git a/src/block/plugin_block_test.c b/src/block/plugin_block_test.c new file mode 100644 index 0000000..08d3096 --- /dev/null +++ b/src/block/plugin_block_test.c @@ -0,0 +1,147 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file block/plugin_block_test.c + * @brief block plugin to test the DHT as a simple key-value store; + * this plugin simply accepts any (new) response for any key + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_block_plugin.h" + +#define DEBUG_TEST GNUNET_EXTRA_LOGGING + + +/** + * Number of bits we set per entry in the bloomfilter. + * Do not change! + */ +#define BLOOMFILTER_K 16 + +/** + * Function called to validate a reply or a request. For + * request evaluation, simply pass "NULL" for the reply_block. + * + * @param cls closure + * @param type block type + * @param query original query (hash) + * @param bf pointer to bloom filter associated with query; possibly updated (!) + * @param bf_mutator mutation value for bf + * @param xquery extrended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in reply block + * @return characterization of result + */ +static enum GNUNET_BLOCK_EvaluationResult +block_plugin_test_evaluate (void *cls, enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode * query, + struct GNUNET_CONTAINER_BloomFilter **bf, + int32_t bf_mutator, const void *xquery, + size_t xquery_size, const void *reply_block, + size_t reply_block_size) +{ + GNUNET_HashCode chash; + GNUNET_HashCode mhash; + + if (type != GNUNET_BLOCK_TYPE_TEST) + return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; + if (xquery_size != 0) + return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; + if (reply_block_size == 0) + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + + if (NULL != bf) + { + GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); + GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); + if (NULL != *bf) + { + if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) + return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; + } + else + { + *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K); + } + GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash); + } + return GNUNET_BLOCK_EVALUATION_OK_MORE; +} + + +/** + * Function called to obtain the key for a block. + * + * @param cls closure + * @param type block type + * @param block block to get the key for + * @param block_size number of bytes in block + * @param key set to the key (query) for the given block + * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported + * (or if extracting a key from a block of this type does not work) + */ +static int +block_plugin_test_get_key (void *cls, enum GNUNET_BLOCK_Type type, + const void *block, size_t block_size, + GNUNET_HashCode * key) +{ + /* always fails since there is no fixed relationship between + * keys and values for test values */ + return GNUNET_SYSERR; +} + + +/** + * Entry point for the plugin. + */ +void * +libgnunet_plugin_block_test_init (void *cls) +{ + static enum GNUNET_BLOCK_Type types[] = + { + GNUNET_BLOCK_TYPE_TEST, + GNUNET_BLOCK_TYPE_ANY /* end of list */ + }; + struct GNUNET_BLOCK_PluginFunctions *api; + + api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); + api->evaluate = &block_plugin_test_evaluate; + api->get_key = &block_plugin_test_get_key; + api->types = types; + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +libgnunet_plugin_block_test_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + +/* end of plugin_block_test.c */ diff --git a/src/block/test_block.c b/src/block/test_block.c new file mode 100644 index 0000000..e57b891 --- /dev/null +++ b/src/block/test_block.c @@ -0,0 +1,77 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file block/test_block.c + * @brief test for block.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_block_lib.h" + +#define DEBUG GNUNET_EXTRA_LOGGING + +#define VERBOSE GNUNET_NO + +static int +test_fs (struct GNUNET_BLOCK_Context *ctx) +{ + GNUNET_HashCode key; + char block[4]; + + memset (block, 1, sizeof (block)); + if (GNUNET_OK != + GNUNET_BLOCK_get_key (ctx, GNUNET_BLOCK_TYPE_FS_DBLOCK, block, + sizeof (block), &key)) + return 1; + if (GNUNET_BLOCK_EVALUATION_OK_LAST != + GNUNET_BLOCK_evaluate (ctx, GNUNET_BLOCK_TYPE_FS_DBLOCK, &key, NULL, 0, + NULL, 0, block, sizeof (block))) + return 2; + if (GNUNET_BLOCK_EVALUATION_REQUEST_VALID != + GNUNET_BLOCK_evaluate (ctx, GNUNET_BLOCK_TYPE_FS_DBLOCK, &key, NULL, 0, + NULL, 0, NULL, 0)) + return 4; + GNUNET_log_skip (1, GNUNET_NO); + if (GNUNET_BLOCK_EVALUATION_REQUEST_INVALID != + GNUNET_BLOCK_evaluate (ctx, GNUNET_BLOCK_TYPE_FS_DBLOCK, &key, NULL, 0, + "bogus", 5, NULL, 0)) + return 8; + GNUNET_log_skip (0, GNUNET_YES); + return 0; +} + +int +main (int argc, char *argv[]) +{ + int ret; + struct GNUNET_BLOCK_Context *ctx; + struct GNUNET_CONFIGURATION_Handle *cfg; + + GNUNET_log_setup ("test-block", "WARNING", NULL); + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_string (cfg, "block", "PLUGINS", "fs"); + ctx = GNUNET_BLOCK_context_create (cfg); + ret = test_fs (ctx); + GNUNET_BLOCK_context_destroy (ctx); + GNUNET_CONFIGURATION_destroy (cfg); + if (ret != 0) + FPRINTF (stderr, "Tests failed: %d\n", ret); + return ret; +} diff --git a/src/chat/Makefile.am b/src/chat/Makefile.am new file mode 100644 index 0000000..2132836 --- /dev/null +++ b/src/chat/Makefile.am @@ -0,0 +1,128 @@ +INCLUDES = -I$(top_srcdir)/src/include + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + chat.conf + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + +lib_LTLIBRARIES = libgnunetchat.la + +libgnunetchat_la_SOURCES = \ + chat.c chat.h + +libgnunetchat_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunetchat_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +bin_PROGRAMS = \ + gnunet-service-chat \ + gnunet-chat + +gnunet_service_chat_SOURCES = \ + gnunet-service-chat.c +gnunet_service_chat_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_chat_SOURCES = \ + gnunet-chat.c +gnunet_chat_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_chat_DEPENDENCIES = \ + libgnunetchat.la + +check_PROGRAMS = \ + test_chat \ + test_chat_acknowledgement \ + test_chat_anonymous \ + test_chat_authentication \ + test_chat_p2p \ + test_chat_acknowledgement_p2p \ + test_chat_anonymous_p2p \ + test_chat_authentication_p2p \ + test_chat_private \ + test_chat_private_p2p + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_chat_SOURCES = \ + test_chat.c +test_chat_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_acknowledgement_SOURCES = \ + test_chat.c +test_chat_acknowledgement_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_anonymous_SOURCES = \ + test_chat.c +test_chat_anonymous_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_authentication_SOURCES = \ + test_chat.c +test_chat_authentication_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_p2p_SOURCES = \ + test_chat.c +test_chat_p2p_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_acknowledgement_p2p_SOURCES = \ + test_chat.c +test_chat_acknowledgement_p2p_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_anonymous_p2p_SOURCES = \ + test_chat.c +test_chat_anonymous_p2p_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_authentication_p2p_SOURCES = \ + test_chat.c +test_chat_authentication_p2p_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_private_SOURCES = \ + test_chat_private.c +test_chat_private_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_private_p2p_SOURCES = \ + test_chat_private.c +test_chat_private_p2p_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_chat_data.conf \ + test_chat_peer1.conf \ + test_chat_peer2.conf \ + test_chat_peer3.conf diff --git a/src/chat/Makefile.in b/src/chat/Makefile.in new file mode 100644 index 0000000..96c673c --- /dev/null +++ b/src/chat/Makefile.in @@ -0,0 +1,1062 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-chat$(EXEEXT) gnunet-chat$(EXEEXT) +check_PROGRAMS = test_chat$(EXEEXT) test_chat_acknowledgement$(EXEEXT) \ + test_chat_anonymous$(EXEEXT) test_chat_authentication$(EXEEXT) \ + test_chat_p2p$(EXEEXT) test_chat_acknowledgement_p2p$(EXEEXT) \ + test_chat_anonymous_p2p$(EXEEXT) \ + test_chat_authentication_p2p$(EXEEXT) \ + test_chat_private$(EXEEXT) test_chat_private_p2p$(EXEEXT) +subdir = src/chat +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/chat.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = chat.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libgnunetchat_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunetchat_la_OBJECTS = chat.lo +libgnunetchat_la_OBJECTS = $(am_libgnunetchat_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetchat_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetchat_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_chat_OBJECTS = gnunet-chat.$(OBJEXT) +gnunet_chat_OBJECTS = $(am_gnunet_chat_OBJECTS) +am__DEPENDENCIES_1 = +am_gnunet_service_chat_OBJECTS = gnunet-service-chat.$(OBJEXT) +gnunet_service_chat_OBJECTS = $(am_gnunet_service_chat_OBJECTS) +gnunet_service_chat_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_test_chat_OBJECTS = test_chat.$(OBJEXT) +test_chat_OBJECTS = $(am_test_chat_OBJECTS) +test_chat_DEPENDENCIES = $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_chat_acknowledgement_OBJECTS = test_chat.$(OBJEXT) +test_chat_acknowledgement_OBJECTS = \ + $(am_test_chat_acknowledgement_OBJECTS) +test_chat_acknowledgement_DEPENDENCIES = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_chat_acknowledgement_p2p_OBJECTS = test_chat.$(OBJEXT) +test_chat_acknowledgement_p2p_OBJECTS = \ + $(am_test_chat_acknowledgement_p2p_OBJECTS) +test_chat_acknowledgement_p2p_DEPENDENCIES = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_chat_anonymous_OBJECTS = test_chat.$(OBJEXT) +test_chat_anonymous_OBJECTS = $(am_test_chat_anonymous_OBJECTS) +test_chat_anonymous_DEPENDENCIES = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_chat_anonymous_p2p_OBJECTS = test_chat.$(OBJEXT) +test_chat_anonymous_p2p_OBJECTS = \ + $(am_test_chat_anonymous_p2p_OBJECTS) +test_chat_anonymous_p2p_DEPENDENCIES = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_chat_authentication_OBJECTS = test_chat.$(OBJEXT) +test_chat_authentication_OBJECTS = \ + $(am_test_chat_authentication_OBJECTS) +test_chat_authentication_DEPENDENCIES = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_chat_authentication_p2p_OBJECTS = test_chat.$(OBJEXT) +test_chat_authentication_p2p_OBJECTS = \ + $(am_test_chat_authentication_p2p_OBJECTS) +test_chat_authentication_p2p_DEPENDENCIES = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_chat_p2p_OBJECTS = test_chat.$(OBJEXT) +test_chat_p2p_OBJECTS = $(am_test_chat_p2p_OBJECTS) +test_chat_p2p_DEPENDENCIES = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_chat_private_OBJECTS = test_chat_private.$(OBJEXT) +test_chat_private_OBJECTS = $(am_test_chat_private_OBJECTS) +test_chat_private_DEPENDENCIES = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_chat_private_p2p_OBJECTS = test_chat_private.$(OBJEXT) +test_chat_private_p2p_OBJECTS = $(am_test_chat_private_p2p_OBJECTS) +test_chat_private_p2p_DEPENDENCIES = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetchat_la_SOURCES) $(gnunet_chat_SOURCES) \ + $(gnunet_service_chat_SOURCES) $(test_chat_SOURCES) \ + $(test_chat_acknowledgement_SOURCES) \ + $(test_chat_acknowledgement_p2p_SOURCES) \ + $(test_chat_anonymous_SOURCES) \ + $(test_chat_anonymous_p2p_SOURCES) \ + $(test_chat_authentication_SOURCES) \ + $(test_chat_authentication_p2p_SOURCES) \ + $(test_chat_p2p_SOURCES) $(test_chat_private_SOURCES) \ + $(test_chat_private_p2p_SOURCES) +DIST_SOURCES = $(libgnunetchat_la_SOURCES) $(gnunet_chat_SOURCES) \ + $(gnunet_service_chat_SOURCES) $(test_chat_SOURCES) \ + $(test_chat_acknowledgement_SOURCES) \ + $(test_chat_acknowledgement_p2p_SOURCES) \ + $(test_chat_anonymous_SOURCES) \ + $(test_chat_anonymous_p2p_SOURCES) \ + $(test_chat_authentication_SOURCES) \ + $(test_chat_authentication_p2p_SOURCES) \ + $(test_chat_p2p_SOURCES) $(test_chat_private_SOURCES) \ + $(test_chat_private_p2p_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + chat.conf + +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage +lib_LTLIBRARIES = libgnunetchat.la +libgnunetchat_la_SOURCES = \ + chat.c chat.h + +libgnunetchat_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunetchat_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +gnunet_service_chat_SOURCES = \ + gnunet-service-chat.c + +gnunet_service_chat_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_chat_SOURCES = \ + gnunet-chat.c + +gnunet_chat_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_chat_DEPENDENCIES = \ + libgnunetchat.la + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_chat_SOURCES = \ + test_chat.c + +test_chat_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_acknowledgement_SOURCES = \ + test_chat.c + +test_chat_acknowledgement_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_anonymous_SOURCES = \ + test_chat.c + +test_chat_anonymous_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_authentication_SOURCES = \ + test_chat.c + +test_chat_authentication_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_p2p_SOURCES = \ + test_chat.c + +test_chat_p2p_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_acknowledgement_p2p_SOURCES = \ + test_chat.c + +test_chat_acknowledgement_p2p_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_anonymous_p2p_SOURCES = \ + test_chat.c + +test_chat_anonymous_p2p_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_authentication_p2p_SOURCES = \ + test_chat.c + +test_chat_authentication_p2p_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_private_SOURCES = \ + test_chat_private.c + +test_chat_private_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_chat_private_p2p_SOURCES = \ + test_chat_private.c + +test_chat_private_p2p_LDADD = \ + $(top_builddir)/src/chat/libgnunetchat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_chat_data.conf \ + test_chat_peer1.conf \ + test_chat_peer2.conf \ + test_chat_peer3.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/chat/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/chat/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +chat.conf: $(top_builddir)/config.status $(srcdir)/chat.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetchat.la: $(libgnunetchat_la_OBJECTS) $(libgnunetchat_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetchat_la_LINK) -rpath $(libdir) $(libgnunetchat_la_OBJECTS) $(libgnunetchat_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-chat$(EXEEXT): $(gnunet_chat_OBJECTS) $(gnunet_chat_DEPENDENCIES) + @rm -f gnunet-chat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_chat_OBJECTS) $(gnunet_chat_LDADD) $(LIBS) +gnunet-service-chat$(EXEEXT): $(gnunet_service_chat_OBJECTS) $(gnunet_service_chat_DEPENDENCIES) + @rm -f gnunet-service-chat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_chat_OBJECTS) $(gnunet_service_chat_LDADD) $(LIBS) +test_chat$(EXEEXT): $(test_chat_OBJECTS) $(test_chat_DEPENDENCIES) + @rm -f test_chat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_chat_OBJECTS) $(test_chat_LDADD) $(LIBS) +test_chat_acknowledgement$(EXEEXT): $(test_chat_acknowledgement_OBJECTS) $(test_chat_acknowledgement_DEPENDENCIES) + @rm -f test_chat_acknowledgement$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_chat_acknowledgement_OBJECTS) $(test_chat_acknowledgement_LDADD) $(LIBS) +test_chat_acknowledgement_p2p$(EXEEXT): $(test_chat_acknowledgement_p2p_OBJECTS) $(test_chat_acknowledgement_p2p_DEPENDENCIES) + @rm -f test_chat_acknowledgement_p2p$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_chat_acknowledgement_p2p_OBJECTS) $(test_chat_acknowledgement_p2p_LDADD) $(LIBS) +test_chat_anonymous$(EXEEXT): $(test_chat_anonymous_OBJECTS) $(test_chat_anonymous_DEPENDENCIES) + @rm -f test_chat_anonymous$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_chat_anonymous_OBJECTS) $(test_chat_anonymous_LDADD) $(LIBS) +test_chat_anonymous_p2p$(EXEEXT): $(test_chat_anonymous_p2p_OBJECTS) $(test_chat_anonymous_p2p_DEPENDENCIES) + @rm -f test_chat_anonymous_p2p$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_chat_anonymous_p2p_OBJECTS) $(test_chat_anonymous_p2p_LDADD) $(LIBS) +test_chat_authentication$(EXEEXT): $(test_chat_authentication_OBJECTS) $(test_chat_authentication_DEPENDENCIES) + @rm -f test_chat_authentication$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_chat_authentication_OBJECTS) $(test_chat_authentication_LDADD) $(LIBS) +test_chat_authentication_p2p$(EXEEXT): $(test_chat_authentication_p2p_OBJECTS) $(test_chat_authentication_p2p_DEPENDENCIES) + @rm -f test_chat_authentication_p2p$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_chat_authentication_p2p_OBJECTS) $(test_chat_authentication_p2p_LDADD) $(LIBS) +test_chat_p2p$(EXEEXT): $(test_chat_p2p_OBJECTS) $(test_chat_p2p_DEPENDENCIES) + @rm -f test_chat_p2p$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_chat_p2p_OBJECTS) $(test_chat_p2p_LDADD) $(LIBS) +test_chat_private$(EXEEXT): $(test_chat_private_OBJECTS) $(test_chat_private_DEPENDENCIES) + @rm -f test_chat_private$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_chat_private_OBJECTS) $(test_chat_private_LDADD) $(LIBS) +test_chat_private_p2p$(EXEEXT): $(test_chat_private_p2p_OBJECTS) $(test_chat_private_p2p_DEPENDENCIES) + @rm -f test_chat_private_p2p$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_chat_private_p2p_OBJECTS) $(test_chat_private_p2p_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-chat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-chat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_chat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_chat_private.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/chat/chat.c b/src/chat/chat.c new file mode 100644 index 0000000..ae73b96 --- /dev/null +++ b/src/chat/chat.c @@ -0,0 +1,822 @@ +/* + This file is part of GNUnet. + (C) 2008, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file chat/chat.c + * @brief convenience API for sending and receiving chat messages + * @author Christian Grothoff + * @author Nathan Evans + * @author Vitaly Minko + */ + +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_protocols.h" +#include "gnunet_signatures.h" +#include "chat.h" + +#define DEBUG_CHAT GNUNET_EXTRA_LOGGING +#define NICK_IDENTITY_PREFIX ".chat_identity_" + + +/** + * Handle for a chat room. + */ +struct GNUNET_CHAT_Room +{ + struct GNUNET_CLIENT_Connection *client; + + const struct GNUNET_CONFIGURATION_Handle *cfg; + + struct GNUNET_CONTAINER_MetaData *member_info; + + char *room_name; + + struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; + + struct MemberList *members; + + int is_joined; + + GNUNET_CHAT_JoinCallback join_callback; + + void *join_callback_cls; + + GNUNET_CHAT_MessageCallback message_callback; + + void *message_callback_cls; + + GNUNET_CHAT_MemberListCallback member_list_callback; + + void *member_list_callback_cls; + + GNUNET_CHAT_MessageConfirmation confirmation_callback; + + void *confirmation_cls; + + uint32_t sequence_number; + + uint32_t msg_options; + +}; + +/** + * Linked list of members in the chat room. + */ +struct MemberList +{ + struct MemberList *next; + + /** + * Description of the member. + */ + struct GNUNET_CONTAINER_MetaData *meta; + + /** + * Member ID (pseudonym). + */ + GNUNET_HashCode id; + +}; + +/** + * Context for transmitting a send-message request. + */ +struct GNUNET_CHAT_SendMessageContext +{ + /** + * Handle for the chat room. + */ + struct GNUNET_CHAT_Room *chat_room; + + /** + * Message that we're sending. + */ + char *message; + + /** + * Options for the message. + */ + enum GNUNET_CHAT_MsgOptions options; + + /** + * Receiver of the message. NULL to send to everyone in the room. + */ + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *receiver; + + /** + * Sequence id of the message. + */ + uint32_t sequence_number; + +}; + +/** + * Context for transmitting a confirmation receipt. + */ +struct GNUNET_CHAT_SendReceiptContext +{ + /** + * Handle for the chat room. + */ + struct GNUNET_CHAT_Room *chat_room; + + /** + * The original message that we're going to acknowledge. + */ + struct ReceiveNotificationMessage *received_msg; + +}; + +/** + * Ask client to send a join request. + */ +static int +rejoin_room (struct GNUNET_CHAT_Room *chat_room); + + +/** + * Transmit a confirmation receipt to the chat service. + * + * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendReceiptContext' + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_acknowledge_request (void *cls, size_t size, void *buf) +{ + struct GNUNET_CHAT_SendReceiptContext *src = cls; + struct ConfirmationReceiptMessage *receipt; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key; + uint16_t msg_len; + size_t msg_size; + + if (NULL == buf) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not transmit confirmation receipt\n")); + return 0; + } +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting confirmation receipt to the service\n"); +#endif + msg_size = sizeof (struct ConfirmationReceiptMessage); + GNUNET_assert (size >= msg_size); + receipt = buf; + receipt->header.size = htons (msg_size); + receipt->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT); + receipt->reserved = htonl (0); + receipt->sequence_number = src->received_msg->sequence_number; + receipt->reserved2 = htonl (0); + receipt->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + GNUNET_CRYPTO_rsa_key_get_public (src->chat_room->my_private_key, &pub_key); + GNUNET_CRYPTO_hash (&pub_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &receipt->target); + receipt->author = src->received_msg->sender; + receipt->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT); + receipt->purpose.size = + htonl (msg_size - sizeof (struct GNUNET_MessageHeader) - + sizeof (uint32_t) - sizeof (struct GNUNET_CRYPTO_RsaSignature)); + msg_len = + ntohs (src->received_msg->header.size) - + sizeof (struct ReceiveNotificationMessage); + GNUNET_CRYPTO_hash (&src->received_msg[1], msg_len, &receipt->content); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (src->chat_room->my_private_key, + &receipt->purpose, + &receipt->signature)); + GNUNET_free (src->received_msg); + GNUNET_free (src); + return msg_size; +} + + +/** + * Handles messages received from the service. Calls the proper client + * callback. + */ +static void +process_result (struct GNUNET_CHAT_Room *room, + const struct GNUNET_MessageHeader *reply) +{ + struct LeaveNotificationMessage *leave_msg; + struct JoinNotificationMessage *join_msg; + struct ReceiveNotificationMessage *received_msg; + struct ConfirmationReceiptMessage *receipt; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + GNUNET_HashCode id; + const GNUNET_HashCode *sender; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_CHAT_SendReceiptContext *src; + struct MemberList *pos; + struct MemberList *prev; + struct GNUNET_CRYPTO_AesSessionKey key; + char decrypted_msg[MAX_MESSAGE_LENGTH]; + uint16_t size; + uint16_t meta_len; + uint16_t msg_len; + char *message_content; + + size = ntohs (reply->size); + switch (ntohs (reply->type)) + { + case GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION: +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a join notification\n"); +#endif + if (size < sizeof (struct JoinNotificationMessage)) + { + GNUNET_break (0); + return; + } + join_msg = (struct JoinNotificationMessage *) reply; + meta_len = size - sizeof (struct JoinNotificationMessage); + meta = + GNUNET_CONTAINER_meta_data_deserialize ((const char *) &join_msg[1], + meta_len); + if (NULL == meta) + { + GNUNET_break (0); + return; + } + pos = GNUNET_malloc (sizeof (struct MemberList)); + pos->meta = meta; + GNUNET_CRYPTO_hash (&join_msg->public_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &pos->id); + GNUNET_PSEUDONYM_add (room->cfg, &pos->id, meta); + pos->next = room->members; + room->members = pos; + if (GNUNET_NO == room->is_joined) + { + GNUNET_CRYPTO_rsa_key_get_public (room->my_private_key, &pkey); + if (0 == + memcmp (&join_msg->public_key, &pkey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) + { + room->join_callback (room->join_callback_cls); + room->is_joined = GNUNET_YES; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("The current user must be the the first one joined\n")); + GNUNET_break (0); + return; + } + } + else + room->member_list_callback (room->member_list_callback_cls, meta, + &join_msg->public_key, + ntohl (join_msg->msg_options)); + break; + case GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION: +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a leave notification\n"); +#endif + if (size < sizeof (struct LeaveNotificationMessage)) + { + GNUNET_break (0); + return; + } + leave_msg = (struct LeaveNotificationMessage *) reply; + room->member_list_callback (room->member_list_callback_cls, NULL, + &leave_msg->user, GNUNET_CHAT_MSG_OPTION_NONE); + GNUNET_CRYPTO_hash (&leave_msg->user, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &id); + prev = NULL; + pos = room->members; + while ((NULL != pos) && + (0 != memcmp (&pos->id, &id, sizeof (GNUNET_HashCode)))) + { + prev = pos; + pos = pos->next; + } + GNUNET_assert (NULL != pos); + if (NULL == prev) + room->members = pos->next; + else + prev->next = pos->next; + GNUNET_CONTAINER_meta_data_destroy (pos->meta); + GNUNET_free (pos); + break; + case GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION: +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message notification\n"); +#endif + if (size <= sizeof (struct ReceiveNotificationMessage)) + { + GNUNET_break (0); + return; + } + received_msg = (struct ReceiveNotificationMessage *) reply; + if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ACKNOWLEDGED)) + { + src = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendReceiptContext)); + src->chat_room = room; + src->received_msg = GNUNET_memdup (received_msg, size); + GNUNET_CLIENT_notify_transmit_ready (room->client, + sizeof (struct + ConfirmationReceiptMessage), + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + GNUNET_YES, + &transmit_acknowledge_request, src); + } + msg_len = size - sizeof (struct ReceiveNotificationMessage); + if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_PRIVATE)) + { + if (-1 == + GNUNET_CRYPTO_rsa_decrypt (room->my_private_key, + &received_msg->encrypted_key, &key, + sizeof (struct + GNUNET_CRYPTO_AesSessionKey))) + { + GNUNET_break (0); + return; + } + msg_len = + GNUNET_CRYPTO_aes_decrypt (&received_msg[1], msg_len, &key, + (const struct + GNUNET_CRYPTO_AesInitializationVector *) + INITVALUE, decrypted_msg); + message_content = decrypted_msg; + } + else + { + message_content = GNUNET_malloc (msg_len + 1); + memcpy (message_content, &received_msg[1], msg_len); + } + message_content[msg_len] = '\0'; + if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)) + { + sender = NULL; + meta = NULL; + } + else + { + pos = room->members; + while ((NULL != pos) && + (0 != + memcmp (&pos->id, &received_msg->sender, + sizeof (GNUNET_HashCode)))) + pos = pos->next; + GNUNET_assert (NULL != pos); + sender = &received_msg->sender; + meta = pos->meta; + } + room->message_callback (room->message_callback_cls, room, sender, meta, + message_content, + GNUNET_TIME_absolute_ntoh (received_msg->timestamp), + ntohl (received_msg->msg_options)); + if (message_content != decrypted_msg) + GNUNET_free (message_content); + break; + case GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION: +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a confirmation receipt\n"); +#endif + if (size < sizeof (struct ConfirmationReceiptMessage)) + { + GNUNET_break (0); + return; + } + receipt = (struct ConfirmationReceiptMessage *) reply; + if (NULL != room->confirmation_callback) + room->confirmation_callback (room->confirmation_cls, room, + ntohl (receipt->sequence_number), + GNUNET_TIME_absolute_ntoh + (receipt->timestamp), &receipt->target); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unknown message type: '%u'\n"), + ntohs (reply->type)); + GNUNET_break_op (0); + break; + } +} + + +/** + * Listen for incoming messages on this chat room. Also, support servers going + * away/coming back (i.e. rejoin chat room to keep server state up to date). + * + * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' + * @param msg message received, NULL on timeout or fatal error + */ +static void +receive_results (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_CHAT_Room *chat_room = cls; + +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message from the service\n"); +#endif + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & GNUNET_SCHEDULER_get_reason ())) + return; + if (NULL == msg) + { + GNUNET_break (0); + rejoin_room (chat_room); + return; + } + process_result (chat_room, msg); + if (NULL == chat_room->client) + return; /* fatal error */ + /* continue receiving */ + GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Read existing private key from file or create a new one if it does not exist + * yet. + * Returns the private key on success, NULL on error. + */ +static struct GNUNET_CRYPTO_RsaPrivateKey * +init_private_key (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *nick_name) +{ + char *home; + char *keyfile; + struct GNUNET_CRYPTO_RsaPrivateKey *privKey; + +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initializing private key\n"); +#endif + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "chat", "HOME", &home)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Configuration option `%s' in section `%s' missing\n"), + "HOME", "chat"); + return NULL; + } + GNUNET_DISK_directory_create (home); + if (GNUNET_OK != GNUNET_DISK_directory_test (home)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to access chat home directory `%s'\n"), home); + GNUNET_free (home); + return NULL; + } + /* read or create private key */ + keyfile = + GNUNET_malloc (strlen (home) + strlen (NICK_IDENTITY_PREFIX) + + strlen (nick_name) + 2); + strcpy (keyfile, home); + GNUNET_free (home); + if (keyfile[strlen (keyfile) - 1] != DIR_SEPARATOR) + strcat (keyfile, DIR_SEPARATOR_STR); + strcat (keyfile, NICK_IDENTITY_PREFIX); + strcat (keyfile, nick_name); + privKey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + if (NULL == privKey) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to create/open key in file `%s'\n"), keyfile); + } + GNUNET_free (keyfile); + return privKey; +} + + +/** + * Transmit a join request to the chat service. + * + * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_join_request (void *cls, size_t size, void *buf) +{ + struct GNUNET_CHAT_Room *chat_room = cls; + struct JoinRequestMessage *join_msg; + char *room; + char *meta; + size_t room_len; + ssize_t meta_len; + size_t size_of_join; + + if (NULL == buf) + { +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Could not transmit join request, retrying...\n"); +#endif + rejoin_room (chat_room); + return 0; + } +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting join request to the service\n"); +#endif + room_len = strlen (chat_room->room_name); + meta_len = + GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info); + size_of_join = sizeof (struct JoinRequestMessage) + meta_len + room_len; + GNUNET_assert (size >= size_of_join); + join_msg = buf; + join_msg->header.size = htons (size); + join_msg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST); + join_msg->msg_options = htonl (chat_room->msg_options); + join_msg->room_name_len = htons (room_len); + join_msg->reserved = htons (0); + join_msg->reserved2 = htonl (0); + GNUNET_CRYPTO_rsa_key_get_public (chat_room->my_private_key, + &join_msg->public_key); + room = (char *) &join_msg[1]; + memcpy (room, chat_room->room_name, room_len); + meta = &room[room_len]; + if (GNUNET_SYSERR == + GNUNET_CONTAINER_meta_data_serialize (chat_room->member_info, &meta, + meta_len, + GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not serialize metadata\n")); + return 0; + } + GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, + GNUNET_TIME_UNIT_FOREVER_REL); + return size_of_join; +} + + +/** + * Ask to send a join request. + */ +static int +rejoin_room (struct GNUNET_CHAT_Room *chat_room) +{ + size_t size_of_join; + + size_of_join = + sizeof (struct JoinRequestMessage) + + GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info) + + strlen (chat_room->room_name); + if (NULL == + GNUNET_CLIENT_notify_transmit_ready (chat_room->client, size_of_join, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + GNUNET_YES, &transmit_join_request, + chat_room)) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Leave a chat room. + */ +void +GNUNET_CHAT_leave_room (struct GNUNET_CHAT_Room *chat_room) +{ + struct MemberList *pos; + +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Leaving the room '%s'\n", + chat_room->room_name); +#endif + GNUNET_CLIENT_disconnect (chat_room->client, GNUNET_NO); + GNUNET_free (chat_room->room_name); + GNUNET_CONTAINER_meta_data_destroy (chat_room->member_info); + GNUNET_CRYPTO_rsa_key_free (chat_room->my_private_key); + while (NULL != chat_room->members) + { + pos = chat_room->members; + chat_room->members = pos->next; + GNUNET_CONTAINER_meta_data_destroy (pos->meta); + GNUNET_free (pos); + } + GNUNET_free (chat_room); +} + + +/** + * Join a chat room. + * + * @param cfg configuration + * @param nick_name nickname of the user joining (used to + * determine which public key to use); + * the nickname should probably also + * be used in the member_info (as "EXTRACTOR_TITLE") + * @param member_info information about the joining member + * @param room_name name of the room + * @param msg_options message options of the joining user + * @param joinCallback function to call on successful join + * @param join_cls closure for joinCallback + * @param messageCallback which function to call if a message has + * been received? + * @param message_cls argument to callback + * @param memberCallback which function to call for join/leave notifications + * @param member_cls argument to callback + * @param confirmationCallback which function to call for confirmations (maybe NULL) + * @param confirmation_cls argument to callback + * @param me member ID (pseudonym) + * @return NULL on error + */ +struct GNUNET_CHAT_Room * +GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *nick_name, + struct GNUNET_CONTAINER_MetaData *member_info, + const char *room_name, + enum GNUNET_CHAT_MsgOptions msg_options, + GNUNET_CHAT_JoinCallback joinCallback, void *join_cls, + GNUNET_CHAT_MessageCallback messageCallback, + void *message_cls, + GNUNET_CHAT_MemberListCallback memberCallback, + void *member_cls, + GNUNET_CHAT_MessageConfirmation confirmationCallback, + void *confirmation_cls, GNUNET_HashCode * me) +{ + struct GNUNET_CHAT_Room *chat_room; + struct GNUNET_CRYPTO_RsaPrivateKey *priv_key; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key; + struct GNUNET_CLIENT_Connection *client; + +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Joining the room '%s'\n", room_name); +#endif + priv_key = init_private_key (cfg, nick_name); + if (NULL == priv_key) + return NULL; + GNUNET_CRYPTO_rsa_key_get_public (priv_key, &pub_key); + GNUNET_CRYPTO_hash (&pub_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + me); + GNUNET_PSEUDONYM_add (cfg, me, member_info); + client = GNUNET_CLIENT_connect ("chat", cfg); + if (NULL == client) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to the chat service\n")); + return NULL; + } + if (NULL == joinCallback) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Undefined mandatory parameter: joinCallback\n")); + return NULL; + } + if (NULL == messageCallback) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Undefined mandatory parameter: messageCallback\n")); + return NULL; + } + if (NULL == memberCallback) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Undefined mandatory parameter: memberCallback\n")); + return NULL; + } + chat_room = GNUNET_malloc (sizeof (struct GNUNET_CHAT_Room)); + chat_room->msg_options = msg_options; + chat_room->room_name = GNUNET_strdup (room_name); + chat_room->member_info = GNUNET_CONTAINER_meta_data_duplicate (member_info); + chat_room->my_private_key = priv_key; + chat_room->is_joined = GNUNET_NO; + chat_room->join_callback = joinCallback; + chat_room->join_callback_cls = join_cls; + chat_room->message_callback = messageCallback; + chat_room->message_callback_cls = message_cls; + chat_room->member_list_callback = memberCallback; + chat_room->member_list_callback_cls = member_cls; + chat_room->confirmation_callback = confirmationCallback; + chat_room->confirmation_cls = confirmation_cls; + chat_room->cfg = cfg; + chat_room->client = client; + chat_room->members = NULL; + if (GNUNET_SYSERR == rejoin_room (chat_room)) + { + GNUNET_CHAT_leave_room (chat_room); + return NULL; + } + return chat_room; +} + + +/** + * Transmit a send-message request to the chat service. + * + * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendMessageContext' + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_send_request (void *cls, size_t size, void *buf) +{ + struct GNUNET_CHAT_SendMessageContext *smc = cls; + struct TransmitRequestMessage *msg_to_send; + size_t msg_size; + + if (NULL == buf) + { +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit a chat message\n"); +#endif + return 0; + } +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting a chat message to the service\n"); +#endif + msg_size = strlen (smc->message) + sizeof (struct TransmitRequestMessage); + GNUNET_assert (size >= msg_size); + msg_to_send = buf; + msg_to_send->header.size = htons (msg_size); + msg_to_send->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST); + msg_to_send->msg_options = htonl (smc->options); + msg_to_send->sequence_number = htonl (smc->sequence_number); + msg_to_send->timestamp = + GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + msg_to_send->reserved = htonl (0); + if (NULL == smc->receiver) + memset (&msg_to_send->target, 0, sizeof (GNUNET_HashCode)); + else + GNUNET_CRYPTO_hash (smc->receiver, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &msg_to_send->target); + memcpy (&msg_to_send[1], smc->message, strlen (smc->message)); + /** + * Client don't encode private messages since public keys of other members are + * stored on the service side. + */ + if (smc->options & GNUNET_CHAT_MSG_AUTHENTICATED) + { + msg_to_send->purpose.purpose = + htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE); + msg_to_send->purpose.size = + htonl (msg_size - sizeof (struct GNUNET_MessageHeader) - + sizeof (struct GNUNET_CRYPTO_RsaSignature)); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (smc->chat_room->my_private_key, + &msg_to_send->purpose, + &msg_to_send->signature)); + } + GNUNET_free (smc->message); + GNUNET_free (smc); + return msg_size; +} + + +/** + * Send a message. + * + * @param room handle for the chat room + * @param message message to be sent + * @param options options for the message + * @param receiver use NULL to send to everyone in the room + * @param sequence_number where to write the sequence id of the message + */ +void +GNUNET_CHAT_send_message (struct GNUNET_CHAT_Room *room, const char *message, + enum GNUNET_CHAT_MsgOptions options, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *receiver, uint32_t * sequence_number) +{ + size_t msg_size; + struct GNUNET_CHAT_SendMessageContext *smc; + +#if DEBUG_CHAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending a message\n"); +#endif + room->sequence_number++; + if (NULL != sequence_number) + *sequence_number = room->sequence_number; + smc = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendMessageContext)); + smc->chat_room = room; + smc->message = GNUNET_strdup (message); + smc->options = options; + smc->receiver = receiver; + smc->sequence_number = room->sequence_number; + msg_size = strlen (message) + sizeof (struct TransmitRequestMessage); + GNUNET_CLIENT_notify_transmit_ready (room->client, msg_size, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + GNUNET_YES, &transmit_send_request, smc); +} + +/* end of chat.c */ diff --git a/src/chat/chat.conf.in b/src/chat/chat.conf.in new file mode 100644 index 0000000..41fe9b4 --- /dev/null +++ b/src/chat/chat.conf.in @@ -0,0 +1,22 @@ +[chat] +AUTOSTART = YES +@UNIXONLY@ PORT = 2090 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-chat +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-chat.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +# DISABLE_SOCKET_FORWARDING = NO +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = + diff --git a/src/chat/chat.h b/src/chat/chat.h new file mode 100644 index 0000000..5df7773 --- /dev/null +++ b/src/chat/chat.h @@ -0,0 +1,485 @@ +/* + This file is part of GNUnet + (C) 2008, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file chat/chat.h + * @brief support for chat + * @author Christian Grothoff + * @author Nathan Evans + * @author Vitaly Minko + */ + +#ifndef CHAT_H +#define CHAT_H + +#include "gnunet_chat_service.h" + +/** + * Constant IV since we generate a new session key per each message. + */ +#define INITVALUE "InitializationVectorValue" + + +/** + * Client-service messages + */ + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Notification sent by service to client indicating that we've received a chat + * message. After this struct, the remaining bytes are the actual text message. + * If the mesasge is private, then the text is encrypted, otherwise it's + * plaintext. + */ +struct ReceiveNotificationMessage +{ + /** + * Message type will be GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION + */ + struct GNUNET_MessageHeader header; + + /** + * Message options, see GNUNET_CHAT_MsgOptions. + */ + uint32_t msg_options GNUNET_PACKED; + + /** + * Sequence number of the message (unique per sender). + */ + uint32_t sequence_number GNUNET_PACKED; + + /** + * For alignment (should be zero). + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Timestamp of the message. + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + + /** + * Hash of the public key of the pseudonym of the sender of the message. + * Should be all zeros for anonymous. + */ + GNUNET_HashCode sender; + + /** + * The encrypted session key. + */ + struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; + +}; + + +/** + * Request sent by client to transmit a chat message to another room members. + * After this struct, the remaining bytes are the actual message in plaintext. + * Private messages are encrypted on the service side. + */ +struct TransmitRequestMessage +{ + /** + * Message type will be GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST + */ + struct GNUNET_MessageHeader header; + + /** + * For alignment (should be zero). + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Signature confirming receipt. Signature covers everything from header + * through content. + */ + struct GNUNET_CRYPTO_RsaSignature signature; + + /** + * What is being signed and why? + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * Desired message options, see GNUNET_CHAT_MsgOptions. + */ + uint32_t msg_options GNUNET_PACKED; + + /** + * Sequence number of the message (unique per sender). + */ + uint32_t sequence_number GNUNET_PACKED; + + /** + * Timestamp of the message. + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + + /** + * Who should receive this message? Set to all zeros for "everyone". + */ + GNUNET_HashCode target; + +}; + + +/** + * Receipt sent from a message receiver to the service to confirm delivery of + * a chat message and from the service to sender of the original message to + * acknowledge delivery. + */ +struct ConfirmationReceiptMessage +{ + /** + * Message type will be + * GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT when sending from client, + * GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION when sending to client. + */ + struct GNUNET_MessageHeader header; + + /** + * For alignment (should be zero). + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Signature confirming receipt. Signature covers everything from header + * through content. + */ + struct GNUNET_CRYPTO_RsaSignature signature; + + /** + * What is being signed and why? + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * Sequence number of the original message. + */ + uint32_t sequence_number GNUNET_PACKED; + + /** + * For alignment (should be zero). + */ + uint32_t reserved2 GNUNET_PACKED; + + /** + * Time of receipt. + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + + /** + * Who is confirming the receipt? + */ + GNUNET_HashCode target; + + /** + * Who is the author of the chat message? + */ + GNUNET_HashCode author; + + /** + * Hash of the (possibly encrypted) content. + */ + GNUNET_HashCode content; + +}; + + +/** + * Message send from client to daemon to join a chat room. + * This struct is followed by the room name and then + * the serialized ECRS meta data describing the new member. + */ +struct JoinRequestMessage +{ + /** + * Message type will be GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST + */ + struct GNUNET_MessageHeader header; + + /** + * Options. Set all options that this client is willing to receive. + * For example, if the client does not want to receive anonymous or + * OTR messages but is willing to generate acknowledgements and + * receive private messages, this should be set to + * GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. + */ + uint32_t msg_options GNUNET_PACKED; + + /** + * Length of the room name. + */ + uint16_t room_name_len GNUNET_PACKED; + + /** + * For alignment (should be zero). + */ + uint16_t reserved GNUNET_PACKED; + uint32_t reserved2 GNUNET_PACKED; + + /** + * Public key of the joining member. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + +}; + + +/** + * Message send by server to client to indicate joining of another room member. + * This struct is followed by the serialized ECRS MetaData describing the new + * member. + */ +struct JoinNotificationMessage +{ + /** + * Message type will be GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION + */ + struct GNUNET_MessageHeader header; + + /** + * Options. Set to all options that the new user is willing to + * process. For example, if the client does not want to receive + * anonymous or OTR messages but is willing to generate + * acknowledgements and receive private messages, this should be set + * to GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. + */ + uint32_t msg_options GNUNET_PACKED; + + /** + * Public key of the new user. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + +}; + + +/** + * Message send by server to client to indicate leaving of another room member. + */ +struct LeaveNotificationMessage +{ + /** + * Message type will be GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION + */ + struct GNUNET_MessageHeader header; + + /** + * Reserved (for alignment). + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Who is leaving? + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded user; + +}; + + +/** + * Peer-to-peer messages + */ + +/** + * Message send by one peer to another to indicate joining of another room + * member. This struct is followed by the room name and then the serialized + * ECRS MetaData describing the new member. + */ +struct P2PJoinNotificationMessage +{ + /** + * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION + */ + struct GNUNET_MessageHeader header; + + /** + * Options. Set all options that this client is willing to receive. + * For example, if the client does not want to receive anonymous or + * OTR messages but is willing to generate acknowledgements and + * receive private messages, this should be set to + * GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. + */ + uint32_t msg_options GNUNET_PACKED; + + /** + * Length of the room name. + */ + uint16_t room_name_len GNUNET_PACKED; + + /** + * Reserved (should be zero). + */ + uint16_t reserved GNUNET_PACKED; + uint32_t reserved2 GNUNET_PACKED; + + /** + * Public key of the joining member. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + +}; + + +/** + * Message send by one peer to another to indicate leaving of another room + * member. + */ +struct P2PLeaveNotificationMessage +{ + /** + * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION + */ + struct GNUNET_MessageHeader header; + + /** + * Reserved (for alignment). + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Who is leaving? + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded user; + +}; + + +/** + * Message send by one peer to another to indicate receiving of a chat message. + * This struct is followed by the room name (only if the message is anonymous) + * and then the remaining bytes are the actual text message. If the mesasge is + * private, then the text is encrypted, otherwise it's plaintext. + */ +struct P2PReceiveNotificationMessage +{ + /** + * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION + */ + struct GNUNET_MessageHeader header; + + /** + * Message options, see GNUNET_CHAT_MsgOptions. + */ + uint32_t msg_options GNUNET_PACKED; + + /** + * Sequence number of the message (unique per sender). + */ + uint32_t sequence_number GNUNET_PACKED; + + /** + * Length of the room name. This is only used for anonymous messages. + */ + uint16_t room_name_len GNUNET_PACKED; + + /** + * Reserved (for alignment). + */ + uint16_t reserved GNUNET_PACKED; + + /** + * Timestamp of the message. + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + + /** + * Hash of the public key of the pseudonym of the sender of the message + * Should be all zeros for anonymous. + */ + GNUNET_HashCode sender; + + /** + * Who should receive this message? Set to all zeros for "everyone". + */ + GNUNET_HashCode target; + + /** + * The encrypted session key. + */ + struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; + +}; + + +/** + * Receipt sent from one peer to another to confirm delivery of a chat message. + */ +struct P2PConfirmationReceiptMessage +{ + /** + * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT + */ + struct GNUNET_MessageHeader header; + + /** + * For alignment (should be zero). + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Signature confirming receipt. Signature covers everything from header + * through content. + */ + struct GNUNET_CRYPTO_RsaSignature signature; + + /** + * What is being signed and why? + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * Sequence number of the original message. + */ + uint32_t msg_sequence_number GNUNET_PACKED; + + /** + * Sequence number of the receipt. + */ + uint32_t sequence_number GNUNET_PACKED; + + /** + * Time of receipt. + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + + /** + * Who is confirming the receipt? + */ + GNUNET_HashCode target; + + /** + * Who is the author of the chat message? + */ + GNUNET_HashCode author; + + /** + * Hash of the (possibly encrypted) content. + */ + GNUNET_HashCode content; + +}; +GNUNET_NETWORK_STRUCT_END + +#endif + +/* end of chat.h */ diff --git a/src/chat/gnunet-chat.c b/src/chat/gnunet-chat.c new file mode 100644 index 0000000..4abc58c --- /dev/null +++ b/src/chat/gnunet-chat.c @@ -0,0 +1,674 @@ +/* + This file is part of GNUnet. + (C) 2007, 2008, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file chat/gnunet-chat.c + * @brief Minimal chat command line tool + * @author Christian Grothoff + * @author Nathan Evans + * @author Vitaly Minko + */ + +#include "platform.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_chat_service.h" +#include + +static int ret; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static char *nickname; + +static char *room_name; + +static struct GNUNET_CONTAINER_MetaData *meta; + +static struct GNUNET_CHAT_Room *room; + +static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task = + GNUNET_SCHEDULER_NO_TASK; + +struct ChatCommand +{ + const char *command; + int (*Action) (const char *arguments, const void *xtra); + const char *helptext; +}; + +struct UserList +{ + struct UserList *next; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + int ignored; +}; + +static struct UserList *users; + +static void +free_user_list () +{ + struct UserList *next; + + while (NULL != users) + { + next = users->next; + GNUNET_free (users); + users = next; + } +} + +static int +do_help (const char *args, const void *xtra); + + +/** + * Callback used for notification that we have joined the room. + * + * @param cls closure + * @return GNUNET_OK + */ +static int +join_cb (void *cls) +{ + FPRINTF (stdout, "%s", _("Joined\n")); + return GNUNET_OK; +} + + +/** + * Callback used for notification about incoming messages. + * + * @param cls closure, NULL + * @param room in which room was the message received? + * @param sender what is the ID of the sender? (maybe NULL) + * @param member_info information about the joining member + * @param message the message text + * @param timestamp time when the member joined + * @param options options for the message + * @return GNUNET_OK to accept the message now, GNUNET_NO to + * accept (but user is away), GNUNET_SYSERR to signal denied delivery + */ +static int +receive_cb (void *cls, struct GNUNET_CHAT_Room *room, + const GNUNET_HashCode * sender, + const struct GNUNET_CONTAINER_MetaData *member_info, + const char *message, struct GNUNET_TIME_Absolute timestamp, + enum GNUNET_CHAT_MsgOptions options) +{ + char *nick; + char *time; + const char *fmt; + + if (NULL != sender) + nick = GNUNET_PSEUDONYM_id_to_name (cfg, sender); + else + nick = GNUNET_strdup (_("anonymous")); + fmt = NULL; + switch ((int) options) + { + case GNUNET_CHAT_MSG_OPTION_NONE: + case GNUNET_CHAT_MSG_ANONYMOUS: + fmt = _("(%s) `%s' said: %s\n"); + break; + case GNUNET_CHAT_MSG_PRIVATE: + fmt = _("(%s) `%s' said to you: %s\n"); + break; + case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ANONYMOUS: + fmt = _("(%s) `%s' said to you: %s\n"); + break; + case GNUNET_CHAT_MSG_AUTHENTICATED: + fmt = _("(%s) `%s' said for sure: %s\n"); + break; + case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_AUTHENTICATED: + fmt = _("(%s) `%s' said to you for sure: %s\n"); + break; + case GNUNET_CHAT_MSG_ACKNOWLEDGED: + fmt = _("(%s) `%s' was confirmed that you received: %s\n"); + break; + case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: + fmt = _("(%s) `%s' was confirmed that you and only you received: %s\n"); + break; + case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_ACKNOWLEDGED: + fmt = _("(%s) `%s' was confirmed that you received from him or her: %s\n"); + break; + case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: + fmt = + _ + ("(%s) `%s' was confirmed that you and only you received from him or her: %s\n"); + break; + case GNUNET_CHAT_MSG_OFF_THE_RECORD: + fmt = _("(%s) `%s' said off the record: %s\n"); + break; + default: + fmt = _("(%s) <%s> said using an unknown message type: %s\n"); + break; + } + time = GNUNET_STRINGS_absolute_time_to_string (timestamp); + FPRINTF (stdout, fmt, time, nick, message); + GNUNET_free (nick); + GNUNET_free (time); + return GNUNET_OK; +} + + +/** + * Callback used for message delivery confirmations. + * + * @param cls closure, NULL + * @param room in which room was the message received? + * @param orig_seq_number sequence number of the original message + * @param timestamp when was the message received? + * @param receiver who is confirming the receipt? + * @return GNUNET_OK to continue, GNUNET_SYSERR to refuse processing further + * confirmations from anyone for this message + */ +static int +confirmation_cb (void *cls, struct GNUNET_CHAT_Room *room, + uint32_t orig_seq_number, + struct GNUNET_TIME_Absolute timestamp, + const GNUNET_HashCode * receiver) +{ + char *nick; + + nick = GNUNET_PSEUDONYM_id_to_name (cfg, receiver); + FPRINTF (stdout, _("'%s' acknowledged message #%d\n"), nick, orig_seq_number); + return GNUNET_OK; +} + + +/** + * Callback used for notification that another room member has joined or left. + * + * @param cls closure (not used) + * @param member_info will be non-null if the member is joining, NULL if he is + * leaving + * @param member_id hash of public key of the user (for unique identification) + * @param options what types of messages is this member willing to receive? + * @return GNUNET_OK + */ +static int +member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, + enum GNUNET_CHAT_MsgOptions options) +{ + char *nick; + GNUNET_HashCode id; + struct UserList *pos; + struct UserList *prev; + + GNUNET_CRYPTO_hash (member_id, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &id); + nick = GNUNET_PSEUDONYM_id_to_name (cfg, &id); + FPRINTF (stdout, + member_info != + NULL ? _("`%s' entered the room\n") : _("`%s' left the room\n"), + nick); + GNUNET_free (nick); + if (NULL != member_info) + { + /* user joining */ + pos = GNUNET_malloc (sizeof (struct UserList)); + pos->next = users; + pos->pkey = *member_id; + pos->ignored = GNUNET_NO; + users = pos; + } + else + { + /* user leaving */ + prev = NULL; + pos = users; + while ((NULL != pos) && + (0 != + memcmp (&pos->pkey, member_id, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))) + { + prev = pos; + pos = pos->next; + } + if (NULL == pos) + { + GNUNET_break (0); + } + else + { + if (NULL == prev) + users = pos->next; + else + prev->next = pos->next; + GNUNET_free (pos); + } + } + return GNUNET_OK; +} + + +static int +do_join (const char *arg, const void *xtra) +{ + char *my_name; + GNUNET_HashCode me; + + if (arg[0] == '#') + arg++; /* ignore first hash */ + GNUNET_CHAT_leave_room (room); + free_user_list (); + GNUNET_free (room_name); + room_name = GNUNET_strdup (arg); + room = + GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, + &receive_cb, NULL, &member_list_cb, NULL, + &confirmation_cb, NULL, &me); + if (NULL == room) + { + FPRINTF (stdout, "%s", _("Could not change username\n")); + return GNUNET_SYSERR; + } + my_name = GNUNET_PSEUDONYM_id_to_name (cfg, &me); + FPRINTF (stdout, _("Joining room `%s' as user `%s'...\n"), room_name, + my_name); + GNUNET_free (my_name); + return GNUNET_OK; +} + + +static int +do_nick (const char *msg, const void *xtra) +{ + char *my_name; + GNUNET_HashCode me; + + GNUNET_CHAT_leave_room (room); + free_user_list (); + GNUNET_free (nickname); + GNUNET_CONTAINER_meta_data_destroy (meta); + nickname = GNUNET_strdup (msg); + meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + nickname, strlen (nickname) + 1); + room = + GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, + &receive_cb, NULL, &member_list_cb, NULL, + &confirmation_cb, NULL, &me); + if (NULL == room) + { + FPRINTF (stdout, "%s", _("Could not change username\n")); + return GNUNET_SYSERR; + } + my_name = GNUNET_PSEUDONYM_id_to_name (cfg, &me); + FPRINTF (stdout, _("Changed username to `%s'\n"), my_name); + GNUNET_free (my_name); + return GNUNET_OK; +} + + +static int +do_names (const char *msg, const void *xtra) +{ + char *name; + struct UserList *pos; + GNUNET_HashCode pid; + + FPRINTF (stdout, _("Users in room `%s': "), room_name); + pos = users; + while (NULL != pos) + { + GNUNET_CRYPTO_hash (&pos->pkey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &pid); + name = GNUNET_PSEUDONYM_id_to_name (cfg, &pid); + FPRINTF (stdout, "`%s' ", name); + GNUNET_free (name); + pos = pos->next; + } + FPRINTF (stdout, "%s", "\n"); + return GNUNET_OK; +} + + +static int +do_send (const char *msg, const void *xtra) +{ + uint32_t seq; + + GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_OPTION_NONE, NULL, &seq); + return GNUNET_OK; +} + + +static int +do_send_pm (const char *msg, const void *xtra) +{ + char *user; + GNUNET_HashCode uid; + GNUNET_HashCode pid; + uint32_t seq; + struct UserList *pos; + + if (NULL == strstr (msg, " ")) + { + FPRINTF (stderr, "%s", _("Syntax: /msg USERNAME MESSAGE")); + return GNUNET_OK; + } + user = GNUNET_strdup (msg); + strstr (user, " ")[0] = '\0'; + msg += strlen (user) + 1; + if (GNUNET_OK != GNUNET_PSEUDONYM_name_to_id (cfg, user, &uid)) + { + FPRINTF (stderr, _("Unknown user `%s'\n"), user); + GNUNET_free (user); + return GNUNET_OK; + } + pos = users; + while (NULL != pos) + { + GNUNET_CRYPTO_hash (&pos->pkey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &pid); + if (0 == memcmp (&pid, &uid, sizeof (GNUNET_HashCode))) + break; + pos = pos->next; + } + if (NULL == pos) + { + FPRINTF (stderr, _("User `%s' is currently not in the room!\n"), user); + GNUNET_free (user); + return GNUNET_OK; + } + GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_PRIVATE, &pos->pkey, + &seq); + GNUNET_free (user); + return GNUNET_OK; +} + + +static int +do_send_sig (const char *msg, const void *xtra) +{ + uint32_t seq; + + GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_AUTHENTICATED, NULL, + &seq); + return GNUNET_OK; +} + + +static int +do_send_ack (const char *msg, const void *xtra) +{ + uint32_t seq; + + GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_ACKNOWLEDGED, NULL, + &seq); + return GNUNET_OK; +} + + +static int +do_send_anonymous (const char *msg, const void *xtra) +{ + uint32_t seq; + + GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_ANONYMOUS, NULL, &seq); + return GNUNET_OK; +} + + +static int +do_quit (const char *args, const void *xtra) +{ + return GNUNET_SYSERR; +} + + +static int +do_unknown (const char *msg, const void *xtra) +{ + FPRINTF (stderr, _("Unknown command `%s'\n"), msg); + return GNUNET_OK; +} + + +/** + * List of supported IRC commands. The order matters! + */ +static struct ChatCommand commands[] = { + {"/join ", &do_join, + gettext_noop + ("Use `/join #roomname' to join a chat room. Joining a room will cause you" + " to leave the current room")}, + {"/nick ", &do_nick, + gettext_noop + ("Use `/nick nickname' to change your nickname. This will cause you to" + " leave the current room and immediately rejoin it with the new name.")}, + {"/msg ", &do_send_pm, + gettext_noop + ("Use `/msg nickname message' to send a private message to the specified" + " user")}, + {"/notice ", &do_send_pm, + gettext_noop ("The `/notice' command is an alias for `/msg'")}, + {"/query ", &do_send_pm, + gettext_noop ("The `/query' command is an alias for `/msg'")}, + {"/sig ", &do_send_sig, + gettext_noop ("Use `/sig message' to send a signed public message")}, + {"/ack ", &do_send_ack, + gettext_noop + ("Use `/ack message' to require signed acknowledgment of the message")}, + {"/anonymous ", &do_send_anonymous, + gettext_noop + ("Use `/anonymous message' to send a public anonymous message")}, + {"/anon ", &do_send_anonymous, + gettext_noop ("The `/anon' command is an alias for `/anonymous'")}, + {"/quit", &do_quit, + gettext_noop ("Use `/quit' to terminate gnunet-chat")}, + {"/leave", &do_quit, + gettext_noop ("The `/leave' command is an alias for `/quit'")}, + {"/names", &do_names, + gettext_noop + ("Use `/names' to list all of the current members in the chat room")}, + {"/help", &do_help, + gettext_noop ("Use `/help command' to get help for a specific command")}, + /* Add standard commands: + * /whois (print metadata), + * /ignore (set flag, check on receive!) */ + /* the following three commands must be last! */ + {"/", &do_unknown, NULL}, + {"", &do_send, NULL}, + {NULL, NULL, NULL}, +}; + + +static int +do_help (const char *args, const void *xtra) +{ + int i; + + i = 0; + while ((NULL != args) && (0 != strlen (args)) && + (commands[i].Action != &do_help)) + { + if (0 == strncasecmp (&args[1], &commands[i].command[1], strlen (args) - 1)) + { + FPRINTF (stdout, "%s\n", gettext (commands[i].helptext)); + return GNUNET_OK; + } + i++; + } + i = 0; + FPRINTF (stdout, "%s", "Available commands:"); + while (commands[i].Action != &do_help) + { + FPRINTF (stdout, " %s", gettext (commands[i].command)); + i++; + } + FPRINTF (stdout, "%s", "\n"); + FPRINTF (stdout, "%s\n", gettext (commands[i].helptext)); + return GNUNET_OK; +} + + +static void +do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_CHAT_leave_room (room); + if (handle_cmd_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (handle_cmd_task); + handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; + } + free_user_list (); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_free (room_name); + GNUNET_free (nickname); +} + + +void +handle_command (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char message[MAX_MESSAGE_LENGTH + 1]; + int i; + + /* read message from command line and handle it */ + memset (message, 0, MAX_MESSAGE_LENGTH + 1); + if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin)) + goto next; + if (strlen (message) == 0) + goto next; + if (message[strlen (message) - 1] == '\n') + message[strlen (message) - 1] = '\0'; + if (strlen (message) == 0) + goto next; + i = 0; + while ((NULL != commands[i].command) && + (0 != + strncasecmp (commands[i].command, message, + strlen (commands[i].command)))) + i++; + if (GNUNET_OK != + commands[i].Action (&message[strlen (commands[i].command)], NULL)) + goto out; + +next: + handle_cmd_task = + GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + GNUNET_SCHEDULER_PRIORITY_UI, + &handle_command, NULL); + return; + +out: + handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure, NULL + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + GNUNET_HashCode me; + char *my_name; + + cfg = c; + /* check arguments */ + if (NULL == nickname) + { + FPRINTF (stderr, "%s", _("You must specify a nickname\n")); + ret = -1; + return; + } + if (NULL == room_name) + room_name = GNUNET_strdup ("gnunet"); + meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + nickname, strlen (nickname) + 1); + room = + GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, + &receive_cb, NULL, &member_list_cb, NULL, + &confirmation_cb, NULL, &me); + if (NULL == room) + { + FPRINTF (stderr, _("Failed to join room `%s'\n"), room_name); + GNUNET_free (room_name); + GNUNET_free (nickname); + GNUNET_CONTAINER_meta_data_destroy (meta); + ret = -1; + return; + } + my_name = GNUNET_PSEUDONYM_id_to_name (cfg, &me); + FPRINTF (stdout, _("Joining room `%s' as user `%s'...\n"), room_name, + my_name); + GNUNET_free (my_name); + handle_cmd_task = + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, + &handle_command, NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_stop_task, + NULL); +} + + +/** + * The main function to chat via GNUnet. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + int flags; + + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'n', "nick", "NAME", + gettext_noop ("set the nickname to use (required)"), + 1, &GNUNET_GETOPT_set_string, &nickname}, + {'r', "room", "NAME", + gettext_noop ("set the chat room to join"), + 1, &GNUNET_GETOPT_set_string, &room_name}, + GNUNET_GETOPT_OPTION_END + }; + +#ifndef WINDOWS + flags = fcntl (0, F_GETFL, 0); + flags |= O_NONBLOCK; + fcntl (0, F_SETFL, flags); +#endif + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-chat", + gettext_noop ("Join a chat on GNUnet."), options, + &run, NULL)) ? ret : 1; +} + +/* end of gnunet-chat.c */ diff --git a/src/chat/gnunet-service-chat.c b/src/chat/gnunet-service-chat.c new file mode 100644 index 0000000..fb127b2 --- /dev/null +++ b/src/chat/gnunet-service-chat.c @@ -0,0 +1,1737 @@ +/* + This file is part of GNUnet. + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file chat/gnunet-service-chat.c + * @brief service providing chat functionality + * @author Christian Grothoff + * @author Vitaly Minko + */ + +#include "platform.h" +#include "gnunet_core_service.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_service_lib.h" +#include "gnunet_signatures.h" +#include "chat.h" + +#define DEBUG_CHAT_SERVICE GNUNET_EXTRA_LOGGING +#define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) +#define EXPECTED_NEIGHBOUR_COUNT 16 +#define QUEUE_SIZE 16 +#define MAX_ANONYMOUS_MSG_LIST_LENGTH 16 + + +/** + * Linked list of our current clients. + */ +struct ChatClient +{ + struct ChatClient *next; + + /** + * Handle for a chat client (NULL for external clients). + */ + struct GNUNET_SERVER_Client *client; + + /** + * Public key of the client. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + + /** + * Name of the room which the client is in. + */ + char *room; + + /** + * Serialized metadata of the client. + */ + char *member_info; + + /** + * Hash of the public key (for convenience). + */ + GNUNET_HashCode id; + + /** + * Options which the client is willing to receive. + */ + uint32_t msg_options; + + /** + * Length of serialized metadata in member_info. + */ + uint16_t meta_len; + + /** + * Sequence number of the last message sent by the client. + */ + uint32_t msg_sequence_number; + + /** + * Sequence number of the last receipt sent by the client. + * Used to discard already processed receipts. + */ + uint32_t rcpt_sequence_number; + +}; + +/** + * Information about a peer that we are connected to. + * We track data that is useful for determining which + * peers should receive our requests. + */ +struct ConnectedPeer +{ + /** + * The peer's identity. + */ + GNUNET_PEER_Id pid; +}; + +/** + * Linked list of recent anonymous messages. + */ +struct AnonymousMessage +{ + struct AnonymousMessage *next; + + /** + * Hash of the message. + */ + GNUNET_HashCode hash; + +}; + + +/** + * Handle to the core service (NULL until we've connected to it). + */ +static struct GNUNET_CORE_Handle *core; + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * The identity of this host. + */ +static const struct GNUNET_PeerIdentity *me; + +/** + * Head of the list of current clients. + */ +static struct ChatClient *client_list_head = NULL; + +/** + * Notification context containing all connected clients. + */ +struct GNUNET_SERVER_NotificationContext *nc = NULL; + +/** + * Head of the list of recent anonymous messages. + */ +static struct AnonymousMessage *anonymous_list_head = NULL; + +/** + * Map of peer identifiers to "struct ConnectedPeer" (for that peer). + */ +static struct GNUNET_CONTAINER_MultiHashMap *connected_peers; + + +static void +remember_anonymous_message (const struct P2PReceiveNotificationMessage + *p2p_rnmsg) +{ + static GNUNET_HashCode hash; + struct AnonymousMessage *anon_msg; + struct AnonymousMessage *prev; + int anon_list_len; + + GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash); + anon_msg = GNUNET_malloc (sizeof (struct AnonymousMessage)); + anon_msg->hash = hash; + anon_msg->next = anonymous_list_head; + anonymous_list_head = anon_msg; + anon_list_len = 1; + prev = NULL; + while ((NULL != anon_msg->next)) + { + prev = anon_msg; + anon_msg = anon_msg->next; + anon_list_len++; + } + if (anon_list_len == MAX_ANONYMOUS_MSG_LIST_LENGTH) + { + GNUNET_free (anon_msg); + if (NULL != prev) + prev->next = NULL; + } +} + + +static int +lookup_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg) +{ + static GNUNET_HashCode hash; + struct AnonymousMessage *anon_msg; + + GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash); + anon_msg = anonymous_list_head; + while ((NULL != anon_msg) && + (0 != memcmp (&anon_msg->hash, &hash, sizeof (GNUNET_HashCode)))) + anon_msg = anon_msg->next; + return (NULL != anon_msg); +} + + +/** + * Transmit a message notification to the peer. + * + * @param cls closure, pointer to the 'struct P2PReceiveNotificationMessage' + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_message_notification_to_peer (void *cls, size_t size, void *buf) +{ + struct P2PReceiveNotificationMessage *my_msg = cls; + struct P2PReceiveNotificationMessage *m = buf; + size_t msg_size; + +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting P2P message notification\n"); +#endif + if (buf == NULL) + { + /* client disconnected */ +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Buffer is NULL, dropping the message\n"); +#endif + return 0; + } + msg_size = ntohs (my_msg->header.size); + GNUNET_assert (size >= msg_size); + memcpy (m, my_msg, msg_size); + GNUNET_free (my_msg); + return msg_size; +} + + +/** + * Ask to send a message notification to the peer. + */ +static int +send_message_noficiation (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct P2PReceiveNotificationMessage *msg = cls; + struct ConnectedPeer *cp = value; + struct GNUNET_PeerIdentity pid; + struct P2PReceiveNotificationMessage *my_msg; + + GNUNET_PEER_resolve (cp->pid, &pid); +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message notification to `%s'\n", + GNUNET_i2s (&pid)); +#endif + my_msg = GNUNET_memdup (msg, ntohs (msg->header.size)); + if (NULL == + GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY, + &pid, ntohs (msg->header.size), + &transmit_message_notification_to_peer, + my_msg)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to queue a message notification\n")); + return GNUNET_YES; +} + + +/** + * A client sent a chat message. Encrypt the message text if the message is + * private. Send the message to local room members and to all connected peers. + * + * @param cls closure, NULL + * @param client identification of the client + * @param message the actual message + */ +static void +handle_transmit_request (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + static GNUNET_HashCode all_zeros; + const struct TransmitRequestMessage *trmsg; + struct ReceiveNotificationMessage *rnmsg; + struct P2PReceiveNotificationMessage *p2p_rnmsg; + struct ChatClient *pos; + struct ChatClient *target; + struct GNUNET_CRYPTO_AesSessionKey key; + char encrypted_msg[MAX_MESSAGE_LENGTH]; + const char *room; + size_t room_len; + int msg_len; + int is_priv; + int is_anon; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n"); + if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + trmsg = (const struct TransmitRequestMessage *) message; + msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage); + is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE)); + if (is_priv) + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n"); +#endif + GNUNET_CRYPTO_aes_create_session_key (&key); + msg_len = + GNUNET_CRYPTO_aes_encrypt (&trmsg[1], msg_len, &key, + (const struct + GNUNET_CRYPTO_AesInitializationVector *) + INITVALUE, encrypted_msg); + if (-1 == msg_len) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not encrypt the message text\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + } + rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len); + rnmsg->header.size = + htons (sizeof (struct ReceiveNotificationMessage) + msg_len); + rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION); + rnmsg->msg_options = trmsg->msg_options; + rnmsg->timestamp = trmsg->timestamp; + pos = client_list_head; + while ((NULL != pos) && (pos->client != client)) + pos = pos->next; + if (NULL == pos) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "The client is not a member of a chat room. Client has to " + "join a chat room first\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + GNUNET_free (rnmsg); + return; + } + room = pos->room; + pos->msg_sequence_number = ntohl (trmsg->sequence_number); + is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)); + if (is_anon) + { + memset (&rnmsg->sender, 0, sizeof (GNUNET_HashCode)); + rnmsg->sequence_number = 0; + } + else + { + rnmsg->sender = pos->id; + rnmsg->sequence_number = trmsg->sequence_number; + } + if (is_priv) + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Encrypting the session key using the public key of '%s'\n", + GNUNET_h2s (&trmsg->target)); +#endif + if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (GNUNET_HashCode))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed message: private, but no target\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + GNUNET_free (rnmsg); + return; + } + memcpy (&rnmsg[1], encrypted_msg, msg_len); + target = client_list_head; + while ((NULL != target) && + (0 != + memcmp (&target->id, &trmsg->target, sizeof (GNUNET_HashCode)))) + target = target->next; + if (NULL == target) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unknown target of the private message\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + GNUNET_free (rnmsg); + return; + } + if (GNUNET_SYSERR == + GNUNET_CRYPTO_rsa_encrypt (&key, + sizeof (struct GNUNET_CRYPTO_AesSessionKey), + &target->public_key, &rnmsg->encrypted_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not encrypt the session key\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + GNUNET_free (rnmsg); + return; + } + } + else + { + memcpy (&rnmsg[1], &trmsg[1], msg_len); + } + pos = client_list_head; +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message to local room members\n"); +#endif + while (NULL != pos) + { + if ((0 == strcmp (room, pos->room)) && (NULL != pos->client) && + (pos->client != client)) + { + if (((!is_priv) || + (0 == memcmp (&trmsg->target, &pos->id, sizeof (GNUNET_HashCode)))) + && (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options)))) + { + GNUNET_SERVER_notification_context_unicast (nc, pos->client, + &rnmsg->header, GNUNET_NO); + } + } + pos = pos->next; + } +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Broadcasting message to neighbour peers\n"); +#endif + if (is_anon) + { + room_len = strlen (room); + p2p_rnmsg = + GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len + + room_len); + p2p_rnmsg->header.size = + htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len + + room_len); + p2p_rnmsg->room_name_len = htons (room_len); + memcpy ((char *) &p2p_rnmsg[1], room, room_len); + memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len); + } + else + { + p2p_rnmsg = + GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len); + p2p_rnmsg->header.size = + htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len); + if (is_priv) + { + memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len); + memcpy (&p2p_rnmsg->encrypted_key, &rnmsg->encrypted_key, + sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); + } + else + memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len); + } + p2p_rnmsg->header.type = + htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION); + p2p_rnmsg->msg_options = trmsg->msg_options; + p2p_rnmsg->sequence_number = trmsg->sequence_number; + p2p_rnmsg->timestamp = trmsg->timestamp; + p2p_rnmsg->reserved = htons (0); + p2p_rnmsg->sender = rnmsg->sender; + p2p_rnmsg->target = trmsg->target; + if (is_anon) + remember_anonymous_message (p2p_rnmsg); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_message_noficiation, p2p_rnmsg); + GNUNET_free (p2p_rnmsg); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + GNUNET_free (rnmsg); +} + + +/** + * Transmit a join notification to the peer. + * + * @param cls closure, pointer to the 'struct ChatClient' + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_join_notification_to_peer (void *cls, size_t size, void *buf) +{ + struct ChatClient *entry = cls; + struct P2PJoinNotificationMessage *m = buf; + size_t room_len; + size_t meta_len; + size_t msg_size; + char *roomptr; + +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P join notification\n"); +#endif + room_len = strlen (entry->room); + meta_len = entry->meta_len; + msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len; + GNUNET_assert (size >= msg_size); + GNUNET_assert (NULL != buf); + m = buf; + m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION); + m->header.size = htons (msg_size); + m->msg_options = htonl (entry->msg_options); + m->room_name_len = htons (room_len); + m->reserved = htons (0); + m->reserved2 = htonl (0); + m->public_key = entry->public_key; + roomptr = (char *) &m[1]; + memcpy (roomptr, entry->room, room_len); + if (meta_len > 0) + memcpy (&roomptr[room_len], entry->member_info, meta_len); + return msg_size; +} + + +/** + * Ask to send a join notification to the peer. + */ +static int +send_join_noficiation (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ChatClient *entry = cls; + struct ConnectedPeer *cp = value; + struct GNUNET_PeerIdentity pid; + size_t msg_size; + + GNUNET_PEER_resolve (cp->pid, &pid); +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending join notification to `%s'\n", + GNUNET_i2s (&pid)); +#endif + msg_size = + sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) + + entry->meta_len; + if (NULL == + GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY, + &pid, msg_size, + &transmit_join_notification_to_peer, + entry)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to queue a join notification\n")); + return GNUNET_YES; +} + + +/** + * A client asked for entering a chat room. Add the new member to the list of + * clients and notify remaining room members. + * + * @param cls closure, NULL + * @param client identification of the client + * @param message the actual message + */ +static void +handle_join_request (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct JoinRequestMessage *jrmsg; + char *room_name; + const char *roomptr; + uint16_t header_size; + uint16_t meta_len; + uint16_t room_name_len; + struct ChatClient *new_entry; + struct ChatClient *entry; + struct JoinNotificationMessage *jnmsg; + struct JoinNotificationMessage *entry_jnmsg; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n"); + if (ntohs (message->size) <= sizeof (struct JoinRequestMessage)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + jrmsg = (const struct JoinRequestMessage *) message; + header_size = ntohs (jrmsg->header.size); + room_name_len = ntohs (jrmsg->room_name_len); + if (header_size - sizeof (struct JoinRequestMessage) <= room_name_len) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed message: wrong length of the room name\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + meta_len = header_size - sizeof (struct JoinRequestMessage) - room_name_len; + roomptr = (const char *) &jrmsg[1]; + room_name = GNUNET_malloc (room_name_len + 1); + memcpy (room_name, roomptr, room_name_len); + room_name[room_name_len] = '\0'; + new_entry = GNUNET_malloc (sizeof (struct ChatClient)); + memset (new_entry, 0, sizeof (struct ChatClient)); + new_entry->client = client; + new_entry->room = room_name; + new_entry->public_key = jrmsg->public_key; + new_entry->meta_len = meta_len; + if (meta_len > 0) + { + new_entry->member_info = GNUNET_malloc (meta_len); + memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len); + } + else + new_entry->member_info = NULL; + GNUNET_CRYPTO_hash (&new_entry->public_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &new_entry->id); + new_entry->msg_options = ntohl (jrmsg->msg_options); + new_entry->next = client_list_head; + client_list_head = new_entry; +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Synchronizing room members between local clients\n"); +#endif + jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len); + jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); + jnmsg->header.size = + htons (sizeof (struct JoinNotificationMessage) + meta_len); + jnmsg->msg_options = jrmsg->msg_options; + jnmsg->public_key = new_entry->public_key; + memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len); + GNUNET_SERVER_notification_context_add (nc, client); + entry = client_list_head; + while (NULL != entry) + { + if (0 == strcmp (room_name, entry->room)) + { + if (NULL != entry->client) + GNUNET_SERVER_notification_context_unicast (nc, entry->client, + &jnmsg->header, GNUNET_NO); + if (entry->client != client) + { + entry_jnmsg = + GNUNET_malloc (sizeof (struct JoinNotificationMessage) + + entry->meta_len); + entry_jnmsg->header.type = + htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); + entry_jnmsg->header.size = + htons (sizeof (struct JoinNotificationMessage) + entry->meta_len); + entry_jnmsg->msg_options = entry->msg_options; + entry_jnmsg->public_key = entry->public_key; + memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len); + GNUNET_SERVER_notification_context_unicast (nc, client, + &entry_jnmsg->header, + GNUNET_NO); + GNUNET_free (entry_jnmsg); + } + } + entry = entry->next; + } +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Broadcasting join notification to neighbour peers\n"); +#endif + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_join_noficiation, new_entry); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + GNUNET_free (jnmsg); +} + +/** + * Transmit a confirmation receipt to the peer. + * + * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage' + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_confirmation_receipt_to_peer (void *cls, size_t size, void *buf) +{ + struct P2PConfirmationReceiptMessage *receipt = cls; + size_t msg_size; + +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting P2P confirmation receipt to '%s'\n", + GNUNET_h2s (&receipt->target)); +#endif + if (buf == NULL) + { + /* client disconnected */ +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Buffer is NULL, dropping the message\n"); +#endif + return 0; + } + msg_size = sizeof (struct P2PConfirmationReceiptMessage); + GNUNET_assert (size >= msg_size); + memcpy (buf, receipt, msg_size); + GNUNET_free (receipt); + return msg_size; +} + + +/** + * Ask to send a confirmation receipt to the peer. + */ +static int +send_confirmation_receipt (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct P2PConfirmationReceiptMessage *receipt = cls; + struct ConnectedPeer *cp = value; + struct GNUNET_PeerIdentity pid; + struct P2PConfirmationReceiptMessage *my_receipt; + size_t msg_size; + + GNUNET_PEER_resolve (cp->pid, &pid); +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending confirmation receipt to `%s'\n", + GNUNET_i2s (&pid)); +#endif + msg_size = sizeof (struct P2PConfirmationReceiptMessage); + my_receipt = + GNUNET_memdup (receipt, sizeof (struct P2PConfirmationReceiptMessage)); + if (NULL == + GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, + MAX_TRANSMIT_DELAY, &pid, msg_size, + &transmit_confirmation_receipt_to_peer, + my_receipt)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to queue a confirmation receipt\n")); + return GNUNET_YES; +} + + +/** + * A client sent a confirmation receipt. Broadcast the receipt to all connected + * peers if the author of the original message is a local client. Otherwise + * check the signature and notify the user if the signature is valid. + * + * @param cls closure, NULL + * @param client identification of the client + * @param message the actual message + */ +static void +handle_acknowledge_request (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct ConfirmationReceiptMessage *receipt; + struct ConfirmationReceiptMessage *crmsg; + struct P2PConfirmationReceiptMessage *p2p_crmsg; + struct ChatClient *target; + struct ChatClient *author; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n"); + receipt = (const struct ConfirmationReceiptMessage *) message; + author = client_list_head; + while ((NULL != author) && + (0 != + memcmp (&receipt->author, &author->id, sizeof (GNUNET_HashCode)))) + author = author->next; + if (NULL == author) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unknown author of the original message\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + target = client_list_head; + while ((NULL != target) && + (0 != + memcmp (&receipt->target, &target->id, sizeof (GNUNET_HashCode)))) + target = target->next; + if (NULL == target) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unknown target of the confirmation receipt\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if (NULL == author->client) + { + target->rcpt_sequence_number++; +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Broadcasting %s's receipt #%u to neighbour peers\n", + GNUNET_h2s (&target->id), target->rcpt_sequence_number); +#endif + p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage)); + p2p_crmsg->header.size = + htons (sizeof (struct P2PConfirmationReceiptMessage)); + p2p_crmsg->header.type = + htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT); + p2p_crmsg->reserved = htonl (0); + p2p_crmsg->signature = receipt->signature; + p2p_crmsg->purpose = receipt->purpose; + p2p_crmsg->msg_sequence_number = receipt->sequence_number; + p2p_crmsg->timestamp = receipt->timestamp; + p2p_crmsg->target = receipt->target; + p2p_crmsg->author = receipt->author; + p2p_crmsg->content = receipt->content; + p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_confirmation_receipt, + p2p_crmsg); + GNUNET_free (p2p_crmsg); + } + else + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Verifying signature of the receipt\n"); +#endif + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT, + &receipt->purpose, &receipt->signature, + &target->public_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid signature of the receipt\n"); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending receipt to the client which sent the original message\n"); +#endif + crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage)); + crmsg->header.type = + htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION); + GNUNET_SERVER_notification_context_unicast (nc, author->client, + &crmsg->header, GNUNET_NO); + GNUNET_free (crmsg); + } + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Transmit a leave notification to the peer. + * + * @param cls closure, pointer to the + * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded' + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_leave_notification_to_peer (void *cls, size_t size, void *buf) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls; + struct P2PLeaveNotificationMessage *m = buf; + size_t msg_size; + +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P leave notification\n"); +#endif + if (buf == NULL) + { + /* client disconnected */ +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Buffer is NULL, dropping the message\n"); +#endif + return 0; + } + msg_size = sizeof (struct P2PLeaveNotificationMessage); + GNUNET_assert (size >= msg_size); + m = buf; + m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION); + m->header.size = htons (msg_size); + m->reserved = htonl (0); + m->user = *public_key; + GNUNET_free (public_key); + return msg_size; +} + + +/** + * Ask to send a leave notification to the peer. + */ +static int +send_leave_noficiation (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ChatClient *entry = cls; + struct ConnectedPeer *cp = value; + struct GNUNET_PeerIdentity pid; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; + size_t msg_size; + + GNUNET_PEER_resolve (cp->pid, &pid); +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending leave notification to `%s'\n", + GNUNET_i2s (&pid)); +#endif + msg_size = sizeof (struct P2PLeaveNotificationMessage); + public_key = + GNUNET_memdup (&entry->public_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + if (NULL == + GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, + MAX_TRANSMIT_DELAY, &pid, msg_size, + &transmit_leave_notification_to_peer, + public_key)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to queue a leave notification\n")); + return GNUNET_YES; +} + + +/** + * A client disconnected. Remove all of its data structure entries and notify + * remaining room members. + * + * @param cls closure, NULL + * @param client identification of the client + */ +static void +handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct ChatClient *entry; + struct ChatClient *pos; + struct ChatClient *prev; + struct LeaveNotificationMessage lnmsg; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n"); + pos = client_list_head; + prev = NULL; + while ((NULL != pos) && (pos->client != client)) + { + prev = pos; + pos = pos->next; + } + if (NULL == pos) + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No such client. There is nothing to do\n"); +#endif + return; + } + if (NULL == prev) + client_list_head = pos->next; + else + prev->next = pos->next; + entry = client_list_head; +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Notifying local room members that the client has disconnected\n"); +#endif + lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage)); + lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION); + lnmsg.reserved = htonl (0); + lnmsg.user = pos->public_key; + while (NULL != entry) + { + if ((0 == strcmp (pos->room, entry->room)) && (NULL != entry->client)) + { + GNUNET_SERVER_notification_context_unicast (nc, entry->client, + &lnmsg.header, GNUNET_NO); + } + entry = entry->next; + } +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Broadcasting leave notification to neighbour peers\n"); +#endif + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_leave_noficiation, pos); + GNUNET_free (pos->room); + GNUNET_free_non_null (pos->member_info); + GNUNET_free (pos); +} + + +/** + * Handle P2P join notification. + * + * @param cls closure, always NULL + * @param other the other peer involved + * @param message the actual message + * @param atsi performance information + * @param atsi_count number of entries in atsi + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_p2p_join_notification (void *cls, + const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + const struct P2PJoinNotificationMessage *p2p_jnmsg; + char *room_name; + const char *roomptr; + uint16_t header_size; + uint16_t meta_len; + uint16_t room_name_len; + struct ChatClient *new_entry; + struct ChatClient *entry; + struct JoinNotificationMessage *jnmsg; + GNUNET_HashCode id; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n"); + if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message; + header_size = ntohs (p2p_jnmsg->header.size); + room_name_len = ntohs (p2p_jnmsg->room_name_len); + if (header_size - sizeof (struct P2PJoinNotificationMessage) <= room_name_len) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed message: wrong length of the room name\n"); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &id); + entry = client_list_head; + while (NULL != entry) + { + if (0 == memcmp (&entry->id, &id, sizeof (GNUNET_HashCode))) + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "The client has already joined. There is nothing to do\n"); +#endif + return GNUNET_OK; + } + entry = entry->next; + } + meta_len = + header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len; + roomptr = (const char *) &p2p_jnmsg[1]; + room_name = GNUNET_malloc (room_name_len + 1); + memcpy (room_name, roomptr, room_name_len); + room_name[room_name_len] = '\0'; + new_entry = GNUNET_malloc (sizeof (struct ChatClient)); + memset (new_entry, 0, sizeof (struct ChatClient)); + new_entry->id = id; + new_entry->client = NULL; + new_entry->room = room_name; + new_entry->public_key = p2p_jnmsg->public_key; + new_entry->meta_len = meta_len; + if (meta_len > 0) + { + new_entry->member_info = GNUNET_malloc (meta_len); + memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len); + } + else + new_entry->member_info = NULL; + new_entry->msg_options = ntohl (p2p_jnmsg->msg_options); + new_entry->next = client_list_head; + client_list_head = new_entry; +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Notifying local room members that we have a new client\n"); +#endif + jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len); + jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); + jnmsg->header.size = + htons (sizeof (struct JoinNotificationMessage) + meta_len); + jnmsg->msg_options = p2p_jnmsg->msg_options; + jnmsg->public_key = new_entry->public_key; + memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len); + entry = client_list_head; + while (NULL != entry) + { + if ((0 == strcmp (room_name, entry->room)) && (NULL != entry->client)) + { + GNUNET_SERVER_notification_context_unicast (nc, entry->client, + &jnmsg->header, GNUNET_NO); + } + entry = entry->next; + } +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Broadcasting join notification to neighbour peers\n"); +#endif + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_join_noficiation, new_entry); + GNUNET_free (jnmsg); + return GNUNET_OK; +} + + +/** + * Handle P2P leave notification. + * + * @param cls closure, always NULL + * @param other the other peer involved + * @param message the actual message + * @param atsi performance information + * @param atsi_count number of entries in atsi + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_p2p_leave_notification (void *cls, + const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + const struct P2PLeaveNotificationMessage *p2p_lnmsg; + GNUNET_HashCode id; + struct ChatClient *pos; + struct ChatClient *prev; + struct ChatClient *entry; + struct LeaveNotificationMessage lnmsg; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n"); + p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message; + GNUNET_CRYPTO_hash (&p2p_lnmsg->user, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &id); + pos = client_list_head; + prev = NULL; + while (NULL != pos) + { + if (0 == memcmp (&pos->id, &id, sizeof (GNUNET_HashCode))) + break; + prev = pos; + pos = pos->next; + } + if (NULL == pos) + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No such client. There is nothing to do\n"); +#endif + return GNUNET_OK; + } + if (NULL == prev) + client_list_head = pos->next; + else + prev->next = pos->next; +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Notifying local room members that the client has gone away\n"); +#endif + lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage)); + lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION); + lnmsg.reserved = htonl (0); + lnmsg.user = pos->public_key; + entry = client_list_head; + while (NULL != entry) + { + if (0 == strcmp (pos->room, entry->room) && (NULL != entry->client)) + { + GNUNET_SERVER_notification_context_unicast (nc, entry->client, + &lnmsg.header, GNUNET_NO); + } + entry = entry->next; + } +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Broadcasting leave notification to neighbour peers\n"); +#endif + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_leave_noficiation, pos); + GNUNET_free (pos->room); + GNUNET_free_non_null (pos->member_info); + GNUNET_free (pos); + return GNUNET_OK; +} + + +/** + * Handle P2P message notification. + * + * @param cls closure, always NULL + * @param other the other peer involved + * @param message the actual message + * @param atsi performance information + * @param atsi_count number of entries in atsi + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_p2p_message_notification (void *cls, + const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + const struct P2PReceiveNotificationMessage *p2p_rnmsg; + struct P2PReceiveNotificationMessage *my_p2p_rnmsg; + struct ReceiveNotificationMessage *rnmsg; + struct ChatClient *sender; + struct ChatClient *pos; + static GNUNET_HashCode all_zeros; + int is_priv; + int is_anon; + uint16_t msg_len; + uint16_t room_name_len; + char *room_name = NULL; + char *text; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n"); + if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message; + msg_len = + ntohs (p2p_rnmsg->header.size) - + sizeof (struct P2PReceiveNotificationMessage); + + is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)); + if (is_anon) + { + room_name_len = ntohs (p2p_rnmsg->room_name_len); + if (msg_len <= room_name_len) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed message: wrong length of the room name\n"); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + msg_len -= room_name_len; + if (lookup_anonymous_message (p2p_rnmsg)) + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "This anonymous message has already been handled."); +#endif + return GNUNET_OK; + } + remember_anonymous_message (p2p_rnmsg); + room_name = GNUNET_malloc (room_name_len + 1); + memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len); + room_name[room_name_len] = '\0'; + text = (char *) &p2p_rnmsg[1] + room_name_len; + } + else + { + sender = client_list_head; + while ((NULL != sender) && + (0 != + memcmp (&sender->id, &p2p_rnmsg->sender, sizeof (GNUNET_HashCode)))) + sender = sender->next; + if (NULL == sender) + { + /* not an error since the sender may have left before we got the + * message */ +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Unknown source. Rejecting the message\n"); +#endif + return GNUNET_OK; + } + if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number)) + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "This message has already been handled." + " Sequence numbers (msg/sender): %u/%u\n", + ntohl (p2p_rnmsg->sequence_number), + sender->msg_sequence_number); +#endif + return GNUNET_OK; + } + sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number); + room_name = sender->room; + text = (char *) &p2p_rnmsg[1]; + } + +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message to local room members\n"); +#endif + rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len); + rnmsg->header.size = + htons (sizeof (struct ReceiveNotificationMessage) + msg_len); + rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION); + rnmsg->msg_options = p2p_rnmsg->msg_options; + rnmsg->sequence_number = p2p_rnmsg->sequence_number; + rnmsg->reserved = htonl (0); + rnmsg->timestamp = p2p_rnmsg->timestamp; + is_priv = + (0 != memcmp (&all_zeros, &p2p_rnmsg->target, sizeof (GNUNET_HashCode))); + if (is_priv) + memcpy (&rnmsg->encrypted_key, &p2p_rnmsg->encrypted_key, + sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); + rnmsg->sender = p2p_rnmsg->sender; + memcpy (&rnmsg[1], text, msg_len); + pos = client_list_head; + while (NULL != pos) + { + if ((0 == strcmp (room_name, pos->room)) && (NULL != pos->client)) + { + if (((!is_priv) || + (0 == + memcmp (&p2p_rnmsg->target, &pos->id, sizeof (GNUNET_HashCode)))) && + (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options)))) + { + GNUNET_SERVER_notification_context_unicast (nc, pos->client, + &rnmsg->header, GNUNET_NO); + } + } + pos = pos->next; + } + if (is_anon) + GNUNET_free (room_name); +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Broadcasting message notification to neighbour peers\n"); +#endif + my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size)); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_message_noficiation, + my_p2p_rnmsg); + GNUNET_free (rnmsg); + return GNUNET_OK; +} + + +/** + * Handle P2P sync request. + * + * @param cls closure, always NULL + * @param other the other peer involved + * @param message the actual message + * @param atsi performance information + * @param atsi_count number of entries in atsi + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_p2p_sync_request (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct ChatClient *entry; + struct GNUNET_CORE_TransmitHandle *th; + size_t msg_size; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n"); +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Notifying the requester of all known clients\n"); +#endif + entry = client_list_head; + while (NULL != entry) + { + msg_size = + sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) + + entry->meta_len; + th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, + MAX_TRANSMIT_DELAY, other, msg_size, + &transmit_join_notification_to_peer, + entry); + GNUNET_assert (NULL != th); + entry = entry->next; + } + return GNUNET_OK; +} + + +/** + * Handle P2P confirmation receipt. + * + * @param cls closure, always NULL + * @param other the other peer involved + * @param message the actual message + * @param atsi performance information + * @param atsi_count number of entries in atsi + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_p2p_confirmation_receipt (void *cls, + const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + const struct P2PConfirmationReceiptMessage *p2p_crmsg; + struct P2PConfirmationReceiptMessage *my_p2p_crmsg; + struct ConfirmationReceiptMessage *crmsg; + struct ChatClient *target; + struct ChatClient *author; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n"); + p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message; + target = client_list_head; + while ((NULL != target) && + (0 != + memcmp (&target->id, &p2p_crmsg->target, sizeof (GNUNET_HashCode)))) + target = target->next; + if (NULL == target) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unknown source of the receipt. Rejecting the message\n"); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number)) + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "This receipt has already been handled." + " Sequence numbers (msg/sender): %u/%u\n", + ntohl (p2p_crmsg->sequence_number), + target->rcpt_sequence_number); +#endif + return GNUNET_OK; + } + target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number); + author = client_list_head; + while ((NULL != author) && + (0 != + memcmp (&author->id, &p2p_crmsg->author, sizeof (GNUNET_HashCode)))) + author = author->next; + if (NULL == author) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unknown addressee. Rejecting the receipt\n"); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + if (NULL == author->client) + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "The author of the original message is not a local client." + " Broadcasting receipt to neighbour peers\n"); +#endif + my_p2p_crmsg = + GNUNET_memdup (p2p_crmsg, + sizeof (struct P2PConfirmationReceiptMessage)); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_confirmation_receipt, + my_p2p_crmsg); + GNUNET_free (my_p2p_crmsg); + } + else + { +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "The author of the original message is a local client." + " Verifying signature of the receipt\n"); +#endif + crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage)); + crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage)); + crmsg->header.type = + htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION); + crmsg->signature = p2p_crmsg->signature; + crmsg->purpose = p2p_crmsg->purpose; + crmsg->sequence_number = p2p_crmsg->msg_sequence_number; + crmsg->reserved2 = 0; + crmsg->timestamp = p2p_crmsg->timestamp; + crmsg->target = p2p_crmsg->target; + crmsg->author = p2p_crmsg->author; + crmsg->content = p2p_crmsg->content; + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT, + &crmsg->purpose, &crmsg->signature, + &target->public_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid signature of the receipt\n"); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "The author of the original message is a local client." + " Sending receipt to the client\n"); +#endif + GNUNET_SERVER_notification_context_unicast (nc, author->client, + &crmsg->header, GNUNET_NO); + GNUNET_free (crmsg); + } + return GNUNET_OK; +} + + +/** + * Transmit a sync request to the peer. + * + * @param cls closure, NULL + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_sync_request_to_peer (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *m = buf; + size_t msg_size; + +#if DEBUG_CHAT_SERVICE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n"); +#endif + msg_size = sizeof (struct GNUNET_MessageHeader); + GNUNET_assert (size >= msg_size); + GNUNET_assert (NULL != buf); + m = buf; + m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST); + m->size = htons (msg_size); + return msg_size; +} + + +/** + * Method called whenever a peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of entries in atsi + */ +static void +peer_connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct ConnectedPeer *cp; + struct GNUNET_CORE_TransmitHandle *th; + + if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity))) + return; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer connected: %s\n", + GNUNET_i2s (peer)); + th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, + MAX_TRANSMIT_DELAY, peer, + sizeof (struct GNUNET_MessageHeader), + &transmit_sync_request_to_peer, NULL); + GNUNET_assert (NULL != th); + cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey); + if (NULL != cp) + { + GNUNET_break (0); + return; + } + cp = GNUNET_malloc (sizeof (struct ConnectedPeer)); + cp->pid = GNUNET_PEER_intern (peer); + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (connected_peers, + &peer->hashPubKey, cp, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); +} + + +/** + * Iterator to free peer entries. + * + * @param cls closure, unused + * @param key current key code + * @param value value in the hash map (peer entry) + * @return GNUNET_YES (we should continue to iterate) + */ +static int +clean_peer (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ConnectedPeer *cp; + const struct GNUNET_PeerIdentity *peer = + (const struct GNUNET_PeerIdentity *) key; + + cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey); + if (cp == NULL) + return GNUNET_YES; + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (connected_peers, + &peer->hashPubKey, cp)); + GNUNET_PEER_change_rc (cp->pid, -1); + GNUNET_free (cp); + return GNUNET_YES; +} + + +/** + * Method called whenever a peer disconnects. + * + * @param cls closure, not used + * @param peer peer identity this notification is about + */ +static void +peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + + if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity))) + return; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer disconnected: %s\n", + GNUNET_i2s (peer)); + clean_peer (NULL, (const GNUNET_HashCode *) peer, NULL); +} + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct AnonymousMessage *next_msg; + struct ChatClient *next_client; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n"); + if (NULL != core) + { + GNUNET_CORE_disconnect (core); + core = NULL; + } + if (NULL != nc) + { + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; + } + while (NULL != client_list_head) + { + next_client = client_list_head->next; + GNUNET_free (client_list_head->room); + GNUNET_free_non_null (client_list_head->member_info); + GNUNET_free (client_list_head); + client_list_head = next_client; + } + while (NULL != anonymous_list_head) + { + next_msg = anonymous_list_head->next; + GNUNET_free (anonymous_list_head); + anonymous_list_head = next_msg; + } + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &clean_peer, NULL); + GNUNET_CONTAINER_multihashmap_destroy (connected_peers); + connected_peers = NULL; +} + + +/** + * To be called on core init/fail. + * + * @param cls closure, NULL + * @param server handle to the server for this service + * @param my_identity the public identity of this peer + */ +static void +core_init (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n"); + me = my_identity; +} + + +/** + * Process chat requests. + * + * @param cls closure, NULL + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_join_request, NULL, + GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0}, + {&handle_transmit_request, NULL, + GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0}, + {&handle_acknowledge_request, NULL, + GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT, + sizeof (struct ConfirmationReceiptMessage)}, + {NULL, NULL, 0, 0} + }; + static const struct GNUNET_CORE_MessageHandler p2p_handlers[] = { + {&handle_p2p_join_notification, + GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0}, + {&handle_p2p_leave_notification, + GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION, + sizeof (struct P2PLeaveNotificationMessage)}, + {&handle_p2p_message_notification, + GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0}, + {&handle_p2p_sync_request, + GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST, + sizeof (struct GNUNET_MessageHeader)}, + {&handle_p2p_confirmation_receipt, + GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT, + sizeof (struct P2PConfirmationReceiptMessage)}, + {NULL, 0, 0} + }; + + GNUNET_log_setup ("gnunet-service-chat", +#if DEBUG_CHAT_SERVICE + "DEBUG", +#else + "WARNING", +#endif + NULL); + cfg = c; + nc = GNUNET_SERVER_notification_context_create (server, 16); + connected_peers = + GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT); + GNUNET_SERVER_add_handlers (server, handlers); + core = + GNUNET_CORE_connect (cfg, QUEUE_SIZE, NULL, &core_init, + &peer_connect_handler, &peer_disconnect_handler, + NULL, GNUNET_NO, NULL, GNUNET_NO, p2p_handlers); + GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, + NULL); +} + + +/** + * The main function for the chat service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "chat", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-service-chat.c */ diff --git a/src/chat/test_chat.c b/src/chat/test_chat.c new file mode 100644 index 0000000..fec5db0 --- /dev/null +++ b/src/chat/test_chat.c @@ -0,0 +1,586 @@ +/* + This file is part of GNUnet. + (C) 2005, 2006, 2007, 2008, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file chat/test_chat.c + * @brief base test case for the chat library + * @author Christian Grothoff + * @author Nathan Evans + * @author Vitaly Minko + * + * This test case serves as a base for simple chatting, anonymous chatting, + * authenticated chatting and acknowledgements test cases. Based on the + * executable being run the correct test case will be performed. Private + * chatting is covered by a separate test case since it requires 3 users. + */ + +#include "platform.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_chat_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on passing the test? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +struct Wanted +{ + struct GNUNET_CONTAINER_MetaData *meta; + + GNUNET_HashCode *sender; + + char *msg; + + const char *me; + + enum GNUNET_CHAT_MsgOptions opt; + + uint32_t sequence_number; + + struct GNUNET_TIME_Absolute timestamp; + + GNUNET_SCHEDULER_Task next_task; + + void *next_task_cls; + +}; + +static struct PeerContext p1; + +static struct PeerContext p2; + +static GNUNET_HashCode alice; + +static GNUNET_HashCode bob; + +static struct GNUNET_CHAT_Room *alice_room; + +static struct GNUNET_CHAT_Room *bob_room; + +static struct GNUNET_CONTAINER_MetaData *alice_meta; + +static struct GNUNET_CONTAINER_MetaData *bob_meta; + +static struct Wanted alice_wanted; + +static struct Wanted bob_wanted; + +static GNUNET_SCHEDULER_TaskIdentifier kill_task; + +static GNUNET_SCHEDULER_TaskIdentifier wait_task; + +static int err; + +static int is_ready; + +static int is_p2p; + +static int is_ackn; + +static int is_anon; + +static int is_auth; + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +abort_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (alice_room != NULL) + { + GNUNET_CHAT_leave_room (alice_room); + alice_room = NULL; + } + if (bob_room != NULL) + { + GNUNET_CHAT_leave_room (bob_room); + bob_room = NULL; + } + err = 1; +} + + +static void +timeout_kill (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Timed out, stopping the test.\n"); +#endif + kill_task = GNUNET_SCHEDULER_NO_TASK; + if (wait_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (wait_task); + wait_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_SCHEDULER_add_continuation (&abort_test, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static int +join_cb (void *cls) +{ + struct Wanted *want = cls; + +#if VERBOSE + printf ("%s has joined\n", want->me); +#endif + if (NULL != want->next_task) + GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); + return GNUNET_OK; +} + + +static int +member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, + enum GNUNET_CHAT_MsgOptions options) +{ + struct Wanted *want = cls; + GNUNET_HashCode sender; + +#if VERBOSE + printf ("%s - told that %s has %s\n", want->me, + member_info == + NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (member_info, + EXTRACTOR_METATYPE_TITLE), + member_info == NULL ? "left" : "joined"); +#endif + GNUNET_CRYPTO_hash (member_id, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &sender); + if ((0 == memcmp (&sender, want->sender, sizeof (GNUNET_HashCode))) && + (((member_info == NULL) && (want->meta == NULL)) || + ((member_info != NULL) && (want->meta != NULL) && + (GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta)))) && + (options == want->opt)) + { + if (NULL != want->next_task) + GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); + } + else + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (&abort_test, NULL); + } + return GNUNET_OK; +} + + +static int +receive_cb (void *cls, struct GNUNET_CHAT_Room *room, + const GNUNET_HashCode * sender, + const struct GNUNET_CONTAINER_MetaData *meta, const char *message, + struct GNUNET_TIME_Absolute timestamp, + enum GNUNET_CHAT_MsgOptions options) +{ + struct Wanted *want = cls; + +#if VERBOSE + printf ("%s - told that %s said %s\n", want->me, + meta == NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (meta, + EXTRACTOR_METATYPE_TITLE), + message); +#endif + if ((0 == strcmp (message, want->msg)) && + (((sender == NULL) && (want->sender == NULL)) || + ((sender != NULL) && (want->sender != NULL) && + (0 == memcmp (sender, want->sender, sizeof (GNUNET_HashCode))))) && + (GNUNET_CONTAINER_meta_data_test_equal (meta, want->meta)) && + (options == want->opt) && + /* Not == since the library sets the actual timestamp, so it may be + * slightly greater + */ + (timestamp.abs_value >= want->timestamp.abs_value)) + { + if (NULL != want->next_task) + GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); + } + else + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (&abort_test, NULL); + } + return GNUNET_OK; +} + + +static int +confirmation_cb (void *cls, struct GNUNET_CHAT_Room *room, + uint32_t orig_seq_number, + struct GNUNET_TIME_Absolute timestamp, + const GNUNET_HashCode * receiver) +{ + struct Wanted *want = cls; + +#if VERBOSE + printf ("%s - told that %s acknowledged message #%d\n", want->me, + GNUNET_CONTAINER_meta_data_get_by_type (want->meta, + EXTRACTOR_METATYPE_TITLE), + orig_seq_number); +#endif + if ((0 == memcmp (receiver, want->sender, sizeof (GNUNET_HashCode))) && + (orig_seq_number == want->sequence_number) && + (timestamp.abs_value >= want->timestamp.abs_value)) + { + if (NULL != want->next_task) + GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); + } + else + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (&abort_test, NULL); + } + return GNUNET_OK; +} + + +static void +wait_until_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_SCHEDULER_Task task = cls; + +#if VERBOSE + printf ("Waiting...\n"); +#endif + if (is_ready) + { + wait_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (task, NULL); + } + else + wait_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 50), + &wait_until_ready, task); +} + + +static void +disconnect_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Alice is leaving.\n"); +#endif + if (is_p2p) + stop_arm (&p2); + GNUNET_CHAT_leave_room (alice_room); + alice_room = NULL; + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; +} + + +static void +disconnect_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Bod is leaving.\n"); +#endif + alice_wanted.meta = NULL; + alice_wanted.sender = &bob; + alice_wanted.msg = NULL; + alice_wanted.opt = 0; + alice_wanted.next_task = &disconnect_alice; + alice_wanted.next_task_cls = NULL; + GNUNET_CHAT_leave_room (bob_room); + bob_room = NULL; +} + + +static void +set_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + is_ready = GNUNET_YES; +} + + +static void +send_to_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Bob says 'Hi!'\n"); +#endif + + alice_wanted.meta = bob_meta; + alice_wanted.sender = &bob; + alice_wanted.msg = "Hi Alice!"; + alice_wanted.opt = GNUNET_CHAT_MSG_OPTION_NONE; + alice_wanted.timestamp = GNUNET_TIME_absolute_get (); + alice_wanted.next_task = &disconnect_bob; + alice_wanted.next_task_cls = NULL; + GNUNET_CHAT_send_message (bob_room, "Hi Alice!", GNUNET_CHAT_MSG_OPTION_NONE, + NULL, NULL); +} + + +static void +send_to_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + enum GNUNET_CHAT_MsgOptions options; + uint32_t *seq = NULL; + +#if VERBOSE + printf ("Alice says 'Hi!'\n"); +#endif + if (is_ackn) + { + options = GNUNET_CHAT_MSG_ACKNOWLEDGED; + alice_wanted.meta = bob_meta; + alice_wanted.sender = &bob; + alice_wanted.timestamp = GNUNET_TIME_absolute_get (); + alice_wanted.next_task = &disconnect_bob; + alice_wanted.next_task_cls = NULL; + bob_wanted.meta = alice_meta; + bob_wanted.sender = &alice; + bob_wanted.next_task = NULL; + seq = &(alice_wanted.sequence_number); + } + else if (is_anon) + { + options = GNUNET_CHAT_MSG_ANONYMOUS; + bob_wanted.meta = NULL; + bob_wanted.sender = NULL; + bob_wanted.next_task = &disconnect_bob; + } + else if (is_auth) + { + options = GNUNET_CHAT_MSG_AUTHENTICATED; + bob_wanted.meta = alice_meta; + bob_wanted.sender = &alice; + bob_wanted.next_task = &disconnect_bob; + } + else + { + options = GNUNET_CHAT_MSG_OPTION_NONE; + bob_wanted.meta = alice_meta; + bob_wanted.sender = &alice; + bob_wanted.next_task = &send_to_alice; + } + bob_wanted.msg = "Hi Bob!"; + bob_wanted.opt = options; + bob_wanted.timestamp = GNUNET_TIME_absolute_get (); + bob_wanted.next_task_cls = NULL; + GNUNET_CHAT_send_message (alice_room, "Hi Bob!", options, NULL, seq); +} + + +static void +prepare_for_alice_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + bob_wanted.meta = alice_meta; + bob_wanted.sender = &alice; + bob_wanted.msg = NULL; + bob_wanted.opt = -1; + bob_wanted.next_task = &set_ready; + bob_wanted.next_task_cls = NULL; +} + + +static void +join_bob_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Bob joining\n"); +#endif + alice_wanted.meta = bob_meta; + alice_wanted.sender = &bob; + alice_wanted.msg = NULL; + alice_wanted.opt = -1; + alice_wanted.next_task = &wait_until_ready; + alice_wanted.next_task_cls = &send_to_bob; + bob_wanted.next_task = &prepare_for_alice_task; + bob_wanted.next_task_cls = NULL; + is_ready = GNUNET_NO; + bob_room = + GNUNET_CHAT_join_room (is_p2p ? p2.cfg : p1.cfg, "bob", bob_meta, "test", + -1, &join_cb, &bob_wanted, &receive_cb, + &bob_wanted, &member_list_cb, &bob_wanted, + &confirmation_cb, &bob_wanted, &bob); + if (NULL == bob_room) + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_CHAT_leave_room (alice_room); + alice_room = NULL; + err = 1; + } +} + + +static void +join_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Alice joining\n"); +#endif + alice_wanted.next_task = &join_bob_task; + alice_wanted.next_task_cls = NULL; + alice_room = + GNUNET_CHAT_join_room (p1.cfg, "alice", alice_meta, "test", -1, &join_cb, + &alice_wanted, &receive_cb, &alice_wanted, + &member_list_cb, &alice_wanted, &confirmation_cb, + &alice_wanted, &alice); + if (NULL == alice_room) + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + err = 1; + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + if (is_p2p) + { + setup_peer (&p1, "test_chat_peer1.conf"); + setup_peer (&p2, "test_chat_peer2.conf"); + } + else + setup_peer (&p1, "test_chat_data.conf"); + + memset (&alice_wanted, 0, sizeof (struct Wanted)); + memset (&bob_wanted, 0, sizeof (struct Wanted)); + alice_wanted.me = "Alice"; + bob_wanted.me = "Bob"; + alice_meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (alice_meta, "", + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "Alice", strlen ("Alice") + 1); + bob_meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (bob_meta, "", + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "Bob", strlen ("Bob") + 1); + kill_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill, NULL); + GNUNET_SCHEDULER_add_now (&join_alice_task, NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-chat", + "-c", + "test_chat_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_chat", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + if (strstr (argv[0], "p2p") != NULL) + { + is_p2p = GNUNET_YES; + } + if (strstr (argv[0], "acknowledgment") != NULL) + { + is_ackn = GNUNET_YES; + } + else if (strstr (argv[0], "anonymous") != NULL) + { + is_anon = GNUNET_YES; + } + else if (strstr (argv[0], "authentication") != NULL) + { + is_auth = GNUNET_YES; + } + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-chat", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_CONTAINER_meta_data_destroy (alice_meta); + GNUNET_CONTAINER_meta_data_destroy (bob_meta); + if (is_p2p) + { + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-1/"); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-2/"); + } + else + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat/"); + return err; +} + +/* end of test_chat.c */ diff --git a/src/chat/test_chat_data.conf b/src/chat/test_chat_data.conf new file mode 100644 index 0000000..3052a4f --- /dev/null +++ b/src/chat/test_chat_data.conf @@ -0,0 +1,56 @@ +[PATHS] +SERVICEHOME = /tmp/gnunet-test-chat/ +DEFAULTCONFIG = test_chat_data.conf + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[resolver] +PORT = 42464 +HOSTNAME = localhost + +[transport] +PORT = 42465 +PLUGINS = + +[arm] +PORT = 42466 +HOSTNAME = localhost +DEFAULTSERVICES = core chat + +[peerinfo] +PORT = 42469 +HOSTNAME = localhost + +[core] +PORT = 42470 +HOSTNAME = localhost + +[chat] +PORT = 42471 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-chat + +[testing] +WEAKRANDOM = YES + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[dns] +AUTOSTART = NO + + + +[nse] +AUTOSTART = NO + + diff --git a/src/chat/test_chat_peer1.conf b/src/chat/test_chat_peer1.conf new file mode 100644 index 0000000..73280da --- /dev/null +++ b/src/chat/test_chat_peer1.conf @@ -0,0 +1,95 @@ +[PATHS] +SERVICEHOME = /tmp/gnunet-test-chat-peer-1/ +DEFAULTCONFIG = test_chat_peer1.conf + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[hostlist] +HTTPPORT = 31000 +OPTIONS = -p + +[resolver] +PORT = 31001 +HOSTNAME = localhost +UNIXPATH = /tmp/gnunet-chat-p1-service-resolver.sock + +[transport] +PORT = 31002 +UNIXPATH = /tmp/gnunet-chat-p1-service-transport.sock +PLUGINS = tcp +#BINARY = /home/grothoff/bin/gnunet-service-transport +#PREFIX = valgrind + +[transport-tcp] +PORT = 31003 + +[arm] +PORT = 31004 +UNIXPATH = /tmp/gnunet-chat-p1-service-arm.sock +HOSTNAME = localhost +DEFAULTSERVICES = resolver transport core topology hostlist statistics chat + +[core] +PORT = 31005 +UNIXPATH = /tmp/gnunet-chat-p1-service-core.sock +HOSTNAME = localhost + +[topology] +MINIMUM-FRIENDS = 0 +FRIENDS-ONLY = NO +AUTOCONNECT = YES +TARGET-CONNECTION-COUNT = 16 +FRIENDS = $SERVICEHOME/friends +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-topology + +[peerinfo] +PORT = 31006 +UNIXPATH = /tmp/gnunet-chat-p1-service-peerinfo.sock +HOSTNAME = localhost + +[statistics] +PORT = 31007 +HOSTNAME = localhost +UNIXPATH = /tmp/gnunet-chat-p1-service-statistics.sock + +[chat] +PORT = 31008 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-chat + +[testing] +WEAKRANDOM = YES + +[fs] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[dht] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[ats] +PORT = 31971 +UNIXPATH = /tmp/gnunet-chat-p1-service-ats.sock diff --git a/src/chat/test_chat_peer2.conf b/src/chat/test_chat_peer2.conf new file mode 100644 index 0000000..00808b5 --- /dev/null +++ b/src/chat/test_chat_peer2.conf @@ -0,0 +1,97 @@ +[PATHS] +SERVICEHOME = /tmp/gnunet-test-chat-peer-2/ +DEFAULTCONFIG = test_chat_peer2.conf + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[hostlist] +SERVERS = http://localhost:31000/ +OPTIONS = -b + +[resolver] +PORT = 32001 +HOSTNAME = localhost +UNIXPATH = /tmp/gnunet-chat-p2-service-resolver.sock + +[transport] +PORT = 32002 +UNIXPATH = /tmp/gnunet-chat-p2-service-transport.sock +PLUGINS = tcp +#BINARY = /home/grothoff/bin/gnunet-service-transport +#PREFIX = valgrind + +[transport-tcp] +PORT = 32003 + +[arm] +PORT = 32004 +UNIXPATH = /tmp/gnunet-chat-p2-service-arm.sock +HOSTNAME = localhost +DEFAULTSERVICES = resolver transport core topology hostlist statistics chat + +[core] +PORT = 32005 +UNIXPATH = /tmp/gnunet-chat-p2-service-core.sock +HOSTNAME = localhost + +[topology] +MINIMUM-FRIENDS = 0 +FRIENDS-ONLY = NO +AUTOCONNECT = YES +TARGET-CONNECTION-COUNT = 16 +FRIENDS = $SERVICEHOME/friends +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-topology + +[peerinfo] +PORT = 32006 +UNIXPATH = /tmp/gnunet-chat-p2-service-peerinfo.sock +HOSTNAME = localhost + +[statistics] +PORT = 32007 +HOSTNAME = localhost +UNIXPATH = /tmp/gnunet-chat-p2-service-statistics.sock + +[chat] +PORT = 32008 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-chat + +[testing] +WEAKRANDOM = YES + +[fs] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[dht] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[ats] +PORT = 32971 +UNIXPATH = /tmp/gnunet-chat-p2-service-ats.sock + diff --git a/src/chat/test_chat_peer3.conf b/src/chat/test_chat_peer3.conf new file mode 100644 index 0000000..a394523 --- /dev/null +++ b/src/chat/test_chat_peer3.conf @@ -0,0 +1,96 @@ +[PATHS] +SERVICEHOME = /tmp/gnunet-test-chat-peer-3/ +DEFAULTCONFIG = test_chat_peer3.conf + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[hostlist] +SERVERS = http://localhost:31000/ +OPTIONS = -b + +[resolver] +PORT = 33001 +HOSTNAME = localhost +UNIXPATH = /tmp/gnunet-chat-p3-service-resolver.sock + +[transport] +PORT = 33002 +UNIXPATH = /tmp/gnunet-chat-p3-service-transport.sock +PLUGINS = tcp +#BINARY = /home/grothoff/bin/gnunet-service-transport +#PREFIX = valgrind + +[transport-tcp] +PORT = 33003 + +[arm] +PORT = 33004 +UNIXPATH = /tmp/gnunet-chat-p3-service-arm.sock +HOSTNAME = localhost +DEFAULTSERVICES = resolver transport core topology hostlist statistics chat + +[core] +PORT = 33005 +UNIXPATH = /tmp/gnunet-chat-p3-service-core.sock +HOSTNAME = localhost + +[topology] +MINIMUM-FRIENDS = 0 +FRIENDS-ONLY = NO +AUTOCONNECT = YES +TARGET-CONNECTION-COUNT = 16 +FRIENDS = $SERVICEHOME/friends +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-topology + +[peerinfo] +PORT = 33006 +UNIXPATH = /tmp/gnunet-chat-p3-service-peerinfo.sock +HOSTNAME = localhost + +[statistics] +PORT = 33007 +HOSTNAME = localhost +UNIXPATH = /tmp/gnunet-chat-p3-service-statistics.sock + +[chat] +PORT = 33008 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-chat + +[testing] +WEAKRANDOM = YES + +[fs] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[dht] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[dns] +AUTOSTART = NO + + + +[nse] +AUTOSTART = NO + + diff --git a/src/chat/test_chat_private.c b/src/chat/test_chat_private.c new file mode 100644 index 0000000..cbc9065 --- /dev/null +++ b/src/chat/test_chat_private.c @@ -0,0 +1,654 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file chat/test_chat_private.c + * @brief testcase for private chatting + * @author Vitaly Minko + */ + +#include "platform.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_chat_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on passing the test? + */ +#define KILL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long until we give up on receiving somebody else's private message? + */ +#define PM_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +struct Wanted +{ + struct GNUNET_CONTAINER_MetaData *meta; + + GNUNET_HashCode *sender; + + /** + * Alternative meta/sender is used when we expect join/leave notification + * from two peers and don't know which one will come first. + */ + struct GNUNET_CONTAINER_MetaData *meta2; + + GNUNET_HashCode *sender2; + + char *msg; + + const char *me; + + enum GNUNET_CHAT_MsgOptions opt; + + struct GNUNET_TIME_Absolute timestamp; + + GNUNET_SCHEDULER_Task next_task; + + void *next_task_cls; + +}; + +static struct PeerContext p1; + +static struct PeerContext p2; + +static struct PeerContext p3; + +static GNUNET_HashCode alice; + +static GNUNET_HashCode bob; + +static GNUNET_HashCode carol; + +static struct GNUNET_CHAT_Room *alice_room; + +static struct GNUNET_CHAT_Room *bob_room; + +static struct GNUNET_CHAT_Room *carol_room; + +static struct GNUNET_CONTAINER_MetaData *alice_meta; + +static struct GNUNET_CONTAINER_MetaData *bob_meta; + +static struct GNUNET_CONTAINER_MetaData *carol_meta; + +static struct Wanted alice_wanted; + +static struct Wanted bob_wanted; + +static struct Wanted carol_wanted; + +static GNUNET_SCHEDULER_TaskIdentifier kill_task; + +static GNUNET_SCHEDULER_TaskIdentifier finish_task; + +static GNUNET_SCHEDULER_TaskIdentifier wait_task; + +static int err; + +static int alice_ready; + +static int bob_ready; + +static int is_p2p; + +struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *bob_public_key = NULL; + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +abort_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (alice_room != NULL) + { + GNUNET_CHAT_leave_room (alice_room); + alice_room = NULL; + } + if (bob_room != NULL) + { + GNUNET_CHAT_leave_room (bob_room); + bob_room = NULL; + } + if (carol_room != NULL) + { + GNUNET_CHAT_leave_room (carol_room); + carol_room = NULL; + } + err = 1; +} + + +static void +timeout_kill (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Timed out, stopping the test.\n"); +#endif + kill_task = GNUNET_SCHEDULER_NO_TASK; + if (wait_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (wait_task); + wait_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_SCHEDULER_add_continuation (&abort_test, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static int +join_cb (void *cls) +{ + struct Wanted *want = cls; + +#if VERBOSE + printf ("%s has joined\n", want->me); +#endif + if (NULL != want->next_task) + GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); + return GNUNET_OK; +} + + +static int +member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, + enum GNUNET_CHAT_MsgOptions options) +{ + struct Wanted *want = cls; + GNUNET_HashCode sender; + +#if VERBOSE + printf ("%s - told that %s has %s\n", want->me, + member_info == + NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (member_info, + EXTRACTOR_METATYPE_TITLE), + member_info == NULL ? "left" : "joined"); +#endif + GNUNET_CRYPTO_hash (member_id, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &sender); + /* entertain both primary and an alternative sender/meta */ + if (((0 == memcmp (&sender, want->sender, sizeof (GNUNET_HashCode))) || + ((want->sender2 != NULL) && + (0 == memcmp (&sender, want->sender2, sizeof (GNUNET_HashCode))))) && + (((member_info == NULL) && (want->meta == NULL)) || + ((member_info != NULL) && + (((want->meta != NULL) && + GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta)) || + ((want->meta2 != NULL) && + GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta2))))) + && (options == want->opt)) + { + /* remember Bob's public key, we need it to send private message */ + if (NULL == bob_public_key && + (0 == memcmp (&bob, want->sender, sizeof (GNUNET_HashCode)))) + bob_public_key = + GNUNET_memdup (member_id, + sizeof (struct + GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + if (want->sender2 != NULL) + { + /* flush alternative sender */ + if (0 == memcmp (&sender, want->sender, sizeof (GNUNET_HashCode))) + { + want->sender = want->sender2; + want->meta = want->meta2; + } + want->sender2 = NULL; + want->meta2 = NULL; + } + else if (NULL != want->next_task) + GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); + } + else + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (&abort_test, NULL); + } + return GNUNET_OK; +} + + +static int +receive_cb (void *cls, struct GNUNET_CHAT_Room *room, + const GNUNET_HashCode * sender, + const struct GNUNET_CONTAINER_MetaData *meta, const char *message, + struct GNUNET_TIME_Absolute timestamp, + enum GNUNET_CHAT_MsgOptions options) +{ + struct Wanted *want = cls; + +#if VERBOSE + printf ("%s - told that %s said '%s'\n", want->me, + meta == NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (meta, + EXTRACTOR_METATYPE_TITLE), + message); +#endif + + if ((want->msg != NULL) && (0 == strcmp (message, want->msg)) && + (((sender == NULL) && (want->sender == NULL)) || + ((sender != NULL) && (want->sender != NULL) && + (0 == memcmp (sender, want->sender, sizeof (GNUNET_HashCode))))) && + (GNUNET_CONTAINER_meta_data_test_equal (meta, want->meta)) && + (options == want->opt) && + /* Not == since the library sets the actual timestamp, so it may be + * slightly greater + */ + (timestamp.abs_value >= want->timestamp.abs_value)) + { + if (NULL != want->next_task) + GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); + } + else + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_cancel (finish_task); + finish_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (&abort_test, NULL); + } + return GNUNET_OK; +} + + +static void +wait_until_all_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_SCHEDULER_Task task = cls; + +#if VERBOSE + printf ("Waiting...\n"); +#endif + if (alice_ready && bob_ready) + { + wait_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (task, NULL); + } + else + wait_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 5000), + &wait_until_all_ready, task); +} + + +static void +set_alice_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + alice_ready = GNUNET_YES; +} + + +static void +set_bob_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + bob_ready = GNUNET_YES; +} + + +static void +disconnect_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Alice is leaving.\n"); +#endif + if (is_p2p) + stop_arm (&p2); + GNUNET_CHAT_leave_room (alice_room); + alice_room = NULL; + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; +} + + +static void +disconnect_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Bod is leaving.\n"); +#endif + if (is_p2p) + stop_arm (&p3); + alice_wanted.meta = NULL; + alice_wanted.sender = &bob; + alice_wanted.msg = NULL; + alice_wanted.opt = 0; + alice_wanted.next_task = &disconnect_alice; + alice_wanted.next_task_cls = NULL; + GNUNET_CHAT_leave_room (bob_room); + bob_room = NULL; +} + + +static void +disconnect_carol (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Carol is leaving.\n"); +#endif + alice_wanted.meta = NULL; + alice_wanted.sender = &carol; + alice_wanted.msg = NULL; + alice_wanted.opt = 0; + alice_wanted.next_task = &set_alice_ready; + alice_wanted.next_task_cls = NULL; + alice_ready = GNUNET_NO; + bob_wanted.meta = NULL; + bob_wanted.sender = &carol; + bob_wanted.msg = NULL; + bob_wanted.opt = 0; + bob_wanted.next_task = &wait_until_all_ready; + bob_wanted.next_task_cls = &disconnect_bob; + bob_ready = GNUNET_YES; + GNUNET_CHAT_leave_room (carol_room); + carol_room = NULL; +} + + +static void +send_from_alice_to_bob (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + uint32_t seq; + +#if VERBOSE + printf ("Alice says 'Hi!' to Bob\n"); +#endif + alice_ready = GNUNET_YES; + bob_ready = GNUNET_NO; + bob_wanted.meta = alice_meta; + bob_wanted.sender = &alice; + bob_wanted.msg = "Hi Bob!"; + bob_wanted.opt = GNUNET_CHAT_MSG_PRIVATE; + bob_wanted.next_task = &set_bob_ready; + bob_wanted.next_task_cls = NULL; + /* Carol should not receive this message */ + carol_wanted.meta = NULL; + carol_wanted.sender = NULL; + carol_wanted.msg = NULL; + carol_wanted.opt = 0; + carol_wanted.next_task = NULL; + carol_wanted.next_task_cls = NULL; + GNUNET_CHAT_send_message (alice_room, "Hi Bob!", GNUNET_CHAT_MSG_PRIVATE, + bob_public_key, &seq); + finish_task = + GNUNET_SCHEDULER_add_delayed (PM_TIMEOUT, &wait_until_all_ready, + &disconnect_carol); +} + + +static void +prepare_bob_for_alice_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + bob_wanted.meta = alice_meta; + bob_wanted.sender = &alice; + bob_wanted.msg = NULL; + bob_wanted.opt = -1; + bob_wanted.next_task = &set_bob_ready; + bob_wanted.next_task_cls = NULL; +} + + +static void +prepare_carol_for_alice_and_bob_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext + *tc) +{ + carol_wanted.meta = alice_meta; + carol_wanted.sender = &alice; + /* set alternative meta/sender since we don't know from which peer + * notification will come first */ + carol_wanted.meta2 = bob_meta; + carol_wanted.sender2 = &bob; + carol_wanted.msg = NULL; + carol_wanted.opt = -1; + carol_wanted.next_task = &wait_until_all_ready; + carol_wanted.next_task_cls = &send_from_alice_to_bob; +} + + +static void +join_carol_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Carol joining\n"); +#endif + alice_wanted.meta = carol_meta; + alice_wanted.sender = &carol; + alice_wanted.msg = NULL; + alice_wanted.opt = -1; + alice_wanted.next_task = &set_alice_ready; + alice_wanted.next_task_cls = NULL; + alice_ready = GNUNET_NO; + bob_wanted.meta = carol_meta; + bob_wanted.sender = &carol; + bob_wanted.msg = NULL; + bob_wanted.opt = -1; + bob_wanted.next_task = &set_bob_ready; + bob_wanted.next_task_cls = NULL; + bob_ready = GNUNET_NO; + carol_wanted.next_task = &prepare_carol_for_alice_and_bob_task; + carol_wanted.next_task_cls = NULL; + carol_room = + GNUNET_CHAT_join_room (is_p2p ? p3.cfg : p1.cfg, "carol", carol_meta, + "test", -1, &join_cb, &carol_wanted, &receive_cb, + &carol_wanted, &member_list_cb, &carol_wanted, + NULL, NULL, &carol); + if (NULL == carol_room) + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_CHAT_leave_room (alice_room); + alice_room = NULL; + GNUNET_CHAT_leave_room (bob_room); + bob_room = NULL; + err = 1; + } +} + + +static void +join_bob_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Bob joining\n"); +#endif + alice_wanted.meta = bob_meta; + alice_wanted.sender = &bob; + alice_wanted.msg = NULL; + alice_wanted.opt = -1; + alice_wanted.next_task = &wait_until_all_ready; + alice_wanted.next_task_cls = &join_carol_task; + alice_ready = GNUNET_YES; + bob_wanted.next_task = &prepare_bob_for_alice_task; + bob_wanted.next_task_cls = NULL; + bob_ready = GNUNET_NO; + bob_room = + GNUNET_CHAT_join_room (is_p2p ? p2.cfg : p1.cfg, "bob", bob_meta, "test", + -1, &join_cb, &bob_wanted, &receive_cb, + &bob_wanted, &member_list_cb, &bob_wanted, NULL, + NULL, &bob); + if (NULL == bob_room) + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_CHAT_leave_room (alice_room); + alice_room = NULL; + err = 1; + } +} + + +static void +join_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + printf ("Alice joining\n"); +#endif + alice_wanted.next_task = &join_bob_task; + alice_wanted.next_task_cls = NULL; + alice_room = + GNUNET_CHAT_join_room (p1.cfg, "alice", alice_meta, "test", -1, &join_cb, + &alice_wanted, &receive_cb, &alice_wanted, + &member_list_cb, &alice_wanted, NULL, NULL, + &alice); + if (NULL == alice_room) + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + err = 1; + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + if (is_p2p) + { + setup_peer (&p1, "test_chat_peer1.conf"); + setup_peer (&p2, "test_chat_peer2.conf"); + setup_peer (&p3, "test_chat_peer3.conf"); + } + else + setup_peer (&p1, "test_chat_data.conf"); + + memset (&alice_wanted, 0, sizeof (struct Wanted)); + memset (&bob_wanted, 0, sizeof (struct Wanted)); + memset (&carol_wanted, 0, sizeof (struct Wanted)); + alice_wanted.me = "Alice"; + bob_wanted.me = "Bob"; + carol_wanted.me = "Carol"; + alice_meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (alice_meta, "", + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "Alice", strlen ("Alice") + 1); + bob_meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (bob_meta, "", + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "Bob", strlen ("Bob") + 1); + carol_meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (carol_meta, "", + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "Carol", strlen ("Carol") + 1); + kill_task = GNUNET_SCHEDULER_add_delayed (KILL_TIMEOUT, &timeout_kill, NULL); + GNUNET_SCHEDULER_add_now (&join_alice_task, NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-chat", + "-c", + "test_chat_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_chat", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + if (strstr (argv[0], "p2p") != NULL) + { + is_p2p = GNUNET_YES; + } + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-chat", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_CONTAINER_meta_data_destroy (alice_meta); + GNUNET_CONTAINER_meta_data_destroy (bob_meta); + GNUNET_CONTAINER_meta_data_destroy (carol_meta); + if (is_p2p) + { + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-1/"); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-2/"); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-3/"); + } + else + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat/"); + return err; +} + +/* end of test_chat_private.c */ diff --git a/src/core/Makefile.am b/src/core/Makefile.am new file mode 100644 index 0000000..ad9bddc --- /dev/null +++ b/src/core/Makefile.am @@ -0,0 +1,137 @@ +INCLUDES = -I$(top_srcdir)/src/include + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + core.conf + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + + +lib_LTLIBRARIES = \ + libgnunetcore.la + +libgnunetcore_la_SOURCES = \ + core_api.c core.h \ + core_api_iterate_peers.c +libgnunetcore_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) +libgnunetcore_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + + +bin_PROGRAMS = \ + gnunet-service-core \ + gnunet-core-list-connections + +gnunet_service_core_SOURCES = \ + gnunet-service-core.c gnunet-service-core.h \ + gnunet-service-core_clients.c gnunet-service-core_clients.h \ + gnunet-service-core_neighbours.c gnunet-service-core_neighbours.h \ + gnunet-service-core_kx.c gnunet-service-core_kx.h \ + gnunet-service-core_sessions.c gnunet-service-core_sessions.h \ + gnunet-service-core_typemap.c gnunet-service-core_typemap.h +gnunet_service_core_LDADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) -lz + + +gnunet_core_list_connections_SOURCES = \ + gnunet-core-list-connections.c +gnunet_core_list_connections_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la +gnunet_core_list_connections_DEPENDENCIES = \ + libgnunetcore.la + +check_PROGRAMS = \ + test_core_api_start_only \ + test_core_api \ + test_core_api_reliability \ + test_core_quota_compliance_symmetric \ + test_core_quota_compliance_asymmetric_send_limited \ + test_core_quota_compliance_asymmetric_recv_limited \ + test_core_api_send_to_self + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_core_api_SOURCES = \ + test_core_api.c +test_core_api_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_core_api_reliability_SOURCES = \ + test_core_api_reliability.c +test_core_api_reliability_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_core_api_send_to_self_SOURCES = \ + test_core_api_send_to_self.c +test_core_api_send_to_self_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_core_api_start_only_SOURCES = \ + test_core_api_start_only.c +test_core_api_start_only_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_core_quota_compliance_symmetric_SOURCES = \ + test_core_quota_compliance.c +test_core_quota_compliance_symmetric_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la + +test_core_quota_compliance_asymmetric_send_limited_SOURCES = \ + test_core_quota_compliance.c +test_core_quota_compliance_asymmetric_send_limited_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la + +test_core_quota_compliance_asymmetric_recv_limited_SOURCES = \ + test_core_quota_compliance.c +test_core_quota_compliance_asymmetric_recv_limited_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la + +EXTRA_DIST = \ + test_core_defaults.conf \ + test_core_api_data.conf \ + test_core_api_peer1.conf \ + test_core_api_peer2.conf \ + test_core_api_send_to_self.conf \ + test_core_quota_asymmetric_recv_limited_peer1.conf \ + test_core_quota_asymmetric_recv_limited_peer2.conf \ + test_core_quota_asymmetric_send_limit_peer1.conf \ + test_core_quota_asymmetric_send_limit_peer2.conf \ + test_core_quota_peer1.conf \ + test_core_quota_peer2.conf diff --git a/src/core/Makefile.in b/src/core/Makefile.in new file mode 100644 index 0000000..42177b4 --- /dev/null +++ b/src/core/Makefile.in @@ -0,0 +1,1081 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-core$(EXEEXT) \ + gnunet-core-list-connections$(EXEEXT) +check_PROGRAMS = test_core_api_start_only$(EXEEXT) \ + test_core_api$(EXEEXT) test_core_api_reliability$(EXEEXT) \ + test_core_quota_compliance_symmetric$(EXEEXT) \ + test_core_quota_compliance_asymmetric_send_limited$(EXEEXT) \ + test_core_quota_compliance_asymmetric_recv_limited$(EXEEXT) \ + test_core_api_send_to_self$(EXEEXT) +subdir = src/core +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/core.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = core.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunetcore_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgnunetcore_la_OBJECTS = core_api.lo core_api_iterate_peers.lo +libgnunetcore_la_OBJECTS = $(am_libgnunetcore_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetcore_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetcore_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_core_list_connections_OBJECTS = \ + gnunet-core-list-connections.$(OBJEXT) +gnunet_core_list_connections_OBJECTS = \ + $(am_gnunet_core_list_connections_OBJECTS) +am_gnunet_service_core_OBJECTS = gnunet-service-core.$(OBJEXT) \ + gnunet-service-core_clients.$(OBJEXT) \ + gnunet-service-core_neighbours.$(OBJEXT) \ + gnunet-service-core_kx.$(OBJEXT) \ + gnunet-service-core_sessions.$(OBJEXT) \ + gnunet-service-core_typemap.$(OBJEXT) +gnunet_service_core_OBJECTS = $(am_gnunet_service_core_OBJECTS) +gnunet_service_core_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_test_core_api_OBJECTS = test_core_api.$(OBJEXT) +test_core_api_OBJECTS = $(am_test_core_api_OBJECTS) +test_core_api_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_core_api_reliability_OBJECTS = \ + test_core_api_reliability.$(OBJEXT) +test_core_api_reliability_OBJECTS = \ + $(am_test_core_api_reliability_OBJECTS) +test_core_api_reliability_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_core_api_send_to_self_OBJECTS = \ + test_core_api_send_to_self.$(OBJEXT) +test_core_api_send_to_self_OBJECTS = \ + $(am_test_core_api_send_to_self_OBJECTS) +test_core_api_send_to_self_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_core_api_start_only_OBJECTS = \ + test_core_api_start_only.$(OBJEXT) +test_core_api_start_only_OBJECTS = \ + $(am_test_core_api_start_only_OBJECTS) +test_core_api_start_only_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_core_quota_compliance_asymmetric_recv_limited_OBJECTS = \ + test_core_quota_compliance.$(OBJEXT) +test_core_quota_compliance_asymmetric_recv_limited_OBJECTS = $(am_test_core_quota_compliance_asymmetric_recv_limited_OBJECTS) +test_core_quota_compliance_asymmetric_recv_limited_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la +am_test_core_quota_compliance_asymmetric_send_limited_OBJECTS = \ + test_core_quota_compliance.$(OBJEXT) +test_core_quota_compliance_asymmetric_send_limited_OBJECTS = $(am_test_core_quota_compliance_asymmetric_send_limited_OBJECTS) +test_core_quota_compliance_asymmetric_send_limited_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la +am_test_core_quota_compliance_symmetric_OBJECTS = \ + test_core_quota_compliance.$(OBJEXT) +test_core_quota_compliance_symmetric_OBJECTS = \ + $(am_test_core_quota_compliance_symmetric_OBJECTS) +test_core_quota_compliance_symmetric_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetcore_la_SOURCES) \ + $(gnunet_core_list_connections_SOURCES) \ + $(gnunet_service_core_SOURCES) $(test_core_api_SOURCES) \ + $(test_core_api_reliability_SOURCES) \ + $(test_core_api_send_to_self_SOURCES) \ + $(test_core_api_start_only_SOURCES) \ + $(test_core_quota_compliance_asymmetric_recv_limited_SOURCES) \ + $(test_core_quota_compliance_asymmetric_send_limited_SOURCES) \ + $(test_core_quota_compliance_symmetric_SOURCES) +DIST_SOURCES = $(libgnunetcore_la_SOURCES) \ + $(gnunet_core_list_connections_SOURCES) \ + $(gnunet_service_core_SOURCES) $(test_core_api_SOURCES) \ + $(test_core_api_reliability_SOURCES) \ + $(test_core_api_send_to_self_SOURCES) \ + $(test_core_api_start_only_SOURCES) \ + $(test_core_quota_compliance_asymmetric_recv_limited_SOURCES) \ + $(test_core_quota_compliance_asymmetric_send_limited_SOURCES) \ + $(test_core_quota_compliance_symmetric_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + core.conf + +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +lib_LTLIBRARIES = \ + libgnunetcore.la + +libgnunetcore_la_SOURCES = \ + core_api.c core.h \ + core_api_iterate_peers.c + +libgnunetcore_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) + +libgnunetcore_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +gnunet_service_core_SOURCES = \ + gnunet-service-core.c gnunet-service-core.h \ + gnunet-service-core_clients.c gnunet-service-core_clients.h \ + gnunet-service-core_neighbours.c gnunet-service-core_neighbours.h \ + gnunet-service-core_kx.c gnunet-service-core_kx.h \ + gnunet-service-core_sessions.c gnunet-service-core_sessions.h \ + gnunet-service-core_typemap.c gnunet-service-core_typemap.h + +gnunet_service_core_LDADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) -lz + +gnunet_core_list_connections_SOURCES = \ + gnunet-core-list-connections.c + +gnunet_core_list_connections_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_core_list_connections_DEPENDENCIES = \ + libgnunetcore.la + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_core_api_SOURCES = \ + test_core_api.c + +test_core_api_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_core_api_reliability_SOURCES = \ + test_core_api_reliability.c + +test_core_api_reliability_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_core_api_send_to_self_SOURCES = \ + test_core_api_send_to_self.c + +test_core_api_send_to_self_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_core_api_start_only_SOURCES = \ + test_core_api_start_only.c + +test_core_api_start_only_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_core_quota_compliance_symmetric_SOURCES = \ + test_core_quota_compliance.c + +test_core_quota_compliance_symmetric_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la + +test_core_quota_compliance_asymmetric_send_limited_SOURCES = \ + test_core_quota_compliance.c + +test_core_quota_compliance_asymmetric_send_limited_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la + +test_core_quota_compliance_asymmetric_recv_limited_SOURCES = \ + test_core_quota_compliance.c + +test_core_quota_compliance_asymmetric_recv_limited_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la + +EXTRA_DIST = \ + test_core_defaults.conf \ + test_core_api_data.conf \ + test_core_api_peer1.conf \ + test_core_api_peer2.conf \ + test_core_api_send_to_self.conf \ + test_core_quota_asymmetric_recv_limited_peer1.conf \ + test_core_quota_asymmetric_recv_limited_peer2.conf \ + test_core_quota_asymmetric_send_limit_peer1.conf \ + test_core_quota_asymmetric_send_limit_peer2.conf \ + test_core_quota_peer1.conf \ + test_core_quota_peer2.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/core/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/core/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +core.conf: $(top_builddir)/config.status $(srcdir)/core.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetcore.la: $(libgnunetcore_la_OBJECTS) $(libgnunetcore_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetcore_la_LINK) -rpath $(libdir) $(libgnunetcore_la_OBJECTS) $(libgnunetcore_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-core-list-connections$(EXEEXT): $(gnunet_core_list_connections_OBJECTS) $(gnunet_core_list_connections_DEPENDENCIES) + @rm -f gnunet-core-list-connections$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_core_list_connections_OBJECTS) $(gnunet_core_list_connections_LDADD) $(LIBS) +gnunet-service-core$(EXEEXT): $(gnunet_service_core_OBJECTS) $(gnunet_service_core_DEPENDENCIES) + @rm -f gnunet-service-core$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_core_OBJECTS) $(gnunet_service_core_LDADD) $(LIBS) +test_core_api$(EXEEXT): $(test_core_api_OBJECTS) $(test_core_api_DEPENDENCIES) + @rm -f test_core_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_core_api_OBJECTS) $(test_core_api_LDADD) $(LIBS) +test_core_api_reliability$(EXEEXT): $(test_core_api_reliability_OBJECTS) $(test_core_api_reliability_DEPENDENCIES) + @rm -f test_core_api_reliability$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_core_api_reliability_OBJECTS) $(test_core_api_reliability_LDADD) $(LIBS) +test_core_api_send_to_self$(EXEEXT): $(test_core_api_send_to_self_OBJECTS) $(test_core_api_send_to_self_DEPENDENCIES) + @rm -f test_core_api_send_to_self$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_core_api_send_to_self_OBJECTS) $(test_core_api_send_to_self_LDADD) $(LIBS) +test_core_api_start_only$(EXEEXT): $(test_core_api_start_only_OBJECTS) $(test_core_api_start_only_DEPENDENCIES) + @rm -f test_core_api_start_only$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_core_api_start_only_OBJECTS) $(test_core_api_start_only_LDADD) $(LIBS) +test_core_quota_compliance_asymmetric_recv_limited$(EXEEXT): $(test_core_quota_compliance_asymmetric_recv_limited_OBJECTS) $(test_core_quota_compliance_asymmetric_recv_limited_DEPENDENCIES) + @rm -f test_core_quota_compliance_asymmetric_recv_limited$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_core_quota_compliance_asymmetric_recv_limited_OBJECTS) $(test_core_quota_compliance_asymmetric_recv_limited_LDADD) $(LIBS) +test_core_quota_compliance_asymmetric_send_limited$(EXEEXT): $(test_core_quota_compliance_asymmetric_send_limited_OBJECTS) $(test_core_quota_compliance_asymmetric_send_limited_DEPENDENCIES) + @rm -f test_core_quota_compliance_asymmetric_send_limited$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_core_quota_compliance_asymmetric_send_limited_OBJECTS) $(test_core_quota_compliance_asymmetric_send_limited_LDADD) $(LIBS) +test_core_quota_compliance_symmetric$(EXEEXT): $(test_core_quota_compliance_symmetric_OBJECTS) $(test_core_quota_compliance_symmetric_DEPENDENCIES) + @rm -f test_core_quota_compliance_symmetric$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_core_quota_compliance_symmetric_OBJECTS) $(test_core_quota_compliance_symmetric_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_api_iterate_peers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-core-list-connections.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core_clients.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core_kx.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core_neighbours.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core_sessions.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core_typemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_core_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_core_api_reliability.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_core_api_send_to_self.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_core_api_start_only.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_core_quota_compliance.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/core/core.conf.in b/src/core/core.conf.in new file mode 100644 index 0000000..84e2df9 --- /dev/null +++ b/src/core/core.conf.in @@ -0,0 +1,22 @@ +[core] +AUTOSTART = YES +@UNIXONLY@ PORT = 2092 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-core +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-core.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +# DISABLE_SOCKET_FORWARDING = NO +# DEBUG = YES +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = diff --git a/src/core/core.h b/src/core/core.h new file mode 100644 index 0000000..4942ad0 --- /dev/null +++ b/src/core/core.h @@ -0,0 +1,380 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/core.h + * @brief common internal definitions for core service + * @author Christian Grothoff + */ +#ifndef CORE_H +#define CORE_H + +#include "gnunet_bandwidth_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_time_lib.h" + +/** + * General core debugging. + */ +#define DEBUG_CORE GNUNET_EXTRA_LOGGING + +/** + * Definition of bits in the InitMessage's options field that specify + * which events this client cares about. Note that inbound messages + * for handlers that were specifically registered are always + * transmitted to the client. + */ +#define GNUNET_CORE_OPTION_NOTHING 0 +#define GNUNET_CORE_OPTION_SEND_STATUS_CHANGE 4 +#define GNUNET_CORE_OPTION_SEND_FULL_INBOUND 8 +#define GNUNET_CORE_OPTION_SEND_HDR_INBOUND 16 +#define GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND 32 +#define GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND 64 + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message transmitted core clients to gnunet-service-core + * to start the interaction. This header is followed by + * uint16_t type values specifying which messages this + * client is interested in. + */ +struct InitMessage +{ + + /** + * Header with type GNUNET_MESSAGE_TYPE_CORE_INIT. + */ + struct GNUNET_MessageHeader header; + + /** + * Options, see GNUNET_CORE_OPTION_ values. + */ + uint32_t options GNUNET_PACKED; + +}; + + +/** + * Message transmitted by the gnunet-service-core process + * to its clients in response to an INIT message. + */ +struct InitReplyMessage +{ + + /** + * Header with type GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Public key of the local peer. + */ + struct GNUNET_PeerIdentity my_identity; + +}; + + +/** + * Message sent by the service to clients to notify them + * about a peer connecting. + */ +struct ConnectNotifyMessage +{ + /** + * Header with type GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT + */ + struct GNUNET_MessageHeader header; + + /** + * Number of ATS key-value pairs that follow this struct + * (excluding the 0-terminator). + */ + uint32_t ats_count GNUNET_PACKED; + + /** + * Identity of the connecting peer. + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Message sent by the service to clients to notify them + * about a peer changing status. + */ +struct PeerStatusNotifyMessage +{ + /** + * Header with type GNUNET_MESSAGE_TYPE_CORE_NOTIFY_PEER_STATUS + */ + struct GNUNET_MessageHeader header; + + /** + * Number of ATS key-value pairs that follow this struct + * (excluding the 0-terminator). + */ + uint32_t ats_count GNUNET_PACKED; + + /** + * When the peer would time out (unless we see activity) + */ + struct GNUNET_TIME_AbsoluteNBO timeout; + + /** + * Available bandwidth from the peer. + */ + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; + + /** + * Available bandwidth to the peer. + */ + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; + + /** + * Identity of the peer. + */ + struct GNUNET_PeerIdentity peer; + + /** + * First of the ATS information blocks (we must have at least + * one due to the 0-termination requirement). + */ + struct GNUNET_ATS_Information ats; + +}; + + +/** + * Message sent by the service to clients to notify them + * about a peer disconnecting. + */ +struct DisconnectNotifyMessage +{ + /** + * Header with type GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT. + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Identity of the connecting peer. + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Message sent by the service to clients to notify them about + * messages being received or transmitted. This overall message is + * followed by the real message, or just the header of the real + * message (depending on the client's preferences). The receiver can + * tell if he got the full message or only a partial message by + * looking at the size field in the header of NotifyTrafficMessage and + * checking it with the size field in the message that follows. + */ +struct NotifyTrafficMessage +{ + /** + * Header with type GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND + * or GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND. + */ + struct GNUNET_MessageHeader header; + + /** + * Number of ATS key-value pairs that follow this struct + * (excluding the 0-terminator). + */ + uint32_t ats_count GNUNET_PACKED; + + /** + * Identity of the receiver or sender. + */ + struct GNUNET_PeerIdentity peer; + + /** + * First of the ATS information blocks (we must have at least + * one due to the 0-termination requirement). + */ + struct GNUNET_ATS_Information ats; + +}; + + +/** + * Client notifying core about the maximum-priority + * message it has in the queue for a particular target. + */ +struct SendMessageRequest +{ + /** + * Header with type GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST + */ + struct GNUNET_MessageHeader header; + + /** + * How important is this message? + */ + uint32_t priority GNUNET_PACKED; + + /** + * By what time would the sender really like to see this + * message transmitted? + */ + struct GNUNET_TIME_AbsoluteNBO deadline; + + /** + * Identity of the intended target. + */ + struct GNUNET_PeerIdentity peer; + + /** + * How large is the client's message queue for this peer? + */ + uint32_t queue_size GNUNET_PACKED; + + /** + * How large is the message? + */ + uint16_t size GNUNET_PACKED; + + /** + * Counter for this peer to match SMRs to replies. + */ + uint16_t smr_id GNUNET_PACKED; + +}; + + +/** + * Core notifying client that it is allowed to now + * transmit a message to the given target + * (response to GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST). + */ +struct SendMessageReady +{ + /** + * Header with type GNUNET_MESSAGE_TYPE_CORE_SEND_READY + */ + struct GNUNET_MessageHeader header; + + /** + * How many bytes are allowed for transmission? + * Guaranteed to be at least as big as the requested size, + * or ZERO if the request is rejected (will timeout, + * peer disconnected, queue full, etc.). + */ + uint16_t size GNUNET_PACKED; + + /** + * smr_id from the request. + */ + uint16_t smr_id GNUNET_PACKED; + + /** + * Identity of the intended target. + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Client asking core to transmit a particular message to a particular + * target (response to GNUNET_MESSAGE_TYPE_CORE_SEND_READY). + */ +struct SendMessage +{ + /** + * Header with type GNUNET_MESSAGE_TYPE_CORE_SEND + */ + struct GNUNET_MessageHeader header; + + /** + * How important is this message? + */ + uint32_t priority GNUNET_PACKED; + + /** + * By what time would the sender really like to see this + * message transmitted? + */ + struct GNUNET_TIME_AbsoluteNBO deadline; + + /** + * Identity of the receiver or sender. + */ + struct GNUNET_PeerIdentity peer; + + /** + * GNUNET_YES if corking is allowed, GNUNET_NO if not. + */ + uint32_t cork GNUNET_PACKED; + + /** + * Always 0. + */ + uint64_t reserved GNUNET_PACKED; + +}; + + +/** + * Client asking core to connect to a particular target. There is no + * response from the core to this type of request (however, if an + * actual connection is created or destroyed, be it because of this + * type request or not, the core generally needs to notify the + * clients). + */ +struct ConnectMessage +{ + /** + * Header with type GNUNET_MESSAGE_TYPE_REQUEST_CONNECT or + * GNUNET_MESSAGE_TYPE_REQUEST_DISCONNECT. + */ + struct GNUNET_MessageHeader header; + + /** + * For alignment. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Identity of the other peer. + */ + struct GNUNET_PeerIdentity peer; + +}; +GNUNET_NETWORK_STRUCT_END +#endif +/* end of core.h */ diff --git a/src/core/core_api.c b/src/core/core_api.c new file mode 100644 index 0000000..66df134 --- /dev/null +++ b/src/core/core_api.c @@ -0,0 +1,1493 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/core_api.c + * @brief core service; this is the main API for encrypted P2P + * communications + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_core_service.h" +#include "core.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "core-api",__VA_ARGS__) + +/** + * Information we track for each peer. + */ +struct PeerRecord +{ + + /** + * We generally do NOT keep peer records in a DLL; this + * DLL is only used IF this peer's 'pending_head' message + * is ready for transmission. + */ + struct PeerRecord *prev; + + /** + * We generally do NOT keep peer records in a DLL; this + * DLL is only used IF this peer's 'pending_head' message + * is ready for transmission. + */ + struct PeerRecord *next; + + /** + * Peer the record is about. + */ + struct GNUNET_PeerIdentity peer; + + /** + * Corresponding core handle. + */ + struct GNUNET_CORE_Handle *ch; + + /** + * Head of doubly-linked list of pending requests. + * Requests are sorted by deadline *except* for HEAD, + * which is only modified upon transmission to core. + */ + struct GNUNET_CORE_TransmitHandle *pending_head; + + /** + * Tail of doubly-linked list of pending requests. + */ + struct GNUNET_CORE_TransmitHandle *pending_tail; + + /** + * ID of timeout task for the 'pending_head' handle + * which is the one with the smallest timeout. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * ID of task to run 'next_request_transmission'. + */ + GNUNET_SCHEDULER_TaskIdentifier ntr_task; + + /** + * Current size of the queue of pending requests. + */ + unsigned int queue_size; + + /** + * SendMessageRequest ID generator for this peer. + */ + uint16_t smr_id_gen; + +}; + + +/** + * Type of function called upon completion. + * + * @param cls closure + * @param success GNUNET_OK on success (which for request_connect + * ONLY means that we transmitted the connect request to CORE, + * it does not mean that we are actually now connected!); + * GNUNET_NO on timeout, + * GNUNET_SYSERR if core was shut down + */ +typedef void (*GNUNET_CORE_ControlContinuation) (void *cls, int success); + + +/** + * Entry in a doubly-linked list of control messages to be transmitted + * to the core service. Control messages include traffic allocation, + * connection requests and of course our initial 'init' request. + * + * The actual message is allocated at the end of this struct. + */ +struct ControlMessage +{ + /** + * This is a doubly-linked list. + */ + struct ControlMessage *next; + + /** + * This is a doubly-linked list. + */ + struct ControlMessage *prev; + + /** + * Function to run after transmission failed/succeeded. + */ + GNUNET_CORE_ControlContinuation cont; + + /** + * Closure for 'cont'. + */ + void *cont_cls; + + /** + * Transmit handle (if one is associated with this ControlMessage), or NULL. + */ + struct GNUNET_CORE_TransmitHandle *th; +}; + + + +/** + * Context for the core service connection. + */ +struct GNUNET_CORE_Handle +{ + + /** + * Configuration we're using. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Closure for the various callbacks. + */ + void *cls; + + /** + * Function to call once we've handshaked with the core service. + */ + GNUNET_CORE_StartupCallback init; + + /** + * Function to call whenever we're notified about a peer connecting. + */ + GNUNET_CORE_ConnectEventHandler connects; + + /** + * Function to call whenever we're notified about a peer disconnecting. + */ + GNUNET_CORE_DisconnectEventHandler disconnects; + + /** + * Function to call whenever we receive an inbound message. + */ + GNUNET_CORE_MessageCallback inbound_notify; + + /** + * Function to call whenever we receive an outbound message. + */ + GNUNET_CORE_MessageCallback outbound_notify; + + /** + * Function handlers for messages of particular type. + */ + const struct GNUNET_CORE_MessageHandler *handlers; + + /** + * Our connection to the service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Handle for our current transmission request. + */ + struct GNUNET_CLIENT_TransmitHandle *cth; + + /** + * Head of doubly-linked list of pending requests. + */ + struct ControlMessage *control_pending_head; + + /** + * Tail of doubly-linked list of pending requests. + */ + struct ControlMessage *control_pending_tail; + + /** + * Head of doubly-linked list of peers that are core-approved + * to send their next message. + */ + struct PeerRecord *ready_peer_head; + + /** + * Tail of doubly-linked list of peers that are core-approved + * to send their next message. + */ + struct PeerRecord *ready_peer_tail; + + /** + * Hash map listing all of the peers that we are currently + * connected to. + */ + struct GNUNET_CONTAINER_MultiHashMap *peers; + + /** + * Identity of this peer. + */ + struct GNUNET_PeerIdentity me; + + /** + * ID of reconnect task (if any). + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * Current delay we use for re-trying to connect to core. + */ + struct GNUNET_TIME_Relative retry_backoff; + + /** + * Number of messages we are allowed to queue per target. + */ + unsigned int queue_size; + + /** + * Number of entries in the handlers array. + */ + unsigned int hcnt; + + /** + * For inbound notifications without a specific handler, do + * we expect to only receive headers? + */ + int inbound_hdr_only; + + /** + * For outbound notifications without a specific handler, do + * we expect to only receive headers? + */ + int outbound_hdr_only; + + /** + * Are we currently disconnected and hence unable to forward + * requests? + */ + int currently_down; + +}; + + +/** + * Handle for a transmission request. + */ +struct GNUNET_CORE_TransmitHandle +{ + + /** + * We keep active transmit handles in a doubly-linked list. + */ + struct GNUNET_CORE_TransmitHandle *next; + + /** + * We keep active transmit handles in a doubly-linked list. + */ + struct GNUNET_CORE_TransmitHandle *prev; + + /** + * Corresponding peer record. + */ + struct PeerRecord *peer; + + /** + * Corresponding SEND_REQUEST message. Only non-NULL + * while SEND_REQUEST message is pending. + */ + struct ControlMessage *cm; + + /** + * Function that will be called to get the actual request + * (once we are ready to transmit this request to the core). + * The function will be called with a NULL buffer to signal + * timeout. + */ + GNUNET_CONNECTION_TransmitReadyNotify get_message; + + /** + * Closure for get_message. + */ + void *get_message_cls; + + /** + * Timeout for this handle. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * How important is this message? + */ + uint32_t priority; + + /** + * Size of this request. + */ + uint16_t msize; + + /** + * Send message request ID for this request. + */ + uint16_t smr_id; + + /** + * Is corking allowed? + */ + int cork; + +}; + + +/** + * Our current client connection went down. Clean it up + * and try to reconnect! + * + * @param h our handle to the core service + */ +static void +reconnect (struct GNUNET_CORE_Handle *h); + + +/** + * Task schedule to try to re-connect to core. + * + * @param cls the 'struct GNUNET_CORE_Handle' + * @param tc task context + */ +static void +reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CORE_Handle *h = cls; + + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service after delay\n"); +#endif + reconnect (h); +} + + +/** + * Notify clients about disconnect and free + * the entry for connected peer. + * + * @param cls the 'struct GNUNET_CORE_Handle*' + * @param key the peer identity (not used) + * @param value the 'struct PeerRecord' to free. + * @return GNUNET_YES (continue) + */ +static int +disconnect_and_free_peer_entry (void *cls, const GNUNET_HashCode * key, + void *value) +{ + struct GNUNET_CORE_Handle *h = cls; + struct GNUNET_CORE_TransmitHandle *th; + struct PeerRecord *pr = value; + + if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (pr->timeout_task); + pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (pr->ntr_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (pr->ntr_task); + pr->ntr_task = GNUNET_SCHEDULER_NO_TASK; + } + if ((pr->prev != NULL) || (pr->next != NULL) || (h->ready_peer_head == pr)) + GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); + if (h->disconnects != NULL) + h->disconnects (h->cls, &pr->peer); + /* all requests should have been cancelled, clean up anyway, just in case */ + GNUNET_break (pr->queue_size == 0); + while (NULL != (th = pr->pending_head)) + { + GNUNET_break (0); + GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th); + pr->queue_size--; + if (th->cm != NULL) + th->cm->th = NULL; + GNUNET_free (th); + } + /* done with 'voluntary' cleanups, now on to normal freeing */ + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (h->peers, key, pr)); + GNUNET_assert (pr->pending_head == NULL); + GNUNET_assert (pr->pending_tail == NULL); + GNUNET_assert (pr->ch == h); + GNUNET_assert (pr->queue_size == 0); + GNUNET_assert (pr->timeout_task == GNUNET_SCHEDULER_NO_TASK); + GNUNET_assert (pr->ntr_task == GNUNET_SCHEDULER_NO_TASK); + GNUNET_free (pr); + return GNUNET_YES; +} + + +/** + * Close down any existing connection to the CORE service and + * try re-establishing it later. + * + * @param h our handle + */ +static void +reconnect_later (struct GNUNET_CORE_Handle *h) +{ + struct ControlMessage *cm; + struct PeerRecord *pr; + + GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); + if (NULL != h->cth) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth); + h->cth = NULL; + } + if (h->client != NULL) + { + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->client = NULL; + } + h->currently_down = GNUNET_YES; + GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); + h->reconnect_task = + GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_task, h); + while (NULL != (cm = h->control_pending_head)) + { + GNUNET_CONTAINER_DLL_remove (h->control_pending_head, + h->control_pending_tail, cm); + if (cm->th != NULL) + cm->th->cm = NULL; + if (cm->cont != NULL) + cm->cont (cm->cont_cls, GNUNET_NO); + GNUNET_free (cm); + } + GNUNET_CONTAINER_multihashmap_iterate (h->peers, + &disconnect_and_free_peer_entry, h); + while (NULL != (pr = h->ready_peer_head)) + GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); + GNUNET_assert (h->control_pending_head == NULL); + h->retry_backoff = + GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, h->retry_backoff); + h->retry_backoff = GNUNET_TIME_relative_multiply (h->retry_backoff, 2); +} + + +/** + * Check the list of pending requests, send the next + * one to the core. + * + * @param h core handle + * @param ignore_currently_down transmit message even if not initialized? + */ +static void +trigger_next_request (struct GNUNET_CORE_Handle *h, int ignore_currently_down); + + +/** + * The given request hit its timeout. Remove from the + * doubly-linked list and call the respective continuation. + * + * @param cls the transmit handle of the request that timed out + * @param tc context, can be NULL (!) + */ +static void +transmission_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Send a control message to the peer asking for transmission + * of the message in the given peer record. + * + * @param pr peer to request transmission to + */ +static void +request_next_transmission (struct PeerRecord *pr) +{ + struct GNUNET_CORE_Handle *h = pr->ch; + struct ControlMessage *cm; + struct SendMessageRequest *smr; + struct GNUNET_CORE_TransmitHandle *th; + + if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (pr->timeout_task); + pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL == (th = pr->pending_head)) + { + trigger_next_request (h, GNUNET_NO); + return; + } + if (th->cm != NULL) + return; /* already done */ + GNUNET_assert (pr->prev == NULL); + GNUNET_assert (pr->next == NULL); + pr->timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (th->timeout), &transmission_timeout, pr); + cm = GNUNET_malloc (sizeof (struct ControlMessage) + + sizeof (struct SendMessageRequest)); + th->cm = cm; + cm->th = th; + smr = (struct SendMessageRequest *) &cm[1]; + smr->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST); + smr->header.size = htons (sizeof (struct SendMessageRequest)); + smr->priority = htonl (th->priority); + smr->deadline = GNUNET_TIME_absolute_hton (th->timeout); + smr->peer = pr->peer; + smr->queue_size = htonl (pr->queue_size); + smr->size = htons (th->msize); + smr->smr_id = htons (th->smr_id = pr->smr_id_gen++); + GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, + h->control_pending_tail, cm); +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding SEND REQUEST for peer `%s' to message queue\n", + GNUNET_i2s (&pr->peer)); +#endif + trigger_next_request (h, GNUNET_NO); +} + + +/** + * The given request hit its timeout. Remove from the + * doubly-linked list and call the respective continuation. + * + * @param cls the transmit handle of the request that timed out + * @param tc context, can be NULL (!) + */ +static void +transmission_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerRecord *pr = cls; + struct GNUNET_CORE_Handle *h = pr->ch; + struct GNUNET_CORE_TransmitHandle *th; + + pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; + th = pr->pending_head; + GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th); + pr->queue_size--; + if ((pr->prev != NULL) || (pr->next != NULL) || (pr == h->ready_peer_head)) + { + /* the request that was 'approved' by core was + * canceled before it could be transmitted; remove + * us from the 'ready' list */ + GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); + } +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Signalling timeout of request for transmission to CORE service\n"); +#endif + request_next_transmission (pr); + GNUNET_assert (0 == th->get_message (th->get_message_cls, 0, NULL)); + GNUNET_free (th); +} + + +/** + * Transmit the next message to the core service. + */ +static size_t +transmit_message (void *cls, size_t size, void *buf) +{ + struct GNUNET_CORE_Handle *h = cls; + struct ControlMessage *cm; + struct GNUNET_CORE_TransmitHandle *th; + struct PeerRecord *pr; + struct SendMessage *sm; + const struct GNUNET_MessageHeader *hdr; + uint16_t msize; + size_t ret; + + GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); + h->cth = NULL; + if (buf == NULL) + { +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmission failed, initiating reconnect\n"); +#endif + reconnect_later (h); + return 0; + } + /* first check for control messages */ + if (NULL != (cm = h->control_pending_head)) + { + hdr = (const struct GNUNET_MessageHeader *) &cm[1]; + msize = ntohs (hdr->size); + if (size < msize) + { + trigger_next_request (h, GNUNET_NO); + return 0; + } +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting control message with %u bytes of type %u to core.\n", + (unsigned int) msize, (unsigned int) ntohs (hdr->type)); +#endif + memcpy (buf, hdr, msize); + GNUNET_CONTAINER_DLL_remove (h->control_pending_head, + h->control_pending_tail, cm); + if (cm->th != NULL) + cm->th->cm = NULL; + if (NULL != cm->cont) + cm->cont (cm->cont_cls, GNUNET_OK); + GNUNET_free (cm); + trigger_next_request (h, GNUNET_NO); + return msize; + } + /* now check for 'ready' P2P messages */ + if (NULL != (pr = h->ready_peer_head)) + { + GNUNET_assert (pr->pending_head != NULL); + th = pr->pending_head; + if (size < th->msize + sizeof (struct SendMessage)) + { + trigger_next_request (h, GNUNET_NO); + return 0; + } + GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); + GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th); + pr->queue_size--; + if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (pr->timeout_task); + pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting SEND request to `%s' with %u bytes.\n", + GNUNET_i2s (&pr->peer), (unsigned int) th->msize); +#endif + sm = (struct SendMessage *) buf; + sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND); + sm->priority = htonl (th->priority); + sm->deadline = GNUNET_TIME_absolute_hton (th->timeout); + sm->peer = pr->peer; + sm->cork = htonl ((uint32_t) th->cork); + sm->reserved = htonl (0); + ret = + th->get_message (th->get_message_cls, + size - sizeof (struct SendMessage), &sm[1]); + +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting SEND request to `%s' yielded %u bytes.\n", + GNUNET_i2s (&pr->peer), ret); +#endif + GNUNET_free (th); + if (0 == ret) + { +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Size of clients message to peer %s is 0!\n", + GNUNET_i2s (&pr->peer)); +#endif + /* client decided to send nothing! */ + request_next_transmission (pr); + return 0; + } +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Produced SEND message to core with %u bytes payload\n", + (unsigned int) ret); +#endif + GNUNET_assert (ret >= sizeof (struct GNUNET_MessageHeader)); + if (ret + sizeof (struct SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + request_next_transmission (pr); + return 0; + } + ret += sizeof (struct SendMessage); + sm->header.size = htons (ret); + GNUNET_assert (ret <= size); + request_next_transmission (pr); + return ret; + } + return 0; +} + + +/** + * Check the list of pending requests, send the next + * one to the core. + * + * @param h core handle + * @param ignore_currently_down transmit message even if not initialized? + */ +static void +trigger_next_request (struct GNUNET_CORE_Handle *h, int ignore_currently_down) +{ + uint16_t msize; + + if ((GNUNET_YES == h->currently_down) && (ignore_currently_down == GNUNET_NO)) + { +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Core connection down, not processing queue\n"); +#endif + return; + } + if (NULL != h->cth) + { +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Request pending, not processing queue\n"); +#endif + return; + } + if (h->control_pending_head != NULL) + msize = + ntohs (((struct GNUNET_MessageHeader *) &h-> + control_pending_head[1])->size); + else if (h->ready_peer_head != NULL) + msize = + h->ready_peer_head->pending_head->msize + sizeof (struct SendMessage); + else + { +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Request queue empty, not processing queue\n"); +#endif + return; /* no pending message */ + } + h->cth = + GNUNET_CLIENT_notify_transmit_ready (h->client, msize, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, &transmit_message, h); +} + + +/** + * Handler for notification messages received from the core. + * + * @param cls our "struct GNUNET_CORE_Handle" + * @param msg the message received from the core service + */ +static void +main_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_CORE_Handle *h = cls; + const struct InitReplyMessage *m; + const struct ConnectNotifyMessage *cnm; + const struct DisconnectNotifyMessage *dnm; + const struct NotifyTrafficMessage *ntm; + const struct GNUNET_MessageHeader *em; + const struct SendMessageReady *smr; + const struct GNUNET_CORE_MessageHandler *mh; + const struct GNUNET_ATS_Information *ats; + GNUNET_CORE_StartupCallback init; + struct PeerRecord *pr; + struct GNUNET_CORE_TransmitHandle *th; + unsigned int hpos; + int trigger; + uint16_t msize; + uint16_t et; + uint32_t ats_count; + + if (msg == NULL) + { + LOG (GNUNET_ERROR_TYPE_INFO, + _ + ("Client was disconnected from core service, trying to reconnect.\n")); + reconnect_later (h); + return; + } + msize = ntohs (msg->size); +#if DEBUG_CORE > 2 + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing message of type %u and size %u from core service\n", + ntohs (msg->type), msize); +#endif + switch (ntohs (msg->type)) + { + case GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY: + if (ntohs (msg->size) != sizeof (struct InitReplyMessage)) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + m = (const struct InitReplyMessage *) msg; + GNUNET_break (0 == ntohl (m->reserved)); + /* start our message processing loop */ + if (GNUNET_YES == h->currently_down) + { + h->currently_down = GNUNET_NO; + trigger_next_request (h, GNUNET_NO); + } + h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; + h->me = m->my_identity; + if (NULL != (init = h->init)) + { + /* mark so we don't call init on reconnect */ + h->init = NULL; +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to core service of peer `%s'.\n", + GNUNET_i2s (&h->me)); +#endif + init (h->cls, h, &h->me); + } + else + { +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Successfully reconnected to core service.\n"); +#endif + } + /* fake 'connect to self' */ + pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &h->me.hashPubKey); + GNUNET_assert (pr == NULL); + pr = GNUNET_malloc (sizeof (struct PeerRecord)); + pr->peer = h->me; + pr->ch = h; + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_put (h->peers, + &h->me.hashPubKey, pr, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); + if (NULL != h->connects) + h->connects (h->cls, &h->me, NULL, 0); + break; + case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT: + if (msize < sizeof (struct ConnectNotifyMessage)) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + cnm = (const struct ConnectNotifyMessage *) msg; + ats_count = ntohl (cnm->ats_count); + if (msize != + sizeof (struct ConnectNotifyMessage) + + ats_count * sizeof (struct GNUNET_ATS_Information)) + { + GNUNET_break (0); + reconnect_later (h); + return; + } +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received notification about connection from `%s'.\n", + GNUNET_i2s (&cnm->peer)); +#endif + if (0 == memcmp (&h->me, &cnm->peer, sizeof (struct GNUNET_PeerIdentity))) + { + /* connect to self!? */ + GNUNET_break (0); + return; + } + pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &cnm->peer.hashPubKey); + if (pr != NULL) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + pr = GNUNET_malloc (sizeof (struct PeerRecord)); + pr->peer = cnm->peer; + pr->ch = h; + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_put (h->peers, + &cnm->peer.hashPubKey, pr, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); + ats = (const struct GNUNET_ATS_Information *) &cnm[1]; + if (NULL != h->connects) + h->connects (h->cls, &cnm->peer, ats, ats_count); + break; + case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT: + if (msize != sizeof (struct DisconnectNotifyMessage)) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + dnm = (const struct DisconnectNotifyMessage *) msg; + if (0 == memcmp (&h->me, &dnm->peer, sizeof (struct GNUNET_PeerIdentity))) + { + /* connection to self!? */ + GNUNET_break (0); + return; + } + GNUNET_break (0 == ntohl (dnm->reserved)); +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received notification about disconnect from `%s'.\n", + GNUNET_i2s (&dnm->peer)); +#endif + pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &dnm->peer.hashPubKey); + if (pr == NULL) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + trigger = ((pr->prev != NULL) || (pr->next != NULL) || + (h->ready_peer_head == pr)); + disconnect_and_free_peer_entry (h, &dnm->peer.hashPubKey, pr); + if (trigger) + trigger_next_request (h, GNUNET_NO); + break; + case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND: + if (msize < sizeof (struct NotifyTrafficMessage)) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + ntm = (const struct NotifyTrafficMessage *) msg; + + ats_count = ntohl (ntm->ats_count); + if ((msize < + sizeof (struct NotifyTrafficMessage) + + ats_count * sizeof (struct GNUNET_ATS_Information) + + sizeof (struct GNUNET_MessageHeader)) || + (GNUNET_ATS_ARRAY_TERMINATOR != ntohl ((&ntm->ats)[ats_count].type))) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + em = (const struct GNUNET_MessageHeader *) &(&ntm->ats)[ats_count + 1]; +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received message of type %u and size %u from peer `%4s'\n", + ntohs (em->type), ntohs (em->size), GNUNET_i2s (&ntm->peer)); +#endif + pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &ntm->peer.hashPubKey); + if (pr == NULL) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + if ((GNUNET_NO == h->inbound_hdr_only) && + (msize != + ntohs (em->size) + sizeof (struct NotifyTrafficMessage) + + +ats_count * sizeof (struct GNUNET_ATS_Information))) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + et = ntohs (em->type); + for (hpos = 0; hpos < h->hcnt; hpos++) + { + mh = &h->handlers[hpos]; + if (mh->type != et) + continue; + if ((mh->expected_size != ntohs (em->size)) && (mh->expected_size != 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected message size %u for message of type %u from peer `%4s'\n", + htons (em->size), mh->type, GNUNET_i2s (&ntm->peer)); + GNUNET_break_op (0); + continue; + } + if (GNUNET_OK != + h->handlers[hpos].callback (h->cls, &ntm->peer, em, &ntm->ats, + ats_count)) + { + /* error in processing, do not process other messages! */ + break; + } + } + if (NULL != h->inbound_notify) + h->inbound_notify (h->cls, &ntm->peer, em, &ntm->ats, ats_count); + break; + case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND: + if (msize < sizeof (struct NotifyTrafficMessage)) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + ntm = (const struct NotifyTrafficMessage *) msg; + if (0 == memcmp (&h->me, &ntm->peer, sizeof (struct GNUNET_PeerIdentity))) + { + /* self-change!? */ + GNUNET_break (0); + return; + } + ats_count = ntohl (ntm->ats_count); + if ((msize < + sizeof (struct NotifyTrafficMessage) + + ats_count * sizeof (struct GNUNET_ATS_Information) + + sizeof (struct GNUNET_MessageHeader)) || + (GNUNET_ATS_ARRAY_TERMINATOR != ntohl ((&ntm->ats)[ats_count].type))) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + em = (const struct GNUNET_MessageHeader *) &(&ntm->ats)[ats_count + 1]; + pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &ntm->peer.hashPubKey); + if (pr == NULL) + { + GNUNET_break (0); + reconnect_later (h); + return; + } +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received notification about transmission to `%s'.\n", + GNUNET_i2s (&ntm->peer)); +#endif + if ((GNUNET_NO == h->outbound_hdr_only) && + (msize != + ntohs (em->size) + sizeof (struct NotifyTrafficMessage) + + ats_count * sizeof (struct GNUNET_ATS_Information))) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + if (NULL == h->outbound_notify) + { + GNUNET_break (0); + break; + } + h->outbound_notify (h->cls, &ntm->peer, em, &ntm->ats, ats_count); + break; + case GNUNET_MESSAGE_TYPE_CORE_SEND_READY: + if (msize != sizeof (struct SendMessageReady)) + { + GNUNET_break (0); + reconnect_later (h); + return; + } + smr = (const struct SendMessageReady *) msg; + pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &smr->peer.hashPubKey); + if (pr == NULL) + { + GNUNET_break (0); + reconnect_later (h); + return; + } +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received notification about transmission readiness to `%s'.\n", + GNUNET_i2s (&smr->peer)); +#endif + if (pr->pending_head == NULL) + { + /* request must have been cancelled between the original request + * and the response from core, ignore core's readiness */ + break; + } + + th = pr->pending_head; + if (ntohs (smr->smr_id) != th->smr_id) + { + /* READY message is for expired or cancelled message, + * ignore! (we should have already sent another request) */ + break; + } + if ((pr->prev != NULL) || (pr->next != NULL) || (h->ready_peer_head == pr)) + { + /* we should not already be on the ready list... */ + GNUNET_break (0); + reconnect_later (h); + return; + } + GNUNET_CONTAINER_DLL_insert (h->ready_peer_head, h->ready_peer_tail, pr); + trigger_next_request (h, GNUNET_NO); + break; + default: + reconnect_later (h); + return; + } + GNUNET_CLIENT_receive (h->client, &main_notify_handler, h, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Task executed once we are done transmitting the INIT message. + * Starts our 'receive' loop. + * + * @param cls the 'struct GNUNET_CORE_Handle' + * @param success were we successful + */ +static void +init_done_task (void *cls, int success) +{ + struct GNUNET_CORE_Handle *h = cls; + + if (success == GNUNET_SYSERR) + return; /* shutdown */ + if (success == GNUNET_NO) + { +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to exchange INIT with core, retrying\n"); +#endif + if (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK) + reconnect_later (h); + return; + } + GNUNET_CLIENT_receive (h->client, &main_notify_handler, h, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Our current client connection went down. Clean it up + * and try to reconnect! + * + * @param h our handle to the core service + */ +static void +reconnect (struct GNUNET_CORE_Handle *h) +{ + struct ControlMessage *cm; + struct InitMessage *init; + uint32_t opt; + uint16_t msize; + uint16_t *ts; + unsigned int hpos; + +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting to CORE service\n"); +#endif + GNUNET_assert (h->client == NULL); + GNUNET_assert (h->currently_down == GNUNET_YES); + h->client = GNUNET_CLIENT_connect ("core", h->cfg); + if (h->client == NULL) + { + reconnect_later (h); + return; + } + msize = h->hcnt * sizeof (uint16_t) + sizeof (struct InitMessage); + cm = GNUNET_malloc (sizeof (struct ControlMessage) + msize); + cm->cont = &init_done_task; + cm->cont_cls = h; + init = (struct InitMessage *) &cm[1]; + init->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT); + init->header.size = htons (msize); + opt = 0; + if (h->inbound_notify != NULL) + { + if (h->inbound_hdr_only) + opt |= GNUNET_CORE_OPTION_SEND_HDR_INBOUND; + else + opt |= GNUNET_CORE_OPTION_SEND_FULL_INBOUND; + } + if (h->outbound_notify != NULL) + { + if (h->outbound_hdr_only) + opt |= GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND; + else + opt |= GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND; + } + init->options = htonl (opt); + ts = (uint16_t *) & init[1]; + for (hpos = 0; hpos < h->hcnt; hpos++) + ts[hpos] = htons (h->handlers[hpos].type); + GNUNET_CONTAINER_DLL_insert (h->control_pending_head, h->control_pending_tail, + cm); + trigger_next_request (h, GNUNET_YES); +} + + + +/** + * Connect to the core service. Note that the connection may + * complete (or fail) asynchronously. + * + * @param cfg configuration to use + * @param queue_size size of the per-peer message queue + * @param cls closure for the various callbacks that follow (including handlers in the handlers array) + * @param init callback to call on timeout or once we have successfully + * connected to the core service; note that timeout is only meaningful if init is not NULL + * @param connects function to call on peer connect, can be NULL + * @param disconnects function to call on peer disconnect / timeout, can be NULL + * @param inbound_notify function to call for all inbound messages, can be NULL + * @param inbound_hdr_only set to GNUNET_YES if inbound_notify will only read the + * GNUNET_MessageHeader and hence we do not need to give it the full message; + * can be used to improve efficiency, ignored if inbound_notify is NULLL + * @param outbound_notify function to call for all outbound messages, can be NULL + * @param outbound_hdr_only set to GNUNET_YES if outbound_notify will only read the + * GNUNET_MessageHeader and hence we do not need to give it the full message + * can be used to improve efficiency, ignored if outbound_notify is NULLL + * @param handlers callbacks for messages we care about, NULL-terminated + * @return handle to the core service (only useful for disconnect until 'init' is called); + * NULL on error (in this case, init is never called) + */ +struct GNUNET_CORE_Handle * +GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int queue_size, void *cls, + GNUNET_CORE_StartupCallback init, + GNUNET_CORE_ConnectEventHandler connects, + GNUNET_CORE_DisconnectEventHandler disconnects, + GNUNET_CORE_MessageCallback inbound_notify, + int inbound_hdr_only, + GNUNET_CORE_MessageCallback outbound_notify, + int outbound_hdr_only, + const struct GNUNET_CORE_MessageHandler *handlers) +{ + struct GNUNET_CORE_Handle *h; + + h = GNUNET_malloc (sizeof (struct GNUNET_CORE_Handle)); + h->cfg = cfg; + h->queue_size = queue_size; + h->cls = cls; + h->init = init; + h->connects = connects; + h->disconnects = disconnects; + h->inbound_notify = inbound_notify; + h->outbound_notify = outbound_notify; + h->inbound_hdr_only = inbound_hdr_only; + h->outbound_hdr_only = outbound_hdr_only; + h->handlers = handlers; + h->hcnt = 0; + h->currently_down = GNUNET_YES; + h->peers = GNUNET_CONTAINER_multihashmap_create (128); + h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; + if (NULL != handlers) + while (handlers[h->hcnt].callback != NULL) + h->hcnt++; + GNUNET_assert (h->hcnt < + (GNUNET_SERVER_MAX_MESSAGE_SIZE - + sizeof (struct InitMessage)) / sizeof (uint16_t)); +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service\n"); +#endif + reconnect (h); + return h; +} + + +/** + * Disconnect from the core service. This function can only + * be called *after* all pending 'GNUNET_CORE_notify_transmit_ready' + * requests have been explicitly canceled. + * + * @param handle connection to core to disconnect + */ +void +GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle) +{ + struct ControlMessage *cm; + +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from CORE service\n"); +#endif + if (handle->cth != NULL) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (handle->cth); + handle->cth = NULL; + } + while (NULL != (cm = handle->control_pending_head)) + { + GNUNET_CONTAINER_DLL_remove (handle->control_pending_head, + handle->control_pending_tail, cm); + if (cm->th != NULL) + cm->th->cm = NULL; + if (cm->cont != NULL) + cm->cont (cm->cont_cls, GNUNET_SYSERR); + GNUNET_free (cm); + } + if (handle->client != NULL) + { + GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO); + handle->client = NULL; + } + GNUNET_CONTAINER_multihashmap_iterate (handle->peers, + &disconnect_and_free_peer_entry, + handle); + if (handle->reconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (handle->reconnect_task); + handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_CONTAINER_multihashmap_destroy (handle->peers); + handle->peers = NULL; + GNUNET_break (handle->ready_peer_head == NULL); + GNUNET_free (handle); +} + + +/** + * Task that calls 'request_next_transmission'. + * + * @param cls the 'struct PeerRecord*' + * @param tc scheduler context + */ +static void +run_request_next_transmission (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerRecord *pr = cls; + + pr->ntr_task = GNUNET_SCHEDULER_NO_TASK; + request_next_transmission (pr); +} + + +/** + * Ask the core to call "notify" once it is ready to transmit the + * given number of bytes to the specified "target". Must only be + * called after a connection to the respective peer has been + * established (and the client has been informed about this). + * + * @param handle connection to core service + * @param cork is corking allowed for this transmission? + * @param priority how important is the message? + * @param maxdelay how long can the message wait? + * @param target who should receive the message, + * use NULL for this peer (loopback) + * @param notify_size how many bytes of buffer space does notify want? + * @param notify function to call when buffer space is available + * @param notify_cls closure for notify + * @return non-NULL if the notify callback was queued, + * NULL if we can not even queue the request (insufficient + * memory); if NULL is returned, "notify" will NOT be called. + */ +struct GNUNET_CORE_TransmitHandle * +GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle, int cork, + uint32_t priority, + struct GNUNET_TIME_Relative maxdelay, + const struct GNUNET_PeerIdentity *target, + size_t notify_size, + GNUNET_CONNECTION_TransmitReadyNotify notify, + void *notify_cls) +{ + struct PeerRecord *pr; + struct GNUNET_CORE_TransmitHandle *th; + struct GNUNET_CORE_TransmitHandle *pos; + struct GNUNET_CORE_TransmitHandle *prev; + struct GNUNET_CORE_TransmitHandle *minp; + + pr = GNUNET_CONTAINER_multihashmap_get (handle->peers, &target->hashPubKey); + if (NULL == pr) + { + /* attempt to send to peer that is not connected */ + LOG (GNUNET_ERROR_TYPE_WARNING, + "Attempting to send to peer `%s' from peer `%s', but not connected!\n", + GNUNET_i2s (target), GNUNET_h2s (&handle->me.hashPubKey)); + GNUNET_break (0); + return NULL; + } + GNUNET_assert (notify_size + sizeof (struct SendMessage) < + GNUNET_SERVER_MAX_MESSAGE_SIZE); + th = GNUNET_malloc (sizeof (struct GNUNET_CORE_TransmitHandle)); + th->peer = pr; + GNUNET_assert (NULL != notify); + th->get_message = notify; + th->get_message_cls = notify_cls; + th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay); + th->priority = priority; + th->msize = notify_size; + th->cork = cork; + /* bound queue size */ + if (pr->queue_size == handle->queue_size) + { + /* find lowest-priority entry, but skip the head of the list */ + minp = pr->pending_head->next; + prev = minp; + while (prev != NULL) + { + if (prev->priority < minp->priority) + minp = prev; + prev = prev->next; + } + if (minp == NULL) + { + GNUNET_break (handle->queue_size != 0); + GNUNET_break (pr->queue_size == 1); + GNUNET_free (th); +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Dropping transmission request: cannot drop queue head and limit is one\n"); +#endif + return NULL; + } + if (priority <= minp->priority) + { +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Dropping transmission request: priority too low\n"); +#endif + GNUNET_free (th); + return NULL; /* priority too low */ + } + GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, minp); + pr->queue_size--; + GNUNET_assert (0 == minp->get_message (minp->get_message_cls, 0, NULL)); + GNUNET_free (minp); + } + + /* Order entries by deadline, but SKIP 'HEAD' (as we may have transmitted + * that request already or might even already be approved to transmit that + * message to core) */ + pos = pr->pending_head; + if (pos != NULL) + pos = pos->next; /* skip head */ + + /* insertion sort */ + prev = pos; + while ((pos != NULL) && (pos->timeout.abs_value < th->timeout.abs_value)) + { + prev = pos; + pos = pos->next; + } + GNUNET_CONTAINER_DLL_insert_after (pr->pending_head, pr->pending_tail, prev, + th); + pr->queue_size++; + /* was the request queue previously empty? */ +#if DEBUG_CORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission request added to queue\n"); +#endif + if ((pr->pending_head == th) && (pr->ntr_task == GNUNET_SCHEDULER_NO_TASK) && + (pr->next == NULL) && (pr->prev == NULL) && + (handle->ready_peer_head != pr)) + pr->ntr_task = + GNUNET_SCHEDULER_add_now (&run_request_next_transmission, pr); + return th; +} + + +/** + * Cancel the specified transmission-ready notification. + * + * @param th handle that was returned by "notify_transmit_ready". + */ +void +GNUNET_CORE_notify_transmit_ready_cancel (struct GNUNET_CORE_TransmitHandle *th) +{ + struct PeerRecord *pr = th->peer; + struct GNUNET_CORE_Handle *h = pr->ch; + int was_head; + + was_head = (pr->pending_head == th); + GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th); + pr->queue_size--; + if (th->cm != NULL) + { + /* we're currently in the control queue, remove */ + GNUNET_CONTAINER_DLL_remove (h->control_pending_head, + h->control_pending_tail, th->cm); + GNUNET_free (th->cm); + } + GNUNET_free (th); + if (was_head) + { + if ((pr->prev != NULL) || (pr->next != NULL) || (pr == h->ready_peer_head)) + { + /* the request that was 'approved' by core was + * canceled before it could be transmitted; remove + * us from the 'ready' list */ + GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); + } + request_next_transmission (pr); + } +} + + +/* end of core_api.c */ diff --git a/src/core/core_api_iterate_peers.c b/src/core/core_api_iterate_peers.c new file mode 100644 index 0000000..7b28842 --- /dev/null +++ b/src/core/core_api_iterate_peers.c @@ -0,0 +1,247 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/core_api_iterate_peers.c + * @brief implementation of the peer_iterate function + * @author Christian Grothoff + * @author Nathan Evans + */ +#include "platform.h" +#include "gnunet_core_service.h" +#include "core.h" + + +struct GNUNET_CORE_RequestContext +{ + /** + * Our connection to the service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Handle for transmitting a request. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Function called with the peer. + */ + GNUNET_CORE_ConnectEventHandler peer_cb; + + /** + * Peer to check for. + */ + struct GNUNET_PeerIdentity *peer; + + /** + * Closure for peer_cb. + */ + void *cb_cls; + +}; + + +/** + * Receive reply from core service with information about a peer. + * + * @param cls our 'struct GNUNET_CORE_RequestContext *' + * @param msg NULL on error or last entry + */ +static void +receive_info (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_CORE_RequestContext *request_context = cls; + const struct ConnectNotifyMessage *connect_message; + uint32_t ats_count; + uint16_t msize; + + /* Handle last message or error case, disconnect and clean up */ + if ((msg == NULL) || + ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END) && + (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)))) + { + if (request_context->peer_cb != NULL) + request_context->peer_cb (request_context->cb_cls, NULL, NULL, 0); + GNUNET_CLIENT_disconnect (request_context->client, GNUNET_NO); + GNUNET_free (request_context); + return; + } + + msize = ntohs (msg->size); + /* Handle incorrect message type or size, disconnect and clean up */ + if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT) || + (msize < sizeof (struct ConnectNotifyMessage))) + { + GNUNET_break (0); + if (request_context->peer_cb != NULL) + request_context->peer_cb (request_context->cb_cls, NULL, NULL, 0); + GNUNET_CLIENT_disconnect (request_context->client, GNUNET_NO); + GNUNET_free (request_context); + return; + } + connect_message = (const struct ConnectNotifyMessage *) msg; + ats_count = ntohl (connect_message->ats_count); + if (msize != + sizeof (struct ConnectNotifyMessage) + + ats_count * sizeof (struct GNUNET_ATS_Information)) + { + GNUNET_break (0); + if (request_context->peer_cb != NULL) + request_context->peer_cb (request_context->cb_cls, NULL, NULL, 0); + GNUNET_CLIENT_disconnect (request_context->client, GNUNET_NO); + GNUNET_free (request_context); + return; + } + /* Normal case */ + if (request_context->peer_cb != NULL) + request_context->peer_cb (request_context->cb_cls, &connect_message->peer, + (const struct GNUNET_ATS_Information *) + &connect_message[1], ats_count); + GNUNET_CLIENT_receive (request_context->client, &receive_info, + request_context, GNUNET_TIME_UNIT_FOREVER_REL); +} + +/** + * Function called to notify a client about the socket + * begin ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_request (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg; + struct GNUNET_PeerIdentity *peer = cls; + int msize; + + if (peer == NULL) + msize = sizeof (struct GNUNET_MessageHeader); + else + msize = + sizeof (struct GNUNET_MessageHeader) + + sizeof (struct GNUNET_PeerIdentity); + + if ((size < msize) || (buf == NULL)) + return 0; + + msg = (struct GNUNET_MessageHeader *) buf; + msg->size = htons (msize); + if (peer != NULL) + { + msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED); + memcpy (&msg[1], peer, sizeof (struct GNUNET_PeerIdentity)); + } + else + msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS); + + return msize; +} + +/** + * Iterate over all currently connected peers. + * Calls peer_cb with each connected peer, and then + * once with NULL to indicate that all peers have + * been handled. + * + * @param cfg configuration to use + * @param peer the specific peer to check for + * @param peer_cb function to call with the peer information + * @param cb_cls closure for peer_cb + * + * @return GNUNET_OK if iterating, GNUNET_SYSERR on error + */ +int +GNUNET_CORE_is_peer_connected (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_PeerIdentity *peer, + GNUNET_CORE_ConnectEventHandler peer_cb, + void *cb_cls) +{ + struct GNUNET_CORE_RequestContext *request_context; + struct GNUNET_CLIENT_Connection *client; + + client = GNUNET_CLIENT_connect ("core", cfg); + if (client == NULL) + return GNUNET_SYSERR; + GNUNET_assert (peer != NULL); + request_context = GNUNET_malloc (sizeof (struct GNUNET_CORE_RequestContext)); + request_context->client = client; + request_context->peer_cb = peer_cb; + request_context->cb_cls = cb_cls; + request_context->peer = peer; + + request_context->th = + GNUNET_CLIENT_notify_transmit_ready (client, + sizeof (struct GNUNET_MessageHeader) + + + sizeof (struct GNUNET_PeerIdentity), + GNUNET_TIME_relative_get_forever (), + GNUNET_YES, &transmit_request, peer); + GNUNET_assert (request_context->th != NULL); + GNUNET_CLIENT_receive (client, &receive_info, request_context, + GNUNET_TIME_relative_get_forever ()); + return GNUNET_OK; +} + +/** + * Iterate over all currently connected peers. + * Calls peer_cb with each connected peer, and then + * once with NULL to indicate that all peers have + * been handled. + * + * @param cfg configuration to use + * @param peer_cb function to call with the peer information + * @param cb_cls closure for peer_cb + * + * @return GNUNET_OK if iterating, GNUNET_SYSERR on error + */ +int +GNUNET_CORE_iterate_peers (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_CORE_ConnectEventHandler peer_cb, + void *cb_cls) +{ + struct GNUNET_CORE_RequestContext *request_context; + struct GNUNET_CLIENT_Connection *client; + + client = GNUNET_CLIENT_connect ("core", cfg); + if (client == NULL) + return GNUNET_SYSERR; + request_context = GNUNET_malloc (sizeof (struct GNUNET_CORE_RequestContext)); + request_context->client = client; + request_context->peer_cb = peer_cb; + request_context->cb_cls = cb_cls; + + request_context->th = + GNUNET_CLIENT_notify_transmit_ready (client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_relative_get_forever (), + GNUNET_YES, &transmit_request, NULL); + + GNUNET_CLIENT_receive (client, &receive_info, request_context, + GNUNET_TIME_relative_get_forever ()); + return GNUNET_OK; +} + +/* end of core_api_iterate_peers.c */ diff --git a/src/core/gnunet-core-list-connections.c b/src/core/gnunet-core-list-connections.c new file mode 100644 index 0000000..fcd0765 --- /dev/null +++ b/src/core/gnunet-core-list-connections.c @@ -0,0 +1,207 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-core-list-connections.c + * @brief Print information about other known _connected_ peers. + * @author Nathan Evans + */ +#include "platform.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_core_service.h" +#include "gnunet_program_lib.h" + +#define VERBOSE 0 +static int no_resolve; + +#if VERBOSE +static unsigned int peer_count; +#endif + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +struct AddressStringList +{ + /** + * Pointer to previous element. + */ + struct AddressStringList *prev; + + /** + * Pointer to next element. + */ + struct AddressStringList *next; + + /** + * Address as string. + */ + char *address_string; +}; + +struct PrintContext +{ + struct GNUNET_PeerIdentity peer; + struct AddressStringList *address_list_head; + struct AddressStringList *address_list_tail; +}; + + +static void +dump_pc (struct PrintContext *pc) +{ + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + struct AddressStringList *address; + + GNUNET_CRYPTO_hash_to_enc (&pc->peer.hashPubKey, &enc); + printf (_("Peer `%s'\n"), (const char *) &enc); + while (NULL != (address = pc->address_list_head)) + { + printf ("\t%s\n", address->address_string); + GNUNET_free (address->address_string); + GNUNET_CONTAINER_DLL_remove (pc->address_list_head, pc->address_list_tail, + address); + GNUNET_free (address); + } + + printf ("\n"); + + GNUNET_free (pc); +} + + +/** + * Function to call with a human-readable format of an address + * + * @param cls closure + * @param peer peer this update is about + * @param address NULL on error, otherwise 0-terminated printable UTF-8 string + */ +static void +process_resolved_address (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address) +{ + struct PrintContext *pc = cls; + +// struct AddressStringList *new_address; + + if (address == NULL) + { + dump_pc (pc); + return; + } + + /* This does exactly the same as gnunet-transport -i ! */ + /* + * new_address = GNUNET_malloc (sizeof (struct AddressStringList)); + * #if VERBOSE + * FPRINTF (stderr, "Received address %s\n", address); + * #endif + * + * new_address->address_string = GNUNET_strdup ("FIXME"); + * GNUNET_CONTAINER_DLL_insert (pc->address_list_head, pc->address_list_tail, + * new_address); + */ +} + + +/** + * Callback for retrieving a list of connected peers. + */ +static void +connected_peer_callback (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct PrintContext *pc; + + if (peer != NULL) /* Not yet finished */ + { +#if VERBOSE + FPRINTF (stderr, "Learned about peer %s\n", GNUNET_i2s (peer)); + peer_count++; +#endif + pc = GNUNET_malloc (sizeof (struct PrintContext)); + pc->peer = *peer; + GNUNET_TRANSPORT_peer_get_active_addresses (cfg, peer, GNUNET_YES, + GNUNET_TIME_UNIT_MINUTES, + &process_resolved_address, pc); + } +#if VERBOSE + else + { + FPRINTF (stderr, "Counted %u total connected peers.\n", peer_count); + } +#endif +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + + cfg = c; + if (args[0] != NULL) + { + FPRINTF (stderr, _("Invalid command line argument `%s'\n"), args[0]); + return; + } + + GNUNET_CORE_iterate_peers (cfg, &connected_peer_callback, NULL); + +} + + +/** + * The main function to obtain peer information. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'n', "numeric", NULL, + gettext_noop ("don't resolve host names"), + 0, &GNUNET_GETOPT_set_one, &no_resolve}, + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-list-connections", + gettext_noop + ("Print information about connected peers."), + options, &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-core-list-connections.c */ diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c new file mode 100644 index 0000000..2eb71c2 --- /dev/null +++ b/src/core/gnunet-service-core.c @@ -0,0 +1,120 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core.c + * @brief high-level P2P messaging + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet-service-core.h" +#include "gnunet-service-core_clients.h" +#include "gnunet-service-core_kx.h" +#include "gnunet-service-core_neighbours.h" +#include "gnunet-service-core_sessions.h" +#include "gnunet-service-core_typemap.h" + + +/** + * Our identity. + */ +struct GNUNET_PeerIdentity GSC_my_identity; + +/** + * Our configuration. + */ +const struct GNUNET_CONFIGURATION_Handle *GSC_cfg; + +/** + * For creating statistics. + */ +struct GNUNET_STATISTICS_Handle *GSC_stats; + + +/** + * Last task run during shutdown. Disconnects us from + * the transport. + */ +static void +cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n"); +#endif + GSC_CLIENTS_done (); + GSC_NEIGHBOURS_done (); + GSC_SESSIONS_done (); + GSC_KX_done (); + GSC_TYPEMAP_done (); + if (GSC_stats != NULL) + { + GNUNET_STATISTICS_destroy (GSC_stats, GNUNET_NO); + GSC_stats = NULL; + } + GSC_cfg = NULL; +} + + +/** + * Initiate core service. + * + * @param cls closure + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + GSC_cfg = c; + GSC_stats = GNUNET_STATISTICS_create ("core", GSC_cfg); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task, + NULL); + GSC_TYPEMAP_init (); + if ((GNUNET_OK != GSC_KX_init ()) || (GNUNET_OK != GSC_NEIGHBOURS_init ())) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + GSC_SESSIONS_init (); + GSC_CLIENTS_init (server); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Core service of `%4s' ready.\n"), + GNUNET_i2s (&GSC_my_identity)); +} + + + +/** + * The main function for the transport service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "core", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-service-core.c */ diff --git a/src/core/gnunet-service-core.h b/src/core/gnunet-service-core.h new file mode 100644 index 0000000..e48ad8b --- /dev/null +++ b/src/core/gnunet-service-core.h @@ -0,0 +1,112 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core.h + * @brief Globals for gnunet-service-core + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_CORE_H +#define GNUNET_SERVICE_CORE_H + +#include "gnunet_statistics_service.h" +#include "core.h" + +/** + * Opaque handle to a client. + */ +struct GSC_Client; + + +/** + * Record kept for each request for transmission issued by a + * client that is still pending. (This struct is used by + * both the 'CLIENTS' and 'SESSIONS' subsystems.) + */ +struct GSC_ClientActiveRequest +{ + + /** + * Active requests are kept in a doubly-linked list of + * the respective target peer. + */ + struct GSC_ClientActiveRequest *next; + + /** + * Active requests are kept in a doubly-linked list of + * the respective target peer. + */ + struct GSC_ClientActiveRequest *prev; + + /** + * Which peer is the message going to be for? + */ + struct GNUNET_PeerIdentity target; + + /** + * Handle to the client. + */ + struct GSC_Client *client_handle; + + /** + * By what time would the client want to see this message out? + */ + struct GNUNET_TIME_Absolute deadline; + + /** + * How important is this request. + */ + uint32_t priority; + + /** + * Has this request been solicited yet? + */ + int was_solicited; + + /** + * How many bytes does the client intend to send? + */ + uint16_t msize; + + /** + * Unique request ID (in big endian). + */ + uint16_t smr_id; + +}; + + +/** + * Our configuration. + */ +extern const struct GNUNET_CONFIGURATION_Handle *GSC_cfg; + +/** + * For creating statistics. + */ +extern struct GNUNET_STATISTICS_Handle *GSC_stats; + +/** + * Our identity. + */ +extern struct GNUNET_PeerIdentity GSC_my_identity; + + +#endif diff --git a/src/core/gnunet-service-core_clients.c b/src/core/gnunet-service-core_clients.c new file mode 100644 index 0000000..4098b45 --- /dev/null +++ b/src/core/gnunet-service-core_clients.c @@ -0,0 +1,887 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core_clients.c + * @brief code for managing interactions with clients of core service + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet-service-core.h" +#include "gnunet-service-core_clients.h" +#include "gnunet-service-core_sessions.h" +#include "gnunet-service-core_typemap.h" +#include "core.h" + + +/** + * How many messages do we queue up at most for optional + * notifications to a client? (this can cause notifications + * about outgoing messages to be dropped). + */ +#define MAX_NOTIFY_QUEUE 1024 + + +/** + * Data structure for each client connected to the core service. + */ +struct GSC_Client +{ + /** + * Clients are kept in a linked list. + */ + struct GSC_Client *next; + + /** + * Clients are kept in a linked list. + */ + struct GSC_Client *prev; + + /** + * Handle for the client with the server API. + */ + struct GNUNET_SERVER_Client *client_handle; + + /** + * Array of the types of messages this peer cares + * about (with "tcnt" entries). Allocated as part + * of this client struct, do not free! + */ + const uint16_t *types; + + /** + * Map of peer identities to active transmission requests of this + * client to the peer (of type 'struct GSC_ClientActiveRequest'). + */ + struct GNUNET_CONTAINER_MultiHashMap *requests; + + /** + * Map containing all peers that this client knows we're connected to. + */ + struct GNUNET_CONTAINER_MultiHashMap *connectmap; + + /** + * Options for messages this client cares about, + * see GNUNET_CORE_OPTION_ values. + */ + uint32_t options; + + /** + * Number of types of incoming messages this client + * specifically cares about. Size of the "types" array. + */ + unsigned int tcnt; + +}; + + +/** + * Head of linked list of our clients. + */ +static struct GSC_Client *client_head; + +/** + * Tail of linked list of our clients. + */ +static struct GSC_Client *client_tail; + +/** + * Context for notifications we need to send to our clients. + */ +static struct GNUNET_SERVER_NotificationContext *notifier; + +/** + * Tokenizer for messages received from clients. + */ +static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst; + + +/** + * Lookup our client struct given the server's client handle. + * + * @param client server client handle to look up + * @return our client handle for the client + */ +static struct GSC_Client * +find_client (struct GNUNET_SERVER_Client *client) +{ + struct GSC_Client *c; + + c = client_head; + while ((c != NULL) && (c->client_handle != client)) + c = c->next; + return c; +} + + +/** + * Send a message to one of our clients. + * + * @param client target for the message + * @param msg message to transmit + * @param can_drop could this message be dropped if the + * client's queue is getting too large? + */ +static void +send_to_client (struct GSC_Client *client, + const struct GNUNET_MessageHeader *msg, int can_drop) +{ +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Preparing to send %u bytes of message of type %u to client.\n", + (unsigned int) ntohs (msg->size), + (unsigned int) ntohs (msg->type)); +#endif + GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle, + msg, can_drop); +} + + +/** + * Send a message to one of our clients. + * + * @param client target for the message + * @param msg message to transmit + * @param can_drop could this message be dropped if the + * client's queue is getting too large? + */ +void +GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg, + int can_drop) +{ + struct GSC_Client *c; + + c = find_client (client); + if (NULL == c) + { + GNUNET_break (0); + return; + } + send_to_client (c, msg, can_drop); +} + + +/** + * Test if the client is interested in messages of the given type. + * + * @param type message type + * @param c client to test + * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not. + */ +static int +type_match (uint16_t type, struct GSC_Client *c) +{ + unsigned int i; + + if (c->tcnt == 0) + return GNUNET_YES; /* peer without handlers matches ALL */ + for (i = 0; i < c->tcnt; i++) + if (type == c->types[i]) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Send a message to all of our current clients that have the right + * options set. + * + * @param sender origin of the message (used to check that this peer is + * known to be connected to the respective client) + * @param msg message to multicast + * @param can_drop can this message be discarded if the queue is too long + * @param options mask to use + * @param type type of the embedded message, 0 for none + */ +static void +send_to_all_clients (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *msg, int can_drop, + int options, uint16_t type) +{ + struct GSC_Client *c; + + for (c = client_head; c != NULL; c = c->next) + { + if ((0 == (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) && + (GNUNET_YES == type_match (type, c))) + continue; /* not the full message, but we'd like the full one! */ + if ((0 == (c->options & options)) && (GNUNET_YES != type_match (type, c))) + continue; /* neither options nor type match permit the message */ +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message to client interested in messages of type %u.\n", + (unsigned int) type); +#endif + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (c->connectmap, + &sender->hashPubKey)); + send_to_client (c, msg, can_drop); + } +} + + +/** + * Handle CORE_INIT request. + * + * @param cls unused + * @param client new client that sent INIT + * @param message the 'struct InitMessage' (presumably) + */ +static void +handle_client_init (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct InitMessage *im; + struct InitReplyMessage irm; + struct GSC_Client *c; + uint16_t msize; + const uint16_t *types; + uint16_t *wtypes; + unsigned int i; + + /* check that we don't have an entry already */ + c = find_client (client); + if (NULL != c) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msize = ntohs (message->size); + if (msize < sizeof (struct InitMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_SERVER_notification_context_add (notifier, client); + im = (const struct InitMessage *) message; + types = (const uint16_t *) &im[1]; + msize -= sizeof (struct InitMessage); + c = GNUNET_malloc (sizeof (struct GSC_Client) + msize); + c->client_handle = client; + c->tcnt = msize / sizeof (uint16_t); + c->options = ntohl (im->options); + c->types = (const uint16_t *) &c[1]; + c->connectmap = GNUNET_CONTAINER_multihashmap_create (16); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_put (c->connectmap, + &GSC_my_identity.hashPubKey, + NULL, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + wtypes = (uint16_t *) & c[1]; + for (i = 0; i < c->tcnt; i++) + wtypes[i] = ntohs (types[i]); + GSC_TYPEMAP_add (wtypes, c->tcnt); + GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c); +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client connecting to core service is interested in %u message types\n", + (unsigned int) c->tcnt); +#endif + /* send init reply message */ + irm.header.size = htons (sizeof (struct InitReplyMessage)); + irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY); + irm.reserved = htonl (0); + irm.my_identity = GSC_my_identity; + send_to_client (c, &irm.header, GNUNET_NO); + GSC_SESSIONS_notify_client_about_sessions (c); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handle CORE_SEND_REQUEST message. + * + * @param cls unused + * @param client new client that sent CORE_SEND_REQUEST + * @param message the 'struct SendMessageRequest' (presumably) + */ +static void +handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct SendMessageRequest *req; + struct GSC_Client *c; + struct GSC_ClientActiveRequest *car; + int is_loopback; + + req = (const struct SendMessageRequest *) message; + c = find_client (client); + if (c == NULL) + { + /* client did not send INIT first! */ + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if (c->requests == NULL) + c->requests = GNUNET_CONTAINER_multihashmap_create (16); +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client asked for transmission to `%s'\n", + GNUNET_i2s (&req->peer)); +#endif + is_loopback = + (0 == + memcmp (&req->peer, &GSC_my_identity, + sizeof (struct GNUNET_PeerIdentity))); + if ((!is_loopback) && + (GNUNET_YES != + GNUNET_CONTAINER_multihashmap_contains (c->connectmap, + &req->peer.hashPubKey))) + { + /* neighbour must have disconnected since request was issued, + * ignore (client will realize it once it processes the + * disconnect notification) */ + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# send requests dropped (disconnected)"), 1, + GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey); + if (car == NULL) + { + /* create new entry */ + car = GNUNET_malloc (sizeof (struct GSC_ClientActiveRequest)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (c->requests, + &req->peer.hashPubKey, + car, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); + car->client_handle = c; + } + else + { + GSC_SESSIONS_dequeue_request (car); + } + car->target = req->peer; + car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline); + car->priority = ntohl (req->priority); + car->msize = ntohs (req->size); + car->smr_id = req->smr_id; + car->was_solicited = GNUNET_NO; + if (is_loopback) + { + /* loopback, satisfy immediately */ + GSC_CLIENTS_solicit_request (car); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + GSC_SESSIONS_queue_request (car); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Closure for the 'client_tokenizer_callback'. + */ +struct TokenizerContext +{ + + /** + * Active request handle for the message. + */ + struct GSC_ClientActiveRequest *car; + + /** + * Is corking allowed (set only once we have the real message). + */ + int cork; + +}; + + +/** + * Handle CORE_SEND request. + * + * @param cls unused + * @param client the client issuing the request + * @param message the "struct SendMessage" + */ +static void +handle_client_send (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct SendMessage *sm; + struct GSC_Client *c; + struct TokenizerContext tc; + uint16_t msize; + + msize = ntohs (message->size); + if (msize < + sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + sm = (const struct SendMessage *) message; + msize -= sizeof (struct SendMessage); + GNUNET_break (0 == ntohl (sm->reserved)); + c = find_client (client); + if (c == NULL) + { + /* client did not send INIT first! */ + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + tc.car = + GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey); + if (NULL == tc.car) + { + /* Must have been that we first approved the request, then got disconnected + * (which triggered removal of the 'car') and now the client gives us a message + * just *before* the client learns about the disconnect. Theoretically, we + * might also now be *again* connected. So this can happen (but should be + * rare). If it does happen, the message is discarded. */ + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# messages discarded (session disconnected)"), + 1, GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (c->requests, + &sm->peer.hashPubKey, + tc.car)); + tc.cork = ntohl (sm->cork); +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client asked for transmission of %u bytes to `%s' %s\n", msize, + GNUNET_i2s (&sm->peer), tc.cork ? "now" : ""); +#endif + GNUNET_SERVER_mst_receive (client_mst, &tc, (const char *) &sm[1], msize, + GNUNET_YES, GNUNET_NO); + if (0 != + memcmp (&tc.car->target, &GSC_my_identity, + sizeof (struct GNUNET_PeerIdentity))) + GSC_SESSIONS_dequeue_request (tc.car); + GNUNET_free (tc.car); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Functions with this signature are called whenever a complete + * message is received by the tokenizer. Used by the 'client_mst' for + * dispatching messages from clients to either the SESSION subsystem + * or other CLIENT (for loopback). + * + * @param cls closure + * @param client reservation request ('struct GSC_ClientActiveRequest') + * @param message the actual message + */ +static void +client_tokenizer_callback (void *cls, void *client, + const struct GNUNET_MessageHeader *message) +{ + struct TokenizerContext *tc = client; + struct GSC_ClientActiveRequest *car = tc->car; + + if (0 == + memcmp (&car->target, &GSC_my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Delivering message of type %u to myself\n", + ntohs (message->type)); +#endif + GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message, + ntohs (message->size), + GNUNET_CORE_OPTION_SEND_FULL_INBOUND | + GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND); + GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message, + sizeof (struct GNUNET_MessageHeader), + GNUNET_CORE_OPTION_SEND_HDR_INBOUND | + GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND); + } + else + { +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Delivering message of type %u to %s\n", ntohs (message->type), + GNUNET_i2s (&car->target)); +#endif + GSC_SESSIONS_transmit (car, message, tc->cork); + } +} + + +/** + * Free client request records. + * + * @param cls NULL + * @param key identity of peer for which this is an active request + * @param value the 'struct GSC_ClientActiveRequest' to free + * @return GNUNET_YES (continue iteration) + */ +static int +destroy_active_client_request (void *cls, const GNUNET_HashCode * key, + void *value) +{ + struct GSC_ClientActiveRequest *car = value; + + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (car-> + client_handle->requests, + &car->target.hashPubKey, + car)); + GSC_SESSIONS_dequeue_request (car); + GNUNET_free (car); + return GNUNET_YES; +} + + +/** + * A client disconnected, clean up. + * + * @param cls closure + * @param client identification of the client + */ +static void +handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct GSC_Client *c; + + if (client == NULL) + return; +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client %p has disconnected from core service.\n", client); +#endif + c = find_client (client); + if (c == NULL) + return; /* client never sent INIT */ + GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c); + if (c->requests != NULL) + { + GNUNET_CONTAINER_multihashmap_iterate (c->requests, + &destroy_active_client_request, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (c->requests); + } + GNUNET_CONTAINER_multihashmap_destroy (c->connectmap); + c->connectmap = NULL; + GSC_TYPEMAP_remove (c->types, c->tcnt); + GNUNET_free (c); +} + + +/** + * Tell a client that we are ready to receive the message. + * + * @param car request that is now ready; the responsibility + * for the handle remains shared between CLIENTS + * and SESSIONS after this call. + */ +void +GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car) +{ + struct GSC_Client *c; + struct SendMessageReady smr; + + c = car->client_handle; + if (GNUNET_YES != + GNUNET_CONTAINER_multihashmap_contains (c->connectmap, + &car->target.hashPubKey)) + { + /* connection has gone down since, drop request */ + GNUNET_assert (0 != + memcmp (&car->target, &GSC_my_identity, + sizeof (struct GNUNET_PeerIdentity))); + GSC_SESSIONS_dequeue_request (car); + GSC_CLIENTS_reject_request (car); + return; + } + smr.header.size = htons (sizeof (struct SendMessageReady)); + smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY); + smr.size = htons (car->msize); + smr.smr_id = car->smr_id; + smr.peer = car->target; + send_to_client (c, &smr.header, GNUNET_NO); +} + + +/** + * Tell a client that we will never be ready to receive the + * given message in time (disconnect or timeout). + * + * @param car request that now permanently failed; the + * responsibility for the handle is now returned + * to CLIENTS (SESSIONS is done with it). + */ +void +GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car) +{ + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (car-> + client_handle->requests, + &car->target.hashPubKey, + car)); + GNUNET_free (car); +} + + +/** + * Notify a particular client about a change to existing connection to + * one of our neighbours (check if the client is interested). Called + * from 'GSC_SESSIONS_notify_client_about_sessions'. + * + * @param client client to notify + * @param neighbour identity of the neighbour that changed status + * @param atsi performance information about neighbour + * @param atsi_count number of entries in 'ats' array + * @param tmap_old previous type map for the neighbour, NULL for disconnect + * @param tmap_new updated type map for the neighbour, NULL for disconnect + */ +void +GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client, + const struct GNUNET_PeerIdentity + *neighbour, + const struct GNUNET_ATS_Information + *atsi, unsigned int atsi_count, + const struct GSC_TypeMap *tmap_old, + const struct GSC_TypeMap *tmap_new) +{ + struct ConnectNotifyMessage *cnm; + size_t size; + char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + struct GNUNET_ATS_Information *a; + struct DisconnectNotifyMessage dcm; + int old_match; + int new_match; + + old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt); + new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt); + if (old_match == new_match) + { + GNUNET_assert (old_match == + GNUNET_CONTAINER_multihashmap_contains (client->connectmap, + &neighbour->hashPubKey)); + return; /* no change */ + } + if (old_match == GNUNET_NO) + { + /* send connect */ + GNUNET_assert (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (client->connectmap, + &neighbour->hashPubKey)); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_put (client->connectmap, + &neighbour->hashPubKey, + NULL, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + size = + sizeof (struct ConnectNotifyMessage) + + (atsi_count) * sizeof (struct GNUNET_ATS_Information); + if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + /* recovery strategy: throw away performance data */ + atsi_count = 0; + size = sizeof (struct ConnectNotifyMessage); + } + cnm = (struct ConnectNotifyMessage *) buf; + cnm->header.size = htons (size); + cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); + cnm->ats_count = htonl (atsi_count); + a = (struct GNUNET_ATS_Information *) &cnm[1]; + memcpy (a, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count); +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n", + "NOTIFY_CONNECT"); +#endif + cnm->peer = *neighbour; + send_to_client (client, &cnm->header, GNUNET_NO); + } + else + { + /* send disconnect */ + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (client->connectmap, + &neighbour->hashPubKey)); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (client->connectmap, + &neighbour->hashPubKey, + NULL)); + dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage)); + dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT); + dcm.reserved = htonl (0); + dcm.peer = *neighbour; + send_to_client (client, &dcm.header, GNUNET_NO); + } +} + + +/** + * Notify all clients about a change to existing session. + * Called from SESSIONS whenever there is a change in sessions + * or types processed by the respective peer. + * + * @param neighbour identity of the neighbour that changed status + * @param atsi performance information about neighbour + * @param atsi_count number of entries in 'ats' array + * @param tmap_old previous type map for the neighbour, NULL for disconnect + * @param tmap_new updated type map for the neighbour, NULL for disconnect + */ +void +GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity + *neighbour, + const struct GNUNET_ATS_Information + *atsi, unsigned int atsi_count, + const struct GSC_TypeMap *tmap_old, + const struct GSC_TypeMap *tmap_new) +{ + struct GSC_Client *c; + + for (c = client_head; c != NULL; c = c->next) + GSC_CLIENTS_notify_client_about_neighbour (c, neighbour, atsi, atsi_count, + tmap_old, tmap_new); +} + + +/** + * Deliver P2P message to interested clients. Caller must have checked + * that the sending peer actually lists the given message type as one + * of its types. + * + * @param sender peer who sent us the message + * @param atsi performance information about neighbour + * @param atsi_count number of entries in 'ats' array + * @param msg the message + * @param msize number of bytes to transmit + * @param options options for checking which clients should + * receive the message + */ +void +GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count, + const struct GNUNET_MessageHeader *msg, + uint16_t msize, int options) +{ + size_t size = + msize + sizeof (struct NotifyTrafficMessage) + + atsi_count * sizeof (struct GNUNET_ATS_Information); + char buf[size]; + struct NotifyTrafficMessage *ntm; + struct GNUNET_ATS_Information *a; + + if (0 == options) + { + GNUNET_snprintf (buf, sizeof (buf), + gettext_noop ("# bytes of messages of type %u received"), + (unsigned int) ntohs (msg->type)); + GNUNET_STATISTICS_update (GSC_stats, buf, msize, GNUNET_NO); + } + if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + /* recovery strategy: throw performance data away... */ + atsi_count = 0; + size = msize + sizeof (struct NotifyTrafficMessage); + } +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core service passes message from `%4s' of type %u to client.\n", + GNUNET_i2s (sender), (unsigned int) ntohs (msg->type)); +#endif + GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type)); + ntm = (struct NotifyTrafficMessage *) buf; + ntm->header.size = htons (size); + ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND); + ntm->ats_count = htonl (atsi_count); + ntm->peer = *sender; + a = &ntm->ats; + memcpy (a, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count); + a[atsi_count].type = htonl (GNUNET_ATS_ARRAY_TERMINATOR); + a[atsi_count].value = htonl (0); + memcpy (&a[atsi_count + 1], msg, msize); + send_to_all_clients (sender, &ntm->header, GNUNET_YES, options, + ntohs (msg->type)); +} + + +/** + * Initialize clients subsystem. + * + * @param server handle to server clients connect to + */ +void +GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_client_init, NULL, + GNUNET_MESSAGE_TYPE_CORE_INIT, 0}, + {&GSC_SESSIONS_handle_client_iterate_peers, NULL, + GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS, + sizeof (struct GNUNET_MessageHeader)}, + {&GSC_SESSIONS_handle_client_have_peer, NULL, + GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED, + sizeof (struct GNUNET_MessageHeader) + + sizeof (struct GNUNET_PeerIdentity)}, + {&handle_client_send_request, NULL, + GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST, + sizeof (struct SendMessageRequest)}, + {&handle_client_send, NULL, + GNUNET_MESSAGE_TYPE_CORE_SEND, 0}, + {NULL, NULL, 0, 0} + }; + + /* setup notification */ + client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL); + notifier = + GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE); + GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); + GNUNET_SERVER_add_handlers (server, handlers); +} + + +/** + * Shutdown clients subsystem. + */ +void +GSC_CLIENTS_done () +{ + struct GSC_Client *c; + + while (NULL != (c = client_head)) + handle_client_disconnect (NULL, c->client_handle); + if (NULL != notifier) + { + GNUNET_SERVER_notification_context_destroy (notifier); + notifier = NULL; + } + GNUNET_SERVER_mst_destroy (client_mst); + client_mst = NULL; +} + +/* end of gnunet-service-core_clients.c */ diff --git a/src/core/gnunet-service-core_clients.h b/src/core/gnunet-service-core_clients.h new file mode 100644 index 0000000..bdad20d --- /dev/null +++ b/src/core/gnunet-service-core_clients.h @@ -0,0 +1,150 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core_clients.h + * @brief code for managing interactions with clients of core service + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_CORE_CLIENTS_H +#define GNUNET_SERVICE_CORE_CLIENTS_H + +#include "gnunet_util_lib.h" +#include "gnunet-service-core.h" +#include "gnunet-service-core_typemap.h" + + +/** + * Send a message to one of our clients. + * + * @param client target for the message + * @param msg message to transmit + * @param can_drop could this message be dropped if the + * client's queue is getting too large? + */ +void +GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg, + int can_drop); + + +/** + * Notify a particular client about a change to existing connection to + * one of our neighbours (check if the client is interested). Called + * from 'GSC_SESSIONS_notify_client_about_sessions'. + * + * @param client client to notify + * @param neighbour identity of the neighbour that changed status + * @param atsi performance information about neighbour + * @param atsi_count number of entries in 'ats' array + * @param tmap_old previous type map for the neighbour, NULL for disconnect + * @param tmap_new updated type map for the neighbour, NULL for disconnect + */ +void +GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client, + const struct GNUNET_PeerIdentity + *neighbour, + const struct GNUNET_ATS_Information + *atsi, unsigned int atsi_count, + const struct GSC_TypeMap *tmap_old, + const struct GSC_TypeMap *tmap_new); + + +/** + * Notify all clients about a change to existing session. + * Called from SESSIONS whenever there is a change in sessions + * or types processed by the respective peer. + * + * @param neighbour identity of the neighbour that changed status + * @param atsi performance information about neighbour + * @param atsi_count number of entries in 'ats' array + * @param tmap_old previous type map for the neighbour, NULL for disconnect + * @param tmap_new updated type map for the neighbour, NULL for disconnect + */ +void +GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity + *neighbour, + const struct GNUNET_ATS_Information + *atsi, unsigned int atsi_count, + const struct GSC_TypeMap *tmap_old, + const struct GSC_TypeMap *tmap_new); + + +/** + * Deliver P2P message to interested clients. Caller must have checked + * that the sending peer actually lists the given message type as one + * of its types. + * + * @param sender peer who sent us the message + * @param atsi performance information about neighbour + * @param atsi_count number of entries in 'ats' array + * @param msg the message + * @param msize number of bytes to transmit + * @param options options for checking which clients should + * receive the message + */ +void +GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count, + const struct GNUNET_MessageHeader *msg, + uint16_t msize, int options); + + +/** + * Tell a client that we are ready to receive the message. + * + * @param car request that is now ready; the responsibility + * for the handle remains shared between CLIENTS + * and SESSIONS after this call. + */ +void +GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car); + + +/** + * Tell a client that we will never be ready to receive the + * given message in time (disconnect or timeout). + * + * @param car request that now permanently failed; the + * responsibility for the handle is now returned + * to CLIENTS (SESSIONS is done with it). + */ +void +GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car); + + +/** + * Initialize clients subsystem. + * + * @param server handle to server clients connect to + */ +void +GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server); + + +/** + * Shutdown clients subsystem. + */ +void +GSC_CLIENTS_done (void); + +#endif +/* end of gnunet-service-core_clients.h */ diff --git a/src/core/gnunet-service-core_kx.c b/src/core/gnunet-service-core_kx.c new file mode 100644 index 0000000..c2acc6b --- /dev/null +++ b/src/core/gnunet-service-core_kx.c @@ -0,0 +1,1579 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core_kx.c + * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other peers + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-core_kx.h" +#include "gnunet-service-core.h" +#include "gnunet-service-core_clients.h" +#include "gnunet-service-core_neighbours.h" +#include "gnunet-service-core_sessions.h" +#include "gnunet_statistics_service.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_constants.h" +#include "gnunet_signatures.h" +#include "gnunet_protocols.h" +#include "core.h" + +/** + * How long do we wait for SET_KEY confirmation initially? + */ +#define INITIAL_SET_KEY_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (MAX_SET_KEY_DELAY, 1) + +/** + * What is the minimum frequency for a PING message? + */ +#define MIN_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +/** + * What is the maximum age of a message for us to consider processing + * it? Note that this looks at the timestamp used by the other peer, + * so clock skew between machines does come into play here. So this + * should be picked high enough so that a little bit of clock skew + * does not prevent peers from connecting to us. + */ +#define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS + +/** + * What is the maximum delay for a SET_KEY message? + */ +#define MAX_SET_KEY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * We're sending an (encrypted) PING to the other peer to check if he + * can decrypt. The other peer should respond with a PONG with the + * same content, except this time encrypted with the receiver's key. + */ +struct PingMessage +{ + /** + * Message type is CORE_PING. + */ + struct GNUNET_MessageHeader header; + + /** + * Seed for the IV + */ + uint32_t iv_seed GNUNET_PACKED; + + /** + * Intended target of the PING, used primarily to check + * that decryption actually worked. + */ + struct GNUNET_PeerIdentity target; + + /** + * Random number chosen to make reply harder. + */ + uint32_t challenge GNUNET_PACKED; +}; + + +/** + * Response to a PING. Includes data from the original PING. + */ +struct PongMessage +{ + /** + * Message type is CORE_PONG. + */ + struct GNUNET_MessageHeader header; + + /** + * Seed for the IV + */ + uint32_t iv_seed GNUNET_PACKED; + + /** + * Random number to make faking the reply harder. Must be + * first field after header (this is where we start to encrypt!). + */ + uint32_t challenge GNUNET_PACKED; + + /** + * Reserved, always 'GNUNET_BANDWIDTH_VALUE_MAX'. + */ + struct GNUNET_BANDWIDTH_Value32NBO reserved; + + /** + * Intended target of the PING, used primarily to check + * that decryption actually worked. + */ + struct GNUNET_PeerIdentity target; +}; + + +/** + * Message transmitted to set (or update) a session key. + */ +struct SetKeyMessage +{ + + /** + * Message type is either CORE_SET_KEY. + */ + struct GNUNET_MessageHeader header; + + /** + * Status of the sender (should be in "enum PeerStateMachine"), nbo. + */ + int32_t sender_status GNUNET_PACKED; + + /** + * Purpose of the signature, will be + * GNUNET_SIGNATURE_PURPOSE_SET_KEY. + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * At what time was this key created? + */ + struct GNUNET_TIME_AbsoluteNBO creation_time; + + /** + * The encrypted session key. + */ + struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; + + /** + * Who is the intended recipient? + */ + struct GNUNET_PeerIdentity target; + + /** + * Signature of the stuff above (starting at purpose). + */ + struct GNUNET_CRYPTO_RsaSignature signature; + +}; + + +/** + * Encapsulation for encrypted messages exchanged between + * peers. Followed by the actual encrypted data. + */ +struct EncryptedMessage +{ + /** + * Message type is either CORE_ENCRYPTED_MESSAGE. + */ + struct GNUNET_MessageHeader header; + + /** + * Random value used for IV generation. + */ + uint32_t iv_seed GNUNET_PACKED; + + /** + * MAC of the encrypted message (starting at 'sequence_number'), + * used to verify message integrity. Everything after this value + * (excluding this value itself) will be encrypted and authenticated. + * ENCRYPTED_HEADER_SIZE must be set to the offset of the *next* field. + */ + GNUNET_HashCode hmac; + + /** + * Sequence number, in network byte order. This field + * must be the first encrypted/decrypted field + */ + uint32_t sequence_number GNUNET_PACKED; + + /** + * Reserved, always 'GNUNET_BANDWIDTH_VALUE_MAX'. + */ + struct GNUNET_BANDWIDTH_Value32NBO reserved; + + /** + * Timestamp. Used to prevent reply of ancient messages + * (recent messages are caught with the sequence number). + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + +}; +GNUNET_NETWORK_STRUCT_END +/** + * Number of bytes (at the beginning) of "struct EncryptedMessage" + * that are NOT encrypted. + */ +#define ENCRYPTED_HEADER_SIZE (offsetof(struct EncryptedMessage, sequence_number)) + + +/** + * State machine for our P2P encryption handshake. Everyone starts in + * "DOWN", if we receive the other peer's key (other peer initiated) + * we start in state RECEIVED (since we will immediately send our + * own); otherwise we start in SENT. If we get back a PONG from + * within either state, we move up to CONFIRMED (the PONG will always + * be sent back encrypted with the key we sent to the other peer). + */ +enum KxStateMachine +{ + /** + * No handshake yet. + */ + KX_STATE_DOWN, + + /** + * We've sent our session key. + */ + KX_STATE_KEY_SENT, + + /** + * We've received the other peers session key. + */ + KX_STATE_KEY_RECEIVED, + + /** + * The other peer has confirmed our session key with a message + * encrypted with his session key (which we got). Key exchange + * is done. + */ + KX_STATE_UP +}; + + +/** + * Information about the status of a key exchange with another peer. + */ +struct GSC_KeyExchangeInfo +{ + /** + * Identity of the peer. + */ + struct GNUNET_PeerIdentity peer; + + /** + * SetKeyMessage to transmit (initialized the first + * time our status goes past 'KX_STATE_KEY_SENT'). + */ + struct SetKeyMessage skm; + + /** + * PING message we transmit to the other peer. + */ + struct PingMessage ping; + + /** + * SetKeyMessage we received and did not process yet. + */ + struct SetKeyMessage *skm_received; + + /** + * PING message we received from the other peer and + * did not process yet (or NULL). + */ + struct PingMessage *ping_received; + + /** + * PONG message we received from the other peer and + * did not process yet (or NULL). + */ + struct PongMessage *pong_received; + + /** + * Encrypted message we received from the other peer and + * did not process yet (or NULL). + */ + struct EncryptedMessage *emsg_received; + + /** + * Non-NULL if we are currently looking up HELLOs for this peer. + * for this peer. + */ + struct GNUNET_PEERINFO_IteratorContext *pitr; + + /** + * Public key of the neighbour, NULL if we don't have it yet. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; + + /** + * We received a PONG message before we got the "public_key" + * (or the SET_KEY). We keep it here until we have a key + * to decrypt it. NULL if no PONG is pending. + */ + struct PongMessage *pending_pong; + + /** + * Key we use to encrypt our messages for the other peer + * (initialized by us when we do the handshake). + */ + struct GNUNET_CRYPTO_AesSessionKey encrypt_key; + + /** + * Key we use to decrypt messages from the other peer + * (given to us by the other peer during the handshake). + */ + struct GNUNET_CRYPTO_AesSessionKey decrypt_key; + + /** + * At what time did we generate our encryption key? + */ + struct GNUNET_TIME_Absolute encrypt_key_created; + + /** + * At what time did the other peer generate the decryption key? + */ + struct GNUNET_TIME_Absolute decrypt_key_created; + + /** + * When should the session time out (if there are no PONGs)? + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * At what frequency are we currently re-trying SET_KEY messages? + */ + struct GNUNET_TIME_Relative set_key_retry_frequency; + + /** + * ID of task used for re-trying SET_KEY and PING message. + */ + GNUNET_SCHEDULER_TaskIdentifier retry_set_key_task; + + /** + * ID of task used for sending keep-alive pings. + */ + GNUNET_SCHEDULER_TaskIdentifier keep_alive_task; + + /** + * Bit map indicating which of the 32 sequence numbers before the last + * were received (good for accepting out-of-order packets and + * estimating reliability of the connection) + */ + unsigned int last_packets_bitmap; + + /** + * last sequence number received on this connection (highest) + */ + uint32_t last_sequence_number_received; + + /** + * last sequence number transmitted + */ + uint32_t last_sequence_number_sent; + + /** + * What was our PING challenge number (for this peer)? + */ + uint32_t ping_challenge; + + /** + * What is our connection status? + */ + enum KxStateMachine status; + +}; + + + +/** + * Handle to peerinfo service. + */ +static struct GNUNET_PEERINFO_Handle *peerinfo; + +/** + * Our private key. + */ +static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; + +/** + * Our public key. + */ +static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; + +/** + * Our message stream tokenizer (for encrypted payload). + */ +static struct GNUNET_SERVER_MessageStreamTokenizer *mst; + + + +/** + * Derive an authentication key from "set key" information + */ +static void +derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey, + const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed, + struct GNUNET_TIME_Absolute creation_time) +{ + static const char ctx[] = "authentication key"; + struct GNUNET_TIME_AbsoluteNBO ctbe; + + + ctbe = GNUNET_TIME_absolute_hton (creation_time); + GNUNET_CRYPTO_hmac_derive_key (akey, skey, &seed, sizeof (seed), &skey->key, + sizeof (skey->key), &ctbe, sizeof (ctbe), ctx, + sizeof (ctx), NULL); +} + + +/** + * Derive an IV from packet information + */ +static void +derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, + const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed, + const struct GNUNET_PeerIdentity *identity) +{ + static const char ctx[] = "initialization vector"; + + GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed), + &identity->hashPubKey.bits, + sizeof (identity->hashPubKey.bits), ctx, + sizeof (ctx), NULL); +} + +/** + * Derive an IV from pong packet information + */ +static void +derive_pong_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, + const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed, + uint32_t challenge, const struct GNUNET_PeerIdentity *identity) +{ + static const char ctx[] = "pong initialization vector"; + + GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed), + &identity->hashPubKey.bits, + sizeof (identity->hashPubKey.bits), &challenge, + sizeof (challenge), ctx, sizeof (ctx), NULL); +} + + +/** + * Encrypt size bytes from in and write the result to out. Use the + * key for outbound traffic of the given neighbour. + * + * @param kx key information context + * @param iv initialization vector to use + * @param in ciphertext + * @param out plaintext + * @param size size of in/out + * @return GNUNET_OK on success + */ +static int +do_encrypt (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_CRYPTO_AesInitializationVector *iv, + const void *in, void *out, size_t size) +{ + if (size != (uint16_t) size) + { + GNUNET_break (0); + return GNUNET_NO; + } + GNUNET_assert (size == + GNUNET_CRYPTO_aes_encrypt (in, (uint16_t) size, + &kx->encrypt_key, iv, out)); + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes encrypted"), size, + GNUNET_NO); +#if DEBUG_CORE > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Encrypted %u bytes for `%4s' using key %u, IV %u\n", + (unsigned int) size, GNUNET_i2s (&kx->peer), + (unsigned int) kx->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv, + sizeof + (iv))); +#endif + return GNUNET_OK; +} + + + + +/** + * Decrypt size bytes from in and write the result to out. Use the + * key for inbound traffic of the given neighbour. This function does + * NOT do any integrity-checks on the result. + * + * @param kx key information context + * @param iv initialization vector to use + * @param in ciphertext + * @param out plaintext + * @param size size of in/out + * @return GNUNET_OK on success + */ +static int +do_decrypt (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_CRYPTO_AesInitializationVector *iv, + const void *in, void *out, size_t size) +{ + if (size != (uint16_t) size) + { + GNUNET_break (0); + return GNUNET_NO; + } + if ((kx->status != KX_STATE_KEY_RECEIVED) && (kx->status != KX_STATE_UP)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (size != + GNUNET_CRYPTO_aes_decrypt (in, (uint16_t) size, &kx->decrypt_key, iv, + out)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes decrypted"), size, + GNUNET_NO); +#if DEBUG_CORE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Decrypted %u bytes from `%4s' using key %u, IV %u\n", + (unsigned int) size, GNUNET_i2s (&kx->peer), + (unsigned int) kx->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv, + sizeof + (*iv))); +#endif + return GNUNET_OK; +} + + +/** + * Send our key (and encrypted PING) to the other peer. + * + * @param kx key exchange context + */ +static void +send_key (struct GSC_KeyExchangeInfo *kx); + + +/** + * Task that will retry "send_key" if our previous attempt failed. + * + * @param cls our 'struct GSC_KeyExchangeInfo' + * @param tc scheduler context + */ +static void +set_key_retry_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GSC_KeyExchangeInfo *kx = cls; + + kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; + kx->set_key_retry_frequency = + GNUNET_TIME_relative_multiply (kx->set_key_retry_frequency, 2); + send_key (kx); +} + + +/** + * PEERINFO is giving us a HELLO for a peer. Add the public key to + * the neighbour's struct and continue with the key exchange. Or, if + * we did not get a HELLO, just do nothing. + * + * @param cls the 'struct GSC_KeyExchangeInfo' to retry sending the key for + * @param peer the peer for which this is the HELLO + * @param hello HELLO message of that peer + * @param err_msg NULL if successful, otherwise contains error message + */ +static void +process_hello (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, const char *err_msg) +{ + struct GSC_KeyExchangeInfo *kx = cls; + struct SetKeyMessage *skm; + + if (err_msg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Error in communication with PEERINFO service\n")); + kx->pitr = NULL; + kx->retry_set_key_task = + GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency, + &set_key_retry_task, kx); + return; + } + if (peer == NULL) + { + kx->pitr = NULL; + if (kx->public_key != NULL) + return; /* done here */ +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to obtain public key for peer `%4s', delaying processing of SET_KEY\n", + GNUNET_i2s (&kx->peer)); +#endif + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# Delayed connecting due to lack of public key"), + 1, GNUNET_NO); + kx->retry_set_key_task = + GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency, + &set_key_retry_task, kx); + return; + } + if (kx->public_key != NULL) + { + /* already have public key, why are we here? */ + GNUNET_break (0); + return; + } + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->retry_set_key_task); + kx->public_key = + GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + if (GNUNET_OK != GNUNET_HELLO_get_key (hello, kx->public_key)) + { + GNUNET_break (0); + GNUNET_free (kx->public_key); + kx->public_key = NULL; + return; + } + send_key (kx); + if (NULL != kx->skm_received) + { + skm = kx->skm_received; + kx->skm_received = NULL; + GSC_KX_handle_set_key (kx, &skm->header); + GNUNET_free (skm); + } +} + + +/** + * Start the key exchange with the given peer. + * + * @param pid identity of the peer to do a key exchange with + * @return key exchange information context + */ +struct GSC_KeyExchangeInfo * +GSC_KX_start (const struct GNUNET_PeerIdentity *pid) +{ + struct GSC_KeyExchangeInfo *kx; + +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initiating key exchange with `%s'\n", + GNUNET_i2s (pid)); +#endif + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# key exchanges initiated"), 1, + GNUNET_NO); + kx = GNUNET_malloc (sizeof (struct GSC_KeyExchangeInfo)); + kx->peer = *pid; + kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY; + kx->pitr = + GNUNET_PEERINFO_iterate (peerinfo, pid, + GNUNET_TIME_UNIT_FOREVER_REL /* timeout? */ , + &process_hello, kx); + return kx; +} + + +/** + * Stop key exchange with the given peer. Clean up key material. + * + * @param kx key exchange to stop + */ +void +GSC_KX_stop (struct GSC_KeyExchangeInfo *kx) +{ + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# key exchanges stopped"), + 1, GNUNET_NO); + if (kx->pitr != NULL) + { + GNUNET_PEERINFO_iterate_cancel (kx->pitr); + kx->pitr = NULL; + } + if (kx->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); + kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; + } + if (kx->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (kx->keep_alive_task); + kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free_non_null (kx->skm_received); + GNUNET_free_non_null (kx->ping_received); + GNUNET_free_non_null (kx->pong_received); + GNUNET_free_non_null (kx->emsg_received); + GNUNET_free_non_null (kx->public_key); + GNUNET_free (kx); +} + + +/** + * We received a SET_KEY message. Validate and update + * our key material and status. + * + * @param kx key exchange status for the corresponding peer + * @param msg the set key message we received + */ +void +GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_MessageHeader *msg) +{ + const struct SetKeyMessage *m; + struct GNUNET_TIME_Absolute t; + struct GNUNET_CRYPTO_AesSessionKey k; + struct PingMessage *ping; + struct PongMessage *pong; + enum KxStateMachine sender_status; + uint16_t size; + + size = ntohs (msg->size); + if (size != sizeof (struct SetKeyMessage)) + { + GNUNET_break_op (0); + return; + } + m = (const struct SetKeyMessage *) msg; + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# session keys received"), + 1, GNUNET_NO); + +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core service receives `%s' request from `%4s'.\n", "SET_KEY", + GNUNET_i2s (&kx->peer)); +#endif + if (kx->public_key == NULL) + { + GNUNET_free_non_null (kx->skm_received); + kx->skm_received = (struct SetKeyMessage *) GNUNET_copy_message (msg); + return; + } + if (0 != + memcmp (&m->target, &GSC_my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("`%s' is for `%s', not for me. Ignoring.\n"), "SET_KEY", + GNUNET_i2s (&m->target)); + return; + } + if ((ntohl (m->purpose.size) != + sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (struct GNUNET_TIME_AbsoluteNBO) + + sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) + + sizeof (struct GNUNET_PeerIdentity)) || + (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_SET_KEY, &m->purpose, + &m->signature, kx->public_key))) + { + /* invalid signature */ + GNUNET_break_op (0); + return; + } + t = GNUNET_TIME_absolute_ntoh (m->creation_time); + if (((kx->status == KX_STATE_KEY_RECEIVED) || (kx->status == KX_STATE_UP)) && + (t.abs_value < kx->decrypt_key_created.abs_value)) + { + /* this could rarely happen due to massive re-ordering of + * messages on the network level, but is most likely either + * a bug or some adversary messing with us. Report. */ + GNUNET_break_op (0); + return; + } + if ((GNUNET_CRYPTO_rsa_decrypt + (my_private_key, &m->encrypted_key, &k, + sizeof (struct GNUNET_CRYPTO_AesSessionKey)) != + sizeof (struct GNUNET_CRYPTO_AesSessionKey)) || + (GNUNET_OK != GNUNET_CRYPTO_aes_check_session_key (&k))) + { + /* failed to decrypt !? */ + GNUNET_break_op (0); + return; + } + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# SET_KEY messages decrypted"), 1, + GNUNET_NO); +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received SET_KEY from `%s'\n", + GNUNET_i2s (&kx->peer)); +#endif + kx->decrypt_key = k; + if (kx->decrypt_key_created.abs_value != t.abs_value) + { + /* fresh key, reset sequence numbers */ + kx->last_sequence_number_received = 0; + kx->last_packets_bitmap = 0; + kx->decrypt_key_created = t; + } + sender_status = (enum KxStateMachine) ntohl (m->sender_status); + + switch (kx->status) + { + case KX_STATE_DOWN: + kx->status = KX_STATE_KEY_RECEIVED; + /* we're not up, so we are already doing 'send_key' */ + break; + case KX_STATE_KEY_SENT: + kx->status = KX_STATE_KEY_RECEIVED; + /* we're not up, so we are already doing 'send_key' */ + break; + case KX_STATE_KEY_RECEIVED: + /* we're not up, so we are already doing 'send_key' */ + break; + case KX_STATE_UP: + if ((sender_status == KX_STATE_DOWN) || + (sender_status == KX_STATE_KEY_SENT)) + send_key (kx); /* we are up, but other peer is not! */ + break; + default: + GNUNET_break (0); + break; + } + if (kx->ping_received != NULL) + { + ping = kx->ping_received; + kx->ping_received = NULL; + GSC_KX_handle_ping (kx, &ping->header); + GNUNET_free (ping); + } + if (kx->pong_received != NULL) + { + pong = kx->pong_received; + kx->pong_received = NULL; + GSC_KX_handle_pong (kx, &pong->header); + GNUNET_free (pong); + } +} + + +/** + * We received a PING message. Validate and transmit + * a PONG message. + * + * @param kx key exchange status for the corresponding peer + * @param msg the encrypted PING message itself + */ +void +GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_MessageHeader *msg) +{ + const struct PingMessage *m; + struct PingMessage t; + struct PongMessage tx; + struct PongMessage tp; + struct GNUNET_CRYPTO_AesInitializationVector iv; + uint16_t msize; + + msize = ntohs (msg->size); + if (msize != sizeof (struct PingMessage)) + { + GNUNET_break_op (0); + return; + } + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# PING messages received"), 1, + GNUNET_NO); + if ((kx->status != KX_STATE_KEY_RECEIVED) && (kx->status != KX_STATE_UP)) + { + /* defer */ + GNUNET_free_non_null (kx->ping_received); + kx->ping_received = (struct PingMessage *) GNUNET_copy_message (msg); + return; + } + m = (const struct PingMessage *) msg; +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core service receives `%s' request from `%4s'.\n", "PING", + GNUNET_i2s (&kx->peer)); +#endif + derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity); + if (GNUNET_OK != + do_decrypt (kx, &iv, &m->target, &t.target, + sizeof (struct PingMessage) - ((void *) &m->target - + (void *) m))) + { + GNUNET_break_op (0); + return; + } + if (0 != + memcmp (&t.target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) + { + char sender[9]; + char peer[9]; + + GNUNET_snprintf (sender, sizeof (sender), "%8s", GNUNET_i2s (&kx->peer)); + GNUNET_snprintf (peer, sizeof (peer), "%8s", GNUNET_i2s (&t.target)); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Received PING from `%s' for different identity: I am `%s', PONG identity: `%s'\n"), + sender, GNUNET_i2s (&GSC_my_identity), peer); + GNUNET_break_op (0); + return; + } +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received PING from `%s'\n", + GNUNET_i2s (&kx->peer)); +#endif + /* construct PONG */ + tx.reserved = GNUNET_BANDWIDTH_VALUE_MAX; + tx.challenge = t.challenge; + tx.target = t.target; + tp.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PONG); + tp.header.size = htons (sizeof (struct PongMessage)); + tp.iv_seed = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + derive_pong_iv (&iv, &kx->encrypt_key, tp.iv_seed, t.challenge, &kx->peer); + do_encrypt (kx, &iv, &tx.challenge, &tp.challenge, + sizeof (struct PongMessage) - ((void *) &tp.challenge - + (void *) &tp)); + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# PONG messages created"), + 1, GNUNET_NO); + GSC_NEIGHBOURS_transmit (&kx->peer, &tp.header, + GNUNET_TIME_UNIT_FOREVER_REL /* FIXME: timeout */ ); +} + + +/** + * Create a fresh SET KEY message for transmission to the other peer. + * Also creates a new key. + * + * @param kx key exchange context to create SET KEY message for + */ +static void +setup_fresh_setkey (struct GSC_KeyExchangeInfo *kx) +{ + struct SetKeyMessage *skm; + + GNUNET_CRYPTO_aes_create_session_key (&kx->encrypt_key); + kx->encrypt_key_created = GNUNET_TIME_absolute_get (); + skm = &kx->skm; + skm->header.size = htons (sizeof (struct SetKeyMessage)); + skm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SET_KEY); + skm->purpose.size = + htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (struct GNUNET_TIME_AbsoluteNBO) + + sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) + + sizeof (struct GNUNET_PeerIdentity)); + skm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_KEY); + skm->creation_time = GNUNET_TIME_absolute_hton (kx->encrypt_key_created); + skm->target = kx->peer; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_encrypt (&kx->encrypt_key, + sizeof (struct + GNUNET_CRYPTO_AesSessionKey), + kx->public_key, + &skm->encrypted_key)); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (my_private_key, &skm->purpose, + &skm->signature)); +} + + +/** + * Create a fresh PING message for transmission to the other peer. + * + * @param kx key exchange context to create PING for + */ +static void +setup_fresh_ping (struct GSC_KeyExchangeInfo *kx) +{ + struct PingMessage pp; + struct PingMessage *pm; + struct GNUNET_CRYPTO_AesInitializationVector iv; + + pm = &kx->ping; + pm->header.size = htons (sizeof (struct PingMessage)); + pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING); + pm->iv_seed = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + derive_iv (&iv, &kx->encrypt_key, pm->iv_seed, &kx->peer); + pp.challenge = kx->ping_challenge; + pp.target = kx->peer; + do_encrypt (kx, &iv, &pp.target, &pm->target, + sizeof (struct PingMessage) - ((void *) &pm->target - + (void *) pm)); +} + + +/** + * Task triggered when a neighbour entry is about to time out + * (and we should prevent this by sending a PING). + * + * @param cls the 'struct GSC_KeyExchangeInfo' + * @param tc scheduler context (not used) + */ +static void +send_keep_alive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GSC_KeyExchangeInfo *kx = cls; + struct GNUNET_TIME_Relative retry; + struct GNUNET_TIME_Relative left; + + kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK; + left = GNUNET_TIME_absolute_get_remaining (kx->timeout); + if (left.rel_value == 0) + { + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# sessions terminated by timeout"), + 1, GNUNET_NO); + GSC_SESSIONS_end (&kx->peer); + kx->status = KX_STATE_DOWN; + return; + } +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending KEEPALIVE to `%s'\n", + GNUNET_i2s (&kx->peer)); +#endif + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# keepalive messages sent"), 1, + GNUNET_NO); + setup_fresh_ping (kx); + GSC_NEIGHBOURS_transmit (&kx->peer, &kx->ping.header, + kx->set_key_retry_frequency); + retry = + GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2), + MIN_PING_FREQUENCY); + kx->keep_alive_task = + GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, kx); +} + + +/** + * We've seen a valid message from the other peer. + * Update the time when the session would time out + * and delay sending our keep alive message further. + * + * @param kx key exchange where we saw activity + */ +static void +update_timeout (struct GSC_KeyExchangeInfo *kx) +{ + kx->timeout = + GNUNET_TIME_relative_to_absolute + (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + if (kx->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (kx->keep_alive_task); + kx->keep_alive_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide + (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + 2), &send_keep_alive, kx); +} + + +/** + * We received a PONG message. Validate and update our status. + * + * @param kx key exchange context for the the PONG + * @param msg the encrypted PONG message itself + */ +void +GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_MessageHeader *msg) +{ + const struct PongMessage *m; + struct PongMessage t; + struct EncryptedMessage *emsg; + struct GNUNET_CRYPTO_AesInitializationVector iv; + uint16_t msize; + + msize = ntohs (msg->size); + if (msize != sizeof (struct PongMessage)) + { + GNUNET_break_op (0); + return; + } + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# PONG messages received"), 1, + GNUNET_NO); + if ((kx->status != KX_STATE_KEY_RECEIVED) && (kx->status != KX_STATE_UP)) + { + if (kx->status == KX_STATE_KEY_SENT) + { + GNUNET_free_non_null (kx->pong_received); + kx->pong_received = (struct PongMessage *) GNUNET_copy_message (msg); + } + return; + } + m = (const struct PongMessage *) msg; +#if DEBUG_HANDSHAKE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core service receives `%s' response from `%4s'.\n", "PONG", + GNUNET_i2s (&kx->peer)); +#endif + /* mark as garbage, just to be sure */ + memset (&t, 255, sizeof (t)); + derive_pong_iv (&iv, &kx->decrypt_key, m->iv_seed, kx->ping_challenge, + &GSC_my_identity); + if (GNUNET_OK != + do_decrypt (kx, &iv, &m->challenge, &t.challenge, + sizeof (struct PongMessage) - ((void *) &m->challenge - + (void *) m))) + { + GNUNET_break_op (0); + return; + } + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# PONG messages decrypted"), 1, + GNUNET_NO); + if ((0 != memcmp (&t.target, &kx->peer, sizeof (struct GNUNET_PeerIdentity))) + || (kx->ping_challenge != t.challenge)) + { + /* PONG malformed */ +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received malformed `%s' wanted sender `%4s' with challenge %u\n", + "PONG", GNUNET_i2s (&kx->peer), + (unsigned int) kx->ping_challenge); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received malformed `%s' received from `%4s' with challenge %u\n", + "PONG", GNUNET_i2s (&t.target), (unsigned int) t.challenge); +#endif + return; + } +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received PONG from `%s'\n", + GNUNET_i2s (&kx->peer)); +#endif + switch (kx->status) + { + case KX_STATE_DOWN: + GNUNET_break (0); /* should be impossible */ + return; + case KX_STATE_KEY_SENT: + GNUNET_break (0); /* should be impossible */ + return; + case KX_STATE_KEY_RECEIVED: + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# session keys confirmed via PONG"), 1, + GNUNET_NO); + kx->status = KX_STATE_UP; + GSC_SESSIONS_create (&kx->peer, kx); + if (GNUNET_SCHEDULER_NO_TASK != kx->retry_set_key_task) + { + GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); + kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_assert (kx->keep_alive_task == GNUNET_SCHEDULER_NO_TASK); + if (kx->emsg_received != NULL) + { + emsg = kx->emsg_received; + kx->emsg_received = NULL; + GSC_KX_handle_encrypted_message (kx, &emsg->header, NULL, + 0 /* FIXME: ATSI */ ); + GNUNET_free (emsg); + } + update_timeout (kx); + break; + case KX_STATE_UP: + update_timeout (kx); + break; + default: + GNUNET_break (0); + break; + } +} + + +/** + * Send our key (and encrypted PING) to the other peer. + * + * @param kx key exchange context + */ +static void +send_key (struct GSC_KeyExchangeInfo *kx) +{ + GNUNET_assert (kx->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK); + if (KX_STATE_UP == kx->status) + return; /* nothing to do */ + if (kx->public_key == NULL) + { + /* lookup public key, then try again */ +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying to obtain public key for `%s'\n", + GNUNET_i2s (&kx->peer)); +#endif + kx->pitr = + GNUNET_PEERINFO_iterate (peerinfo, &kx->peer, + GNUNET_TIME_UNIT_FOREVER_REL /* timeout? */ , + &process_hello, kx); + return; + } + + /* update status */ + switch (kx->status) + { + case KX_STATE_DOWN: + kx->status = KX_STATE_KEY_SENT; + /* setup SET KEY message */ + setup_fresh_setkey (kx); + setup_fresh_ping (kx); + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# SET_KEY and PING messages created"), 1, + GNUNET_NO); + break; + case KX_STATE_KEY_SENT: + break; + case KX_STATE_KEY_RECEIVED: + break; + case KX_STATE_UP: + GNUNET_break (0); + return; + default: + GNUNET_break (0); + return; + } + + /* always update sender status in SET KEY message */ + kx->skm.sender_status = htonl ((int32_t) kx->status); +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SET_KEY and PING to `%s'\n", + GNUNET_i2s (&kx->peer)); +#endif + GSC_NEIGHBOURS_transmit (&kx->peer, &kx->skm.header, + kx->set_key_retry_frequency); + GSC_NEIGHBOURS_transmit (&kx->peer, &kx->ping.header, + kx->set_key_retry_frequency); + kx->retry_set_key_task = + GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency, + &set_key_retry_task, kx); +} + + +/** + * Encrypt and transmit a message with the given payload. + * + * @param kx key exchange context + * @param payload payload of the message + * @param payload_size number of bytes in 'payload' + */ +void +GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx, + const void *payload, size_t payload_size) +{ + size_t used = payload_size + sizeof (struct EncryptedMessage); + char pbuf[used]; /* plaintext */ + char cbuf[used]; /* ciphertext */ + struct EncryptedMessage *em; /* encrypted message */ + struct EncryptedMessage *ph; /* plaintext header */ + struct GNUNET_CRYPTO_AesInitializationVector iv; + struct GNUNET_CRYPTO_AuthKey auth_key; + + ph = (struct EncryptedMessage *) pbuf; + ph->iv_seed = + htonl (GNUNET_CRYPTO_random_u32 + (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX)); + ph->sequence_number = htonl (++kx->last_sequence_number_sent); + ph->reserved = GNUNET_BANDWIDTH_VALUE_MAX; + ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + memcpy (&ph[1], payload, payload_size); + + em = (struct EncryptedMessage *) cbuf; + em->header.size = htons (used); + em->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE); + em->iv_seed = ph->iv_seed; + derive_iv (&iv, &kx->encrypt_key, ph->iv_seed, &kx->peer); + GNUNET_assert (GNUNET_OK == + do_encrypt (kx, &iv, &ph->sequence_number, + &em->sequence_number, + used - ENCRYPTED_HEADER_SIZE)); +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted %u bytes for %s\n", + used - ENCRYPTED_HEADER_SIZE, GNUNET_i2s (&kx->peer)); +#endif + derive_auth_key (&auth_key, &kx->encrypt_key, ph->iv_seed, + kx->encrypt_key_created); + GNUNET_CRYPTO_hmac (&auth_key, &em->sequence_number, + used - ENCRYPTED_HEADER_SIZE, &em->hmac); + GSC_NEIGHBOURS_transmit (&kx->peer, &em->header, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Closure for 'deliver_message' + */ +struct DeliverMessageContext +{ + + /** + * Performance information for the connection. + */ + const struct GNUNET_ATS_Information *atsi; + + /** + * Sender of the message. + */ + const struct GNUNET_PeerIdentity *peer; + + /** + * Number of entries in 'atsi' array. + */ + uint32_t atsi_count; +}; + + +/** + * We received an encrypted message. Decrypt, validate and + * pass on to the appropriate clients. + * + * @param kx key exchange context for encrypting the message + * @param msg encrypted message + * @param atsi performance data + * @param atsi_count number of entries in ats (excluding 0-termination) + */ +void +GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_MessageHeader *msg, + const struct GNUNET_ATS_Information *atsi, + uint32_t atsi_count) +{ + const struct EncryptedMessage *m; + struct EncryptedMessage *pt; /* plaintext */ + GNUNET_HashCode ph; + uint32_t snum; + struct GNUNET_TIME_Absolute t; + struct GNUNET_CRYPTO_AesInitializationVector iv; + struct GNUNET_CRYPTO_AuthKey auth_key; + struct DeliverMessageContext dmc; + uint16_t size = ntohs (msg->size); + char buf[size]; + + if (size < + sizeof (struct EncryptedMessage) + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return; + } + m = (const struct EncryptedMessage *) msg; + if ((kx->status != KX_STATE_KEY_RECEIVED) && (kx->status != KX_STATE_UP)) + { + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# failed to decrypt message (no session key)"), + 1, GNUNET_NO); + return; + } + if (kx->status == KX_STATE_KEY_RECEIVED) + { + /* defer */ + GNUNET_free_non_null (kx->ping_received); + kx->emsg_received = (struct EncryptedMessage *) GNUNET_copy_message (msg); + return; + } + /* validate hash */ + derive_auth_key (&auth_key, &kx->decrypt_key, m->iv_seed, + kx->decrypt_key_created); + GNUNET_CRYPTO_hmac (&auth_key, &m->sequence_number, + size - ENCRYPTED_HEADER_SIZE, &ph); + if (0 != memcmp (&ph, &m->hmac, sizeof (GNUNET_HashCode))) + { + /* checksum failed */ + GNUNET_break_op (0); + return; + } + derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity); + /* decrypt */ + if (GNUNET_OK != + do_decrypt (kx, &iv, &m->sequence_number, &buf[ENCRYPTED_HEADER_SIZE], + size - ENCRYPTED_HEADER_SIZE)) + return; +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypted %u bytes from %s\n", + size - ENCRYPTED_HEADER_SIZE, GNUNET_i2s (&kx->peer)); +#endif + pt = (struct EncryptedMessage *) buf; + + /* validate sequence number */ + snum = ntohl (pt->sequence_number); + if (kx->last_sequence_number_received == snum) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received duplicate message, ignoring.\n"); + /* duplicate, ignore */ + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# bytes dropped (duplicates)"), + size, GNUNET_NO); + return; + } + if ((kx->last_sequence_number_received > snum) && + (kx->last_sequence_number_received - snum > 32)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received ancient out of sequence message, ignoring.\n"); + /* ancient out of sequence, ignore */ + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# bytes dropped (out of sequence)"), size, + GNUNET_NO); + return; + } + if (kx->last_sequence_number_received > snum) + { + unsigned int rotbit = 1 << (kx->last_sequence_number_received - snum - 1); + + if ((kx->last_packets_bitmap & rotbit) != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received duplicate message, ignoring.\n"); + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# bytes dropped (duplicates)"), + size, GNUNET_NO); + /* duplicate, ignore */ + return; + } + kx->last_packets_bitmap |= rotbit; + } + if (kx->last_sequence_number_received < snum) + { + unsigned int shift = (snum - kx->last_sequence_number_received); + + if (shift >= 8 * sizeof (kx->last_packets_bitmap)) + kx->last_packets_bitmap = 0; + else + kx->last_packets_bitmap <<= shift; + kx->last_sequence_number_received = snum; + } + + /* check timestamp */ + t = GNUNET_TIME_absolute_ntoh (pt->timestamp); + if (GNUNET_TIME_absolute_get_duration (t).rel_value > + MAX_MESSAGE_AGE.rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Message received far too old (%llu ms). Content ignored.\n"), + GNUNET_TIME_absolute_get_duration (t).rel_value); + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# bytes dropped (ancient message)"), size, + GNUNET_NO); + return; + } + + /* process decrypted message(s) */ + update_timeout (kx); + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# bytes of payload decrypted"), + size - sizeof (struct EncryptedMessage), GNUNET_NO); + dmc.atsi = atsi; + dmc.atsi_count = atsi_count; + dmc.peer = &kx->peer; + if (GNUNET_OK != + GNUNET_SERVER_mst_receive (mst, &dmc, + &buf[sizeof (struct EncryptedMessage)], + size - sizeof (struct EncryptedMessage), + GNUNET_YES, GNUNET_NO)) + GNUNET_break_op (0); +} + + +/** + * Deliver P2P message to interested clients. + * Invokes send twice, once for clients that want the full message, and once + * for clients that only want the header + * + * @param cls always NULL + * @param client who sent us the message (struct GSC_KeyExchangeInfo) + * @param m the message + */ +static void +deliver_message (void *cls, void *client, const struct GNUNET_MessageHeader *m) +{ + struct DeliverMessageContext *dmc = client; + + switch (ntohs (m->type)) + { + case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP: + case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP: + GSC_SESSIONS_set_typemap (dmc->peer, m); + return; + default: + GSC_CLIENTS_deliver_message (dmc->peer, dmc->atsi, dmc->atsi_count, m, + ntohs (m->size), + GNUNET_CORE_OPTION_SEND_FULL_INBOUND); + GSC_CLIENTS_deliver_message (dmc->peer, dmc->atsi, dmc->atsi_count, m, + sizeof (struct GNUNET_MessageHeader), + GNUNET_CORE_OPTION_SEND_HDR_INBOUND); + } +} + + +/** + * Initialize KX subsystem. + * + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GSC_KX_init () +{ + char *keyfile; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (GSC_cfg, "GNUNETD", "HOSTKEY", + &keyfile)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Core service is lacking HOSTKEY configuration setting. Exiting.\n")); + return GNUNET_SYSERR; + } + my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_free (keyfile); + if (my_private_key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Core service could not access hostkey. Exiting.\n")); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); + GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), + &GSC_my_identity.hashPubKey); + peerinfo = GNUNET_PEERINFO_connect (GSC_cfg); + if (NULL == peerinfo) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access PEERINFO service. Exiting.\n")); + GNUNET_CRYPTO_rsa_key_free (my_private_key); + my_private_key = NULL; + return GNUNET_SYSERR; + } + mst = GNUNET_SERVER_mst_create (&deliver_message, NULL); + return GNUNET_OK; +} + + +/** + * Shutdown KX subsystem. + */ +void +GSC_KX_done () +{ + if (my_private_key != NULL) + { + GNUNET_CRYPTO_rsa_key_free (my_private_key); + my_private_key = NULL; + } + if (peerinfo != NULL) + { + GNUNET_PEERINFO_disconnect (peerinfo); + peerinfo = NULL; + } + if (mst != NULL) + { + GNUNET_SERVER_mst_destroy (mst); + mst = NULL; + } +} + +/* end of gnunet-service-core_kx.c */ diff --git a/src/core/gnunet-service-core_kx.h b/src/core/gnunet-service-core_kx.h new file mode 100644 index 0000000..5ecd2c1 --- /dev/null +++ b/src/core/gnunet-service-core_kx.h @@ -0,0 +1,137 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core_kx.h + * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other peers + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_CORE_KX_H +#define GNUNET_SERVICE_CORE_KX_H + +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" + + +/** + * Information about the status of a key exchange with another peer. + */ +struct GSC_KeyExchangeInfo; + + +/** + * We received a SET_KEY message. Validate and update + * our key material and status. + * + * @param kx key exchange status for the corresponding peer + * @param msg the set key message we received + */ +void +GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_MessageHeader *msg); + + +/** + * We received a PING message. Validate and transmit + * a PONG message. + * + * @param kx key exchange status for the corresponding peer + * @param msg the encrypted PING message itself + */ +void +GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_MessageHeader *msg); + + +/** + * We received a PONG message. Validate and update our status. + * + * @param kx key exchange status for the corresponding peer + * @param msg the encrypted PONG message itself + */ +void +GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_MessageHeader *msg); + + +/** + * Encrypt and transmit a message with the given payload. + * + * @param kx key exchange context + * @param payload payload of the message + * @param payload_size number of bytes in 'payload' + */ +void +GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx, + const void *payload, size_t payload_size); + + +/** + * We received an encrypted message. Decrypt, validate and + * pass on to the appropriate clients. + * + * @param kx key exchange information context + * @param msg encrypted message + * @param atsi performance data + * @param atsi_count number of entries in ats (excluding 0-termination) + */ +void +GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_MessageHeader *msg, + const struct GNUNET_ATS_Information *atsi, + uint32_t atsi_count); + + +/** + * Start the key exchange with the given peer. + * + * @param pid identity of the peer to do a key exchange with + * @return key exchange information context + */ +struct GSC_KeyExchangeInfo * +GSC_KX_start (const struct GNUNET_PeerIdentity *pid); + + +/** + * Stop key exchange with the given peer. Clean up key material. + * + * @param kx key exchange to stop + */ +void +GSC_KX_stop (struct GSC_KeyExchangeInfo *kx); + + +/** + * Initialize KX subsystem. + * + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GSC_KX_init (void); + + +/** + * Shutdown KX subsystem. + */ +void +GSC_KX_done (void); + +#endif +/* end of gnunet-service-core_kx.h */ diff --git a/src/core/gnunet-service-core_neighbours.c b/src/core/gnunet-service-core_neighbours.c new file mode 100644 index 0000000..c4db40a --- /dev/null +++ b/src/core/gnunet-service-core_neighbours.c @@ -0,0 +1,528 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core_neighbours.c + * @brief code for managing low-level 'plaintext' connections with transport (key exchange may or may not be done yet) + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet-service-core.h" +#include "gnunet-service-core_neighbours.h" +#include "gnunet-service-core_kx.h" +#include "gnunet-service-core_sessions.h" +#include "gnunet_constants.h" + + +/** + * Message ready for transmission via transport service. This struct + * is followed by the actual content of the message. + */ +struct NeighbourMessageEntry +{ + + /** + * We keep messages in a doubly linked list. + */ + struct NeighbourMessageEntry *next; + + /** + * We keep messages in a doubly linked list. + */ + struct NeighbourMessageEntry *prev; + + /** + * By when are we supposed to transmit this message? + */ + struct GNUNET_TIME_Absolute deadline; + + /** + * How long is the message? (number of bytes following the "struct + * MessageEntry", but not including the size of "struct + * MessageEntry" itself!) + */ + size_t size; + +}; + + +/** + * Data kept per transport-connected peer. + */ +struct Neighbour +{ + + /** + * Head of the batched message queue (already ordered, transmit + * starting with the head). + */ + struct NeighbourMessageEntry *message_head; + + /** + * Tail of the batched message queue (already ordered, append new + * messages to tail). + */ + struct NeighbourMessageEntry *message_tail; + + /** + * Handle for pending requests for transmission to this peer + * with the transport service. NULL if no request is pending. + */ + struct GNUNET_TRANSPORT_TransmitHandle *th; + + /** + * Information about the key exchange with the other peer. + */ + struct GSC_KeyExchangeInfo *kxinfo; + + /** + * Identity of the other peer. + */ + struct GNUNET_PeerIdentity peer; + + /** + * ID of task used for re-trying plaintext scheduling. + */ + GNUNET_SCHEDULER_TaskIdentifier retry_plaintext_task; + +}; + + +/** + * Map of peer identities to 'struct Neighbour'. + */ +static struct GNUNET_CONTAINER_MultiHashMap *neighbours; + +/** + * Transport service. + */ +static struct GNUNET_TRANSPORT_Handle *transport; + + +/** + * Find the entry for the given neighbour. + * + * @param peer identity of the neighbour + * @return NULL if we are not connected, otherwise the + * neighbour's entry. + */ +static struct Neighbour * +find_neighbour (const struct GNUNET_PeerIdentity *peer) +{ + return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey); +} + + +/** + * Free the given entry for the neighbour. + * + * @param n neighbour to free + */ +static void +free_neighbour (struct Neighbour *n) +{ + struct NeighbourMessageEntry *m; + +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Destroying neighbour entry for peer `%4s'\n", + GNUNET_i2s (&n->peer)); +#endif + while (NULL != (m = n->message_head)) + { + GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m); + GNUNET_free (m); + } + if (NULL != n->th) + { + GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th); + n->th = NULL; + } + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# sessions terminated by transport disconnect"), + 1, GNUNET_NO); + GSC_SESSIONS_end (&n->peer); + if (NULL != n->kxinfo) + { + GSC_KX_stop (n->kxinfo); + n->kxinfo = NULL; + } + if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (n->retry_plaintext_task); + n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (neighbours, + &n->peer.hashPubKey, n)); + GNUNET_STATISTICS_set (GSC_stats, + gettext_noop ("# neighbour entries allocated"), + GNUNET_CONTAINER_multihashmap_size (neighbours), + GNUNET_NO); + GNUNET_free (n); +} + + +/** + * Check if we have encrypted messages for the specified neighbour + * pending, and if so, check with the transport about sending them + * out. + * + * @param n neighbour to check. + */ +static void +process_queue (struct Neighbour *n); + + +/** + * Function called when the transport service is ready to receive a + * message for the respective peer + * + * @param cls neighbour to use message from + * @param size number of bytes we can transmit + * @param buf where to copy the message + * @return number of bytes transmitted + */ +static size_t +transmit_ready (void *cls, size_t size, void *buf) +{ + struct Neighbour *n = cls; + struct NeighbourMessageEntry *m; + size_t ret; + char *cbuf; + + n->th = NULL; + m = n->message_head; + if (m == NULL) + { + GNUNET_break (0); + return 0; + } + GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m); + if (buf == NULL) + { +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmission of message of type %u and size %u failed\n", + (unsigned int) + ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), + (unsigned int) m->size); +#endif + GNUNET_free (m); + process_queue (n); + return 0; + } + cbuf = buf; + GNUNET_assert (size >= m->size); + memcpy (cbuf, &m[1], m->size); + ret = m->size; +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copied message of type %u and size %u into transport buffer for `%4s'\n", + (unsigned int) + ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), + (unsigned int) ret, GNUNET_i2s (&n->peer)); +#endif + GNUNET_free (m); + process_queue (n); + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# encrypted bytes given to transport"), ret, + GNUNET_NO); + return ret; +} + + +/** + * Check if we have messages for the specified neighbour pending, and + * if so, check with the transport about sending them out. + * + * @param n neighbour to check. + */ +static void +process_queue (struct Neighbour *n) +{ + struct NeighbourMessageEntry *m; + + if (n->th != NULL) + return; /* request already pending */ + m = n->message_head; + if (m == NULL) + { + /* notify sessions that the queue is empty and more messages + * could thus be queued now */ + GSC_SESSIONS_solicit (&n->peer); + return; + } +#if DEBUG_CORE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n", + (unsigned int) m->size, GNUNET_i2s (&n->peer), + (unsigned long long) + GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value); +#endif + n->th = + GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size, 0, + GNUNET_TIME_absolute_get_remaining + (m->deadline), &transmit_ready, + n); + if (n->th != NULL) + return; + /* message request too large or duplicate request */ + GNUNET_break (0); + /* discard encrypted message */ + GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m); + GNUNET_free (m); + process_queue (n); +} + + + +/** + * Function called by transport to notify us that + * a peer connected to us (on the network level). + * + * @param cls closure + * @param peer the peer that connected + * @param atsi performance data + * @param atsi_count number of entries in ats (excluding 0-termination) + */ +static void +handle_transport_notify_connect (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + uint32_t atsi_count) +{ + struct Neighbour *n; + + if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break (0); + return; + } + n = find_neighbour (peer); + if (n != NULL) + { + /* duplicate connect notification!? */ + GNUNET_break (0); + return; + } +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received connection from `%4s'.\n", + GNUNET_i2s (peer)); +#endif + n = GNUNET_malloc (sizeof (struct Neighbour)); + n->peer = *peer; + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (neighbours, + &n->peer.hashPubKey, n, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + GNUNET_STATISTICS_set (GSC_stats, + gettext_noop ("# neighbour entries allocated"), + GNUNET_CONTAINER_multihashmap_size (neighbours), + GNUNET_NO); + n->kxinfo = GSC_KX_start (peer); +} + + +/** + * Function called by transport telling us that a peer + * disconnected. + * + * @param cls closure + * @param peer the peer that disconnected + */ +static void +handle_transport_notify_disconnect (void *cls, + const struct GNUNET_PeerIdentity *peer) +{ + struct Neighbour *n; + +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer `%4s' disconnected from us; received notification from transport.\n", + GNUNET_i2s (peer)); +#endif + n = find_neighbour (peer); + if (n == NULL) + { + GNUNET_break (0); + return; + } + free_neighbour (n); +} + + +/** + * Function called by the transport for each received message. + * + * @param cls closure + * @param peer (claimed) identity of the other peer + * @param message the message + * @param atsi performance data + * @param atsi_count number of entries in ats (excluding 0-termination) + */ +static void +handle_transport_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + uint32_t atsi_count) +{ + struct Neighbour *n; + uint16_t type; + +#if DEBUG_CORE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received message of type %u from `%4s', demultiplexing.\n", + (unsigned int) ntohs (message->type), GNUNET_i2s (peer)); +#endif + if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break (0); + return; + } + n = find_neighbour (peer); + if (n == NULL) + { + /* received message from peer that is not connected!? */ + GNUNET_break (0); + return; + } + type = ntohs (message->type); + switch (type) + { + case GNUNET_MESSAGE_TYPE_CORE_SET_KEY: + GSC_KX_handle_set_key (n->kxinfo, message); + break; + case GNUNET_MESSAGE_TYPE_CORE_PING: + GSC_KX_handle_ping (n->kxinfo, message); + break; + case GNUNET_MESSAGE_TYPE_CORE_PONG: + GSC_KX_handle_pong (n->kxinfo, message); + break; + case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE: + GSC_KX_handle_encrypted_message (n->kxinfo, message, atsi, atsi_count); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Unsupported message of type %u (%u bytes) received from peer `%s'\n"), + (unsigned int) type, (unsigned int) ntohs (message->size), + GNUNET_i2s (peer)); + return; + } +} + + +/** + * Transmit the given message to the given target. + * + * @param target peer that should receive the message (must be connected) + * @param msg message to transmit + * @param timeout by when should the transmission be done? + */ +void +GSC_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target, + const struct GNUNET_MessageHeader *msg, + struct GNUNET_TIME_Relative timeout) +{ + struct NeighbourMessageEntry *me; + struct Neighbour *n; + size_t msize; + + n = find_neighbour (target); + if (NULL == n) + { + GNUNET_break (0); + return; + } + msize = ntohs (msg->size); + me = GNUNET_malloc (sizeof (struct NeighbourMessageEntry) + msize); + me->deadline = GNUNET_TIME_relative_to_absolute (timeout); + me->size = msize; + memcpy (&me[1], msg, msize); + GNUNET_CONTAINER_DLL_insert_tail (n->message_head, n->message_tail, me); + process_queue (n); +} + + +/** + * Initialize neighbours subsystem. + */ +int +GSC_NEIGHBOURS_init () +{ + neighbours = GNUNET_CONTAINER_multihashmap_create (128); + transport = + GNUNET_TRANSPORT_connect (GSC_cfg, &GSC_my_identity, NULL, + &handle_transport_receive, + &handle_transport_notify_connect, + &handle_transport_notify_disconnect); + if (NULL == transport) + { + GNUNET_CONTAINER_multihashmap_destroy (neighbours); + neighbours = NULL; + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Wrapper around 'free_neighbour'. + * + * @param cls unused + * @param key peer identity + * @param value the 'struct Neighbour' to free + * @return GNUNET_OK (continue to iterate) + */ +static int +free_neighbour_helper (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct Neighbour *n = value; + + /* transport should have 'disconnected' all neighbours... */ + GNUNET_break (0); + free_neighbour (n); + return GNUNET_OK; +} + + +/** + * Shutdown neighbours subsystem. + */ +void +GSC_NEIGHBOURS_done () +{ + if (NULL == transport) + return; + GNUNET_TRANSPORT_disconnect (transport); + transport = NULL; + GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (neighbours); + neighbours = NULL; +} + +/* end of gnunet-service-core_neighbours.c */ diff --git a/src/core/gnunet-service-core_neighbours.h b/src/core/gnunet-service-core_neighbours.h new file mode 100644 index 0000000..d613c46 --- /dev/null +++ b/src/core/gnunet-service-core_neighbours.h @@ -0,0 +1,63 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core_neighbours.h + * @brief code for managing low-level 'plaintext' connections with transport (key exchange may or may not be done yet) + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_CORE_NEIGHBOURS_H +#define GNUNET_SERVICE_CORE_NEIGHBOURS_H + +#include "gnunet_util_lib.h" + +/** + * Transmit the given message to the given target. Note that a + * non-control messages should only be transmitted after a + * 'GSC_SESSION_solicit' call was made (that call is always invoked + * when the message queue is empty). Outbound quotas and memory + * bounds will then be enfoced (as GSC_SESSION_solicit is only called + * if sufficient banwdith is available). + * + * @param target peer that should receive the message (must be connected) + * @param msg message to transmit + * @param timeout by when should the transmission be done? + */ +void +GSC_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target, + const struct GNUNET_MessageHeader *msg, + struct GNUNET_TIME_Relative timeout); + + +/** + * Initialize neighbours subsystem. + */ +int +GSC_NEIGHBOURS_init (void); + + +/** + * Shutdown neighbours subsystem. + */ +void +GSC_NEIGHBOURS_done (void); + + +#endif diff --git a/src/core/gnunet-service-core_sessions.c b/src/core/gnunet-service-core_sessions.c new file mode 100644 index 0000000..1f697cf --- /dev/null +++ b/src/core/gnunet-service-core_sessions.c @@ -0,0 +1,826 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core_sessions.c + * @brief code for managing of 'encrypted' sessions (key exchange done) + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-core.h" +#include "gnunet-service-core_neighbours.h" +#include "gnunet-service-core_kx.h" +#include "gnunet-service-core_typemap.h" +#include "gnunet-service-core_sessions.h" +#include "gnunet-service-core_clients.h" +#include "gnunet_constants.h" + +/** + * How often do we transmit our typemap? + */ +#define TYPEMAP_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) + + +/** + * Message ready for encryption. This struct is followed by the + * actual content of the message. + */ +struct SessionMessageEntry +{ + + /** + * We keep messages in a doubly linked list. + */ + struct SessionMessageEntry *next; + + /** + * We keep messages in a doubly linked list. + */ + struct SessionMessageEntry *prev; + + /** + * Deadline for transmission, 1s after we received it (if we + * are not corking), otherwise "now". Note that this message + * does NOT expire past its deadline. + */ + struct GNUNET_TIME_Absolute deadline; + + /** + * How long is the message? (number of bytes following the "struct + * MessageEntry", but not including the size of "struct + * MessageEntry" itself!) + */ + size_t size; + +}; + + +/** + * Data kept per session. + */ +struct Session +{ + /** + * Identity of the other peer. + */ + struct GNUNET_PeerIdentity peer; + + /** + * Head of list of requests from clients for transmission to + * this peer. + */ + struct GSC_ClientActiveRequest *active_client_request_head; + + /** + * Tail of list of requests from clients for transmission to + * this peer. + */ + struct GSC_ClientActiveRequest *active_client_request_tail; + + /** + * Head of list of messages ready for encryption. + */ + struct SessionMessageEntry *sme_head; + + /** + * Tail of list of messages ready for encryption. + */ + struct SessionMessageEntry *sme_tail; + + /** + * Information about the key exchange with the other peer. + */ + struct GSC_KeyExchangeInfo *kxinfo; + + /** + * Current type map for this peer. + */ + struct GSC_TypeMap *tmap; + + /** + * At what time did we initially establish this session? + * (currently unused, should be integrated with ATS in the + * future...). + */ + struct GNUNET_TIME_Absolute time_established; + + /** + * Task to transmit corked messages with a delay. + */ + GNUNET_SCHEDULER_TaskIdentifier cork_task; + + /** + * Task to transmit our type map. + */ + GNUNET_SCHEDULER_TaskIdentifier typemap_task; + + /** + * Is the neighbour queue empty and thus ready for us + * to transmit an encrypted message? + */ + int ready_to_transmit; + +}; + + +/** + * Map of peer identities to 'struct Session'. + */ +static struct GNUNET_CONTAINER_MultiHashMap *sessions; + + +/** + * Find the session for the given peer. + * + * @param peer identity of the peer + * @return NULL if we are not connected, otherwise the + * session handle + */ +static struct Session * +find_session (const struct GNUNET_PeerIdentity *peer) +{ + return GNUNET_CONTAINER_multihashmap_get (sessions, &peer->hashPubKey); +} + + +/** + * End the session with the given peer (we are no longer + * connected). + * + * @param pid identity of peer to kill session with + */ +void +GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid) +{ + struct Session *session; + struct GSC_ClientActiveRequest *car; + struct SessionMessageEntry *sme; + + session = find_session (pid); + if (NULL == session) + return; +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Destroying session for peer `%4s'\n", + GNUNET_i2s (&session->peer)); +#endif + if (GNUNET_SCHEDULER_NO_TASK != session->cork_task) + { + GNUNET_SCHEDULER_cancel (session->cork_task); + session->cork_task = GNUNET_SCHEDULER_NO_TASK; + } + while (NULL != (car = session->active_client_request_head)) + { + GNUNET_CONTAINER_DLL_remove (session->active_client_request_head, + session->active_client_request_tail, car); + GSC_CLIENTS_reject_request (car); + } + while (NULL != (sme = session->sme_head)) + { + GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme); + GNUNET_free (sme); + } + GNUNET_SCHEDULER_cancel (session->typemap_task); + GSC_CLIENTS_notify_clients_about_neighbour (&session->peer, NULL, + 0 /* FIXME: ATSI */ , + session->tmap, NULL); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (sessions, + &session-> + peer.hashPubKey, + session)); + GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# entries in session map"), + GNUNET_CONTAINER_multihashmap_size (sessions), + GNUNET_NO); + GSC_TYPEMAP_destroy (session->tmap); + session->tmap = NULL; + GNUNET_free (session); +} + + +/** + * Transmit our current typemap message to the other peer. + * (Done periodically in case an update got lost). + * + * @param cls the 'struct Session*' + * @param tc unused + */ +static void +transmit_typemap_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Session *session = cls; + struct GNUNET_MessageHeader *hdr; + struct GNUNET_TIME_Relative delay; + + delay = TYPEMAP_FREQUENCY; + /* randomize a bit to avoid spont. sync */ + delay.rel_value += + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000); + session->typemap_task = + GNUNET_SCHEDULER_add_delayed (delay, &transmit_typemap_task, session); + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# type map refreshes sent"), 1, + GNUNET_NO); + hdr = GSC_TYPEMAP_compute_type_map_message (); + GSC_KX_encrypt_and_transmit (session->kxinfo, hdr, ntohs (hdr->size)); + GNUNET_free (hdr); +} + + +/** + * Create a session, a key exchange was just completed. + * + * @param peer peer that is now connected + * @param kx key exchange that completed + */ +void +GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, + struct GSC_KeyExchangeInfo *kx) +{ + struct Session *session; + +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating session for peer `%4s'\n", + GNUNET_i2s (peer)); +#endif + session = GNUNET_malloc (sizeof (struct Session)); + session->tmap = GSC_TYPEMAP_create (); + session->peer = *peer; + session->kxinfo = kx; + session->time_established = GNUNET_TIME_absolute_get (); + session->typemap_task = + GNUNET_SCHEDULER_add_now (&transmit_typemap_task, session); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (sessions, &peer->hashPubKey, + session, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# entries in session map"), + GNUNET_CONTAINER_multihashmap_size (sessions), + GNUNET_NO); + GSC_CLIENTS_notify_clients_about_neighbour (peer, NULL, 0 /* FIXME: ATSI */ , + NULL, session->tmap); +} + + +/** + * Notify the given client about the session (client is new). + * + * @param cls the 'struct GSC_Client' + * @param key peer identity + * @param value the 'struct Session' + * @return GNUNET_OK (continue to iterate) + */ +static int +notify_client_about_session (void *cls, const GNUNET_HashCode * key, + void *value) +{ + struct GSC_Client *client = cls; + struct Session *session = value; + + GSC_CLIENTS_notify_client_about_neighbour (client, &session->peer, NULL, 0, /* FIXME: ATS!? */ + NULL, /* old TMAP: none */ + session->tmap); + return GNUNET_OK; +} + + +/** + * We have a new client, notify it about all current sessions. + * + * @param client the new client + */ +void +GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client) +{ + /* notify new client about existing sessions */ + GNUNET_CONTAINER_multihashmap_iterate (sessions, ¬ify_client_about_session, + client); +} + + +/** + * Try to perform a transmission on the given session. Will solicit + * additional messages if the 'sme' queue is not full enough. + * + * @param session session to transmit messages from + */ +static void +try_transmission (struct Session *session); + + +/** + * Queue a request from a client for transmission to a particular peer. + * + * @param car request to queue; this handle is then shared between + * the caller (CLIENTS subsystem) and SESSIONS and must not + * be released by either until either 'GNUNET_SESSIONS_dequeue', + * 'GNUNET_SESSIONS_transmit' or 'GNUNET_CLIENTS_failed' + * have been invoked on it + */ +void +GSC_SESSIONS_queue_request (struct GSC_ClientActiveRequest *car) +{ + struct Session *session; + + session = find_session (&car->target); + if (session == NULL) + { +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Dropped client request for transmission (am disconnected)\n"); +#endif + GNUNET_break (0); /* should have been rejected earlier */ + GSC_CLIENTS_reject_request (car); + return; + } + if (car->msize > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) + { + GNUNET_break (0); + GSC_CLIENTS_reject_request (car); + return; + } +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received client transmission request. queueing\n"); +#endif + GNUNET_CONTAINER_DLL_insert (session->active_client_request_head, + session->active_client_request_tail, car); + try_transmission (session); +} + + +/** + * Dequeue a request from a client from transmission to a particular peer. + * + * @param car request to dequeue; this handle will then be 'owned' by + * the caller (CLIENTS sysbsystem) + */ +void +GSC_SESSIONS_dequeue_request (struct GSC_ClientActiveRequest *car) +{ + struct Session *s; + + if (0 == + memcmp (&car->target, &GSC_my_identity, + sizeof (struct GNUNET_PeerIdentity))) + return; + s = find_session (&car->target); + GNUNET_assert (NULL != s); + GNUNET_CONTAINER_DLL_remove (s->active_client_request_head, + s->active_client_request_tail, car); +} + + +/** + * Discard all expired active transmission requests from clients. + * + * @param session session to clean up + */ +static void +discard_expired_requests (struct Session *session) +{ + struct GSC_ClientActiveRequest *pos; + struct GSC_ClientActiveRequest *nxt; + struct GNUNET_TIME_Absolute now; + + now = GNUNET_TIME_absolute_get (); + pos = NULL; + nxt = session->active_client_request_head; + while (NULL != nxt) + { + pos = nxt; + nxt = pos->next; + if ((pos->deadline.abs_value < now.abs_value) && + (GNUNET_YES != pos->was_solicited)) + { + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# messages discarded (expired prior to transmission)"), + 1, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (session->active_client_request_head, + session->active_client_request_tail, pos); + GSC_CLIENTS_reject_request (pos); + } + } +} + + +/** + * Solicit messages for transmission. + * + * @param session session to solict messages for + */ +static void +solicit_messages (struct Session *session) +{ + struct GSC_ClientActiveRequest *car; + struct GSC_ClientActiveRequest *nxt; + size_t so_size; + + discard_expired_requests (session); + so_size = 0; + nxt = session->active_client_request_head; + while (NULL != (car = nxt)) + { + nxt = car->next; + if (so_size + car->msize > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) + break; + so_size += car->msize; + if (car->was_solicited == GNUNET_YES) + continue; + car->was_solicited = GNUNET_YES; + GSC_CLIENTS_solicit_request (car); + } +} + + +/** + * Some messages were delayed (corked), but the timeout has now expired. + * Send them now. + * + * @param cls 'struct Session' with the messages to transmit now + * @param tc scheduler context (unused) + */ +static void +pop_cork_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Session *session = cls; + + session->cork_task = GNUNET_SCHEDULER_NO_TASK; + try_transmission (session); +} + + +/** + * Try to perform a transmission on the given session. Will solicit + * additional messages if the 'sme' queue is not full enough. + * + * @param session session to transmit messages from + */ +static void +try_transmission (struct Session *session) +{ + struct SessionMessageEntry *pos; + size_t msize; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute min_deadline; + + if (GNUNET_YES != session->ready_to_transmit) + return; + msize = 0; + min_deadline = GNUNET_TIME_UNIT_FOREVER_ABS; + /* check 'ready' messages */ + pos = session->sme_head; + while ((NULL != pos) && + (msize + pos->size <= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)) + { + GNUNET_assert (pos->size < GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE); + msize += pos->size; + min_deadline = GNUNET_TIME_absolute_min (min_deadline, pos->deadline); + pos = pos->next; + } + now = GNUNET_TIME_absolute_get (); + if ((msize == 0) || + ((msize < GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / 2) && + (min_deadline.abs_value > now.abs_value))) + { + /* not enough ready yet, try to solicit more */ + solicit_messages (session); + if (msize > 0) + { + /* if there is data to send, just not yet, make sure we do transmit + * it once the deadline is reached */ + if (session->cork_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (session->cork_task); + session->cork_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (min_deadline), &pop_cork_task, + session); + } + return; + } + /* create plaintext buffer of all messages, encrypt and transmit */ + { + static unsigned long long total_bytes; + static unsigned int total_msgs; + char pbuf[msize]; /* plaintext */ + size_t used; + + used = 0; + while ((NULL != (pos = session->sme_head)) && (used + pos->size <= msize)) + { + memcpy (&pbuf[used], &pos[1], pos->size); + used += pos->size; + GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, pos); + GNUNET_free (pos); + } + /* compute average payload size */ + total_bytes += used; + total_msgs++; + if (0 == total_msgs) + { + /* 2^32 messages, wrap around... */ + total_msgs = 1; + total_bytes = used; + } + GNUNET_STATISTICS_set (GSC_stats, "# avg payload per encrypted message", + total_bytes / total_msgs, GNUNET_NO); + /* now actually transmit... */ + session->ready_to_transmit = GNUNET_NO; + GSC_KX_encrypt_and_transmit (session->kxinfo, pbuf, used); + } +} + + +/** + * Send a message to the neighbour now. + * + * @param cls the message + * @param key neighbour's identity + * @param value 'struct Neighbour' of the target + * @return always GNUNET_OK + */ +static int +do_send_message (void *cls, const GNUNET_HashCode * key, void *value) +{ + const struct GNUNET_MessageHeader *hdr = cls; + struct Session *session = value; + struct SessionMessageEntry *m; + uint16_t size; + + size = ntohs (hdr->size); + m = GNUNET_malloc (sizeof (struct SessionMessageEntry) + size); + memcpy (&m[1], hdr, size); + m->size = size; + GNUNET_CONTAINER_DLL_insert (session->sme_head, session->sme_tail, m); + try_transmission (session); + return GNUNET_OK; +} + + +/** + * Broadcast a message to all neighbours. + * + * @param msg message to transmit + */ +void +GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg) +{ + if (NULL == sessions) + return; + GNUNET_CONTAINER_multihashmap_iterate (sessions, &do_send_message, + (void *) msg); +} + + +/** + * Traffic is being solicited for the given peer. This means that the + * message queue on the transport-level (NEIGHBOURS subsystem) is now + * empty and it is now OK to transmit another (non-control) message. + * + * @param pid identity of peer ready to receive data + */ +void +GSC_SESSIONS_solicit (const struct GNUNET_PeerIdentity *pid) +{ + struct Session *session; + + session = find_session (pid); + if (NULL == session) + return; + session->ready_to_transmit = GNUNET_YES; + try_transmission (session); +} + + +/** + * Transmit a message to a particular peer. + * + * @param car original request that was queued and then solicited; + * this handle will now be 'owned' by the SESSIONS subsystem + * @param msg message to transmit + * @param cork is corking allowed? + */ +void +GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car, + const struct GNUNET_MessageHeader *msg, int cork) +{ + struct Session *session; + struct SessionMessageEntry *sme; + size_t msize; + + session = find_session (&car->target); + if (NULL == session) + return; + msize = ntohs (msg->size); + sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + msize); + memcpy (&sme[1], msg, msize); + sme->size = msize; + if (GNUNET_YES == cork) + sme->deadline = + GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_MAX_CORK_DELAY); + GNUNET_CONTAINER_DLL_insert_tail (session->sme_head, session->sme_tail, sme); + try_transmission (session); +} + + +/** + * Helper function for GSC_SESSIONS_handle_client_iterate_peers. + * + * @param cls the 'struct GNUNET_SERVER_TransmitContext' to queue replies + * @param key identity of the connected peer + * @param value the 'struct Neighbour' for the peer + * @return GNUNET_OK (continue to iterate) + */ +#include "core.h" +static int +queue_connect_message (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_SERVER_TransmitContext *tc = cls; + struct Session *session = value; + struct ConnectNotifyMessage cnm; + + /* FIXME: code duplication with clients... */ + cnm.header.size = htons (sizeof (struct ConnectNotifyMessage)); + cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); + // FIXME: full ats... + cnm.ats_count = htonl (0); + cnm.peer = session->peer; + GNUNET_SERVER_transmit_context_append_message (tc, &cnm.header); + return GNUNET_OK; +} + + +/** + * Handle CORE_ITERATE_PEERS request. For this request type, the client + * does not have to have transmitted an INIT request. All current peers + * are returned, regardless of which message types they accept. + * + * @param cls unused + * @param client client sending the iteration request + * @param message iteration request message + */ +void +GSC_SESSIONS_handle_client_iterate_peers (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader + *message) +{ + struct GNUNET_MessageHeader done_msg; + struct GNUNET_SERVER_TransmitContext *tc; + + tc = GNUNET_SERVER_transmit_context_create (client); + GNUNET_CONTAINER_multihashmap_iterate (sessions, &queue_connect_message, tc); + done_msg.size = htons (sizeof (struct GNUNET_MessageHeader)); + done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END); + GNUNET_SERVER_transmit_context_append_message (tc, &done_msg); + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Handle CORE_PEER_CONNECTED request. Notify client about connection + * to the given neighbour. For this request type, the client does not + * have to have transmitted an INIT request. All current peers are + * returned, regardless of which message types they accept. + * + * @param cls unused + * @param client client sending the iteration request + * @param message iteration request message + */ +void +GSC_SESSIONS_handle_client_have_peer (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader + *message) +{ + struct GNUNET_MessageHeader done_msg; + struct GNUNET_SERVER_TransmitContext *tc; + const struct GNUNET_PeerIdentity *peer; + + peer = (const struct GNUNET_PeerIdentity *) &message[1]; // YUCK! + tc = GNUNET_SERVER_transmit_context_create (client); + GNUNET_CONTAINER_multihashmap_get_multiple (sessions, &peer->hashPubKey, + &queue_connect_message, tc); + done_msg.size = htons (sizeof (struct GNUNET_MessageHeader)); + done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END); + GNUNET_SERVER_transmit_context_append_message (tc, &done_msg); + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * We've received a typemap message from a peer, update ours. + * Notifies clients about the session. + * + * @param peer peer this is about + * @param msg typemap update message + */ +void +GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *msg) +{ + struct Session *session; + struct GSC_TypeMap *nmap; + + nmap = GSC_TYPEMAP_get_from_message (msg); + if (NULL == nmap) + return; /* malformed */ + session = find_session (peer); + if (NULL == session) + { + GNUNET_break (0); + return; + } + GSC_CLIENTS_notify_clients_about_neighbour (peer, NULL, 0, /* FIXME: ATS */ + session->tmap, nmap); + GSC_TYPEMAP_destroy (session->tmap); + session->tmap = nmap; +} + + +/** + * The given peer send a message of the specified type. Make sure the + * respective bit is set in its type-map and that clients are notified + * about the session. + * + * @param peer peer this is about + * @param type type of the message + */ +void +GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer, + uint16_t type) +{ + struct Session *session; + struct GSC_TypeMap *nmap; + + if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) + return; + session = find_session (peer); + GNUNET_assert (NULL != session); + if (GNUNET_YES == GSC_TYPEMAP_test_match (session->tmap, &type, 1)) + return; /* already in it */ + nmap = GSC_TYPEMAP_extend (session->tmap, &type, 1); + GSC_CLIENTS_notify_clients_about_neighbour (peer, NULL, 0, /* FIXME: ATS */ + session->tmap, nmap); + GSC_TYPEMAP_destroy (session->tmap); + session->tmap = nmap; +} + + +/** + * Initialize sessions subsystem. + */ +void +GSC_SESSIONS_init () +{ + sessions = GNUNET_CONTAINER_multihashmap_create (128); +} + + +/** + * Helper function for GSC_SESSIONS_handle_client_iterate_peers. + * + * @param cls NULL + * @param key identity of the connected peer + * @param value the 'struct Session' for the peer + * @return GNUNET_OK (continue to iterate) + */ +static int +free_session_helper (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct Session *session = value; + + GSC_SESSIONS_end (&session->peer); + return GNUNET_OK; +} + + +/** + * Shutdown sessions subsystem. + */ +void +GSC_SESSIONS_done () +{ + GNUNET_CONTAINER_multihashmap_iterate (sessions, &free_session_helper, NULL); + GNUNET_CONTAINER_multihashmap_destroy (sessions); + sessions = NULL; +} + +/* end of gnunet-service-core_sessions.c */ diff --git a/src/core/gnunet-service-core_sessions.h b/src/core/gnunet-service-core_sessions.h new file mode 100644 index 0000000..e09cf50 --- /dev/null +++ b/src/core/gnunet-service-core_sessions.h @@ -0,0 +1,192 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core_neighbours.h + * @brief code for managing of 'encrypted' sessions (key exchange done) + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_CORE_SESSIONS_H +#define GNUNET_SERVICE_CORE_SESSIONS_H + +#include "gnunet-service-core.h" +#include "gnunet-service-core_kx.h" + + +/** + * Create a session, a key exchange was just completed. + * + * @param peer peer that is now connected + * @param kx key exchange that completed + */ +void +GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, + struct GSC_KeyExchangeInfo *kx); + + +/** + * End the session with the given peer (we are no longer + * connected). + * + * @param pid identity of peer to kill session with + */ +void +GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid); + + +/** + * Traffic is being solicited for the given peer. This means that the + * message queue on the transport-level (NEIGHBOURS subsystem) is now + * empty and it is now OK to transmit another (non-control) message. + * + * @param pid identity of peer ready to receive data + */ +void +GSC_SESSIONS_solicit (const struct GNUNET_PeerIdentity *pid); + + +/** + * Queue a request from a client for transmission to a particular peer. + * + * @param car request to queue; this handle is then shared between + * the caller (CLIENTS subsystem) and SESSIONS and must not + * be released by either until either 'GNUNET_SESSIONS_dequeue', + * or 'GNUNET_CLIENTS_failed' + * have been invoked on it + */ +void +GSC_SESSIONS_queue_request (struct GSC_ClientActiveRequest *car); + + +/** + * Dequeue a request from a client from transmission to a particular peer. + * + * @param car request to dequeue; this handle will then be 'owned' by + * the caller (CLIENTS sysbsystem) + */ +void +GSC_SESSIONS_dequeue_request (struct GSC_ClientActiveRequest *car); + + +/** + * Transmit a message to a particular peer. + * + * @param car original request that was queued and then solicited, + * ownership does not change (dequeue will be called soon). + * @param msg message to transmit + * @param cork is corking allowed? + */ +void +GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car, + const struct GNUNET_MessageHeader *msg, int cork); + + +/** + * Broadcast a message to all neighbours. + * + * @param msg message to transmit + */ +void +GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg); + + +/** + * We have a new client, notify it about all current sessions. + * + * @param client the new client + */ +void +GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client); + +/** + * We've received a typemap message from a peer, update ours. + * Notifies clients about the session. + * + * @param peer peer this is about + * @param msg typemap update message + */ +void +GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *msg); + + +/** + * The given peer send a message of the specified type. Make sure the + * respective bit is set in its type-map and that clients are notified + * about the session. + * + * @param peer peer this is about + * @param type type of the message + */ +void +GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer, + uint16_t type); + + +/** + * Handle CORE_ITERATE_PEERS request. For this request type, the client + * does not have to have transmitted an INIT request. All current peers + * are returned, regardless of which message types they accept. + * + * @param cls unused + * @param client client sending the iteration request + * @param message iteration request message + */ +void +GSC_SESSIONS_handle_client_iterate_peers (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader + *message); + + +/** + * Handle CORE_PEER_CONNECTED request. Notify client about connection + * to the given neighbour. For this request type, the client does not + * have to have transmitted an INIT request. All current peers are + * returned, regardless of which message types they accept. + * + * @param cls unused + * @param client client sending the iteration request + * @param message iteration request message + */ +void +GSC_SESSIONS_handle_client_have_peer (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader + *message); + + + +/** + * Initialize sessions subsystem. + */ +void +GSC_SESSIONS_init (void); + + +/** + * Shutdown sessions subsystem. + */ +void +GSC_SESSIONS_done (void); + + + +#endif diff --git a/src/core/gnunet-service-core_typemap.c b/src/core/gnunet-service-core_typemap.c new file mode 100644 index 0000000..d2dab5d --- /dev/null +++ b/src/core/gnunet-service-core_typemap.c @@ -0,0 +1,297 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core_typemap.c + * @brief management of map that specifies which message types this peer supports + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet-service-core.h" +#include "gnunet-service-core_sessions.h" +#include "gnunet-service-core_typemap.h" +#include + + +/** + * A type map describing which messages a given neighbour is able + * to process. + */ +struct GSC_TypeMap +{ + uint32_t bits[(UINT16_MAX + 1) / 32]; +}; + +/** + * Bitmap of message types this peer is able to handle. + */ +static struct GSC_TypeMap my_type_map; + +/** + * Counters for message types this peer is able to handle. + */ +static uint8_t map_counters[UINT16_MAX + 1]; + + +/** + * Compute a type map message for this peer. + * + * @return this peers current type map message. + */ +struct GNUNET_MessageHeader * +GSC_TYPEMAP_compute_type_map_message () +{ + char *tmp; + uLongf dlen; + struct GNUNET_MessageHeader *hdr; + +#ifdef compressBound + dlen = compressBound (sizeof (my_type_map)); +#else + dlen = sizeof (my_type_map) + (sizeof (my_type_map) / 100) + 20; + /* documentation says 100.1% oldSize + 12 bytes, but we + * should be able to overshoot by more to be safe */ +#endif + hdr = GNUNET_malloc (dlen + sizeof (struct GNUNET_MessageHeader)); + tmp = (char *) &hdr[1]; + if ((Z_OK != + compress2 ((Bytef *) tmp, &dlen, (const Bytef *) &my_type_map, + sizeof (my_type_map), 9)) || (dlen >= sizeof (my_type_map))) + { + dlen = sizeof (my_type_map); + memcpy (tmp, &my_type_map, sizeof (my_type_map)); + hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP); + } + else + { + hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP); + } + hdr->size = htons ((uint16_t) dlen + sizeof (struct GNUNET_MessageHeader)); + return hdr; +} + + +/** + * Extract a type map from a TYPE_MAP message. + * + * @param msg a type map message + * @return NULL on error + */ +struct GSC_TypeMap * +GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg) +{ + struct GSC_TypeMap *ret; + uint16_t size; + uLongf dlen; + + size = ntohs (msg->size); + switch (ntohs (msg->type)) + { + case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP: + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# type maps received"), + 1, GNUNET_NO); + if (size != sizeof (struct GSC_TypeMap)) + { + GNUNET_break_op (0); + return NULL; + } + ret = GNUNET_malloc (sizeof (struct GSC_TypeMap)); + memcpy (ret, &msg[1], sizeof (struct GSC_TypeMap)); + return ret; + case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP: + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# type maps received"), + 1, GNUNET_NO); + ret = GNUNET_malloc (sizeof (struct GSC_TypeMap)); + dlen = sizeof (struct GSC_TypeMap); + if ((Z_OK != + uncompress ((Bytef *) ret, &dlen, (const Bytef *) &msg[1], + (uLong) size)) || (dlen != sizeof (struct GSC_TypeMap))) + { + GNUNET_break_op (0); + GNUNET_free (ret); + return NULL; + } + return ret; + default: + GNUNET_break (0); + return NULL; + } +} + + +/** + * Send my type map to all connected peers (it got changed). + */ +static void +broadcast_my_type_map () +{ + struct GNUNET_MessageHeader *hdr; + + hdr = GSC_TYPEMAP_compute_type_map_message (); + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# updates to my type map"), 1, + GNUNET_NO); + GSC_SESSIONS_broadcast (hdr); + GNUNET_free (hdr); +} + + +/** + * Add a set of types to our type map. + */ +void +GSC_TYPEMAP_add (const uint16_t * types, unsigned int tlen) +{ + unsigned int i; + int changed; + + changed = GNUNET_NO; + for (i = 0; i < tlen; i++) + { + if (0 == map_counters[types[i]]++) + { + my_type_map.bits[types[i] / 32] |= (1 << (types[i] % 32)); + changed = GNUNET_YES; + } + } + if (GNUNET_YES == changed) + broadcast_my_type_map (); +} + + +/** + * Remove a set of types from our type map. + */ +void +GSC_TYPEMAP_remove (const uint16_t * types, unsigned int tlen) +{ + unsigned int i; + int changed; + + changed = GNUNET_NO; + for (i = 0; i < tlen; i++) + { + if (0 == --map_counters[types[i]]) + { + my_type_map.bits[types[i] / 32] &= ~(1 << (types[i] % 32)); + changed = GNUNET_YES; + } + } + if (GNUNET_YES == changed) + broadcast_my_type_map (); +} + + +/** + * Test if any of the types from the types array is in the + * given type map. + * + * @param tmap map to test + * @param types array of types + * @param tcnt number of entries in types + * @return GNUNET_YES if a type is in the map, GNUNET_NO if not + */ +int +GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap, const uint16_t * types, + unsigned int tcnt) +{ + unsigned int i; + + if (NULL == tmap) + return GNUNET_NO; + if (0 == tcnt) + return GNUNET_YES; /* matches all */ + for (i = 0; i < tcnt; i++) + if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32)))) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Add additional types to a given typemap. + * + * @param tmap map to extend (not changed) + * @param types array of types to add + * @param tcnt number of entries in types + * @return updated type map (fresh copy) + */ +struct GSC_TypeMap * +GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap, const uint16_t * types, + unsigned int tcnt) +{ + struct GSC_TypeMap *ret; + unsigned int i; + + ret = GNUNET_malloc (sizeof (struct GSC_TypeMap)); + if (NULL != tmap) + memcpy (ret, tmap, sizeof (struct GSC_TypeMap)); + for (i = 0; i < tcnt; i++) + ret->bits[types[i] / 32] |= (1 << (types[i] % 32)); + return ret; +} + + +/** + * Create an empty type map. + * + * @return an empty type map + */ +struct GSC_TypeMap * +GSC_TYPEMAP_create () +{ + return GNUNET_malloc (sizeof (struct GSC_TypeMap)); +} + + +/** + * Free the given type map. + * + * @param tmap a type map + */ +void +GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap) +{ + GNUNET_free (tmap); +} + + +/** + * Initialize typemap subsystem. + */ +void +GSC_TYPEMAP_init () +{ + /* nothing to do */ +} + + +/** + * Shutdown typemap subsystem. + */ +void +GSC_TYPEMAP_done () +{ + /* nothing to do */ +} + +/* end of gnunet-service-core_typemap.c */ diff --git a/src/core/gnunet-service-core_typemap.h b/src/core/gnunet-service-core_typemap.h new file mode 100644 index 0000000..aee4573 --- /dev/null +++ b/src/core/gnunet-service-core_typemap.h @@ -0,0 +1,129 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/gnunet-service-core_typemap.h + * @brief management of map that specifies which message types this peer supports + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_CORE_TYPEMAP_H +#define GNUNET_SERVICE_CORE_TYPEMAP_H + +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" + +/** + * Map specifying which message types a peer supports. + */ +struct GSC_TypeMap; + + +/** + * Add a set of types to our type map. + */ +void +GSC_TYPEMAP_add (const uint16_t * types, unsigned int tlen); + + +/** + * Remove a set of types from our type map. + */ +void +GSC_TYPEMAP_remove (const uint16_t * types, unsigned int tlen); + + +/** + * Compute a type map message for this peer. + * + * @return this peers current type map message. + */ +struct GNUNET_MessageHeader * +GSC_TYPEMAP_compute_type_map_message (void); + + +/** + * Extract a type map from a TYPE_MAP message. + * + * @param msg a type map message + * @return NULL on error + */ +struct GSC_TypeMap * +GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg); + + +/** + * Test if any of the types from the types array is in the + * given type map. + * + * @param tmap map to test + * @param types array of types + * @param tcnt number of entries in types + * @return GNUNET_YES if a type is in the map, GNUNET_NO if not + */ +int +GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap, const uint16_t * types, + unsigned int tcnt); + + +/** + * Add additional types to a given typemap. + * + * @param tmap map to extend (not changed) + * @param types array of types to add + * @param tcnt number of entries in types + * @return updated type map (fresh copy) + */ +struct GSC_TypeMap * +GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap, const uint16_t * types, + unsigned int tcnt); + +/** + * Create an empty type map. + * + * @return an empty type map + */ +struct GSC_TypeMap * +GSC_TYPEMAP_create (void); + + +/** + * Free the given type map. + * + * @param tmap a type map + */ +void +GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap); + + +/** + * Initialize typemap subsystem. + */ +void +GSC_TYPEMAP_init (void); + + +/** + * Shutdown typemap subsystem. + */ +void +GSC_TYPEMAP_done (void); + +#endif +/* end of gnunet-service-core_typemap.h */ diff --git a/src/core/test_core_api.c b/src/core/test_core_api.c new file mode 100644 index 0000000..271c2ce --- /dev/null +++ b/src/core/test_core_api.c @@ -0,0 +1,412 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file core/test_core_api.c + * @brief testcase for core_api.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_arm_service.h" +#include "gnunet_core_service.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +#define MTYPE 12345 + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_CORE_Handle *ch; + struct GNUNET_PeerIdentity id; + struct GNUNET_TRANSPORT_Handle *th; + struct GNUNET_TRANSPORT_GetHelloHandle *ghh; + struct GNUNET_MessageHeader *hello; + int connect_status; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct PeerContext p2; + +static GNUNET_SCHEDULER_TaskIdentifier err_task; + +static GNUNET_SCHEDULER_TaskIdentifier con_task; + +static int ok; + +#if VERBOSE +#define OKPP do { ok++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +process_hello (void *cls, const struct GNUNET_MessageHeader *message) +{ + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received (my) `%s' from transport service\n", "HELLO"); + GNUNET_assert (message != NULL); + if ((p == &p1) && (p2.th != NULL)) + GNUNET_TRANSPORT_offer_hello (p2.th, message, NULL, NULL); + if ((p == &p2) && (p1.th != NULL)) + GNUNET_TRANSPORT_offer_hello (p1.th, message, NULL, NULL); +} + + +static void +terminate_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (ok == 6); + GNUNET_CORE_disconnect (p1.ch); + p1.ch = NULL; + GNUNET_CORE_disconnect (p2.ch); + p2.ch = NULL; + GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); + p1.ghh = NULL; + GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); + p2.ghh = NULL; + GNUNET_TRANSPORT_disconnect (p1.th); + p1.th = NULL; + GNUNET_TRANSPORT_disconnect (p2.th); + p2.th = NULL; + if (GNUNET_SCHEDULER_NO_TASK != con_task) + { + GNUNET_SCHEDULER_cancel (con_task); + con_task = GNUNET_SCHEDULER_NO_TASK; + } + ok = 0; +} + + +static void +terminate_task_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + FPRINTF (stderr, "ENDING ANGRILY %u\n", ok); +#endif + GNUNET_break (0); + if (NULL != p1.ch) + { + GNUNET_CORE_disconnect (p1.ch); + p1.ch = NULL; + } + if (NULL != p2.ch) + { + GNUNET_CORE_disconnect (p2.ch); + p2.ch = NULL; + } + if (p1.th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); + GNUNET_TRANSPORT_disconnect (p1.th); + p1.th = NULL; + } + if (p2.th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); + GNUNET_TRANSPORT_disconnect (p2.th); + p2.th = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != con_task) + { + GNUNET_SCHEDULER_cancel (con_task); + con_task = GNUNET_SCHEDULER_NO_TASK; + } + ok = 42; +} + + +static size_t +transmit_ready (void *cls, size_t size, void *buf) +{ + struct PeerContext *p = cls; + struct GNUNET_MessageHeader *m; + + GNUNET_assert (ok == 4); + OKPP; + GNUNET_assert (p == &p1); + GNUNET_assert (buf != NULL); + m = (struct GNUNET_MessageHeader *) buf; + m->type = htons (MTYPE); + m->size = htons (sizeof (struct GNUNET_MessageHeader)); + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct PeerContext *pc = cls; + + if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + GNUNET_assert (pc->connect_status == 0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Encrypted connection established to peer `%4s'\n", + GNUNET_i2s (peer)); + if (GNUNET_SCHEDULER_NO_TASK != con_task) + { + GNUNET_SCHEDULER_cancel (con_task); + con_task = GNUNET_SCHEDULER_NO_TASK; + } + pc->connect_status = 1; + if (pc == &p1) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&p2.id)); + if (NULL == + GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_YES, 0, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 145), + &p2.id, + sizeof (struct GNUNET_MessageHeader), + &transmit_ready, &p1)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&p2.id)); + } + } +} + + +static void +disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *pc = cls; + + if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + pc->connect_status = 0; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted connection to `%4s' cut\n", + GNUNET_i2s (peer)); +} + + +static int +inbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core provides inbound data from `%4s'.\n", GNUNET_i2s (other)); + return GNUNET_OK; +} + + +static int +outbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core notifies about outbound data for `%4s'.\n", + GNUNET_i2s (other)); + return GNUNET_OK; +} + + + +static int +process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving message from `%4s'.\n", + GNUNET_i2s (peer)); + GNUNET_assert (ok == 5); + OKPP; + GNUNET_SCHEDULER_cancel (err_task); + err_task = GNUNET_SCHEDULER_add_now (&terminate_task, NULL); + return GNUNET_OK; +} + + +static struct GNUNET_CORE_MessageHandler handlers[] = { + {&process_mtype, MTYPE, sizeof (struct GNUNET_MessageHeader)}, + {NULL, 0, 0} +}; + + +static void +connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + con_task = GNUNET_SCHEDULER_NO_TASK; + return; + } + con_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &connect_task, + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking transport (1) to connect to peer `%4s'\n", + GNUNET_i2s (&p2.id)); + GNUNET_TRANSPORT_try_connect (p1.th, &p2.id); +} + + +static void +init_notify (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core connection to `%4s' established\n", + GNUNET_i2s (my_identity)); + GNUNET_assert (server != NULL); + p->id = *my_identity; + p->ch = server; + if (cls == &p1) + { + GNUNET_assert (ok == 2); + OKPP; + /* connect p2 */ + p2.ch = + GNUNET_CORE_connect (p2.cfg, 1, &p2, &init_notify, &connect_notify, + &disconnect_notify, &inbound_notify, GNUNET_YES, + &outbound_notify, GNUNET_YES, handlers); + } + else + { + GNUNET_assert (ok == 3); + OKPP; + GNUNET_assert (cls == &p2); + con_task = GNUNET_SCHEDULER_add_now (&connect_task, NULL); + } +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, NULL, NULL); + GNUNET_assert (p->th != NULL); + p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_assert (ok == 1); + OKPP; + setup_peer (&p1, "test_core_api_peer1.conf"); + setup_peer (&p2, "test_core_api_peer2.conf"); + err_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 300), + &terminate_task_error, NULL); + p1.ch = + GNUNET_CORE_connect (p1.cfg, 1, &p1, &init_notify, &connect_notify, + &disconnect_notify, &inbound_notify, GNUNET_YES, + &outbound_notify, GNUNET_YES, handlers); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + +static int +check () +{ + char *const argv[] = { "test-core-api", + "-c", + "test_core_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-core-api", "nohelp", options, &run, &ok); + stop_arm (&p1); + stop_arm (&p2); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-core-api", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); + + return ret; +} + +/* end of test_core_api.c */ diff --git a/src/core/test_core_api_data.conf b/src/core/test_core_api_data.conf new file mode 100644 index 0000000..30eea2d --- /dev/null +++ b/src/core/test_core_api_data.conf @@ -0,0 +1,15 @@ +@INLINE@ test_core_defaults.conf +[PATHS] +DEFAULTCONFIG = test_core_api_data.conf + +[arm] +DEFAULTSERVICES = topology hostlist + +[ats] +WAN_QUOTA_IN = 64 kiB +WAN_QUOTA_OUT = 64 kiB + +[core] +PORT = 2092 +UNIXPATH = /tmp/gnunet-service-core.sock + diff --git a/src/core/test_core_api_peer1.conf b/src/core/test_core_api_peer1.conf new file mode 100644 index 0000000..662318a --- /dev/null +++ b/src/core/test_core_api_peer1.conf @@ -0,0 +1,30 @@ +@INLINE@ test_core_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-core-peer-1/ +DEFAULTCONFIG = test_core_api_peer1.conf + +[transport-tcp] +PORT = 12468 + +[arm] +PORT = 12466 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12467 + +[resolver] +PORT = 12464 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12469 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12465 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + +[ats] +PORT = 12471 +UNIXPATH = /tmp/gnunet-p1-service-ats.sock diff --git a/src/core/test_core_api_peer2.conf b/src/core/test_core_api_peer2.conf new file mode 100644 index 0000000..2e848b8 --- /dev/null +++ b/src/core/test_core_api_peer2.conf @@ -0,0 +1,35 @@ +@INLINE@ test_core_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-core-peer-2/ +DEFAULTCONFIG = test_core_api_peer2.conf + +[transport-tcp] +PORT = 22468 + +[arm] +PORT = 22466 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 22467 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 22464 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 22469 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 22465 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + +[core] +PORT = 22470 +UNIXPATH = /tmp/gnunet-p2-service-core.sock + +[ats] +PORT = 22471 +UNIXPATH = /tmp/gnunet-p2-service-ats.sock diff --git a/src/core/test_core_api_reliability.c b/src/core/test_core_api_reliability.c new file mode 100644 index 0000000..645b27e --- /dev/null +++ b/src/core/test_core_api_reliability.c @@ -0,0 +1,533 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file core/test_core_api_reliability.c + * @brief testcase for core_api.c focusing on reliable transmission (with TCP) + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_core_service.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * Note that this value must not significantly exceed + * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise + * messages may be dropped even for a reliable transport. + */ +#define TOTAL_MSGS (600 * 10) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 6000) + +/** + * What delay do we request from the core service for transmission? + */ +#define FAST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +#define MTYPE 12345 + + +static unsigned long long total_bytes; + +static struct GNUNET_TIME_Absolute start_time; + +static GNUNET_SCHEDULER_TaskIdentifier err_task; + +static GNUNET_SCHEDULER_TaskIdentifier connect_task; + + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_CORE_Handle *ch; + struct GNUNET_PeerIdentity id; + struct GNUNET_TRANSPORT_Handle *th; + struct GNUNET_MessageHeader *hello; + struct GNUNET_TRANSPORT_GetHelloHandle *ghh; + int connect_status; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct PeerContext p2; + +static int ok; + +static int32_t tr_n; + + +#if VERBOSE +#define OKPP do { ok++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + +struct TestMessage +{ + struct GNUNET_MessageHeader header; + uint32_t num; +}; + + +static unsigned int +get_size (unsigned int iter) +{ + unsigned int ret; + + if (iter < 60000) + return iter + sizeof (struct TestMessage); + ret = (iter * iter * iter); + return sizeof (struct TestMessage) + (ret % 60000); +} + +static void +process_hello (void *cls, const struct GNUNET_MessageHeader *message); + +static void +terminate_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned long long delta; + + GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); + GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); + GNUNET_CORE_disconnect (p1.ch); + p1.ch = NULL; + GNUNET_CORE_disconnect (p2.ch); + p2.ch = NULL; + if (connect_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (connect_task); + GNUNET_TRANSPORT_disconnect (p1.th); + p1.th = NULL; + GNUNET_TRANSPORT_disconnect (p2.th); + p2.th = NULL; + delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; + FPRINTF (stderr, "\nThroughput was %llu kb/s\n", + total_bytes * 1000 / 1024 / delta); + GAUGER ("CORE", "Core throughput/s", total_bytes * 1000 / 1024 / delta, + "kb/s"); + ok = 0; +} + + +static void +terminate_task_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_break (0); + if (p1.ch != NULL) + { + GNUNET_CORE_disconnect (p1.ch); + p1.ch = NULL; + } + if (p2.ch != NULL) + { + GNUNET_CORE_disconnect (p2.ch); + p2.ch = NULL; + } + if (connect_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (connect_task); + if (p1.th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); + GNUNET_TRANSPORT_disconnect (p1.th); + p1.th = NULL; + } + if (p2.th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); + GNUNET_TRANSPORT_disconnect (p2.th); + p2.th = NULL; + } + ok = 42; +} + + +static void +try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + connect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, + NULL); + GNUNET_TRANSPORT_try_connect (p1.th, &p2.id); +} + +static size_t +transmit_ready (void *cls, size_t size, void *buf) +{ + char *cbuf = buf; + struct TestMessage hdr; + unsigned int s; + unsigned int ret; + + GNUNET_assert (size <= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE); + if (buf == NULL) + { + if (p1.ch != NULL) + GNUNET_break (NULL != + GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, + FAST_TIMEOUT, &p2.id, + get_size (tr_n), + &transmit_ready, &p1)); + return 0; + } + GNUNET_assert (tr_n < TOTAL_MSGS); + ret = 0; + s = get_size (tr_n); + GNUNET_assert (size >= s); + GNUNET_assert (buf != NULL); + cbuf = buf; + do + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message %u of size %u at offset %u\n", tr_n, s, ret); +#endif + hdr.header.size = htons (s); + hdr.header.type = htons (MTYPE); + hdr.num = htonl (tr_n); + memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); + ret += sizeof (struct TestMessage); + memset (&cbuf[ret], tr_n, s - sizeof (struct TestMessage)); + ret += s - sizeof (struct TestMessage); + tr_n++; + s = get_size (tr_n); + if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) + break; /* sometimes pack buffer full, sometimes not */ + } + while (size - ret >= s); + GNUNET_SCHEDULER_cancel (err_task); + err_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Returning total message block of size %u\n", ret); + total_bytes += ret; + return ret; +} + + + +static void +connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct PeerContext *pc = cls; + + if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + GNUNET_assert (pc->connect_status == 0); + pc->connect_status = 1; + if (pc == &p1) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Encrypted connection established to peer `%4s'\n", + GNUNET_i2s (peer)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&p2.id)); + GNUNET_SCHEDULER_cancel (err_task); + err_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); + start_time = GNUNET_TIME_absolute_get (); + GNUNET_break (NULL != + GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, + TIMEOUT, &p2.id, + get_size (0), + &transmit_ready, &p1)); + } +} + + +static void +disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *pc = cls; + + if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + pc->connect_status = 0; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted connection to `%4s' cut\n", + GNUNET_i2s (peer)); +} + + +static int +inbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core provides inbound data from `%4s'.\n", GNUNET_i2s (other)); +#endif + return GNUNET_OK; +} + + +static int +outbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core notifies about outbound data for `%4s'.\n", + GNUNET_i2s (other)); +#endif + return GNUNET_OK; +} + + +static size_t +transmit_ready (void *cls, size_t size, void *buf); + +static int +process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + static int n; + unsigned int s; + const struct TestMessage *hdr; + + hdr = (const struct TestMessage *) message; + s = get_size (n); + if (MTYPE != ntohs (message->type)) + return GNUNET_SYSERR; + if (ntohs (message->size) != s) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u of size %u, got %u bytes of message %u\n", + n, s, ntohs (message->size), ntohl (hdr->num)); + GNUNET_SCHEDULER_cancel (err_task); + err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, NULL); + return GNUNET_SYSERR; + } + if (ntohl (hdr->num) != n) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u of size %u, got %u bytes of message %u\n", + n, s, ntohs (message->size), ntohl (hdr->num)); + GNUNET_SCHEDULER_cancel (err_task); + err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, NULL); + return GNUNET_SYSERR; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message %u of size %u\n", + ntohl (hdr->num), ntohs (message->size)); +#endif + n++; + if (0 == (n % (TOTAL_MSGS / 100))) + FPRINTF (stderr, "%s", "."); + if (n == TOTAL_MSGS) + { + GNUNET_SCHEDULER_cancel (err_task); + GNUNET_SCHEDULER_add_now (&terminate_task, NULL); + } + else + { + if (n == tr_n) + GNUNET_break (NULL != + GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, + FAST_TIMEOUT, &p2.id, + get_size (tr_n), + &transmit_ready, &p1)); + } + return GNUNET_OK; +} + + +static struct GNUNET_CORE_MessageHandler handlers[] = { + {&process_mtype, MTYPE, 0}, + {NULL, 0, 0} +}; + + + +static void +init_notify (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to CORE service of `%4s' established\n", + GNUNET_i2s (my_identity)); + GNUNET_assert (server != NULL); + p->id = *my_identity; + p->ch = server; + if (cls == &p1) + { + GNUNET_assert (ok == 2); + OKPP; + /* connect p2 */ + GNUNET_CORE_connect (p2.cfg, 1, &p2, &init_notify, &connect_notify, + &disconnect_notify, &inbound_notify, GNUNET_YES, + &outbound_notify, GNUNET_YES, handlers); + } + else + { + GNUNET_assert (ok == 3); + OKPP; + GNUNET_assert (cls == &p2); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking transport (1) to connect to peer `%4s'\n", + GNUNET_i2s (&p2.id)); + connect_task = GNUNET_SCHEDULER_add_now (&try_connect, NULL); + } +} + + +static void +process_hello (void *cls, const struct GNUNET_MessageHeader *message) +{ + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received (my) `%s' from transport service\n", "HELLO"); + GNUNET_assert (message != NULL); + p->hello = GNUNET_malloc (ntohs (message->size)); + memcpy (p->hello, message, ntohs (message->size)); + if ((p == &p1) && (p2.th != NULL)) + GNUNET_TRANSPORT_offer_hello (p2.th, message, NULL, NULL); + if ((p == &p2) && (p1.th != NULL)) + GNUNET_TRANSPORT_offer_hello (p1.th, message, NULL, NULL); + + if ((p == &p1) && (p2.hello != NULL)) + GNUNET_TRANSPORT_offer_hello (p1.th, p2.hello, NULL, NULL); + if ((p == &p2) && (p1.hello != NULL)) + GNUNET_TRANSPORT_offer_hello (p2.th, p1.hello, NULL, NULL); +} + + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, NULL, NULL); + GNUNET_assert (p->th != NULL); + p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_assert (ok == 1); + OKPP; + setup_peer (&p1, "test_core_api_peer1.conf"); + setup_peer (&p2, "test_core_api_peer2.conf"); + err_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); + GNUNET_CORE_connect (p1.cfg, 1, &p1, &init_notify, &connect_notify, + &disconnect_notify, &inbound_notify, GNUNET_YES, + &outbound_notify, GNUNET_YES, handlers); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + +static int +check () +{ + char *const argv[] = { "test-core-api-reliability", + "-c", + "test_core_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-core-api-reliability", "nohelp", options, &run, + &ok); + stop_arm (&p1); + stop_arm (&p2); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-core-api", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); + + return ret; +} + +/* end of test_core_api_reliability.c */ diff --git a/src/core/test_core_api_send_to_self.c b/src/core/test_core_api_send_to_self.c new file mode 100644 index 0000000..4fa73d9 --- /dev/null +++ b/src/core/test_core_api_send_to_self.c @@ -0,0 +1,242 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file core/test_core_api_send_to_self.c + * @brief + * @author Philipp Toelke + */ +#include +#include +#include +#include +#include +#include + +/** + * Final status code. + */ +static int ret; + +/** + * Handle to the cleanup task. + */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +static struct GNUNET_PeerIdentity myself; + +/** + * Configuration to load for the new peer. + */ +struct GNUNET_CONFIGURATION_Handle *core_cfg; + +/** + * The handle to core + */ +struct GNUNET_CORE_Handle *core; + +/** + * Handle to gnunet-service-arm. + */ +struct GNUNET_OS_Process *arm_proc; + +/** + * Function scheduled as very last function, cleans up after us + */ +static void +cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tskctx) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + + if (core != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting core.\n"); + GNUNET_CORE_disconnect (core); + core = NULL; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peer\n"); + if (0 != GNUNET_OS_process_kill (arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + + if (GNUNET_OS_process_wait (arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (arm_proc)); + GNUNET_OS_process_close (arm_proc); + arm_proc = NULL; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); +} + +static int +receive (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) +{ + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message from peer %s\n", + GNUNET_i2s (other)); + GNUNET_SCHEDULER_add_now (&cleanup, NULL); + ret = 0; + return GNUNET_OK; +} + +static size_t +send_message (void *cls, size_t size, void *buf) +{ + if (size == 0 || buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not send; got 0 buffer\n"); + return 0; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending!\n"); + struct GNUNET_MessageHeader *hdr = buf; + + hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); + hdr->type = htons (GNUNET_MESSAGE_TYPE_DUMMY); + return ntohs (hdr->size); +} + +static void +init (void *cls, struct GNUNET_CORE_Handle *core, + const struct GNUNET_PeerIdentity *my_identity) +{ + if (core == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could NOT connect to CORE;\n"); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Correctly connected to CORE; we are the peer %s.\n", + GNUNET_i2s (my_identity)); + memcpy (&myself, my_identity, sizeof (struct GNUNET_PeerIdentity)); +} + +static void +connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected to peer %s.\n", + GNUNET_i2s (peer)); + if (0 == memcmp (peer, &myself, sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected to myself; sending message!\n"); + GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 0, + GNUNET_TIME_UNIT_FOREVER_REL, peer, + sizeof (struct GNUNET_MessageHeader), + send_message, NULL); + } +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const static struct GNUNET_CORE_MessageHandler handlers[] = { + {&receive, GNUNET_MESSAGE_TYPE_DUMMY, 0}, + {NULL, 0, 0} + }; + + core_cfg = GNUNET_CONFIGURATION_create (); + + arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", "test_core_api_peer1.conf", NULL); + + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (core_cfg, + "test_core_api_peer1.conf")); + + core = + GNUNET_CORE_connect (core_cfg, 42, NULL, &init, &connect_cb, NULL, NULL, + 0, NULL, 0, handlers); + + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 300), &cleanup, + cls); +} + + +static int +check () +{ + char *const argv[] = { "test-core-api-send-to-self", + "-c", + "test_core_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + ret = 1; + + return (GNUNET_OK == + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test_core_api_send_to_self", + gettext_noop ("help text"), options, &run, + NULL)) ? ret : 1; +} + +/** + * The main function to obtain template from gnunetd. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *argv[]) +{ + GNUNET_log_setup ("test-core-api-send-to-self", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); + return ret; +} + +/* end of test_core_api_send_to_self.c */ diff --git a/src/core/test_core_api_send_to_self.conf b/src/core/test_core_api_send_to_self.conf new file mode 100644 index 0000000..6737726 --- /dev/null +++ b/src/core/test_core_api_send_to_self.conf @@ -0,0 +1,32 @@ +@INLINE@ test_core_defaults.conf +[PATHS] +SERVICEHOME = ~/.gnunet/ +DEFAULTCONFIG = test_core_api_send_to_self.conf + +[arm] +PORT = 2425 +DEFAULTSERVICES = core test-sts + +[core] +PORT = 24512 +UNIXPATH = /tmp/gnunet-service-core.sock + +[ats] +WAN_QUOTA_IN = 104857600 +WAN_QUOTA_OUT = 104757600 +PORT = 24571 +UNIXPATH = /tmp/gnunet-p1-service-ats.sock + +[test-sts] +AUTOSTART = YES +PORT = 9252 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = test_core_api_send_to_self +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +TOTAL_QUOTA_IN = 65536 +TOTAL_QUOTA_OUT = 65536 +UNIXPATH = /tmp/gnunet-service-sts.sock + diff --git a/src/core/test_core_api_start_only.c b/src/core/test_core_api_start_only.c new file mode 100644 index 0000000..2eca575 --- /dev/null +++ b/src/core/test_core_api_start_only.c @@ -0,0 +1,262 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_core_api_start_only.c + * @brief testcase for core_api.c that only starts two peers, + * connects to the core service and shuts down again + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_arm_service.h" +#include "gnunet_core_service.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" + +#define VERBOSE GNUNET_NO + +#define TIMEOUT 5 + +#define START_ARM GNUNET_YES + +#define MTYPE 12345 + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_CORE_Handle *ch; + struct GNUNET_PeerIdentity id; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct PeerContext p2; + +static GNUNET_SCHEDULER_TaskIdentifier timeout_task_id; + +static int ok; + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + + +static void +connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ +} + + +static void +disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) +{ +} + + +static int +inbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + return GNUNET_OK; +} + + +static int +outbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + return GNUNET_OK; +} + + +static struct GNUNET_CORE_MessageHandler handlers[] = { + {NULL, 0, 0} +}; + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_CORE_disconnect (p1.ch); + p1.ch = NULL; + GNUNET_CORE_disconnect (p2.ch); + p2.ch = NULL; + ok = 0; +} + + + + +static void +init_notify (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct PeerContext *p = cls; + + GNUNET_assert (server != NULL); + GNUNET_assert (p->ch == server); + if (cls == &p1) + { + /* connect p2 */ + p2.ch = + GNUNET_CORE_connect (p2.cfg, 1, &p2, &init_notify, &connect_notify, + &disconnect_notify, &inbound_notify, GNUNET_YES, + &outbound_notify, GNUNET_YES, handlers); + } + else + { + GNUNET_assert (cls == &p2); + GNUNET_SCHEDULER_cancel (timeout_task_id); + GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + } +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +timeout_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + FPRINTF (stderr, "%s", "Timeout.\n"); + if (p1.ch != NULL) + { + GNUNET_CORE_disconnect (p1.ch); + p1.ch = NULL; + } + if (p2.ch != NULL) + { + GNUNET_CORE_disconnect (p2.ch); + p2.ch = NULL; + } + ok = 42; +} + + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_assert (ok == 1); + OKPP; + setup_peer (&p1, "test_core_api_peer1.conf"); + setup_peer (&p2, "test_core_api_peer2.conf"); + timeout_task_id = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, TIMEOUT), + &timeout_task, NULL); + p1.ch = + GNUNET_CORE_connect (p1.cfg, 1, &p1, &init_notify, &connect_notify, + &disconnect_notify, &inbound_notify, GNUNET_YES, + &outbound_notify, GNUNET_YES, handlers); +} + + +static void +stop_arm (struct PeerContext *p) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peer\n"); +#if START_ARM + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static int +check () +{ + char *const argv[] = { "test-core-api-start-only", + "-c", + "test_core_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-core-api-start-only", "nohelp", options, &run, &ok); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test finished\n"); + stop_arm (&p1); + stop_arm (&p2); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-core-api-start-only", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); + return ret; +} + +/* end of test_core_api_start_only.c */ diff --git a/src/core/test_core_defaults.conf b/src/core/test_core_defaults.conf new file mode 100644 index 0000000..098c0ba --- /dev/null +++ b/src/core/test_core_defaults.conf @@ -0,0 +1,59 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunet-core/ +DEFAULTCONFIG = test_core_defaults.conf + +[arm] +DEFAULTSERVICES = + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +PORT = 12470 +UNIXPATH = /tmp/gnunet-p1-service-core.sock + +[transport-tcp] +BINDTO = 127.0.0.1 + +[testing] +WEAKRANDOM = YES + +[fs] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[dht] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[dv] +AUTOSTART = NO + +[chat] +AUTOSTART = NO + +[gns] +AUTOSTART = NO + +[vpn] +AUTOSTART = NO diff --git a/src/core/test_core_quota_asymmetric_recv_limited_peer1.conf b/src/core/test_core_quota_asymmetric_recv_limited_peer1.conf new file mode 100644 index 0000000..5501fb8 --- /dev/null +++ b/src/core/test_core_quota_asymmetric_recv_limited_peer1.conf @@ -0,0 +1,39 @@ +@INLINE@ test_core_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-core-quota-asym-recv-lim-peer-1/ +DEFAULTCONFIG = test_core_quota_asymmetric_recv_limited_peer1.conf + +[transport-tcp] +PORT = 12488 + +[arm] +PORT = 12486 +UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-arm.sock + +[statistics] +PORT = 12487 +UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-statistics.sock + +[resolver] +PORT = 12484 +UNIXPATH = /tmp/gnunet-core-asym-recv-1-service-resolver.sock + +[peerinfo] +PORT = 12489 +UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-peerinfo.sock + +[transport] +PORT = 12485 +UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-transport.sock + +[ats] +PORT = 12491 +UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-ats.sock +WAN_QUOTA_IN = 1 MB +WAN_QUOTA_OUT = 1 MB + +[core] +PORT = 12490 +UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-core.sock +DEBUG = NO + diff --git a/src/core/test_core_quota_asymmetric_recv_limited_peer2.conf b/src/core/test_core_quota_asymmetric_recv_limited_peer2.conf new file mode 100644 index 0000000..0c89523 --- /dev/null +++ b/src/core/test_core_quota_asymmetric_recv_limited_peer2.conf @@ -0,0 +1,39 @@ +@INLINE@ test_core_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-core-quota-asym-recv-lim-peer-2/ +DEFAULTCONFIG = test_core_quota_asymmetric_recv_limited_peer2.conf + +[transport-tcp] +PORT = 22488 + +[arm] +PORT = 22486 +UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-arm.sock + +[statistics] +PORT = 22487 +UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-statistics.sock + +[resolver] +PORT = 22484 +UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-resolver.sock + +[peerinfo] +PORT = 22489 +UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-peerinfo.sock + +[transport] +PORT = 22485 +UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-transport.sock + +[core] +PORT = 22490 +UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-core.sock +DEBUG = NO + +[ats] +PORT = 22491 +UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-ats.sock +WAN_QUOTA_IN = 10 kiB +WAN_QUOTA_OUT = 10 kiB + diff --git a/src/core/test_core_quota_asymmetric_send_limit_peer1.conf b/src/core/test_core_quota_asymmetric_send_limit_peer1.conf new file mode 100644 index 0000000..568cf6b --- /dev/null +++ b/src/core/test_core_quota_asymmetric_send_limit_peer1.conf @@ -0,0 +1,38 @@ +@INLINE@ test_core_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-core-quota-asym-send-lim-peer-1/ +DEFAULTCONFIG = test_core_quota_asymmetric_send_limit_peer1.conf + +[transport-tcp] +PORT = 12488 + +[arm] +PORT = 12486 +UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-arm.sock + +[statistics] +PORT = 12487 +UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-statistics.sock + +[resolver] +PORT = 12484 +UNIXPATH = /tmp/gnunet-core-asym-send-1-service-resolver.sock + +[peerinfo] +PORT = 12489 +UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-peerinfo.sock + +[transport] +PORT = 12485 +UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-transport.sock + +[ats] +WAN_QUOTA_IN = 10240 +WAN_QUOTA_OUT = 10240 +PORT = 12491 +UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-ats.sock + +[core] +PORT = 12490 +UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-core.sock +DEBUG = NO diff --git a/src/core/test_core_quota_asymmetric_send_limit_peer2.conf b/src/core/test_core_quota_asymmetric_send_limit_peer2.conf new file mode 100644 index 0000000..5474ce9 --- /dev/null +++ b/src/core/test_core_quota_asymmetric_send_limit_peer2.conf @@ -0,0 +1,38 @@ +@INLINE@ test_core_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-core-quota-asym-send-lim-peer-2/ +DEFAULTCONFIG = test_core_quota_asymmetric_send_limit_peer2.conf + +[transport-tcp] +PORT = 22488 + +[arm] +PORT = 22486 +UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-arm.sock + +[statistics] +PORT = 22487 +UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-statistics.sock + +[resolver] +PORT = 22484 +UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-resolver.sock + +[peerinfo] +PORT = 22489 +UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-peerinfo.sock + +[transport] +PORT = 22485 +UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-transport.sock + +[core] +PORT = 22490 +UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-core.sock +DEBUG = NO + +[ats] +PORT = 22491 +UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-ats.sock +WAN_QUOTA_IN = 1 MB +WAN_QUOTA_OUT = 1 MB diff --git a/src/core/test_core_quota_compliance.c b/src/core/test_core_quota_compliance.c new file mode 100644 index 0000000..7c16531 --- /dev/null +++ b/src/core/test_core_quota_compliance.c @@ -0,0 +1,750 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file core/test_core_quota_compliance.c + * @brief testcase for core_api.c focusing quota compliance on core level + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_core_service.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_statistics_service.h" + +#define VERBOSE GNUNET_NO + +#define SYMMETRIC 0 +#define ASYMMETRIC_SEND_LIMITED 1 +#define ASYMMETRIC_RECV_LIMITED 2 + +#define START_ARM GNUNET_YES + +/** + * Note that this value must not significantly exceed + * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise + * messages may be dropped even for a reliable transport. + */ +#define TOTAL_MSGS (60000 * 10) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +/** + * What delay do we request from the core service for transmission? + */ +#define FAST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150) + +#define MTYPE 12345 +#define MESSAGESIZE 1024 +#define MEASUREMENT_LENGTH GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + +static unsigned long long total_bytes_sent; +static unsigned long long total_bytes_recv; + +static struct GNUNET_TIME_Absolute start_time; + +static GNUNET_SCHEDULER_TaskIdentifier err_task; + +static GNUNET_SCHEDULER_TaskIdentifier measure_task; + +static GNUNET_SCHEDULER_TaskIdentifier connect_task; + + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_CORE_Handle *ch; + struct GNUNET_CORE_TransmitHandle *nth; + struct GNUNET_PeerIdentity id; + struct GNUNET_TRANSPORT_Handle *th; + struct GNUNET_MessageHeader *hello; + struct GNUNET_STATISTICS_Handle *stats; + struct GNUNET_TRANSPORT_GetHelloHandle *ghh; + int connect_status; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; +static struct PeerContext p2; + +static unsigned long long current_quota_p1_in; +static unsigned long long current_quota_p1_out; +static unsigned long long current_quota_p2_in; +static unsigned long long current_quota_p2_out; + +static int ok; +static int test; +static int32_t tr_n; + +static int running; + + +#if VERBOSE +#define OKPP do { ok++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + +struct TestMessage +{ + struct GNUNET_MessageHeader header; + uint32_t num; +}; + +static void +process_hello (void *cls, const struct GNUNET_MessageHeader *message); + +static void +terminate_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CORE_Handle *ch; + + err_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); + GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); + if (p1.nth != NULL) + { + GNUNET_CORE_notify_transmit_ready_cancel (p1.nth); + p1.nth = NULL; + } + if (connect_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (connect_task); + ch = p1.ch; + p1.ch = NULL; + GNUNET_CORE_disconnect (ch); + ch = p2.ch; + p2.ch = NULL; + GNUNET_CORE_disconnect (ch); + GNUNET_TRANSPORT_disconnect (p1.th); + p1.th = NULL; + GNUNET_TRANSPORT_disconnect (p2.th); + p2.th = NULL; +} + + +static void +terminate_task_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + err_task = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testcase failed!\n"); + //GNUNET_break (0); + if (p1.nth != NULL) + { + GNUNET_CORE_notify_transmit_ready_cancel (p1.nth); + p1.nth = NULL; + } + if (measure_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (measure_task); + if (connect_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (connect_task); + + GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); + GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); + + GNUNET_CORE_disconnect (p1.ch); + p1.ch = NULL; + GNUNET_CORE_disconnect (p2.ch); + p2.ch = NULL; + GNUNET_TRANSPORT_disconnect (p1.th); + p1.th = NULL; + GNUNET_TRANSPORT_disconnect (p2.th); + p2.th = NULL; + ok = 42; +} + + +static void +try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + connect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, + NULL); + GNUNET_TRANSPORT_try_connect (p1.th, &p2.id); + GNUNET_TRANSPORT_try_connect (p2.th, &p1.id); +} + +/** + * Callback function to process statistic values. + * + * @param cls closure + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +print_stat (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + if (cls == &p1) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer1 %50s = %12llu\n", name, + (unsigned long long) value); + if (cls == &p2) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer2 %50s = %12llu\n", name, + (unsigned long long) value); + return GNUNET_OK; +} + +static void +measurement_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned long long delta; + unsigned long long throughput_out; + unsigned long long throughput_in; + unsigned long long max_quota_in; + unsigned long long max_quota_out; + unsigned long long quota_delta; + enum GNUNET_ErrorType kind = GNUNET_ERROR_TYPE_DEBUG; + + measure_task = GNUNET_SCHEDULER_NO_TASK; + FPRINTF (stdout, "%s", "\n"); + running = GNUNET_NO; + + delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; + + throughput_out = total_bytes_sent * 1000 / delta; /* convert to bytes/s */ + throughput_in = total_bytes_recv * 1000 / delta; /* convert to bytes/s */ + + max_quota_in = GNUNET_MIN (current_quota_p1_in, current_quota_p2_in); + max_quota_out = GNUNET_MIN (current_quota_p1_out, current_quota_p2_out); + if (max_quota_out < max_quota_in) + quota_delta = max_quota_in / 5; + else + quota_delta = max_quota_out / 5; + + if ((throughput_out > (max_quota_out + quota_delta)) || + (throughput_in > (max_quota_in + quota_delta))) + ok = 1; + else + ok = 0; + GNUNET_STATISTICS_get (p1.stats, "core", "# discarded CORE_SEND requests", + GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p1); + + GNUNET_STATISTICS_get (p1.stats, "core", + "# discarded CORE_SEND request bytes", + GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p1); + GNUNET_STATISTICS_get (p1.stats, "core", + "# discarded lower priority CORE_SEND requests", + GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, NULL); + GNUNET_STATISTICS_get (p1.stats, "core", + "# discarded lower priority CORE_SEND request bytes", + GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p1); + GNUNET_STATISTICS_get (p2.stats, "core", "# discarded CORE_SEND requests", + GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); + + GNUNET_STATISTICS_get (p2.stats, "core", + "# discarded CORE_SEND request bytes", + GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); + GNUNET_STATISTICS_get (p2.stats, "core", + "# discarded lower priority CORE_SEND requests", + GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); + GNUNET_STATISTICS_get (p2.stats, "core", + "# discarded lower priority CORE_SEND request bytes", + GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); + + if (ok != 0) + kind = GNUNET_ERROR_TYPE_ERROR; + switch (test) + { + case SYMMETRIC: + GNUNET_log (kind, "Core quota compliance test with symmetric quotas: %s\n", + (ok != 0) ? "PASSED" : "FAILED"); + break; + case ASYMMETRIC_SEND_LIMITED: + GNUNET_log (kind, + "Core quota compliance test with limited sender quota: %s\n", + (ok != 0) ? "PASSED" : "FAILED"); + break; + case ASYMMETRIC_RECV_LIMITED: + GNUNET_log (kind, + "Core quota compliance test with limited receiver quota: %s\n", + (ok != 0) ? "PASSED" : "FAILED"); + break; + }; + GNUNET_log (kind, "Peer 1 send rate: %llu b/s (%llu bytes in %llu ms)\n", + throughput_out, total_bytes_sent, delta); + GNUNET_log (kind, "Peer 1 send quota: %llu b/s\n", current_quota_p1_out); + GNUNET_log (kind, "Peer 2 receive rate: %llu b/s (%llu bytes in %llu ms)\n", + throughput_in, total_bytes_recv, delta); + GNUNET_log (kind, "Peer 2 receive quota: %llu b/s\n", current_quota_p2_in); +/* + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Max. inbound quota allowed: %llu b/s\n",max_quota_in ); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Max. outbound quota allowed: %llu b/s\n",max_quota_out); +*/ + GNUNET_SCHEDULER_cancel (err_task); + err_task = GNUNET_SCHEDULER_add_now (&terminate_task, NULL); + +} + +static size_t +transmit_ready (void *cls, size_t size, void *buf) +{ + char *cbuf = buf; + struct TestMessage hdr; + unsigned int ret; + + p1.nth = NULL; + GNUNET_assert (size <= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE); + if (buf == NULL) + { + if ((p1.ch != NULL) && (p1.connect_status == 1)) + GNUNET_break (NULL != + (p1.nth = + GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, + FAST_TIMEOUT, &p2.id, + MESSAGESIZE, + &transmit_ready, &p1))); + return 0; + } + GNUNET_assert (tr_n < TOTAL_MSGS); + ret = 0; + GNUNET_assert (size >= MESSAGESIZE); + GNUNET_assert (buf != NULL); + cbuf = buf; + do + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message %u of size %u at offset %u\n", tr_n, + MESSAGESIZE, ret); + hdr.header.size = htons (MESSAGESIZE); + hdr.header.type = htons (MTYPE); + hdr.num = htonl (tr_n); + memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); + ret += sizeof (struct TestMessage); + memset (&cbuf[ret], tr_n, MESSAGESIZE - sizeof (struct TestMessage)); + ret += MESSAGESIZE - sizeof (struct TestMessage); + tr_n++; + if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) + break; /* sometimes pack buffer full, sometimes not */ + } + while (size - ret >= MESSAGESIZE); + GNUNET_SCHEDULER_cancel (err_task); + err_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); + + total_bytes_sent += ret; + return ret; +} + + + +static void +connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct PeerContext *pc = cls; + + if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) + return; /* loopback */ + GNUNET_assert (pc->connect_status == 0); + pc->connect_status = 1; + if (pc == &p1) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Encrypted connection established to peer `%4s'\n", + GNUNET_i2s (peer)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&p2.id)); + if (err_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (err_task); + err_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); + start_time = GNUNET_TIME_absolute_get (); + running = GNUNET_YES; + measure_task = + GNUNET_SCHEDULER_add_delayed (MEASUREMENT_LENGTH, &measurement_stop, + NULL); + + GNUNET_break (NULL != + (p1.nth = + GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, + TIMEOUT, &p2.id, + MESSAGESIZE, + &transmit_ready, &p1))); + } +} + + +static void +disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *pc = cls; + + if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) + return; /* loopback */ + pc->connect_status = 0; + if (GNUNET_SCHEDULER_NO_TASK != measure_task) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Measurement aborted due to disconnect!\n"); + GNUNET_SCHEDULER_cancel (measure_task); + measure_task = GNUNET_SCHEDULER_NO_TASK; + } + if (pc->nth != NULL) + { + GNUNET_CORE_notify_transmit_ready_cancel (pc->nth); + pc->nth = NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted connection to `%4s' cut\n", + GNUNET_i2s (peer)); +} + + +static int +inbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core provides inbound data from `%4s' %llu.\n", + GNUNET_i2s (other), ntohs (message->size)); + total_bytes_recv += ntohs (message->size); + return GNUNET_OK; +} + + +static int +outbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core notifies about outbound data for `%4s'.\n", + GNUNET_i2s (other)); + return GNUNET_OK; +} + + +static size_t +transmit_ready (void *cls, size_t size, void *buf); + +static int +process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + static int n; + const struct TestMessage *hdr; + + hdr = (const struct TestMessage *) message; + if (MTYPE != ntohs (message->type)) + return GNUNET_SYSERR; + if (ntohs (message->size) != MESSAGESIZE) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u of size %u, got %u bytes of message %u\n", + n, MESSAGESIZE, ntohs (message->size), ntohl (hdr->num)); + GNUNET_SCHEDULER_cancel (err_task); + err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, NULL); + return GNUNET_SYSERR; + } + if (ntohl (hdr->num) != n) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u of size %u, got %u bytes of message %u\n", + n, MESSAGESIZE, ntohs (message->size), ntohl (hdr->num)); + GNUNET_SCHEDULER_cancel (err_task); + err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, NULL); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message %u of size %u\n", + ntohl (hdr->num), ntohs (message->size)); + n++; + if (0 == (n % 10)) + FPRINTF (stderr, "%s", "."); + + + if (running == GNUNET_YES) + GNUNET_break (NULL != + GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, + FAST_TIMEOUT, &p2.id, + MESSAGESIZE, + &transmit_ready, &p1)); + return GNUNET_OK; +} + + +static struct GNUNET_CORE_MessageHandler handlers[] = { + {&process_mtype, MTYPE, 0}, + {NULL, 0, 0} +}; + + + +static void +init_notify (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connection to CORE service of `%4s' established\n", + GNUNET_i2s (my_identity)); + GNUNET_assert (server != NULL); + p->id = *my_identity; + GNUNET_assert (p->ch == server); + if (cls == &p1) + { + GNUNET_assert (ok == 2); + OKPP; + /* connect p2 */ + p2.ch = + GNUNET_CORE_connect (p2.cfg, 1, &p2, &init_notify, &connect_notify, + &disconnect_notify, &inbound_notify, GNUNET_YES, + &outbound_notify, GNUNET_YES, handlers); + } + else + { + GNUNET_assert (ok == 3); + OKPP; + GNUNET_assert (cls == &p2); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking core (1) to connect to peer `%4s'\n", + GNUNET_i2s (&p2.id)); + connect_task = GNUNET_SCHEDULER_add_now (&try_connect, NULL); + } +} + + +static void +process_hello (void *cls, const struct GNUNET_MessageHeader *message) +{ + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received (my) `%s' from transport service\n", "HELLO"); + GNUNET_assert (message != NULL); + p->hello = GNUNET_malloc (ntohs (message->size)); + memcpy (p->hello, message, ntohs (message->size)); + if ((p == &p1) && (p2.th != NULL)) + GNUNET_TRANSPORT_offer_hello (p2.th, message, NULL, NULL); + if ((p == &p2) && (p1.th != NULL)) + GNUNET_TRANSPORT_offer_hello (p1.th, message, NULL, NULL); + + if ((p == &p1) && (p2.hello != NULL)) + GNUNET_TRANSPORT_offer_hello (p1.th, p2.hello, NULL, NULL); + if ((p == &p2) && (p1.hello != NULL)) + GNUNET_TRANSPORT_offer_hello (p2.th, p1.hello, NULL, NULL); +} + + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + p->stats = GNUNET_STATISTICS_create ("core", p->cfg); + GNUNET_assert (p->stats != NULL); + p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, NULL, NULL); + GNUNET_assert (p->th != NULL); + p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_assert (ok == 1); + OKPP; + err_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); + if (test == SYMMETRIC) + { + setup_peer (&p1, "test_core_quota_peer1.conf"); + setup_peer (&p2, "test_core_quota_peer2.conf"); + } + else if (test == ASYMMETRIC_SEND_LIMITED) + { + setup_peer (&p1, "test_core_quota_asymmetric_send_limit_peer1.conf"); + setup_peer (&p2, "test_core_quota_asymmetric_send_limit_peer2.conf"); + } + else if (test == ASYMMETRIC_RECV_LIMITED) + { + setup_peer (&p1, "test_core_quota_asymmetric_recv_limited_peer1.conf"); + setup_peer (&p2, "test_core_quota_asymmetric_recv_limited_peer2.conf"); + } + + GNUNET_assert (test != -1); + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONFIGURATION_get_value_size (p1.cfg, "ATS", + "WAN_QUOTA_IN", + ¤t_quota_p1_in)); + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONFIGURATION_get_value_size (p2.cfg, "ATS", + "WAN_QUOTA_IN", + ¤t_quota_p2_in)); + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONFIGURATION_get_value_size (p1.cfg, "ATS", + "WAN_QUOTA_OUT", + ¤t_quota_p1_out)); + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONFIGURATION_get_value_size (p2.cfg, "ATS", + "WAN_QUOTA_OUT", + ¤t_quota_p2_out)); + + p1.ch = + GNUNET_CORE_connect (p1.cfg, 1, &p1, &init_notify, &connect_notify, + &disconnect_notify, &inbound_notify, GNUNET_YES, + &outbound_notify, GNUNET_YES, handlers); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + +static int +check () +{ + + + char *const argv[] = { "test-core-quota-compliance", + "-c", + "test_core_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-core-quota-compliance", "nohelp", options, &run, + &ok); + stop_arm (&p1); + stop_arm (&p2); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + test = -1; + if (strstr (argv[0], "_symmetric") != NULL) + { + test = SYMMETRIC; + } + else if (strstr (argv[0], "_asymmetric_send") != NULL) + { + test = ASYMMETRIC_SEND_LIMITED; + } + else if (strstr (argv[0], "_asymmetric_recv") != NULL) + { + test = ASYMMETRIC_RECV_LIMITED; + } + GNUNET_assert (test != -1); + if (test == SYMMETRIC) + { + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-sym-peer-1/"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-sym-peer-2/"); + } + else if (test == ASYMMETRIC_SEND_LIMITED) + { + GNUNET_DISK_directory_remove + ("/tmp/test-gnunet-core-quota-asym-send-lim-peer-1/"); + GNUNET_DISK_directory_remove + ("/tmp/test-gnunet-core-quota-asym-send-lim-peer-2/"); + } + else if (test == ASYMMETRIC_RECV_LIMITED) + { + GNUNET_DISK_directory_remove + ("/tmp/test-gnunet-core-quota-asym-recv-lim-peer-1/"); + GNUNET_DISK_directory_remove + ("/tmp/test-gnunet-core-quota-asym-recv-lim-peer-2/"); + } + + GNUNET_log_setup ("test-core-quota-compliance", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + if (test == SYMMETRIC) + { + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-sym-peer-1/"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-sym-peer-2/"); + } + else if (test == ASYMMETRIC_SEND_LIMITED) + { + GNUNET_DISK_directory_remove + ("/tmp/test-gnunet-core-quota-asym-send-lim-peer-1/"); + GNUNET_DISK_directory_remove + ("/tmp/test-gnunet-core-quota-asym-send-lim-peer-2/"); + } + else if (test == ASYMMETRIC_RECV_LIMITED) + { + GNUNET_DISK_directory_remove + ("/tmp/test-gnunet-core-quota-asym-recv-lim-peer-1/"); + GNUNET_DISK_directory_remove + ("/tmp/test-gnunet-core-quota-asym-recv-lim-peer-2/"); + } + + + + return ret; +} + +/* end of test_core_api_reliability.c */ diff --git a/src/core/test_core_quota_peer1.conf b/src/core/test_core_quota_peer1.conf new file mode 100644 index 0000000..4ff2ee4 --- /dev/null +++ b/src/core/test_core_quota_peer1.conf @@ -0,0 +1,40 @@ +@INLINE@ test_core_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-core-quota-sym-peer-1/ +DEFAULTCONFIG = test_core_quota_peer1.conf + +[transport-tcp] +PORT = 12468 + +[arm] +PORT = 12476 +UNIXPATH = /tmp/gnunet-core-sym-p1-service-arm.sock + +[statistics] +PORT = 12477 +UNIXPATH = /tmp/gnunet-core-sym-p1-service-statistics.sock + +[resolver] +PORT = 12474 +UNIXPATH = /tmp/gnunet-core-sym-p1-service-resolver.sock + +[peerinfo] +PORT = 12479 +UNIXPATH = /tmp/gnunet-core-sym-p1-service-peerinfo.sock + +[transport] +PORT = 12475 +UNIXPATH = /tmp/gnunet-core-sym-p1-service-transport.sock + +[ats] +WAN_QUOTA_IN = 10240 +WAN_QUOTA_OUT = 10240 + +[core] +PORT = 12480 +UNIXPATH = /tmp/gnunet-core-sym-p1-service-core.sock +DEBUG = NO + +[ats] +PORT = 12481 +UNIXPATH = /tmp/gnunet-core-sym-p1-service-ats.sock diff --git a/src/core/test_core_quota_peer2.conf b/src/core/test_core_quota_peer2.conf new file mode 100644 index 0000000..61e03fb --- /dev/null +++ b/src/core/test_core_quota_peer2.conf @@ -0,0 +1,38 @@ +@INLINE@ test_core_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-core-quota-sym-peer-2/ +DEFAULTCONFIG = test_core_quota_peer2.conf + +[transport-tcp] +PORT = 22478 + +[arm] +PORT = 22476 +UNIXPATH = /tmp/gnunet-core-sym-p2-service-arm.sock + +[statistics] +PORT = 22477 +UNIXPATH = /tmp/gnunet-core-sym-p2-service-statistics.sock + +[resolver] +PORT = 22474 +UNIXPATH = /tmp/gnunet-core-sym-p2-service-resolver.sock + +[peerinfo] +PORT = 22479 +UNIXPATH = /tmp/gnunet-core-sym-p2-service-peerinfo.sock + +[transport] +PORT = 22475 +UNIXPATH = /tmp/gnunet-core-sym-p2-service-transport.sock + +[core] +PORT = 22480 +UNIXPATH = /tmp/gnunet-core-sym-p2-service-core.sock +DEBUG = NO + +[ats] +PORT = 22482 +UNIXPATH = /tmp/gnunet-core-sym-p2-service-ats.sock +WAN_QUOTA_IN = 10 kiB +WAN_QUOTA_OUT = 10 kiB diff --git a/src/datacache/Makefile.am b/src/datacache/Makefile.am new file mode 100644 index 0000000..6b3f916 --- /dev/null +++ b/src/datacache/Makefile.am @@ -0,0 +1,190 @@ +INCLUDES = -I$(top_srcdir)/src/include + +plugindir = $(libdir)/gnunet + +pkgcfgdir= $(pkgdatadir)/config.d/ + +dist_pkgcfg_DATA = \ + datacache.conf + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIBS = -lgcov +endif + +if HAVE_SQLITE + SQLITE_PLUGIN = libgnunet_plugin_datacache_sqlite.la +endif +if HAVE_MYSQL + MYSQL_PLUGIN = libgnunet_plugin_datacache_mysql.la +endif +if HAVE_POSTGRES + POSTGRES_PLUGIN = libgnunet_plugin_datacache_postgres.la +endif + +lib_LTLIBRARIES = \ + libgnunetdatacache.la + +libgnunetdatacache_la_SOURCES = \ + datacache.c +libgnunetdatacache_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +libgnunetdatacache_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:1:0 + + +plugin_LTLIBRARIES = \ + $(SQLITE_PLUGIN) \ + $(MYSQL_PLUGIN) \ + $(POSTGRES_PLUGIN) \ + libgnunet_plugin_datacache_template.la + + +libgnunet_plugin_datacache_sqlite_la_SOURCES = \ + plugin_datacache_sqlite.c +libgnunet_plugin_datacache_sqlite_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 +libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_datacache_mysql_la_SOURCES = \ + plugin_datacache_mysql.c +libgnunet_plugin_datacache_mysql_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient +libgnunet_plugin_datacache_mysql_la_CPPFLAGS = \ + $(MYSQL_CPPFLAGS) +libgnunet_plugin_datacache_mysql_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient + +libgnunet_plugin_datacache_postgres_la_SOURCES = \ + plugin_datacache_postgres.c +libgnunet_plugin_datacache_postgres_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq +libgnunet_plugin_datacache_postgres_la_CPPFLAGS = \ + $(POSTGRES_CPPFLAGS) +libgnunet_plugin_datacache_postgres_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq + +libgnunet_plugin_datacache_template_la_SOURCES = \ + plugin_datacache_template.c +libgnunet_plugin_datacache_template_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) +libgnunet_plugin_datacache_template_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + +if HAVE_SQLITE +if HAVE_BENCHMARKS + SQLITE_BENCHMARKS = \ + perf_datacache_sqlite +endif +SQLITE_TESTS = \ + test_datacache_sqlite \ + test_datacache_quota_sqlite \ + $(SQLITE_BENCHMARKS) +endif + +if HAVE_MYSQL +if HAVE_BENCHMARKS + MYSQL_BENCHMARKS = \ + perf_datacache_mysql +endif +MYSQL_TESTS = \ + test_datacache_mysql \ + test_datacache_quota_mysql \ + $(MYSQL_BENCHMARKS) +endif + +if HAVE_POSTGRES +if HAVE_BENCHMARKS + POSTGRES_BENCHMARKS = \ + perf_datacache_postgres +endif +POSTGRES_TESTS = \ + test_datacache_postgres \ + test_datacache_quota_postgres \ + $(POSTGRES_BENCHMARKS) +endif + +check_PROGRAMS = \ + $(SQLITE_TESTS) \ + $(MYSQL_TESTS) \ + $(POSTGRES_TESTS) + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_datacache_sqlite_SOURCES = \ + test_datacache.c +test_datacache_sqlite_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datacache_quota_sqlite_SOURCES = \ + test_datacache_quota.c +test_datacache_quota_sqlite_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datacache_sqlite_SOURCES = \ + perf_datacache.c +perf_datacache_sqlite_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datacache_mysql_SOURCES = \ + test_datacache.c +test_datacache_mysql_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datacache_quota_mysql_SOURCES = \ + test_datacache_quota.c +test_datacache_quota_mysql_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datacache_mysql_SOURCES = \ + perf_datacache.c +perf_datacache_mysql_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datacache_postgres_SOURCES = \ + test_datacache.c +test_datacache_postgres_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datacache_quota_postgres_SOURCES = \ + test_datacache_quota.c +test_datacache_quota_postgres_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datacache_postgres_SOURCES = \ + perf_datacache.c +perf_datacache_postgres_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_datacache_data_sqlite.conf \ + perf_datacache_data_sqlite.conf \ + test_datacache_data_mysql.conf \ + perf_datacache_data_mysql.conf \ + test_datacache_data_postgres.conf \ + perf_datacache_data_postgres.conf diff --git a/src/datacache/Makefile.in b/src/datacache/Makefile.in new file mode 100644 index 0000000..fd0d3e2 --- /dev/null +++ b/src/datacache/Makefile.in @@ -0,0 +1,1188 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +check_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_4) $(am__EXEEXT_6) +subdir = src/datacache +DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunet_plugin_datacache_mysql_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgnunet_plugin_datacache_mysql_la_OBJECTS = \ + libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo +libgnunet_plugin_datacache_mysql_la_OBJECTS = \ + $(am_libgnunet_plugin_datacache_mysql_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_datacache_mysql_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_datacache_mysql_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +@HAVE_MYSQL_TRUE@am_libgnunet_plugin_datacache_mysql_la_rpath = \ +@HAVE_MYSQL_TRUE@ -rpath $(plugindir) +libgnunet_plugin_datacache_postgres_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgnunet_plugin_datacache_postgres_la_OBJECTS = libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo +libgnunet_plugin_datacache_postgres_la_OBJECTS = \ + $(am_libgnunet_plugin_datacache_postgres_la_OBJECTS) +libgnunet_plugin_datacache_postgres_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_datacache_postgres_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +@HAVE_POSTGRES_TRUE@am_libgnunet_plugin_datacache_postgres_la_rpath = \ +@HAVE_POSTGRES_TRUE@ -rpath $(plugindir) +libgnunet_plugin_datacache_sqlite_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunet_plugin_datacache_sqlite_la_OBJECTS = \ + plugin_datacache_sqlite.lo +libgnunet_plugin_datacache_sqlite_la_OBJECTS = \ + $(am_libgnunet_plugin_datacache_sqlite_la_OBJECTS) +libgnunet_plugin_datacache_sqlite_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_datacache_sqlite_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +@HAVE_SQLITE_TRUE@am_libgnunet_plugin_datacache_sqlite_la_rpath = \ +@HAVE_SQLITE_TRUE@ -rpath $(plugindir) +libgnunet_plugin_datacache_template_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunet_plugin_datacache_template_la_OBJECTS = \ + plugin_datacache_template.lo +libgnunet_plugin_datacache_template_la_OBJECTS = \ + $(am_libgnunet_plugin_datacache_template_la_OBJECTS) +libgnunet_plugin_datacache_template_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_datacache_template_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +libgnunetdatacache_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunetdatacache_la_OBJECTS = datacache.lo +libgnunetdatacache_la_OBJECTS = $(am_libgnunetdatacache_la_OBJECTS) +libgnunetdatacache_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetdatacache_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@am__EXEEXT_1 = perf_datacache_sqlite$(EXEEXT) +@HAVE_SQLITE_TRUE@am__EXEEXT_2 = test_datacache_sqlite$(EXEEXT) \ +@HAVE_SQLITE_TRUE@ test_datacache_quota_sqlite$(EXEEXT) \ +@HAVE_SQLITE_TRUE@ $(am__EXEEXT_1) +@HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@am__EXEEXT_3 = perf_datacache_mysql$(EXEEXT) +@HAVE_MYSQL_TRUE@am__EXEEXT_4 = test_datacache_mysql$(EXEEXT) \ +@HAVE_MYSQL_TRUE@ test_datacache_quota_mysql$(EXEEXT) \ +@HAVE_MYSQL_TRUE@ $(am__EXEEXT_3) +@HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@am__EXEEXT_5 = perf_datacache_postgres$(EXEEXT) +@HAVE_POSTGRES_TRUE@am__EXEEXT_6 = test_datacache_postgres$(EXEEXT) \ +@HAVE_POSTGRES_TRUE@ test_datacache_quota_postgres$(EXEEXT) \ +@HAVE_POSTGRES_TRUE@ $(am__EXEEXT_5) +am_perf_datacache_mysql_OBJECTS = perf_datacache.$(OBJEXT) +perf_datacache_mysql_OBJECTS = $(am_perf_datacache_mysql_OBJECTS) +perf_datacache_mysql_DEPENDENCIES = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_datacache_postgres_OBJECTS = perf_datacache.$(OBJEXT) +perf_datacache_postgres_OBJECTS = \ + $(am_perf_datacache_postgres_OBJECTS) +perf_datacache_postgres_DEPENDENCIES = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_datacache_sqlite_OBJECTS = perf_datacache.$(OBJEXT) +perf_datacache_sqlite_OBJECTS = $(am_perf_datacache_sqlite_OBJECTS) +perf_datacache_sqlite_DEPENDENCIES = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datacache_mysql_OBJECTS = test_datacache.$(OBJEXT) +test_datacache_mysql_OBJECTS = $(am_test_datacache_mysql_OBJECTS) +test_datacache_mysql_DEPENDENCIES = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datacache_postgres_OBJECTS = test_datacache.$(OBJEXT) +test_datacache_postgres_OBJECTS = \ + $(am_test_datacache_postgres_OBJECTS) +test_datacache_postgres_DEPENDENCIES = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datacache_quota_mysql_OBJECTS = \ + test_datacache_quota.$(OBJEXT) +test_datacache_quota_mysql_OBJECTS = \ + $(am_test_datacache_quota_mysql_OBJECTS) +test_datacache_quota_mysql_DEPENDENCIES = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datacache_quota_postgres_OBJECTS = \ + test_datacache_quota.$(OBJEXT) +test_datacache_quota_postgres_OBJECTS = \ + $(am_test_datacache_quota_postgres_OBJECTS) +test_datacache_quota_postgres_DEPENDENCIES = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datacache_quota_sqlite_OBJECTS = \ + test_datacache_quota.$(OBJEXT) +test_datacache_quota_sqlite_OBJECTS = \ + $(am_test_datacache_quota_sqlite_OBJECTS) +test_datacache_quota_sqlite_DEPENDENCIES = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datacache_sqlite_OBJECTS = test_datacache.$(OBJEXT) +test_datacache_sqlite_OBJECTS = $(am_test_datacache_sqlite_OBJECTS) +test_datacache_sqlite_DEPENDENCIES = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunet_plugin_datacache_mysql_la_SOURCES) \ + $(libgnunet_plugin_datacache_postgres_la_SOURCES) \ + $(libgnunet_plugin_datacache_sqlite_la_SOURCES) \ + $(libgnunet_plugin_datacache_template_la_SOURCES) \ + $(libgnunetdatacache_la_SOURCES) \ + $(perf_datacache_mysql_SOURCES) \ + $(perf_datacache_postgres_SOURCES) \ + $(perf_datacache_sqlite_SOURCES) \ + $(test_datacache_mysql_SOURCES) \ + $(test_datacache_postgres_SOURCES) \ + $(test_datacache_quota_mysql_SOURCES) \ + $(test_datacache_quota_postgres_SOURCES) \ + $(test_datacache_quota_sqlite_SOURCES) \ + $(test_datacache_sqlite_SOURCES) +DIST_SOURCES = $(libgnunet_plugin_datacache_mysql_la_SOURCES) \ + $(libgnunet_plugin_datacache_postgres_la_SOURCES) \ + $(libgnunet_plugin_datacache_sqlite_la_SOURCES) \ + $(libgnunet_plugin_datacache_template_la_SOURCES) \ + $(libgnunetdatacache_la_SOURCES) \ + $(perf_datacache_mysql_SOURCES) \ + $(perf_datacache_postgres_SOURCES) \ + $(perf_datacache_sqlite_SOURCES) \ + $(test_datacache_mysql_SOURCES) \ + $(test_datacache_postgres_SOURCES) \ + $(test_datacache_quota_mysql_SOURCES) \ + $(test_datacache_quota_postgres_SOURCES) \ + $(test_datacache_quota_sqlite_SOURCES) \ + $(test_datacache_sqlite_SOURCES) +DATA = $(dist_pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +plugindir = $(libdir)/gnunet +pkgcfgdir = $(pkgdatadir)/config.d/ +dist_pkgcfg_DATA = \ + datacache.conf + +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIBS = -lgcov +@HAVE_SQLITE_TRUE@SQLITE_PLUGIN = libgnunet_plugin_datacache_sqlite.la +@HAVE_MYSQL_TRUE@MYSQL_PLUGIN = libgnunet_plugin_datacache_mysql.la +@HAVE_POSTGRES_TRUE@POSTGRES_PLUGIN = libgnunet_plugin_datacache_postgres.la +lib_LTLIBRARIES = \ + libgnunetdatacache.la + +libgnunetdatacache_la_SOURCES = \ + datacache.c + +libgnunetdatacache_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +libgnunetdatacache_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:1:0 + +plugin_LTLIBRARIES = \ + $(SQLITE_PLUGIN) \ + $(MYSQL_PLUGIN) \ + $(POSTGRES_PLUGIN) \ + libgnunet_plugin_datacache_template.la + +libgnunet_plugin_datacache_sqlite_la_SOURCES = \ + plugin_datacache_sqlite.c + +libgnunet_plugin_datacache_sqlite_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 + +libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_datacache_mysql_la_SOURCES = \ + plugin_datacache_mysql.c + +libgnunet_plugin_datacache_mysql_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient + +libgnunet_plugin_datacache_mysql_la_CPPFLAGS = \ + $(MYSQL_CPPFLAGS) + +libgnunet_plugin_datacache_mysql_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient + +libgnunet_plugin_datacache_postgres_la_SOURCES = \ + plugin_datacache_postgres.c + +libgnunet_plugin_datacache_postgres_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq + +libgnunet_plugin_datacache_postgres_la_CPPFLAGS = \ + $(POSTGRES_CPPFLAGS) + +libgnunet_plugin_datacache_postgres_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq + +libgnunet_plugin_datacache_template_la_SOURCES = \ + plugin_datacache_template.c + +libgnunet_plugin_datacache_template_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) + +libgnunet_plugin_datacache_template_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +@HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@SQLITE_BENCHMARKS = \ +@HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@ perf_datacache_sqlite + +@HAVE_SQLITE_TRUE@SQLITE_TESTS = \ +@HAVE_SQLITE_TRUE@ test_datacache_sqlite \ +@HAVE_SQLITE_TRUE@ test_datacache_quota_sqlite \ +@HAVE_SQLITE_TRUE@ $(SQLITE_BENCHMARKS) + +@HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@MYSQL_BENCHMARKS = \ +@HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@ perf_datacache_mysql + +@HAVE_MYSQL_TRUE@MYSQL_TESTS = \ +@HAVE_MYSQL_TRUE@ test_datacache_mysql \ +@HAVE_MYSQL_TRUE@ test_datacache_quota_mysql \ +@HAVE_MYSQL_TRUE@ $(MYSQL_BENCHMARKS) + +@HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@POSTGRES_BENCHMARKS = \ +@HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@ perf_datacache_postgres + +@HAVE_POSTGRES_TRUE@POSTGRES_TESTS = \ +@HAVE_POSTGRES_TRUE@ test_datacache_postgres \ +@HAVE_POSTGRES_TRUE@ test_datacache_quota_postgres \ +@HAVE_POSTGRES_TRUE@ $(POSTGRES_BENCHMARKS) + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_datacache_sqlite_SOURCES = \ + test_datacache.c + +test_datacache_sqlite_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datacache_quota_sqlite_SOURCES = \ + test_datacache_quota.c + +test_datacache_quota_sqlite_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datacache_sqlite_SOURCES = \ + perf_datacache.c + +perf_datacache_sqlite_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datacache_mysql_SOURCES = \ + test_datacache.c + +test_datacache_mysql_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datacache_quota_mysql_SOURCES = \ + test_datacache_quota.c + +test_datacache_quota_mysql_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datacache_mysql_SOURCES = \ + perf_datacache.c + +perf_datacache_mysql_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datacache_postgres_SOURCES = \ + test_datacache.c + +test_datacache_postgres_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datacache_quota_postgres_SOURCES = \ + test_datacache_quota.c + +test_datacache_quota_postgres_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datacache_postgres_SOURCES = \ + perf_datacache.c + +perf_datacache_postgres_LDADD = \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_datacache_data_sqlite.conf \ + perf_datacache_data_sqlite.conf \ + test_datacache_data_mysql.conf \ + perf_datacache_data_mysql.conf \ + test_datacache_data_postgres.conf \ + perf_datacache_data_postgres.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/datacache/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/datacache/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_datacache_mysql.la: $(libgnunet_plugin_datacache_mysql_la_OBJECTS) $(libgnunet_plugin_datacache_mysql_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_datacache_mysql_la_LINK) $(am_libgnunet_plugin_datacache_mysql_la_rpath) $(libgnunet_plugin_datacache_mysql_la_OBJECTS) $(libgnunet_plugin_datacache_mysql_la_LIBADD) $(LIBS) +libgnunet_plugin_datacache_postgres.la: $(libgnunet_plugin_datacache_postgres_la_OBJECTS) $(libgnunet_plugin_datacache_postgres_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_datacache_postgres_la_LINK) $(am_libgnunet_plugin_datacache_postgres_la_rpath) $(libgnunet_plugin_datacache_postgres_la_OBJECTS) $(libgnunet_plugin_datacache_postgres_la_LIBADD) $(LIBS) +libgnunet_plugin_datacache_sqlite.la: $(libgnunet_plugin_datacache_sqlite_la_OBJECTS) $(libgnunet_plugin_datacache_sqlite_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_datacache_sqlite_la_LINK) $(am_libgnunet_plugin_datacache_sqlite_la_rpath) $(libgnunet_plugin_datacache_sqlite_la_OBJECTS) $(libgnunet_plugin_datacache_sqlite_la_LIBADD) $(LIBS) +libgnunet_plugin_datacache_template.la: $(libgnunet_plugin_datacache_template_la_OBJECTS) $(libgnunet_plugin_datacache_template_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_datacache_template_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_datacache_template_la_OBJECTS) $(libgnunet_plugin_datacache_template_la_LIBADD) $(LIBS) +libgnunetdatacache.la: $(libgnunetdatacache_la_OBJECTS) $(libgnunetdatacache_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetdatacache_la_LINK) -rpath $(libdir) $(libgnunetdatacache_la_OBJECTS) $(libgnunetdatacache_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +perf_datacache_mysql$(EXEEXT): $(perf_datacache_mysql_OBJECTS) $(perf_datacache_mysql_DEPENDENCIES) + @rm -f perf_datacache_mysql$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_datacache_mysql_OBJECTS) $(perf_datacache_mysql_LDADD) $(LIBS) +perf_datacache_postgres$(EXEEXT): $(perf_datacache_postgres_OBJECTS) $(perf_datacache_postgres_DEPENDENCIES) + @rm -f perf_datacache_postgres$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_datacache_postgres_OBJECTS) $(perf_datacache_postgres_LDADD) $(LIBS) +perf_datacache_sqlite$(EXEEXT): $(perf_datacache_sqlite_OBJECTS) $(perf_datacache_sqlite_DEPENDENCIES) + @rm -f perf_datacache_sqlite$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_datacache_sqlite_OBJECTS) $(perf_datacache_sqlite_LDADD) $(LIBS) +test_datacache_mysql$(EXEEXT): $(test_datacache_mysql_OBJECTS) $(test_datacache_mysql_DEPENDENCIES) + @rm -f test_datacache_mysql$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datacache_mysql_OBJECTS) $(test_datacache_mysql_LDADD) $(LIBS) +test_datacache_postgres$(EXEEXT): $(test_datacache_postgres_OBJECTS) $(test_datacache_postgres_DEPENDENCIES) + @rm -f test_datacache_postgres$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datacache_postgres_OBJECTS) $(test_datacache_postgres_LDADD) $(LIBS) +test_datacache_quota_mysql$(EXEEXT): $(test_datacache_quota_mysql_OBJECTS) $(test_datacache_quota_mysql_DEPENDENCIES) + @rm -f test_datacache_quota_mysql$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datacache_quota_mysql_OBJECTS) $(test_datacache_quota_mysql_LDADD) $(LIBS) +test_datacache_quota_postgres$(EXEEXT): $(test_datacache_quota_postgres_OBJECTS) $(test_datacache_quota_postgres_DEPENDENCIES) + @rm -f test_datacache_quota_postgres$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datacache_quota_postgres_OBJECTS) $(test_datacache_quota_postgres_LDADD) $(LIBS) +test_datacache_quota_sqlite$(EXEEXT): $(test_datacache_quota_sqlite_OBJECTS) $(test_datacache_quota_sqlite_DEPENDENCIES) + @rm -f test_datacache_quota_sqlite$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datacache_quota_sqlite_OBJECTS) $(test_datacache_quota_sqlite_LDADD) $(LIBS) +test_datacache_sqlite$(EXEEXT): $(test_datacache_sqlite_OBJECTS) $(test_datacache_sqlite_DEPENDENCIES) + @rm -f test_datacache_sqlite$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datacache_sqlite_OBJECTS) $(test_datacache_sqlite_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datacache.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_datacache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_datacache_sqlite.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_datacache_template.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_datacache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_datacache_quota.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo: plugin_datacache_mysql.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datacache_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.Tpo -c -o libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo `test -f 'plugin_datacache_mysql.c' || echo '$(srcdir)/'`plugin_datacache_mysql.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.Tpo $(DEPDIR)/libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_datacache_mysql.c' object='libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datacache_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo `test -f 'plugin_datacache_mysql.c' || echo '$(srcdir)/'`plugin_datacache_mysql.c + +libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo: plugin_datacache_postgres.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datacache_postgres_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.Tpo -c -o libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo `test -f 'plugin_datacache_postgres.c' || echo '$(srcdir)/'`plugin_datacache_postgres.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.Tpo $(DEPDIR)/libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_datacache_postgres.c' object='libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datacache_postgres_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo `test -f 'plugin_datacache_postgres.c' || echo '$(srcdir)/'`plugin_datacache_postgres.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-dist_pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_pkgcfgDATA install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_pkgcfgDATA uninstall-libLTLIBRARIES \ + uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-dist_pkgcfgDATA install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-dist_pkgcfgDATA uninstall-libLTLIBRARIES \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/datacache/datacache.c b/src/datacache/datacache.c new file mode 100644 index 0000000..936031b --- /dev/null +++ b/src/datacache/datacache.c @@ -0,0 +1,304 @@ +/* + This file is part of GNUnet + (C) 2004, 2005, 2006, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datacache/datacache.c + * @brief datacache API implementation + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_datacache_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_datacache_plugin.h" + +#define DEBUG_DATACACHE GNUNET_EXTRA_LOGGING + +#define LOG(kind,...) GNUNET_log_from (kind, "datacache", __VA_ARGS__) + +#define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache", op, fn) + +/** + * Internal state of the datacache library. + */ +struct GNUNET_DATACACHE_Handle +{ + + /** + * Bloomfilter to quickly tell if we don't have the content. + */ + struct GNUNET_CONTAINER_BloomFilter *filter; + + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Opaque handle for the statistics service. + */ + struct GNUNET_STATISTICS_Handle *stats; + + /** + * Configuration section to use. + */ + char *section; + + /** + * API of the transport as returned by the plugin's + * initialization function. + */ + struct GNUNET_DATACACHE_PluginFunctions *api; + + /** + * Short name for the plugin (i.e. "sqlite"). + */ + char *short_name; + + /** + * Name of the library (i.e. "gnunet_plugin_datacache_sqlite"). + */ + char *lib_name; + + /** + * Name for the bloom filter file. + */ + char *bloom_name; + + /** + * Environment provided to our plugin. + */ + struct GNUNET_DATACACHE_PluginEnvironment env; + + /** + * How much space is in use right now? + */ + unsigned long long utilization; + +}; + + +/** + * Function called by plugins to notify the datacache + * about content deletions. + * + * @param cls closure + * @param key key of the content that was deleted + * @param size number of bytes that were made available + */ +static void +env_delete_notify (void *cls, const GNUNET_HashCode * key, size_t size) +{ + struct GNUNET_DATACACHE_Handle *h = cls; + +#if DEBUG_DATACACHE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Content under key `%s' discarded\n", + GNUNET_h2s (key)); +#endif + GNUNET_assert (h->utilization >= size); + h->utilization -= size; + GNUNET_CONTAINER_bloomfilter_remove (h->filter, key); + GNUNET_STATISTICS_update (h->stats, gettext_noop ("# bytes stored"), -size, + GNUNET_NO); +} + + +/** + * Create a data cache. + * + * @param cfg configuration to use + * @param section section in the configuration that contains our options + * @return handle to use to access the service + */ +struct GNUNET_DATACACHE_Handle * +GNUNET_DATACACHE_create (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section) +{ + unsigned int bf_size; + unsigned long long quota; + struct GNUNET_DATACACHE_Handle *ret; + char *libname; + char *name; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_size (cfg, section, "QUOTA", "a)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("No `%s' specified for `%s' in configuration!\n"), "QUOTA", section); + return NULL; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, section, "DATABASE", &name)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", + section); + return NULL; + } + bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */ + + ret = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_Handle)); + ret->bloom_name = GNUNET_DISK_mktemp ("gnunet-datacachebloom"); + if (NULL != ret->bloom_name) + { + ret->filter = GNUNET_CONTAINER_bloomfilter_load (ret->bloom_name, quota / 1024, /* 8 bit per entry in DB, expect 1k entries */ + 5); + } + if (NULL == ret->filter) + { + ret->filter = GNUNET_CONTAINER_bloomfilter_init (NULL, bf_size, 5); /* approx. 3% false positives at max use */ + } + if (NULL == ret->filter) + { + GNUNET_free (name); + GNUNET_free (ret->bloom_name); + GNUNET_free (ret); + return NULL; + } + ret->stats = GNUNET_STATISTICS_create ("datacache", cfg); + ret->section = GNUNET_strdup (section); + ret->env.cfg = cfg; + ret->env.delete_notify = &env_delete_notify; + ret->env.section = ret->section; + ret->env.cls = ret; + ret->env.delete_notify = &env_delete_notify; + ret->env.quota = quota; + LOG (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datacache plugin\n"), name); + GNUNET_asprintf (&libname, "libgnunet_plugin_datacache_%s", name); + ret->short_name = name; + ret->lib_name = libname; + ret->api = GNUNET_PLUGIN_load (libname, &ret->env); + if (ret->api == NULL) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Failed to load datacache plugin for `%s'\n"), name); + GNUNET_DATACACHE_destroy (ret); + return NULL; + } + return ret; +} + + +/** + * Destroy a data cache (and free associated resources). + * + * @param h handle to the datastore + */ +void +GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h) +{ + if (h->filter != NULL) + GNUNET_CONTAINER_bloomfilter_free (h->filter); + if (h->api != NULL) + GNUNET_break (NULL == GNUNET_PLUGIN_unload (h->lib_name, h->api)); + GNUNET_free (h->lib_name); + GNUNET_free (h->short_name); + GNUNET_free (h->section); + if (h->bloom_name != NULL) + { + if (0 != UNLINK (h->bloom_name)) + GNUNET_log_from_strerror_file (GNUNET_ERROR_TYPE_WARNING, "datacache", + "unlink", h->bloom_name); + GNUNET_free (h->bloom_name); + } + GNUNET_STATISTICS_destroy (h->stats, GNUNET_NO); + GNUNET_free (h); +} + + +/** + * Store an item in the datastore. + * + * @param h handle to the datacache + * @param key key to store data under + * @param size number of bytes in data + * @param data data to store + * @param type type of the value + * @param discard_time when to discard the value in any case + * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.) + */ +int +GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, + const GNUNET_HashCode * key, size_t size, + const char *data, enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute discard_time) +{ + uint32_t used; + + used = h->api->put (h->api->cls, key, size, data, type, discard_time); + if (used == 0) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } +#if DEBUG_DATACACHE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Stored data under key `%s' in cache\n", + GNUNET_h2s (key)); +#endif + GNUNET_STATISTICS_update (h->stats, gettext_noop ("# bytes stored"), size, + GNUNET_NO); + GNUNET_CONTAINER_bloomfilter_add (h->filter, key); + while (h->utilization + used > h->env.quota) + GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls)); + h->utilization += used; + return GNUNET_OK; +} + + +/** + * Iterate over the results for a particular key + * in the datacache. + * + * @param h handle to the datacache + * @param key what to look up + * @param type entries of which type are relevant? + * @param iter maybe NULL (to just count) + * @param iter_cls closure for iter + * @return the number of results found + */ +unsigned int +GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h, + const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, + GNUNET_DATACACHE_Iterator iter, void *iter_cls) +{ + GNUNET_STATISTICS_update (h->stats, gettext_noop ("# requests received"), 1, + GNUNET_NO); +#if DEBUG_DATACACHE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing request for key `%s'\n", + GNUNET_h2s (key)); +#endif + if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_test (h->filter, key)) + { + GNUNET_STATISTICS_update (h->stats, + gettext_noop + ("# requests filtered by bloom filter"), 1, + GNUNET_NO); +#if DEBUG_DATACACHE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Bloomfilter filters request for key `%s'\n", + GNUNET_h2s (key)); +#endif + return 0; /* can not be present */ + } + return h->api->get (h->api->cls, key, type, iter, iter_cls); +} + + + +/* end of datacache_api.c */ diff --git a/src/datacache/datacache.conf b/src/datacache/datacache.conf new file mode 100644 index 0000000..125a4e5 --- /dev/null +++ b/src/datacache/datacache.conf @@ -0,0 +1,10 @@ +[datacache-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf +# USER = gnunet +# PASSWORD = +# HOST = localhost +# PORT = 3306 + +[datacache-postgres] +CONFIG = connect_timeout=10; dbname=gnunet diff --git a/src/datacache/perf_datacache.c b/src/datacache/perf_datacache.c new file mode 100644 index 0000000..77edbf9 --- /dev/null +++ b/src/datacache/perf_datacache.c @@ -0,0 +1,175 @@ +/* + This file is part of GNUnet. + (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* + * @file datacache/perf_datacache.c + * @brief Performance evaluation for the datacache implementations. + * @author Nils Durner + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_datacache_lib.h" +#include + +#define VERBOSE GNUNET_NO + +#define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0) + +#define ITERATIONS 10000 + +static int ok; + +static unsigned int found; + +/** + * Name of plugin under test. + */ +static const char *plugin_name; + + +static int +checkIt (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, size_t size, const char *data, + enum GNUNET_BLOCK_Type type) +{ + if ((size == sizeof (GNUNET_HashCode)) && (0 == memcmp (data, cls, size))) + found++; + return GNUNET_OK; +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_DATACACHE_Handle *h; + GNUNET_HashCode k; + GNUNET_HashCode n; + struct GNUNET_TIME_Absolute exp; + struct GNUNET_TIME_Absolute start; + unsigned int i; + char gstr[128]; + + ok = 0; + h = GNUNET_DATACACHE_create (cfg, "perfcache"); + + if (h == NULL) + { + FPRINTF (stderr, "%s", "Failed to initialize datacache. Database likely not setup, skipping test.\n"); + return; + } + exp = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS); + start = GNUNET_TIME_absolute_get (); + memset (&k, 0, sizeof (GNUNET_HashCode)); + for (i = 0; i < ITERATIONS; i++) + { + if (0 == i % (ITERATIONS / 80)) + FPRINTF (stderr, "%s", "."); + GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); + ASSERT (GNUNET_OK == + GNUNET_DATACACHE_put (h, &k, sizeof (GNUNET_HashCode), + (const char *) &n, 1 + i % 16, exp)); + k = n; + } + FPRINTF (stderr, "%s", "\n"); + FPRINTF (stdout, "Stored %u items in %llums\n", ITERATIONS, + (unsigned long long) + GNUNET_TIME_absolute_get_duration (start).rel_value); + GNUNET_snprintf (gstr, sizeof (gstr), "DATACACHE-%s", plugin_name); + GAUGER (gstr, "Time to PUT item in datacache", + GNUNET_TIME_absolute_get_duration (start).rel_value / ITERATIONS, + "ms/item"); + start = GNUNET_TIME_absolute_get (); + memset (&k, 0, sizeof (GNUNET_HashCode)); + for (i = 0; i < ITERATIONS; i++) + { + if (0 == i % (ITERATIONS / 80)) + FPRINTF (stderr, "%s", "."); + GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); + GNUNET_DATACACHE_get (h, &k, 1 + i % 16, &checkIt, &n); + k = n; + } + FPRINTF (stderr, "%s", "\n"); + FPRINTF (stdout, + "Found %u/%u items in %llums (%u were deleted during storage processing)\n", + found, ITERATIONS, + (unsigned long long) + GNUNET_TIME_absolute_get_duration (start).rel_value, + ITERATIONS - found); + if (found > 0) + GAUGER (gstr, "Time to GET item from datacache", + GNUNET_TIME_absolute_get_duration (start).rel_value / found, + "ms/item"); + GNUNET_DATACACHE_destroy (h); + ASSERT (ok == 0); + return; +FAILURE: + if (h != NULL) + GNUNET_DATACACHE_destroy (h); + ok = GNUNET_SYSERR; +} + + +int +main (int argc, char *argv[]) +{ + char *pos; + char cfg_name[128]; + + char *const xargv[] = { + "perf-datacache", + "-c", + cfg_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("perf-datacache", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + /* determine name of plugin to use */ + plugin_name = argv[0]; + while (NULL != (pos = strstr (plugin_name, "_"))) + plugin_name = pos + 1; + if (NULL != (pos = strstr (plugin_name, "."))) + pos[0] = 0; + else + pos = (char *) plugin_name; + + GNUNET_snprintf (cfg_name, sizeof (cfg_name), "perf_datacache_data_%s.conf", + plugin_name); + if (pos != plugin_name) + pos[0] = '.'; + GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, + "perf-datacache", "nohelp", options, &run, NULL); + if (ok != 0) + FPRINTF (stderr, "Missed some perfcases: %d\n", ok); + return ok; +} + +/* end of perf_datacache.c */ diff --git a/src/datacache/perf_datacache_data_mysql.conf b/src/datacache/perf_datacache_data_mysql.conf new file mode 100644 index 0000000..1760f7d --- /dev/null +++ b/src/datacache/perf_datacache_data_mysql.conf @@ -0,0 +1,13 @@ +[perfcache] +QUOTA = 500 KB +DATABASE = mysql + +[datacache-mysql] +DATABASE = gnunetcheck +# CONFIG = ~/.my.cnf +# USER = +# PASSWORD = +# HOST = +# PORT = + + diff --git a/src/datacache/perf_datacache_data_postgres.conf b/src/datacache/perf_datacache_data_postgres.conf new file mode 100644 index 0000000..c92f52a --- /dev/null +++ b/src/datacache/perf_datacache_data_postgres.conf @@ -0,0 +1,8 @@ +[perfcache] +QUOTA = 500 KB +DATABASE = postgres + +[datacache-postgres] +CONFIG = connect_timeout=10; dbname=gnunetcheck + + diff --git a/src/datacache/perf_datacache_data_sqlite.conf b/src/datacache/perf_datacache_data_sqlite.conf new file mode 100644 index 0000000..9d0dbbd --- /dev/null +++ b/src/datacache/perf_datacache_data_sqlite.conf @@ -0,0 +1,4 @@ +[perfcache] +QUOTA = 500 KB +DATABASE = sqlite + diff --git a/src/datacache/plugin_datacache_mysql.c b/src/datacache/plugin_datacache_mysql.c new file mode 100644 index 0000000..9185c5c --- /dev/null +++ b/src/datacache/plugin_datacache_mysql.c @@ -0,0 +1,1005 @@ +/* + This file is part of GNUnet + (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datacache/plugin_datacache_mysql.c + * @brief mysql for an implementation of a database backend for the datacache + * @author Christian Grothoff + * + * SETUP INSTRUCTIONS: + * + * 1) Access mysql as root, + *
+ *
+ *    $ mysql -u root -p
+ *
+ *    
+ * and do the following. [You should replace $USER with the username + * that will be running the gnunetd process]. + * @verbatim + CREATE DATABASE gnunet; + GRANT select,insert,update,delete,create,alter,drop,create temporary tables + ON gnunet.* TO $USER@localhost; + SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like'); + FLUSH PRIVILEGES; + @endverbatim + * 2) In the $HOME directory of $USER, create a ".my.cnf" file + * with the following lines + * @verbatim + [client] + user=$USER + password=$the_password_you_like + @endverbatim + * + * Thats it -- now you can configure your datastores in GNUnet to + * use MySQL. Note that .my.cnf file is a security risk unless its on + * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic + * link. Even greater security risk can be achieved by setting no + * password for $USER. Luckily $USER has only priviledges to mess + * up GNUnet's tables, nothing else (unless you give him more, + * of course).

+ * + * 3) Still, perhaps you should briefly try if the DB connection + * works. First, login as $USER. Then use, + * @verbatim + $ mysql -u $USER -p $the_password_you_like + mysql> use gnunet; + @endverbatim + * + * If you get the message "Database changed" it probably works. + * + * [If you get "ERROR 2002: Can't connect to local MySQL server + * through socket '/tmp/mysql.sock' (2)" it may be resolvable by + * "ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock" + * so there may be some additional trouble depending on your mysql setup.] + * + * PROBLEMS? + * + * If you have problems related to the mysql module, your best + * friend is probably the mysql manual. The first thing to check + * is that mysql is basically operational, that you can connect + * to it, create tables, issue queries etc. + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_datacache_plugin.h" +#include + +#define DEBUG_DATACACHE_MYSQL GNUNET_EXTRA_LOGGING + +/** + * Estimate of the per-entry overhead (including indices). + */ +#define OVERHEAD ((4*2+4*2+8*2+8*2+sizeof(GNUNET_HashCode)*5+8)) + +/** + * Maximum number of supported parameters for a prepared + * statement. Increase if needed. + */ +#define MAX_PARAM 16 + +/** + * Die with an error message that indicates + * a failure of the command 'cmd' with the message given + * by strerror(errno). + */ +#define DIE_MYSQL(cmd, dbh) do { GNUNET_log(GNUNET_ERROR_TYPE__ERROR, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); GNUNET_abort(); } while(0); + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' on file 'filename' + * with the message given by strerror(errno). + */ +#define LOG_MYSQL(level, cmd, dbh) do { GNUNET_log(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); } while(0); + +struct GNUNET_MysqlStatementHandle +{ + struct GNUNET_MysqlStatementHandle *next; + + struct GNUNET_MysqlStatementHandle *prev; + + char *query; + + MYSQL_STMT *statement; + + int valid; + +}; + + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + /** + * Our execution environment. + */ + struct GNUNET_DATACACHE_PluginEnvironment *env; + + /** + * Handle to the mysql database. + */ + MYSQL *dbf; + + struct GNUNET_MysqlStatementHandle *shead; + + struct GNUNET_MysqlStatementHandle *stail; + + /** + * Filename of "my.cnf" (msyql configuration). + */ + char *cnffile; + +#define SELECT_VALUE_STMT "SELECT value,expire FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?" + struct GNUNET_MysqlStatementHandle *select_value; + +#define COUNT_VALUE_STMT "SELECT count(*) FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ?" + struct GNUNET_MysqlStatementHandle *count_value; + +#define SELECT_OLD_VALUE_STMT "SELECT hash, vhash, type, value FROM gn080dstore FORCE INDEX (expireidx) ORDER BY puttime ASC LIMIT 1" + struct GNUNET_MysqlStatementHandle *select_old_value; + +#define DELETE_VALUE_STMT "DELETE FROM gn080dstore WHERE hash = ? AND vhash = ? AND type = ? AND value = ?" + struct GNUNET_MysqlStatementHandle *delete_value; + +#define INSERT_VALUE_STMT "INSERT INTO gn080dstore (type, puttime, expire, hash, vhash, value) "\ + "VALUES (?, ?, ?, ?, ?, ?)" + struct GNUNET_MysqlStatementHandle *insert_value; + +#define UPDATE_VALUE_STMT "UPDATE gn080dstore FORCE INDEX (allidx) SET puttime=?, expire=? "\ + "WHERE hash=? AND vhash=? AND type=?" + struct GNUNET_MysqlStatementHandle *update_value; + +}; + + +/** + * Obtain the location of ".my.cnf". + * + * @param cfg our configuration + * @return NULL on error + */ +static char * +get_my_cnf_path (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *cnffile; + char *home_dir; + struct stat st; + +#ifndef WINDOWS + struct passwd *pw; +#endif + int configured; + +#ifndef WINDOWS + pw = getpwuid (getuid ()); + if (!pw) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "getpwuid"); + return NULL; + } + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (cfg, "datacache-mysql", "CONFIG")) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_filename (cfg, + "datacache-mysql", + "CONFIG", + &cnffile)); + configured = GNUNET_YES; + } + else + { + home_dir = GNUNET_strdup (pw->pw_dir); + GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir); + GNUNET_free (home_dir); + configured = GNUNET_NO; + } +#else + home_dir = (char *) GNUNET_malloc (_MAX_PATH + 1); + plibc_conv_to_win_path ("~/", home_dir); + GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir); + GNUNET_free (home_dir); + configured = GNUNET_NO; +#endif + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Trying to use file `%s' for MySQL configuration.\n"), cnffile); + if ((0 != STAT (cnffile, &st)) || (0 != ACCESS (cnffile, R_OK)) || + (!S_ISREG (st.st_mode))) + { + if (configured == GNUNET_YES) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access file `%s': %s\n"), cnffile, + STRERROR (errno)); + GNUNET_free (cnffile); + return NULL; + } + return cnffile; +} + + +/** + * Free a prepared statement. + * + * @param plugin plugin context + * @param s prepared statement + */ +static void +prepared_statement_destroy (struct Plugin *plugin, + struct GNUNET_MysqlStatementHandle *s) +{ + GNUNET_CONTAINER_DLL_remove (plugin->shead, plugin->stail, s); + if (s->valid) + mysql_stmt_close (s->statement); + GNUNET_free (s->query); + GNUNET_free (s); +} + + +/** + * Close database connection and all prepared statements (we got a DB + * disconnect error). + */ +static int +iclose (struct Plugin *plugin) +{ + while (NULL != plugin->shead) + prepared_statement_destroy (plugin, plugin->shead); + if (plugin->dbf != NULL) + { + mysql_close (plugin->dbf); + plugin->dbf = NULL; + } + return GNUNET_OK; +} + + +/** + * Open the connection with the database (and initialize + * our default options). + * + * @return GNUNET_OK on success + */ +static int +iopen (struct Plugin *ret) +{ + char *mysql_dbname; + char *mysql_server; + char *mysql_user; + char *mysql_password; + unsigned long long mysql_port; + my_bool reconnect; + unsigned int timeout; + + ret->dbf = mysql_init (NULL); + if (ret->dbf == NULL) + return GNUNET_SYSERR; + if (ret->cnffile != NULL) + mysql_options (ret->dbf, MYSQL_READ_DEFAULT_FILE, ret->cnffile); + mysql_options (ret->dbf, MYSQL_READ_DEFAULT_GROUP, "client"); + reconnect = 0; + mysql_options (ret->dbf, MYSQL_OPT_RECONNECT, &reconnect); + mysql_options (ret->dbf, MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout); + mysql_options (ret->dbf, MYSQL_SET_CHARSET_NAME, "UTF8"); + timeout = 60; /* in seconds */ + mysql_options (ret->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout); + mysql_options (ret->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout); + mysql_dbname = NULL; + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (ret->env->cfg, "datacache-mysql", + "DATABASE")) + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (ret->env->cfg, + "datacache-mysql", + "DATABASE", + &mysql_dbname)); + else + mysql_dbname = GNUNET_strdup ("gnunet"); + mysql_user = NULL; + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (ret->env->cfg, "datacache-mysql", + "USER")) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (ret->env->cfg, + "datacache-mysql", + "USER", &mysql_user)); + } + mysql_password = NULL; + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (ret->env->cfg, "datacache-mysql", + "PASSWORD")) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (ret->env->cfg, + "datacache-mysql", + "PASSWORD", + &mysql_password)); + } + mysql_server = NULL; + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (ret->env->cfg, "datacache-mysql", + "HOST")) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (ret->env->cfg, + "datacache-mysql", + "HOST", + &mysql_server)); + } + mysql_port = 0; + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (ret->env->cfg, "datacache-mysql", + "PORT")) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (ret->env->cfg, + "datacache-mysql", + "PORT", &mysql_port)); + } + + GNUNET_assert (mysql_dbname != NULL); + mysql_real_connect (ret->dbf, mysql_server, mysql_user, mysql_password, + mysql_dbname, (unsigned int) mysql_port, NULL, + CLIENT_IGNORE_SIGPIPE); + GNUNET_free_non_null (mysql_server); + GNUNET_free_non_null (mysql_user); + GNUNET_free_non_null (mysql_password); + GNUNET_free (mysql_dbname); + if (mysql_error (ret->dbf)[0]) + { + LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_real_connect", ret); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Run the given MySQL statement. + * + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +run_statement (struct Plugin *plugin, const char *statement) +{ + if ((NULL == plugin->dbf) && (GNUNET_OK != iopen (plugin))) + return GNUNET_SYSERR; + mysql_query (plugin->dbf, statement); + if (mysql_error (plugin->dbf)[0]) + { + LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_query", plugin); + iclose (plugin); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +/** + * Create a prepared statement. + * + * @return NULL on error + */ +static struct GNUNET_MysqlStatementHandle * +prepared_statement_create (struct Plugin *plugin, const char *statement) +{ + struct GNUNET_MysqlStatementHandle *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_MysqlStatementHandle)); + ret->query = GNUNET_strdup (statement); + GNUNET_CONTAINER_DLL_insert (plugin->shead, plugin->stail, ret); + return ret; +} + + +/** + * Prepare a statement for running. + * + * @return GNUNET_OK on success + */ +static int +prepare_statement (struct Plugin *plugin, + struct GNUNET_MysqlStatementHandle *ret) +{ + if (GNUNET_YES == ret->valid) + return GNUNET_OK; + if ((NULL == plugin->dbf) && (GNUNET_OK != iopen (plugin))) + return GNUNET_SYSERR; + ret->statement = mysql_stmt_init (plugin->dbf); + if (ret->statement == NULL) + { + iclose (plugin); + return GNUNET_SYSERR; + } + if (mysql_stmt_prepare (ret->statement, ret->query, strlen (ret->query))) + { + LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", plugin); + mysql_stmt_close (ret->statement); + ret->statement = NULL; + iclose (plugin); + return GNUNET_SYSERR; + } + ret->valid = GNUNET_YES; + return GNUNET_OK; + +} + + +/** + * Bind the parameters for the given MySQL statement + * and run it. + * + * @param plugin plugin context + * @param s statement to bind and run + * @param ap arguments for the binding + * @return GNUNET_SYSERR on error, GNUNET_OK on success + */ +static int +init_params (struct Plugin *plugin, struct GNUNET_MysqlStatementHandle *s, + va_list ap) +{ + MYSQL_BIND qbind[MAX_PARAM]; + unsigned int pc; + unsigned int off; + enum enum_field_types ft; + + pc = mysql_stmt_param_count (s->statement); + if (pc > MAX_PARAM) + { + /* increase internal constant! */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + memset (qbind, 0, sizeof (qbind)); + off = 0; + ft = 0; + while ((pc > 0) && (-1 != (int) (ft = va_arg (ap, enum enum_field_types)))) + { + qbind[off].buffer_type = ft; + switch (ft) + { + case MYSQL_TYPE_FLOAT: + qbind[off].buffer = va_arg (ap, float *); + + break; + case MYSQL_TYPE_LONGLONG: + qbind[off].buffer = va_arg (ap, unsigned long long *); + qbind[off].is_unsigned = va_arg (ap, int); + + break; + case MYSQL_TYPE_LONG: + qbind[off].buffer = va_arg (ap, unsigned int *); + qbind[off].is_unsigned = va_arg (ap, int); + + break; + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_BLOB: + qbind[off].buffer = va_arg (ap, void *); + qbind[off].buffer_length = va_arg (ap, unsigned long); + qbind[off].length = va_arg (ap, unsigned long *); + + break; + default: + /* unsupported type */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + pc--; + off++; + } + if (!((pc == 0) && (-1 != (int) ft) && (va_arg (ap, int) == -1))) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (mysql_stmt_bind_param (s->statement, qbind)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed at %s:%d with error: %s\n"), + "mysql_stmt_bind_param", __FILE__, __LINE__, + mysql_stmt_error (s->statement)); + iclose (plugin); + return GNUNET_SYSERR; + } + if (mysql_stmt_execute (s->statement)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed at %s:%d with error: %s\n"), + "mysql_stmt_execute", __FILE__, __LINE__, + mysql_stmt_error (s->statement)); + iclose (plugin); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +/** + * Type of a callback that will be called for each + * data set returned from MySQL. + * + * @param cls user-defined argument + * @param num_values number of elements in values + * @param values values returned by MySQL + * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort + */ +typedef int (*GNUNET_MysqlDataProcessor) (void *cls, unsigned int num_values, + MYSQL_BIND * values); + + +/** + * Run a prepared SELECT statement. + * + * @param plugin plugin context + * @param s handle to SELECT statment + * @param result_size number of elements in results array + * @param results pointer to already initialized MYSQL_BIND + * array (of sufficient size) for passing results + * @param processor function to call on each result + * @param processor_cls extra argument to processor + * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective + * values (size + buffer-reference for pointers); terminated + * with "-1" + * @return GNUNET_SYSERR on error, otherwise + * the number of successfully affected (or queried) rows + */ +static int +prepared_statement_run_select (struct Plugin *plugin, + struct GNUNET_MysqlStatementHandle *s, + unsigned int result_size, MYSQL_BIND * results, + GNUNET_MysqlDataProcessor processor, + void *processor_cls, ...) +{ + va_list ap; + int ret; + unsigned int rsize; + int total; + + if (GNUNET_OK != prepare_statement (plugin, s)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + va_start (ap, processor_cls); + if (GNUNET_OK != init_params (plugin, s, ap)) + { + GNUNET_break (0); + va_end (ap); + return GNUNET_SYSERR; + } + va_end (ap); + rsize = mysql_stmt_field_count (s->statement); + if (rsize > result_size) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (mysql_stmt_bind_result (s->statement, results)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed at %s:%d with error: %s\n"), + "mysql_stmt_bind_result", __FILE__, __LINE__, + mysql_stmt_error (s->statement)); + iclose (plugin); + return GNUNET_SYSERR; + } + + total = 0; + while (1) + { + ret = mysql_stmt_fetch (s->statement); + if (ret == MYSQL_NO_DATA) + break; + if (ret != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed at %s:%d with error: %s\n"), + "mysql_stmt_fetch", __FILE__, __LINE__, + mysql_stmt_error (s->statement)); + iclose (plugin); + return GNUNET_SYSERR; + } + if (processor != NULL) + if (GNUNET_OK != processor (processor_cls, rsize, results)) + break; + total++; + } + mysql_stmt_reset (s->statement); + return total; +} + + + +/** + * Run a prepared statement that does NOT produce results. + * + * @param plugin plugin context + * @param s handle to SELECT statment + * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective + * values (size + buffer-reference for pointers); terminated + * with "-1" + * @param insert_id NULL or address where to store the row ID of whatever + * was inserted (only for INSERT statements!) + * @return GNUNET_SYSERR on error, otherwise + * the number of successfully affected rows + */ +static int +prepared_statement_run (struct Plugin *plugin, + struct GNUNET_MysqlStatementHandle *s, + unsigned long long *insert_id, ...) +{ + va_list ap; + int affected; + + if (GNUNET_OK != prepare_statement (plugin, s)) + return GNUNET_SYSERR; + va_start (ap, insert_id); + if (GNUNET_OK != init_params (plugin, s, ap)) + { + va_end (ap); + return GNUNET_SYSERR; + } + va_end (ap); + affected = mysql_stmt_affected_rows (s->statement); + if (NULL != insert_id) + *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement); + mysql_stmt_reset (s->statement); + return affected; +} + + +/** + * Create temporary table and prepare statements. + * + * @param plugin plugin context + * @return GNUNET_OK on success + */ +static int +itable (struct Plugin *plugin) +{ +#define MRUNS(a) (GNUNET_OK != run_statement (plugin, a) ) + if (MRUNS + ("CREATE TEMPORARY TABLE gn080dstore (" + " type INT(11) UNSIGNED NOT NULL DEFAULT 0," + " puttime BIGINT UNSIGNED NOT NULL DEFAULT 0," + " expire BIGINT UNSIGNED NOT NULL DEFAULT 0," + " hash BINARY(64) NOT NULL DEFAULT ''," + " vhash BINARY(64) NOT NULL DEFAULT ''," + " value BLOB NOT NULL DEFAULT ''," + " INDEX hashidx (hash(64),type,expire)," + " INDEX allidx (hash(64),vhash(64),type)," " INDEX expireidx (puttime)" + ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1")) + return GNUNET_SYSERR; +#undef MRUNS +#define PINIT(a,b) (NULL == (a = prepared_statement_create(plugin, b))) + if (PINIT (plugin->select_value, SELECT_VALUE_STMT) || + PINIT (plugin->count_value, COUNT_VALUE_STMT) || + PINIT (plugin->select_old_value, SELECT_OLD_VALUE_STMT) || + PINIT (plugin->delete_value, DELETE_VALUE_STMT) || + PINIT (plugin->insert_value, INSERT_VALUE_STMT) || + PINIT (plugin->update_value, UPDATE_VALUE_STMT)) + return GNUNET_SYSERR; +#undef PINIT + return GNUNET_OK; +} + + +/** + * Store an item in the datastore. + * + * @param cls closure (our "struct Plugin") + * @param key key to store data under + * @param size number of bytes in data + * @param data data to store + * @param type type of the value + * @param discard_time when to discard the value in any case + * @return 0 on error, number of bytes used otherwise + */ +static size_t +mysql_plugin_put (void *cls, const GNUNET_HashCode * key, size_t size, + const char *data, enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute discard_time) +{ + struct Plugin *plugin = cls; + struct GNUNET_TIME_Absolute now; + unsigned long k_length; + unsigned long h_length; + unsigned long v_length; + unsigned long long v_now; + unsigned long long v_discard_time; + unsigned int v_type; + GNUNET_HashCode vhash; + int ret; + + if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE) + return GNUNET_SYSERR; + GNUNET_CRYPTO_hash (data, size, &vhash); + now = GNUNET_TIME_absolute_get (); + + /* first try UPDATE */ + h_length = sizeof (GNUNET_HashCode); + k_length = sizeof (GNUNET_HashCode); + v_length = size; + v_type = type; + v_now = (unsigned long long) now.abs_value; + v_discard_time = (unsigned long long) discard_time.abs_value; + if (GNUNET_OK == + prepared_statement_run (plugin, plugin->update_value, NULL, + MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES, + MYSQL_TYPE_LONGLONG, &v_discard_time, GNUNET_YES, + MYSQL_TYPE_BLOB, key, sizeof (GNUNET_HashCode), + &k_length, MYSQL_TYPE_BLOB, &vhash, + sizeof (GNUNET_HashCode), &h_length, + MYSQL_TYPE_LONG, &v_type, GNUNET_YES, -1)) + return GNUNET_OK; + + /* now try INSERT */ + h_length = sizeof (GNUNET_HashCode); + k_length = sizeof (GNUNET_HashCode); + v_length = size; + if (GNUNET_OK != + (ret = + prepared_statement_run (plugin, plugin->insert_value, NULL, + MYSQL_TYPE_LONG, &type, GNUNET_YES, + MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES, + MYSQL_TYPE_LONGLONG, &v_discard_time, GNUNET_YES, + MYSQL_TYPE_BLOB, key, sizeof (GNUNET_HashCode), + &k_length, MYSQL_TYPE_BLOB, &vhash, + sizeof (GNUNET_HashCode), &h_length, + MYSQL_TYPE_BLOB, data, (unsigned long) size, + &v_length, -1))) + { + if (ret == GNUNET_SYSERR) + itable (plugin); + return GNUNET_SYSERR; + } + return size + OVERHEAD; +} + + +static int +return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values) +{ + return GNUNET_OK; +} + + +/** + * Iterate over the results for a particular key + * in the datastore. + * + * @param cls closure (our "struct Plugin") + * @param key + * @param type entries of which type are relevant? + * @param iter maybe NULL (to just count) + * @param iter_cls closure for iter + * @return the number of results found + */ +static unsigned int +mysql_plugin_get (void *cls, const GNUNET_HashCode * key, + enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, + void *iter_cls) +{ + struct Plugin *plugin = cls; + MYSQL_BIND rbind[3]; + unsigned long h_length; + unsigned long v_length; + unsigned long long v_expire; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute expire; + unsigned int cnt; + unsigned long long total; + unsigned long long v_now; + unsigned int off; + unsigned int v_type; + int ret; + char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE]; + + now = GNUNET_TIME_absolute_get (); + h_length = sizeof (GNUNET_HashCode); + v_length = sizeof (buffer); + total = -1; + memset (rbind, 0, sizeof (rbind)); + rbind[0].buffer_type = MYSQL_TYPE_LONGLONG; + rbind[0].buffer = &total; + rbind[0].is_unsigned = GNUNET_YES; + v_type = type; + v_now = (unsigned long long) now.abs_value; + if ((GNUNET_OK != + (ret = + prepared_statement_run_select (plugin, plugin->count_value, 1, rbind, + return_ok, NULL, MYSQL_TYPE_BLOB, key, + sizeof (GNUNET_HashCode), &h_length, + MYSQL_TYPE_LONG, &v_type, GNUNET_YES, + MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES, + -1))) || (-1 == total)) + { + if (ret == GNUNET_SYSERR) + itable (plugin); + return GNUNET_SYSERR; + } + if ((iter == NULL) || (total == 0)) + return (int) total; + + off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); + cnt = 0; + while (cnt < total) + { + memset (rbind, 0, sizeof (rbind)); + rbind[0].buffer_type = MYSQL_TYPE_BLOB; + rbind[0].buffer_length = sizeof (buffer); + rbind[0].length = &v_length; + rbind[0].buffer = buffer; + rbind[1].buffer_type = MYSQL_TYPE_LONGLONG; + rbind[1].is_unsigned = 1; + rbind[1].buffer = &v_expire; + off = (off + 1) % total; + if (GNUNET_OK != + (ret = + prepared_statement_run_select (plugin, plugin->select_value, 2, rbind, + return_ok, NULL, MYSQL_TYPE_BLOB, key, + sizeof (GNUNET_HashCode), &h_length, + MYSQL_TYPE_LONG, &v_type, GNUNET_YES, + MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES, + MYSQL_TYPE_LONG, &off, GNUNET_YES, -1))) + { + if (ret == GNUNET_SYSERR) + itable (plugin); + return GNUNET_SYSERR; + } + cnt++; + expire.abs_value = v_expire; + if (GNUNET_OK != iter (iter_cls, expire, key, v_length, buffer, type)) + break; + } + return cnt; +} + + +/** + * Delete the entry with the lowest expiration value + * from the datacache right now. + * + * @param cls closure (our "struct Plugin") + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +mysql_plugin_del (void *cls) +{ + struct Plugin *plugin = cls; + + MYSQL_BIND rbind[5]; + unsigned int v_type; + GNUNET_HashCode v_key; + GNUNET_HashCode vhash; + unsigned long k_length; + unsigned long h_length; + unsigned long v_length; + int ret; + char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE]; + + k_length = sizeof (GNUNET_HashCode); + h_length = sizeof (GNUNET_HashCode); + v_length = sizeof (buffer); + memset (rbind, 0, sizeof (rbind)); + rbind[0].buffer_type = MYSQL_TYPE_BLOB; + rbind[0].buffer_length = sizeof (GNUNET_HashCode); + rbind[0].length = &k_length; + rbind[0].buffer = &v_key; + rbind[1].buffer_type = MYSQL_TYPE_BLOB; + rbind[1].buffer_length = sizeof (GNUNET_HashCode); + rbind[1].length = &h_length; + rbind[1].buffer = &vhash; + rbind[2].buffer_type = MYSQL_TYPE_LONG; + rbind[2].is_unsigned = 1; + rbind[2].buffer = &v_type; + rbind[3].buffer_type = MYSQL_TYPE_BLOB; + rbind[3].buffer_length = sizeof (buffer); + rbind[3].length = &v_length; + rbind[3].buffer = buffer; + if ((GNUNET_OK != + (ret = + prepared_statement_run_select (plugin, plugin->select_old_value, 4, + rbind, return_ok, NULL, -1))) || + (GNUNET_OK != + (ret = + prepared_statement_run (plugin, plugin->delete_value, NULL, + MYSQL_TYPE_BLOB, &v_key, + sizeof (GNUNET_HashCode), &k_length, + MYSQL_TYPE_BLOB, &vhash, + sizeof (GNUNET_HashCode), &h_length, + MYSQL_TYPE_LONG, &v_type, GNUNET_YES, + MYSQL_TYPE_BLOB, buffer, + (unsigned long) sizeof (buffer), &v_length, + -1)))) + { + if (ret == GNUNET_SYSERR) + itable (plugin); + return GNUNET_SYSERR; + } + plugin->env->delete_notify (plugin->env->cls, &v_key, v_length + OVERHEAD); + + return GNUNET_OK; +} + + +/** + * Entry point for the plugin. + * + * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet") + * @return the plugin's closure (our "struct Plugin") + */ +void * +libgnunet_plugin_datacache_mysql_init (void *cls) +{ + struct GNUNET_DATACACHE_PluginEnvironment *env = cls; + struct GNUNET_DATACACHE_PluginFunctions *api; + struct Plugin *plugin; + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + plugin->cnffile = get_my_cnf_path (env->cfg); + if (GNUNET_OK != iopen (plugin)) + { + GNUNET_free_non_null (plugin->cnffile); + GNUNET_free (plugin); + return NULL; + } + if (GNUNET_OK != itable (plugin)) + { + iclose (plugin); + GNUNET_free_non_null (plugin->cnffile); + GNUNET_free (plugin); + return NULL; + } + api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions)); + api->cls = plugin; + api->get = &mysql_plugin_get; + api->put = &mysql_plugin_put; + api->del = &mysql_plugin_del; + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "mysql", + _("MySQL datacache running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls closure (our "struct Plugin") + * @return NULL + */ +void * +libgnunet_plugin_datacache_mysql_done (void *cls) +{ + struct GNUNET_DATACACHE_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + iclose (plugin); + GNUNET_free_non_null (plugin->cnffile); + GNUNET_free (plugin); + GNUNET_free (api); + mysql_library_end (); + return NULL; +} + + +/* end of plugin_datacache_mysql.c */ diff --git a/src/datacache/plugin_datacache_postgres.c b/src/datacache/plugin_datacache_postgres.c new file mode 100644 index 0000000..3486d76 --- /dev/null +++ b/src/datacache/plugin_datacache_postgres.c @@ -0,0 +1,524 @@ +/* + This file is part of GNUnet + (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datacache/plugin_datacache_postgres.c + * @brief postgres for an implementation of a database backend for the datacache + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_datacache_plugin.h" +#include + +#define DEBUG_POSTGRES GNUNET_EXTRA_LOGGING + +/** + * Per-entry overhead estimate + */ +#define OVERHEAD (sizeof(GNUNET_HashCode) + 24) + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + /** + * Our execution environment. + */ + struct GNUNET_DATACACHE_PluginEnvironment *env; + + /** + * Native Postgres database handle. + */ + PGconn *dbh; + +}; + + +/** + * Check if the result obtained from Postgres has + * the desired status code. If not, log an error, clear the + * result and return GNUNET_SYSERR. + * + * @return GNUNET_OK if the result is acceptable + */ +static int +check_result (struct Plugin *plugin, PGresult * ret, int expected_status, + const char *command, const char *args, int line) +{ + if (ret == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "datastore-postgres", + "Postgres failed to allocate result for `%s:%s' at %d\n", + command, args, line); + return GNUNET_SYSERR; + } + if (PQresultStatus (ret) != expected_status) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "datastore-postgres", + _("`%s:%s' failed at %s:%d with error: %s"), command, args, + __FILE__, line, PQerrorMessage (plugin->dbh)); + PQclear (ret); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Run simple SQL statement (without results). + */ +static int +pq_exec (struct Plugin *plugin, const char *sql, int line) +{ + PGresult *ret; + + ret = PQexec (plugin->dbh, sql); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "PQexec", sql, line)) + return GNUNET_SYSERR; + PQclear (ret); + return GNUNET_OK; +} + + +/** + * Prepare SQL statement. + */ +static int +pq_prepare (struct Plugin *plugin, const char *name, const char *sql, + int nparms, int line) +{ + PGresult *ret; + + ret = PQprepare (plugin->dbh, name, sql, nparms, NULL); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "PQprepare", sql, line)) + return GNUNET_SYSERR; + PQclear (ret); + return GNUNET_OK; +} + + +/** + * @brief Get a database handle + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +init_connection (struct Plugin *plugin) +{ + char *conninfo; + PGresult *ret; + + /* Open database and precompile statements */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, + "datacache-postgres", "CONFIG", + &conninfo)) + conninfo = NULL; + plugin->dbh = PQconnectdb (conninfo == NULL ? "" : conninfo); + GNUNET_free_non_null (conninfo); + if (NULL == plugin->dbh) + { + /* FIXME: warn about out-of-memory? */ + return GNUNET_SYSERR; + } + if (PQstatus (plugin->dbh) != CONNECTION_OK) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "datacache-postgres", + _("Unable to initialize Postgres: %s"), + PQerrorMessage (plugin->dbh)); + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + ret = + PQexec (plugin->dbh, + "CREATE TEMPORARY TABLE gn090dc (" + " type INTEGER NOT NULL DEFAULT 0," + " discard_time BIGINT NOT NULL DEFAULT 0," + " key BYTEA NOT NULL DEFAULT ''," + " value BYTEA NOT NULL DEFAULT '')" "WITH OIDS"); + if ((ret == NULL) || ((PQresultStatus (ret) != PGRES_COMMAND_OK) && (0 != strcmp ("42P07", /* duplicate table */ + PQresultErrorField + (ret, + PG_DIAG_SQLSTATE))))) + { + (void) check_result (plugin, ret, PGRES_COMMAND_OK, "CREATE TABLE", + "gn090dc", __LINE__); + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + if (PQresultStatus (ret) == PGRES_COMMAND_OK) + { + if ((GNUNET_OK != + pq_exec (plugin, "CREATE INDEX idx_key ON gn090dc (key)", __LINE__)) || + (GNUNET_OK != + pq_exec (plugin, "CREATE INDEX idx_dt ON gn090dc (discard_time)", + __LINE__))) + { + PQclear (ret); + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + } + PQclear (ret); +#if 1 + ret = + PQexec (plugin->dbh, + "ALTER TABLE gn090dc ALTER value SET STORAGE EXTERNAL"); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090dc", + __LINE__)) + { + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + PQclear (ret); + ret = PQexec (plugin->dbh, "ALTER TABLE gn090dc ALTER key SET STORAGE PLAIN"); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090dc", + __LINE__)) + { + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + PQclear (ret); +#endif + if ((GNUNET_OK != + pq_prepare (plugin, "getkt", + "SELECT discard_time,type,value FROM gn090dc " + "WHERE key=$1 AND type=$2 ", 2, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "getk", + "SELECT discard_time,type,value FROM gn090dc " + "WHERE key=$1", 1, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "getm", + "SELECT length(value),oid,key FROM gn090dc " + "ORDER BY discard_time ASC LIMIT 1", 0, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "delrow", "DELETE FROM gn090dc WHERE oid=$1", 1, + __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "put", + "INSERT INTO gn090dc (type, discard_time, key, value) " + "VALUES ($1, $2, $3, $4)", 4, __LINE__))) + { + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Delete the row identified by the given rowid (qid + * in postgres). + * + * @return GNUNET_OK on success + */ +static int +delete_by_rowid (struct Plugin *plugin, uint32_t rowid) +{ + uint32_t brow = htonl (rowid); + const char *paramValues[] = { (const char *) &brow }; + int paramLengths[] = { sizeof (brow) }; + const int paramFormats[] = { 1 }; + PGresult *ret; + + ret = + PQexecPrepared (plugin->dbh, "delrow", 1, paramValues, paramLengths, + paramFormats, 1); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "PQexecPrepared", "delrow", + __LINE__)) + { + return GNUNET_SYSERR; + } + PQclear (ret); + return GNUNET_OK; +} + + +/** + * Store an item in the datastore. + * + * @param cls closure (our "struct Plugin") + * @param key key to store data under + * @param size number of bytes in data + * @param data data to store + * @param type type of the value + * @param discard_time when to discard the value in any case + * @return 0 on error, number of bytes used otherwise + */ +static size_t +postgres_plugin_put (void *cls, const GNUNET_HashCode * key, size_t size, + const char *data, enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute discard_time) +{ + struct Plugin *plugin = cls; + PGresult *ret; + uint32_t btype = htonl (type); + uint64_t bexpi = GNUNET_TIME_absolute_hton (discard_time).abs_value__; + + const char *paramValues[] = { + (const char *) &btype, + (const char *) &bexpi, + (const char *) key, + (const char *) data + }; + int paramLengths[] = { + sizeof (btype), + sizeof (bexpi), + sizeof (GNUNET_HashCode), + size + }; + const int paramFormats[] = { 1, 1, 1, 1 }; + + ret = + PQexecPrepared (plugin->dbh, "put", 4, paramValues, paramLengths, + paramFormats, 1); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "PQexecPrepared", "put", + __LINE__)) + return GNUNET_SYSERR; + PQclear (ret); + return size + OVERHEAD; +} + + +/** + * Iterate over the results for a particular key + * in the datastore. + * + * @param cls closure (our "struct Plugin") + * @param key + * @param type entries of which type are relevant? + * @param iter maybe NULL (to just count) + * @param iter_cls closure for iter + * @return the number of results found + */ +static unsigned int +postgres_plugin_get (void *cls, const GNUNET_HashCode * key, + enum GNUNET_BLOCK_Type type, + GNUNET_DATACACHE_Iterator iter, void *iter_cls) +{ + struct Plugin *plugin = cls; + uint32_t btype = htonl (type); + + const char *paramValues[] = { + (const char *) key, + (const char *) &btype, + }; + int paramLengths[] = { + sizeof (GNUNET_HashCode), + sizeof (btype), + }; + const int paramFormats[] = { 1, 1 }; + struct GNUNET_TIME_Absolute expiration_time; + uint32_t size; + unsigned int cnt; + unsigned int i; + PGresult *res; + + res = + PQexecPrepared (plugin->dbh, (type == 0) ? "getk" : "getkt", + (type == 0) ? 1 : 2, paramValues, paramLengths, + paramFormats, 1); + if (GNUNET_OK != + check_result (plugin, res, PGRES_TUPLES_OK, "PQexecPrepared", + (type == 0) ? "getk" : "getkt", __LINE__)) + { +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datacache-postgres", + "Ending iteration (postgres error)\n"); +#endif + return 0; + } + + if (0 == (cnt = PQntuples (res))) + { + /* no result */ +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datacache-postgres", + "Ending iteration (no more results)\n"); +#endif + PQclear (res); + return 0; + } + if (iter == NULL) + { + PQclear (res); + return cnt; + } + if ((3 != PQnfields (res)) || (sizeof (uint64_t) != PQfsize (res, 0)) || + (sizeof (uint32_t) != PQfsize (res, 1))) + { + GNUNET_break (0); + PQclear (res); + return 0; + } + for (i = 0; i < cnt; i++) + { + expiration_time.abs_value = + GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, i, 0)); + type = ntohl (*(uint32_t *) PQgetvalue (res, i, 1)); + size = PQgetlength (res, i, 2); +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datacache-postgres", + "Found result of size %u bytes and type %u in database\n", + (unsigned int) size, (unsigned int) type); +#endif + if (GNUNET_SYSERR == + iter (iter_cls, expiration_time, key, size, PQgetvalue (res, i, 2), + (enum GNUNET_BLOCK_Type) type)) + { +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datacache-postgres", + "Ending iteration (client error)\n"); +#endif + PQclear (res); + return cnt; + } + } + PQclear (res); + return cnt; +} + + +/** + * Delete the entry with the lowest expiration value + * from the datacache right now. + * + * @param cls closure (our "struct Plugin") + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +postgres_plugin_del (void *cls) +{ + struct Plugin *plugin = cls; + uint32_t size; + uint32_t oid; + GNUNET_HashCode key; + PGresult *res; + + res = PQexecPrepared (plugin->dbh, "getm", 0, NULL, NULL, NULL, 1); + if (GNUNET_OK != + check_result (plugin, res, PGRES_TUPLES_OK, "PQexecPrepared", "getm", + __LINE__)) + { +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datacache-postgres", + "Ending iteration (postgres error)\n"); +#endif + return 0; + } + if (0 == PQntuples (res)) + { + /* no result */ +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datacache-postgres", + "Ending iteration (no more results)\n"); +#endif + PQclear (res); + return GNUNET_SYSERR; + } + if ((3 != PQnfields (res)) || (sizeof (size) != PQfsize (res, 0)) || + (sizeof (oid) != PQfsize (res, 1)) || + (sizeof (GNUNET_HashCode) != PQgetlength (res, 0, 2))) + { + GNUNET_break (0); + PQclear (res); + return 0; + } + size = ntohl (*(uint32_t *) PQgetvalue (res, 0, 0)); + oid = ntohl (*(uint32_t *) PQgetvalue (res, 0, 1)); + memcpy (&key, PQgetvalue (res, 0, 2), sizeof (GNUNET_HashCode)); + PQclear (res); + if (GNUNET_OK != delete_by_rowid (plugin, oid)) + return GNUNET_SYSERR; + plugin->env->delete_notify (plugin->env->cls, &key, size + OVERHEAD); + return GNUNET_OK; +} + + +/** + * Entry point for the plugin. + * + * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet") + * @return the plugin's closure (our "struct Plugin") + */ +void * +libgnunet_plugin_datacache_postgres_init (void *cls) +{ + struct GNUNET_DATACACHE_PluginEnvironment *env = cls; + struct GNUNET_DATACACHE_PluginFunctions *api; + struct Plugin *plugin; + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + + if (GNUNET_OK != init_connection (plugin)) + { + GNUNET_free (plugin); + return NULL; + } + + api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions)); + api->cls = plugin; + api->get = &postgres_plugin_get; + api->put = &postgres_plugin_put; + api->del = &postgres_plugin_del; + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "datacache-postgres", + _("Postgres datacache running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls closure (our "struct Plugin") + * @return NULL + */ +void * +libgnunet_plugin_datacache_postgres_done (void *cls) +{ + struct GNUNET_DATACACHE_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + PQfinish (plugin->dbh); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + + + +/* end of plugin_datacache_postgres.c */ diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c new file mode 100644 index 0000000..f852d3b --- /dev/null +++ b/src/datacache/plugin_datacache_sqlite.c @@ -0,0 +1,490 @@ +/* + This file is part of GNUnet + (C) 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datacache/plugin_datacache_sqlite.c + * @brief sqlite for an implementation of a database backend for the datacache + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_datacache_plugin.h" +#include + +#define DEBUG_DATACACHE_SQLITE GNUNET_EXTRA_LOGGING + +#define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__) + +#define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-sqlite", op, fn) + + +/** + * How much overhead do we assume per entry in the + * datacache? + */ +#define OVERHEAD (sizeof(GNUNET_HashCode) + 32) + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + /** + * Our execution environment. + */ + struct GNUNET_DATACACHE_PluginEnvironment *env; + + /** + * Handle to the sqlite database. + */ + sqlite3 *dbh; + + /** + * Filename used for the DB. + */ + char *fn; +}; + + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' on file 'filename' + * with the message given by strerror(errno). + */ +#define LOG_SQLITE(db, level, cmd) do { LOG (level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db)); } while(0) + + +#define SQLITE3_EXEC(db, cmd) do { emsg = NULL; if (SQLITE_OK != sqlite3_exec(db, cmd, NULL, NULL, &emsg)) { LOG (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("`%s' failed at %s:%d with error: %s\n"), "sqlite3_exec", __FILE__, __LINE__, emsg); sqlite3_free(emsg); } } while(0) + + +/** + * @brief Prepare a SQL statement + */ +static int +sq_prepare (sqlite3 * dbh, const char *zSql, /* SQL statement, UTF-8 encoded */ + sqlite3_stmt ** ppStmt) +{ /* OUT: Statement handle */ + char *dummy; + + return sqlite3_prepare (dbh, zSql, strlen (zSql), ppStmt, + (const char **) &dummy); +} + + +/** + * Store an item in the datastore. + * + * @param cls closure (our "struct Plugin") + * @param key key to store data under + * @param size number of bytes in data + * @param data data to store + * @param type type of the value + * @param discard_time when to discard the value in any case + * @return 0 on error, number of bytes used otherwise + */ +static size_t +sqlite_plugin_put (void *cls, const GNUNET_HashCode * key, size_t size, + const char *data, enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute discard_time) +{ + struct Plugin *plugin = cls; + sqlite3_stmt *stmt; + int64_t dval; + +#if DEBUG_DATACACHE_SQLITE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing `%s' of %u bytes with key `%4s' and expiration %llums\n", + "PUT", (unsigned int) size, GNUNET_h2s (key), + (unsigned long long) + GNUNET_TIME_absolute_get_remaining (discard_time).rel_value); +#endif + dval = (int64_t) discard_time.abs_value; + if (dval < 0) + dval = INT64_MAX; + if (sq_prepare + (plugin->dbh, + "INSERT INTO ds090 (type, expire, key, value) VALUES (?, ?, ?, ?)", + &stmt) != SQLITE_OK) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sq_prepare"); + return 0; + } + if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) || + (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, dval)) || + (SQLITE_OK != + sqlite3_bind_blob (stmt, 3, key, sizeof (GNUNET_HashCode), + SQLITE_TRANSIENT)) || + (SQLITE_OK != sqlite3_bind_blob (stmt, 4, data, size, SQLITE_TRANSIENT))) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_xxx"); + sqlite3_finalize (stmt); + return 0; + } + if (SQLITE_DONE != sqlite3_step (stmt)) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + sqlite3_finalize (stmt); + return 0; + } + if (SQLITE_OK != sqlite3_finalize (stmt)) + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_finalize"); + return size + OVERHEAD; +} + + +/** + * Iterate over the results for a particular key + * in the datastore. + * + * @param cls closure (our "struct Plugin") + * @param key + * @param type entries of which type are relevant? + * @param iter maybe NULL (to just count) + * @param iter_cls closure for iter + * @return the number of results found + */ +static unsigned int +sqlite_plugin_get (void *cls, const GNUNET_HashCode * key, + enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, + void *iter_cls) +{ + struct Plugin *plugin = cls; + sqlite3_stmt *stmt; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute exp; + unsigned int size; + const char *dat; + unsigned int cnt; + unsigned int off; + unsigned int total; + char scratch[256]; + int64_t ntime; + + now = GNUNET_TIME_absolute_get (); +#if DEBUG_DATACACHE_SQLITE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' for key `%4s'\n", "GET", + GNUNET_h2s (key)); +#endif + if (sq_prepare + (plugin->dbh, + "SELECT count(*) FROM ds090 WHERE key=? AND type=? AND expire >= ?", + &stmt) != SQLITE_OK) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sq_prepare"); + return 0; + } + ntime = (int64_t) now.abs_value; + GNUNET_assert (ntime >= 0); + if ((SQLITE_OK != + sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode), + SQLITE_TRANSIENT)) || + (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || + (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value))) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_xxx"); + sqlite3_finalize (stmt); + return 0; + } + + if (SQLITE_ROW != sqlite3_step (stmt)) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite_step"); + sqlite3_finalize (stmt); +#if DEBUG_DATACACHE_SQLITE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "No content found when processing `%s' for key `%4s'\n", "GET", + GNUNET_h2s (key)); +#endif + return 0; + } + total = sqlite3_column_int (stmt, 0); + sqlite3_finalize (stmt); + if ((total == 0) || (iter == NULL)) + { +#if DEBUG_DATACACHE_SQLITE + if (0 == total) + LOG (GNUNET_ERROR_TYPE_DEBUG, + "No content found when processing `%s' for key `%4s'\n", "GET", + GNUNET_h2s (key)); +#endif + return total; + } + + cnt = 0; + off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); + while (cnt < total) + { + off = (off + 1) % total; + GNUNET_snprintf (scratch, sizeof (scratch), + "SELECT value,expire FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u", + off); + if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sq_prepare"); + return cnt; + } + if ((SQLITE_OK != + sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode), + SQLITE_TRANSIENT)) || + (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || + (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value))) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_xxx"); + sqlite3_finalize (stmt); + return cnt; + } + if (sqlite3_step (stmt) != SQLITE_ROW) + break; + size = sqlite3_column_bytes (stmt, 0); + dat = sqlite3_column_blob (stmt, 0); + exp.abs_value = sqlite3_column_int64 (stmt, 1); + ntime = (int64_t) exp.abs_value; + if (ntime == INT64_MAX) + exp = GNUNET_TIME_UNIT_FOREVER_ABS; + cnt++; +#if DEBUG_DATACACHE_SQLITE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Found %u-byte result when processing `%s' for key `%4s'\n", + (unsigned int) size, "GET", GNUNET_h2s (key)); +#endif + if (GNUNET_OK != iter (iter_cls, exp, key, size, dat, type)) + { + sqlite3_finalize (stmt); + break; + } + sqlite3_finalize (stmt); + } + return cnt; +} + + +/** + * Delete the entry with the lowest expiration value + * from the datacache right now. + * + * @param cls closure (our "struct Plugin") + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +sqlite_plugin_del (void *cls) +{ + struct Plugin *plugin = cls; + unsigned long long rowid; + unsigned int dsize; + sqlite3_stmt *stmt; + sqlite3_stmt *dstmt; + GNUNET_HashCode hc; + +#if DEBUG_DATACACHE_SQLITE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s'\n", "DEL"); +#endif + stmt = NULL; + dstmt = NULL; + if (sq_prepare + (plugin->dbh, + "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1", + &stmt) != SQLITE_OK) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sq_prepare"); + if (stmt != NULL) + (void) sqlite3_finalize (stmt); + return GNUNET_SYSERR; + } + if (SQLITE_ROW != sqlite3_step (stmt)) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + (void) sqlite3_finalize (stmt); + return GNUNET_SYSERR; + } + rowid = sqlite3_column_int64 (stmt, 0); + GNUNET_assert (sqlite3_column_bytes (stmt, 1) == sizeof (GNUNET_HashCode)); + memcpy (&hc, sqlite3_column_blob (stmt, 1), sizeof (GNUNET_HashCode)); + dsize = sqlite3_column_bytes (stmt, 2); + if (SQLITE_OK != sqlite3_finalize (stmt)) + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + if (sq_prepare (plugin->dbh, "DELETE FROM ds090 WHERE _ROWID_=?", &dstmt) != + SQLITE_OK) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sq_prepare"); + if (stmt != NULL) + (void) sqlite3_finalize (stmt); + return GNUNET_SYSERR; + } + if (SQLITE_OK != sqlite3_bind_int64 (dstmt, 1, rowid)) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind"); + (void) sqlite3_finalize (dstmt); + return GNUNET_SYSERR; + } + if (sqlite3_step (dstmt) != SQLITE_DONE) + { + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + (void) sqlite3_finalize (dstmt); + return GNUNET_SYSERR; + } + plugin->env->delete_notify (plugin->env->cls, &hc, dsize + OVERHEAD); + if (SQLITE_OK != sqlite3_finalize (dstmt)) + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_finalize"); + return GNUNET_OK; +} + + +/** + * Entry point for the plugin. + * + * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet") + * @return the plugin's closure (our "struct Plugin") + */ +void * +libgnunet_plugin_datacache_sqlite_init (void *cls) +{ + struct GNUNET_DATACACHE_PluginEnvironment *env = cls; + struct GNUNET_DATACACHE_PluginFunctions *api; + struct Plugin *plugin; + char *fn; + char *fn_utf8; + sqlite3 *dbh; + char *emsg; + + fn = GNUNET_DISK_mktemp ("gnunet-datacache"); + if (fn == NULL) + { + GNUNET_break (0); + return NULL; + } +#ifdef ENABLE_NLS + fn_utf8 = GNUNET_STRINGS_to_utf8 (fn, strlen (fn), nl_langinfo (CODESET)); +#else + /* good luck */ + fn_utf8 = GNUNET_STRINGS_to_utf8 (fn, strlen (fn), "UTF-8"); +#endif + if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh)) + { + GNUNET_free (fn); + GNUNET_free (fn_utf8); + return NULL; + } + GNUNET_free (fn); + + SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY"); + SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE"); + SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF"); + SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF"); + SQLITE3_EXEC (dbh, "PRAGMA count_changes=OFF"); + SQLITE3_EXEC (dbh, "PRAGMA page_size=4092"); + SQLITE3_EXEC (dbh, + "CREATE TABLE ds090 (" " type INTEGER NOT NULL DEFAULT 0," + " expire INTEGER NOT NULL DEFAULT 0," + " key BLOB NOT NULL DEFAULT ''," + " value BLOB NOT NULL DEFAULT '')"); + SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds090 (key,type,expire)"); + SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire ON ds090 (expire)"); + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + plugin->dbh = dbh; + plugin->fn = fn_utf8; + api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions)); + api->cls = plugin; + api->get = &sqlite_plugin_get; + api->put = &sqlite_plugin_put; + api->del = &sqlite_plugin_del; + LOG (GNUNET_ERROR_TYPE_INFO, _("Sqlite datacache running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls closure (our "struct Plugin") + * @return NULL + */ +void * +libgnunet_plugin_datacache_sqlite_done (void *cls) +{ + struct GNUNET_DATACACHE_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + int result; + +#if SQLITE_VERSION_NUMBER >= 3007000 + sqlite3_stmt *stmt; +#endif + +#if !WINDOWS || defined(__CYGWIN__) + if (0 != UNLINK (plugin->fn)) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", plugin->fn); + GNUNET_free (plugin->fn); +#endif + result = sqlite3_close (plugin->dbh); +#if SQLITE_VERSION_NUMBER >= 3007000 + if (result == SQLITE_BUSY) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _ + ("Tried to close sqlite without finalizing all prepared statements.\n")); + stmt = sqlite3_next_stmt (plugin->dbh, NULL); + while (stmt != NULL) + { +#if DEBUG_SQLITE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Closing statement %p\n", stmt); +#endif + result = sqlite3_finalize (stmt); +#if DEBUG_SQLITE + if (result != SQLITE_OK) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to close statement %p: %d\n", + stmt, result); +#endif + stmt = sqlite3_next_stmt (plugin->dbh, NULL); + } + result = sqlite3_close (plugin->dbh); + } +#endif + if (SQLITE_OK != result) + LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); + +#if WINDOWS && !defined(__CYGWIN__) + if (0 != UNLINK (plugin->fn)) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", plugin->fn); + GNUNET_free (plugin->fn); +#endif + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + + + +/* end of plugin_datacache_sqlite.c */ diff --git a/src/datacache/plugin_datacache_template.c b/src/datacache/plugin_datacache_template.c new file mode 100644 index 0000000..2d3f160 --- /dev/null +++ b/src/datacache/plugin_datacache_template.c @@ -0,0 +1,145 @@ +/* + This file is part of GNUnet + (C) 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datacache/plugin_datacache_template.c + * @brief template for an implementation of a database backend for the datacache + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_datacache_plugin.h" + + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + /** + * Our execution environment. + */ + struct GNUNET_DATACACHE_PluginEnvironment *env; +}; + + +/** + * Store an item in the datastore. + * + * @param cls closure (our "struct Plugin") + * @param key key to store data under + * @param size number of bytes in data + * @param data data to store + * @param type type of the value + * @param discard_time when to discard the value in any case + * @return 0 on error, number of bytes used otherwise + */ +static size_t +template_plugin_put (void *cls, const GNUNET_HashCode * key, size_t size, + const char *data, enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute discard_time) +{ + GNUNET_break (0); + return 0; +} + + +/** + * Iterate over the results for a particular key + * in the datastore. + * + * @param cls closure (our "struct Plugin") + * @param key + * @param type entries of which type are relevant? + * @param iter maybe NULL (to just count) + * @param iter_cls closure for iter + * @return the number of results found + */ +static unsigned int +template_plugin_get (void *cls, const GNUNET_HashCode * key, + enum GNUNET_BLOCK_Type type, + GNUNET_DATACACHE_Iterator iter, void *iter_cls) +{ + GNUNET_break (0); + return 0; +} + + +/** + * Delete the entry with the lowest expiration value + * from the datacache right now. + * + * @param cls closure (our "struct Plugin") + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +template_plugin_del (void *cls) +{ + GNUNET_break (0); + return GNUNET_SYSERR; +} + + +/** + * Entry point for the plugin. + * + * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet") + * @return the plugin's closure (our "struct Plugin") + */ +void * +libgnunet_plugin_datacache_template_init (void *cls) +{ + struct GNUNET_DATACACHE_PluginEnvironment *env = cls; + struct GNUNET_DATACACHE_PluginFunctions *api; + struct Plugin *plugin; + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions)); + api->cls = plugin; + api->get = &template_plugin_get; + api->put = &template_plugin_put; + api->del = &template_plugin_del; + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "template", + _("Template datacache running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls closure (our "struct Plugin") + * @return NULL + */ +void * +libgnunet_plugin_datacache_template_done (void *cls) +{ + struct GNUNET_DATACACHE_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + + + +/* end of plugin_datacache_template.c */ diff --git a/src/datacache/test_datacache.c b/src/datacache/test_datacache.c new file mode 100644 index 0000000..d8d2f05 --- /dev/null +++ b/src/datacache/test_datacache.c @@ -0,0 +1,162 @@ +/* + This file is part of GNUnet. + (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* + * @file datacache/test_datacache.c + * @brief Test for the datacache implementations. + * @author Nils Durner + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_datacache_lib.h" + +#define VERBOSE GNUNET_NO + +#define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0) + +static int ok; + +/** + * Name of plugin under test. + */ +static const char *plugin_name; + + +static int +checkIt (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, size_t size, const char *data, + enum GNUNET_BLOCK_Type type) +{ + if (size != sizeof (GNUNET_HashCode)) + { + printf ("ERROR: Invalid size\n"); + ok = 2; + } + if (0 != memcmp (data, cls, size)) + { + printf ("ERROR: Invalid data\n"); + ok = 3; + } + return GNUNET_OK; +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_DATACACHE_Handle *h; + GNUNET_HashCode k; + GNUNET_HashCode n; + struct GNUNET_TIME_Absolute exp; + unsigned int i; + + ok = 0; + h = GNUNET_DATACACHE_create (cfg, "testcache"); + if (h == NULL) + { + FPRINTF (stderr, + "%s", + "Failed to initialize datacache. Database likely not setup, skipping test.\n"); + return; + } + exp = GNUNET_TIME_absolute_get (); + exp.abs_value += 5 * 60 * 1000; + memset (&k, 0, sizeof (GNUNET_HashCode)); + for (i = 0; i < 100; i++) + { + GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); + ASSERT (GNUNET_OK == + GNUNET_DATACACHE_put (h, &k, sizeof (GNUNET_HashCode), + (const char *) &n, 1 + i % 16, exp)); + k = n; + } + memset (&k, 0, sizeof (GNUNET_HashCode)); + for (i = 0; i < 100; i++) + { + GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); + ASSERT (1 == GNUNET_DATACACHE_get (h, &k, 1 + i % 16, &checkIt, &n)); + k = n; + } + + memset (&k, 42, sizeof (GNUNET_HashCode)); + GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); + ASSERT (GNUNET_OK == + GNUNET_DATACACHE_put (h, &k, sizeof (GNUNET_HashCode), + (const char *) &n, 792, + GNUNET_TIME_UNIT_FOREVER_ABS)); + ASSERT (0 != GNUNET_DATACACHE_get (h, &k, 792, &checkIt, &n)); + + GNUNET_DATACACHE_destroy (h); + ASSERT (ok == 0); + return; +FAILURE: + if (h != NULL) + GNUNET_DATACACHE_destroy (h); + ok = GNUNET_SYSERR; +} + + +int +main (int argc, char *argv[]) +{ + char *pos; + char cfg_name[128]; + + char *const xargv[] = { + "test-datacache", + "-c", + cfg_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test-datacache", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + /* determine name of plugin to use */ + plugin_name = argv[0]; + while (NULL != (pos = strstr (plugin_name, "_"))) + plugin_name = pos + 1; + if (NULL != (pos = strstr (plugin_name, "."))) + pos[0] = 0; + else + pos = (char *) plugin_name; + + GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_datacache_data_%s.conf", + plugin_name); + if (pos != plugin_name) + pos[0] = '.'; + GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, + "test-datacache", "nohelp", options, &run, NULL); + if (ok != 0) + FPRINTF (stderr, "Missed some testcases: %d\n", ok); + return ok; +} + +/* end of test_datacache.c */ diff --git a/src/datacache/test_datacache_data_mysql.conf b/src/datacache/test_datacache_data_mysql.conf new file mode 100644 index 0000000..bc9daa3 --- /dev/null +++ b/src/datacache/test_datacache_data_mysql.conf @@ -0,0 +1,13 @@ +[testcache] +QUOTA = 1 MB +DATABASE = mysql + +[datacache-mysql] +DATABASE = gnunetcheck +# CONFIG = ~/.my.cnf +# USER = +# PASSWORD = +# HOST = +# PORT = + + diff --git a/src/datacache/test_datacache_data_postgres.conf b/src/datacache/test_datacache_data_postgres.conf new file mode 100644 index 0000000..09e8e72 --- /dev/null +++ b/src/datacache/test_datacache_data_postgres.conf @@ -0,0 +1,8 @@ + +[testcache] +QUOTA = 1 MB +DATABASE = postgres + +[datacache-postgres] +CONFIG = connect_timeout=10; dbname=gnunetcheck + diff --git a/src/datacache/test_datacache_data_sqlite.conf b/src/datacache/test_datacache_data_sqlite.conf new file mode 100644 index 0000000..bf6ce1b --- /dev/null +++ b/src/datacache/test_datacache_data_sqlite.conf @@ -0,0 +1,5 @@ +[testcache] +QUOTA = 1 MB +DATABASE = sqlite + + diff --git a/src/datacache/test_datacache_quota.c b/src/datacache/test_datacache_quota.c new file mode 100644 index 0000000..cc47bdb --- /dev/null +++ b/src/datacache/test_datacache_quota.c @@ -0,0 +1,151 @@ +/* + This file is part of GNUnet. + (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* + * @file datacache/test_datacache_quota.c + * @brief Test for the quota code of the datacache implementations. + * @author Nils Durner + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_datacache_lib.h" + +#define VERBOSE GNUNET_NO + +#define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0) + +static int ok; + +/** + * Name of plugin under test. + */ +static const char *plugin_name; + +/** + * Quota is 1 MB. Each iteration of the test puts in about 1 MB of + * data. We do 10 iterations. Afterwards we check that the data from + * the first 5 iterations has all been discarded and that at least + * some of the data from the last iteration is still there. + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_DATACACHE_Handle *h; + GNUNET_HashCode k; + GNUNET_HashCode n; + unsigned int i; + unsigned int j; + char buf[3200]; + struct GNUNET_TIME_Absolute exp; + + ok = 0; + h = GNUNET_DATACACHE_create (cfg, "testcache"); + + if (h == NULL) + { + FPRINTF (stderr, "%s", "Failed to initialize datacache. Database likely not setup, skipping test.\n"); + return; + } + exp = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS); + memset (buf, 1, sizeof (buf)); + memset (&k, 0, sizeof (GNUNET_HashCode)); + for (i = 0; i < 10; i++) + { + FPRINTF (stderr, "%s", "."); + GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); + for (j = i; j < sizeof (buf); j += 10) + { + exp.abs_value++; + buf[j] = i; + ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, j, buf, 1 + i, exp)); + ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL)); + } + k = n; + } + FPRINTF (stderr, "%s", "\n"); + memset (&k, 0, sizeof (GNUNET_HashCode)); + for (i = 0; i < 10; i++) + { + FPRINTF (stderr, "%s", "."); + GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); + if (i < 2) + ASSERT (0 == GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL)); + if (i == 9) + ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL)); + k = n; + } + FPRINTF (stderr, "%s", "\n"); + GNUNET_DATACACHE_destroy (h); + return; +FAILURE: + if (h != NULL) + GNUNET_DATACACHE_destroy (h); + ok = GNUNET_SYSERR; +} + + +int +main (int argc, char *argv[]) +{ + char *pos; + char cfg_name[128]; + + char *const xargv[] = { + "test-datacache-quota", + "-c", + cfg_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test-datacache-quota", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + /* determine name of plugin to use */ + plugin_name = argv[0]; + while (NULL != (pos = strstr (plugin_name, "_"))) + plugin_name = pos + 1; + if (NULL != (pos = strstr (plugin_name, "."))) + pos[0] = 0; + else + pos = (char *) plugin_name; + + GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_datacache_data_%s.conf", + plugin_name); + if (pos != plugin_name) + pos[0] = '.'; + GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, + "test-datacache-quota", "nohelp", options, &run, NULL); + if (ok != 0) + FPRINTF (stderr, "Missed some testcases: %d\n", ok); + return ok; +} + +/* end of test_datacache_quota.c */ diff --git a/src/datastore/Makefile.am b/src/datastore/Makefile.am new file mode 100644 index 0000000..44c5bbe --- /dev/null +++ b/src/datastore/Makefile.am @@ -0,0 +1,234 @@ +INCLUDES = -I$(top_srcdir)/src/include + +plugindir = $(libdir)/gnunet + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + datastore.conf + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIBS = -lgcov +endif + + +lib_LTLIBRARIES = \ + libgnunetdatastore.la + +libgnunetdatastore_la_SOURCES = \ + datastore_api.c datastore.h +libgnunetdatastore_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +libgnunetdatastore_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 1:0:0 + + +bin_PROGRAMS = \ + gnunet-service-datastore + +gnunet_service_datastore_SOURCES = \ + gnunet-service-datastore.c +gnunet_service_datastore_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +if HAVE_MYSQL + MYSQL_PLUGIN = libgnunet_plugin_datastore_mysql.la +if HAVE_BENCHMARKS + MYSQL_BENCHMARKS = \ + perf_datastore_api_mysql \ + perf_plugin_datastore_mysql +endif + MYSQL_TESTS = \ + test_datastore_api_mysql \ + test_datastore_api_management_mysql \ + test_plugin_datastore_mysql \ + $(MYSQL_BENCHMARKS) +endif +if HAVE_SQLITE + SQLITE_PLUGIN = libgnunet_plugin_datastore_sqlite.la +if HAVE_BENCHMARKS + SQLITE_BENCHMARKS = \ + perf_datastore_api_sqlite \ + perf_plugin_datastore_sqlite +endif + SQLITE_TESTS = \ + test_datastore_api_sqlite \ + test_datastore_api_management_sqlite \ + test_plugin_datastore_sqlite \ + $(SQLITE_BENCHMARKS) +endif +if HAVE_POSTGRES + POSTGRES_PLUGIN = libgnunet_plugin_datastore_postgres.la +if HAVE_BENCHMARKS + POSTGRES_BENCHMARKS = \ + perf_datastore_api_postgres \ + perf_plugin_datastore_postgres +endif + POSTGRES_TESTS = \ + test_datastore_api_postgres \ + test_datastore_api_management_postgres \ + test_plugin_datastore_postgres \ + $(POSTGRES_BENCHMARKS) +endif + +plugin_LTLIBRARIES = \ + $(SQLITE_PLUGIN) \ + $(MYSQL_PLUGIN) \ + $(POSTGRES_PLUGIN) \ + libgnunet_plugin_datastore_template.la + + +libgnunet_plugin_datastore_sqlite_la_SOURCES = \ + plugin_datastore_sqlite.c +libgnunet_plugin_datastore_sqlite_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 +libgnunet_plugin_datastore_sqlite_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + +libgnunet_plugin_datastore_mysql_la_SOURCES = \ + plugin_datastore_mysql.c +libgnunet_plugin_datastore_mysql_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lz -lmysqlclient +libgnunet_plugin_datastore_mysql_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient +libgnunet_plugin_datastore_mysql_la_CPPFLAGS = \ + $(MYSQL_CPPFLAGS) + +libgnunet_plugin_datastore_postgres_la_SOURCES = \ + plugin_datastore_postgres.c +libgnunet_plugin_datastore_postgres_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq +libgnunet_plugin_datastore_postgres_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq +libgnunet_plugin_datastore_postgres_la_CPPFLAGS = \ + $(POSTGRES_CPPFLAGS) + + +libgnunet_plugin_datastore_template_la_SOURCES = \ + plugin_datastore_template.c +libgnunet_plugin_datastore_template_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) +libgnunet_plugin_datastore_template_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +check_PROGRAMS = \ + $(SQLITE_TESTS) \ + $(MYSQL_TESTS) \ + $(POSTGRES_TESTS) + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_datastore_api_sqlite_SOURCES = \ + test_datastore_api.c +test_datastore_api_sqlite_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datastore_api_management_sqlite_SOURCES = \ + test_datastore_api_management.c +test_datastore_api_management_sqlite_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datastore_api_sqlite_SOURCES = \ + perf_datastore_api.c +perf_datastore_api_sqlite_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_plugin_datastore_sqlite_SOURCES = \ + perf_plugin_datastore.c +perf_plugin_datastore_sqlite_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_plugin_datastore_sqlite_SOURCES = \ + test_plugin_datastore.c +test_plugin_datastore_sqlite_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + + +test_datastore_api_mysql_SOURCES = \ + test_datastore_api.c +test_datastore_api_mysql_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datastore_api_management_mysql_SOURCES = \ + test_datastore_api_management.c +test_datastore_api_management_mysql_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datastore_api_mysql_SOURCES = \ + perf_datastore_api.c +perf_datastore_api_mysql_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_plugin_datastore_mysql_SOURCES = \ + test_plugin_datastore.c +test_plugin_datastore_mysql_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_plugin_datastore_mysql_SOURCES = \ + perf_plugin_datastore.c +perf_plugin_datastore_mysql_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + + +test_datastore_api_postgres_SOURCES = \ + test_datastore_api.c +test_datastore_api_postgres_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datastore_api_management_postgres_SOURCES = \ + test_datastore_api_management.c +test_datastore_api_management_postgres_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datastore_api_postgres_SOURCES = \ + perf_datastore_api.c +perf_datastore_api_postgres_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_plugin_datastore_postgres_SOURCES = \ + test_plugin_datastore.c +test_plugin_datastore_postgres_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_plugin_datastore_postgres_SOURCES = \ + perf_plugin_datastore.c +perf_plugin_datastore_postgres_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + + +EXTRA_DIST = \ + test_defaults.conf \ + test_datastore_api_data_sqlite.conf \ + perf_plugin_datastore_data_sqlite.conf \ + test_datastore_api_data_mysql.conf \ + perf_plugin_datastore_data_mysql.conf \ + test_datastore_api_data_postgres.conf \ + perf_plugin_datastore_data_postgres.conf \ + test_plugin_datastore_data_mysql.conf \ + test_plugin_datastore_data_postgres.conf \ + test_plugin_datastore_data_sqlite.conf \ No newline at end of file diff --git a/src/datastore/Makefile.in b/src/datastore/Makefile.in new file mode 100644 index 0000000..d85f1ea --- /dev/null +++ b/src/datastore/Makefile.in @@ -0,0 +1,1384 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-datastore$(EXEEXT) +check_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_4) $(am__EXEEXT_6) +subdir = src/datastore +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/datastore.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = datastore.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunet_plugin_datastore_mysql_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunet_plugin_datastore_mysql_la_OBJECTS = \ + libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo +libgnunet_plugin_datastore_mysql_la_OBJECTS = \ + $(am_libgnunet_plugin_datastore_mysql_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_datastore_mysql_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_datastore_mysql_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +@HAVE_MYSQL_TRUE@am_libgnunet_plugin_datastore_mysql_la_rpath = \ +@HAVE_MYSQL_TRUE@ -rpath $(plugindir) +libgnunet_plugin_datastore_postgres_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunet_plugin_datastore_postgres_la_OBJECTS = libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo +libgnunet_plugin_datastore_postgres_la_OBJECTS = \ + $(am_libgnunet_plugin_datastore_postgres_la_OBJECTS) +libgnunet_plugin_datastore_postgres_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_datastore_postgres_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +@HAVE_POSTGRES_TRUE@am_libgnunet_plugin_datastore_postgres_la_rpath = \ +@HAVE_POSTGRES_TRUE@ -rpath $(plugindir) +libgnunet_plugin_datastore_sqlite_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunet_plugin_datastore_sqlite_la_OBJECTS = \ + plugin_datastore_sqlite.lo +libgnunet_plugin_datastore_sqlite_la_OBJECTS = \ + $(am_libgnunet_plugin_datastore_sqlite_la_OBJECTS) +libgnunet_plugin_datastore_sqlite_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_datastore_sqlite_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +@HAVE_SQLITE_TRUE@am_libgnunet_plugin_datastore_sqlite_la_rpath = \ +@HAVE_SQLITE_TRUE@ -rpath $(plugindir) +libgnunet_plugin_datastore_template_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunet_plugin_datastore_template_la_OBJECTS = \ + plugin_datastore_template.lo +libgnunet_plugin_datastore_template_la_OBJECTS = \ + $(am_libgnunet_plugin_datastore_template_la_OBJECTS) +libgnunet_plugin_datastore_template_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_datastore_template_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +libgnunetdatastore_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunetdatastore_la_OBJECTS = datastore_api.lo +libgnunetdatastore_la_OBJECTS = $(am_libgnunetdatastore_la_OBJECTS) +libgnunetdatastore_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetdatastore_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@am__EXEEXT_1 = perf_datastore_api_sqlite$(EXEEXT) \ +@HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@ perf_plugin_datastore_sqlite$(EXEEXT) +@HAVE_SQLITE_TRUE@am__EXEEXT_2 = test_datastore_api_sqlite$(EXEEXT) \ +@HAVE_SQLITE_TRUE@ test_datastore_api_management_sqlite$(EXEEXT) \ +@HAVE_SQLITE_TRUE@ test_plugin_datastore_sqlite$(EXEEXT) \ +@HAVE_SQLITE_TRUE@ $(am__EXEEXT_1) +@HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@am__EXEEXT_3 = perf_datastore_api_mysql$(EXEEXT) \ +@HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@ perf_plugin_datastore_mysql$(EXEEXT) +@HAVE_MYSQL_TRUE@am__EXEEXT_4 = test_datastore_api_mysql$(EXEEXT) \ +@HAVE_MYSQL_TRUE@ test_datastore_api_management_mysql$(EXEEXT) \ +@HAVE_MYSQL_TRUE@ test_plugin_datastore_mysql$(EXEEXT) \ +@HAVE_MYSQL_TRUE@ $(am__EXEEXT_3) +@HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@am__EXEEXT_5 = perf_datastore_api_postgres$(EXEEXT) \ +@HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@ perf_plugin_datastore_postgres$(EXEEXT) +@HAVE_POSTGRES_TRUE@am__EXEEXT_6 = \ +@HAVE_POSTGRES_TRUE@ test_datastore_api_postgres$(EXEEXT) \ +@HAVE_POSTGRES_TRUE@ test_datastore_api_management_postgres$(EXEEXT) \ +@HAVE_POSTGRES_TRUE@ test_plugin_datastore_postgres$(EXEEXT) \ +@HAVE_POSTGRES_TRUE@ $(am__EXEEXT_5) +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_service_datastore_OBJECTS = \ + gnunet-service-datastore.$(OBJEXT) +gnunet_service_datastore_OBJECTS = \ + $(am_gnunet_service_datastore_OBJECTS) +gnunet_service_datastore_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_perf_datastore_api_mysql_OBJECTS = perf_datastore_api.$(OBJEXT) +perf_datastore_api_mysql_OBJECTS = \ + $(am_perf_datastore_api_mysql_OBJECTS) +perf_datastore_api_mysql_DEPENDENCIES = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_datastore_api_postgres_OBJECTS = perf_datastore_api.$(OBJEXT) +perf_datastore_api_postgres_OBJECTS = \ + $(am_perf_datastore_api_postgres_OBJECTS) +perf_datastore_api_postgres_DEPENDENCIES = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_datastore_api_sqlite_OBJECTS = perf_datastore_api.$(OBJEXT) +perf_datastore_api_sqlite_OBJECTS = \ + $(am_perf_datastore_api_sqlite_OBJECTS) +perf_datastore_api_sqlite_DEPENDENCIES = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_plugin_datastore_mysql_OBJECTS = \ + perf_plugin_datastore.$(OBJEXT) +perf_plugin_datastore_mysql_OBJECTS = \ + $(am_perf_plugin_datastore_mysql_OBJECTS) +perf_plugin_datastore_mysql_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_plugin_datastore_postgres_OBJECTS = \ + perf_plugin_datastore.$(OBJEXT) +perf_plugin_datastore_postgres_OBJECTS = \ + $(am_perf_plugin_datastore_postgres_OBJECTS) +perf_plugin_datastore_postgres_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_plugin_datastore_sqlite_OBJECTS = \ + perf_plugin_datastore.$(OBJEXT) +perf_plugin_datastore_sqlite_OBJECTS = \ + $(am_perf_plugin_datastore_sqlite_OBJECTS) +perf_plugin_datastore_sqlite_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datastore_api_management_mysql_OBJECTS = \ + test_datastore_api_management.$(OBJEXT) +test_datastore_api_management_mysql_OBJECTS = \ + $(am_test_datastore_api_management_mysql_OBJECTS) +test_datastore_api_management_mysql_DEPENDENCIES = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datastore_api_management_postgres_OBJECTS = \ + test_datastore_api_management.$(OBJEXT) +test_datastore_api_management_postgres_OBJECTS = \ + $(am_test_datastore_api_management_postgres_OBJECTS) +test_datastore_api_management_postgres_DEPENDENCIES = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datastore_api_management_sqlite_OBJECTS = \ + test_datastore_api_management.$(OBJEXT) +test_datastore_api_management_sqlite_OBJECTS = \ + $(am_test_datastore_api_management_sqlite_OBJECTS) +test_datastore_api_management_sqlite_DEPENDENCIES = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datastore_api_mysql_OBJECTS = test_datastore_api.$(OBJEXT) +test_datastore_api_mysql_OBJECTS = \ + $(am_test_datastore_api_mysql_OBJECTS) +test_datastore_api_mysql_DEPENDENCIES = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datastore_api_postgres_OBJECTS = test_datastore_api.$(OBJEXT) +test_datastore_api_postgres_OBJECTS = \ + $(am_test_datastore_api_postgres_OBJECTS) +test_datastore_api_postgres_DEPENDENCIES = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_datastore_api_sqlite_OBJECTS = test_datastore_api.$(OBJEXT) +test_datastore_api_sqlite_OBJECTS = \ + $(am_test_datastore_api_sqlite_OBJECTS) +test_datastore_api_sqlite_DEPENDENCIES = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_plugin_datastore_mysql_OBJECTS = \ + test_plugin_datastore.$(OBJEXT) +test_plugin_datastore_mysql_OBJECTS = \ + $(am_test_plugin_datastore_mysql_OBJECTS) +test_plugin_datastore_mysql_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_plugin_datastore_postgres_OBJECTS = \ + test_plugin_datastore.$(OBJEXT) +test_plugin_datastore_postgres_OBJECTS = \ + $(am_test_plugin_datastore_postgres_OBJECTS) +test_plugin_datastore_postgres_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_plugin_datastore_sqlite_OBJECTS = \ + test_plugin_datastore.$(OBJEXT) +test_plugin_datastore_sqlite_OBJECTS = \ + $(am_test_plugin_datastore_sqlite_OBJECTS) +test_plugin_datastore_sqlite_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunet_plugin_datastore_mysql_la_SOURCES) \ + $(libgnunet_plugin_datastore_postgres_la_SOURCES) \ + $(libgnunet_plugin_datastore_sqlite_la_SOURCES) \ + $(libgnunet_plugin_datastore_template_la_SOURCES) \ + $(libgnunetdatastore_la_SOURCES) \ + $(gnunet_service_datastore_SOURCES) \ + $(perf_datastore_api_mysql_SOURCES) \ + $(perf_datastore_api_postgres_SOURCES) \ + $(perf_datastore_api_sqlite_SOURCES) \ + $(perf_plugin_datastore_mysql_SOURCES) \ + $(perf_plugin_datastore_postgres_SOURCES) \ + $(perf_plugin_datastore_sqlite_SOURCES) \ + $(test_datastore_api_management_mysql_SOURCES) \ + $(test_datastore_api_management_postgres_SOURCES) \ + $(test_datastore_api_management_sqlite_SOURCES) \ + $(test_datastore_api_mysql_SOURCES) \ + $(test_datastore_api_postgres_SOURCES) \ + $(test_datastore_api_sqlite_SOURCES) \ + $(test_plugin_datastore_mysql_SOURCES) \ + $(test_plugin_datastore_postgres_SOURCES) \ + $(test_plugin_datastore_sqlite_SOURCES) +DIST_SOURCES = $(libgnunet_plugin_datastore_mysql_la_SOURCES) \ + $(libgnunet_plugin_datastore_postgres_la_SOURCES) \ + $(libgnunet_plugin_datastore_sqlite_la_SOURCES) \ + $(libgnunet_plugin_datastore_template_la_SOURCES) \ + $(libgnunetdatastore_la_SOURCES) \ + $(gnunet_service_datastore_SOURCES) \ + $(perf_datastore_api_mysql_SOURCES) \ + $(perf_datastore_api_postgres_SOURCES) \ + $(perf_datastore_api_sqlite_SOURCES) \ + $(perf_plugin_datastore_mysql_SOURCES) \ + $(perf_plugin_datastore_postgres_SOURCES) \ + $(perf_plugin_datastore_sqlite_SOURCES) \ + $(test_datastore_api_management_mysql_SOURCES) \ + $(test_datastore_api_management_postgres_SOURCES) \ + $(test_datastore_api_management_sqlite_SOURCES) \ + $(test_datastore_api_mysql_SOURCES) \ + $(test_datastore_api_postgres_SOURCES) \ + $(test_datastore_api_sqlite_SOURCES) \ + $(test_plugin_datastore_mysql_SOURCES) \ + $(test_plugin_datastore_postgres_SOURCES) \ + $(test_plugin_datastore_sqlite_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +plugindir = $(libdir)/gnunet +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + datastore.conf + +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIBS = -lgcov +lib_LTLIBRARIES = \ + libgnunetdatastore.la + +libgnunetdatastore_la_SOURCES = \ + datastore_api.c datastore.h + +libgnunetdatastore_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +libgnunetdatastore_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 1:0:0 + +gnunet_service_datastore_SOURCES = \ + gnunet-service-datastore.c + +gnunet_service_datastore_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +@HAVE_MYSQL_TRUE@MYSQL_PLUGIN = libgnunet_plugin_datastore_mysql.la +@HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@MYSQL_BENCHMARKS = \ +@HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@ perf_datastore_api_mysql \ +@HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@ perf_plugin_datastore_mysql + +@HAVE_MYSQL_TRUE@MYSQL_TESTS = \ +@HAVE_MYSQL_TRUE@ test_datastore_api_mysql \ +@HAVE_MYSQL_TRUE@ test_datastore_api_management_mysql \ +@HAVE_MYSQL_TRUE@ test_plugin_datastore_mysql \ +@HAVE_MYSQL_TRUE@ $(MYSQL_BENCHMARKS) + +@HAVE_SQLITE_TRUE@SQLITE_PLUGIN = libgnunet_plugin_datastore_sqlite.la +@HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@SQLITE_BENCHMARKS = \ +@HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@ perf_datastore_api_sqlite \ +@HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@ perf_plugin_datastore_sqlite + +@HAVE_SQLITE_TRUE@SQLITE_TESTS = \ +@HAVE_SQLITE_TRUE@ test_datastore_api_sqlite \ +@HAVE_SQLITE_TRUE@ test_datastore_api_management_sqlite \ +@HAVE_SQLITE_TRUE@ test_plugin_datastore_sqlite \ +@HAVE_SQLITE_TRUE@ $(SQLITE_BENCHMARKS) + +@HAVE_POSTGRES_TRUE@POSTGRES_PLUGIN = libgnunet_plugin_datastore_postgres.la +@HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@POSTGRES_BENCHMARKS = \ +@HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@ perf_datastore_api_postgres \ +@HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@ perf_plugin_datastore_postgres + +@HAVE_POSTGRES_TRUE@POSTGRES_TESTS = \ +@HAVE_POSTGRES_TRUE@ test_datastore_api_postgres \ +@HAVE_POSTGRES_TRUE@ test_datastore_api_management_postgres \ +@HAVE_POSTGRES_TRUE@ test_plugin_datastore_postgres \ +@HAVE_POSTGRES_TRUE@ $(POSTGRES_BENCHMARKS) + +plugin_LTLIBRARIES = \ + $(SQLITE_PLUGIN) \ + $(MYSQL_PLUGIN) \ + $(POSTGRES_PLUGIN) \ + libgnunet_plugin_datastore_template.la + +libgnunet_plugin_datastore_sqlite_la_SOURCES = \ + plugin_datastore_sqlite.c + +libgnunet_plugin_datastore_sqlite_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 + +libgnunet_plugin_datastore_sqlite_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_datastore_mysql_la_SOURCES = \ + plugin_datastore_mysql.c + +libgnunet_plugin_datastore_mysql_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lz -lmysqlclient + +libgnunet_plugin_datastore_mysql_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient + +libgnunet_plugin_datastore_mysql_la_CPPFLAGS = \ + $(MYSQL_CPPFLAGS) + +libgnunet_plugin_datastore_postgres_la_SOURCES = \ + plugin_datastore_postgres.c + +libgnunet_plugin_datastore_postgres_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq + +libgnunet_plugin_datastore_postgres_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq + +libgnunet_plugin_datastore_postgres_la_CPPFLAGS = \ + $(POSTGRES_CPPFLAGS) + +libgnunet_plugin_datastore_template_la_SOURCES = \ + plugin_datastore_template.c + +libgnunet_plugin_datastore_template_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) + +libgnunet_plugin_datastore_template_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_datastore_api_sqlite_SOURCES = \ + test_datastore_api.c + +test_datastore_api_sqlite_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datastore_api_management_sqlite_SOURCES = \ + test_datastore_api_management.c + +test_datastore_api_management_sqlite_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datastore_api_sqlite_SOURCES = \ + perf_datastore_api.c + +perf_datastore_api_sqlite_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_plugin_datastore_sqlite_SOURCES = \ + perf_plugin_datastore.c + +perf_plugin_datastore_sqlite_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_plugin_datastore_sqlite_SOURCES = \ + test_plugin_datastore.c + +test_plugin_datastore_sqlite_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datastore_api_mysql_SOURCES = \ + test_datastore_api.c + +test_datastore_api_mysql_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datastore_api_management_mysql_SOURCES = \ + test_datastore_api_management.c + +test_datastore_api_management_mysql_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datastore_api_mysql_SOURCES = \ + perf_datastore_api.c + +perf_datastore_api_mysql_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_plugin_datastore_mysql_SOURCES = \ + test_plugin_datastore.c + +test_plugin_datastore_mysql_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_plugin_datastore_mysql_SOURCES = \ + perf_plugin_datastore.c + +perf_plugin_datastore_mysql_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datastore_api_postgres_SOURCES = \ + test_datastore_api.c + +test_datastore_api_postgres_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_datastore_api_management_postgres_SOURCES = \ + test_datastore_api_management.c + +test_datastore_api_management_postgres_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_datastore_api_postgres_SOURCES = \ + perf_datastore_api.c + +perf_datastore_api_postgres_LDADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_plugin_datastore_postgres_SOURCES = \ + test_plugin_datastore.c + +test_plugin_datastore_postgres_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_plugin_datastore_postgres_SOURCES = \ + perf_plugin_datastore.c + +perf_plugin_datastore_postgres_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_defaults.conf \ + test_datastore_api_data_sqlite.conf \ + perf_plugin_datastore_data_sqlite.conf \ + test_datastore_api_data_mysql.conf \ + perf_plugin_datastore_data_mysql.conf \ + test_datastore_api_data_postgres.conf \ + perf_plugin_datastore_data_postgres.conf \ + test_plugin_datastore_data_mysql.conf \ + test_plugin_datastore_data_postgres.conf \ + test_plugin_datastore_data_sqlite.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/datastore/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/datastore/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +datastore.conf: $(top_builddir)/config.status $(srcdir)/datastore.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_datastore_mysql.la: $(libgnunet_plugin_datastore_mysql_la_OBJECTS) $(libgnunet_plugin_datastore_mysql_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_datastore_mysql_la_LINK) $(am_libgnunet_plugin_datastore_mysql_la_rpath) $(libgnunet_plugin_datastore_mysql_la_OBJECTS) $(libgnunet_plugin_datastore_mysql_la_LIBADD) $(LIBS) +libgnunet_plugin_datastore_postgres.la: $(libgnunet_plugin_datastore_postgres_la_OBJECTS) $(libgnunet_plugin_datastore_postgres_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_datastore_postgres_la_LINK) $(am_libgnunet_plugin_datastore_postgres_la_rpath) $(libgnunet_plugin_datastore_postgres_la_OBJECTS) $(libgnunet_plugin_datastore_postgres_la_LIBADD) $(LIBS) +libgnunet_plugin_datastore_sqlite.la: $(libgnunet_plugin_datastore_sqlite_la_OBJECTS) $(libgnunet_plugin_datastore_sqlite_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_datastore_sqlite_la_LINK) $(am_libgnunet_plugin_datastore_sqlite_la_rpath) $(libgnunet_plugin_datastore_sqlite_la_OBJECTS) $(libgnunet_plugin_datastore_sqlite_la_LIBADD) $(LIBS) +libgnunet_plugin_datastore_template.la: $(libgnunet_plugin_datastore_template_la_OBJECTS) $(libgnunet_plugin_datastore_template_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_datastore_template_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_datastore_template_la_OBJECTS) $(libgnunet_plugin_datastore_template_la_LIBADD) $(LIBS) +libgnunetdatastore.la: $(libgnunetdatastore_la_OBJECTS) $(libgnunetdatastore_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetdatastore_la_LINK) -rpath $(libdir) $(libgnunetdatastore_la_OBJECTS) $(libgnunetdatastore_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-service-datastore$(EXEEXT): $(gnunet_service_datastore_OBJECTS) $(gnunet_service_datastore_DEPENDENCIES) + @rm -f gnunet-service-datastore$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_datastore_OBJECTS) $(gnunet_service_datastore_LDADD) $(LIBS) +perf_datastore_api_mysql$(EXEEXT): $(perf_datastore_api_mysql_OBJECTS) $(perf_datastore_api_mysql_DEPENDENCIES) + @rm -f perf_datastore_api_mysql$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_datastore_api_mysql_OBJECTS) $(perf_datastore_api_mysql_LDADD) $(LIBS) +perf_datastore_api_postgres$(EXEEXT): $(perf_datastore_api_postgres_OBJECTS) $(perf_datastore_api_postgres_DEPENDENCIES) + @rm -f perf_datastore_api_postgres$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_datastore_api_postgres_OBJECTS) $(perf_datastore_api_postgres_LDADD) $(LIBS) +perf_datastore_api_sqlite$(EXEEXT): $(perf_datastore_api_sqlite_OBJECTS) $(perf_datastore_api_sqlite_DEPENDENCIES) + @rm -f perf_datastore_api_sqlite$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_datastore_api_sqlite_OBJECTS) $(perf_datastore_api_sqlite_LDADD) $(LIBS) +perf_plugin_datastore_mysql$(EXEEXT): $(perf_plugin_datastore_mysql_OBJECTS) $(perf_plugin_datastore_mysql_DEPENDENCIES) + @rm -f perf_plugin_datastore_mysql$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_plugin_datastore_mysql_OBJECTS) $(perf_plugin_datastore_mysql_LDADD) $(LIBS) +perf_plugin_datastore_postgres$(EXEEXT): $(perf_plugin_datastore_postgres_OBJECTS) $(perf_plugin_datastore_postgres_DEPENDENCIES) + @rm -f perf_plugin_datastore_postgres$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_plugin_datastore_postgres_OBJECTS) $(perf_plugin_datastore_postgres_LDADD) $(LIBS) +perf_plugin_datastore_sqlite$(EXEEXT): $(perf_plugin_datastore_sqlite_OBJECTS) $(perf_plugin_datastore_sqlite_DEPENDENCIES) + @rm -f perf_plugin_datastore_sqlite$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_plugin_datastore_sqlite_OBJECTS) $(perf_plugin_datastore_sqlite_LDADD) $(LIBS) +test_datastore_api_management_mysql$(EXEEXT): $(test_datastore_api_management_mysql_OBJECTS) $(test_datastore_api_management_mysql_DEPENDENCIES) + @rm -f test_datastore_api_management_mysql$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datastore_api_management_mysql_OBJECTS) $(test_datastore_api_management_mysql_LDADD) $(LIBS) +test_datastore_api_management_postgres$(EXEEXT): $(test_datastore_api_management_postgres_OBJECTS) $(test_datastore_api_management_postgres_DEPENDENCIES) + @rm -f test_datastore_api_management_postgres$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datastore_api_management_postgres_OBJECTS) $(test_datastore_api_management_postgres_LDADD) $(LIBS) +test_datastore_api_management_sqlite$(EXEEXT): $(test_datastore_api_management_sqlite_OBJECTS) $(test_datastore_api_management_sqlite_DEPENDENCIES) + @rm -f test_datastore_api_management_sqlite$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datastore_api_management_sqlite_OBJECTS) $(test_datastore_api_management_sqlite_LDADD) $(LIBS) +test_datastore_api_mysql$(EXEEXT): $(test_datastore_api_mysql_OBJECTS) $(test_datastore_api_mysql_DEPENDENCIES) + @rm -f test_datastore_api_mysql$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datastore_api_mysql_OBJECTS) $(test_datastore_api_mysql_LDADD) $(LIBS) +test_datastore_api_postgres$(EXEEXT): $(test_datastore_api_postgres_OBJECTS) $(test_datastore_api_postgres_DEPENDENCIES) + @rm -f test_datastore_api_postgres$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datastore_api_postgres_OBJECTS) $(test_datastore_api_postgres_LDADD) $(LIBS) +test_datastore_api_sqlite$(EXEEXT): $(test_datastore_api_sqlite_OBJECTS) $(test_datastore_api_sqlite_DEPENDENCIES) + @rm -f test_datastore_api_sqlite$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_datastore_api_sqlite_OBJECTS) $(test_datastore_api_sqlite_LDADD) $(LIBS) +test_plugin_datastore_mysql$(EXEEXT): $(test_plugin_datastore_mysql_OBJECTS) $(test_plugin_datastore_mysql_DEPENDENCIES) + @rm -f test_plugin_datastore_mysql$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_plugin_datastore_mysql_OBJECTS) $(test_plugin_datastore_mysql_LDADD) $(LIBS) +test_plugin_datastore_postgres$(EXEEXT): $(test_plugin_datastore_postgres_OBJECTS) $(test_plugin_datastore_postgres_DEPENDENCIES) + @rm -f test_plugin_datastore_postgres$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_plugin_datastore_postgres_OBJECTS) $(test_plugin_datastore_postgres_LDADD) $(LIBS) +test_plugin_datastore_sqlite$(EXEEXT): $(test_plugin_datastore_sqlite_OBJECTS) $(test_plugin_datastore_sqlite_DEPENDENCIES) + @rm -f test_plugin_datastore_sqlite$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_plugin_datastore_sqlite_OBJECTS) $(test_plugin_datastore_sqlite_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datastore_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-datastore.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_datastore_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_plugin_datastore.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_datastore_sqlite.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_datastore_template.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_datastore_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_datastore_api_management.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_plugin_datastore.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo: plugin_datastore_mysql.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datastore_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.Tpo -c -o libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo `test -f 'plugin_datastore_mysql.c' || echo '$(srcdir)/'`plugin_datastore_mysql.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.Tpo $(DEPDIR)/libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_datastore_mysql.c' object='libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datastore_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo `test -f 'plugin_datastore_mysql.c' || echo '$(srcdir)/'`plugin_datastore_mysql.c + +libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo: plugin_datastore_postgres.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datastore_postgres_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.Tpo -c -o libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo `test -f 'plugin_datastore_postgres.c' || echo '$(srcdir)/'`plugin_datastore_postgres.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.Tpo $(DEPDIR)/libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_datastore_postgres.c' object='libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datastore_postgres_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo `test -f 'plugin_datastore_postgres.c' || echo '$(srcdir)/'`plugin_datastore_postgres.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-pkgcfgDATA \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/datastore/datastore.conf.in b/src/datastore/datastore.conf.in new file mode 100644 index 0000000..837c619 --- /dev/null +++ b/src/datastore/datastore.conf.in @@ -0,0 +1,33 @@ +[datastore] +AUTOSTART = YES +UNIXPATH = /tmp/gnunet-service-datastore.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +@UNIXONLY@ PORT = 2093 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-datastore +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +QUOTA = 100 MB +BLOOMFILTER = $SERVICEHOME/datastore/bloomfilter +DATABASE = sqlite +# DISABLE_SOCKET_FORWARDING = NO + +[datastore-sqlite] +FILENAME = $SERVICEHOME/datastore/sqlite.db + +[datastore-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[datastore-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf +# USER = gnunet +# PASSWORD = +# HOST = localhost +# PORT = 3306 + + + diff --git a/src/datastore/datastore.h b/src/datastore/datastore.h new file mode 100644 index 0000000..1126027 --- /dev/null +++ b/src/datastore/datastore.h @@ -0,0 +1,263 @@ +/* + This file is part of GNUnet + (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datastore/datastore.h + * @brief structs for communication between datastore service and API + * @author Christian Grothoff + */ + +#ifndef DATASTORE_H +#define DATASTORE_H + +#define DEBUG_DATASTORE GNUNET_EXTRA_LOGGING + +#include "gnunet_util_lib.h" + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message from datastore service informing client about + * the current size of the datastore. + */ +struct ReserveMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE. + */ + struct GNUNET_MessageHeader header; + + /** + * Number of items to reserve. + */ + uint32_t entries GNUNET_PACKED; + + /** + * Number of bytes to reserve. + */ + uint64_t amount GNUNET_PACKED; +}; + + +/** + * Message from datastore service informing client about + * the success or failure of a requested operation. + * This header is optionally followed by a variable-size, + * 0-terminated error message. + */ +struct StatusMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_DATASTORE_STATUS. + */ + struct GNUNET_MessageHeader header; + + /** + * Status code, -1 for errors. + */ + int32_t status GNUNET_PACKED; + + /** + * Minimum expiration time required for content to be stored + * by the datacache at this time, zero for unknown or no limit. + */ + struct GNUNET_TIME_AbsoluteNBO min_expiration; + +}; + + +/** + * Message from datastore client informing service that + * the remainder of the reserved bytes can now be released + * for other requests. + */ +struct ReleaseReserveMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE. + */ + struct GNUNET_MessageHeader header; + + /** + * Reservation id. + */ + int32_t rid GNUNET_PACKED; + +}; + + +/** + * Message to the datastore service asking about specific + * content. + */ +struct GetMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_DATASTORE_GET. Size + * can either be "sizeof(struct GetMessage)" or + * "sizeof(struct GetMessage) - sizeof(GNUNET_HashCode)"! + */ + struct GNUNET_MessageHeader header; + + /** + * Desired content type. (actually an enum GNUNET_BLOCK_Type) + */ + uint32_t type GNUNET_PACKED; + + /** + * Offset of the result. + */ + uint64_t offset GNUNET_PACKED; + + /** + * Desired key (optional). Check the "size" of the + * header to see if the key is actually present. + */ + GNUNET_HashCode key GNUNET_PACKED; + +}; + + +/** + * Message to the datastore service asking about zero + * anonymity content. + */ +struct GetZeroAnonymityMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY. + */ + struct GNUNET_MessageHeader header; + + /** + * Desired content type (actually an enum GNUNET_BLOCK_Type) + */ + uint32_t type GNUNET_PACKED; + + /** + * Offset of the result. + */ + uint64_t offset GNUNET_PACKED; + +}; + + +/** + * Message to the datastore service requesting an update + * to the priority or expiration for some content. + */ +struct UpdateMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE. + */ + struct GNUNET_MessageHeader header; + + /** + * Desired priority increase. + */ + int32_t priority GNUNET_PACKED; + + /** + * Desired new expiration time. + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /** + * Unique ID for the content. + */ + uint64_t uid; + +}; + + +/** + * Message transmitting content from or to the datastore + * service. + */ +struct DataMessage +{ + /** + * Type is either GNUNET_MESSAGE_TYPE_DATASTORE_PUT, + * GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE or + * GNUNET_MESSAGE_TYPE_DATASTORE_DATA. Depending on the message + * type, some fields may simply have values of zero. + */ + struct GNUNET_MessageHeader header; + + /** + * Reservation ID to use; use zero for none. + */ + uint32_t rid GNUNET_PACKED; + + /** + * Number of bytes in the item (NBO). + */ + uint32_t size GNUNET_PACKED; + + /** + * Type of the item (NBO), zero for remove, (actually an enum GNUNET_BLOCK_Type) + */ + uint32_t type GNUNET_PACKED; + + /** + * Priority of the item (NBO), zero for remove. + */ + uint32_t priority GNUNET_PACKED; + + /** + * Desired anonymity level (NBO), zero for remove. + */ + uint32_t anonymity GNUNET_PACKED; + + /** + * Desired replication level. 0 from service to API. + */ + uint32_t replication GNUNET_PACKED; + + /** + * For alignment. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Unique ID for the content (can be used for UPDATE); + * can be zero for remove (which indicates that + * the datastore should use whatever UID matches + * the key and content). + */ + uint64_t uid; + + /** + * Expiration time (NBO); zero for remove. + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /** + * Key under which the item can be found. + */ + GNUNET_HashCode key GNUNET_PACKED; + +}; +GNUNET_NETWORK_STRUCT_END + + + +#endif diff --git a/src/datastore/datastore_api.c b/src/datastore/datastore_api.c new file mode 100644 index 0000000..4f406a2 --- /dev/null +++ b/src/datastore/datastore_api.c @@ -0,0 +1,1505 @@ +/* + This file is part of GNUnet + (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datastore/datastore_api.c + * @brief Management for the datastore for files stored on a GNUnet node. Implements + * a priority queue for requests (with timeouts). + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_arm_service.h" +#include "gnunet_constants.h" +#include "gnunet_datastore_service.h" +#include "gnunet_statistics_service.h" +#include "datastore.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "datastore-api",__VA_ARGS__) + +/** + * If a client stopped asking for more results, how many more do + * we receive from the DB before killing the connection? Trade-off + * between re-doing TCP handshakes and (needlessly) receiving + * useless results. + */ +#define MAX_EXCESS_RESULTS 8 + +/** + * Context for processing status messages. + */ +struct StatusContext +{ + /** + * Continuation to call with the status. + */ + GNUNET_DATASTORE_ContinuationWithStatus cont; + + /** + * Closure for cont. + */ + void *cont_cls; + +}; + + +/** + * Context for processing result messages. + */ +struct ResultContext +{ + /** + * Function to call with the result. + */ + GNUNET_DATASTORE_DatumProcessor proc; + + /** + * Closure for proc. + */ + void *proc_cls; + +}; + + +/** + * Context for a queue operation. + */ +union QueueContext +{ + + struct StatusContext sc; + + struct ResultContext rc; + +}; + + + +/** + * Entry in our priority queue. + */ +struct GNUNET_DATASTORE_QueueEntry +{ + + /** + * This is a linked list. + */ + struct GNUNET_DATASTORE_QueueEntry *next; + + /** + * This is a linked list. + */ + struct GNUNET_DATASTORE_QueueEntry *prev; + + /** + * Handle to the master context. + */ + struct GNUNET_DATASTORE_Handle *h; + + /** + * Response processor (NULL if we are not waiting for a response). + * This struct should be used for the closure, function-specific + * arguments can be passed via 'qc'. + */ + GNUNET_CLIENT_MessageHandler response_proc; + + /** + * Function to call after transmission of the request. + */ + GNUNET_DATASTORE_ContinuationWithStatus cont; + + /** + * Closure for 'cont'. + */ + void *cont_cls; + + /** + * Context for the operation. + */ + union QueueContext qc; + + /** + * Task for timeout signalling. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Timeout for the current operation. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Priority in the queue. + */ + unsigned int priority; + + /** + * Maximum allowed length of queue (otherwise + * this request should be discarded). + */ + unsigned int max_queue; + + /** + * Number of bytes in the request message following + * this struct. 32-bit value for nicer memory + * access (and overall struct alignment). + */ + uint32_t message_size; + + /** + * Has this message been transmitted to the service? + * Only ever GNUNET_YES for the head of the queue. + * Note that the overall struct should end at a + * multiple of 64 bits. + */ + int was_transmitted; + +}; + +/** + * Handle to the datastore service. + */ +struct GNUNET_DATASTORE_Handle +{ + + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Current connection to the datastore service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Handle for statistics. + */ + struct GNUNET_STATISTICS_Handle *stats; + + /** + * Current transmit handle. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Current head of priority queue. + */ + struct GNUNET_DATASTORE_QueueEntry *queue_head; + + /** + * Current tail of priority queue. + */ + struct GNUNET_DATASTORE_QueueEntry *queue_tail; + + /** + * Task for trying to reconnect. + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * How quickly should we retry? Used for exponential back-off on + * connect-errors. + */ + struct GNUNET_TIME_Relative retry_time; + + /** + * Number of entries in the queue. + */ + unsigned int queue_size; + + /** + * Number of results we're receiving for the current query + * after application stopped to care. Used to determine when + * to reset the connection. + */ + unsigned int result_count; + + /** + * Are we currently trying to receive from the service? + */ + int in_receive; + + /** + * We should ignore the next message(s) from the service. + */ + unsigned int skip_next_messages; + +}; + + + +/** + * Connect to the datastore service. + * + * @param cfg configuration to use + * @return handle to use to access the service + */ +struct GNUNET_DATASTORE_Handle * +GNUNET_DATASTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_CLIENT_Connection *c; + struct GNUNET_DATASTORE_Handle *h; + + c = GNUNET_CLIENT_connect ("datastore", cfg); + if (c == NULL) + return NULL; /* oops */ + h = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_Handle) + + GNUNET_SERVER_MAX_MESSAGE_SIZE - 1); + h->client = c; + h->cfg = cfg; + h->stats = GNUNET_STATISTICS_create ("datastore-api", cfg); + return h; +} + + +/** + * Transmit DROP message to datastore service. + * + * @param cls the 'struct GNUNET_DATASTORE_Handle' + * @param size number of bytes that can be copied to buf + * @param buf where to copy the drop message + * @return number of bytes written to buf + */ +static size_t +transmit_drop (void *cls, size_t size, void *buf) +{ + struct GNUNET_DATASTORE_Handle *h = cls; + struct GNUNET_MessageHeader *hdr; + + if (buf == NULL) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Failed to transmit request to drop database.\n")); + GNUNET_DATASTORE_disconnect (h, GNUNET_NO); + return 0; + } + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + hdr = buf; + hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); + hdr->type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_DROP); + GNUNET_DATASTORE_disconnect (h, GNUNET_NO); + return sizeof (struct GNUNET_MessageHeader); +} + + +/** + * Disconnect from the datastore service (and free + * associated resources). + * + * @param h handle to the datastore + * @param drop set to GNUNET_YES to delete all data in datastore (!) + */ +void +GNUNET_DATASTORE_disconnect (struct GNUNET_DATASTORE_Handle *h, int drop) +{ + struct GNUNET_DATASTORE_QueueEntry *qe; + +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Datastore disconnect\n"); +#endif + if (NULL != h->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } + if (h->client != NULL) + { + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->client = NULL; + } + if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (h->reconnect_task); + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + while (NULL != (qe = h->queue_head)) + { + GNUNET_assert (NULL != qe->response_proc); + qe->response_proc (h, NULL); + } + if (GNUNET_YES == drop) + { + h->client = GNUNET_CLIENT_connect ("datastore", h->cfg); + if (h->client != NULL) + { + if (NULL != + GNUNET_CLIENT_notify_transmit_ready (h->client, + sizeof (struct + GNUNET_MessageHeader), + GNUNET_TIME_UNIT_MINUTES, + GNUNET_YES, &transmit_drop, h)) + return; + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->client = NULL; + } + GNUNET_break (0); + } + GNUNET_STATISTICS_destroy (h->stats, GNUNET_NO); + h->stats = NULL; + GNUNET_free (h); +} + + +/** + * A request has timed out (before being transmitted to the service). + * + * @param cls the 'struct GNUNET_DATASTORE_QueueEntry' + * @param tc scheduler context + */ +static void +timeout_queue_entry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_DATASTORE_QueueEntry *qe = cls; + + GNUNET_STATISTICS_update (qe->h->stats, + gettext_noop ("# queue entry timeouts"), 1, + GNUNET_NO); + qe->task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (qe->was_transmitted == GNUNET_NO); +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Timeout of request in datastore queue\n"); +#endif + qe->response_proc (qe->h, NULL); +} + + +/** + * Create a new entry for our priority queue (and possibly discard other entires if + * the queue is getting too long). + * + * @param h handle to the datastore + * @param msize size of the message to queue + * @param queue_priority priority of the entry + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout timeout for the operation + * @param response_proc function to call with replies (can be NULL) + * @param qc client context (NOT a closure for response_proc) + * @return NULL if the queue is full + */ +static struct GNUNET_DATASTORE_QueueEntry * +make_queue_entry (struct GNUNET_DATASTORE_Handle *h, size_t msize, + unsigned int queue_priority, unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_CLIENT_MessageHandler response_proc, + const union QueueContext *qc) +{ + struct GNUNET_DATASTORE_QueueEntry *ret; + struct GNUNET_DATASTORE_QueueEntry *pos; + unsigned int c; + + c = 0; + pos = h->queue_head; + while ((pos != NULL) && (c < max_queue_size) && + (pos->priority >= queue_priority)) + { + c++; + pos = pos->next; + } + if (c >= max_queue_size) + { + GNUNET_STATISTICS_update (h->stats, gettext_noop ("# queue overflows"), 1, + GNUNET_NO); + return NULL; + } + ret = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_QueueEntry) + msize); + ret->h = h; + ret->response_proc = response_proc; + ret->qc = *qc; + ret->timeout = GNUNET_TIME_relative_to_absolute (timeout); + ret->priority = queue_priority; + ret->max_queue = max_queue_size; + ret->message_size = msize; + ret->was_transmitted = GNUNET_NO; + if (pos == NULL) + { + /* append at the tail */ + pos = h->queue_tail; + } + else + { + pos = pos->prev; + /* do not insert at HEAD if HEAD query was already + * transmitted and we are still receiving replies! */ + if ((pos == NULL) && (h->queue_head->was_transmitted)) + pos = h->queue_head; + } + c++; + GNUNET_STATISTICS_update (h->stats, gettext_noop ("# queue entries created"), + 1, GNUNET_NO); + GNUNET_CONTAINER_DLL_insert_after (h->queue_head, h->queue_tail, pos, ret); + h->queue_size++; + ret->task = GNUNET_SCHEDULER_add_delayed (timeout, &timeout_queue_entry, ret); + pos = ret->next; + while (pos != NULL) + { + if ((pos->max_queue < h->queue_size) && (pos->was_transmitted == GNUNET_NO)) + { + GNUNET_assert (pos->response_proc != NULL); + /* move 'pos' element to head so that it will be + * killed on 'NULL' call below */ +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Dropping request from datastore queue\n"); +#endif + GNUNET_CONTAINER_DLL_remove (h->queue_head, h->queue_tail, pos); + GNUNET_CONTAINER_DLL_insert (h->queue_head, h->queue_tail, pos); + GNUNET_STATISTICS_update (h->stats, + gettext_noop + ("# Requests dropped from datastore queue"), 1, + GNUNET_NO); + GNUNET_assert (h->queue_head == pos); + pos->response_proc (h, NULL); + break; + } + pos = pos->next; + } + return ret; +} + + +/** + * Process entries in the queue (or do nothing if we are already + * doing so). + * + * @param h handle to the datastore + */ +static void +process_queue (struct GNUNET_DATASTORE_Handle *h); + + +/** + * Try reconnecting to the datastore service. + * + * @param cls the 'struct GNUNET_DATASTORE_Handle' + * @param tc scheduler context + */ +static void +try_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_DATASTORE_Handle *h = cls; + + if (h->retry_time.rel_value < GNUNET_CONSTANTS_SERVICE_RETRY.rel_value) + h->retry_time = GNUNET_CONSTANTS_SERVICE_RETRY; + else + h->retry_time = GNUNET_TIME_relative_multiply (h->retry_time, 2); + if (h->retry_time.rel_value > GNUNET_CONSTANTS_SERVICE_TIMEOUT.rel_value) + h->retry_time = GNUNET_CONSTANTS_SERVICE_TIMEOUT; + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + h->client = GNUNET_CLIENT_connect ("datastore", h->cfg); + if (h->client == NULL) + { + LOG (GNUNET_ERROR_TYPE_ERROR, "DATASTORE reconnect failed (fatally)\n"); + return; + } + GNUNET_STATISTICS_update (h->stats, + gettext_noop + ("# datastore connections (re)created"), 1, + GNUNET_NO); +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnected to DATASTORE\n"); +#endif + process_queue (h); +} + + +/** + * Disconnect from the service and then try reconnecting to the datastore service + * after some delay. + * + * @param h handle to datastore to disconnect and reconnect + */ +static void +do_disconnect (struct GNUNET_DATASTORE_Handle *h) +{ + if (h->client == NULL) + { +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "client NULL in disconnect, will not try to reconnect\n"); +#endif + return; + } +#if 0 + GNUNET_STATISTICS_update (stats, gettext_noop ("# reconnected to DATASTORE"), + 1, GNUNET_NO); +#endif + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->skip_next_messages = 0; + h->client = NULL; + h->reconnect_task = + GNUNET_SCHEDULER_add_delayed (h->retry_time, &try_reconnect, h); +} + + +/** + * Function called whenever we receive a message from + * the service. Calls the appropriate handler. + * + * @param cls the 'struct GNUNET_DATASTORE_Handle' + * @param msg the received message + */ +static void +receive_cb (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_DATASTORE_Handle *h = cls; + struct GNUNET_DATASTORE_QueueEntry *qe; + + h->in_receive = GNUNET_NO; +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving reply from datastore\n"); +#endif + if (h->skip_next_messages > 0) + { + h->skip_next_messages--; + process_queue (h); + return; + } + if (NULL == (qe = h->queue_head)) + { + GNUNET_break (0); + process_queue (h); + return; + } + qe->response_proc (h, msg); +} + + +/** + * Transmit request from queue to datastore service. + * + * @param cls the 'struct GNUNET_DATASTORE_Handle' + * @param size number of bytes that can be copied to buf + * @param buf where to copy the drop message + * @return number of bytes written to buf + */ +static size_t +transmit_request (void *cls, size_t size, void *buf) +{ + struct GNUNET_DATASTORE_Handle *h = cls; + struct GNUNET_DATASTORE_QueueEntry *qe; + size_t msize; + + h->th = NULL; + if (NULL == (qe = h->queue_head)) + return 0; /* no entry in queue */ + if (buf == NULL) + { +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit request to DATASTORE.\n"); +#endif + GNUNET_STATISTICS_update (h->stats, + gettext_noop ("# transmission request failures"), + 1, GNUNET_NO); + do_disconnect (h); + return 0; + } + if (size < (msize = qe->message_size)) + { + process_queue (h); + return 0; + } +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u byte request to DATASTORE\n", + msize); +#endif + memcpy (buf, &qe[1], msize); + qe->was_transmitted = GNUNET_YES; + GNUNET_SCHEDULER_cancel (qe->task); + qe->task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (GNUNET_NO == h->in_receive); + h->in_receive = GNUNET_YES; + GNUNET_CLIENT_receive (h->client, &receive_cb, h, + GNUNET_TIME_absolute_get_remaining (qe->timeout)); + GNUNET_STATISTICS_update (h->stats, + gettext_noop ("# bytes sent to datastore"), 1, + GNUNET_NO); + return msize; +} + + +/** + * Process entries in the queue (or do nothing if we are already + * doing so). + * + * @param h handle to the datastore + */ +static void +process_queue (struct GNUNET_DATASTORE_Handle *h) +{ + struct GNUNET_DATASTORE_QueueEntry *qe; + + if (NULL == (qe = h->queue_head)) + { +#if DEBUG_DATASTORE > 1 + LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue empty\n"); +#endif + return; /* no entry in queue */ + } + if (qe->was_transmitted == GNUNET_YES) + { +#if DEBUG_DATASTORE > 1 + LOG (GNUNET_ERROR_TYPE_DEBUG, "Head request already transmitted\n"); +#endif + return; /* waiting for replies */ + } + if (h->th != NULL) + { +#if DEBUG_DATASTORE > 1 + LOG (GNUNET_ERROR_TYPE_DEBUG, "Pending transmission request\n"); +#endif + return; /* request pending */ + } + if (h->client == NULL) + { +#if DEBUG_DATASTORE > 1 + LOG (GNUNET_ERROR_TYPE_DEBUG, "Not connected\n"); +#endif + return; /* waiting for reconnect */ + } + if (GNUNET_YES == h->in_receive) + { + /* wait for response to previous query */ + return; + } +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Queueing %u byte request to DATASTORE\n", + qe->message_size); +#endif + h->th = + GNUNET_CLIENT_notify_transmit_ready (h->client, qe->message_size, + GNUNET_TIME_absolute_get_remaining + (qe->timeout), GNUNET_YES, + &transmit_request, h); + GNUNET_assert (GNUNET_NO == h->in_receive); + GNUNET_break (NULL != h->th); +} + + +/** + * Dummy continuation used to do nothing (but be non-zero). + * + * @param cls closure + * @param result result + * @param min_expiration expiration time + * @param emsg error message + */ +static void +drop_status_cont (void *cls, int32_t result, + struct GNUNET_TIME_Absolute min_expiration, + const char *emsg) +{ + /* do nothing */ +} + + +/** + * Free a queue entry. Removes the given entry from the + * queue and releases associated resources. Does NOT + * call the callback. + * + * @param qe entry to free. + */ +static void +free_queue_entry (struct GNUNET_DATASTORE_QueueEntry *qe) +{ + struct GNUNET_DATASTORE_Handle *h = qe->h; + + GNUNET_CONTAINER_DLL_remove (h->queue_head, h->queue_tail, qe); + if (qe->task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (qe->task); + qe->task = GNUNET_SCHEDULER_NO_TASK; + } + h->queue_size--; + qe->was_transmitted = GNUNET_SYSERR; /* use-after-free warning */ + GNUNET_free (qe); +} + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +process_status_message (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_DATASTORE_Handle *h = cls; + struct GNUNET_DATASTORE_QueueEntry *qe; + struct StatusContext rc; + const struct StatusMessage *sm; + const char *emsg; + int32_t status; + int was_transmitted; + + if (NULL == (qe = h->queue_head)) + { + GNUNET_break (0); + do_disconnect (h); + return; + } + rc = qe->qc.sc; + if (msg == NULL) + { + was_transmitted = qe->was_transmitted; + free_queue_entry (qe); + if (was_transmitted == GNUNET_YES) + do_disconnect (h); + else + process_queue (h); + if (rc.cont != NULL) + rc.cont (rc.cont_cls, GNUNET_SYSERR, + GNUNET_TIME_UNIT_ZERO_ABS, + _("Failed to receive status response from database.")); + return; + } + GNUNET_assert (GNUNET_YES == qe->was_transmitted); + free_queue_entry (qe); + if ((ntohs (msg->size) < sizeof (struct StatusMessage)) || + (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DATASTORE_STATUS)) + { + GNUNET_break (0); + h->retry_time = GNUNET_TIME_UNIT_ZERO; + do_disconnect (h); + if (rc.cont != NULL) + rc.cont (rc.cont_cls, GNUNET_SYSERR, + GNUNET_TIME_UNIT_ZERO_ABS, + _("Error reading response from datastore service")); + return; + } + sm = (const struct StatusMessage *) msg; + status = ntohl (sm->status); + emsg = NULL; + if (ntohs (msg->size) > sizeof (struct StatusMessage)) + { + emsg = (const char *) &sm[1]; + if (emsg[ntohs (msg->size) - sizeof (struct StatusMessage) - 1] != '\0') + { + GNUNET_break (0); + emsg = _("Invalid error message received from datastore service"); + } + } + if ((status == GNUNET_SYSERR) && (emsg == NULL)) + { + GNUNET_break (0); + emsg = _("Invalid error message received from datastore service"); + } +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received status %d/%s\n", (int) status, emsg); +#endif + GNUNET_STATISTICS_update (h->stats, + gettext_noop ("# status messages received"), 1, + GNUNET_NO); + h->retry_time.rel_value = 0; + process_queue (h); + if (rc.cont != NULL) + rc.cont (rc.cont_cls, status, + GNUNET_TIME_absolute_ntoh (sm->min_expiration), + emsg); +} + + +/** + * Store an item in the datastore. If the item is already present, + * the priorities are summed up and the higher expiration time and + * lower anonymity level is used. + * + * @param h handle to the datastore + * @param rid reservation ID to use (from "reserve"); use 0 if no + * prior reservation was made + * @param key key for the value + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param replication how often should the content be replicated to other peers? + * @param expiration expiration time for the content + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout timeout for the operation + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel; note that even if NULL is returned, the callback will be invoked + * (or rather, will already have been invoked) + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h, uint32_t rid, + const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + uint32_t replication, + struct GNUNET_TIME_Absolute expiration, + unsigned int queue_priority, unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_DATASTORE_QueueEntry *qe; + struct DataMessage *dm; + size_t msize; + union QueueContext qc; + +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Asked to put %u bytes of data under key `%s' for %llu ms\n", size, + GNUNET_h2s (key), + GNUNET_TIME_absolute_get_remaining (expiration).rel_value); +#endif + msize = sizeof (struct DataMessage) + size; + GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); + qc.sc.cont = cont; + qc.sc.cont_cls = cont_cls; + qe = make_queue_entry (h, msize, queue_priority, max_queue_size, timeout, + &process_status_message, &qc); + if (qe == NULL) + { +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for PUT\n"); +#endif + return NULL; + } + GNUNET_STATISTICS_update (h->stats, gettext_noop ("# PUT requests executed"), + 1, GNUNET_NO); + dm = (struct DataMessage *) &qe[1]; + dm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_PUT); + dm->header.size = htons (msize); + dm->rid = htonl (rid); + dm->size = htonl ((uint32_t) size); + dm->type = htonl (type); + dm->priority = htonl (priority); + dm->anonymity = htonl (anonymity); + dm->replication = htonl (replication); + dm->reserved = htonl (0); + dm->uid = GNUNET_htonll (0); + dm->expiration = GNUNET_TIME_absolute_hton (expiration); + dm->key = *key; + memcpy (&dm[1], data, size); + process_queue (h); + return qe; +} + + +/** + * Reserve space in the datastore. This function should be used + * to avoid "out of space" failures during a longer sequence of "put" + * operations (for example, when a file is being inserted). + * + * @param h handle to the datastore + * @param amount how much space (in bytes) should be reserved (for content only) + * @param entries how many entries will be created (to calculate per-entry overhead) + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response (or before dying in queue) + * @param cont continuation to call when done; "success" will be set to + * a positive reservation value if space could be reserved. + * @param cont_cls closure for cont + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel; note that even if NULL is returned, the callback will be invoked + * (or rather, will already have been invoked) + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_reserve (struct GNUNET_DATASTORE_Handle *h, uint64_t amount, + uint32_t entries, unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_DATASTORE_QueueEntry *qe; + struct ReserveMessage *rm; + union QueueContext qc; + + if (cont == NULL) + cont = &drop_status_cont; +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Asked to reserve %llu bytes of data and %u entries\n", + (unsigned long long) amount, (unsigned int) entries); +#endif + qc.sc.cont = cont; + qc.sc.cont_cls = cont_cls; + qe = make_queue_entry (h, sizeof (struct ReserveMessage), queue_priority, + max_queue_size, timeout, &process_status_message, &qc); + if (qe == NULL) + { +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry to reserve\n"); +#endif + return NULL; + } + GNUNET_STATISTICS_update (h->stats, + gettext_noop ("# RESERVE requests executed"), 1, + GNUNET_NO); + rm = (struct ReserveMessage *) &qe[1]; + rm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE); + rm->header.size = htons (sizeof (struct ReserveMessage)); + rm->entries = htonl (entries); + rm->amount = GNUNET_htonll (amount); + process_queue (h); + return qe; +} + + +/** + * Signal that all of the data for which a reservation was made has + * been stored and that whatever excess space might have been reserved + * can now be released. + * + * @param h handle to the datastore + * @param rid reservation ID (value of "success" in original continuation + * from the "reserve" function). + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel; note that even if NULL is returned, the callback will be invoked + * (or rather, will already have been invoked) + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_release_reserve (struct GNUNET_DATASTORE_Handle *h, + uint32_t rid, unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_DATASTORE_QueueEntry *qe; + struct ReleaseReserveMessage *rrm; + union QueueContext qc; + + if (cont == NULL) + cont = &drop_status_cont; +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to release reserve %d\n", rid); +#endif + qc.sc.cont = cont; + qc.sc.cont_cls = cont_cls; + qe = make_queue_entry (h, sizeof (struct ReleaseReserveMessage), + queue_priority, max_queue_size, timeout, + &process_status_message, &qc); + if (qe == NULL) + { +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Could not create queue entry to release reserve\n"); +#endif + return NULL; + } + GNUNET_STATISTICS_update (h->stats, + gettext_noop + ("# RELEASE RESERVE requests executed"), 1, + GNUNET_NO); + rrm = (struct ReleaseReserveMessage *) &qe[1]; + rrm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE); + rrm->header.size = htons (sizeof (struct ReleaseReserveMessage)); + rrm->rid = htonl (rid); + process_queue (h); + return qe; +} + + +/** + * Update a value in the datastore. + * + * @param h handle to the datastore + * @param uid identifier for the value + * @param priority how much to increase the priority of the value + * @param expiration new expiration value should be MAX of existing and this argument + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel; note that even if NULL is returned, the callback will be invoked + * (or rather, will already have been invoked) + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h, uint64_t uid, + uint32_t priority, + struct GNUNET_TIME_Absolute expiration, + unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_DATASTORE_QueueEntry *qe; + struct UpdateMessage *um; + union QueueContext qc; + + if (cont == NULL) + cont = &drop_status_cont; +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Asked to update entry %llu raising priority by %u and expiration to %llu\n", + uid, (unsigned int) priority, (unsigned long long) expiration.abs_value); +#endif + qc.sc.cont = cont; + qc.sc.cont_cls = cont_cls; + qe = make_queue_entry (h, sizeof (struct UpdateMessage), queue_priority, + max_queue_size, timeout, &process_status_message, &qc); + if (qe == NULL) + { +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for UPDATE\n"); +#endif + return NULL; + } + GNUNET_STATISTICS_update (h->stats, + gettext_noop ("# UPDATE requests executed"), 1, + GNUNET_NO); + um = (struct UpdateMessage *) &qe[1]; + um->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE); + um->header.size = htons (sizeof (struct UpdateMessage)); + um->priority = htonl (priority); + um->expiration = GNUNET_TIME_absolute_hton (expiration); + um->uid = GNUNET_htonll (uid); + process_queue (h); + return qe; +} + + +/** + * Explicitly remove some content from the database. + * The "cont"inuation will be called with status + * "GNUNET_OK" if content was removed, "GNUNET_NO" + * if no matching entry was found and "GNUNET_SYSERR" + * on all other types of errors. + * + * @param h handle to the datastore + * @param key key for the value + * @param size number of bytes in data + * @param data content stored + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel; note that even if NULL is returned, the callback will be invoked + * (or rather, will already have been invoked) + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h, + const GNUNET_HashCode * key, size_t size, + const void *data, unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_DATASTORE_QueueEntry *qe; + struct DataMessage *dm; + size_t msize; + union QueueContext qc; + + if (cont == NULL) + cont = &drop_status_cont; +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to remove %u bytes under key `%s'\n", + size, GNUNET_h2s (key)); +#endif + qc.sc.cont = cont; + qc.sc.cont_cls = cont_cls; + msize = sizeof (struct DataMessage) + size; + GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); + qe = make_queue_entry (h, msize, queue_priority, max_queue_size, timeout, + &process_status_message, &qc); + if (qe == NULL) + { +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for REMOVE\n"); +#endif + return NULL; + } + GNUNET_STATISTICS_update (h->stats, + gettext_noop ("# REMOVE requests executed"), 1, + GNUNET_NO); + dm = (struct DataMessage *) &qe[1]; + dm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE); + dm->header.size = htons (msize); + dm->rid = htonl (0); + dm->size = htonl (size); + dm->type = htonl (0); + dm->priority = htonl (0); + dm->anonymity = htonl (0); + dm->uid = GNUNET_htonll (0); + dm->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_ZERO_ABS); + dm->key = *key; + memcpy (&dm[1], data, size); + process_queue (h); + return qe; +} + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +process_result_message (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_DATASTORE_Handle *h = cls; + struct GNUNET_DATASTORE_QueueEntry *qe; + struct ResultContext rc; + const struct DataMessage *dm; + int was_transmitted; + + if (msg == NULL) + { + qe = h->queue_head; + GNUNET_assert (NULL != qe); + rc = qe->qc.rc; + was_transmitted = qe->was_transmitted; + free_queue_entry (qe); + if (was_transmitted == GNUNET_YES) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Failed to receive response from database.\n")); + do_disconnect (h); + } + else + { + process_queue (h); + } + if (rc.proc != NULL) + rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, + 0); + return; + } + if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END) + { + GNUNET_break (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)); + qe = h->queue_head; + rc = qe->qc.rc; + GNUNET_assert (GNUNET_YES == qe->was_transmitted); + free_queue_entry (qe); +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received end of result set, new queue size is %u\n", h->queue_size); +#endif + h->retry_time.rel_value = 0; + h->result_count = 0; + process_queue (h); + if (rc.proc != NULL) + rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, + 0); + return; + } + qe = h->queue_head; + GNUNET_assert (NULL != qe); + rc = qe->qc.rc; + if (GNUNET_YES != qe->was_transmitted) + { + GNUNET_break (0); + free_queue_entry (qe); + h->retry_time = GNUNET_TIME_UNIT_ZERO; + do_disconnect (h); + if (rc.proc != NULL) + rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, + 0); + return; + } + if ((ntohs (msg->size) < sizeof (struct DataMessage)) || + (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DATASTORE_DATA) || + (ntohs (msg->size) != + sizeof (struct DataMessage) + + ntohl (((const struct DataMessage *) msg)->size))) + { + GNUNET_break (0); + free_queue_entry (qe); + h->retry_time = GNUNET_TIME_UNIT_ZERO; + do_disconnect (h); + if (rc.proc != NULL) + rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, + 0); + return; + } + GNUNET_STATISTICS_update (h->stats, gettext_noop ("# Results received"), 1, + GNUNET_NO); + dm = (const struct DataMessage *) msg; +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received result %llu with type %u and size %u with key %s\n", + (unsigned long long) GNUNET_ntohll (dm->uid), ntohl (dm->type), + ntohl (dm->size), GNUNET_h2s (&dm->key)); +#endif + free_queue_entry (qe); + h->retry_time.rel_value = 0; + process_queue (h); + if (rc.proc != NULL) + rc.proc (rc.proc_cls, &dm->key, ntohl (dm->size), &dm[1], ntohl (dm->type), + ntohl (dm->priority), ntohl (dm->anonymity), + GNUNET_TIME_absolute_ntoh (dm->expiration), + GNUNET_ntohll (dm->uid)); +} + + +/** + * Get a random value from the datastore for content replication. + * Returns a single, random value among those with the highest + * replication score, lowering positive replication scores by one for + * the chosen value (if only content with a replication score exists, + * a random value is returned and replication scores are not changed). + * + * @param h handle to the datastore + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param proc function to call on a random value; it + * will be called once with a value (if available) + * and always once with a value of NULL. + * @param proc_cls closure for proc + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_get_for_replication (struct GNUNET_DATASTORE_Handle *h, + unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_DatumProcessor proc, + void *proc_cls) +{ + struct GNUNET_DATASTORE_QueueEntry *qe; + struct GNUNET_MessageHeader *m; + union QueueContext qc; + + GNUNET_assert (NULL != proc); +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to get replication entry in %llu ms\n", + (unsigned long long) timeout.rel_value); +#endif + qc.rc.proc = proc; + qc.rc.proc_cls = proc_cls; + qe = make_queue_entry (h, sizeof (struct GNUNET_MessageHeader), + queue_priority, max_queue_size, timeout, + &process_result_message, &qc); + if (qe == NULL) + { +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Could not create queue entry for GET REPLICATION\n"); +#endif + return NULL; + } + GNUNET_STATISTICS_update (h->stats, + gettext_noop + ("# GET REPLICATION requests executed"), 1, + GNUNET_NO); + m = (struct GNUNET_MessageHeader *) &qe[1]; + m->type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_GET_REPLICATION); + m->size = htons (sizeof (struct GNUNET_MessageHeader)); + process_queue (h); + return qe; +} + + +/** + * Get a single zero-anonymity value from the datastore. + * + * @param h handle to the datastore + * @param offset offset of the result (modulo num-results); set to + * a random 64-bit value initially; then increment by + * one each time; detect that all results have been found by uid + * being again the first uid ever returned. + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param type allowed type for the operation (never zero) + * @param proc function to call on a random value; it + * will be called once with a value (if available) + * or with NULL if none value exists. + * @param proc_cls closure for proc + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h, + uint64_t offset, + unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + enum GNUNET_BLOCK_Type type, + GNUNET_DATASTORE_DatumProcessor proc, + void *proc_cls) +{ + struct GNUNET_DATASTORE_QueueEntry *qe; + struct GetZeroAnonymityMessage *m; + union QueueContext qc; + + GNUNET_assert (NULL != proc); + GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY); +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Asked to get %llu-th zero-anonymity entry of type %d in %llu ms\n", + (unsigned long long) offset, type, + (unsigned long long) timeout.rel_value); +#endif + qc.rc.proc = proc; + qc.rc.proc_cls = proc_cls; + qe = make_queue_entry (h, sizeof (struct GetZeroAnonymityMessage), + queue_priority, max_queue_size, timeout, + &process_result_message, &qc); + if (qe == NULL) + { +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Could not create queue entry for zero-anonymity procation\n"); +#endif + return NULL; + } + GNUNET_STATISTICS_update (h->stats, + gettext_noop + ("# GET ZERO ANONYMITY requests executed"), 1, + GNUNET_NO); + m = (struct GetZeroAnonymityMessage *) &qe[1]; + m->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY); + m->header.size = htons (sizeof (struct GetZeroAnonymityMessage)); + m->type = htonl ((uint32_t) type); + m->offset = GNUNET_htonll (offset); + process_queue (h); + return qe; +} + + +/** + * Get a result for a particular key from the datastore. The processor + * will only be called once. + * + * @param h handle to the datastore + * @param offset offset of the result (modulo num-results); set to + * a random 64-bit value initially; then increment by + * one each time; detect that all results have been found by uid + * being again the first uid ever returned. + * @param key maybe NULL (to match all entries) + * @param type desired type, 0 for any + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param proc function to call on each matching value; + * will be called once with a NULL value at the end + * @param proc_cls closure for proc + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h, uint64_t offset, + const GNUNET_HashCode * key, + enum GNUNET_BLOCK_Type type, + unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_DatumProcessor proc, void *proc_cls) +{ + struct GNUNET_DATASTORE_QueueEntry *qe; + struct GetMessage *gm; + union QueueContext qc; + + GNUNET_assert (NULL != proc); +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Asked to look for data of type %u under key `%s'\n", + (unsigned int) type, GNUNET_h2s (key)); +#endif + qc.rc.proc = proc; + qc.rc.proc_cls = proc_cls; + qe = make_queue_entry (h, sizeof (struct GetMessage), queue_priority, + max_queue_size, timeout, &process_result_message, &qc); + if (qe == NULL) + { +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not queue request for `%s'\n", + GNUNET_h2s (key)); +#endif + return NULL; + } + GNUNET_STATISTICS_update (h->stats, gettext_noop ("# GET requests executed"), + 1, GNUNET_NO); + gm = (struct GetMessage *) &qe[1]; + gm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_GET); + gm->type = htonl (type); + gm->offset = GNUNET_htonll (offset); + if (key != NULL) + { + gm->header.size = htons (sizeof (struct GetMessage)); + gm->key = *key; + } + else + { + gm->header.size = + htons (sizeof (struct GetMessage) - sizeof (GNUNET_HashCode)); + } + process_queue (h); + return qe; +} + + +/** + * Cancel a datastore operation. The final callback from the + * operation must not have been done yet. + * + * @param qe operation to cancel + */ +void +GNUNET_DATASTORE_cancel (struct GNUNET_DATASTORE_QueueEntry *qe) +{ + struct GNUNET_DATASTORE_Handle *h; + + GNUNET_assert (GNUNET_SYSERR != qe->was_transmitted); + h = qe->h; +#if DEBUG_DATASTORE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Pending DATASTORE request %p cancelled (%d, %d)\n", qe, + qe->was_transmitted, h->queue_head == qe); +#endif + if (GNUNET_YES == qe->was_transmitted) + { + free_queue_entry (qe); + h->skip_next_messages++; + return; + } + free_queue_entry (qe); + process_queue (h); +} + + +/* end of datastore_api.c */ diff --git a/src/datastore/gnunet-service-datastore.c b/src/datastore/gnunet-service-datastore.c new file mode 100644 index 0000000..1d7e8cd --- /dev/null +++ b/src/datastore/gnunet-service-datastore.c @@ -0,0 +1,1693 @@ +/* + This file is part of GNUnet + (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datastore/gnunet-service-datastore.c + * @brief Management for the datastore for files stored on a GNUnet node + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_statistics_service.h" +#include "gnunet_datastore_plugin.h" +#include "datastore.h" + +/** + * How many messages do we queue at most per client? + */ +#define MAX_PENDING 1024 + +/** + * How long are we at most keeping "expired" content + * past the expiration date in the database? + */ +#define MAX_EXPIRE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +/** + * How fast are we allowed to query the database for deleting + * expired content? (1 item per second). + */ +#define MIN_EXPIRE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * Name under which we store current space consumption. + */ +static char *quota_stat_name; + +/** + * After how many payload-changing operations + * do we sync our statistics? + */ +#define MAX_STAT_SYNC_LAG 50 + + +/** + * Our datastore plugin. + */ +struct DatastorePlugin +{ + + /** + * API of the transport as returned by the plugin's + * initialization function. + */ + struct GNUNET_DATASTORE_PluginFunctions *api; + + /** + * Short name for the plugin (i.e. "sqlite"). + */ + char *short_name; + + /** + * Name of the library (i.e. "gnunet_plugin_datastore_sqlite"). + */ + char *lib_name; + + /** + * Environment this transport service is using + * for this plugin. + */ + struct GNUNET_DATASTORE_PluginEnvironment env; + +}; + + +/** + * Linked list of active reservations. + */ +struct ReservationList +{ + + /** + * This is a linked list. + */ + struct ReservationList *next; + + /** + * Client that made the reservation. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Number of bytes (still) reserved. + */ + uint64_t amount; + + /** + * Number of items (still) reserved. + */ + uint64_t entries; + + /** + * Reservation identifier. + */ + int32_t rid; + +}; + + + +/** + * Our datastore plugin (NULL if not available). + */ +static struct DatastorePlugin *plugin; + +/** + * Linked list of space reservations made by clients. + */ +static struct ReservationList *reservations; + +/** + * Bloomfilter to quickly tell if we don't have the content. + */ +static struct GNUNET_CONTAINER_BloomFilter *filter; + +/** + * How much space are we allowed to use? + */ +static unsigned long long quota; + +/** + * Should the database be dropped on exit? + */ +static int do_drop; + +/** + * Name of our plugin. + */ +static char *plugin_name; + +/** + * How much space are we using for the cache? (space available for + * insertions that will be instantly reclaimed by discarding less + * important content --- or possibly whatever we just inserted into + * the "cache"). + */ +static unsigned long long cache_size; + +/** + * How much space have we currently reserved? + */ +static unsigned long long reserved; + +/** + * How much data are we currently storing + * in the database? + */ +static unsigned long long payload; + +/** + * Number of updates that were made to the + * payload value since we last synchronized + * it with the statistics service. + */ +static unsigned int lastSync; + +/** + * Did we get an answer from statistics? + */ +static int stats_worked; + +/** + * Identity of the task that is used to delete + * expired content. + */ +static GNUNET_SCHEDULER_TaskIdentifier expired_kill_task; + +/** + * Our configuration. + */ +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Minimum time that content should have to not be discarded instantly + * (time stamp of any content that we've been discarding recently to + * stay below the quota). FOREVER if we had to expire content with + * non-zero priority. + */ +static struct GNUNET_TIME_Absolute min_expiration; + +/** + * Handle for reporting statistics. + */ +static struct GNUNET_STATISTICS_Handle *stats; + + +/** + * Synchronize our utilization statistics with the + * statistics service. + */ +static void +sync_stats () +{ + GNUNET_STATISTICS_set (stats, quota_stat_name, payload, GNUNET_YES); + GNUNET_STATISTICS_set (stats, "# utilization by current datastore", payload, GNUNET_NO); + lastSync = 0; +} + + + +/** + * Context for transmitting replies to clients. + */ +struct TransmitCallbackContext +{ + + /** + * We keep these in a doubly-linked list (for cleanup). + */ + struct TransmitCallbackContext *next; + + /** + * We keep these in a doubly-linked list (for cleanup). + */ + struct TransmitCallbackContext *prev; + + /** + * The message that we're asked to transmit. + */ + struct GNUNET_MessageHeader *msg; + + /** + * Handle for the transmission request. + */ + struct GNUNET_CONNECTION_TransmitHandle *th; + + /** + * Client that we are transmitting to. + */ + struct GNUNET_SERVER_Client *client; + +}; + + +/** + * Head of the doubly-linked list (for cleanup). + */ +static struct TransmitCallbackContext *tcc_head; + +/** + * Tail of the doubly-linked list (for cleanup). + */ +static struct TransmitCallbackContext *tcc_tail; + +/** + * Have we already cleaned up the TCCs and are hence no longer + * willing (or able) to transmit anything to anyone? + */ +static int cleaning_done; + +/** + * Handle for pending get request. + */ +static struct GNUNET_STATISTICS_GetHandle *stat_get; + + +/** + * Task that is used to remove expired entries from + * the datastore. This task will schedule itself + * again automatically to always delete all expired + * content quickly. + * + * @param cls not used + * @param tc task context + */ +static void +delete_expired (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Iterate over the expired items stored in the datastore. + * Delete all expired items; once we have processed all + * expired items, re-schedule the "delete_expired" task. + * + * @param cls not used + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + * + * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue + * (continue on call to "next", of course), + * GNUNET_NO to delete the item and continue (if supported) + */ +static int +expired_processor (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, uint64_t uid) +{ + struct GNUNET_TIME_Absolute now; + + if (key == NULL) + { + expired_kill_task = + GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY, + GNUNET_SCHEDULER_PRIORITY_IDLE, + &delete_expired, NULL); + return GNUNET_SYSERR; + } + now = GNUNET_TIME_absolute_get (); + if (expiration.abs_value > now.abs_value) + { + /* finished processing */ + expired_kill_task = + GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY, + GNUNET_SCHEDULER_PRIORITY_IDLE, + &delete_expired, NULL); + return GNUNET_SYSERR; + } +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Deleting content `%s' of type %u that expired %llu ms ago\n", + GNUNET_h2s (key), type, + (unsigned long long) (now.abs_value - expiration.abs_value)); +#endif + min_expiration = now; + GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes expired"), size, + GNUNET_YES); + GNUNET_CONTAINER_bloomfilter_remove (filter, key); + expired_kill_task = + GNUNET_SCHEDULER_add_delayed_with_priority (MIN_EXPIRE_DELAY, + GNUNET_SCHEDULER_PRIORITY_IDLE, + &delete_expired, NULL); + return GNUNET_NO; +} + + +/** + * Task that is used to remove expired entries from + * the datastore. This task will schedule itself + * again automatically to always delete all expired + * content quickly. + * + * @param cls not used + * @param tc task context + */ +static void +delete_expired (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + expired_kill_task = GNUNET_SCHEDULER_NO_TASK; + plugin->api->get_expiration (plugin->api->cls, &expired_processor, NULL); +} + + +/** + * An iterator over a set of items stored in the datastore + * that deletes until we're happy with respect to our quota. + * + * @param cls closure + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + * + * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue + * (continue on call to "next", of course), + * GNUNET_NO to delete the item and continue (if supported) + */ +static int +quota_processor (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, uint64_t uid) +{ + unsigned long long *need = cls; + + if (NULL == key) + return GNUNET_SYSERR; +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Deleting %llu bytes of low-priority (%u) content `%s' of type %u at %llu ms prior to expiration (still trying to free another %llu bytes)\n", + (unsigned long long) (size + GNUNET_DATASTORE_ENTRY_OVERHEAD), + (unsigned int) priority, + GNUNET_h2s (key), type, + (unsigned long long) GNUNET_TIME_absolute_get_remaining (expiration).rel_value, + *need); +#endif + if (size + GNUNET_DATASTORE_ENTRY_OVERHEAD > *need) + *need = 0; + else + *need -= size + GNUNET_DATASTORE_ENTRY_OVERHEAD; + if (priority > 0) + min_expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + else + min_expiration = expiration; + GNUNET_STATISTICS_update (stats, + gettext_noop ("# bytes purged (low-priority)"), + size, GNUNET_YES); + GNUNET_CONTAINER_bloomfilter_remove (filter, key); + return GNUNET_NO; +} + + +/** + * Manage available disk space by running tasks + * that will discard content if necessary. This + * function will be run whenever a request for + * "need" bytes of storage could only be satisfied + * by eating into the "cache" (and we want our cache + * space back). + * + * @param need number of bytes of content that were + * placed into the "cache" (and hence the + * number of bytes that should be removed). + */ +static void +manage_space (unsigned long long need) +{ + unsigned long long last; + +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asked to free up %llu bytes of cache space\n", need); +#endif + last = 0; + while ((need > 0) && (last != need)) + { + last = need; + plugin->api->get_expiration (plugin->api->cls, "a_processor, &need); + } +} + + +/** + * Function called to notify a client about the socket + * begin ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_callback (void *cls, size_t size, void *buf) +{ + struct TransmitCallbackContext *tcc = cls; + size_t msize; + + tcc->th = NULL; + GNUNET_CONTAINER_DLL_remove (tcc_head, tcc_tail, tcc); + msize = ntohs (tcc->msg->size); + if (size == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Transmission to client failed!\n")); + GNUNET_SERVER_receive_done (tcc->client, GNUNET_SYSERR); + GNUNET_SERVER_client_drop (tcc->client); + GNUNET_free (tcc->msg); + GNUNET_free (tcc); + return 0; + } + GNUNET_assert (size >= msize); + memcpy (buf, tcc->msg, msize); + GNUNET_SERVER_receive_done (tcc->client, GNUNET_OK); + GNUNET_SERVER_client_drop (tcc->client); + GNUNET_free (tcc->msg); + GNUNET_free (tcc); + return msize; +} + + +/** + * Transmit the given message to the client. + * + * @param client target of the message + * @param msg message to transmit, will be freed! + */ +static void +transmit (struct GNUNET_SERVER_Client *client, struct GNUNET_MessageHeader *msg) +{ + struct TransmitCallbackContext *tcc; + + if (GNUNET_YES == cleaning_done) + { +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Shutdown in progress, aborting transmission.\n"); +#endif + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + GNUNET_free (msg); + return; + } + tcc = GNUNET_malloc (sizeof (struct TransmitCallbackContext)); + tcc->msg = msg; + tcc->client = client; + if (NULL == + (tcc->th = + GNUNET_SERVER_notify_transmit_ready (client, ntohs (msg->size), + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_callback, tcc))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + GNUNET_free (msg); + GNUNET_free (tcc); + return; + } + GNUNET_SERVER_client_keep (client); + GNUNET_CONTAINER_DLL_insert (tcc_head, tcc_tail, tcc); +} + + +/** + * Transmit a status code to the client. + * + * @param client receiver of the response + * @param code status code + * @param msg optional error message (can be NULL) + */ +static void +transmit_status (struct GNUNET_SERVER_Client *client, int code, const char *msg) +{ + struct StatusMessage *sm; + size_t slen; + +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting `%s' message with value %d and message `%s'\n", + "STATUS", code, msg != NULL ? msg : "(none)"); +#endif + slen = (msg == NULL) ? 0 : strlen (msg) + 1; + sm = GNUNET_malloc (sizeof (struct StatusMessage) + slen); + sm->header.size = htons (sizeof (struct StatusMessage) + slen); + sm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_STATUS); + sm->status = htonl (code); + sm->min_expiration = GNUNET_TIME_absolute_hton (min_expiration); + if (slen > 0) + memcpy (&sm[1], msg, slen); + transmit (client, &sm->header); +} + + + +/** + * Function that will transmit the given datastore entry + * to the client. + * + * @param cls closure, pointer to the client (of type GNUNET_SERVER_Client). + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + * + * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue, + * GNUNET_NO to delete the item and continue (if supported) + */ +static int +transmit_item (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct GNUNET_SERVER_Client *client = cls; + struct GNUNET_MessageHeader *end; + struct DataMessage *dm; + + if (key == NULL) + { + /* transmit 'DATA_END' */ +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' message\n", + "DATA_END"); +#endif + end = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader)); + end->size = htons (sizeof (struct GNUNET_MessageHeader)); + end->type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END); + transmit (client, end); + GNUNET_SERVER_client_drop (client); + return GNUNET_OK; + } + GNUNET_assert (sizeof (struct DataMessage) + size < + GNUNET_SERVER_MAX_MESSAGE_SIZE); + dm = GNUNET_malloc (sizeof (struct DataMessage) + size); + dm->header.size = htons (sizeof (struct DataMessage) + size); + dm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_DATA); + dm->rid = htonl (0); + dm->size = htonl (size); + dm->type = htonl (type); + dm->priority = htonl (priority); + dm->anonymity = htonl (anonymity); + dm->replication = htonl (0); + dm->reserved = htonl (0); + dm->expiration = GNUNET_TIME_absolute_hton (expiration); + dm->uid = GNUNET_htonll (uid); + dm->key = *key; + memcpy (&dm[1], data, size); +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting `%s' message for `%s' of type %u with expiration %llu (now: %llu)\n", + "DATA", GNUNET_h2s (key), type, + (unsigned long long) expiration.abs_value, + (unsigned long long) GNUNET_TIME_absolute_get ().abs_value); +#endif + GNUNET_STATISTICS_update (stats, gettext_noop ("# results found"), 1, + GNUNET_NO); + transmit (client, &dm->header); + GNUNET_SERVER_client_drop (client); + return GNUNET_OK; +} + + +/** + * Handle RESERVE-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_reserve (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + /** + * Static counter to produce reservation identifiers. + */ + static int reservation_gen; + + const struct ReserveMessage *msg = (const struct ReserveMessage *) message; + struct ReservationList *e; + unsigned long long used; + unsigned long long req; + uint64_t amount; + uint32_t entries; + +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", "RESERVE"); +#endif + amount = GNUNET_ntohll (msg->amount); + entries = ntohl (msg->entries); + used = payload + reserved; + req = + amount + ((unsigned long long) GNUNET_DATASTORE_ENTRY_OVERHEAD) * entries; + if (used + req > quota) + { + if (quota < used) + used = quota; /* cheat a bit for error message (to avoid negative numbers) */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Insufficient space (%llu bytes are available) to satisfy `%s' request for %llu bytes\n"), + quota - used, "RESERVE", req); + if (cache_size < req) + { + /* TODO: document this in the FAQ; essentially, if this + * message happens, the insertion request could be blocked + * by less-important content from migration because it is + * larger than 1/8th of the overall available space, and + * we only reserve 1/8th for "fresh" insertions */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("The requested amount (%llu bytes) is larger than the cache size (%llu bytes)\n"), + req, cache_size); + transmit_status (client, 0, + gettext_noop + ("Insufficient space to satisfy request and " + "requested amount is larger than cache size")); + } + else + { + transmit_status (client, 0, + gettext_noop ("Insufficient space to satisfy request")); + } + return; + } + reserved += req; + GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved, + GNUNET_NO); + e = GNUNET_malloc (sizeof (struct ReservationList)); + e->next = reservations; + reservations = e; + e->client = client; + e->amount = amount; + e->entries = entries; + e->rid = ++reservation_gen; + if (reservation_gen < 0) + reservation_gen = 0; /* wrap around */ + transmit_status (client, e->rid, NULL); +} + + +/** + * Handle RELEASE_RESERVE-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_release_reserve (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct ReleaseReserveMessage *msg = + (const struct ReleaseReserveMessage *) message; + struct ReservationList *pos; + struct ReservationList *prev; + struct ReservationList *next; + int rid = ntohl (msg->rid); + unsigned long long rem; + +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", + "RELEASE_RESERVE"); +#endif + next = reservations; + prev = NULL; + while (NULL != (pos = next)) + { + next = pos->next; + if (rid == pos->rid) + { + if (prev == NULL) + reservations = next; + else + prev->next = next; + rem = + pos->amount + + ((unsigned long long) GNUNET_DATASTORE_ENTRY_OVERHEAD) * pos->entries; + GNUNET_assert (reserved >= rem); + reserved -= rem; + GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved, + GNUNET_NO); +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Returning %llu remaining reserved bytes to storage pool\n", + rem); +#endif + GNUNET_free (pos); + transmit_status (client, GNUNET_OK, NULL); + return; + } + prev = pos; + } + GNUNET_break (0); + transmit_status (client, GNUNET_SYSERR, + gettext_noop ("Could not find matching reservation")); +} + + +/** + * Check that the given message is a valid data message. + * + * @return NULL if the message is not well-formed, otherwise the message + */ +static const struct DataMessage * +check_data (const struct GNUNET_MessageHeader *message) +{ + uint16_t size; + uint32_t dsize; + const struct DataMessage *dm; + + size = ntohs (message->size); + if (size < sizeof (struct DataMessage)) + { + GNUNET_break (0); + return NULL; + } + dm = (const struct DataMessage *) message; + dsize = ntohl (dm->size); + if (size != dsize + sizeof (struct DataMessage)) + { + GNUNET_break (0); + return NULL; + } + return dm; +} + + +/** + * Context for a PUT request used to see if the content is + * already present. + */ +struct PutContext +{ + /** + * Client to notify on completion. + */ + struct GNUNET_SERVER_Client *client; + +#if ! HAVE_UNALIGNED_64_ACCESS + void *reserved; +#endif + + /* followed by the 'struct DataMessage' */ +}; + + +/** + * Actually put the data message. + * + * @param client sender of the message + * @param dm message with the data to store + */ +static void +execute_put (struct GNUNET_SERVER_Client *client, const struct DataMessage *dm) +{ + uint32_t size; + char *msg; + int ret; + + size = ntohl (dm->size); + msg = NULL; + ret = + plugin->api->put (plugin->api->cls, &dm->key, size, &dm[1], + ntohl (dm->type), ntohl (dm->priority), + ntohl (dm->anonymity), ntohl (dm->replication), + GNUNET_TIME_absolute_ntoh (dm->expiration), &msg); + if (GNUNET_OK == ret) + { + GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes stored"), size, + GNUNET_YES); + GNUNET_CONTAINER_bloomfilter_add (filter, &dm->key); +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully stored %u bytes of type %u under key `%s'\n", + size, ntohl (dm->type), GNUNET_h2s (&dm->key)); +#endif + } + transmit_status (client, ret, msg); + GNUNET_free_non_null (msg); + if (quota - reserved - cache_size < payload) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Need %llu bytes more space (%llu allowed, using %llu)\n"), + (unsigned long long) size + GNUNET_DATASTORE_ENTRY_OVERHEAD, + (unsigned long long) (quota - reserved - cache_size), + (unsigned long long) payload); + manage_space (size + GNUNET_DATASTORE_ENTRY_OVERHEAD); + } +} + + +/** + * Function that will check if the given datastore entry + * matches the put and if none match executes the put. + * + * @param cls closure, pointer to the client (of type 'struct PutContext'). + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + * + * @return GNUNET_OK usually + * GNUNET_NO to delete the item + */ +static int +check_present (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct PutContext *pc = cls; + const struct DataMessage *dm; + + dm = (const struct DataMessage *) &pc[1]; + if (key == NULL) + { + execute_put (pc->client, dm); + GNUNET_SERVER_client_drop (pc->client); + GNUNET_free (pc); + return GNUNET_OK; + } + if ((GNUNET_BLOCK_TYPE_FS_DBLOCK == type) || + (GNUNET_BLOCK_TYPE_FS_IBLOCK == type) || ((size == ntohl (dm->size)) && + (0 == + memcmp (&dm[1], data, size)))) + { +#if DEBUG_MYSQL + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Result already present in datastore\n"); +#endif + /* FIXME: change API to allow increasing 'replication' counter */ + if ((ntohl (dm->priority) > 0) || + (GNUNET_TIME_absolute_ntoh (dm->expiration).abs_value > + expiration.abs_value)) + plugin->api->update (plugin->api->cls, uid, + (int32_t) ntohl (dm->priority), + GNUNET_TIME_absolute_ntoh (dm->expiration), NULL); + transmit_status (pc->client, GNUNET_NO, NULL); + GNUNET_SERVER_client_drop (pc->client); + GNUNET_free (pc); + } + else + { + execute_put (pc->client, dm); + GNUNET_SERVER_client_drop (pc->client); + GNUNET_free (pc); + } + return GNUNET_OK; +} + + +/** + * Handle PUT-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_put (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct DataMessage *dm = check_data (message); + int rid; + struct ReservationList *pos; + struct PutContext *pc; + GNUNET_HashCode vhash; + uint32_t size; + + if ((dm == NULL) || (ntohl (dm->type) == 0)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Processing `%s' request for `%s' of type %u\n", "PUT", + GNUNET_h2s (&dm->key), ntohl (dm->type)); +#endif + rid = ntohl (dm->rid); + size = ntohl (dm->size); + if (rid > 0) + { + pos = reservations; + while ((NULL != pos) && (rid != pos->rid)) + pos = pos->next; + GNUNET_break (pos != NULL); + if (NULL != pos) + { + GNUNET_break (pos->entries > 0); + GNUNET_break (pos->amount >= size); + pos->entries--; + pos->amount -= size; + reserved -= (size + GNUNET_DATASTORE_ENTRY_OVERHEAD); + GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved, + GNUNET_NO); + } + } + if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (filter, &dm->key)) + { + GNUNET_CRYPTO_hash (&dm[1], size, &vhash); + pc = GNUNET_malloc (sizeof (struct PutContext) + size + + sizeof (struct DataMessage)); + pc->client = client; + GNUNET_SERVER_client_keep (client); + memcpy (&pc[1], dm, size + sizeof (struct DataMessage)); + plugin->api->get_key (plugin->api->cls, 0, &dm->key, &vhash, + ntohl (dm->type), &check_present, pc); + return; + } + execute_put (client, dm); +} + + +/** + * Handle GET-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_get (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GetMessage *msg; + uint16_t size; + + size = ntohs (message->size); + if ((size != sizeof (struct GetMessage)) && + (size != sizeof (struct GetMessage) - sizeof (GNUNET_HashCode))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msg = (const struct GetMessage *) message; +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Processing `%s' request for `%s' of type %u\n", "GET", + GNUNET_h2s (&msg->key), ntohl (msg->type)); +#endif + GNUNET_STATISTICS_update (stats, gettext_noop ("# GET requests received"), 1, + GNUNET_NO); + GNUNET_SERVER_client_keep (client); + if ((size == sizeof (struct GetMessage)) && + (GNUNET_YES != GNUNET_CONTAINER_bloomfilter_test (filter, &msg->key))) + { + /* don't bother database... */ +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Empty result set for `%s' request for `%s' (bloomfilter).\n", + "GET", GNUNET_h2s (&msg->key)); +#endif + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# requests filtered by bloomfilter"), 1, + GNUNET_NO); + transmit_item (client, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, + 0); + return; + } + plugin->api->get_key (plugin->api->cls, GNUNET_ntohll (msg->offset), + ((size == + sizeof (struct GetMessage)) ? &msg->key : NULL), NULL, + ntohl (msg->type), &transmit_item, client); +} + + +/** + * Handle UPDATE-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_update (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct UpdateMessage *msg; + int ret; + char *emsg; + + GNUNET_STATISTICS_update (stats, gettext_noop ("# UPDATE requests received"), + 1, GNUNET_NO); + msg = (const struct UpdateMessage *) message; + emsg = NULL; +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request for %llu\n", + "UPDATE", (unsigned long long) GNUNET_ntohll (msg->uid)); +#endif + ret = + plugin->api->update (plugin->api->cls, GNUNET_ntohll (msg->uid), + (int32_t) ntohl (msg->priority), + GNUNET_TIME_absolute_ntoh (msg->expiration), &emsg); + transmit_status (client, ret, emsg); + GNUNET_free_non_null (emsg); +} + + +/** + * Handle GET_REPLICATION-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_get_replication (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", + "GET_REPLICATION"); +#endif + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# GET REPLICATION requests received"), 1, + GNUNET_NO); + GNUNET_SERVER_client_keep (client); + plugin->api->get_replication (plugin->api->cls, &transmit_item, client); +} + + +/** + * Handle GET_ZERO_ANONYMITY-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_get_zero_anonymity (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GetZeroAnonymityMessage *msg = + (const struct GetZeroAnonymityMessage *) message; + enum GNUNET_BLOCK_Type type; + + type = (enum GNUNET_BLOCK_Type) ntohl (msg->type); + if (type == GNUNET_BLOCK_TYPE_ANY) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", + "GET_ZERO_ANONYMITY"); +#endif + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# GET ZERO ANONYMITY requests received"), 1, + GNUNET_NO); + GNUNET_SERVER_client_keep (client); + plugin->api->get_zero_anonymity (plugin->api->cls, + GNUNET_ntohll (msg->offset), type, + &transmit_item, client); +} + + +/** + * Callback function that will cause the item that is passed + * in to be deleted (by returning GNUNET_NO). + */ +static int +remove_callback (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, uint64_t uid) +{ + struct GNUNET_SERVER_Client *client = cls; + + if (key == NULL) + { +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No further matches for `%s' request.\n", "REMOVE"); +#endif + transmit_status (client, GNUNET_NO, _("Content not found")); + GNUNET_SERVER_client_drop (client); + return GNUNET_OK; /* last item */ + } +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Item %llu matches `%s' request for key `%s' and type %u.\n", + (unsigned long long) uid, "REMOVE", GNUNET_h2s (key), type); +#endif + GNUNET_STATISTICS_update (stats, + gettext_noop ("# bytes removed (explicit request)"), + size, GNUNET_YES); + GNUNET_CONTAINER_bloomfilter_remove (filter, key); + transmit_status (client, GNUNET_OK, NULL); + GNUNET_SERVER_client_drop (client); + return GNUNET_NO; +} + + +/** + * Handle REMOVE-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_remove (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct DataMessage *dm = check_data (message); + GNUNET_HashCode vhash; + + if (dm == NULL) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Processing `%s' request for `%s' of type %u\n", "REMOVE", + GNUNET_h2s (&dm->key), ntohl (dm->type)); +#endif + GNUNET_STATISTICS_update (stats, gettext_noop ("# REMOVE requests received"), + 1, GNUNET_NO); + GNUNET_SERVER_client_keep (client); + GNUNET_CRYPTO_hash (&dm[1], ntohl (dm->size), &vhash); + plugin->api->get_key (plugin->api->cls, 0, &dm->key, &vhash, + (enum GNUNET_BLOCK_Type) ntohl (dm->type), + &remove_callback, client); +} + + +/** + * Handle DROP-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_drop (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", "DROP"); +#endif + do_drop = GNUNET_YES; + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Function called by plugins to notify us about a + * change in their disk utilization. + * + * @param cls closure (NULL) + * @param delta change in disk utilization, + * 0 for "reset to empty" + */ +static void +disk_utilization_change_cb (void *cls, int delta) +{ + if ((delta < 0) && (payload < -delta)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Datastore payload inaccurate (%lld < %lld). Trying to fix.\n"), + (long long) payload, (long long) -delta); + payload = plugin->api->estimate_size (plugin->api->cls); + sync_stats (); + return; + } + payload += delta; + lastSync++; + if (lastSync >= MAX_STAT_SYNC_LAG) + sync_stats (); +} + + +/** + * Callback function to process statistic values. + * + * @param cls closure (struct Plugin*) + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +process_stat_in (void *cls, const char *subsystem, const char *name, + uint64_t value, int is_persistent) +{ + GNUNET_assert (stats_worked == GNUNET_NO); + stats_worked = GNUNET_YES; + payload += value; +#if DEBUG_SQLITE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Notification from statistics about existing payload (%llu), new payload is %llu\n", + abs_value, payload); +#endif + return GNUNET_OK; +} + + +static void +process_stat_done (void *cls, int success) +{ + struct DatastorePlugin *plugin = cls; + + stat_get = NULL; + if (stats_worked == GNUNET_NO) + payload = plugin->api->estimate_size (plugin->api->cls); +} + + +/** + * Load the datastore plugin. + */ +static struct DatastorePlugin * +load_plugin () +{ + struct DatastorePlugin *ret; + char *libname; + + ret = GNUNET_malloc (sizeof (struct DatastorePlugin)); + ret->env.cfg = cfg; + ret->env.duc = &disk_utilization_change_cb; + ret->env.cls = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datastore plugin\n"), + plugin_name); + GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", plugin_name); + ret->short_name = GNUNET_strdup (plugin_name); + ret->lib_name = libname; + ret->api = GNUNET_PLUGIN_load (libname, &ret->env); + if (ret->api == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to load datastore plugin for `%s'\n"), plugin_name); + GNUNET_free (ret->short_name); + GNUNET_free (libname); + GNUNET_free (ret); + return NULL; + } + return ret; +} + + +/** + * Function called when the service shuts + * down. Unloads our datastore plugin. + * + * @param plug plugin to unload + */ +static void +unload_plugin (struct DatastorePlugin *plug) +{ +#if DEBUG_DATASTORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Datastore service is unloading plugin...\n"); +#endif + GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api)); + GNUNET_free (plug->lib_name); + GNUNET_free (plug->short_name); + GNUNET_free (plug); + GNUNET_free (quota_stat_name); + quota_stat_name = NULL; +} + + +/** + * Final task run after shutdown. Unloads plugins and disconnects us from + * statistics. + */ +static void +unload_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (lastSync > 0) + sync_stats (); + if (GNUNET_YES == do_drop) + plugin->api->drop (plugin->api->cls); + unload_plugin (plugin); + plugin = NULL; + if (filter != NULL) + { + GNUNET_CONTAINER_bloomfilter_free (filter); + filter = NULL; + } + if (stat_get != NULL) + { + GNUNET_STATISTICS_get_cancel (stat_get); + stat_get = NULL; + } + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_YES); + stats = NULL; + } + GNUNET_free_non_null (plugin_name); + plugin_name = NULL; +} + + +/** + * Last task run during shutdown. Disconnects us from + * the transport and core. + */ +static void +cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TransmitCallbackContext *tcc; + + cleaning_done = GNUNET_YES; + while (NULL != (tcc = tcc_head)) + { + GNUNET_CONTAINER_DLL_remove (tcc_head, tcc_tail, tcc); + if (tcc->th != NULL) + { + GNUNET_CONNECTION_notify_transmit_ready_cancel (tcc->th); + GNUNET_SERVER_client_drop (tcc->client); + } + GNUNET_free (tcc->msg); + GNUNET_free (tcc); + } + if (expired_kill_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (expired_kill_task); + expired_kill_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_SCHEDULER_add_continuation (&unload_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +/** + * Function that removes all active reservations made + * by the given client and releases the space for other + * requests. + * + * @param cls closure + * @param client identification of the client + */ +static void +cleanup_reservations (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct ReservationList *pos; + struct ReservationList *prev; + struct ReservationList *next; + + if (client == NULL) + return; + prev = NULL; + pos = reservations; + while (NULL != pos) + { + next = pos->next; + if (pos->client == client) + { + if (prev == NULL) + reservations = next; + else + prev->next = next; + reserved -= pos->amount + pos->entries * GNUNET_DATASTORE_ENTRY_OVERHEAD; + GNUNET_free (pos); + } + else + { + prev = pos; + } + pos = next; + } + GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved, + GNUNET_NO); +} + + +/** + * Adds a given key to the bloomfilter 'count' times. + * + * @param cls the bloomfilter + * @param key key to add + * @param count number of times to add key + */ +static void +add_key_to_bloomfilter (void *cls, + const GNUNET_HashCode *key, + unsigned int count) +{ + struct GNUNET_CONTAINER_BloomFilter *bf = cls; + while (0 < count--) + GNUNET_CONTAINER_bloomfilter_add (bf, key); +} + + +/** + * Process datastore requests. + * + * @param cls closure + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_reserve, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE, + sizeof (struct ReserveMessage)}, + {&handle_release_reserve, NULL, + GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE, + sizeof (struct ReleaseReserveMessage)}, + {&handle_put, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_PUT, 0}, + {&handle_update, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE, + sizeof (struct UpdateMessage)}, + {&handle_get, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_GET, 0}, + {&handle_get_replication, NULL, + GNUNET_MESSAGE_TYPE_DATASTORE_GET_REPLICATION, + sizeof (struct GNUNET_MessageHeader)}, + {&handle_get_zero_anonymity, NULL, + GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY, + sizeof (struct GetZeroAnonymityMessage)}, + {&handle_remove, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE, 0}, + {&handle_drop, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_DROP, + sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} + }; + char *fn; + char *pfn; + unsigned int bf_size; + int refresh_bf; + + cfg = c; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE", + &plugin_name)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", + "DATASTORE"); + return; + } + GNUNET_asprintf ("a_stat_name, + _("# bytes used in file-sharing datastore `%s'"), + plugin_name); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_size (cfg, "DATASTORE", "QUOTA", "a)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No `%s' specified for `%s' in configuration!\n"), "QUOTA", + "DATASTORE"); + return; + } + stats = GNUNET_STATISTICS_create ("datastore", cfg); + GNUNET_STATISTICS_set (stats, gettext_noop ("# quota"), quota, GNUNET_NO); + cache_size = quota / 8; /* Or should we make this an option? */ + GNUNET_STATISTICS_set (stats, gettext_noop ("# cache size"), cache_size, + GNUNET_NO); + if (quota / (32 * 1024LL) > (1 << 31)) + bf_size = (1 << 31); /* absolute limit: ~2 GB, beyond that BF just won't help anyway */ + else + bf_size = quota / (32 * 1024LL); /* 8 bit per entry, 1 bit per 32 kb in DB */ + fn = NULL; + if ((GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "DATASTORE", "BLOOMFILTER", + &fn)) || + (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Could not use specified filename `%s' for bloomfilter.\n"), + fn != NULL ? fn : ""); + GNUNET_free_non_null (fn); + fn = NULL; + } + if (fn != NULL) + { + GNUNET_asprintf (&pfn, "%s.%s", fn, plugin_name); + if (GNUNET_YES == GNUNET_DISK_file_test (pfn)) + { + filter = GNUNET_CONTAINER_bloomfilter_load (pfn, bf_size, 5); /* approx. 3% false positives at max use */ + if (NULL == filter) + { + /* file exists but not valid, remove and try again, but refresh */ + if (0 != UNLINK (pfn)) + { + /* failed to remove, run without file */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to remove bogus bloomfilter file `%s'\n"), + pfn); + GNUNET_free (pfn); + pfn = NULL; + filter = GNUNET_CONTAINER_bloomfilter_load (NULL, bf_size, 5); /* approx. 3% false positives at max use */ + refresh_bf = GNUNET_YES; + } + else + { + /* try again after remove */ + filter = GNUNET_CONTAINER_bloomfilter_load (pfn, bf_size, 5); /* approx. 3% false positives at max use */ + refresh_bf = GNUNET_YES; + if (NULL == filter) + { + /* failed yet again, give up on using file */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to remove bogus bloomfilter file `%s'\n"), + pfn); + GNUNET_free (pfn); + pfn = NULL; + filter = GNUNET_CONTAINER_bloomfilter_load (NULL, bf_size, 5); /* approx. 3% false positives at max use */ + } + } + } + else + { + /* normal case: have an existing valid bf file, no need to refresh */ + refresh_bf = GNUNET_NO; + } + } + else + { + filter = GNUNET_CONTAINER_bloomfilter_load (pfn, bf_size, 5); /* approx. 3% false positives at max use */ + refresh_bf = GNUNET_YES; + } + GNUNET_free (pfn); + } + else + { + filter = GNUNET_CONTAINER_bloomfilter_init (NULL, bf_size, 5); /* approx. 3% false positives at max use */ + refresh_bf = GNUNET_YES; + } + GNUNET_free_non_null (fn); + if (filter == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to initialize bloomfilter.\n")); + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_YES); + stats = NULL; + } + return; + } + plugin = load_plugin (); + if (NULL == plugin) + { + GNUNET_CONTAINER_bloomfilter_free (filter); + filter = NULL; + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_YES); + stats = NULL; + } + return; + } + stat_get = + GNUNET_STATISTICS_get (stats, "datastore", quota_stat_name, + GNUNET_TIME_UNIT_SECONDS, &process_stat_done, + &process_stat_in, plugin); + GNUNET_SERVER_disconnect_notify (server, &cleanup_reservations, NULL); + GNUNET_SERVER_add_handlers (server, handlers); + if (GNUNET_YES == refresh_bf) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Rebuilding bloomfilter. Please be patient.\n")); + if (NULL != plugin->api->get_keys) + plugin->api->get_keys (plugin->api->cls, &add_key_to_bloomfilter, filter); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Plugin does not support get_keys function. Please fix!\n")); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Bloomfilter construction complete.\n")); + } + expired_kill_task = + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, + &delete_expired, NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task, + NULL); +} + + +/** + * The main function for the datastore service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + int ret; + + ret = + (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "datastore", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; + return ret; +} + + +/* end of gnunet-service-datastore.c */ diff --git a/src/datastore/perf_datastore_api.c b/src/datastore/perf_datastore_api.c new file mode 100644 index 0000000..aae152d --- /dev/null +++ b/src/datastore/perf_datastore_api.c @@ -0,0 +1,405 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2007, 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* + * @file datastore/perf_datastore_api.c + * @brief performance measurement for the datastore implementation + * @author Christian Grothoff + * + * This testcase inserts a bunch of (variable size) data and then + * deletes data until the (reported) database size drops below a given + * threshold. This is iterated 10 times, with the actual size of the + * content stored and the number of operations performed being printed + * for each iteration. The code also prints a "I" for every 40 blocks + * inserted and a "D" for every 40 blocks deleted. The deletion + * strategy uses the "random" iterator. Priorities and expiration + * dates are set using a pseudo-random value within a realistic range. + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_datastore_service.h" +#include + +#define VERBOSE GNUNET_NO + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) + +static const char *plugin_name; + +static struct GNUNET_DATASTORE_Handle *datastore; + +/** + * Target datastore size (in bytes). + */ +#define MAX_SIZE 1024LL * 1024 * 4 + +/** + * Report progress outside of major reports? Should probably be GNUNET_YES if + * size is > 16 MB. + */ +#define REPORT_ID GNUNET_YES + +/** + * Number of put operations equivalent to 1/3rd of MAX_SIZE + */ +#define PUT_10 MAX_SIZE / 32 / 1024 / 3 + +/** + * Total number of iterations (each iteration doing + * PUT_10 put operations); we report full status every + * 10 iterations. Abort with CTRL-C. + */ +#define ITERATIONS 8 + + +static unsigned long long stored_bytes; + +static unsigned long long stored_entries; + +static unsigned long long stored_ops; + +static struct GNUNET_TIME_Absolute start_time; + +static int ok; + +enum RunPhase +{ + RP_DONE = 0, + RP_PUT, + RP_CUT, + RP_REPORT, + RP_ERROR +}; + + +struct CpsRunContext +{ + const struct GNUNET_CONFIGURATION_Handle *cfg; + enum RunPhase phase; + int j; + unsigned long long size; + int i; +}; + + + +static void +run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + + + +static void +check_success (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) +{ + struct CpsRunContext *crc = cls; + + if (GNUNET_OK != success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Check success failed: `%s'\n", msg); + crc->phase = RP_ERROR; + GNUNET_SCHEDULER_add_now (&run_continuation, crc); + return; + } +#if REPORT_ID + FPRINTF (stderr, "%s", "I"); +#endif + stored_bytes += crc->size; + stored_ops++; + stored_entries++; + crc->j++; + if (crc->j >= PUT_10) + { + crc->j = 0; + crc->i++; + if (crc->i == ITERATIONS) + crc->phase = RP_DONE; + else + crc->phase = RP_CUT; + } + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +/** + * Continuation called to notify client about result of the + * operation. + * + * @param cls closure + * @param success GNUNET_SYSERR on failure + * @param min_expiration minimum expiration time required for content to be stored + * by the datacache at this time, zero for unknown + * @param msg NULL on success, otherwise an error message + */ +static void +remove_next (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) +{ + struct CpsRunContext *crc = cls; + + if (GNUNET_OK != success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "remove_next failed: `%s'\n", msg); + crc->phase = RP_ERROR; + GNUNET_SCHEDULER_add_now (&run_continuation, crc); + return; + } +#if REPORT_ID + FPRINTF (stderr, "%s", "D"); +#endif + GNUNET_assert (GNUNET_OK == success); + GNUNET_SCHEDULER_add_now (&run_continuation, crc); +} + + +static void +delete_value (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct CpsRunContext *crc = cls; + + GNUNET_assert (NULL != key); + stored_ops++; + stored_bytes -= size; + stored_entries--; + stored_ops++; + if (stored_bytes < MAX_SIZE) + crc->phase = RP_PUT; + GNUNET_assert (NULL != + GNUNET_DATASTORE_remove (datastore, key, size, data, 1, 1, + TIMEOUT, &remove_next, crc)); +} + + +static void +run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CpsRunContext *crc = cls; + size_t size; + static GNUNET_HashCode key; + static char data[65536]; + int i; + int k; + char gstr[128]; + + ok = (int) crc->phase; + switch (crc->phase) + { + case RP_PUT: + memset (&key, 256 - crc->i, sizeof (GNUNET_HashCode)); + i = crc->j; + k = crc->i; + /* most content is 32k */ + size = 32 * 1024; + if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 0) /* but some of it is less! */ + size = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024); + crc->size = size = size - (size & 7); /* always multiple of 8 */ + GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &key); + memset (data, i, size); + if (i > 255) + memset (data, i - 255, size / 2); + data[0] = k; + GNUNET_assert (NULL != + GNUNET_DATASTORE_put (datastore, 0, &key, size, data, i + 1, + GNUNET_CRYPTO_random_u32 + (GNUNET_CRYPTO_QUALITY_WEAK, 100), i, + 0, + GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + GNUNET_CRYPTO_random_u32 + (GNUNET_CRYPTO_QUALITY_WEAK, 1000))), + 1, 1, TIMEOUT, &check_success, crc)); + break; + case RP_CUT: + /* trim down below MAX_SIZE again */ + GNUNET_assert (NULL != + GNUNET_DATASTORE_get_for_replication (datastore, 1, 1, + TIMEOUT, &delete_value, + crc)); + break; + case RP_REPORT: + printf ( +#if REPORT_ID + "\n" +#endif + "Stored %llu kB / %lluk ops / %llu ops/s\n", stored_bytes / 1024, /* used size in k */ + stored_ops / 1024, /* total operations (in k) */ + 1000 * stored_ops / (1 + + GNUNET_TIME_absolute_get_duration + (start_time).rel_value)); + crc->phase = RP_PUT; + crc->j = 0; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case RP_DONE: + GNUNET_snprintf (gstr, sizeof (gstr), "DATASTORE-%s", plugin_name); + if ((crc->i == ITERATIONS) && (stored_ops > 0)) + GAUGER (gstr, "PUT operation duration", + GNUNET_TIME_absolute_get_duration (start_time).rel_value / + stored_ops, "ms/operation"); + GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); + GNUNET_free (crc); + ok = 0; + break; + case RP_ERROR: + GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); + GNUNET_free (crc); + ok = 1; + break; + default: + GNUNET_assert (0); + } +} + + +static void +run_tests (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) +{ + struct CpsRunContext *crc = cls; + + if (success != GNUNET_YES) + { + FPRINTF (stderr, + "Test 'put' operation failed with error `%s' database likely not setup, skipping test.", + msg); + GNUNET_free (crc); + return; + } + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct CpsRunContext *crc; + static GNUNET_HashCode zkey; + + datastore = GNUNET_DATASTORE_connect (cfg); + start_time = GNUNET_TIME_absolute_get (); + crc = GNUNET_malloc (sizeof (struct CpsRunContext)); + crc->cfg = cfg; + crc->phase = RP_PUT; + if (NULL == + GNUNET_DATASTORE_put (datastore, 0, &zkey, 4, "TEST", + GNUNET_BLOCK_TYPE_TEST, 0, 0, 0, + GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_UNIT_SECONDS), 0, 1, + GNUNET_TIME_UNIT_MINUTES, &run_tests, crc)) + { + FPRINTF (stderr, "%s", "Test 'put' operation failed.\n"); + ok = 1; + GNUNET_free (crc); + } +} + + +static int +check () +{ + struct GNUNET_OS_Process *proc; + char cfg_name[128]; + + char *const argv[] = { + "perf-datastore-api", + "-c", + cfg_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_snprintf (cfg_name, sizeof (cfg_name), + "test_datastore_api_data_%s.conf", plugin_name); + proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfg_name, NULL); + GNUNET_assert (NULL != proc); + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "perf-datastore-api", "nohelp", options, &run, NULL); + sleep (1); /* give datastore chance to process 'DROP' */ + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + ok = 1; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + char *pos; + char dir_name[128]; + + sleep (1); + /* determine name of plugin to use */ + plugin_name = argv[0]; + while (NULL != (pos = strstr (plugin_name, "_"))) + plugin_name = pos + 1; + if (NULL != (pos = strstr (plugin_name, "."))) + pos[0] = 0; + else + pos = (char *) plugin_name; + + GNUNET_snprintf (dir_name, sizeof (dir_name), "/tmp/test-gnunet-datastore-%s", + plugin_name); + GNUNET_DISK_directory_remove (dir_name); + GNUNET_log_setup ("perf-datastore-api", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + if (pos != plugin_name) + pos[0] = '.'; +#if REPORT_ID + FPRINTF (stderr, "%s", "\n"); +#endif + GNUNET_DISK_directory_remove (dir_name); + return ret; +} + +/* end of perf_datastore_api.c */ diff --git a/src/datastore/perf_plugin_datastore.c b/src/datastore/perf_plugin_datastore.c new file mode 100644 index 0000000..1860374 --- /dev/null +++ b/src/datastore/perf_plugin_datastore.c @@ -0,0 +1,521 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2007, 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* + * @file perf_plugin_datastore.c + * @brief Profile database plugin directly, focusing on iterators. + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_datastore_plugin.h" +#include + +#define VERBOSE GNUNET_NO + +/** + * Target datastore size (in bytes). Realistic sizes are + * more like 16 GB (not the default of 16 MB); however, + * those take too long to run them in the usual "make check" + * sequence. Hence the value used for shipping is tiny. + */ +#define MAX_SIZE 1024LL * 1024 * 16 * 1 + +#define ITERATIONS 2 + +/** + * Number of put operations equivalent to 1/10th of MAX_SIZE + */ +#define PUT_10 (MAX_SIZE / 32 / 1024 / ITERATIONS) + +static char category[256]; + +static unsigned int hits[PUT_10 / 8 + 1]; + +static unsigned long long stored_bytes; + +static unsigned long long stored_entries; + +static unsigned long long stored_ops; + +static const char *plugin_name; + +static int ok; + +enum RunPhase +{ + RP_ERROR = 0, + RP_PUT, + RP_REP_GET, + RP_ZA_GET, + RP_EXP_GET, + RP_DONE +}; + + +struct CpsRunContext +{ + unsigned int i; + struct GNUNET_TIME_Absolute start; + struct GNUNET_TIME_Absolute end; + const struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_DATASTORE_PluginFunctions *api; + enum RunPhase phase; + unsigned int cnt; + unsigned int iter; + uint64_t offset; +}; + + +/** + * Function called by plugins to notify us about a + * change in their disk utilization. + * + * @param cls closure (NULL) + * @param delta change in disk utilization, + * 0 for "reset to empty" + */ +static void +disk_utilization_change_cb (void *cls, int delta) +{ +} + + +static void +putValue (struct GNUNET_DATASTORE_PluginFunctions *api, int i, int k) +{ + char value[65536]; + size_t size; + static GNUNET_HashCode key; + static int ic; + char *msg; + unsigned int prio; + + /* most content is 32k */ + size = 32 * 1024; + if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 0) /* but some of it is less! */ + size = 8 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024); + size = size - (size & 7); /* always multiple of 8 */ + + /* generate random key */ + key.bits[0] = (unsigned int) GNUNET_TIME_absolute_get ().abs_value; + GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &key); + memset (value, i, size); + if (i > 255) + memset (value, i - 255, size / 2); + value[0] = k; + memcpy (&value[4], &i, sizeof (i)); + msg = NULL; + prio = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100); + if (GNUNET_OK != api->put (api->cls, &key, size, value, 1 + i % 4 /* type */ , + prio, i % 4 /* anonymity */ , + 0 /* replication */ , + GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, + 60 * 60 * 60 * 1000 + + GNUNET_CRYPTO_random_u32 + (GNUNET_CRYPTO_QUALITY_WEAK, 1000))), &msg)) + { + FPRINTF (stderr, "ERROR: `%s'\n", msg); + GNUNET_free_non_null (msg); + return; + } + ic++; + stored_bytes += size; + stored_ops++; + stored_entries++; +} + +static void +test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +static int +iterate_zeros (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct CpsRunContext *crc = cls; + int i; + const char *cdata = data; + + GNUNET_assert (key != NULL); + GNUNET_assert (size >= 8); + memcpy (&i, &cdata[4], sizeof (i)); + hits[i / 8] |= (1 << (i % 8)); + +#if VERBOSE + FPRINTF (stderr, "Found result type=%u, priority=%u, size=%u, expire=%llu\n", + type, priority, size, (unsigned long long) expiration.abs_value); +#endif + crc->cnt++; + if (crc->cnt == PUT_10 / 4 - 1) + { + unsigned int bc; + + bc = 0; + for (i = 0; i < PUT_10; i++) + if (0 != (hits[i / 8] & (1 << (i % 8)))) + bc++; + + crc->end = GNUNET_TIME_absolute_get (); + printf ("%s took %llu ms yielding %u/%u items\n", + "Select random zero-anonymity item", + (unsigned long long) (crc->end.abs_value - crc->start.abs_value), + bc, crc->cnt); + if (crc->cnt > 0) + GAUGER (category, "Select random zero-anonymity item", + (crc->end.abs_value - crc->start.abs_value) / crc->cnt, + "ms/item"); + memset (hits, 0, sizeof (hits)); + crc->phase++; + crc->cnt = 0; + crc->start = GNUNET_TIME_absolute_get (); + } + GNUNET_SCHEDULER_add_now (&test, crc); + return GNUNET_OK; +} + + +static int +expiration_get (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, uint64_t uid) +{ + struct CpsRunContext *crc = cls; + int i; + const char *cdata = data; + + GNUNET_assert (size >= 8); + memcpy (&i, &cdata[4], sizeof (i)); + hits[i / 8] |= (1 << (i % 8)); + crc->cnt++; + if (PUT_10 <= crc->cnt) + { + unsigned int bc; + + bc = 0; + for (i = 0; i < PUT_10; i++) + if (0 != (hits[i / 8] & (1 << (i % 8)))) + bc++; + + crc->end = GNUNET_TIME_absolute_get (); + printf ("%s took %llu ms yielding %u/%u items\n", + "Selecting and deleting by expiration", + (unsigned long long) (crc->end.abs_value - crc->start.abs_value), + bc, (unsigned int) PUT_10); + if (crc->cnt > 0) + GAUGER (category, "Selecting and deleting by expiration", + (crc->end.abs_value - crc->start.abs_value) / crc->cnt, + "ms/item"); + memset (hits, 0, sizeof (hits)); + if (++crc->iter == ITERATIONS) + crc->phase++; + else + crc->phase = RP_PUT; + crc->cnt = 0; + crc->start = GNUNET_TIME_absolute_get (); + } + GNUNET_SCHEDULER_add_now (&test, crc); + return GNUNET_NO; +} + + +static int +replication_get (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, uint64_t uid) +{ + struct CpsRunContext *crc = cls; + int i; + const char *cdata = data; + + GNUNET_assert (NULL != key); + GNUNET_assert (size >= 8); + memcpy (&i, &cdata[4], sizeof (i)); + hits[i / 8] |= (1 << (i % 8)); + crc->cnt++; + if (PUT_10 <= crc->cnt) + { + unsigned int bc; + + bc = 0; + for (i = 0; i < PUT_10; i++) + if (0 != (hits[i / 8] & (1 << (i % 8)))) + bc++; + + crc->end = GNUNET_TIME_absolute_get (); + printf ("%s took %llu ms yielding %u/%u items\n", + "Selecting random item for replication", + (unsigned long long) (crc->end.abs_value - crc->start.abs_value), + bc, (unsigned int) PUT_10); + if (crc->cnt > 0) + GAUGER (category, "Selecting random item for replication", + (crc->end.abs_value - crc->start.abs_value) / crc->cnt, + "ms/item"); + memset (hits, 0, sizeof (hits)); + crc->phase++; + crc->offset = 0; + crc->cnt = 0; + crc->start = GNUNET_TIME_absolute_get (); + } + + GNUNET_SCHEDULER_add_now (&test, crc); + return GNUNET_OK; +} + + +/** + * Function called when the service shuts + * down. Unloads our datastore plugin. + * + * @param api api to unload + * @param cfg configuration to use + */ +static void +unload_plugin (struct GNUNET_DATASTORE_PluginFunctions *api, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *name; + char *libname; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE", + &name)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", + "DATASTORE"); + return; + } + GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name); + GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api)); + GNUNET_free (libname); + GNUNET_free (name); +} + + + +/** + * Last task run during shutdown. Disconnects us from + * the transport and core. + */ +static void +cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CpsRunContext *crc = cls; + + unload_plugin (crc->api, crc->cfg); + GNUNET_free (crc); +} + + +static void +test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CpsRunContext *crc = cls; + int j; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + GNUNET_break (0); + crc->phase = RP_ERROR; + } +#if VERBOSE + FPRINTF (stderr, "In phase %d, iteration %u\n", crc->phase, crc->cnt); +#endif + switch (crc->phase) + { + case RP_ERROR: + GNUNET_break (0); + crc->api->drop (crc->api->cls); + ok = 1; + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, + &cleaning_task, crc); + break; + case RP_PUT: + crc->start = GNUNET_TIME_absolute_get (); + for (j = 0; j < PUT_10; j++) + putValue (crc->api, j, crc->i); + crc->end = GNUNET_TIME_absolute_get (); + { + printf ("%s took %llu ms for %llu items\n", "Storing an item", + (unsigned long long) (crc->end.abs_value - crc->start.abs_value), + PUT_10); + if (PUT_10 > 0) + GAUGER (category, "Storing an item", + (crc->end.abs_value - crc->start.abs_value) / PUT_10, + "ms/item"); + } + crc->i++; + crc->start = GNUNET_TIME_absolute_get (); + crc->phase++; + GNUNET_SCHEDULER_add_now (&test, crc); + break; + case RP_REP_GET: + crc->api->get_replication (crc->api->cls, &replication_get, crc); + break; + case RP_ZA_GET: + crc->api->get_zero_anonymity (crc->api->cls, crc->offset++, 1, + &iterate_zeros, crc); + break; + case RP_EXP_GET: + crc->api->get_expiration (crc->api->cls, &expiration_get, crc); + break; + case RP_DONE: + crc->api->drop (crc->api->cls); + ok = 0; + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, + &cleaning_task, crc); + break; + } +} + + +/** + * Load the datastore plugin. + */ +static struct GNUNET_DATASTORE_PluginFunctions * +load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + static struct GNUNET_DATASTORE_PluginEnvironment env; + struct GNUNET_DATASTORE_PluginFunctions *ret; + char *name; + char *libname; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE", + &name)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", + "DATASTORE"); + return NULL; + } + env.cfg = cfg; + env.duc = &disk_utilization_change_cb; + env.cls = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datastore plugin\n"), + name); + GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name); + if (NULL == (ret = GNUNET_PLUGIN_load (libname, &env))) + { + FPRINTF (stderr, "Failed to load plugin `%s'!\n", name); + return NULL; + } + GNUNET_free (libname); + GNUNET_free (name); + return ret; +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + struct GNUNET_DATASTORE_PluginFunctions *api; + struct CpsRunContext *crc; + + api = load_plugin (c); + if (api == NULL) + { + FPRINTF (stderr, + "%s", "Could not initialize plugin, assuming database not configured. Test not run!\n"); + return; + } + crc = GNUNET_malloc (sizeof (struct CpsRunContext)); + crc->api = api; + crc->cfg = c; + crc->phase = RP_PUT; + ok = 2; + GNUNET_SCHEDULER_add_now (&test, crc); +} + + +static int +check () +{ + char cfg_name[128]; + + char *const argv[] = { + "perf-plugin-datastore", + "-c", + cfg_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_snprintf (category, sizeof (category), "DATASTORE-%s", plugin_name); + GNUNET_snprintf (cfg_name, sizeof (cfg_name), + "perf_plugin_datastore_data_%s.conf", plugin_name); + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "perf-plugin-datastore", "nohelp", options, &run, NULL); + if (ok != 0) + FPRINTF (stderr, "Missed some testcases: %u\n", ok); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + char *pos; + char dir_name[128]; + + sleep (1); + /* determine name of plugin to use */ + plugin_name = argv[0]; + while (NULL != (pos = strstr (plugin_name, "_"))) + plugin_name = pos + 1; + if (NULL != (pos = strstr (plugin_name, "."))) + pos[0] = 0; + else + pos = (char *) plugin_name; + + GNUNET_snprintf (dir_name, sizeof (dir_name), "/tmp/perf-gnunet-datastore-%s", + plugin_name); + GNUNET_DISK_directory_remove (dir_name); + GNUNET_log_setup ("perf-plugin-datastore", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + if (pos != plugin_name) + pos[0] = '.'; + GNUNET_DISK_directory_remove (dir_name); + + return ret; +} + +/* end of perf_plugin_datastore.c */ diff --git a/src/datastore/perf_plugin_datastore_data_mysql.conf b/src/datastore/perf_plugin_datastore_data_mysql.conf new file mode 100644 index 0000000..dd26512 --- /dev/null +++ b/src/datastore/perf_plugin_datastore_data_mysql.conf @@ -0,0 +1,11 @@ +@INLINE@ test_defaults.conf +[PATHS] +SERVICEHOME = /tmp/perf-gnunet-datastore-mysql/ +DEFAULTCONFIG = perf_plugin_datastore_data_mysql.conf + +[datastore] +DATABASE = mysql + +[datastore-mysql] +DATABASE = gnunetcheck + diff --git a/src/datastore/perf_plugin_datastore_data_postgres.conf b/src/datastore/perf_plugin_datastore_data_postgres.conf new file mode 100644 index 0000000..53ce6cf --- /dev/null +++ b/src/datastore/perf_plugin_datastore_data_postgres.conf @@ -0,0 +1,11 @@ +@INLINE@ test_defaults.conf +[PATHS] +SERVICEHOME = /tmp/perf-gnunet-datastore-postgres/ +DEFAULTCONFIG = perf_plugin_datastore_data_postgres.conf + +[datastore] +DATABASE = postgres + +[datastore-postgres] +CONFIG = dbname=gnunetcheck + diff --git a/src/datastore/perf_plugin_datastore_data_sqlite.conf b/src/datastore/perf_plugin_datastore_data_sqlite.conf new file mode 100644 index 0000000..241d85e --- /dev/null +++ b/src/datastore/perf_plugin_datastore_data_sqlite.conf @@ -0,0 +1,5 @@ +@INLINE@ test_defaults.conf +[PATHS] +SERVICEHOME = /tmp/perf-gnunet-datastore-sqlite/ +DEFAULTCONFIG = perf_plugin_datastore_data_sqlite.conf + diff --git a/src/datastore/plugin_datastore_mysql.c b/src/datastore/plugin_datastore_mysql.c new file mode 100644 index 0000000..76d6ad7 --- /dev/null +++ b/src/datastore/plugin_datastore_mysql.c @@ -0,0 +1,1612 @@ +/* + This file is part of GNUnet + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datastore/plugin_datastore_mysql.c + * @brief mysql-based datastore backend + * @author Igor Wronsky + * @author Christian Grothoff + * + * NOTE: This db module does NOT work with mysql prior to 4.1 since + * it uses prepared statements. MySQL 5.0.46 promises to fix a bug + * in MyISAM that is causing us grief. At the time of this writing, + * that version is yet to be released. In anticipation, the code + * will use MyISAM with 5.0.46 (and higher). If you run such a + * version, please run "make check" to verify that the MySQL bug + * was actually fixed in your version (and if not, change the + * code below to use MyISAM for gn071). + * + * HIGHLIGHTS + * + * Pros + * + On up-to-date hardware where mysql can be used comfortably, this + * module will have better performance than the other db choices + * (according to our tests). + * + Its often possible to recover the mysql database from internal + * inconsistencies. The other db choices do not support repair! + * Cons + * - Memory usage (Comment: "I have 1G and it never caused me trouble") + * - Manual setup + * + * MANUAL SETUP INSTRUCTIONS + * + * 1) in /etc/gnunet.conf, set + * @verbatim + [datastore] + DATABASE = "mysql" + @endverbatim + * 2) Then access mysql as root, + * @verbatim + $ mysql -u root -p + @endverbatim + * and do the following. [You should replace $USER with the username + * that will be running the gnunetd process]. + * @verbatim + CREATE DATABASE gnunet; + GRANT select,insert,update,delete,create,alter,drop,create temporary tables + ON gnunet.* TO $USER@localhost; + SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like'); + FLUSH PRIVILEGES; + @endverbatim + * 3) In the $HOME directory of $USER, create a ".my.cnf" file + * with the following lines + * @verbatim + [client] + user=$USER + password=$the_password_you_like + @endverbatim + * + * Thats it. Note that .my.cnf file is a security risk unless its on + * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic + * link. Even greater security risk can be achieved by setting no + * password for $USER. Luckily $USER has only priviledges to mess + * up GNUnet's tables, nothing else (unless you give him more, + * of course).

+ * + * 4) Still, perhaps you should briefly try if the DB connection + * works. First, login as $USER. Then use, + * + * @verbatim + $ mysql -u $USER -p $the_password_you_like + mysql> use gnunet; + @endverbatim + * + * If you get the message "Database changed" it probably works. + * + * [If you get "ERROR 2002: Can't connect to local MySQL server + * through socket '/tmp/mysql.sock' (2)" it may be resolvable by + * "ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock" + * so there may be some additional trouble depending on your mysql setup.] + * + * REPAIRING TABLES + * + * - Its probably healthy to check your tables for inconsistencies + * every now and then. + * - If you get odd SEGVs on gnunetd startup, it might be that the mysql + * databases have been corrupted. + * - The tables can be verified/fixed in two ways; + * 1) by running mysqlcheck -A, or + * 2) by executing (inside of mysql using the GNUnet database): + * @verbatim + mysql> REPAIR TABLE gn090; + @endverbatim + * + * PROBLEMS? + * + * If you have problems related to the mysql module, your best + * friend is probably the mysql manual. The first thing to check + * is that mysql is basically operational, that you can connect + * to it, create tables, issue queries etc. + */ + +#include "platform.h" +#include "gnunet_datastore_plugin.h" +#include "gnunet_util_lib.h" +#include + +#define DEBUG_MYSQL GNUNET_EXTRA_LOGGING + +#define MAX_DATUM_SIZE 65536 + +/** + * Maximum number of supported parameters for a prepared + * statement. Increase if needed. + */ +#define MAX_PARAM 16 + +/** + * Die with an error message that indicates + * a failure of the command 'cmd' with the message given + * by strerror(errno). + */ +#define DIE_MYSQL(cmd, dbh) do { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); GNUNET_abort(); } while(0); + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' on file 'filename' + * with the message given by strerror(errno). + */ +#define LOG_MYSQL(level, cmd, dbh) do { GNUNET_log(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); } while(0); + + +struct GNUNET_MysqlStatementHandle +{ + struct GNUNET_MysqlStatementHandle *next; + + struct GNUNET_MysqlStatementHandle *prev; + + char *query; + + MYSQL_STMT *statement; + + int valid; + +}; + + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + /** + * Our execution environment. + */ + struct GNUNET_DATASTORE_PluginEnvironment *env; + + /** + * Handle to talk to MySQL. + */ + MYSQL *dbf; + + /** + * We keep all prepared statements in a DLL. This is the head. + */ + struct GNUNET_MysqlStatementHandle *shead; + + /** + * We keep all prepared statements in a DLL. This is the tail. + */ + struct GNUNET_MysqlStatementHandle *stail; + + /** + * Filename of "my.cnf" (msyql configuration). + */ + char *cnffile; + + /** + * Prepared statements. + */ +#define INSERT_ENTRY "INSERT INTO gn090 (repl,type,prio,anonLevel,expire,rvalue,hash,vhash,value) VALUES (?,?,?,?,?,?,?,?,?)" + struct GNUNET_MysqlStatementHandle *insert_entry; + +#define DELETE_ENTRY_BY_UID "DELETE FROM gn090 WHERE uid=?" + struct GNUNET_MysqlStatementHandle *delete_entry_by_uid; + +#define COUNT_ENTRY_BY_HASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash) WHERE hash=?" + struct GNUNET_MysqlStatementHandle *count_entry_by_hash; + +#define SELECT_ENTRY_BY_HASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash) WHERE hash=? ORDER BY uid LIMIT 1 OFFSET ?" + struct GNUNET_MysqlStatementHandle *select_entry_by_hash; + +#define COUNT_ENTRY_BY_HASH_AND_VHASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=?" + struct GNUNET_MysqlStatementHandle *count_entry_by_hash_and_vhash; + +#define SELECT_ENTRY_BY_HASH_AND_VHASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? ORDER BY uid LIMIT 1 OFFSET ?" + struct GNUNET_MysqlStatementHandle *select_entry_by_hash_and_vhash; + +#define COUNT_ENTRY_BY_HASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=?" + struct GNUNET_MysqlStatementHandle *count_entry_by_hash_and_type; + +#define SELECT_ENTRY_BY_HASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=? ORDER BY uid LIMIT 1 OFFSET ?" + struct GNUNET_MysqlStatementHandle *select_entry_by_hash_and_type; + +#define COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=?" + struct GNUNET_MysqlStatementHandle *count_entry_by_hash_vhash_and_type; + +#define SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=? ORDER BY uid ASC LIMIT 1 OFFSET ?" + struct GNUNET_MysqlStatementHandle *select_entry_by_hash_vhash_and_type; + +#define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE uid=?" + struct GNUNET_MysqlStatementHandle *update_entry; + +#define DEC_REPL "UPDATE gn090 SET repl=GREATEST (0, repl - 1) WHERE uid=?" + struct GNUNET_MysqlStatementHandle *dec_repl; + +#define SELECT_SIZE "SELECT SUM(BIT_LENGTH(value) DIV 8) FROM gn090" + struct GNUNET_MysqlStatementHandle *get_size; + +#define SELECT_IT_NON_ANONYMOUS "SELECT type,prio,anonLevel,expire,hash,value,uid "\ + "FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) "\ + "WHERE anonLevel=0 AND type=? AND "\ + "(rvalue >= ? OR"\ + " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) WHERE anonLevel=0 AND type=? AND rvalue>=?)) "\ + "ORDER BY rvalue ASC LIMIT 1" + struct GNUNET_MysqlStatementHandle *zero_iter; + +#define SELECT_IT_EXPIRATION "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_expire) WHERE expire < ? ORDER BY expire ASC LIMIT 1" + struct GNUNET_MysqlStatementHandle *select_expiration; + +#define SELECT_IT_PRIORITY "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_prio) ORDER BY prio ASC LIMIT 1" + struct GNUNET_MysqlStatementHandle *select_priority; + +#define SELECT_IT_REPLICATION "SELECT type,prio,anonLevel,expire,hash,value,uid "\ + "FROM gn090 FORCE INDEX (idx_repl_rvalue) "\ + "WHERE repl=? AND "\ + " (rvalue>=? OR"\ + " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_repl_rvalue) WHERE repl=? AND rvalue>=?)) "\ + "ORDER BY rvalue ASC "\ + "LIMIT 1" + struct GNUNET_MysqlStatementHandle *select_replication; + +#define SELECT_MAX_REPL "SELECT MAX(repl) FROM gn090" + struct GNUNET_MysqlStatementHandle *max_repl; + +}; + + +/** + * Obtain the location of ".my.cnf". + * + * @param cfg our configuration + * @return NULL on error + */ +static char * +get_my_cnf_path (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *cnffile; + char *home_dir; + struct stat st; + +#ifndef WINDOWS + struct passwd *pw; +#endif + int configured; + +#ifndef WINDOWS + pw = getpwuid (getuid ()); + if (!pw) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "getpwuid"); + return NULL; + } + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (cfg, "datastore-mysql", "CONFIG")) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_filename (cfg, + "datastore-mysql", + "CONFIG", + &cnffile)); + configured = GNUNET_YES; + } + else + { + home_dir = GNUNET_strdup (pw->pw_dir); + GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir); + GNUNET_free (home_dir); + configured = GNUNET_NO; + } +#else + home_dir = (char *) GNUNET_malloc (_MAX_PATH + 1); + plibc_conv_to_win_path ("~/", home_dir); + GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir); + GNUNET_free (home_dir); + configured = GNUNET_NO; +#endif + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Trying to use file `%s' for MySQL configuration.\n"), cnffile); + if ((0 != STAT (cnffile, &st)) || (0 != ACCESS (cnffile, R_OK)) || + (!S_ISREG (st.st_mode))) + { + if (configured == GNUNET_YES) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access file `%s': %s\n"), cnffile, + STRERROR (errno)); + GNUNET_free (cnffile); + return NULL; + } + return cnffile; +} + + +/** + * Close database connection and all prepared statements (we got a DB + * disconnect error). + * + * @param plugin plugin context + */ +static int +iclose (struct Plugin *plugin) +{ + struct GNUNET_MysqlStatementHandle *s; + + for (s = plugin->shead; s != NULL; s = s->next) + { + if (s->valid) + { + mysql_stmt_close (s->statement); + s->valid = GNUNET_NO; + } + } + if (plugin->dbf != NULL) + { + mysql_close (plugin->dbf); + plugin->dbf = NULL; + } + return GNUNET_OK; +} + + +/** + * Open the connection with the database (and initialize + * our default options). + * + * @param plugin plugin context + * @return GNUNET_OK on success + */ +static int +iopen (struct Plugin *plugin) +{ + char *mysql_dbname; + char *mysql_server; + char *mysql_user; + char *mysql_password; + unsigned long long mysql_port; + my_bool reconnect; + unsigned int timeout; + + plugin->dbf = mysql_init (NULL); + if (plugin->dbf == NULL) + return GNUNET_SYSERR; + if (plugin->cnffile != NULL) + mysql_options (plugin->dbf, MYSQL_READ_DEFAULT_FILE, plugin->cnffile); + mysql_options (plugin->dbf, MYSQL_READ_DEFAULT_GROUP, "client"); + reconnect = 0; + mysql_options (plugin->dbf, MYSQL_OPT_RECONNECT, &reconnect); + timeout = 120; /* in seconds */ + mysql_options (plugin->dbf, MYSQL_OPT_CONNECT_TIMEOUT, + (const void *) &timeout); + mysql_options (plugin->dbf, MYSQL_SET_CHARSET_NAME, "UTF8"); + timeout = 60; /* in seconds */ + mysql_options (plugin->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout); + mysql_options (plugin->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout); + mysql_dbname = NULL; + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (plugin->env->cfg, "datastore-mysql", + "DATABASE")) + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, + "datastore-mysql", + "DATABASE", + &mysql_dbname)); + else + mysql_dbname = GNUNET_strdup ("gnunet"); + mysql_user = NULL; + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (plugin->env->cfg, "datastore-mysql", + "USER")) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, + "datastore-mysql", + "USER", &mysql_user)); + } + mysql_password = NULL; + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (plugin->env->cfg, "datastore-mysql", + "PASSWORD")) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, + "datastore-mysql", + "PASSWORD", + &mysql_password)); + } + mysql_server = NULL; + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (plugin->env->cfg, "datastore-mysql", + "HOST")) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, + "datastore-mysql", + "HOST", + &mysql_server)); + } + mysql_port = 0; + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (plugin->env->cfg, "datastore-mysql", + "PORT")) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, + "datastore-mysql", + "PORT", &mysql_port)); + } + + GNUNET_assert (mysql_dbname != NULL); + mysql_real_connect (plugin->dbf, mysql_server, mysql_user, mysql_password, + mysql_dbname, (unsigned int) mysql_port, NULL, + CLIENT_IGNORE_SIGPIPE); + GNUNET_free_non_null (mysql_server); + GNUNET_free_non_null (mysql_user); + GNUNET_free_non_null (mysql_password); + GNUNET_free (mysql_dbname); + if (mysql_error (plugin->dbf)[0]) + { + LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_real_connect", plugin); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Run the given MySQL statement. + * + * @param plugin plugin context + * @param statement SQL statement to run + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +run_statement (struct Plugin *plugin, const char *statement) +{ + if ((NULL == plugin->dbf) && (GNUNET_OK != iopen (plugin))) + return GNUNET_SYSERR; + mysql_query (plugin->dbf, statement); + if (mysql_error (plugin->dbf)[0]) + { + LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_query", plugin); + iclose (plugin); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Create a prepared statement. + * + * @param plugin plugin context + * @param statement SQL statement text to prepare + * @return NULL on error + */ +static struct GNUNET_MysqlStatementHandle * +prepared_statement_create (struct Plugin *plugin, const char *statement) +{ + struct GNUNET_MysqlStatementHandle *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_MysqlStatementHandle)); + ret->query = GNUNET_strdup (statement); + GNUNET_CONTAINER_DLL_insert (plugin->shead, plugin->stail, ret); + return ret; +} + + +/** + * Prepare a statement for running. + * + * @param plugin plugin context + * @param ret handle to prepared statement + * @return GNUNET_OK on success + */ +static int +prepare_statement (struct Plugin *plugin, + struct GNUNET_MysqlStatementHandle *ret) +{ + if (GNUNET_YES == ret->valid) + return GNUNET_OK; + if ((NULL == plugin->dbf) && (GNUNET_OK != iopen (plugin))) + return GNUNET_SYSERR; + ret->statement = mysql_stmt_init (plugin->dbf); + if (ret->statement == NULL) + { + iclose (plugin); + return GNUNET_SYSERR; + } + if (mysql_stmt_prepare (ret->statement, ret->query, strlen (ret->query))) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql", + _("Failed to prepare statement `%s'\n"), ret->query); + LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", plugin); + mysql_stmt_close (ret->statement); + ret->statement = NULL; + iclose (plugin); + return GNUNET_SYSERR; + } + ret->valid = GNUNET_YES; + return GNUNET_OK; + +} + + +/** + * Bind the parameters for the given MySQL statement + * and run it. + * + * @param plugin plugin context + * @param s statement to bind and run + * @param ap arguments for the binding + * @return GNUNET_SYSERR on error, GNUNET_OK on success + */ +static int +init_params (struct Plugin *plugin, struct GNUNET_MysqlStatementHandle *s, + va_list ap) +{ + MYSQL_BIND qbind[MAX_PARAM]; + unsigned int pc; + unsigned int off; + enum enum_field_types ft; + + pc = mysql_stmt_param_count (s->statement); + if (pc > MAX_PARAM) + { + /* increase internal constant! */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + memset (qbind, 0, sizeof (qbind)); + off = 0; + ft = 0; + while ((pc > 0) && (-1 != (int) (ft = va_arg (ap, enum enum_field_types)))) + { + qbind[off].buffer_type = ft; + switch (ft) + { + case MYSQL_TYPE_FLOAT: + qbind[off].buffer = va_arg (ap, float *); + + break; + case MYSQL_TYPE_LONGLONG: + qbind[off].buffer = va_arg (ap, unsigned long long *); + qbind[off].is_unsigned = va_arg (ap, int); + + break; + case MYSQL_TYPE_LONG: + qbind[off].buffer = va_arg (ap, unsigned int *); + qbind[off].is_unsigned = va_arg (ap, int); + + break; + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_BLOB: + qbind[off].buffer = va_arg (ap, void *); + qbind[off].buffer_length = va_arg (ap, unsigned long); + qbind[off].length = va_arg (ap, unsigned long *); + + break; + default: + /* unsupported type */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + pc--; + off++; + } + if (!((pc == 0) && (-1 != (int) ft) && (va_arg (ap, int) == -1))) + { + GNUNET_assert (0); + return GNUNET_SYSERR; + } + if (mysql_stmt_bind_param (s->statement, qbind)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed at %s:%d with error: %s\n"), + "mysql_stmt_bind_param", __FILE__, __LINE__, + mysql_stmt_error (s->statement)); + iclose (plugin); + return GNUNET_SYSERR; + } + if (mysql_stmt_execute (s->statement)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' for `%s' failed at %s:%d with error: %s\n"), + "mysql_stmt_execute", s->query, __FILE__, __LINE__, + mysql_stmt_error (s->statement)); + iclose (plugin); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Run a prepared SELECT statement. + * + * @param plugin plugin context + * @param s statement to run + * @param result_size number of elements in results array + * @param results pointer to already initialized MYSQL_BIND + * array (of sufficient size) for passing results + * @param ap pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective + * values (size + buffer-reference for pointers); terminated + * with "-1" + * @return GNUNET_SYSERR on error, otherwise GNUNET_OK or GNUNET_NO (no result) + */ +static int +prepared_statement_run_select_va (struct Plugin *plugin, + struct GNUNET_MysqlStatementHandle *s, + unsigned int result_size, + MYSQL_BIND * results, va_list ap) +{ + int ret; + unsigned int rsize; + + if (GNUNET_OK != prepare_statement (plugin, s)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != init_params (plugin, s, ap)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + rsize = mysql_stmt_field_count (s->statement); + if (rsize > result_size) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (mysql_stmt_bind_result (s->statement, results)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed at %s:%d with error: %s\n"), + "mysql_stmt_bind_result", __FILE__, __LINE__, + mysql_stmt_error (s->statement)); + iclose (plugin); + return GNUNET_SYSERR; + } + ret = mysql_stmt_fetch (s->statement); + if (ret == MYSQL_NO_DATA) + return GNUNET_NO; + if (ret != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed at %s:%d with error: %s\n"), "mysql_stmt_fetch", + __FILE__, __LINE__, mysql_stmt_error (s->statement)); + iclose (plugin); + return GNUNET_SYSERR; + } + mysql_stmt_reset (s->statement); + return GNUNET_OK; +} + + +/** + * Run a prepared SELECT statement. + * + * @param plugin plugin context + * @param s statement to run + * @param result_size number of elements in results array + * @param results pointer to already initialized MYSQL_BIND + * array (of sufficient size) for passing results + * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective + * values (size + buffer-reference for pointers); terminated + * with "-1" + * @return GNUNET_SYSERR on error, otherwise + * the number of successfully affected (or queried) rows + */ +static int +prepared_statement_run_select (struct Plugin *plugin, + struct GNUNET_MysqlStatementHandle *s, + unsigned int result_size, MYSQL_BIND * results, + ...) +{ + va_list ap; + int ret; + + va_start (ap, results); + ret = prepared_statement_run_select_va (plugin, s, result_size, results, ap); + va_end (ap); + return ret; +} + + +/** + * Run a prepared statement that does NOT produce results. + * + * @param plugin plugin context + * @param s statement to run + * @param insert_id NULL or address where to store the row ID of whatever + * was inserted (only for INSERT statements!) + * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective + * values (size + buffer-reference for pointers); terminated + * with "-1" + * @return GNUNET_SYSERR on error, otherwise + * the number of successfully affected rows + */ +static int +prepared_statement_run (struct Plugin *plugin, + struct GNUNET_MysqlStatementHandle *s, + unsigned long long *insert_id, ...) +{ + va_list ap; + int affected; + + if (GNUNET_OK != prepare_statement (plugin, s)) + return GNUNET_SYSERR; + va_start (ap, insert_id); + if (GNUNET_OK != init_params (plugin, s, ap)) + { + va_end (ap); + return GNUNET_SYSERR; + } + va_end (ap); + affected = mysql_stmt_affected_rows (s->statement); + if (NULL != insert_id) + *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement); + mysql_stmt_reset (s->statement); + return affected; +} + + +/** + * Delete an entry from the gn090 table. + * + * @param plugin plugin context + * @param uid unique ID of the entry to delete + * @return GNUNET_OK on success, GNUNET_NO if no such value exists, GNUNET_SYSERR on error + */ +static int +do_delete_entry (struct Plugin *plugin, unsigned long long uid) +{ + int ret; + +#if DEBUG_MYSQL + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting value %llu from gn090 table\n", + uid); +#endif + ret = + prepared_statement_run (plugin, plugin->delete_entry_by_uid, NULL, + MYSQL_TYPE_LONGLONG, &uid, GNUNET_YES, -1); + if (ret >= 0) + return GNUNET_OK; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Deleting value %llu from gn090 table failed\n", uid); + return ret; +} + + +/** + * Get an estimate of how much space the database is + * currently using. + * + * @param cls our "struct Plugin *" + * @return number of bytes used on disk + */ +static unsigned long long +mysql_plugin_estimate_size (void *cls) +{ + struct Plugin *plugin = cls; + MYSQL_BIND cbind[1]; + long long total; + + memset (cbind, 0, sizeof (cbind)); + total = 0; + cbind[0].buffer_type = MYSQL_TYPE_LONGLONG; + cbind[0].buffer = &total; + cbind[0].is_unsigned = GNUNET_NO; + if (GNUNET_OK != + prepared_statement_run_select (plugin, plugin->get_size, 1, cbind, -1)) + return 0; + return total; +} + + +/** + * Store an item in the datastore. + * + * @param cls closure + * @param key key for the item + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param replication replication-level for the content + * @param expiration expiration time for the content + * @param msg set to error message + * @return GNUNET_OK on success + */ +static int +mysql_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, uint32_t replication, + struct GNUNET_TIME_Absolute expiration, char **msg) +{ + struct Plugin *plugin = cls; + unsigned int irepl = replication; + unsigned int ipriority = priority; + unsigned int ianonymity = anonymity; + unsigned long long lexpiration = expiration.abs_value; + unsigned long long lrvalue = + (unsigned long long) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX); + unsigned long hashSize; + unsigned long hashSize2; + unsigned long lsize; + GNUNET_HashCode vhash; + + if (size > MAX_DATUM_SIZE) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + hashSize = sizeof (GNUNET_HashCode); + hashSize2 = sizeof (GNUNET_HashCode); + lsize = size; + GNUNET_CRYPTO_hash (data, size, &vhash); + if (GNUNET_OK != + prepared_statement_run (plugin, plugin->insert_entry, NULL, + MYSQL_TYPE_LONG, &irepl, GNUNET_YES, + MYSQL_TYPE_LONG, &type, GNUNET_YES, + MYSQL_TYPE_LONG, &ipriority, GNUNET_YES, + MYSQL_TYPE_LONG, &ianonymity, GNUNET_YES, + MYSQL_TYPE_LONGLONG, &lexpiration, GNUNET_YES, + MYSQL_TYPE_LONGLONG, &lrvalue, GNUNET_YES, + MYSQL_TYPE_BLOB, key, hashSize, &hashSize, + MYSQL_TYPE_BLOB, &vhash, hashSize2, &hashSize2, + MYSQL_TYPE_BLOB, data, lsize, &lsize, -1)) + return GNUNET_SYSERR; +#if DEBUG_MYSQL + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Inserted value `%s' with size %u into gn090 table\n", + GNUNET_h2s (key), (unsigned int) size); +#endif + if (size > 0) + plugin->env->duc (plugin->env->cls, size); + return GNUNET_OK; +} + + +/** + * Update the priority for a particular key in the datastore. If + * the expiration time in value is different than the time found in + * the datastore, the higher value should be kept. For the + * anonymity level, the lower value is to be used. The specified + * priority should be added to the existing priority, ignoring the + * priority in value. + * + * Note that it is possible for multiple values to match this put. + * In that case, all of the respective values are updated. + * + * @param cls our "struct Plugin*" + * @param uid unique identifier of the datum + * @param delta by how much should the priority + * change? If priority + delta < 0 the + * priority should be set to 0 (never go + * negative). + * @param expire new expiration time should be the + * MAX of any existing expiration time and + * this value + * @param msg set to error message + * @return GNUNET_OK on success + */ +static int +mysql_plugin_update (void *cls, uint64_t uid, int delta, + struct GNUNET_TIME_Absolute expire, char **msg) +{ + struct Plugin *plugin = cls; + unsigned long long vkey = uid; + unsigned long long lexpire = expire.abs_value; + int ret; + +#if DEBUG_MYSQL + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Updating value %llu adding %d to priority and maxing exp at %llu\n", + vkey, delta, lexpire); +#endif + ret = + prepared_statement_run (plugin, plugin->update_entry, NULL, + MYSQL_TYPE_LONG, &delta, GNUNET_NO, + MYSQL_TYPE_LONGLONG, &lexpire, GNUNET_YES, + MYSQL_TYPE_LONGLONG, &lexpire, GNUNET_YES, + MYSQL_TYPE_LONGLONG, &vkey, GNUNET_YES, -1); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to update value %llu\n", + vkey); + } + return ret; +} + + +/** + * Run the given select statement and call 'proc' on the resulting + * values (which must be in particular positions). + * + * @param plugin the plugin handle + * @param stmt select statement to run + * @param proc function to call on result + * @param proc_cls closure for proc + * @param ... arguments to initialize stmt + */ +static void +execute_select (struct Plugin *plugin, struct GNUNET_MysqlStatementHandle *stmt, + PluginDatumProcessor proc, void *proc_cls, ...) +{ + va_list ap; + int ret; + unsigned int type; + unsigned int priority; + unsigned int anonymity; + unsigned long long exp; + unsigned long hashSize; + unsigned long size; + unsigned long long uid; + char value[GNUNET_DATASTORE_MAX_VALUE_SIZE]; + GNUNET_HashCode key; + struct GNUNET_TIME_Absolute expiration; + MYSQL_BIND rbind[7]; + + hashSize = sizeof (GNUNET_HashCode); + memset (rbind, 0, sizeof (rbind)); + rbind[0].buffer_type = MYSQL_TYPE_LONG; + rbind[0].buffer = &type; + rbind[0].is_unsigned = 1; + rbind[1].buffer_type = MYSQL_TYPE_LONG; + rbind[1].buffer = &priority; + rbind[1].is_unsigned = 1; + rbind[2].buffer_type = MYSQL_TYPE_LONG; + rbind[2].buffer = &anonymity; + rbind[2].is_unsigned = 1; + rbind[3].buffer_type = MYSQL_TYPE_LONGLONG; + rbind[3].buffer = &exp; + rbind[3].is_unsigned = 1; + rbind[4].buffer_type = MYSQL_TYPE_BLOB; + rbind[4].buffer = &key; + rbind[4].buffer_length = hashSize; + rbind[4].length = &hashSize; + rbind[5].buffer_type = MYSQL_TYPE_BLOB; + rbind[5].buffer = value; + rbind[5].buffer_length = size = sizeof (value); + rbind[5].length = &size; + rbind[6].buffer_type = MYSQL_TYPE_LONGLONG; + rbind[6].buffer = &uid; + rbind[6].is_unsigned = 1; + + va_start (ap, proc_cls); + ret = prepared_statement_run_select_va (plugin, stmt, 7, rbind, ap); + va_end (ap); + if (ret <= 0) + { + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + GNUNET_assert (size <= sizeof (value)); + if ((rbind[4].buffer_length != sizeof (GNUNET_HashCode)) || + (hashSize != sizeof (GNUNET_HashCode))) + { + GNUNET_break (0); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } +#if DEBUG_MYSQL + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found %u-byte value under key `%s' with prio %u, anon %u, expire %llu selecting from gn090 table\n", + (unsigned int) size, GNUNET_h2s (&key), priority, anonymity, exp); +#endif + GNUNET_assert (size < MAX_DATUM_SIZE); + expiration.abs_value = exp; + ret = + proc (proc_cls, &key, size, value, type, priority, anonymity, expiration, + uid); + if (ret == GNUNET_NO) + { + do_delete_entry (plugin, uid); + if (size != 0) + plugin->env->duc (plugin->env->cls, -size); + } +} + + + +/** + * Get one of the results for a particular key in the datastore. + * + * @param cls closure + * @param offset offset of the result (modulo num-results); + * specific ordering does not matter for the offset + * @param key key to match, never NULL + * @param vhash hash of the value, maybe NULL (to + * match all values that have the right key). + * Note that for DBlocks there is no difference + * betwen key and vhash, but for other blocks + * there may be! + * @param type entries of which type are relevant? + * Use 0 for any type. + * @param proc function to call on the matching value, + * with NULL for if no value matches + * @param proc_cls closure for proc + */ +static void +mysql_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key, + const GNUNET_HashCode * vhash, + enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + int ret; + MYSQL_BIND cbind[1]; + long long total; + unsigned long hashSize; + unsigned long hashSize2; + unsigned long long off; + + GNUNET_assert (key != NULL); + GNUNET_assert (NULL != proc); + hashSize = sizeof (GNUNET_HashCode); + hashSize2 = sizeof (GNUNET_HashCode); + memset (cbind, 0, sizeof (cbind)); + total = -1; + cbind[0].buffer_type = MYSQL_TYPE_LONGLONG; + cbind[0].buffer = &total; + cbind[0].is_unsigned = GNUNET_NO; + if (type != 0) + { + if (vhash != NULL) + { + ret = + prepared_statement_run_select (plugin, + plugin-> + count_entry_by_hash_vhash_and_type, 1, + cbind, MYSQL_TYPE_BLOB, key, hashSize, + &hashSize, MYSQL_TYPE_BLOB, vhash, + hashSize2, &hashSize2, MYSQL_TYPE_LONG, + &type, GNUNET_YES, -1); + } + else + { + ret = + prepared_statement_run_select (plugin, + plugin->count_entry_by_hash_and_type, + 1, cbind, MYSQL_TYPE_BLOB, key, + hashSize, &hashSize, MYSQL_TYPE_LONG, + &type, GNUNET_YES, -1); + } + } + else + { + if (vhash != NULL) + { + ret = + prepared_statement_run_select (plugin, + plugin->count_entry_by_hash_and_vhash, + 1, cbind, MYSQL_TYPE_BLOB, key, + hashSize, &hashSize, MYSQL_TYPE_BLOB, + vhash, hashSize2, &hashSize2, -1); + + } + else + { + ret = + prepared_statement_run_select (plugin, plugin->count_entry_by_hash, 1, + cbind, MYSQL_TYPE_BLOB, key, hashSize, + &hashSize, -1); + } + } + if ((ret != GNUNET_OK) || (0 >= total)) + { + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + offset = offset % total; + off = (unsigned long long) offset; +#if DEBUG_MYSQL + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Obtaining %llu/%lld result for GET `%s'\n", off, total, + GNUNET_h2s (key)); +#endif + + if (type != GNUNET_BLOCK_TYPE_ANY) + { + if (NULL != vhash) + { + execute_select (plugin, plugin->select_entry_by_hash_vhash_and_type, proc, + proc_cls, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, + MYSQL_TYPE_BLOB, vhash, hashSize, &hashSize, + MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, + &off, GNUNET_YES, -1); + } + else + { + execute_select (plugin, plugin->select_entry_by_hash_and_type, proc, + proc_cls, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, + MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, + &off, GNUNET_YES, -1); + } + } + else + { + if (NULL != vhash) + { + execute_select (plugin, plugin->select_entry_by_hash_and_vhash, proc, + proc_cls, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, + MYSQL_TYPE_BLOB, vhash, hashSize, &hashSize, + MYSQL_TYPE_LONGLONG, &off, GNUNET_YES, -1); + } + else + { + execute_select (plugin, plugin->select_entry_by_hash, proc, proc_cls, + MYSQL_TYPE_BLOB, key, hashSize, &hashSize, + MYSQL_TYPE_LONGLONG, &off, GNUNET_YES, -1); + } + } +} + + +/** + * Get a zero-anonymity datum from the datastore. + * + * @param cls our "struct Plugin*" + * @param offset offset of the result + * @param type entries of which type should be considered? + * Use 0 for any type. + * @param proc function to call on a matching value or NULL + * @param proc_cls closure for iter + */ +static void +mysql_plugin_get_zero_anonymity (void *cls, uint64_t offset, + enum GNUNET_BLOCK_Type type, + PluginDatumProcessor proc, void *proc_cls) +{ + struct Plugin *plugin = cls; + unsigned long long rvalue = + (unsigned long long) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX); + + execute_select (plugin, plugin->zero_iter, proc, proc_cls, MYSQL_TYPE_LONG, + &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, &rvalue, GNUNET_YES, + MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, + &rvalue, GNUNET_YES, -1); +} + + +/** + * Context for 'repl_proc' function. + */ +struct ReplCtx +{ + + /** + * Plugin handle. + */ + struct Plugin *plugin; + + /** + * Function to call for the result (or the NULL). + */ + PluginDatumProcessor proc; + + /** + * Closure for proc. + */ + void *proc_cls; +}; + + +/** + * Wrapper for the processor for 'mysql_plugin_get_replication'. + * Decrements the replication counter and calls the original + * iterator. + * + * @param cls closure + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + * + * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue + * (continue on call to "next", of course), + * GNUNET_NO to delete the item and continue (if supported) + */ +static int +repl_proc (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct ReplCtx *rc = cls; + struct Plugin *plugin = rc->plugin; + unsigned long long oid; + int ret; + int iret; + + ret = + rc->proc (rc->proc_cls, key, size, data, type, priority, anonymity, + expiration, uid); + if (NULL != key) + { + oid = (unsigned long long) uid; + iret = + prepared_statement_run (plugin, plugin->dec_repl, NULL, + MYSQL_TYPE_LONGLONG, &oid, GNUNET_YES, -1); + if (iret == GNUNET_SYSERR) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to reduce replication counter\n"); + return GNUNET_SYSERR; + } + } + return ret; +} + + +/** + * Get a random item for replication. Returns a single, not expired, + * random item from those with the highest replication counters. The + * item's replication counter is decremented by one IF it was positive + * before. Call 'proc' with all values ZERO or NULL if the datastore + * is empty. + * + * @param cls closure + * @param proc function to call the value (once only). + * @param proc_cls closure for proc + */ +static void +mysql_plugin_get_replication (void *cls, PluginDatumProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + struct ReplCtx rc; + unsigned long long rvalue; + unsigned long repl; + MYSQL_BIND results; + + rc.plugin = plugin; + rc.proc = proc; + rc.proc_cls = proc_cls; + memset (&results, 0, sizeof (results)); + results.buffer_type = MYSQL_TYPE_LONG; + results.buffer = &repl; + results.is_unsigned = GNUNET_YES; + + if (1 != + prepared_statement_run_select (plugin, plugin->max_repl, 1, &results, -1)) + { + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + + rvalue = + (unsigned long long) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX); + execute_select (plugin, plugin->select_replication, &repl_proc, &rc, + MYSQL_TYPE_LONG, &repl, GNUNET_YES, MYSQL_TYPE_LONGLONG, + &rvalue, GNUNET_YES, MYSQL_TYPE_LONG, &repl, GNUNET_YES, + MYSQL_TYPE_LONGLONG, &rvalue, GNUNET_YES, -1); + +} + + +/** + * Get all of the keys in the datastore. + * + * @param cls closure + * @param proc function to call on each key + * @param proc_cls closure for proc + */ +static void +mysql_plugin_get_keys (void *cls, + PluginKeyProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + const char *query = "SELECT hash FROM gn090"; + int ret; + MYSQL_STMT *statement; + GNUNET_HashCode key; + MYSQL_BIND cbind[1]; + unsigned long length; + + statement = mysql_stmt_init (plugin->dbf); + if (statement == NULL) + { + iclose (plugin); + return; + } + if (mysql_stmt_prepare (statement, query, strlen (query))) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql", + _("Failed to prepare statement `%s'\n"), query); + LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", plugin); + mysql_stmt_close (statement); + iclose (plugin); + return; + } + GNUNET_assert (proc != NULL); + if (mysql_stmt_execute (statement)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' for `%s' failed at %s:%d with error: %s\n"), + "mysql_stmt_execute", query, __FILE__, __LINE__, + mysql_stmt_error (statement)); + mysql_stmt_close (statement); + iclose (plugin); + return; + } + memset (cbind, 0, sizeof (cbind)); + cbind[0].buffer_type = MYSQL_TYPE_BLOB; + cbind[0].buffer = &key; + cbind[0].buffer_length = sizeof (key); + cbind[0].length = &length; + cbind[0].is_unsigned = GNUNET_NO; + if (mysql_stmt_bind_result (statement, cbind)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed at %s:%d with error: %s\n"), + "mysql_stmt_bind_result", __FILE__, __LINE__, + mysql_stmt_error (statement)); + iclose (plugin); + return; + } + while (0 == (ret = mysql_stmt_fetch (statement))) + { + if (sizeof (GNUNET_HashCode) == length) + proc (proc_cls, &key, 1); + } + if (ret != MYSQL_NO_DATA) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed at %s:%d with error: %s\n"), + "mysql_stmt_fetch", __FILE__, __LINE__, + mysql_stmt_error (statement)); + mysql_stmt_close (statement); + iclose (plugin); + return; + } + mysql_stmt_close (statement); +} + + +/** + * Context for 'expi_proc' function. + */ +struct ExpiCtx +{ + + /** + * Plugin handle. + */ + struct Plugin *plugin; + + /** + * Function to call for the result (or the NULL). + */ + PluginDatumProcessor proc; + + /** + * Closure for proc. + */ + void *proc_cls; +}; + + + +/** + * Wrapper for the processor for 'mysql_plugin_get_expiration'. + * If no expired value was found, we do a second query for + * low-priority content. + * + * @param cls closure + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + * + * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue + * (continue on call to "next", of course), + * GNUNET_NO to delete the item and continue (if supported) + */ +static int +expi_proc (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct ExpiCtx *rc = cls; + struct Plugin *plugin = rc->plugin; + + if (NULL == key) + { + execute_select (plugin, plugin->select_priority, rc->proc, rc->proc_cls, + -1); + return GNUNET_SYSERR; + } + return rc->proc (rc->proc_cls, key, size, data, type, priority, anonymity, + expiration, uid); +} + + +/** + * Get a random item for expiration. + * Call 'proc' with all values ZERO or NULL if the datastore is empty. + * + * @param cls closure + * @param proc function to call the value (once only). + * @param proc_cls closure for proc + */ +static void +mysql_plugin_get_expiration (void *cls, PluginDatumProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + long long nt; + struct ExpiCtx rc; + + rc.plugin = plugin; + rc.proc = proc; + rc.proc_cls = proc_cls; + nt = (long long) GNUNET_TIME_absolute_get ().abs_value; + execute_select (plugin, plugin->select_expiration, expi_proc, &rc, + MYSQL_TYPE_LONGLONG, &nt, GNUNET_YES, -1); + +} + + +/** + * Drop database. + * + * @param cls the "struct Plugin*" + */ +static void +mysql_plugin_drop (void *cls) +{ + struct Plugin *plugin = cls; + + if (GNUNET_OK != run_statement (plugin, "DROP TABLE gn090")) + return; /* error */ + plugin->env->duc (plugin->env->cls, 0); +} + + +/** + * Entry point for the plugin. + * + * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*" + * @return our "struct Plugin*" + */ +void * +libgnunet_plugin_datastore_mysql_init (void *cls) +{ + struct GNUNET_DATASTORE_PluginEnvironment *env = cls; + struct GNUNET_DATASTORE_PluginFunctions *api; + struct Plugin *plugin; + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + plugin->cnffile = get_my_cnf_path (env->cfg); + if (GNUNET_OK != iopen (plugin)) + { + iclose (plugin); + GNUNET_free_non_null (plugin->cnffile); + GNUNET_free (plugin); + return NULL; + } +#define MRUNS(a) (GNUNET_OK != run_statement (plugin, a) ) +#define PINIT(a,b) (NULL == (a = prepared_statement_create(plugin, b))) + if (MRUNS + ("CREATE TABLE IF NOT EXISTS gn090 (" + " repl INT(11) UNSIGNED NOT NULL DEFAULT 0," + " type INT(11) UNSIGNED NOT NULL DEFAULT 0," + " prio INT(11) UNSIGNED NOT NULL DEFAULT 0," + " anonLevel INT(11) UNSIGNED NOT NULL DEFAULT 0," + " expire BIGINT UNSIGNED NOT NULL DEFAULT 0," + " rvalue BIGINT UNSIGNED NOT NULL," + " hash BINARY(64) NOT NULL DEFAULT ''," + " vhash BINARY(64) NOT NULL DEFAULT ''," + " value BLOB NOT NULL DEFAULT ''," " uid BIGINT NOT NULL AUTO_INCREMENT," + " PRIMARY KEY (uid)," " INDEX idx_hash (hash(64))," + " INDEX idx_hash_uid (hash(64),uid)," + " INDEX idx_hash_vhash (hash(64),vhash(64))," + " INDEX idx_hash_type_uid (hash(64),type,rvalue)," + " INDEX idx_prio (prio)," " INDEX idx_repl_rvalue (repl,rvalue)," + " INDEX idx_expire (expire)," + " INDEX idx_anonLevel_type_rvalue (anonLevel,type,rvalue)" + ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1") || + PINIT (plugin->insert_entry, INSERT_ENTRY) || + PINIT (plugin->delete_entry_by_uid, DELETE_ENTRY_BY_UID) || + PINIT (plugin->select_entry_by_hash, SELECT_ENTRY_BY_HASH) || + PINIT (plugin->select_entry_by_hash_and_vhash, + SELECT_ENTRY_BY_HASH_AND_VHASH) || + PINIT (plugin->select_entry_by_hash_and_type, + SELECT_ENTRY_BY_HASH_AND_TYPE) || + PINIT (plugin->select_entry_by_hash_vhash_and_type, + SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE) || + PINIT (plugin->count_entry_by_hash, COUNT_ENTRY_BY_HASH) || + PINIT (plugin->get_size, SELECT_SIZE) || + PINIT (plugin->count_entry_by_hash_and_vhash, + COUNT_ENTRY_BY_HASH_AND_VHASH) || + PINIT (plugin->count_entry_by_hash_and_type, COUNT_ENTRY_BY_HASH_AND_TYPE) + || PINIT (plugin->count_entry_by_hash_vhash_and_type, + COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE) || + PINIT (plugin->update_entry, UPDATE_ENTRY) || + PINIT (plugin->dec_repl, DEC_REPL) || + PINIT (plugin->zero_iter, SELECT_IT_NON_ANONYMOUS) || + PINIT (plugin->select_expiration, SELECT_IT_EXPIRATION) || + PINIT (plugin->select_priority, SELECT_IT_PRIORITY) || + PINIT (plugin->max_repl, SELECT_MAX_REPL) || + PINIT (plugin->select_replication, SELECT_IT_REPLICATION)) + { + iclose (plugin); + GNUNET_free_non_null (plugin->cnffile); + GNUNET_free (plugin); + return NULL; + } +#undef PINIT +#undef MRUNS + + api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions)); + api->cls = plugin; + api->estimate_size = &mysql_plugin_estimate_size; + api->put = &mysql_plugin_put; + api->update = &mysql_plugin_update; + api->get_key = &mysql_plugin_get_key; + api->get_replication = &mysql_plugin_get_replication; + api->get_expiration = &mysql_plugin_get_expiration; + api->get_zero_anonymity = &mysql_plugin_get_zero_anonymity; + api->get_keys = &mysql_plugin_get_keys; + api->drop = &mysql_plugin_drop; + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "mysql", + _("Mysql database running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * @param cls our "struct Plugin*" + * @return always NULL + */ +void * +libgnunet_plugin_datastore_mysql_done (void *cls) +{ + struct GNUNET_DATASTORE_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + struct GNUNET_MysqlStatementHandle *s; + + iclose (plugin); + while (NULL != (s = plugin->shead)) + { + GNUNET_CONTAINER_DLL_remove (plugin->shead, plugin->stail, s); + GNUNET_free (s->query); + GNUNET_free (s); + } + GNUNET_free_non_null (plugin->cnffile); + GNUNET_free (plugin); + GNUNET_free (api); + mysql_library_end (); + return NULL; +} + +/* end of plugin_datastore_mysql.c */ diff --git a/src/datastore/plugin_datastore_postgres.c b/src/datastore/plugin_datastore_postgres.c new file mode 100644 index 0000000..16393c2 --- /dev/null +++ b/src/datastore/plugin_datastore_postgres.c @@ -0,0 +1,1039 @@ +/* + This file is part of GNUnet + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datastore/plugin_datastore_postgres.c + * @brief postgres-based datastore backend + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_datastore_plugin.h" +#include + +#define DEBUG_POSTGRES GNUNET_EXTRA_LOGGING + +/** + * After how many ms "busy" should a DB operation fail for good? + * A low value makes sure that we are more responsive to requests + * (especially PUTs). A high value guarantees a higher success + * rate (SELECTs in iterate can take several seconds despite LIMIT=1). + * + * The default value of 1s should ensure that users do not experience + * huge latencies while at the same time allowing operations to succeed + * with reasonable probability. + */ +#define BUSY_TIMEOUT GNUNET_TIME_UNIT_SECONDS + + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + /** + * Our execution environment. + */ + struct GNUNET_DATASTORE_PluginEnvironment *env; + + /** + * Native Postgres database handle. + */ + PGconn *dbh; + +}; + + +/** + * Check if the result obtained from Postgres has + * the desired status code. If not, log an error, clear the + * result and return GNUNET_SYSERR. + * + * @param plugin global context + * @param ret result to check + * @param expected_status expected return value + * @param command name of SQL command that was run + * @param args arguments to SQL command + * @param line line number for error reporting + * @return GNUNET_OK if the result is acceptable + */ +static int +check_result (struct Plugin *plugin, PGresult * ret, int expected_status, + const char *command, const char *args, int line) +{ + if (ret == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "datastore-postgres", + "Postgres failed to allocate result for `%s:%s' at %d\n", + command, args, line); + return GNUNET_SYSERR; + } + if (PQresultStatus (ret) != expected_status) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "datastore-postgres", + _("`%s:%s' failed at %s:%d with error: %s"), command, args, + __FILE__, line, PQerrorMessage (plugin->dbh)); + PQclear (ret); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +/** + * Run simple SQL statement (without results). + * + * @param plugin global context + * @param sql statement to run + * @param line code line for error reporting + */ +static int +pq_exec (struct Plugin *plugin, const char *sql, int line) +{ + PGresult *ret; + + ret = PQexec (plugin->dbh, sql); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "PQexec", sql, line)) + return GNUNET_SYSERR; + PQclear (ret); + return GNUNET_OK; +} + +/** + * Prepare SQL statement. + * + * @param plugin global context + * @param name name for the prepared SQL statement + * @param sql SQL code to prepare + * @param nparams number of parameters in sql + * @param line code line for error reporting + * @return GNUNET_OK on success + */ +static int +pq_prepare (struct Plugin *plugin, const char *name, const char *sql, + int nparams, int line) +{ + PGresult *ret; + + ret = PQprepare (plugin->dbh, name, sql, nparams, NULL); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "PQprepare", sql, line)) + return GNUNET_SYSERR; + PQclear (ret); + return GNUNET_OK; +} + +/** + * @brief Get a database handle + * + * @param plugin global context + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +init_connection (struct Plugin *plugin) +{ + char *conninfo; + PGresult *ret; + + /* Open database and precompile statements */ + conninfo = NULL; + (void) GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, + "datastore-postgres", "CONFIG", + &conninfo); + plugin->dbh = PQconnectdb (conninfo == NULL ? "" : conninfo); + if (NULL == plugin->dbh) + { + /* FIXME: warn about out-of-memory? */ + GNUNET_free_non_null (conninfo); + return GNUNET_SYSERR; + } + if (PQstatus (plugin->dbh) != CONNECTION_OK) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "datastore-postgres", + _ + ("Unable to initialize Postgres with configuration `%s': %s"), + conninfo, PQerrorMessage (plugin->dbh)); + PQfinish (plugin->dbh); + plugin->dbh = NULL; + GNUNET_free_non_null (conninfo); + return GNUNET_SYSERR; + } + GNUNET_free_non_null (conninfo); + ret = + PQexec (plugin->dbh, + "CREATE TABLE gn090 (" " repl INTEGER NOT NULL DEFAULT 0," + " type INTEGER NOT NULL DEFAULT 0," + " prio INTEGER NOT NULL DEFAULT 0," + " anonLevel INTEGER NOT NULL DEFAULT 0," + " expire BIGINT NOT NULL DEFAULT 0," + " rvalue BIGINT NOT NULL DEFAULT 0," + " hash BYTEA NOT NULL DEFAULT ''," + " vhash BYTEA NOT NULL DEFAULT ''," + " value BYTEA NOT NULL DEFAULT '')" "WITH OIDS"); + if ((ret == NULL) || ((PQresultStatus (ret) != PGRES_COMMAND_OK) && (0 != strcmp ("42P07", /* duplicate table */ + PQresultErrorField + (ret, + PG_DIAG_SQLSTATE))))) + { + (void) check_result (plugin, ret, PGRES_COMMAND_OK, "CREATE TABLE", "gn090", + __LINE__); + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + if (PQresultStatus (ret) == PGRES_COMMAND_OK) + { + if ((GNUNET_OK != + pq_exec (plugin, "CREATE INDEX idx_hash ON gn090 (hash)", __LINE__)) || + (GNUNET_OK != + pq_exec (plugin, "CREATE INDEX idx_hash_vhash ON gn090 (hash,vhash)", + __LINE__)) || + (GNUNET_OK != + pq_exec (plugin, "CREATE INDEX idx_prio ON gn090 (prio)", __LINE__)) || + (GNUNET_OK != + pq_exec (plugin, "CREATE INDEX idx_expire ON gn090 (expire)", + __LINE__)) || + (GNUNET_OK != + pq_exec (plugin, + "CREATE INDEX idx_prio_anon ON gn090 (prio,anonLevel)", + __LINE__)) || + (GNUNET_OK != + pq_exec (plugin, + "CREATE INDEX idx_prio_hash_anon ON gn090 (prio,hash,anonLevel)", + __LINE__)) || + (GNUNET_OK != + pq_exec (plugin, "CREATE INDEX idx_repl_rvalue ON gn090 (repl,rvalue)", + __LINE__)) || + (GNUNET_OK != + pq_exec (plugin, "CREATE INDEX idx_expire_hash ON gn090 (expire,hash)", + __LINE__))) + { + PQclear (ret); + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + } + PQclear (ret); + ret = + PQexec (plugin->dbh, + "ALTER TABLE gn090 ALTER value SET STORAGE EXTERNAL"); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090", + __LINE__)) + { + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + PQclear (ret); + ret = PQexec (plugin->dbh, "ALTER TABLE gn090 ALTER hash SET STORAGE PLAIN"); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090", + __LINE__)) + { + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + PQclear (ret); + ret = PQexec (plugin->dbh, "ALTER TABLE gn090 ALTER vhash SET STORAGE PLAIN"); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090", + __LINE__)) + { + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + PQclear (ret); + if ((GNUNET_OK != + pq_prepare (plugin, "getvt", + "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " + "WHERE hash=$1 AND vhash=$2 AND type=$3 " + "ORDER BY oid ASC LIMIT 1 OFFSET $4", 4, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "gett", + "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " + "WHERE hash=$1 AND type=$2 " + "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "getv", + "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " + "WHERE hash=$1 AND vhash=$2 " + "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "get", + "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " + "WHERE hash=$1 " "ORDER BY oid ASC LIMIT 1 OFFSET $2", 2, + __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "put", + "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " + "VALUES ($1, $2, $3, $4, $5, RANDOM(), $6, $7, $8)", 9, + __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "update", + "UPDATE gn090 SET prio = prio + $1, expire = CASE WHEN expire < $2 THEN $2 ELSE expire END " + "WHERE oid = $3", 3, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "decrepl", + "UPDATE gn090 SET repl = GREATEST (repl - 1, 0) " + "WHERE oid = $1", 1, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "select_non_anonymous", + "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " + "WHERE anonLevel = 0 AND type = $1 ORDER BY oid DESC LIMIT 1 OFFSET $2", + 1, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "select_expiration_order", + "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " + "WHERE expire < $1 ORDER BY prio ASC LIMIT 1) " "UNION " + "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " + "ORDER BY prio ASC LIMIT 1) " "ORDER BY expire ASC LIMIT 1", + 1, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "select_replication_order", + "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " + "ORDER BY repl DESC,RANDOM() LIMIT 1", 0, __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "delrow", "DELETE FROM gn090 " "WHERE oid=$1", 1, + __LINE__)) || + (GNUNET_OK != + pq_prepare (plugin, "get_keys", "SELECT hash FROM gn090", 0, + __LINE__))) + { + PQfinish (plugin->dbh); + plugin->dbh = NULL; + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Delete the row identified by the given rowid (qid + * in postgres). + * + * @param plugin global context + * @param rowid which row to delete + * @return GNUNET_OK on success + */ +static int +delete_by_rowid (struct Plugin *plugin, unsigned int rowid) +{ + uint32_t browid; + const char *paramValues[] = { (const char *) &browid }; + int paramLengths[] = { sizeof (browid) }; + const int paramFormats[] = { 1 }; + PGresult *ret; + + browid = htonl (rowid); + ret = + PQexecPrepared (plugin->dbh, "delrow", 1, paramValues, paramLengths, + paramFormats, 1); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "PQexecPrepared", "delrow", + __LINE__)) + { + return GNUNET_SYSERR; + } + PQclear (ret); + return GNUNET_OK; +} + + +/** + * Get an estimate of how much space the database is + * currently using. + * + * @param cls our "struct Plugin*" + * @return number of bytes used on disk + */ +static unsigned long long +postgres_plugin_estimate_size (void *cls) +{ + struct Plugin *plugin = cls; + unsigned long long total; + PGresult *ret; + + ret = + PQexecParams (plugin->dbh, + "SELECT SUM(LENGTH(value))+256*COUNT(*) FROM gn090", 0, + NULL, NULL, NULL, NULL, 1); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_TUPLES_OK, "PQexecParams", "get_size", + __LINE__)) + { + return 0; + } + if ((PQntuples (ret) != 1) || (PQnfields (ret) != 1) || + (PQgetlength (ret, 0, 0) != sizeof (unsigned long long))) + { + GNUNET_break (0); + PQclear (ret); + return 0; + } + total = GNUNET_ntohll (*(const unsigned long long *) PQgetvalue (ret, 0, 0)); + PQclear (ret); + return total; +} + + +/** + * Store an item in the datastore. + * + * @param cls closure + * @param key key for the item + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param replication replication-level for the content + * @param expiration expiration time for the content + * @param msg set to error message + * @return GNUNET_OK on success + */ +static int +postgres_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + uint32_t replication, + struct GNUNET_TIME_Absolute expiration, char **msg) +{ + struct Plugin *plugin = cls; + GNUNET_HashCode vhash; + PGresult *ret; + uint32_t btype = htonl (type); + uint32_t bprio = htonl (priority); + uint32_t banon = htonl (anonymity); + uint32_t brepl = htonl (replication); + uint64_t bexpi = GNUNET_TIME_absolute_hton (expiration).abs_value__; + + const char *paramValues[] = { + (const char *) &brepl, + (const char *) &btype, + (const char *) &bprio, + (const char *) &banon, + (const char *) &bexpi, + (const char *) key, + (const char *) &vhash, + (const char *) data + }; + int paramLengths[] = { + sizeof (brepl), + sizeof (btype), + sizeof (bprio), + sizeof (banon), + sizeof (bexpi), + sizeof (GNUNET_HashCode), + sizeof (GNUNET_HashCode), + size + }; + const int paramFormats[] = { 1, 1, 1, 1, 1, 1, 1, 1 }; + + GNUNET_CRYPTO_hash (data, size, &vhash); + ret = + PQexecPrepared (plugin->dbh, "put", 8, paramValues, paramLengths, + paramFormats, 1); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "PQexecPrepared", "put", + __LINE__)) + return GNUNET_SYSERR; + PQclear (ret); + plugin->env->duc (plugin->env->cls, size + GNUNET_DATASTORE_ENTRY_OVERHEAD); +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", + "Stored %u bytes in database\n", (unsigned int) size); +#endif + return GNUNET_OK; +} + + +/** + * Function invoked to process the result and call + * the processor. + * + * @param plugin global plugin data + * @param proc function to call the value (once only). + * @param proc_cls closure for proc + * @param res result from exec + * @param line line number for error messages + */ +static void +process_result (struct Plugin *plugin, PluginDatumProcessor proc, + void *proc_cls, PGresult * res, int line) +{ + int iret; + enum GNUNET_BLOCK_Type type; + uint32_t anonymity; + uint32_t priority; + uint32_t size; + unsigned int rowid; + struct GNUNET_TIME_Absolute expiration_time; + GNUNET_HashCode key; + + if (GNUNET_OK != + check_result (plugin, res, PGRES_TUPLES_OK, "PQexecPrepared", "select", + line)) + { +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", + "Ending iteration (postgres error)\n"); +#endif + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + + if (0 == PQntuples (res)) + { + /* no result */ +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", + "Ending iteration (no more results)\n"); +#endif + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + PQclear (res); + return; + } + if ((1 != PQntuples (res)) || (7 != PQnfields (res)) || + (sizeof (uint32_t) != PQfsize (res, 0)) || + (sizeof (uint32_t) != PQfsize (res, 6))) + { + GNUNET_break (0); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + PQclear (res); + return; + } + rowid = ntohl (*(uint32_t *) PQgetvalue (res, 0, 6)); + if ((sizeof (uint32_t) != PQfsize (res, 0)) || + (sizeof (uint32_t) != PQfsize (res, 1)) || + (sizeof (uint32_t) != PQfsize (res, 2)) || + (sizeof (uint64_t) != PQfsize (res, 3)) || + (sizeof (GNUNET_HashCode) != PQgetlength (res, 0, 4))) + { + GNUNET_break (0); + PQclear (res); + delete_by_rowid (plugin, rowid); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + + type = ntohl (*(uint32_t *) PQgetvalue (res, 0, 0)); + priority = ntohl (*(uint32_t *) PQgetvalue (res, 0, 1)); + anonymity = ntohl (*(uint32_t *) PQgetvalue (res, 0, 2)); + expiration_time.abs_value = + GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, 0, 3)); + memcpy (&key, PQgetvalue (res, 0, 4), sizeof (GNUNET_HashCode)); + size = PQgetlength (res, 0, 5); +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", + "Found result of size %u bytes and type %u in database\n", + (unsigned int) size, (unsigned int) type); +#endif + iret = + proc (proc_cls, &key, size, PQgetvalue (res, 0, 5), + (enum GNUNET_BLOCK_Type) type, priority, anonymity, expiration_time, + rowid); + PQclear (res); + if (iret == GNUNET_NO) + { +#if DEBUG_POSTGRES + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Processor asked for item %u to be removed.\n", rowid); +#endif + if (GNUNET_OK == delete_by_rowid (plugin, rowid)) + { +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", + "Deleting %u bytes from database\n", + (unsigned int) size); +#endif + plugin->env->duc (plugin->env->cls, + -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); +#if DEBUG_POSTGRES + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", + "Deleted %u bytes from database\n", (unsigned int) size); +#endif + } + } +} + + +/** + * Iterate over the results for a particular key + * in the datastore. + * + * @param cls closure + * @param offset offset of the result (modulo num-results); + * specific ordering does not matter for the offset + * @param key maybe NULL (to match all entries) + * @param vhash hash of the value, maybe NULL (to + * match all values that have the right key). + * Note that for DBlocks there is no difference + * betwen key and vhash, but for other blocks + * there may be! + * @param type entries of which type are relevant? + * Use 0 for any type. + * @param proc function to call on the matching value; + * will be called once with a NULL if no value matches + * @param proc_cls closure for iter + */ +static void +postgres_plugin_get_key (void *cls, uint64_t offset, + const GNUNET_HashCode * key, + const GNUNET_HashCode * vhash, + enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + const int paramFormats[] = { 1, 1, 1, 1, 1 }; + int paramLengths[4]; + const char *paramValues[4]; + int nparams; + const char *pname; + PGresult *ret; + uint64_t total; + uint64_t blimit_off; + uint32_t btype; + + GNUNET_assert (key != NULL); + paramValues[0] = (const char *) key; + paramLengths[0] = sizeof (GNUNET_HashCode); + btype = htonl (type); + if (type != 0) + { + if (vhash != NULL) + { + paramValues[1] = (const char *) vhash; + paramLengths[1] = sizeof (GNUNET_HashCode); + paramValues[2] = (const char *) &btype; + paramLengths[2] = sizeof (btype); + paramValues[3] = (const char *) &blimit_off; + paramLengths[3] = sizeof (blimit_off); + nparams = 4; + pname = "getvt"; + ret = + PQexecParams (plugin->dbh, + "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2 AND type=$3", + 3, NULL, paramValues, paramLengths, paramFormats, 1); + } + else + { + paramValues[1] = (const char *) &btype; + paramLengths[1] = sizeof (btype); + paramValues[2] = (const char *) &blimit_off; + paramLengths[2] = sizeof (blimit_off); + nparams = 3; + pname = "gett"; + ret = + PQexecParams (plugin->dbh, + "SELECT count(*) FROM gn090 WHERE hash=$1 AND type=$2", + 2, NULL, paramValues, paramLengths, paramFormats, 1); + } + } + else + { + if (vhash != NULL) + { + paramValues[1] = (const char *) vhash; + paramLengths[1] = sizeof (GNUNET_HashCode); + paramValues[2] = (const char *) &blimit_off; + paramLengths[2] = sizeof (blimit_off); + nparams = 3; + pname = "getv"; + ret = + PQexecParams (plugin->dbh, + "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2", + 2, NULL, paramValues, paramLengths, paramFormats, 1); + } + else + { + paramValues[1] = (const char *) &blimit_off; + paramLengths[1] = sizeof (blimit_off); + nparams = 2; + pname = "get"; + ret = + PQexecParams (plugin->dbh, "SELECT count(*) FROM gn090 WHERE hash=$1", + 1, NULL, paramValues, paramLengths, paramFormats, 1); + } + } + if (GNUNET_OK != + check_result (plugin, ret, PGRES_TUPLES_OK, "PQexecParams", pname, + __LINE__)) + { + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + if ((PQntuples (ret) != 1) || (PQnfields (ret) != 1) || + (PQgetlength (ret, 0, 0) != sizeof (unsigned long long))) + { + GNUNET_break (0); + PQclear (ret); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + total = GNUNET_ntohll (*(const unsigned long long *) PQgetvalue (ret, 0, 0)); + PQclear (ret); + if (total == 0) + { + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + blimit_off = GNUNET_htonll (offset % total); + ret = + PQexecPrepared (plugin->dbh, pname, nparams, paramValues, paramLengths, + paramFormats, 1); + process_result (plugin, proc, proc_cls, ret, __LINE__); +} + + +/** + * Select a subset of the items in the datastore and call + * the given iterator for each of them. + * + * @param cls our "struct Plugin*" + * @param offset offset of the result (modulo num-results); + * specific ordering does not matter for the offset + * @param type entries of which type should be considered? + * Use 0 for any type. + * @param proc function to call on the matching value; + * will be called with a NULL if no value matches + * @param proc_cls closure for proc + */ +static void +postgres_plugin_get_zero_anonymity (void *cls, uint64_t offset, + enum GNUNET_BLOCK_Type type, + PluginDatumProcessor proc, void *proc_cls) +{ + struct Plugin *plugin = cls; + uint32_t btype; + uint64_t boff; + const int paramFormats[] = { 1, 1 }; + int paramLengths[] = { sizeof (btype), sizeof (boff) }; + const char *paramValues[] = { (const char *) &btype, (const char *) &boff }; + PGresult *ret; + + btype = htonl ((uint32_t) type); + boff = GNUNET_htonll (offset); + ret = + PQexecPrepared (plugin->dbh, "select_non_anonymous", 2, paramValues, + paramLengths, paramFormats, 1); + process_result (plugin, proc, proc_cls, ret, __LINE__); +} + + +/** + * Context for 'repl_iter' function. + */ +struct ReplCtx +{ + + /** + * Plugin handle. + */ + struct Plugin *plugin; + + /** + * Function to call for the result (or the NULL). + */ + PluginDatumProcessor proc; + + /** + * Closure for proc. + */ + void *proc_cls; +}; + + +/** + * Wrapper for the iterator for 'sqlite_plugin_replication_get'. + * Decrements the replication counter and calls the original + * iterator. + * + * @param cls closure + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + * + * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue + * (continue on call to "next", of course), + * GNUNET_NO to delete the item and continue (if supported) + */ +static int +repl_proc (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct ReplCtx *rc = cls; + struct Plugin *plugin = rc->plugin; + int ret; + PGresult *qret; + uint32_t boid; + + ret = + rc->proc (rc->proc_cls, key, size, data, type, priority, anonymity, + expiration, uid); + if (NULL != key) + { + boid = htonl ((uint32_t) uid); + const char *paramValues[] = { + (const char *) &boid, + }; + int paramLengths[] = { + sizeof (boid), + }; + const int paramFormats[] = { 1 }; + qret = + PQexecPrepared (plugin->dbh, "decrepl", 1, paramValues, paramLengths, + paramFormats, 1); + if (GNUNET_OK != + check_result (plugin, qret, PGRES_COMMAND_OK, "PQexecPrepared", + "decrepl", __LINE__)) + return GNUNET_SYSERR; + PQclear (qret); + } + return ret; +} + + +/** + * Get a random item for replication. Returns a single, not expired, random item + * from those with the highest replication counters. The item's + * replication counter is decremented by one IF it was positive before. + * Call 'proc' with all values ZERO or NULL if the datastore is empty. + * + * @param cls closure + * @param proc function to call the value (once only). + * @param proc_cls closure for proc + */ +static void +postgres_plugin_get_replication (void *cls, PluginDatumProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + struct ReplCtx rc; + PGresult *ret; + + rc.plugin = plugin; + rc.proc = proc; + rc.proc_cls = proc_cls; + ret = + PQexecPrepared (plugin->dbh, "select_replication_order", 0, NULL, NULL, + NULL, 1); + process_result (plugin, &repl_proc, &rc, ret, __LINE__); +} + + +/** + * Get a random item for expiration. + * Call 'proc' with all values ZERO or NULL if the datastore is empty. + * + * @param cls closure + * @param proc function to call the value (once only). + * @param proc_cls closure for proc + */ +static void +postgres_plugin_get_expiration (void *cls, PluginDatumProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + uint64_t btime; + const int paramFormats[] = { 1 }; + int paramLengths[] = { sizeof (btime) }; + const char *paramValues[] = { (const char *) &btime }; + PGresult *ret; + + btime = GNUNET_htonll (GNUNET_TIME_absolute_get ().abs_value); + ret = + PQexecPrepared (plugin->dbh, "select_expiration_order", 1, paramValues, + paramLengths, paramFormats, 1); + process_result (plugin, proc, proc_cls, ret, __LINE__); +} + + +/** + * Update the priority for a particular key in the datastore. If + * the expiration time in value is different than the time found in + * the datastore, the higher value should be kept. For the + * anonymity level, the lower value is to be used. The specified + * priority should be added to the existing priority, ignoring the + * priority in value. + * + * Note that it is possible for multiple values to match this put. + * In that case, all of the respective values are updated. + * + * @param cls our "struct Plugin*" + * @param uid unique identifier of the datum + * @param delta by how much should the priority + * change? If priority + delta < 0 the + * priority should be set to 0 (never go + * negative). + * @param expire new expiration time should be the + * MAX of any existing expiration time and + * this value + * @param msg set to error message + * @return GNUNET_OK on success + */ +static int +postgres_plugin_update (void *cls, uint64_t uid, int delta, + struct GNUNET_TIME_Absolute expire, char **msg) +{ + struct Plugin *plugin = cls; + PGresult *ret; + int32_t bdelta = (int32_t) htonl ((uint32_t) delta); + uint32_t boid = htonl ((uint32_t) uid); + uint64_t bexpire = GNUNET_TIME_absolute_hton (expire).abs_value__; + + const char *paramValues[] = { + (const char *) &bdelta, + (const char *) &bexpire, + (const char *) &boid, + }; + int paramLengths[] = { + sizeof (bdelta), + sizeof (bexpire), + sizeof (boid), + }; + const int paramFormats[] = { 1, 1, 1 }; + + ret = + PQexecPrepared (plugin->dbh, "update", 3, paramValues, paramLengths, + paramFormats, 1); + if (GNUNET_OK != + check_result (plugin, ret, PGRES_COMMAND_OK, "PQexecPrepared", "update", + __LINE__)) + return GNUNET_SYSERR; + PQclear (ret); + return GNUNET_OK; +} + + + +/** + * Get all of the keys in the datastore. + * + * @param cls closure + * @param proc function to call on each key + * @param proc_cls closure for proc + */ +static void +postgres_plugin_get_keys (void *cls, + PluginKeyProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + int ret; + int i; + GNUNET_HashCode key; + PGresult * res; + + res = PQexecPrepared (plugin->dbh, "get_keys", 0, NULL, NULL, NULL, 1); + ret = PQntuples (res); + for (i=0;ienv = env; + if (GNUNET_OK != init_connection (plugin)) + { + GNUNET_free (plugin); + return NULL; + } + api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions)); + api->cls = plugin; + api->estimate_size = &postgres_plugin_estimate_size; + api->put = &postgres_plugin_put; + api->update = &postgres_plugin_update; + api->get_key = &postgres_plugin_get_key; + api->get_replication = &postgres_plugin_get_replication; + api->get_expiration = &postgres_plugin_get_expiration; + api->get_zero_anonymity = &postgres_plugin_get_zero_anonymity; + api->get_keys = &postgres_plugin_get_keys; + api->drop = &postgres_plugin_drop; + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "datastore-postgres", + _("Postgres database running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * @param cls our "struct Plugin*" + * @return always NULL + */ +void * +libgnunet_plugin_datastore_postgres_done (void *cls) +{ + struct GNUNET_DATASTORE_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + PQfinish (plugin->dbh); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + +/* end of plugin_datastore_postgres.c */ diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c new file mode 100644 index 0000000..cd5ae39 --- /dev/null +++ b/src/datastore/plugin_datastore_sqlite.c @@ -0,0 +1,1264 @@ + /* + * This file is part of GNUnet + * (C) 2009, 2011 Christian Grothoff (and other contributing authors) + * + * GNUnet is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 3, or (at your + * option) any later version. + * + * GNUnet is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNUnet; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * @file datastore/plugin_datastore_sqlite.c + * @brief sqlite-based datastore backend + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_datastore_plugin.h" +#include + +/** + * Enable or disable logging debug messages. + */ +#define DEBUG_SQLITE GNUNET_EXTRA_LOGGING + +/** + * We allocate items on the stack at times. To prevent a stack + * overflow, we impose a limit on the maximum size for the data per + * item. 64k should be enough. + */ +#define MAX_ITEM_SIZE 65536 + +/** + * After how many ms "busy" should a DB operation fail for good? + * A low value makes sure that we are more responsive to requests + * (especially PUTs). A high value guarantees a higher success + * rate (SELECTs in iterate can take several seconds despite LIMIT=1). + * + * The default value of 250ms should ensure that users do not experience + * huge latencies while at the same time allowing operations to succeed + * with reasonable probability. + */ +#define BUSY_TIMEOUT_MS 250 + + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' on file 'filename' + * with the message given by strerror(errno). + */ +#define LOG_SQLITE(db, msg, level, cmd) do { GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); if (msg != NULL) GNUNET_asprintf(msg, _("`%s' failed at %s:%u with error: %s"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0) + + + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + /** + * Our execution environment. + */ + struct GNUNET_DATASTORE_PluginEnvironment *env; + + /** + * Database filename. + */ + char *fn; + + /** + * Native SQLite database handle. + */ + sqlite3 *dbh; + + /** + * Precompiled SQL for deletion. + */ + sqlite3_stmt *delRow; + + /** + * Precompiled SQL for update. + */ + sqlite3_stmt *updPrio; + + /** + * Get maximum repl value in database. + */ + sqlite3_stmt *maxRepl; + + /** + * Precompiled SQL for replication decrement. + */ + sqlite3_stmt *updRepl; + + /** + * Precompiled SQL for replication selection. + */ + sqlite3_stmt *selRepl; + + /** + * Precompiled SQL for expiration selection. + */ + sqlite3_stmt *selExpi; + + /** + * Precompiled SQL for expiration selection. + */ + sqlite3_stmt *selZeroAnon; + + /** + * Precompiled SQL for insertion. + */ + sqlite3_stmt *insertContent; + + /** + * Should the database be dropped on shutdown? + */ + int drop_on_shutdown; + +}; + + +/** + * @brief Prepare a SQL statement + * + * @param dbh handle to the database + * @param zSql SQL statement, UTF-8 encoded + * @param ppStmt set to the prepared statement + * @return 0 on success + */ +static int +sq_prepare (sqlite3 * dbh, const char *zSql, sqlite3_stmt ** ppStmt) +{ + char *dummy; + int result; + + result = + sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt, + (const char **) &dummy); +#if DEBUG_SQLITE && 0 + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result); +#endif + return result; +} + + +/** + * Create our database indices. + * + * @param dbh handle to the database + */ +static void +create_indices (sqlite3 * dbh) +{ + /* create indices */ + if ((SQLITE_OK != + sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_hash ON gn090 (hash)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS idx_hash_vhash ON gn090 (hash,vhash)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS idx_expire_repl ON gn090 (expire ASC,repl DESC)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS idx_comb ON gn090 (anonLevel ASC,expire ASC,prio,type,hash)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS idx_anon_type_hash ON gn090 (anonLevel ASC,type,hash)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS idx_expire ON gn090 (expire ASC)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn090 (repl,rvalue)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS idx_repl ON gn090 (repl DESC)", + NULL, NULL, NULL))) + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite", + "Failed to create indices: %s\n", sqlite3_errmsg (dbh)); +} + + +#if 0 +#define CHECK(a) GNUNET_break(a) +#define ENULL NULL +#else +#define ENULL &e +#define ENULL_DEFINED 1 +#define CHECK(a) if (! a) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); } +#endif + + +/** + * Initialize the database connections and associated + * data structures (create tables and indices + * as needed as well). + * + * @param cfg our configuration + * @param plugin the plugin context (state for this module) + * @return GNUNET_OK on success + */ +static int +database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct Plugin *plugin) +{ + sqlite3_stmt *stmt; + char *afsdir; + +#if ENULL_DEFINED + char *e; +#endif + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "datastore-sqlite", + "FILENAME", &afsdir)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite", + _ + ("Option `%s' in section `%s' missing in configuration!\n"), + "FILENAME", "datastore-sqlite"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != GNUNET_DISK_file_test (afsdir)) + { + if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) + { + GNUNET_break (0); + GNUNET_free (afsdir); + return GNUNET_SYSERR; + } + /* database is new or got deleted, reset payload to zero! */ + plugin->env->duc (plugin->env->cls, 0); + } +#ifdef ENABLE_NLS + plugin->fn = + GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), nl_langinfo (CODESET)); +#else + plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), "UTF-8"); /* good luck */ +#endif + GNUNET_free (afsdir); + + /* Open database and precompile statements */ + if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite", + _("Unable to initialize SQLite: %s.\n"), + sqlite3_errmsg (plugin->dbh)); + return GNUNET_SYSERR; + } + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA synchronous=OFF", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL, + NULL, ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA count_changes=OFF", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA page_size=4092", NULL, NULL, + ENULL)); + + CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS)); + + + /* We have to do it here, because otherwise precompiling SQL might fail */ + CHECK (SQLITE_OK == + sq_prepare (plugin->dbh, + "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn090'", + &stmt)); + if ((sqlite3_step (stmt) == SQLITE_DONE) && + (sqlite3_exec + (plugin->dbh, + "CREATE TABLE gn090 (" " repl INT4 NOT NULL DEFAULT 0," + " type INT4 NOT NULL DEFAULT 0," " prio INT4 NOT NULL DEFAULT 0," + " anonLevel INT4 NOT NULL DEFAULT 0," + " expire INT8 NOT NULL DEFAULT 0," " rvalue INT8 NOT NULL," + " hash TEXT NOT NULL DEFAULT ''," " vhash TEXT NOT NULL DEFAULT ''," + " value BLOB NOT NULL DEFAULT '')", NULL, NULL, NULL) != SQLITE_OK)) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec"); + sqlite3_finalize (stmt); + return GNUNET_SYSERR; + } + sqlite3_finalize (stmt); + create_indices (plugin->dbh); + + if ((sq_prepare + (plugin->dbh, + "UPDATE gn090 " + "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?", + &plugin->updPrio) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?", + &plugin->updRepl) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " +#if SQLITE_VERSION_NUMBER >= 3007000 + "INDEXED BY idx_repl_rvalue " +#endif + "WHERE repl=?2 AND " " (rvalue>=?1 OR " + " NOT EXISTS (SELECT 1 FROM gn090 " +#if SQLITE_VERSION_NUMBER >= 3007000 + "INDEXED BY idx_repl_rvalue " +#endif + "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) " + "ORDER BY rvalue ASC LIMIT 1", &plugin->selRepl) != SQLITE_OK) || + (sq_prepare (plugin->dbh, "SELECT MAX(repl) FROM gn090" +#if SQLITE_VERSION_NUMBER >= 3007000 + " INDEXED BY idx_repl_rvalue" +#endif + "", &plugin->maxRepl) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " +#if SQLITE_VERSION_NUMBER >= 3007000 + "INDEXED BY idx_expire " +#endif + "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) " + "ORDER BY expire ASC LIMIT 1", &plugin->selExpi) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " +#if SQLITE_VERSION_NUMBER >= 3007000 + "INDEXED BY idx_anon_type_hash " +#endif + "WHERE (anonLevel = 0 AND type=?1) " + "ORDER BY hash DESC LIMIT 1 OFFSET ?2", + &plugin->selZeroAnon) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + &plugin->insertContent) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, "DELETE FROM gn090 WHERE _ROWID_ = ?", + &plugin->delRow) != SQLITE_OK)) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "precompiling"); + return GNUNET_SYSERR; + } + + return GNUNET_OK; +} + + +/** + * Shutdown database connection and associate data + * structures. + * @param plugin the plugin context (state for this module) + */ +static void +database_shutdown (struct Plugin *plugin) +{ + int result; + +#if SQLITE_VERSION_NUMBER >= 3007000 + sqlite3_stmt *stmt; +#endif + + if (plugin->delRow != NULL) + sqlite3_finalize (plugin->delRow); + if (plugin->updPrio != NULL) + sqlite3_finalize (plugin->updPrio); + if (plugin->updRepl != NULL) + sqlite3_finalize (plugin->updRepl); + if (plugin->selRepl != NULL) + sqlite3_finalize (plugin->selRepl); + if (plugin->maxRepl != NULL) + sqlite3_finalize (plugin->maxRepl); + if (plugin->selExpi != NULL) + sqlite3_finalize (plugin->selExpi); + if (plugin->selZeroAnon != NULL) + sqlite3_finalize (plugin->selZeroAnon); + if (plugin->insertContent != NULL) + sqlite3_finalize (plugin->insertContent); + result = sqlite3_close (plugin->dbh); +#if SQLITE_VERSION_NUMBER >= 3007000 + if (result == SQLITE_BUSY) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", + _ + ("Tried to close sqlite without finalizing all prepared statements.\n")); + stmt = sqlite3_next_stmt (plugin->dbh, NULL); + while (stmt != NULL) + { +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "Closing statement %p\n", stmt); +#endif + result = sqlite3_finalize (stmt); + if (result != SQLITE_OK) + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", + "Failed to close statement %p: %d\n", stmt, result); + stmt = sqlite3_next_stmt (plugin->dbh, NULL); + } + result = sqlite3_close (plugin->dbh); + } +#endif + if (SQLITE_OK != result) + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); + + GNUNET_free_non_null (plugin->fn); +} + + +/** + * Delete the database entry with the given + * row identifier. + * + * @param plugin the plugin context (state for this module) + * @param rid the ID of the row to delete + */ +static int +delete_by_rowid (struct Plugin *plugin, unsigned long long rid) +{ + if (SQLITE_OK != sqlite3_bind_int64 (plugin->delRow, 1, rid)) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (plugin->delRow)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_SYSERR; + } + if (SQLITE_DONE != sqlite3_step (plugin->delRow)) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + if (SQLITE_OK != sqlite3_reset (plugin->delRow)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_SYSERR; + } + if (SQLITE_OK != sqlite3_reset (plugin->delRow)) + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_OK; +} + + +/** + * Store an item in the datastore. + * + * @param cls closure + * @param key key for the item + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param replication replication-level for the content + * @param expiration expiration time for the content + * @param msg set to an error message + * @return GNUNET_OK on success + */ +static int +sqlite_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, uint32_t replication, + struct GNUNET_TIME_Absolute expiration, char **msg) +{ + struct Plugin *plugin = cls; + int n; + int ret; + sqlite3_stmt *stmt; + GNUNET_HashCode vhash; + uint64_t rvalue; + + if (size > MAX_ITEM_SIZE) + return GNUNET_SYSERR; +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "Storing in database block with type %u/key `%s'/priority %u/expiration in %llu ms (%lld).\n", + type, GNUNET_h2s (key), priority, + (unsigned long long) + GNUNET_TIME_absolute_get_remaining (expiration).rel_value, + (long long) expiration.abs_value); +#endif + GNUNET_CRYPTO_hash (data, size, &vhash); + stmt = plugin->insertContent; + rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); + if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, replication)) || + (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || + (SQLITE_OK != sqlite3_bind_int (stmt, 3, priority)) || + (SQLITE_OK != sqlite3_bind_int (stmt, 4, anonymity)) || + (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, expiration.abs_value)) || + (SQLITE_OK != sqlite3_bind_int64 (stmt, 6, rvalue)) || + (SQLITE_OK != + sqlite3_bind_blob (stmt, 7, key, sizeof (GNUNET_HashCode), + SQLITE_TRANSIENT)) || + (SQLITE_OK != + sqlite3_bind_blob (stmt, 8, &vhash, sizeof (GNUNET_HashCode), + SQLITE_TRANSIENT)) || + (SQLITE_OK != sqlite3_bind_blob (stmt, 9, data, size, SQLITE_TRANSIENT))) + { + LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_SYSERR; + } + n = sqlite3_step (stmt); + switch (n) + { + case SQLITE_DONE: + plugin->env->duc (plugin->env->cls, size + GNUNET_DATASTORE_ENTRY_OVERHEAD); +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "Stored new entry (%u bytes)\n", + size + GNUNET_DATASTORE_ENTRY_OVERHEAD); +#endif + ret = GNUNET_OK; + break; + case SQLITE_BUSY: + GNUNET_break (0); + LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + ret = GNUNET_SYSERR; + break; + default: + LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + database_shutdown (plugin); + database_setup (plugin->env->cfg, plugin); + return GNUNET_SYSERR; + } + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return ret; +} + + +/** + * Update the priority for a particular key in the datastore. If + * the expiration time in value is different than the time found in + * the datastore, the higher value should be kept. For the + * anonymity level, the lower value is to be used. The specified + * priority should be added to the existing priority, ignoring the + * priority in value. + * + * Note that it is possible for multiple values to match this put. + * In that case, all of the respective values are updated. + * + * @param cls the plugin context (state for this module) + * @param uid unique identifier of the datum + * @param delta by how much should the priority + * change? If priority + delta < 0 the + * priority should be set to 0 (never go + * negative). + * @param expire new expiration time should be the + * MAX of any existing expiration time and + * this value + * @param msg set to an error message + * @return GNUNET_OK on success + */ +static int +sqlite_plugin_update (void *cls, uint64_t uid, int delta, + struct GNUNET_TIME_Absolute expire, char **msg) +{ + struct Plugin *plugin = cls; + int n; + + if ((SQLITE_OK != sqlite3_bind_int (plugin->updPrio, 1, delta)) || + (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 2, expire.abs_value)) + || (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 3, uid))) + { + LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (plugin->updPrio)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_SYSERR; + + } + n = sqlite3_step (plugin->updPrio); + if (SQLITE_OK != sqlite3_reset (plugin->updPrio)) + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + switch (n) + { + case SQLITE_DONE: +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Block updated\n"); +#endif + return GNUNET_OK; + case SQLITE_BUSY: + LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_NO; + default: + LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_SYSERR; + } +} + + +/** + * Execute statement that gets a row and call the callback + * with the result. Resets the statement afterwards. + * + * @param plugin the plugin + * @param stmt the statement + * @param proc processor to call + * @param proc_cls closure for 'proc' + */ +static void +execute_get (struct Plugin *plugin, sqlite3_stmt * stmt, + PluginDatumProcessor proc, void *proc_cls) +{ + int n; + struct GNUNET_TIME_Absolute expiration; + unsigned long long rowid; + unsigned int size; + int ret; + + n = sqlite3_step (stmt); + switch (n) + { + case SQLITE_ROW: + size = sqlite3_column_bytes (stmt, 5); + rowid = sqlite3_column_int64 (stmt, 6); + if (sqlite3_column_bytes (stmt, 4) != sizeof (GNUNET_HashCode)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", + _ + ("Invalid data in database. Trying to fix (by deletion).\n")); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + if (GNUNET_OK == delete_by_rowid (plugin, rowid)) + plugin->env->duc (plugin->env->cls, + -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); + break; + } + expiration.abs_value = sqlite3_column_int64 (stmt, 3); +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "Found reply in database with expiration %llu\n", + (unsigned long long) expiration.abs_value); +#endif + ret = proc (proc_cls, sqlite3_column_blob (stmt, 4) /* key */ , + size, sqlite3_column_blob (stmt, 5) /* data */ , + sqlite3_column_int (stmt, 0) /* type */ , + sqlite3_column_int (stmt, 1) /* priority */ , + sqlite3_column_int (stmt, 2) /* anonymity */ , + expiration, rowid); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + if ((GNUNET_NO == ret) && (GNUNET_OK == delete_by_rowid (plugin, rowid))) + plugin->env->duc (plugin->env->cls, + -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); + return; + case SQLITE_DONE: + /* database must be empty */ + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + break; + case SQLITE_BUSY: + case SQLITE_ERROR: + case SQLITE_MISUSE: + default: + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + GNUNET_break (0); + database_shutdown (plugin); + database_setup (plugin->env->cfg, plugin); + break; + } + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); +} + + + +/** + * Select a subset of the items in the datastore and call + * the given processor for the item. + * + * @param cls our plugin context + * @param offset offset of the result (modulo num-results); + * specific ordering does not matter for the offset + * @param type entries of which type should be considered? + * Use 0 for any type. + * @param proc function to call on each matching value; + * will be called once with a NULL value at the end + * @param proc_cls closure for proc + */ +static void +sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset, + enum GNUNET_BLOCK_Type type, + PluginDatumProcessor proc, void *proc_cls) +{ + struct Plugin *plugin = cls; + sqlite3_stmt *stmt; + + GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY); + stmt = plugin->selZeroAnon; + if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) || + (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, offset))) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + execute_get (plugin, stmt, proc, proc_cls); +} + + + +/** + * Get results for a particular key in the datastore. + * + * @param cls closure + * @param offset offset (mod count). + * @param key key to match, never NULL + * @param vhash hash of the value, maybe NULL (to + * match all values that have the right key). + * Note that for DBlocks there is no difference + * betwen key and vhash, but for other blocks + * there may be! + * @param type entries of which type are relevant? + * Use 0 for any type. + * @param proc function to call on each matching value; + * will be called once with a NULL value at the end + * @param proc_cls closure for proc + */ +static void +sqlite_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key, + const GNUNET_HashCode * vhash, + enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + int ret; + int total; + int limit_off; + unsigned int sqoff; + sqlite3_stmt *stmt; + char scratch[256]; + + GNUNET_assert (proc != NULL); + GNUNET_assert (key != NULL); + GNUNET_snprintf (scratch, sizeof (scratch), + "SELECT count(*) FROM gn090 WHERE hash=?%s%s", + vhash == NULL ? "" : " AND vhash=?", + type == 0 ? "" : " AND type=?"); + if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite_prepare"); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + sqoff = 1; + ret = + sqlite3_bind_blob (stmt, sqoff++, key, sizeof (GNUNET_HashCode), + SQLITE_TRANSIENT); + if ((vhash != NULL) && (ret == SQLITE_OK)) + ret = + sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (GNUNET_HashCode), + SQLITE_TRANSIENT); + if ((type != 0) && (ret == SQLITE_OK)) + ret = sqlite3_bind_int (stmt, sqoff++, type); + if (SQLITE_OK != ret) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_bind"); + sqlite3_finalize (stmt); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + ret = sqlite3_step (stmt); + if (ret != SQLITE_ROW) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite_step"); + sqlite3_finalize (stmt); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + total = sqlite3_column_int (stmt, 0); + sqlite3_finalize (stmt); + if (0 == total) + { + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + limit_off = (int) (offset % total); + if (limit_off < 0) + limit_off += total; + GNUNET_snprintf (scratch, sizeof (scratch), + "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ " + "FROM gn090 WHERE hash=?%s%s " + "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", + vhash == NULL ? "" : " AND vhash=?", + type == 0 ? "" : " AND type=?"); + if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite_prepare"); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + sqoff = 1; + ret = + sqlite3_bind_blob (stmt, sqoff++, key, sizeof (GNUNET_HashCode), + SQLITE_TRANSIENT); + if ((vhash != NULL) && (ret == SQLITE_OK)) + ret = + sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (GNUNET_HashCode), + SQLITE_TRANSIENT); + if ((type != 0) && (ret == SQLITE_OK)) + ret = sqlite3_bind_int (stmt, sqoff++, type); + if (ret == SQLITE_OK) + ret = sqlite3_bind_int64 (stmt, sqoff++, limit_off); + if (ret != SQLITE_OK) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite_bind"); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + execute_get (plugin, stmt, proc, proc_cls); + sqlite3_finalize (stmt); +} + + + +/** + * Context for 'repl_proc' function. + */ +struct ReplCtx +{ + + /** + * Function to call for the result (or the NULL). + */ + PluginDatumProcessor proc; + + /** + * Closure for proc. + */ + void *proc_cls; + + /** + * UID to use. + */ + uint64_t uid; + + /** + * Yes if UID was set. + */ + int have_uid; +}; + + +/** + * Wrapper for the processor for 'sqlite_plugin_replication_get'. + * Decrements the replication counter and calls the original + * processor. + * + * @param cls closure + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + * + * @return GNUNET_OK for normal return, + * GNUNET_NO to delete the item + */ +static int +repl_proc (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct ReplCtx *rc = cls; + int ret; + + ret = + rc->proc (rc->proc_cls, key, size, data, type, priority, anonymity, + expiration, uid); + if (key != NULL) + { + rc->uid = uid; + rc->have_uid = GNUNET_YES; + } + return ret; +} + + +/** + * Get a random item for replication. Returns a single random item + * from those with the highest replication counters. The item's + * replication counter is decremented by one IF it was positive before. + * Call 'proc' with all values ZERO or NULL if the datastore is empty. + * + * @param cls closure + * @param proc function to call the value (once only). + * @param proc_cls closure for proc + */ +static void +sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + struct ReplCtx rc; + uint64_t rvalue; + uint32_t repl; + sqlite3_stmt *stmt; + +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "Getting random block based on replication order.\n"); +#endif + rc.have_uid = GNUNET_NO; + rc.proc = proc; + rc.proc_cls = proc_cls; + stmt = plugin->maxRepl; + if (SQLITE_ROW != sqlite3_step (stmt)) + { + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + /* DB empty */ + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + repl = sqlite3_column_int (stmt, 0); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + stmt = plugin->selRepl; + rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); + if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, rvalue)) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + if (SQLITE_OK != sqlite3_bind_int (stmt, 2, repl)) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + execute_get (plugin, stmt, &repl_proc, &rc); + if (GNUNET_YES == rc.have_uid) + { + if (SQLITE_OK != sqlite3_bind_int64 (plugin->updRepl, 1, rc.uid)) + { + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (plugin->updRepl)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return; + } + if (SQLITE_DONE != sqlite3_step (plugin->updRepl)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + if (SQLITE_OK != sqlite3_reset (plugin->updRepl)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + } +} + + + +/** + * Get a random item that has expired or has low priority. + * Call 'proc' with all values ZERO or NULL if the datastore is empty. + * + * @param cls closure + * @param proc function to call the value (once only). + * @param proc_cls closure for proc + */ +static void +sqlite_plugin_get_expiration (void *cls, PluginDatumProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + sqlite3_stmt *stmt; + struct GNUNET_TIME_Absolute now; + +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "Getting random block based on expiration and priority order.\n"); +#endif + now = GNUNET_TIME_absolute_get (); + stmt = plugin->selExpi; + if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, now.abs_value)) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, NULL, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); + return; + } + execute_get (plugin, stmt, proc, proc_cls); +} + + + +/** + * Get all of the keys in the datastore. + * + * @param cls closure + * @param proc function to call on each key + * @param proc_cls closure for proc + */ +static void +sqlite_plugin_get_keys (void *cls, + PluginKeyProcessor proc, + void *proc_cls) +{ + struct Plugin *plugin = cls; + const GNUNET_HashCode *key; + sqlite3_stmt *stmt; + int ret; + + GNUNET_assert (proc != NULL); + if (sq_prepare (plugin->dbh, "SELECT hash FROM gn090", &stmt) != SQLITE_OK) + { + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite_prepare"); + return; + } + while (SQLITE_ROW == (ret = sqlite3_step (stmt))) + { + key = sqlite3_column_blob (stmt, 1); + if (sizeof (GNUNET_HashCode) == sqlite3_column_bytes (stmt, 1)) + proc (proc_cls, key, 1); + } + if (SQLITE_DONE != ret) + LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); + sqlite3_finalize (stmt); +} + + +/** + * Drop database. + * + * @param cls our plugin context + */ +static void +sqlite_plugin_drop (void *cls) +{ + struct Plugin *plugin = cls; + + plugin->drop_on_shutdown = GNUNET_YES; +} + + +/** + * Get an estimate of how much space the database is + * currently using. + * + * @param cls the 'struct Plugin' + * @return the size of the database on disk (estimate) + */ +static unsigned long long +sqlite_plugin_estimate_size (void *cls) +{ + struct Plugin *plugin = cls; + sqlite3_stmt *stmt; + uint64_t pages; + uint64_t page_size; + +#if ENULL_DEFINED + char *e; +#endif + + if (SQLITE_VERSION_NUMBER < 3006000) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "datastore-sqlite", + _ + ("sqlite version to old to determine size, assuming zero\n")); + return 0; + } + CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "VACUUM", NULL, NULL, ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL, + NULL, ENULL)); + CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_count", &stmt)); + if (SQLITE_ROW == sqlite3_step (stmt)) + pages = sqlite3_column_int64 (stmt, 0); + else + pages = 0; + sqlite3_finalize (stmt); + CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_size", &stmt)); + CHECK (SQLITE_ROW == sqlite3_step (stmt)); + page_size = sqlite3_column_int64 (stmt, 0); + sqlite3_finalize (stmt); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"), + (unsigned long long) pages, (unsigned long long) page_size); + return pages * page_size; +} + + +/** + * Entry point for the plugin. + * + * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*" + * @return NULL on error, othrewise the plugin context + */ +void * +libgnunet_plugin_datastore_sqlite_init (void *cls) +{ + static struct Plugin plugin; + struct GNUNET_DATASTORE_PluginEnvironment *env = cls; + struct GNUNET_DATASTORE_PluginFunctions *api; + + if (plugin.env != NULL) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.env = env; + if (GNUNET_OK != database_setup (env->cfg, &plugin)) + { + database_shutdown (&plugin); + return NULL; + } + api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions)); + api->cls = &plugin; + api->estimate_size = &sqlite_plugin_estimate_size; + api->put = &sqlite_plugin_put; + api->update = &sqlite_plugin_update; + api->get_key = &sqlite_plugin_get_key; + api->get_replication = &sqlite_plugin_get_replication; + api->get_expiration = &sqlite_plugin_get_expiration; + api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity; + api->get_keys = &sqlite_plugin_get_keys; + api->drop = &sqlite_plugin_drop; + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "sqlite", + _("Sqlite database running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_datastore_sqlite_done (void *cls) +{ + char *fn; + struct GNUNET_DATASTORE_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "sqlite plugin is done\n"); +#endif + + fn = NULL; + if (plugin->drop_on_shutdown) + fn = GNUNET_strdup (plugin->fn); +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "Shutting down database\n"); +#endif + database_shutdown (plugin); + plugin->env = NULL; + GNUNET_free (api); + if (fn != NULL) + { + if (0 != UNLINK (fn)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); + GNUNET_free (fn); + } +#if DEBUG_SQLITE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "sqlite plugin is finished\n"); +#endif + return NULL; +} + +/* end of plugin_datastore_sqlite.c */ diff --git a/src/datastore/plugin_datastore_template.c b/src/datastore/plugin_datastore_template.c new file mode 100644 index 0000000..174d3d2 --- /dev/null +++ b/src/datastore/plugin_datastore_template.c @@ -0,0 +1,262 @@ +/* + This file is part of GNUnet + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file datastore/plugin_datastore_template.c + * @brief template-based datastore backend + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_datastore_plugin.h" + + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + /** + * Our execution environment. + */ + struct GNUNET_DATASTORE_PluginEnvironment *env; +}; + + +/** + * Get an estimate of how much space the database is + * currently using. + * + * @param cls our "struct Plugin*" + * @return number of bytes used on disk + */ +static unsigned long long +template_plugin_estimate_size (void *cls) +{ + GNUNET_break (0); + return 0; +} + + +/** + * Store an item in the datastore. + * + * @param cls closure + * @param key key for the item + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param replication replication-level for the content + * @param expiration expiration time for the content + * @param msg set to error message + * @return GNUNET_OK on success + */ +static int +template_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + uint32_t replication, + struct GNUNET_TIME_Absolute expiration, char **msg) +{ + GNUNET_break (0); + *msg = GNUNET_strdup ("not implemented"); + return GNUNET_SYSERR; +} + + +/** + * Get one of the results for a particular key in the datastore. + * + * @param cls closure + * @param offset offset of the result (modulo num-results); + * specific ordering does not matter for the offset + * @param key maybe NULL (to match all entries) + * @param vhash hash of the value, maybe NULL (to + * match all values that have the right key). + * Note that for DBlocks there is no difference + * betwen key and vhash, but for other blocks + * there may be! + * @param type entries of which type are relevant? + * Use 0 for any type. + * @param proc function to call on each matching value; + * will be called with NULL if nothing matches + * @param proc_cls closure for proc + */ +static void +template_plugin_get_key (void *cls, uint64_t offset, + const GNUNET_HashCode * key, + const GNUNET_HashCode * vhash, + enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, + void *proc_cls) +{ + GNUNET_break (0); +} + + + +/** + * Get a random item for replication. Returns a single, not expired, + * random item from those with the highest replication counters. The + * item's replication counter is decremented by one IF it was positive + * before. Call 'proc' with all values ZERO or NULL if the datastore + * is empty. + * + * @param cls closure + * @param proc function to call the value (once only). + * @param proc_cls closure for proc + */ +static void +template_plugin_get_replication (void *cls, PluginDatumProcessor proc, + void *proc_cls) +{ + GNUNET_break (0); +} + + +/** + * Get a random item for expiration. Call 'proc' with all values ZERO + * or NULL if the datastore is empty. + * + * @param cls closure + * @param proc function to call the value (once only). + * @param proc_cls closure for proc + */ +static void +template_plugin_get_expiration (void *cls, PluginDatumProcessor proc, + void *proc_cls) +{ + GNUNET_break (0); +} + + +/** + * Update the priority for a particular key in the datastore. If + * the expiration time in value is different than the time found in + * the datastore, the higher value should be kept. For the + * anonymity level, the lower value is to be used. The specified + * priority should be added to the existing priority, ignoring the + * priority in value. + * + * Note that it is possible for multiple values to match this put. + * In that case, all of the respective values are updated. + * + * @param cls our "struct Plugin*" + * @param uid unique identifier of the datum + * @param delta by how much should the priority + * change? If priority + delta < 0 the + * priority should be set to 0 (never go + * negative). + * @param expire new expiration time should be the + * MAX of any existing expiration time and + * this value + * @param msg set to error message + * @return GNUNET_OK on success + */ +static int +template_plugin_update (void *cls, uint64_t uid, int delta, + struct GNUNET_TIME_Absolute expire, char **msg) +{ + GNUNET_break (0); + *msg = GNUNET_strdup ("not implemented"); + return GNUNET_SYSERR; +} + + +/** + * Call the given processor on an item with zero anonymity. + * + * @param cls our "struct Plugin*" + * @param offset offset of the result (modulo num-results); + * specific ordering does not matter for the offset + * @param type entries of which type should be considered? + * Use 0 for any type. + * @param proc function to call on each matching value; + * will be called with NULL if no value matches + * @param proc_cls closure for proc + */ +static void +template_plugin_get_zero_anonymity (void *cls, uint64_t offset, + enum GNUNET_BLOCK_Type type, + PluginDatumProcessor proc, void *proc_cls) +{ + GNUNET_break (0); +} + + +/** + * Drop database. + */ +static void +template_plugin_drop (void *cls) +{ + GNUNET_break (0); +} + + +/** + * Entry point for the plugin. + * + * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*" + * @return our "struct Plugin*" + */ +void * +libgnunet_plugin_datastore_template_init (void *cls) +{ + struct GNUNET_DATASTORE_PluginEnvironment *env = cls; + struct GNUNET_DATASTORE_PluginFunctions *api; + struct Plugin *plugin; + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions)); + api->cls = plugin; + api->estimate_size = &template_plugin_estimate_size; + api->put = &template_plugin_put; + api->update = &template_plugin_update; + api->get_key = &template_plugin_get_key; + api->get_replication = &template_plugin_get_replication; + api->get_expiration = &template_plugin_get_expiration; + api->get_zero_anonymity = &template_plugin_get_zero_anonymity; + api->drop = &template_plugin_drop; + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "template", + _("Template database running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * @param cls our "struct Plugin*" + * @return always NULL + */ +void * +libgnunet_plugin_datastore_template_done (void *cls) +{ + struct GNUNET_DATASTORE_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + +/* end of plugin_datastore_template.c */ diff --git a/src/datastore/test_datastore_api.c b/src/datastore/test_datastore_api.c new file mode 100644 index 0000000..25836ca --- /dev/null +++ b/src/datastore/test_datastore_api.c @@ -0,0 +1,589 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* + * @file datastore/test_datastore_api.c + * @brief Test for the basic datastore API. + * @author Christian Grothoff + * + * TODO: + * - test reservation failure + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_datastore_service.h" + +#define VERBOSE GNUNET_NO + +#define START_DATASTORE GNUNET_YES + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) + +#define ITERATIONS 256 + +static struct GNUNET_DATASTORE_Handle *datastore; + +static struct GNUNET_TIME_Absolute now; + +static int ok; + +/** + * Name of plugin under test. + */ +static const char *plugin_name; + +static size_t +get_size (int i) +{ + return 8 * i; +} + + +static const void * +get_data (int i) +{ + static char buf[60000]; + + memset (buf, i, 8 * i); + return buf; +} + + +static int +get_type (int i) +{ + return i + 1; +} + + +static int +get_priority (int i) +{ + return i + 1; +} + + +static int +get_anonymity (int i) +{ + return i; +} + + +static struct GNUNET_TIME_Absolute +get_expiration (int i) +{ + struct GNUNET_TIME_Absolute av; + + av.abs_value = now.abs_value + 20000000 - i * 1000; + return av; +} + +enum RunPhase +{ + RP_DONE = 0, + RP_PUT = 1, + RP_GET = 2, + RP_DEL = 3, + RP_DO_DEL = 4, + RP_DELVALIDATE = 5, + RP_RESERVE = 6, + RP_PUT_MULTIPLE = 7, + RP_PUT_MULTIPLE_NEXT = 8, + RP_GET_MULTIPLE = 9, + RP_GET_MULTIPLE_NEXT = 10, + RP_UPDATE = 11, + RP_UPDATE_VALIDATE = 12, + RP_ERROR +}; + + +struct CpsRunContext +{ + GNUNET_HashCode key; + int i; + int rid; + const struct GNUNET_CONFIGURATION_Handle *cfg; + void *data; + size_t size; + enum RunPhase phase; + uint64_t uid; + uint64_t offset; + uint64_t first_uid; +}; + + +static void +run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +static void +check_success (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) +{ + struct CpsRunContext *crc = cls; + + if (GNUNET_OK != success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Operation %d/%d not successfull: `%s'\n", crc->phase, crc->i, + msg); + crc->phase = RP_ERROR; + } + GNUNET_free_non_null (crc->data); + crc->data = NULL; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +get_reserved (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) +{ + struct CpsRunContext *crc = cls; + + if (0 >= success) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error obtaining reservation: `%s'\n", + msg); + GNUNET_assert (0 < success); + crc->rid = success; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +check_value (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct CpsRunContext *crc = cls; + int i; + + i = crc->i; + if (NULL == key) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Value check failed (got NULL key) in %d/%d\n", crc->phase, + crc->i); + crc->phase = RP_ERROR; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + return; + } +#if 0 + FPRINTF (stderr, "Check value got `%s' of size %u, type %d, expire %llu\n", + GNUNET_h2s (key), (unsigned int) size, type, + (unsigned long long) expiration.abs_value); + FPRINTF (stderr, + "Check value iteration %d wants size %u, type %d, expire %llu\n", i, + (unsigned int) get_size (i), get_type (i), + (unsigned long long) get_expiration (i).abs_value); +#endif + GNUNET_assert (size == get_size (i)); + GNUNET_assert (0 == memcmp (data, get_data (i), size)); + GNUNET_assert (type == get_type (i)); + GNUNET_assert (priority == get_priority (i)); + GNUNET_assert (anonymity == get_anonymity (i)); + GNUNET_assert (expiration.abs_value == get_expiration (i).abs_value); + crc->offset++; + if (crc->i == 0) + { + crc->phase = RP_DEL; + crc->i = ITERATIONS; + } + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +delete_value (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct CpsRunContext *crc = cls; + + GNUNET_assert (crc->data == NULL); + GNUNET_assert (NULL != key); + crc->size = size; + crc->key = *key; + crc->data = GNUNET_malloc (size); + memcpy (crc->data, data, size); + crc->phase = RP_DO_DEL; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +check_nothing (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct CpsRunContext *crc = cls; + + GNUNET_assert (key == NULL); + if (crc->i == 0) + crc->phase = RP_RESERVE; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +check_multiple (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, uint64_t uid) +{ + struct CpsRunContext *crc = cls; + + GNUNET_assert (key != NULL); + switch (crc->phase) + { + case RP_GET_MULTIPLE: + crc->phase = RP_GET_MULTIPLE_NEXT; + crc->first_uid = uid; + crc->offset++; + break; + case RP_GET_MULTIPLE_NEXT: + GNUNET_assert (uid != crc->first_uid); + crc->phase = RP_UPDATE; + break; + default: + GNUNET_break (0); + crc->phase = RP_ERROR; + break; + } + if (priority == get_priority (42)) + crc->uid = uid; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +check_update (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct CpsRunContext *crc = cls; + + GNUNET_assert (key != NULL); + if ((anonymity == get_anonymity (42)) && (size == get_size (42)) && + (priority == get_priority (42) + 100)) + crc->phase = RP_DONE; + else + { + GNUNET_assert (size == get_size (43)); + crc->offset++; + } + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CpsRunContext *crc = cls; + + ok = (int) crc->phase; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test in phase %u\n", crc->phase); +#endif + switch (crc->phase) + { + case RP_PUT: +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "PUT", + crc->i); +#endif + GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); + GNUNET_DATASTORE_put (datastore, 0, &crc->key, get_size (crc->i), + get_data (crc->i), get_type (crc->i), + get_priority (crc->i), get_anonymity (crc->i), 0, + get_expiration (crc->i), 1, 1, TIMEOUT, + &check_success, crc); + crc->i++; + if (crc->i == ITERATIONS) + crc->phase = RP_GET; + break; + case RP_GET: + crc->i--; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET", + crc->i); +#endif + GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); + GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, + get_type (crc->i), 1, 1, TIMEOUT, &check_value, + crc); + break; + case RP_DEL: + crc->i--; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "DEL", + crc->i); +#endif + crc->data = NULL; + GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); + GNUNET_assert (NULL != + GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, + get_type (crc->i), 1, 1, TIMEOUT, + &delete_value, crc)); + break; + case RP_DO_DEL: +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "DO_DEL", + crc->i); +#endif + if (crc->i == 0) + { + crc->i = ITERATIONS; + crc->phase = RP_DELVALIDATE; + } + else + { + crc->phase = RP_DEL; + } + GNUNET_assert (NULL != + GNUNET_DATASTORE_remove (datastore, &crc->key, crc->size, + crc->data, 1, 1, TIMEOUT, + &check_success, crc)); + break; + case RP_DELVALIDATE: + crc->i--; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", + "DEL-VALIDATE", crc->i); +#endif + GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); + GNUNET_assert (NULL != + GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, + get_type (crc->i), 1, 1, TIMEOUT, + &check_nothing, crc)); + break; + case RP_RESERVE: + crc->phase = RP_PUT_MULTIPLE; + GNUNET_DATASTORE_reserve (datastore, 128 * 1024, 2, 1, 1, TIMEOUT, + &get_reserved, crc); + break; + case RP_PUT_MULTIPLE: + crc->phase = RP_PUT_MULTIPLE_NEXT; + GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (42), + get_data (42), get_type (42), get_priority (42), + get_anonymity (42), 0, get_expiration (42), 1, 1, + TIMEOUT, &check_success, crc); + break; + case RP_PUT_MULTIPLE_NEXT: + crc->phase = RP_GET_MULTIPLE; + GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (43), + get_data (43), get_type (42), get_priority (43), + get_anonymity (43), 0, get_expiration (43), 1, 1, + TIMEOUT, &check_success, crc); + break; + case RP_GET_MULTIPLE: + GNUNET_assert (NULL != + GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, + get_type (42), 1, 1, TIMEOUT, + &check_multiple, crc)); + break; + case RP_GET_MULTIPLE_NEXT: + GNUNET_assert (NULL != + GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, + get_type (42), 1, 1, TIMEOUT, + &check_multiple, crc)); + break; + case RP_UPDATE: + GNUNET_assert (crc->uid > 0); + crc->phase = RP_UPDATE_VALIDATE; + GNUNET_DATASTORE_update (datastore, crc->uid, 100, get_expiration (42), 1, + 1, TIMEOUT, &check_success, crc); + break; + case RP_UPDATE_VALIDATE: + GNUNET_assert (NULL != + GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, + get_type (42), 1, 1, TIMEOUT, + &check_update, crc)); + break; + case RP_DONE: +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished, disconnecting\n"); +#endif + GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); + GNUNET_free (crc); + ok = 0; + break; + case RP_ERROR: + GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); + GNUNET_free (crc); + ok = 43; + break; + } +} + + +static void +run_tests (void *cls, int32_t success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) +{ + struct CpsRunContext *crc = cls; + + switch (success) + { + case GNUNET_YES: + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + return; + case GNUNET_NO: + FPRINTF (stderr, "%s", "Test 'put' operation failed, key already exists (!?)\n"); + GNUNET_free (crc); + return; + case GNUNET_SYSERR: + FPRINTF (stderr, + "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n", + msg); + GNUNET_free (crc); + return; + default: + GNUNET_assert (0); + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct CpsRunContext *crc; + static GNUNET_HashCode zkey; + + crc = GNUNET_malloc (sizeof (struct CpsRunContext)); + crc->cfg = cfg; + crc->phase = RP_PUT; + now = GNUNET_TIME_absolute_get (); + datastore = GNUNET_DATASTORE_connect (cfg); + if (NULL == + GNUNET_DATASTORE_put (datastore, 0, &zkey, 4, "TEST", + GNUNET_BLOCK_TYPE_TEST, 0, 0, 0, + GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_UNIT_SECONDS), 0, 1, + GNUNET_TIME_UNIT_MINUTES, &run_tests, crc)) + { + FPRINTF (stderr, "%s", "Test 'put' operation failed.\n"); + ok = 1; + GNUNET_free (crc); + } +} + + +static int +check () +{ + char cfg_name[128]; + +#if START_DATASTORE + struct GNUNET_OS_Process *proc; +#endif + char *const argv[] = { + "test-datastore-api", + "-c", + cfg_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_snprintf (cfg_name, sizeof (cfg_name), + "test_datastore_api_data_%s.conf", plugin_name); +#if START_DATASTORE + proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfg_name, NULL); +#endif + GNUNET_assert (NULL != proc); + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-datastore-api", "nohelp", options, &run, NULL); +#if START_DATASTORE + sleep (1); /* give datastore chance to receive 'DROP' request */ + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + ok = 1; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; +#endif + if (ok != 0) + FPRINTF (stderr, "Missed some testcases: %u\n", ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + char *pos; + char dir_name[128]; + + sleep (1); + /* determine name of plugin to use */ + plugin_name = argv[0]; + while (NULL != (pos = strstr (plugin_name, "_"))) + plugin_name = pos + 1; + if (NULL != (pos = strstr (plugin_name, "."))) + pos[0] = 0; + else + pos = (char *) plugin_name; + + GNUNET_snprintf (dir_name, sizeof (dir_name), "/tmp/test-gnunet-datastore-%s", + plugin_name); + GNUNET_DISK_directory_remove (dir_name); + GNUNET_log_setup ("test-datastore-api", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + if (pos != plugin_name) + pos[0] = '.'; + GNUNET_DISK_directory_remove (dir_name); + return ret; +} + +/* end of test_datastore_api.c */ diff --git a/src/datastore/test_datastore_api_data_mysql.conf b/src/datastore/test_datastore_api_data_mysql.conf new file mode 100644 index 0000000..8e5a3dc --- /dev/null +++ b/src/datastore/test_datastore_api_data_mysql.conf @@ -0,0 +1,28 @@ +@INLINE@ test_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-datastore-mysql/ +DEFAULTCONFIG = test_datastore_api_data_mysql.conf + +[TESTING] +WEAKRANDOM = YES + +[arm] +PORT = 42466 +DEFAULTSERVICES = + +[statistics] +PORT = 22667 + +[resolver] +PORT = 42464 + +[datastore] +QUOTA = 10 MB +DATABASE = mysql + +[datastore-mysql] +DATABASE = gnunetcheck + +[fs] +AUTOSTART = NO + diff --git a/src/datastore/test_datastore_api_data_postgres.conf b/src/datastore/test_datastore_api_data_postgres.conf new file mode 100644 index 0000000..046c561 --- /dev/null +++ b/src/datastore/test_datastore_api_data_postgres.conf @@ -0,0 +1,28 @@ +@INLINE@ test_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-datastore-postgres/ +DEFAULTCONFIG = test_datastore_api_data_postgres.conf + +[TESTING] +WEAKRANDOM = YES + +[arm] +PORT = 42466 +DEFAULTSERVICES = + +[statistics] +PORT = 22667 + +[resolver] +PORT = 42464 + +[datastore] +QUOTA = 10 MB +DATABASE = postgres + +[datastore-postgres] +CONFIG = dbname=gnunetcheck + +[fs] +AUTOSTART = NO + diff --git a/src/datastore/test_datastore_api_data_sqlite.conf b/src/datastore/test_datastore_api_data_sqlite.conf new file mode 100644 index 0000000..098f9d2 --- /dev/null +++ b/src/datastore/test_datastore_api_data_sqlite.conf @@ -0,0 +1,24 @@ +@INLINE@ test_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-datastore-sqlite/ +DEFAULTCONFIG = test_datastore_api_data_sqlite.conf + +[TESTING] +WEAKRANDOM = YES + +[arm] +PORT = 42466 +DEFAULTSERVICES = + +[statistics] +PORT = 22667 + +[resolver] +PORT = 42464 + +[datastore] +QUOTA = 10 MB + +[fs] +AUTOSTART = NO + diff --git a/src/datastore/test_datastore_api_management.c b/src/datastore/test_datastore_api_management.c new file mode 100644 index 0000000..4015c2c --- /dev/null +++ b/src/datastore/test_datastore_api_management.c @@ -0,0 +1,373 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2007, 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* + * @file datastore/test_datastore_api_management.c + * @brief Test for the space management functions of the datastore implementation. + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_datastore_service.h" + +#define VERBOSE GNUNET_NO + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * Number of iterations to run; must be large enough + * so that the quota will be exceeded! + */ +#define ITERATIONS 5000 + +static struct GNUNET_DATASTORE_Handle *datastore; + +static struct GNUNET_TIME_Absolute now; + +static int ok; + +static const char *plugin_name; + +static size_t +get_size (int i) +{ + return 8 + 8 * (i % 256); +} + + +static const void * +get_data (int i) +{ + static char buf[60000]; + + memset (buf, i, 8 + 8 * (i % 256)); + return buf; +} + + +static int +get_type (int i) +{ + return 1; +} + + +static int +get_priority (int i) +{ + return i + 1; +} + + +static int +get_anonymity (int i) +{ + return i; +} + + +static struct GNUNET_TIME_Absolute +get_expiration (int i) +{ + struct GNUNET_TIME_Absolute av; + + av.abs_value = now.abs_value + i * 1000; + return av; +} + +enum RunPhase +{ + RP_PUT, + RP_GET, + RP_DONE, + RP_GET_FAIL +}; + + +struct CpsRunContext +{ + GNUNET_HashCode key; + int i; + int found; + const struct GNUNET_CONFIGURATION_Handle *cfg; + void *data; + enum RunPhase phase; + uint64_t offset; +}; + + +static void +run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +static void +check_success (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) +{ + struct CpsRunContext *crc = cls; + + if (GNUNET_OK != success) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", msg); + GNUNET_assert (GNUNET_OK == success); + GNUNET_free_non_null (crc->data); + crc->data = NULL; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +check_value (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct CpsRunContext *crc = cls; + int i; + + if (NULL == key) + { + crc->phase = RP_GET_FAIL; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + return; + } + i = crc->i; + GNUNET_assert (size == get_size (i)); + GNUNET_assert (0 == memcmp (data, get_data (i), size)); + GNUNET_assert (type == get_type (i)); + GNUNET_assert (priority == get_priority (i)); + GNUNET_assert (anonymity == get_anonymity (i)); + GNUNET_assert (expiration.abs_value == get_expiration (i).abs_value); + crc->offset++; + crc->i--; + if (crc->i == 0) + crc->phase = RP_DONE; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +check_nothing (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, + uint64_t uid) +{ + struct CpsRunContext *crc = cls; + + GNUNET_assert (key == NULL); + if (0 == --crc->i) + crc->phase = RP_DONE; + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CpsRunContext *crc = cls; + + ok = (int) crc->phase; + switch (crc->phase) + { + case RP_PUT: +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "PUT", + crc->i); +#endif + GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); + GNUNET_DATASTORE_put (datastore, 0, &crc->key, get_size (crc->i), + get_data (crc->i), get_type (crc->i), + get_priority (crc->i), get_anonymity (crc->i), 0, + get_expiration (crc->i), 1, 1, TIMEOUT, + &check_success, crc); + crc->i++; + if (crc->i == ITERATIONS) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Sleeping to give datastore time to clean up\n"); + sleep (1); + crc->phase = RP_GET; + crc->i--; + } + break; + case RP_GET: +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET", + crc->i); +#endif + GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); + GNUNET_DATASTORE_get_key (datastore, crc->offset++, &crc->key, + get_type (crc->i), 1, 1, TIMEOUT, &check_value, + crc); + break; + case RP_GET_FAIL: +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET(f)", + crc->i); +#endif + GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); + GNUNET_DATASTORE_get_key (datastore, crc->offset++, &crc->key, + get_type (crc->i), 1, 1, TIMEOUT, &check_nothing, + crc); + break; + case RP_DONE: + GNUNET_assert (0 == crc->i); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished, disconnecting\n"); +#endif + GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); + GNUNET_free (crc); + ok = 0; + } +} + + +static void +run_tests (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) +{ + struct CpsRunContext *crc = cls; + + if (success != GNUNET_YES) + { + FPRINTF (stderr, + "Test 'put' operation failed with error `%s' database likely not setup, skipping test.", + msg); + GNUNET_free (crc); + return; + } + GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct CpsRunContext *crc; + static GNUNET_HashCode zkey; + + crc = GNUNET_malloc (sizeof (struct CpsRunContext)); + crc->cfg = cfg; + crc->phase = RP_PUT; + now = GNUNET_TIME_absolute_get (); + datastore = GNUNET_DATASTORE_connect (cfg); + if (NULL == + GNUNET_DATASTORE_put (datastore, 0, &zkey, 4, "TEST", + GNUNET_BLOCK_TYPE_TEST, 0, 0, 0, + GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_UNIT_SECONDS), 0, 1, + GNUNET_TIME_UNIT_MINUTES, &run_tests, crc)) + { + FPRINTF (stderr, "%s", "Test 'put' operation failed.\n"); + GNUNET_free (crc); + ok = 1; + } +} + + + +static int +check () +{ + struct GNUNET_OS_Process *proc; + char cfg_name[128]; + + char *const argv[] = { + "test-datastore-api-management", + "-c", + cfg_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_snprintf (cfg_name, sizeof (cfg_name), + "test_datastore_api_data_%s.conf", plugin_name); + proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfg_name, NULL); + GNUNET_assert (NULL != proc); + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-datastore-api-management", "nohelp", options, &run, + NULL); + sleep (1); /* give datastore chance to process 'DROP' request */ + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + ok = 1; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; + if (ok != 0) + FPRINTF (stderr, "Missed some testcases: %u\n", ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + char *pos; + char dir_name[128]; + + sleep (1); + /* determine name of plugin to use */ + plugin_name = argv[0]; + while (NULL != (pos = strstr (plugin_name, "_"))) + plugin_name = pos + 1; + if (NULL != (pos = strstr (plugin_name, "."))) + pos[0] = 0; + else + pos = (char *) plugin_name; + + GNUNET_snprintf (dir_name, sizeof (dir_name), "/tmp/test-gnunet-datastore-%s", + plugin_name); + GNUNET_DISK_directory_remove (dir_name); + GNUNET_log_setup ("test-datastore-api-management", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + if (pos != plugin_name) + pos[0] = '.'; + GNUNET_DISK_directory_remove (dir_name); + return ret; +} + +/* end of test_datastore_api_management.c */ diff --git a/src/datastore/test_defaults.conf b/src/datastore/test_defaults.conf new file mode 100644 index 0000000..113d6bb --- /dev/null +++ b/src/datastore/test_defaults.conf @@ -0,0 +1,30 @@ +[datastore] +PORT = 22654 +QUOTA = 1 MB + +[dht] +AUTOSTART = NO + +[dns] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[dv] +AUTOSTART = NO + +[chat] +AUTOSTART = NO + +[vpn] +AUTOSTART = NO + +[gns] +AUTOSTART = NO + +[dv] +AUTOSTART = NO diff --git a/src/datastore/test_plugin_datastore.c b/src/datastore/test_plugin_datastore.c new file mode 100644 index 0000000..16fe40c --- /dev/null +++ b/src/datastore/test_plugin_datastore.c @@ -0,0 +1,421 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* + * @file test_plugin_datastore.c + * @brief Test database plugin directly, calling each API function once + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_datastore_plugin.h" + +#define VERBOSE GNUNET_NO + +/** + * Number of put operations to perform. + */ +#define PUT_10 10 + +static unsigned long long stored_bytes; + +static unsigned long long stored_entries; + +static unsigned long long stored_ops; + +static const char *plugin_name; + +static int ok; + +enum RunPhase +{ + RP_ERROR = 0, + RP_PUT, + RP_GET, + RP_UPDATE, + RP_ITER_ZERO, + RP_REPL_GET, + RP_EXPI_GET, + RP_DROP +}; + + +struct CpsRunContext +{ + const struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_DATASTORE_PluginFunctions *api; + enum RunPhase phase; + unsigned int cnt; + unsigned int i; + uint64_t offset; +}; + + +/** + * Function called by plugins to notify us about a + * change in their disk utilization. + * + * @param cls closure (NULL) + * @param delta change in disk utilization, + * 0 for "reset to empty" + */ +static void +disk_utilization_change_cb (void *cls, int delta) +{ + /* do nothing */ +} + + +static void +gen_key (int i, GNUNET_HashCode * key) +{ + memset (key, 0, sizeof (GNUNET_HashCode)); + key->bits[0] = (unsigned int) i; + GNUNET_CRYPTO_hash (key, sizeof (GNUNET_HashCode), key); +} + + +static void +put_value (struct GNUNET_DATASTORE_PluginFunctions *api, int i, int k) +{ + char value[65536]; + size_t size; + GNUNET_HashCode key; + char *msg; + unsigned int prio; + + /* most content is 32k */ + size = 32 * 1024; + + if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 0) /* but some of it is less! */ + size = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024); + size = size - (size & 7); /* always multiple of 8 */ + + /* generate random key */ + gen_key (i, &key); + memset (value, i, size); + if (i > 255) + memset (value, i - 255, size / 2); + value[0] = k; + msg = NULL; + prio = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100); +#if VERBOSE + FPRINTF (stderr, "putting type %u, anon %u under key %s\n", i + 1, i, + GNUNET_h2s (&key)); +#endif + if (GNUNET_OK != api->put (api->cls, &key, size, value, i + 1 /* type */ , + prio, i /* anonymity */ , + 0 /* replication */ , + GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, + 60 * 60 * 60 * 1000 + + GNUNET_CRYPTO_random_u32 + (GNUNET_CRYPTO_QUALITY_WEAK, 1000))), &msg)) + { + FPRINTF (stderr, "ERROR: `%s'\n", msg); + GNUNET_free_non_null (msg); + return; + } + stored_bytes += size; + stored_ops++; + stored_entries++; +} + + +static void +test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +static uint64_t guid; + + +static int +iterate_one_shot (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, uint64_t uid) +{ + struct CpsRunContext *crc = cls; + + GNUNET_assert (key != NULL); + guid = uid; + crc->phase++; +#if VERBOSE + FPRINTF (stderr, + "Found result type=%u, priority=%u, size=%u, expire=%llu, key %s\n", + type, priority, size, (unsigned long long) expiration.abs_value, + GNUNET_h2s (key)); +#endif + GNUNET_SCHEDULER_add_now (&test, crc); + return GNUNET_OK; +} + + +/** + * Function called when the service shuts + * down. Unloads our datastore plugin. + * + * @param api api to unload + * @param cfg configuration to use + */ +static void +unload_plugin (struct GNUNET_DATASTORE_PluginFunctions *api, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *name; + char *libname; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE", + &name)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", + "DATASTORE"); + return; + } + GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name); + GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api)); + GNUNET_free (libname); + GNUNET_free (name); +} + + + +/** + * Last task run during shutdown. Disconnects us from + * the transport and core. + */ +static void +cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CpsRunContext *crc = cls; + + unload_plugin (crc->api, crc->cfg); + GNUNET_free (crc); +} + + +static void +test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CpsRunContext *crc = cls; + int j; + unsigned long long os; + unsigned long long cs; + GNUNET_HashCode key; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test aborted.\n"); + crc->phase = RP_ERROR; + } +#if VERBOSE + FPRINTF (stderr, "In phase %d, iteration %u\n", crc->phase, crc->cnt); +#endif + switch (crc->phase) + { + case RP_ERROR: + ok = 1; + GNUNET_break (0); + crc->api->drop (crc->api->cls); + GNUNET_SCHEDULER_add_now (&cleaning_task, crc); + break; + case RP_PUT: + os = 0; + for (j = 0; j < PUT_10; j++) + { + put_value (crc->api, j, crc->i); + cs = crc->api->estimate_size (crc->api->cls); + GNUNET_assert (os <= cs); + os = cs; + } + crc->phase++; + GNUNET_SCHEDULER_add_now (&test, crc); + break; + case RP_GET: + if (crc->cnt == 1) + { + crc->cnt = 0; + crc->phase++; + GNUNET_SCHEDULER_add_now (&test, crc); + break; + } + gen_key (5, &key); + crc->api->get_key (crc->api->cls, crc->offset++, &key, NULL, + GNUNET_BLOCK_TYPE_ANY, &iterate_one_shot, crc); + break; + case RP_UPDATE: + GNUNET_assert (GNUNET_OK == + crc->api->update (crc->api->cls, guid, 1, + GNUNET_TIME_UNIT_ZERO_ABS, NULL)); + crc->phase++; + GNUNET_SCHEDULER_add_now (&test, crc); + break; + + case RP_ITER_ZERO: + if (crc->cnt == 1) + { + crc->cnt = 0; + crc->phase++; + GNUNET_SCHEDULER_add_now (&test, crc); + break; + } + crc->api->get_zero_anonymity (crc->api->cls, 0, 1, &iterate_one_shot, crc); + break; + case RP_REPL_GET: + crc->api->get_replication (crc->api->cls, &iterate_one_shot, crc); + break; + case RP_EXPI_GET: + crc->api->get_expiration (crc->api->cls, &iterate_one_shot, crc); + break; + case RP_DROP: + crc->api->drop (crc->api->cls); + GNUNET_SCHEDULER_add_now (&cleaning_task, crc); + break; + } +} + + +/** + * Load the datastore plugin. + */ +static struct GNUNET_DATASTORE_PluginFunctions * +load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + static struct GNUNET_DATASTORE_PluginEnvironment env; + struct GNUNET_DATASTORE_PluginFunctions *ret; + char *name; + char *libname; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE", + &name)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", + "DATASTORE"); + return NULL; + } + env.cfg = cfg; + env.duc = &disk_utilization_change_cb; + env.cls = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datastore plugin\n"), + name); + GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name); + if (NULL == (ret = GNUNET_PLUGIN_load (libname, &env))) + { + FPRINTF (stderr, "Failed to load plugin `%s'!\n", name); + return NULL; + } + GNUNET_free (libname); + GNUNET_free (name); + return ret; +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + struct GNUNET_DATASTORE_PluginFunctions *api; + struct CpsRunContext *crc; + + api = load_plugin (c); + if (api == NULL) + { + FPRINTF (stderr, + "%s", "Could not initialize plugin, assuming database not configured. Test not run!\n"); + return; + } + crc = GNUNET_malloc (sizeof (struct CpsRunContext)); + crc->api = api; + crc->cfg = c; + crc->phase = RP_PUT; + GNUNET_SCHEDULER_add_now (&test, crc); +} + + +static int +check () +{ + char cfg_name[128]; + + char *const argv[] = { + "test-plugin-datastore", + "-c", + cfg_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_snprintf (cfg_name, sizeof (cfg_name), + "test_plugin_datastore_data_%s.conf", plugin_name); + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-plugin-datastore", "nohelp", options, &run, NULL); + if (ok != 0) + FPRINTF (stderr, "Missed some testcases: %u\n", ok); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + char *pos; + char dir_name[128]; + + sleep (1); + /* determine name of plugin to use */ + plugin_name = argv[0]; + while (NULL != (pos = strstr (plugin_name, "_"))) + plugin_name = pos + 1; + if (NULL != (pos = strstr (plugin_name, "."))) + pos[0] = 0; + else + pos = (char *) plugin_name; + + GNUNET_snprintf (dir_name, sizeof (dir_name), + "/tmp/test-gnunet-datastore-plugin-%s", plugin_name); + GNUNET_DISK_directory_remove (dir_name); + GNUNET_log_setup ("test-plugin-datastore", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + if (pos != plugin_name) + pos[0] = '.'; + GNUNET_DISK_directory_remove (dir_name); + + return ret; +} + +/* end of test_plugin_datastore.c */ diff --git a/src/datastore/test_plugin_datastore_data_mysql.conf b/src/datastore/test_plugin_datastore_data_mysql.conf new file mode 100644 index 0000000..957818a --- /dev/null +++ b/src/datastore/test_plugin_datastore_data_mysql.conf @@ -0,0 +1,11 @@ +@INLINE@ test_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-datastore-plugin-mysql/ +DEFAULTCONFIG = test_plugin_datastore_data_mysql.conf + +[datastore] +DATABASE = mysql + +[datastore-mysql] +DATABASE = gnunetcheck + diff --git a/src/datastore/test_plugin_datastore_data_postgres.conf b/src/datastore/test_plugin_datastore_data_postgres.conf new file mode 100644 index 0000000..d796496 --- /dev/null +++ b/src/datastore/test_plugin_datastore_data_postgres.conf @@ -0,0 +1,11 @@ +@INLINE@ test_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-datastore-plugin-postgres/ +DEFAULTCONFIG = test_plugin_datastore_data_postgres.conf + +[datastore] +DATABASE = postgres + +[datastore-postgres] +CONFIG = dbname=gnunetcheck + diff --git a/src/datastore/test_plugin_datastore_data_sqlite.conf b/src/datastore/test_plugin_datastore_data_sqlite.conf new file mode 100644 index 0000000..f1fcf5f --- /dev/null +++ b/src/datastore/test_plugin_datastore_data_sqlite.conf @@ -0,0 +1,5 @@ +@INLINE@ test_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-datastore-plugin-sqlite/ +DEFAULTCONFIG = test_plugin_datastore_data_sqlite.conf + diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am new file mode 100644 index 0000000..93880c2 --- /dev/null +++ b/src/dht/Makefile.am @@ -0,0 +1,204 @@ +INCLUDES = -I$(top_srcdir)/src/include +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 +endif + +plugindir = $(libdir)/gnunet + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + dht.conf + +if HAVE_ZLIB + ZLIB_LNK = -lz +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +lib_LTLIBRARIES = \ + libgnunetdht.la + +libgnunetdht_la_SOURCES = \ + dht_api.c dht.h +libgnunetdht_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(XLIB) +libgnunetdht_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 1:0:1 + + +plugin_LTLIBRARIES = \ + libgnunet_plugin_block_dht.la + +libgnunet_plugin_block_dht_la_SOURCES = \ + plugin_block_dht.c +libgnunet_plugin_block_dht_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_block_dht_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) +libgnunet_plugin_block_dht_la_DEPENDENCIES = \ + $(top_builddir)/src/block/libgnunetblock.la + + + +bin_PROGRAMS = \ + gnunet-service-dht \ + gnunet-dht-get \ + gnunet-dht-put + +gnunet_service_dht_SOURCES = \ + gnunet-service-dht.c gnunet-service-dht.h \ + gnunet-service-dht_clients.c gnunet-service-dht_clients.h \ + gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \ + gnunet-service-dht_hello.c gnunet-service-dht_hello.h \ + gnunet-service-dht_nse.c gnunet-service-dht_nse.h \ + gnunet-service-dht_neighbours.c gnunet-service-dht_neighbours.h \ + gnunet-service-dht_routing.c gnunet-service-dht_routing.h +gnunet_service_dht_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/ats/libgnunetats.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lm + +gnunet_dht_get_SOURCES = \ + gnunet-dht-get.c +gnunet_dht_get_LDADD = \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +gnunet_dht_get_DEPENDENCIES = \ + libgnunetdht.la + +gnunet_dht_put_SOURCES = \ + gnunet-dht-put.c +gnunet_dht_put_LDADD = \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +gnunet_dht_put_DEPENDENCIES = \ + libgnunetdht.la + +check_PROGRAMS = \ + test_dht_api \ + test_dht_twopeer \ + test_dht_twopeer_put_get \ + test_dht_twopeer_get_put \ + test_dht_twopeer_path_tracking \ + test_dht_multipeer \ + test_dht_line \ + test_dht_2dtorus \ + test_dht_monitor + +if ENABLE_TEST_RUN +TESTS = test_dht_api $(check_SCRIPTS) \ + test_dht_twopeer \ + test_dht_twopeer_put_get \ + test_dht_twopeer_get_put \ + test_dht_twopeer_path_tracking \ + test_dht_multipeer \ + test_dht_line \ + test_dht_2dtorus \ + test_dht_monitor +endif + +test_dht_api_SOURCES = \ + test_dht_api.c +test_dht_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/dht/libgnunetdht.la +test_dht_api_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_twopeer_SOURCES = \ + test_dht_twopeer.c +test_dht_twopeer_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la +test_dht_twopeer_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_twopeer_put_get_SOURCES = \ + test_dht_twopeer_put_get.c +test_dht_twopeer_put_get_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_twopeer_get_put_SOURCES = \ + test_dht_twopeer_get_put.c +test_dht_twopeer_get_put_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_twopeer_path_tracking_SOURCES = \ + test_dht_twopeer_path_tracking.c +test_dht_twopeer_path_tracking_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_multipeer_SOURCES = \ + test_dht_multipeer.c +test_dht_multipeer_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la +test_dht_multipeer_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_2dtorus_SOURCES = \ + test_dht_topo.c +test_dht_2dtorus_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la +test_dht_2dtorus_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_line_SOURCES = \ + test_dht_topo.c +test_dht_line_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la +test_dht_line_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_monitor_SOURCES = test_dht_monitor.c +test_dht_monitor_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la +test_dht_monitor_DEPENDENCIES = \ + libgnunetdht.la + +EXTRA_DIST = \ + $(check_SCRIPTS) \ + test_dht_api_data.conf \ + test_dht_api_peer1.conf \ + test_dht_twopeer_data.conf \ + test_dht_multipeer_data.conf \ + test_dht_2dtorus.conf \ + test_dht_line.conf \ + multipeer_topo.dat + +check_SCRIPTS = \ + test_dht_tools.sh diff --git a/src/dht/Makefile.in b/src/dht/Makefile.in new file mode 100644 index 0000000..97e9c59 --- /dev/null +++ b/src/dht/Makefile.in @@ -0,0 +1,1197 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-dht$(EXEEXT) gnunet-dht-get$(EXEEXT) \ + gnunet-dht-put$(EXEEXT) +check_PROGRAMS = test_dht_api$(EXEEXT) test_dht_twopeer$(EXEEXT) \ + test_dht_twopeer_put_get$(EXEEXT) \ + test_dht_twopeer_get_put$(EXEEXT) \ + test_dht_twopeer_path_tracking$(EXEEXT) \ + test_dht_multipeer$(EXEEXT) test_dht_line$(EXEEXT) \ + test_dht_2dtorus$(EXEEXT) test_dht_monitor$(EXEEXT) +@ENABLE_TEST_RUN_TRUE@TESTS = test_dht_api$(EXEEXT) $(check_SCRIPTS) \ +@ENABLE_TEST_RUN_TRUE@ test_dht_twopeer$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_dht_twopeer_put_get$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_dht_twopeer_get_put$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_dht_twopeer_path_tracking$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_dht_multipeer$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_dht_line$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_dht_2dtorus$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_dht_monitor$(EXEEXT) +subdir = src/dht +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/dht.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = dht.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) +am_libgnunet_plugin_block_dht_la_OBJECTS = plugin_block_dht.lo +libgnunet_plugin_block_dht_la_OBJECTS = \ + $(am_libgnunet_plugin_block_dht_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_block_dht_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_block_dht_la_LDFLAGS) $(LDFLAGS) -o $@ +am__DEPENDENCIES_1 = +libgnunetdht_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunetdht_la_OBJECTS = dht_api.lo +libgnunetdht_la_OBJECTS = $(am_libgnunetdht_la_OBJECTS) +libgnunetdht_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetdht_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_dht_get_OBJECTS = gnunet-dht-get.$(OBJEXT) +gnunet_dht_get_OBJECTS = $(am_gnunet_dht_get_OBJECTS) +am_gnunet_dht_put_OBJECTS = gnunet-dht-put.$(OBJEXT) +gnunet_dht_put_OBJECTS = $(am_gnunet_dht_put_OBJECTS) +am_gnunet_service_dht_OBJECTS = gnunet-service-dht.$(OBJEXT) \ + gnunet-service-dht_clients.$(OBJEXT) \ + gnunet-service-dht_datacache.$(OBJEXT) \ + gnunet-service-dht_hello.$(OBJEXT) \ + gnunet-service-dht_nse.$(OBJEXT) \ + gnunet-service-dht_neighbours.$(OBJEXT) \ + gnunet-service-dht_routing.$(OBJEXT) +gnunet_service_dht_OBJECTS = $(am_gnunet_service_dht_OBJECTS) +gnunet_service_dht_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/ats/libgnunetats.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_dht_2dtorus_OBJECTS = test_dht_topo.$(OBJEXT) +test_dht_2dtorus_OBJECTS = $(am_test_dht_2dtorus_OBJECTS) +am_test_dht_api_OBJECTS = test_dht_api.$(OBJEXT) +test_dht_api_OBJECTS = $(am_test_dht_api_OBJECTS) +am_test_dht_line_OBJECTS = test_dht_topo.$(OBJEXT) +test_dht_line_OBJECTS = $(am_test_dht_line_OBJECTS) +am_test_dht_monitor_OBJECTS = test_dht_monitor.$(OBJEXT) +test_dht_monitor_OBJECTS = $(am_test_dht_monitor_OBJECTS) +am_test_dht_multipeer_OBJECTS = test_dht_multipeer.$(OBJEXT) +test_dht_multipeer_OBJECTS = $(am_test_dht_multipeer_OBJECTS) +am_test_dht_twopeer_OBJECTS = test_dht_twopeer.$(OBJEXT) +test_dht_twopeer_OBJECTS = $(am_test_dht_twopeer_OBJECTS) +am_test_dht_twopeer_get_put_OBJECTS = \ + test_dht_twopeer_get_put.$(OBJEXT) +test_dht_twopeer_get_put_OBJECTS = \ + $(am_test_dht_twopeer_get_put_OBJECTS) +test_dht_twopeer_get_put_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la +am_test_dht_twopeer_path_tracking_OBJECTS = \ + test_dht_twopeer_path_tracking.$(OBJEXT) +test_dht_twopeer_path_tracking_OBJECTS = \ + $(am_test_dht_twopeer_path_tracking_OBJECTS) +test_dht_twopeer_path_tracking_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la +am_test_dht_twopeer_put_get_OBJECTS = \ + test_dht_twopeer_put_get.$(OBJEXT) +test_dht_twopeer_put_get_OBJECTS = \ + $(am_test_dht_twopeer_put_get_OBJECTS) +test_dht_twopeer_put_get_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunet_plugin_block_dht_la_SOURCES) \ + $(libgnunetdht_la_SOURCES) $(gnunet_dht_get_SOURCES) \ + $(gnunet_dht_put_SOURCES) $(gnunet_service_dht_SOURCES) \ + $(test_dht_2dtorus_SOURCES) $(test_dht_api_SOURCES) \ + $(test_dht_line_SOURCES) $(test_dht_monitor_SOURCES) \ + $(test_dht_multipeer_SOURCES) $(test_dht_twopeer_SOURCES) \ + $(test_dht_twopeer_get_put_SOURCES) \ + $(test_dht_twopeer_path_tracking_SOURCES) \ + $(test_dht_twopeer_put_get_SOURCES) +DIST_SOURCES = $(libgnunet_plugin_block_dht_la_SOURCES) \ + $(libgnunetdht_la_SOURCES) $(gnunet_dht_get_SOURCES) \ + $(gnunet_dht_put_SOURCES) $(gnunet_service_dht_SOURCES) \ + $(test_dht_2dtorus_SOURCES) $(test_dht_api_SOURCES) \ + $(test_dht_line_SOURCES) $(test_dht_monitor_SOURCES) \ + $(test_dht_multipeer_SOURCES) $(test_dht_twopeer_SOURCES) \ + $(test_dht_twopeer_get_put_SOURCES) \ + $(test_dht_twopeer_path_tracking_SOURCES) \ + $(test_dht_twopeer_put_get_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 +plugindir = $(libdir)/gnunet +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + dht.conf + +@HAVE_ZLIB_TRUE@ZLIB_LNK = -lz +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +lib_LTLIBRARIES = \ + libgnunetdht.la + +libgnunetdht_la_SOURCES = \ + dht_api.c dht.h + +libgnunetdht_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(XLIB) + +libgnunetdht_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 1:0:1 + +plugin_LTLIBRARIES = \ + libgnunet_plugin_block_dht.la + +libgnunet_plugin_block_dht_la_SOURCES = \ + plugin_block_dht.c + +libgnunet_plugin_block_dht_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_block_dht_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_block_dht_la_DEPENDENCIES = \ + $(top_builddir)/src/block/libgnunetblock.la + +gnunet_service_dht_SOURCES = \ + gnunet-service-dht.c gnunet-service-dht.h \ + gnunet-service-dht_clients.c gnunet-service-dht_clients.h \ + gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \ + gnunet-service-dht_hello.c gnunet-service-dht_hello.h \ + gnunet-service-dht_nse.c gnunet-service-dht_nse.h \ + gnunet-service-dht_neighbours.c gnunet-service-dht_neighbours.h \ + gnunet-service-dht_routing.c gnunet-service-dht_routing.h + +gnunet_service_dht_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/ats/libgnunetats.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/datacache/libgnunetdatacache.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lm + +gnunet_dht_get_SOURCES = \ + gnunet-dht-get.c + +gnunet_dht_get_LDADD = \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_dht_get_DEPENDENCIES = \ + libgnunetdht.la + +gnunet_dht_put_SOURCES = \ + gnunet-dht-put.c + +gnunet_dht_put_LDADD = \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_dht_put_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_api_SOURCES = \ + test_dht_api.c + +test_dht_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_api_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_twopeer_SOURCES = \ + test_dht_twopeer.c + +test_dht_twopeer_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_twopeer_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_twopeer_put_get_SOURCES = \ + test_dht_twopeer_put_get.c + +test_dht_twopeer_put_get_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_twopeer_get_put_SOURCES = \ + test_dht_twopeer_get_put.c + +test_dht_twopeer_get_put_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_twopeer_path_tracking_SOURCES = \ + test_dht_twopeer_path_tracking.c + +test_dht_twopeer_path_tracking_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_multipeer_SOURCES = \ + test_dht_multipeer.c + +test_dht_multipeer_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_multipeer_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_2dtorus_SOURCES = \ + test_dht_topo.c + +test_dht_2dtorus_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_2dtorus_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_line_SOURCES = \ + test_dht_topo.c + +test_dht_line_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_line_DEPENDENCIES = \ + libgnunetdht.la + +test_dht_monitor_SOURCES = test_dht_monitor.c +test_dht_monitor_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_dht_monitor_DEPENDENCIES = \ + libgnunetdht.la + +EXTRA_DIST = \ + $(check_SCRIPTS) \ + test_dht_api_data.conf \ + test_dht_api_peer1.conf \ + test_dht_twopeer_data.conf \ + test_dht_multipeer_data.conf \ + test_dht_2dtorus.conf \ + test_dht_line.conf \ + multipeer_topo.dat + +check_SCRIPTS = \ + test_dht_tools.sh + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/dht/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/dht/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +dht.conf: $(top_builddir)/config.status $(srcdir)/dht.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_block_dht.la: $(libgnunet_plugin_block_dht_la_OBJECTS) $(libgnunet_plugin_block_dht_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_block_dht_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_dht_la_OBJECTS) $(libgnunet_plugin_block_dht_la_LIBADD) $(LIBS) +libgnunetdht.la: $(libgnunetdht_la_OBJECTS) $(libgnunetdht_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetdht_la_LINK) -rpath $(libdir) $(libgnunetdht_la_OBJECTS) $(libgnunetdht_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-dht-get$(EXEEXT): $(gnunet_dht_get_OBJECTS) $(gnunet_dht_get_DEPENDENCIES) + @rm -f gnunet-dht-get$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_dht_get_OBJECTS) $(gnunet_dht_get_LDADD) $(LIBS) +gnunet-dht-put$(EXEEXT): $(gnunet_dht_put_OBJECTS) $(gnunet_dht_put_DEPENDENCIES) + @rm -f gnunet-dht-put$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_dht_put_OBJECTS) $(gnunet_dht_put_LDADD) $(LIBS) +gnunet-service-dht$(EXEEXT): $(gnunet_service_dht_OBJECTS) $(gnunet_service_dht_DEPENDENCIES) + @rm -f gnunet-service-dht$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_dht_OBJECTS) $(gnunet_service_dht_LDADD) $(LIBS) +test_dht_2dtorus$(EXEEXT): $(test_dht_2dtorus_OBJECTS) $(test_dht_2dtorus_DEPENDENCIES) + @rm -f test_dht_2dtorus$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_dht_2dtorus_OBJECTS) $(test_dht_2dtorus_LDADD) $(LIBS) +test_dht_api$(EXEEXT): $(test_dht_api_OBJECTS) $(test_dht_api_DEPENDENCIES) + @rm -f test_dht_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_dht_api_OBJECTS) $(test_dht_api_LDADD) $(LIBS) +test_dht_line$(EXEEXT): $(test_dht_line_OBJECTS) $(test_dht_line_DEPENDENCIES) + @rm -f test_dht_line$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_dht_line_OBJECTS) $(test_dht_line_LDADD) $(LIBS) +test_dht_monitor$(EXEEXT): $(test_dht_monitor_OBJECTS) $(test_dht_monitor_DEPENDENCIES) + @rm -f test_dht_monitor$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_dht_monitor_OBJECTS) $(test_dht_monitor_LDADD) $(LIBS) +test_dht_multipeer$(EXEEXT): $(test_dht_multipeer_OBJECTS) $(test_dht_multipeer_DEPENDENCIES) + @rm -f test_dht_multipeer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_dht_multipeer_OBJECTS) $(test_dht_multipeer_LDADD) $(LIBS) +test_dht_twopeer$(EXEEXT): $(test_dht_twopeer_OBJECTS) $(test_dht_twopeer_DEPENDENCIES) + @rm -f test_dht_twopeer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_dht_twopeer_OBJECTS) $(test_dht_twopeer_LDADD) $(LIBS) +test_dht_twopeer_get_put$(EXEEXT): $(test_dht_twopeer_get_put_OBJECTS) $(test_dht_twopeer_get_put_DEPENDENCIES) + @rm -f test_dht_twopeer_get_put$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_dht_twopeer_get_put_OBJECTS) $(test_dht_twopeer_get_put_LDADD) $(LIBS) +test_dht_twopeer_path_tracking$(EXEEXT): $(test_dht_twopeer_path_tracking_OBJECTS) $(test_dht_twopeer_path_tracking_DEPENDENCIES) + @rm -f test_dht_twopeer_path_tracking$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_dht_twopeer_path_tracking_OBJECTS) $(test_dht_twopeer_path_tracking_LDADD) $(LIBS) +test_dht_twopeer_put_get$(EXEEXT): $(test_dht_twopeer_put_get_OBJECTS) $(test_dht_twopeer_put_get_DEPENDENCIES) + @rm -f test_dht_twopeer_put_get$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_dht_twopeer_put_get_OBJECTS) $(test_dht_twopeer_put_get_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dht_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-dht-get.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-dht-put.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_clients.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_datacache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_hello.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_neighbours.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_nse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_routing.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_dht.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_monitor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_multipeer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_topo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_twopeer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_twopeer_get_put.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_twopeer_path_tracking.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_twopeer_put_get.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-pkgcfgDATA \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/dht/dht.conf.in b/src/dht/dht.conf.in new file mode 100644 index 0000000..17c13e9 --- /dev/null +++ b/src/dht/dht.conf.in @@ -0,0 +1,39 @@ +[dht] +AUTOSTART = YES +@UNIXONLY@ PORT = 2095 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dht +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +BUCKET_SIZE = 4 +UNIXPATH = /tmp/gnunet-service-dht.sock +# This could be relaxed... +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +# DISABLE_SOCKET_FORWARDING = NO +# DEBUG = YES +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = +# DO_FIND_PEER = +# STRICT_KADEMLIA = +# USE_MAX_HOPS = +# MAX_HOPS = +# REPUBLISH = YES +# REPLICATION_FREQUENCY = 60 +# STOP_ON_CLOSEST = +# STOP_FOUND = +# CONVERGE_MODIFIER = + + +[dhtcache] +DATABASE = sqlite +QUOTA = 1 MB + diff --git a/src/dht/dht.h b/src/dht/dht.h new file mode 100644 index 0000000..9894be8 --- /dev/null +++ b/src/dht/dht.h @@ -0,0 +1,261 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Christian Grothoff + * @author Nathan Evans + * @file dht/dht.h + */ + +#ifndef DHT_H +#define DHT_H + + +/** + * Size of the bloom filter the DHT uses to filter peers. + */ +#define DHT_BLOOM_SIZE 128 + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message which indicates the DHT should cancel outstanding + * requests and discard any state. + */ +struct GNUNET_DHT_ClientGetStopMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DHT_GET_STOP + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Unique ID identifying this request + */ + uint64_t unique_id GNUNET_PACKED; + + /** + * Key of this request + */ + GNUNET_HashCode key; + +}; + + +/** + * DHT GET message sent from clients to service. Indicates that a GET + * request should be issued. + */ +struct GNUNET_DHT_ClientGetMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET + */ + struct GNUNET_MessageHeader header; + + /** + * Message options, actually an 'enum GNUNET_DHT_RouteOption' value. + */ + uint32_t options GNUNET_PACKED; + + /** + * Replication level for this message + */ + uint32_t desired_replication_level GNUNET_PACKED; + + /** + * The type for the data for the GET request; actually an 'enum + * GNUNET_BLOCK_Type'. + */ + uint32_t type; + + /** + * The key to search for + */ + GNUNET_HashCode key; + + /** + * Unique ID identifying this request, if 0 then + * the client will not expect a response + */ + uint64_t unique_id GNUNET_PACKED; + + /* Possibly followed by xquery, copied to end of this dealy do */ + +}; + + +/** + * Reply to a GET send from the service to a client. + */ +struct GNUNET_DHT_ClientResultMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * The type for the data. + */ + uint32_t type; + + /** + * Number of peers recorded in the outgoing path from source to the + * storgage location of this message. + */ + uint32_t put_path_length GNUNET_PACKED; + + /** + * The number of peer identities recorded from the storage location + * to this peer. + */ + uint32_t get_path_length GNUNET_PACKED; + + /** + * Unique ID of the matching GET request. + */ + uint64_t unique_id GNUNET_PACKED; + + /** + * When does this entry expire? + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /** + * The key that was searched for + */ + GNUNET_HashCode key; + + /* put path, get path and actual data are copied to end of this dealy do */ + +}; + + +/** + * Message to insert data into the DHT, sent from clients to DHT service. + */ +struct GNUNET_DHT_ClientPutMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT + */ + struct GNUNET_MessageHeader header; + + /** + * The type of data to insert. + */ + uint32_t type GNUNET_PACKED; + + /** + * Message options, actually an 'enum GNUNET_DHT_RouteOption' value. + */ + uint32_t options GNUNET_PACKED; + + /** + * Replication level for this message + */ + uint32_t desired_replication_level GNUNET_PACKED; + + /** + * How long should this data persist? + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /** + * The key to store the value under. + */ + GNUNET_HashCode key; + + /* DATA copied to end of this message */ + +}; + + +/** + * Message to monitor requests going through peer, clients <--> DHT service. + */ +struct GNUNET_DHT_MonitorMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DHT_MONITOR_{GET, PUT, GET_RESP, PUT_RESP*} + * (*) not yet implemented, necessary for key randomization + */ + struct GNUNET_MessageHeader header; + + /** + * The type of data in the request. + */ + uint32_t type GNUNET_PACKED; + + /** + * Message options, actually an 'enum GNUNET_DHT_RouteOption' value. + */ + uint32_t options GNUNET_PACKED; + + /** + * Replication level for this message + */ + uint32_t desired_replication_level GNUNET_PACKED; + + /** + * Number of peers recorded in the outgoing path from source to the + * storgage location of this message. + */ + uint32_t put_path_length GNUNET_PACKED; + + /** + * The number of peer identities recorded from the storage location + * to this peer. + */ + uint32_t get_path_length GNUNET_PACKED; + + /** + * Unique ID for GET / GET responses. + */ + uint64_t unique_id GNUNET_PACKED; + + /** + * How long should this data persist? + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /** + * The key to store the value under. + */ + GNUNET_HashCode key; + + /* put path (if tracked) */ + + /* get path (if tracked) */ + + /* Payload */ + +}; + +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c new file mode 100644 index 0000000..3cb13b4 --- /dev/null +++ b/src/dht/dht_api.c @@ -0,0 +1,997 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/dht_api.c + * @brief library to access the DHT service + * @author Christian Grothoff + * @author Nathan Evans + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_dht_service.h" +#include "dht.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "dht-api",__VA_ARGS__) + +/** + * Entry in our list of messages to be (re-)transmitted. + */ +struct PendingMessage +{ + /** + * This is a doubly-linked list. + */ + struct PendingMessage *prev; + + /** + * This is a doubly-linked list. + */ + struct PendingMessage *next; + + /** + * Message that is pending, allocated at the end + * of this struct. + */ + const struct GNUNET_MessageHeader *msg; + + /** + * Handle to the DHT API context. + */ + struct GNUNET_DHT_Handle *handle; + + /** + * Continuation to call when the request has been + * transmitted (for the first time) to the service; can be NULL. + */ + GNUNET_SCHEDULER_Task cont; + + /** + * Closure for 'cont'. + */ + void *cont_cls; + + /** + * Timeout task for this message + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * Unique ID for this request + */ + uint64_t unique_id; + + /** + * Free the saved message once sent, set to GNUNET_YES for messages + * that do not receive responses; GNUNET_NO if this pending message + * is aliased from a 'struct GNUNET_DHT_RouteHandle' and will be freed + * from there. + */ + int free_on_send; + + /** + * GNUNET_YES if this message is in our pending queue right now. + */ + int in_pending_queue; + +}; + + +/** + * Handle to a GET request + */ +struct GNUNET_DHT_GetHandle +{ + + /** + * Iterator to call on data receipt + */ + GNUNET_DHT_GetIterator iter; + + /** + * Closure for the iterator callback + */ + void *iter_cls; + + /** + * Main handle to this DHT api + */ + struct GNUNET_DHT_Handle *dht_handle; + + /** + * The actual message sent for this request, + * used for retransmitting requests on service + * failure/reconnect. Freed on route_stop. + */ + struct PendingMessage *message; + + /** + * Key that this get request is for + */ + GNUNET_HashCode key; + + /** + * Unique identifier for this request (for key collisions). + */ + uint64_t unique_id; + +}; + + +/** + * Handle to a monitoring request. + */ +struct GNUNET_DHT_MonitorHandle +{ + /** + * DLL. + */ + struct GNUNET_DHT_MonitorHandle *next; + + /** + * DLL. + */ + struct GNUNET_DHT_MonitorHandle *prev; + + /** + * Main handle to this DHT api. + */ + struct GNUNET_DHT_Handle *dht_handle; + + /** + * Type of block looked for. + */ + enum GNUNET_BLOCK_Type type; + + /** + * Key being looked for, NULL == all. + */ + GNUNET_HashCode *key; + + /** + * Callback for each received message of interest. + */ + GNUNET_DHT_MonitorCB cb; + + /** + * Closure for cb. + */ + void *cb_cls; + +}; + + +/** + * Connection to the DHT service. + */ +struct GNUNET_DHT_Handle +{ + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Socket (if available). + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Currently pending transmission request (or NULL). + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Head of linked list of messages we would like to transmit. + */ + struct PendingMessage *pending_head; + + /** + * Tail of linked list of messages we would like to transmit. + */ + struct PendingMessage *pending_tail; + + /** + * Head of linked list of messages we would like to monitor. + */ + struct GNUNET_DHT_MonitorHandle *monitor_head; + + /** + * Tail of linked list of messages we would like to monitor. + */ + struct GNUNET_DHT_MonitorHandle *monitor_tail; + + /** + * Hash map containing the current outstanding unique requests + * (values are of type 'struct GNUNET_DHT_RouteHandle'). + */ + struct GNUNET_CONTAINER_MultiHashMap *active_requests; + + /** + * Task for trying to reconnect. + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * How quickly should we retry? Used for exponential back-off on + * connect-errors. + */ + struct GNUNET_TIME_Relative retry_time; + + /** + * Generator for unique ids. + */ + uint64_t uid_gen; + + /** + * Did we start our receive loop yet? + */ + int in_receive; +}; + + +/** + * Handler for messages received from the DHT service + * a demultiplexer which handles numerous message types + * + */ +static void +service_message_handler (void *cls, const struct GNUNET_MessageHeader *msg); + + +/** + * Try to (re)connect to the DHT service. + * + * @return GNUNET_YES on success, GNUNET_NO on failure. + */ +static int +try_connect (struct GNUNET_DHT_Handle *handle) +{ + if (handle->client != NULL) + return GNUNET_OK; + handle->in_receive = GNUNET_NO; + handle->client = GNUNET_CLIENT_connect ("dht", handle->cfg); + if (handle->client == NULL) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Failed to connect to the DHT service!\n")); + return GNUNET_NO; + } + return GNUNET_YES; +} + + +/** + * Add the request corresponding to the given route handle + * to the pending queue (if it is not already in there). + * + * @param cls the 'struct GNUNET_DHT_Handle*' + * @param key key for the request (not used) + * @param value the 'struct GNUNET_DHT_GetHandle*' + * @return GNUNET_YES (always) + */ +static int +add_request_to_pending (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_DHT_Handle *handle = cls; + struct GNUNET_DHT_GetHandle *rh = value; + + if (GNUNET_NO == rh->message->in_pending_queue) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Retransmitting request related to %s to DHT %p\n", GNUNET_h2s (key), + handle); + GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, + rh->message); + rh->message->in_pending_queue = GNUNET_YES; + } + return GNUNET_YES; +} + + +/** + * Try to send messages from list of messages to send + * @param handle DHT_Handle + */ +static void +process_pending_messages (struct GNUNET_DHT_Handle *handle); + + +/** + * Try reconnecting to the dht service. + * + * @param cls GNUNET_DHT_Handle + * @param tc scheduler context + */ +static void +try_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_DHT_Handle *handle = cls; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting with DHT %p\n", handle); + handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + if (handle->retry_time.rel_value < GNUNET_CONSTANTS_SERVICE_RETRY.rel_value) + handle->retry_time = GNUNET_CONSTANTS_SERVICE_RETRY; + else + handle->retry_time = GNUNET_TIME_relative_multiply (handle->retry_time, 2); + if (handle->retry_time.rel_value > GNUNET_CONSTANTS_SERVICE_TIMEOUT.rel_value) + handle->retry_time = GNUNET_CONSTANTS_SERVICE_TIMEOUT; + handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + if (GNUNET_YES != try_connect (handle)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "dht reconnect failed(!)\n"); + return; + } + GNUNET_CONTAINER_multihashmap_iterate (handle->active_requests, + &add_request_to_pending, handle); + process_pending_messages (handle); +} + + +/** + * Try reconnecting to the DHT service. + * + * @param handle handle to dht to (possibly) disconnect and reconnect + */ +static void +do_disconnect (struct GNUNET_DHT_Handle *handle) +{ + if (handle->client == NULL) + return; + GNUNET_assert (handle->reconnect_task == GNUNET_SCHEDULER_NO_TASK); + if (NULL != handle->th) + GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); + handle->th = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Disconnecting from DHT service, will try to reconnect in %llu ms\n", + (unsigned long long) handle->retry_time.rel_value); + GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO); + handle->client = NULL; + handle->reconnect_task = + GNUNET_SCHEDULER_add_delayed (handle->retry_time, &try_reconnect, handle); +} + + +/** + * Transmit the next pending message, called by notify_transmit_ready + */ +static size_t +transmit_pending (void *cls, size_t size, void *buf); + + +/** + * Try to send messages from list of messages to send + */ +static void +process_pending_messages (struct GNUNET_DHT_Handle *handle) +{ + struct PendingMessage *head; + + if (handle->client == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "process_pending_messages called, but client is null, reconnecting\n"); + do_disconnect (handle); + return; + } + if (handle->th != NULL) + return; + if (NULL == (head = handle->pending_head)) + return; + handle->th = + GNUNET_CLIENT_notify_transmit_ready (handle->client, + ntohs (head->msg->size), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &transmit_pending, + handle); + if (NULL != handle->th) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "notify_transmit_ready returned NULL, reconnecting\n"); + do_disconnect (handle); +} + + +/** + * Transmit the next pending message, called by notify_transmit_ready + */ +static size_t +transmit_pending (void *cls, size_t size, void *buf) +{ + struct GNUNET_DHT_Handle *handle = cls; + struct PendingMessage *head; + size_t tsize; + + handle->th = NULL; + if (buf == NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmission to DHT service failed! Reconnecting!\n"); + do_disconnect (handle); + return 0; + } + if (NULL == (head = handle->pending_head)) + return 0; + + tsize = ntohs (head->msg->size); + if (size < tsize) + { + process_pending_messages (handle); + return 0; + } + memcpy (buf, head->msg, tsize); + GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, + head); + head->in_pending_queue = GNUNET_NO; + if (head->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (head->timeout_task); + head->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != head->cont) + { + head->cont (head->cont_cls, NULL); + head->cont = NULL; + head->cont_cls = NULL; + } + if (GNUNET_YES == head->free_on_send) + GNUNET_free (head); + process_pending_messages (handle); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Forwarded request of %u bytes to DHT service\n", (unsigned int) tsize); + if (GNUNET_NO == handle->in_receive) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting to process replies from DHT\n"); + handle->in_receive = GNUNET_YES; + GNUNET_CLIENT_receive (handle->client, &service_message_handler, handle, + GNUNET_TIME_UNIT_FOREVER_REL); + } + return tsize; +} + + +/** + * Process a given reply that might match the given + * request. + * + * @param cls the 'struct GNUNET_DHT_ClientResultMessage' + * @param key query of the request + * @param value the 'struct GNUNET_DHT_RouteHandle' of a request matching the same key + * @return GNUNET_YES to continue to iterate over all results, + * GNUNET_NO if the reply is malformed + */ +static int +process_reply (void *cls, const GNUNET_HashCode * key, void *value) +{ + const struct GNUNET_DHT_ClientResultMessage *dht_msg = cls; + struct GNUNET_DHT_GetHandle *get_handle = value; + const struct GNUNET_PeerIdentity *put_path; + const struct GNUNET_PeerIdentity *get_path; + uint32_t put_path_length; + uint32_t get_path_length; + size_t data_length; + size_t msize; + size_t meta_length; + const void *data; + + if (dht_msg->unique_id != get_handle->unique_id) + { + /* UID mismatch */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Ignoring reply for %s: UID mismatch: %llu/%llu\n", GNUNET_h2s (key), + dht_msg->unique_id, get_handle->unique_id); + return GNUNET_YES; + } + msize = ntohs (dht_msg->header.size); + put_path_length = ntohl (dht_msg->put_path_length); + get_path_length = ntohl (dht_msg->get_path_length); + meta_length = + sizeof (struct GNUNET_DHT_ClientResultMessage) + + sizeof (struct GNUNET_PeerIdentity) * (get_path_length + put_path_length); + if ((msize < meta_length) || + (get_path_length > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || + (put_path_length > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break (0); + return GNUNET_NO; + } + data_length = msize - meta_length; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Giving %u byte reply for %s to application\n", + (unsigned int) data_length, GNUNET_h2s (key)); + put_path = (const struct GNUNET_PeerIdentity *) &dht_msg[1]; + get_path = &put_path[put_path_length]; + data = &get_path[get_path_length]; + get_handle->iter (get_handle->iter_cls, + GNUNET_TIME_absolute_ntoh (dht_msg->expiration), key, + get_path, get_path_length, put_path, put_path_length, + ntohl (dht_msg->type), data_length, data); + return GNUNET_YES; +} + + +/** + * Process a monitoring message from the service. + * + * @param handle The DHT handle. + * @param msg Message from the service. + * + * @return GNUNET_OK if everything went fine, + * GNUNET_SYSERR if the message is malformed. + */ +static int +process_monitor_message (struct GNUNET_DHT_Handle *handle, + const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_DHT_MonitorMessage *m; + struct GNUNET_DHT_MonitorHandle *h; + size_t msize; + + if (ntohs (msg->type) < GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET || + ntohs (msg->type) > GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT) + return GNUNET_SYSERR; + msize = ntohs (msg->size); + if (msize < sizeof (struct GNUNET_DHT_MonitorMessage)) + return GNUNET_SYSERR; + + m = (struct GNUNET_DHT_MonitorMessage *) msg; + h = handle->monitor_head; + while (NULL != h) + { + if (h->type == ntohl(m->type) && + (NULL == h->key || + memcmp (h->key, &m->key, sizeof (GNUNET_HashCode)) == 0)) + { + struct GNUNET_PeerIdentity *path; + uint32_t getl; + uint32_t putl; + + path = (struct GNUNET_PeerIdentity *) &m[1]; + getl = ntohl (m->get_path_length); + putl = ntohl (m->put_path_length); + h->cb (h->cb_cls, ntohs(msg->type), + GNUNET_TIME_absolute_ntoh(m->expiration), + &m->key, + &path[getl], putl, path, getl, + ntohl (m->desired_replication_level), + ntohl (m->options), ntohl (m->type), + (void *) &path[getl + putl], + ntohs (msg->size) - + sizeof (struct GNUNET_DHT_MonitorMessage) - + sizeof (struct GNUNET_PeerIdentity) * (putl + getl)); + } + h = h->next; + } + + return GNUNET_OK; +} + +/** + * Handler for messages received from the DHT service + * a demultiplexer which handles numerous message types + * + * @param cls the 'struct GNUNET_DHT_Handle' + * @param msg the incoming message + */ +static void +service_message_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_DHT_Handle *handle = cls; + const struct GNUNET_DHT_ClientResultMessage *dht_msg; + + if (msg == NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Error receiving data from DHT service, reconnecting\n"); + do_disconnect (handle); + return; + } + if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT) + { + if (process_monitor_message (handle, msg) == GNUNET_OK) + { + GNUNET_CLIENT_receive (handle->client, &service_message_handler, handle, + GNUNET_TIME_UNIT_FOREVER_REL); + return; + } + GNUNET_break (0); + do_disconnect (handle); + return; + } + if (ntohs (msg->size) < sizeof (struct GNUNET_DHT_ClientResultMessage)) + { + GNUNET_break (0); + do_disconnect (handle); + return; + } + dht_msg = (const struct GNUNET_DHT_ClientResultMessage *) msg; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received reply for `%s' from DHT service %p\n", + GNUNET_h2s (&dht_msg->key), handle); + GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_requests, + &dht_msg->key, &process_reply, + (void *) dht_msg); + GNUNET_CLIENT_receive (handle->client, &service_message_handler, handle, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Initialize the connection with the DHT service. + * + * @param cfg configuration to use + * @param ht_len size of the internal hash table to use for + * processing multiple GET/FIND requests in parallel + * + * @return handle to the DHT service, or NULL on error + */ +struct GNUNET_DHT_Handle * +GNUNET_DHT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int ht_len) +{ + struct GNUNET_DHT_Handle *handle; + + handle = GNUNET_malloc (sizeof (struct GNUNET_DHT_Handle)); + handle->cfg = cfg; + handle->uid_gen = + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); + handle->active_requests = GNUNET_CONTAINER_multihashmap_create (ht_len); + if (GNUNET_NO == try_connect (handle)) + { + GNUNET_DHT_disconnect (handle); + return NULL; + } + return handle; +} + + +/** + * Shutdown connection with the DHT service. + * + * @param handle handle of the DHT connection to stop + */ +void +GNUNET_DHT_disconnect (struct GNUNET_DHT_Handle *handle) +{ + struct PendingMessage *pm; + + GNUNET_assert (handle != NULL); + GNUNET_assert (0 == + GNUNET_CONTAINER_multihashmap_size (handle->active_requests)); + if (handle->th != NULL) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); + handle->th = NULL; + } + while (NULL != (pm = handle->pending_head)) + { + GNUNET_assert (GNUNET_YES == pm->in_pending_queue); + GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, + pm); + pm->in_pending_queue = GNUNET_NO; + GNUNET_assert (GNUNET_YES == pm->free_on_send); + if (GNUNET_SCHEDULER_NO_TASK != pm->timeout_task) + GNUNET_SCHEDULER_cancel (pm->timeout_task); + if (NULL != pm->cont) + pm->cont (pm->cont_cls, NULL); + GNUNET_free (pm); + } + if (handle->client != NULL) + { + GNUNET_CLIENT_disconnect (handle->client, GNUNET_YES); + handle->client = NULL; + } + if (handle->reconnect_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (handle->reconnect_task); + GNUNET_CONTAINER_multihashmap_destroy (handle->active_requests); + GNUNET_free (handle); +} + + +/** + * Timeout for the transmission of a fire&forget-request. Clean it up. + * + * @param cls the 'struct PendingMessage' + * @param tc scheduler context + */ +static void +timeout_put_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PendingMessage *pending = cls; + struct GNUNET_DHT_Handle *handle; + + handle = pending->handle; + GNUNET_assert (GNUNET_YES == pending->in_pending_queue); + GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, + pending); + pending->in_pending_queue = GNUNET_NO; + if (pending->cont != NULL) + pending->cont (pending->cont_cls, tc); + GNUNET_free (pending); +} + + +/** + * Perform a PUT operation storing data in the DHT. + * + * @param handle handle to DHT service + * @param key the key to store under + * @param desired_replication_level estimate of how many + * nearest peers this request should reach + * @param options routing options for this message + * @param type type of the value + * @param size number of bytes in data; must be less than 64k + * @param data the data to store + * @param exp desired expiration time for the value + * @param timeout how long to wait for transmission of this request + * @param cont continuation to call when done (transmitting request to service) + * @param cont_cls closure for cont + */ +void +GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle, const GNUNET_HashCode * key, + uint32_t desired_replication_level, + enum GNUNET_DHT_RouteOption options, + enum GNUNET_BLOCK_Type type, size_t size, const char *data, + struct GNUNET_TIME_Absolute exp, + struct GNUNET_TIME_Relative timeout, GNUNET_SCHEDULER_Task cont, + void *cont_cls) +{ + struct GNUNET_DHT_ClientPutMessage *put_msg; + size_t msize; + struct PendingMessage *pending; + + msize = sizeof (struct GNUNET_DHT_ClientPutMessage) + size; + if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || + (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) + { + GNUNET_break (0); + if (NULL != cont) + cont (cont_cls, NULL); + return; + } + pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + put_msg = (struct GNUNET_DHT_ClientPutMessage *) &pending[1]; + pending->msg = &put_msg->header; + pending->handle = handle; + pending->cont = cont; + pending->cont_cls = cont_cls; + pending->free_on_send = GNUNET_YES; + pending->timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, &timeout_put_request, pending); + put_msg->header.size = htons (msize); + put_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT); + put_msg->type = htonl (type); + put_msg->options = htonl ((uint32_t) options); + put_msg->desired_replication_level = htonl (desired_replication_level); + put_msg->expiration = GNUNET_TIME_absolute_hton (exp); + put_msg->key = *key; + memcpy (&put_msg[1], data, size); + GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, + pending); + pending->in_pending_queue = GNUNET_YES; + process_pending_messages (handle); +} + + +/** + * Perform an asynchronous GET operation on the DHT identified. See + * also "GNUNET_BLOCK_evaluate". + * + * @param handle handle to the DHT service + * @param timeout how long to wait for transmission of this request to the service + * @param type expected type of the response object + * @param key the key to look up + * @param desired_replication_level estimate of how many + nearest peers this request should reach + * @param options routing options for this message + * @param xquery extended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param iter function to call on each result + * @param iter_cls closure for iter + * @return handle to stop the async get + */ +struct GNUNET_DHT_GetHandle * +GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle, + struct GNUNET_TIME_Relative timeout, + enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * key, + uint32_t desired_replication_level, + enum GNUNET_DHT_RouteOption options, const void *xquery, + size_t xquery_size, GNUNET_DHT_GetIterator iter, + void *iter_cls) +{ + struct GNUNET_DHT_ClientGetMessage *get_msg; + struct GNUNET_DHT_GetHandle *get_handle; + size_t msize; + struct PendingMessage *pending; + + msize = sizeof (struct GNUNET_DHT_ClientGetMessage) + xquery_size; + if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || + (xquery_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) + { + GNUNET_break (0); + return NULL; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending query for %s to DHT %p\n", + GNUNET_h2s (key), handle); + pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + get_msg = (struct GNUNET_DHT_ClientGetMessage *) &pending[1]; + pending->msg = &get_msg->header; + pending->handle = handle; + pending->free_on_send = GNUNET_NO; + get_msg->header.size = htons (msize); + get_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET); + get_msg->options = htonl ((uint32_t) options); + get_msg->desired_replication_level = htonl (desired_replication_level); + get_msg->type = htonl (type); + get_msg->key = *key; + handle->uid_gen++; + get_msg->unique_id = handle->uid_gen; + memcpy (&get_msg[1], xquery, xquery_size); + GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, + pending); + pending->in_pending_queue = GNUNET_YES; + get_handle = GNUNET_malloc (sizeof (struct GNUNET_DHT_GetHandle)); + get_handle->iter = iter; + get_handle->iter_cls = iter_cls; + get_handle->message = pending; + get_handle->unique_id = get_msg->unique_id; + GNUNET_CONTAINER_multihashmap_put (handle->active_requests, key, get_handle, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + process_pending_messages (handle); + return get_handle; +} + + +/** + * Stop async DHT-get. + * + * @param get_handle handle to the GET operation to stop + */ +void +GNUNET_DHT_get_stop (struct GNUNET_DHT_GetHandle *get_handle) +{ + struct GNUNET_DHT_Handle *handle; + const struct GNUNET_DHT_ClientGetMessage *get_msg; + struct GNUNET_DHT_ClientGetStopMessage *stop_msg; + struct PendingMessage *pending; + + handle = get_handle->message->handle; + get_msg = + (const struct GNUNET_DHT_ClientGetMessage *) get_handle->message->msg; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending STOP for %s to DHT via %p\n", + GNUNET_h2s (&get_msg->key), handle); + /* generate STOP */ + pending = + GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct GNUNET_DHT_ClientGetStopMessage)); + stop_msg = (struct GNUNET_DHT_ClientGetStopMessage *) &pending[1]; + pending->msg = &stop_msg->header; + pending->handle = handle; + pending->free_on_send = GNUNET_YES; + stop_msg->header.size = + htons (sizeof (struct GNUNET_DHT_ClientGetStopMessage)); + stop_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP); + stop_msg->reserved = htonl (0); + stop_msg->unique_id = get_msg->unique_id; + stop_msg->key = get_msg->key; + GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, + pending); + pending->in_pending_queue = GNUNET_YES; + + /* remove 'GET' from active status */ + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (handle->active_requests, + &get_msg->key, + get_handle)); + if (GNUNET_YES == get_handle->message->in_pending_queue) + { + GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, + get_handle->message); + get_handle->message->in_pending_queue = GNUNET_NO; + } + GNUNET_free (get_handle->message); + GNUNET_free (get_handle); + + process_pending_messages (handle); +} + + +/** + * Start monitoring the local DHT service. + * + * @param handle Handle to the DHT service. + * @param type Type of blocks that are of interest. + * @param key Key of data of interest, NULL for all. + * @param cb Callback to process all monitored data. + * @param cb_cls Closure for cb. + * + * @return Handle to stop monitoring. + */ +struct GNUNET_DHT_MonitorHandle * +GNUNET_DHT_monitor_start (struct GNUNET_DHT_Handle *handle, + enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode *key, + GNUNET_DHT_MonitorCB cb, + void *cb_cls) +{ + struct GNUNET_DHT_MonitorHandle *h; + struct GNUNET_DHT_MonitorMessage *m; + struct PendingMessage *pending; + + h = GNUNET_malloc (sizeof (struct GNUNET_DHT_MonitorHandle)); + GNUNET_CONTAINER_DLL_insert(handle->monitor_head, handle->monitor_tail, h); + + GNUNET_assert (NULL != cb); + h->cb = cb; + h->cb_cls = cb_cls; + h->type = type; + h->dht_handle = handle; + if (NULL != key) + { + h->key = GNUNET_malloc (sizeof(GNUNET_HashCode)); + memcpy (h->key, key, sizeof(GNUNET_HashCode)); + } + + pending = GNUNET_malloc (sizeof (struct GNUNET_DHT_MonitorMessage) + + sizeof (struct PendingMessage)); + m = (struct GNUNET_DHT_MonitorMessage *) &pending[1]; + pending->msg = &m->header; + pending->handle = handle; + pending->free_on_send = GNUNET_YES; + m->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET); + m->header.size = htons (sizeof (struct GNUNET_DHT_MonitorMessage)); + m->type = htonl(type); + if (NULL != key) + memcpy (&m->key, key, sizeof(GNUNET_HashCode)); + GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, + pending); + pending->in_pending_queue = GNUNET_YES; + process_pending_messages (handle); + + return h; +} + + +/** + * Stop monitoring. + * + * @param handle The handle to the monitor request returned by monitor_start. + * + * On return get_handle will no longer be valid, caller must not use again!!! + */ +void +GNUNET_DHT_monitor_stop (struct GNUNET_DHT_MonitorHandle *handle) +{ + GNUNET_free_non_null (handle->key); + GNUNET_CONTAINER_DLL_remove (handle->dht_handle->monitor_head, + handle->dht_handle->monitor_tail, + handle); + GNUNET_free (handle); +} + + + +/* end of dht_api.c */ diff --git a/src/dht/gnunet-dht-get.c b/src/dht/gnunet-dht-get.c new file mode 100644 index 0000000..6ad4b30 --- /dev/null +++ b/src/dht/gnunet-dht-get.c @@ -0,0 +1,236 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dht/gnunet-dht-get.c + * @brief search for data in DHT + * @author Christian Grothoff + * @author Nathan Evans + */ +#include "platform.h" +#include "gnunet_dht_service.h" + +/** + * The type of the query + */ +static unsigned int query_type; + +/** + * Desired replication level + */ +static unsigned int replication = 5; + +/** + * The key for the query + */ +static char *query_key; + +/** + * User supplied timeout value (in seconds) + */ +static unsigned long long timeout_request = 5; + +/** + * When this request should really die + */ +struct GNUNET_TIME_Absolute absolute_timeout; + +/** + * Be verbose + */ +static int verbose; + +/** + * Handle to the DHT + */ +static struct GNUNET_DHT_Handle *dht_handle; + +/** + * Global handle of the configuration + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Handle for the get request + */ +static struct GNUNET_DHT_GetHandle *get_handle; + +/** + * Count of results found + */ +static unsigned int result_count; + +/** + * Global status value + */ +static int ret; + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (dht_handle != NULL) + { + GNUNET_DHT_disconnect (dht_handle); + dht_handle = NULL; + } +} + + +static void +cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (get_handle != NULL) + { + GNUNET_DHT_get_stop (get_handle); + get_handle = NULL; + } + GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); +} + + +/** + * Iterator called on each result obtained for a DHT + * operation that expects a reply + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param get_path peers on reply path (or NULL if not recorded) + * @param get_path_length number of entries in get_path + * @param put_path peers on the PUT path (or NULL if not recorded) + * @param put_path_length number of entries in get_path + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +static void +get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + FPRINTF (stdout, "Result %d, type %d:\n%.*s\n", result_count, type, + (unsigned int) size, (char *) data); + result_count++; +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + struct GNUNET_TIME_Relative timeout; + GNUNET_HashCode key; + + cfg = c; + + if (query_key == NULL) + { + if (verbose) + FPRINTF (stderr, "%s", "Must provide key for DHT GET!\n"); + ret = 1; + return; + } + + dht_handle = GNUNET_DHT_connect (cfg, 1); + + if (dht_handle == NULL) + { + if (verbose) + FPRINTF (stderr, "%s", "Couldn't connect to DHT service!\n"); + ret = 1; + return; + } + else if (verbose) + FPRINTF (stderr, "%s", "Connected to DHT service!\n"); + + if (query_type == GNUNET_BLOCK_TYPE_ANY) /* Type of data not set */ + query_type = GNUNET_BLOCK_TYPE_TEST; + + GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key); + + timeout = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, timeout_request); + absolute_timeout = GNUNET_TIME_relative_to_absolute (timeout); + + if (verbose) + FPRINTF (stderr, "Issuing GET request for %s!\n", query_key); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (absolute_timeout), &cleanup_task, NULL); + get_handle = + GNUNET_DHT_get_start (dht_handle, timeout, query_type, &key, replication, + GNUNET_DHT_RO_NONE, NULL, 0, &get_result_iterator, + NULL); + +} + + +/** + * gnunet-dht-get command line options + */ +static struct GNUNET_GETOPT_CommandLineOption options[] = { + {'k', "key", "KEY", + gettext_noop ("the query key"), + 1, &GNUNET_GETOPT_set_string, &query_key}, + {'r', "replication", "LEVEL", + gettext_noop ("how many parallel requests (replicas) to create"), + 1, &GNUNET_GETOPT_set_uint, &replication}, + {'t', "type", "TYPE", + gettext_noop ("the type of data to look for"), + 1, &GNUNET_GETOPT_set_uint, &query_type}, + {'T', "timeout", "TIMEOUT", + gettext_noop ("how long to execute this query before giving up?"), + 1, &GNUNET_GETOPT_set_ulong, &timeout_request}, + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END +}; + + +/** + * Entry point for gnunet-dht-get + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-dht-get", + gettext_noop + ("Issue a GET request to the GNUnet DHT, prints results."), + options, &run, NULL)) ? ret : 1; +} + +/* end of gnunet-dht-get.c */ diff --git a/src/dht/gnunet-dht-put.c b/src/dht/gnunet-dht-put.c new file mode 100644 index 0000000..ef5ae5e --- /dev/null +++ b/src/dht/gnunet-dht-put.c @@ -0,0 +1,207 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dht/gnunet-dht-put.c + * @brief search for data in DHT + * @author Christian Grothoff + * @author Nathan Evans + */ +#include "platform.h" +#include "gnunet_dht_service.h" + +/** + * The type of the query + */ +static unsigned int query_type; + +/** + * The key for the query + */ +static char *query_key; + +/** + * User supplied timeout value + */ +static unsigned long long timeout_request = 5; + +/** + * User supplied expiration value + */ +static unsigned long long expiration_seconds = 3600; + +/** + * Desired replication level. + */ +static unsigned int replication = 5; + +/** + * Be verbose + */ +static int verbose; + +/** + * Handle to the DHT + */ +static struct GNUNET_DHT_Handle *dht_handle; + + +/** + * Global handle of the configuration + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Global status value + */ +static int ret; + +/** + * The data to insert into the dht + */ +static char *data; + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (dht_handle != NULL) + { + GNUNET_DHT_disconnect (dht_handle); + dht_handle = NULL; + } +} + +/** + * Signature of the main function of a task. + * + * @param cls closure + * @param tc context information (why was this task triggered now) + */ +void +message_sent_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (verbose) + FPRINTF (stderr, "%s", _("PUT request sent!\n")); + GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); +} + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + struct GNUNET_TIME_Relative timeout; + struct GNUNET_TIME_Absolute expiration; + GNUNET_HashCode key; + + cfg = c; + + if ((query_key == NULL) || (data == NULL)) + { + FPRINTF (stderr, "%s", _("Must provide KEY and DATA for DHT put!\n")); + ret = 1; + return; + } + + dht_handle = GNUNET_DHT_connect (cfg, 1); + if (dht_handle == NULL) + { + FPRINTF (stderr, _("Could not connect to %s service!\n"), "DHT"); + ret = 1; + return; + } + else if (verbose) + FPRINTF (stderr, _("Connected to %s service!\n"), "DHT"); + + if (query_type == GNUNET_BLOCK_TYPE_ANY) /* Type of data not set */ + query_type = GNUNET_BLOCK_TYPE_TEST; + + GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key); + + timeout = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, timeout_request); + expiration = + GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + expiration_seconds)); + + if (verbose) + FPRINTF (stderr, _("Issuing put request for `%s' with data `%s'!\n"), + query_key, data); + GNUNET_DHT_put (dht_handle, &key, replication, GNUNET_DHT_RO_NONE, query_type, + strlen (data), data, expiration, timeout, &message_sent_cont, + NULL); + +} + + +/** + * gnunet-dht-put command line options + */ +static struct GNUNET_GETOPT_CommandLineOption options[] = { + {'d', "data", "DATA", + gettext_noop ("the data to insert under the key"), + 1, &GNUNET_GETOPT_set_string, &data}, + {'e', "expiration", "EXPIRATION", + gettext_noop ("how long to store this entry in the dht (in seconds)"), + 1, &GNUNET_GETOPT_set_ulong, &expiration_seconds}, + {'k', "key", "KEY", + gettext_noop ("the query key"), + 1, &GNUNET_GETOPT_set_string, &query_key}, + {'r', "replication", "LEVEL", + gettext_noop ("how many replicas to create"), + 1, &GNUNET_GETOPT_set_uint, &replication}, + {'t', "type", "TYPE", + gettext_noop ("the type to insert data as"), + 1, &GNUNET_GETOPT_set_uint, &query_type}, + {'T', "timeout", "TIMEOUT", + gettext_noop ("how long to execute this query before giving up?"), + 1, &GNUNET_GETOPT_set_ulong, &timeout_request}, + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END +}; + + +/** + * Entry point for gnunet-dht-put + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-dht-put", + gettext_noop + ("Issue a PUT request to the GNUnet DHT insert DATA under KEY."), + options, &run, NULL)) ? ret : 1; +} + +/* end of gnunet-dht-put.c */ diff --git a/src/dht/gnunet-service-dht.c b/src/dht/gnunet-service-dht.c new file mode 100644 index 0000000..72575ac --- /dev/null +++ b/src/dht/gnunet-service-dht.c @@ -0,0 +1,190 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht.c + * @brief GNUnet DHT service + * @author Christian Grothoff + * @author Nathan Evans + */ +#include "platform.h" +#include "gnunet_block_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet-service-dht.h" +#include "gnunet-service-dht_clients.h" +#include "gnunet-service-dht_datacache.h" +#include "gnunet-service-dht_hello.h" +#include "gnunet-service-dht_neighbours.h" +#include "gnunet-service-dht_nse.h" +#include "gnunet-service-dht_routing.h" + + + +/** + * Handle for the statistics service. + */ +struct GNUNET_STATISTICS_Handle *GDS_stats; + +/** + * Our handle to the BLOCK library. + */ +struct GNUNET_BLOCK_Context *GDS_block_context; + +/** + * The configuration the DHT service is running with + */ +const struct GNUNET_CONFIGURATION_Handle *GDS_cfg; + +/** + * Our HELLO + */ +struct GNUNET_MessageHeader *GDS_my_hello; + +/** + * Handle to the transport service, for getting our hello + */ +struct GNUNET_TRANSPORT_Handle *GDS_transport_handle; + + +/** + * Handle to get our current HELLO. + */ +static struct GNUNET_TRANSPORT_GetHelloHandle *ghh; + + +/** + * Receive the HELLO from transport service, free current and replace + * if necessary. + * + * @param cls NULL + * @param message HELLO message of peer + */ +static void +process_hello (void *cls, const struct GNUNET_MessageHeader *message) +{ + GNUNET_assert (message != NULL); + GNUNET_free_non_null (GDS_my_hello); + GDS_my_hello = GNUNET_malloc (ntohs (message->size)); + memcpy (GDS_my_hello, message, ntohs (message->size)); +} + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != ghh) + { + GNUNET_TRANSPORT_get_hello_cancel (ghh); + ghh = NULL; + } + if (GDS_transport_handle != NULL) + { + GNUNET_TRANSPORT_disconnect (GDS_transport_handle); + GDS_transport_handle = NULL; + } + GDS_NEIGHBOURS_done (); + GDS_DATACACHE_done (); + GDS_ROUTING_done (); + GDS_HELLO_done (); + GDS_NSE_done (); + if (GDS_block_context != NULL) + { + GNUNET_BLOCK_context_destroy (GDS_block_context); + GDS_block_context = NULL; + } + if (GDS_stats != NULL) + { + GNUNET_STATISTICS_destroy (GDS_stats, GNUNET_YES); + GDS_stats = NULL; + } + GNUNET_free_non_null (GDS_my_hello); + GDS_my_hello = NULL; +} + + +/** + * Process dht requests. + * + * @param cls closure + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + GDS_cfg = c; + GDS_block_context = GNUNET_BLOCK_context_create (GDS_cfg); + GDS_stats = GNUNET_STATISTICS_create ("dht", GDS_cfg); + GDS_ROUTING_init (); + GDS_NSE_init (); + GDS_DATACACHE_init (); + GDS_HELLO_init (); + GDS_CLIENTS_init (server); + if (GNUNET_OK != GDS_NEIGHBOURS_init ()) + { + shutdown_task (NULL, NULL); + return; + } + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + GDS_transport_handle = + GNUNET_TRANSPORT_connect (GDS_cfg, NULL, NULL, NULL, NULL, NULL); + if (GDS_transport_handle == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to connect to transport service!\n")); + return; + } + ghh = GNUNET_TRANSPORT_get_hello (GDS_transport_handle, &process_hello, NULL); +} + + +/** + * The main function for the dht service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + int ret; + + ret = + (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "dht", GNUNET_SERVICE_OPTION_NONE, &run, + NULL)) ? 0 : 1; + GDS_CLIENTS_done (); + return ret; +} + +/* end of gnunet-service-dht.c */ diff --git a/src/dht/gnunet-service-dht.h b/src/dht/gnunet-service-dht.h new file mode 100644 index 0000000..f06b24b --- /dev/null +++ b/src/dht/gnunet-service-dht.h @@ -0,0 +1,60 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht.h + * @brief GNUnet DHT globals + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_DHT_H +#define GNUNET_SERVICE_DHT_H + +#include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" + +#define DEBUG_DHT GNUNET_EXTRA_LOGGING + +/** + * Configuration we use. + */ +extern const struct GNUNET_CONFIGURATION_Handle *GDS_cfg; + +/** + * Our handle to the BLOCK library. + */ +extern struct GNUNET_BLOCK_Context *GDS_block_context; + +/** + * Handle for the statistics service. + */ +extern struct GNUNET_STATISTICS_Handle *GDS_stats; + +/** + * Our HELLO + */ +extern struct GNUNET_MessageHeader *GDS_my_hello; + +/** + * Handle to the transport service, for getting our hello + */ +extern struct GNUNET_TRANSPORT_Handle *GDS_transport_handle; + +#endif diff --git a/src/dht/gnunet-service-dht_clients.c b/src/dht/gnunet-service-dht_clients.c new file mode 100644 index 0000000..96fcd34 --- /dev/null +++ b/src/dht/gnunet-service-dht_clients.c @@ -0,0 +1,1164 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_clients.c + * @brief GNUnet DHT service's client management code + * @author Christian Grothoff + * @author Nathan Evans + */ + +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_protocols.h" +#include "gnunet_statistics_service.h" +#include "gnunet-service-dht.h" +#include "gnunet-service-dht_clients.h" +#include "gnunet-service-dht_datacache.h" +#include "gnunet-service-dht_neighbours.h" +#include "dht.h" + + +/** + * Linked list of messages to send to clients. + */ +struct PendingMessage +{ + /** + * Pointer to next item in the list + */ + struct PendingMessage *next; + + /** + * Pointer to previous item in the list + */ + struct PendingMessage *prev; + + /** + * Actual message to be sent, allocated at the end of the struct: + * // msg = (cast) &pm[1]; + * // memcpy (&pm[1], data, len); + */ + const struct GNUNET_MessageHeader *msg; + +}; + + +/** + * Struct containing information about a client, + * handle to connect to it, and any pending messages + * that need to be sent to it. + */ +struct ClientList +{ + /** + * Linked list of active clients + */ + struct ClientList *next; + + /** + * Linked list of active clients + */ + struct ClientList *prev; + + /** + * The handle to this client + */ + struct GNUNET_SERVER_Client *client_handle; + + /** + * Handle to the current transmission request, NULL + * if none pending. + */ + struct GNUNET_CONNECTION_TransmitHandle *transmit_handle; + + /** + * Linked list of pending messages for this client + */ + struct PendingMessage *pending_head; + + /** + * Tail of linked list of pending messages for this client + */ + struct PendingMessage *pending_tail; + +}; + + +/** + * Entry in the DHT routing table for a client's GET request. + */ +struct ClientQueryRecord +{ + + /** + * The key this request was about + */ + GNUNET_HashCode key; + + /** + * Client responsible for the request. + */ + struct ClientList *client; + + /** + * Extended query (see gnunet_block_lib.h), allocated at the end of this struct. + */ + const void *xquery; + + /** + * Replies we have already seen for this request. + */ + GNUNET_HashCode *seen_replies; + + /** + * Pointer to this nodes heap location in the retry-heap (for fast removal) + */ + struct GNUNET_CONTAINER_HeapNode *hnode; + + /** + * What's the delay between re-try operations that we currently use for this + * request? + */ + struct GNUNET_TIME_Relative retry_frequency; + + /** + * What's the next time we should re-try this request? + */ + struct GNUNET_TIME_Absolute retry_time; + + /** + * The unique identifier of this request + */ + uint64_t unique_id; + + /** + * Number of bytes in xquery. + */ + size_t xquery_size; + + /** + * Number of entries in 'seen_replies'. + */ + unsigned int seen_replies_count; + + /** + * Desired replication level + */ + uint32_t replication; + + /** + * Any message options for this request + */ + uint32_t msg_options; + + /** + * The type for the data for the GET request. + */ + enum GNUNET_BLOCK_Type type; + +}; + + +/** + * Struct containing paremeters of monitoring requests. + */ +struct ClientMonitorRecord +{ + + /** + * Next element in DLL. + */ + struct ClientMonitorRecord *next; + + /** + * Previous element in DLL. + */ + struct ClientMonitorRecord *prev; + + /** + * Type of blocks that are of interest + */ + enum GNUNET_BLOCK_Type type; + + /** + * Key of data of interest, NULL for all. + */ + GNUNET_HashCode *key; + + /** + * Client to notify of these requests. + */ + struct ClientList *client; +}; + + +/** + * List of active clients. + */ +static struct ClientList *client_head; + +/** + * List of active clients. + */ +static struct ClientList *client_tail; + +/** + * List of active monitoring requests. + */ +static struct ClientMonitorRecord *monitor_head; + +/** + * List of active monitoring requests. + */ +static struct ClientMonitorRecord *monitor_tail; + +/** + * Hashmap for fast key based lookup, maps keys to 'struct ClientQueryRecord' entries. + */ +static struct GNUNET_CONTAINER_MultiHashMap *forward_map; + +/** + * Heap with all of our client's request, sorted by retry time (earliest on top). + */ +static struct GNUNET_CONTAINER_Heap *retry_heap; + +/** + * Task that re-transmits requests (using retry_heap). + */ +static GNUNET_SCHEDULER_TaskIdentifier retry_task; + + +/** + * Find a client if it exists, add it otherwise. + * + * @param client the server handle to the client + * + * @return the client if found, a new client otherwise + */ +static struct ClientList * +find_active_client (struct GNUNET_SERVER_Client *client) +{ + struct ClientList *pos = client_head; + struct ClientList *ret; + + while (pos != NULL) + { + if (pos->client_handle == client) + return pos; + pos = pos->next; + } + ret = GNUNET_malloc (sizeof (struct ClientList)); + ret->client_handle = client; + GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ret); + return ret; +} + + +/** + * Iterator over hash map entries that frees all entries + * associated with the given client. + * + * @param cls client to search for in source routes + * @param key current key code (ignored) + * @param value value in the hash map, a ClientQueryRecord + * @return GNUNET_YES (we should continue to iterate) + */ +static int +remove_client_records (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ClientList *client = cls; + struct ClientQueryRecord *record = value; + + if (record->client != client) + return GNUNET_YES; +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Removing client %p's record for key %s\n", client, + GNUNET_h2s (key)); +#endif + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (forward_map, key, + record)); + if (NULL != record->hnode) + GNUNET_CONTAINER_heap_remove_node (record->hnode); + GNUNET_array_grow (record->seen_replies, record->seen_replies_count, 0); + GNUNET_free (record); + return GNUNET_YES; +} + + +/** + * Functions with this signature are called whenever a client + * is disconnected on the network level. + * + * @param cls closure (NULL for dht) + * @param client identification of the client; NULL + * for the last call when the server is destroyed + */ +static void +handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct ClientList *pos; + struct PendingMessage *reply; + struct ClientMonitorRecord *monitor; + +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Local client %p disconnects\n", client); +#endif + pos = find_active_client (client); + GNUNET_CONTAINER_DLL_remove (client_head, client_tail, pos); + if (pos->transmit_handle != NULL) + GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->transmit_handle); + while (NULL != (reply = pos->pending_head)) + { + GNUNET_CONTAINER_DLL_remove (pos->pending_head, pos->pending_tail, reply); + GNUNET_free (reply); + } + monitor = monitor_head; + while (NULL != monitor) + { + if (monitor->client == pos) + { + struct ClientMonitorRecord *next; + + GNUNET_free_non_null (monitor->key); + next = monitor->next; + GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, monitor); + GNUNET_free (monitor); + monitor = next; + } + else + monitor = monitor->next; + } + GNUNET_CONTAINER_multihashmap_iterate (forward_map, &remove_client_records, + pos); + GNUNET_free (pos); +} + + +/** + * Route the given request via the DHT. This includes updating + * the bloom filter and retransmission times, building the P2P + * message and initiating the routing operation. + */ +static void +transmit_request (struct ClientQueryRecord *cqr) +{ + int32_t reply_bf_mutator; + struct GNUNET_CONTAINER_BloomFilter *reply_bf; + struct GNUNET_CONTAINER_BloomFilter *peer_bf; + + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# GET requests from clients injected"), 1, + GNUNET_NO); + reply_bf_mutator = + (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT32_MAX); + reply_bf = + GNUNET_BLOCK_construct_bloomfilter (reply_bf_mutator, cqr->seen_replies, + cqr->seen_replies_count); + peer_bf = + GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, + GNUNET_CONSTANTS_BLOOMFILTER_K); + GDS_NEIGHBOURS_handle_get (cqr->type, cqr->msg_options, cqr->replication, + 0 /* hop count */ , + &cqr->key, cqr->xquery, cqr->xquery_size, reply_bf, + reply_bf_mutator, peer_bf); + GNUNET_CONTAINER_bloomfilter_free (reply_bf); + GNUNET_CONTAINER_bloomfilter_free (peer_bf); + + /* exponential back-off for retries, max 1h */ + cqr->retry_frequency = + GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_HOURS, + GNUNET_TIME_relative_multiply + (cqr->retry_frequency, 2)); + cqr->retry_time = GNUNET_TIME_relative_to_absolute (cqr->retry_frequency); +} + + +/** + * Task that looks at the 'retry_heap' and transmits all of the requests + * on the heap that are ready for transmission. Then re-schedules + * itself (unless the heap is empty). + * + * @param cls unused + * @param tc scheduler context + */ +static void +transmit_next_request_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ClientQueryRecord *cqr; + struct GNUNET_TIME_Relative delay; + + retry_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + while (NULL != (cqr = GNUNET_CONTAINER_heap_remove_root (retry_heap))) + { + cqr->hnode = NULL; + delay = GNUNET_TIME_absolute_get_remaining (cqr->retry_time); + if (delay.rel_value > 0) + { + cqr->hnode = + GNUNET_CONTAINER_heap_insert (retry_heap, cqr, + cqr->retry_time.abs_value); + retry_task = + GNUNET_SCHEDULER_add_delayed (delay, &transmit_next_request_task, + NULL); + return; + } + transmit_request (cqr); + cqr->hnode = + GNUNET_CONTAINER_heap_insert (retry_heap, cqr, + cqr->retry_time.abs_value); + } +} + + +/** + * Handler for PUT messages. + * + * @param cls closure for the service + * @param client the client we received this message from + * @param message the actual message received + */ +static void +handle_dht_local_put (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_DHT_ClientPutMessage *dht_msg; + struct GNUNET_CONTAINER_BloomFilter *peer_bf; + uint16_t size; + + size = ntohs (message->size); + if (size < sizeof (struct GNUNET_DHT_ClientPutMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# PUT requests received from clients"), 1, + GNUNET_NO); + dht_msg = (const struct GNUNET_DHT_ClientPutMessage *) message; + /* give to local clients */ +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Handling local PUT of %u-bytes for query %s\n", + size - sizeof (struct GNUNET_DHT_ClientPutMessage), + GNUNET_h2s (&dht_msg->key)); +#endif + GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (dht_msg->expiration), + &dht_msg->key, 0, NULL, 0, NULL, + ntohl (dht_msg->type), + size - sizeof (struct GNUNET_DHT_ClientPutMessage), + &dht_msg[1]); + /* store locally */ + GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (dht_msg->expiration), + &dht_msg->key, 0, NULL, ntohl (dht_msg->type), + size - sizeof (struct GNUNET_DHT_ClientPutMessage), + &dht_msg[1]); + /* route to other peers */ + peer_bf = + GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, + GNUNET_CONSTANTS_BLOOMFILTER_K); + GDS_NEIGHBOURS_handle_put (ntohl (dht_msg->type), ntohl (dht_msg->options), + ntohl (dht_msg->desired_replication_level), + GNUNET_TIME_absolute_ntoh (dht_msg->expiration), + 0 /* hop count */ , + peer_bf, &dht_msg->key, 0, NULL, &dht_msg[1], + size - + sizeof (struct GNUNET_DHT_ClientPutMessage)); + GNUNET_CONTAINER_bloomfilter_free (peer_bf); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handler for any generic DHT messages, calls the appropriate handler + * depending on message type, sends confirmation if responses aren't otherwise + * expected. + * + * @param cls closure for the service + * @param client the client we received this message from + * @param message the actual message received + */ +static void +handle_dht_local_get (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_DHT_ClientGetMessage *get; + struct ClientQueryRecord *cqr; + size_t xquery_size; + const char *xquery; + uint16_t size; + + size = ntohs (message->size); + if (size < sizeof (struct GNUNET_DHT_ClientGetMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + xquery_size = size - sizeof (struct GNUNET_DHT_ClientGetMessage); + get = (const struct GNUNET_DHT_ClientGetMessage *) message; + xquery = (const char *) &get[1]; + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# GET requests received from clients"), 1, + GNUNET_NO); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received request for %s from local client %p\n", + GNUNET_h2s (&get->key), client); +#endif + cqr = GNUNET_malloc (sizeof (struct ClientQueryRecord) + xquery_size); + cqr->key = get->key; + cqr->client = find_active_client (client); + cqr->xquery = (void *) &cqr[1]; + memcpy (&cqr[1], xquery, xquery_size); + cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, 0); + cqr->retry_frequency = GNUNET_TIME_UNIT_MILLISECONDS; + cqr->retry_time = GNUNET_TIME_absolute_get (); + cqr->unique_id = get->unique_id; + cqr->xquery_size = xquery_size; + cqr->replication = ntohl (get->desired_replication_level); + cqr->msg_options = ntohl (get->options); + cqr->type = ntohl (get->type); + GNUNET_CONTAINER_multihashmap_put (forward_map, &get->key, cqr, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + /* start remote requests */ + if (GNUNET_SCHEDULER_NO_TASK != retry_task) + GNUNET_SCHEDULER_cancel (retry_task); + retry_task = GNUNET_SCHEDULER_add_now (&transmit_next_request_task, NULL); + /* perform local lookup */ + GDS_DATACACHE_handle_get (&get->key, cqr->type, cqr->xquery, xquery_size, + NULL, 0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Closure for 'remove_by_unique_id'. + */ +struct RemoveByUniqueIdContext +{ + /** + * Client that issued the removal request. + */ + struct ClientList *client; + + /** + * Unique ID of the request. + */ + uint64_t unique_id; +}; + + +/** + * Iterator over hash map entries that frees all entries + * that match the given client and unique ID. + * + * @param cls unique ID and client to search for in source routes + * @param key current key code + * @param value value in the hash map, a ClientQueryRecord + * @return GNUNET_YES (we should continue to iterate) + */ +static int +remove_by_unique_id (void *cls, const GNUNET_HashCode * key, void *value) +{ + const struct RemoveByUniqueIdContext *ctx = cls; + struct ClientQueryRecord *record = value; + + if (record->unique_id != ctx->unique_id) + return GNUNET_YES; +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Removing client %p's record for key %s (by unique id)\n", + ctx->client->client_handle, GNUNET_h2s (key)); +#endif + return remove_client_records (ctx->client, key, record); +} + + +/** + * Handler for any generic DHT stop messages, calls the appropriate handler + * depending on message type (if processed locally) + * + * @param cls closure for the service + * @param client the client we received this message from + * @param message the actual message received + * + */ +static void +handle_dht_local_get_stop (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_DHT_ClientGetStopMessage *dht_stop_msg = + (const struct GNUNET_DHT_ClientGetStopMessage *) message; + struct RemoveByUniqueIdContext ctx; + + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# GET STOP requests received from clients"), 1, + GNUNET_NO); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p stopped request for key %s\n", + client, GNUNET_h2s (&dht_stop_msg->key)); +#endif + ctx.client = find_active_client (client); + ctx.unique_id = dht_stop_msg->unique_id; + GNUNET_CONTAINER_multihashmap_get_multiple (forward_map, &dht_stop_msg->key, + &remove_by_unique_id, &ctx); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handler for monitor messages + * + * @param cls closure for the service + * @param client the client we received this message from + * @param message the actual message received + * + */ +static void +handle_dht_local_monitor (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct ClientMonitorRecord *r; + const struct GNUNET_DHT_MonitorMessage *msg; + unsigned int i; + char *c; + + msg = (struct GNUNET_DHT_MonitorMessage *) message; + r = GNUNET_malloc (sizeof(struct ClientMonitorRecord)); + + r->client = find_active_client(client); + r->type = ntohl(msg->type); + c = (char *) &msg->key; + for (i = 0; i < sizeof (GNUNET_HashCode) && c[i] == 0; i++); + if (sizeof (GNUNET_HashCode) == i) + r->key = NULL; + else + { + r->key = GNUNET_malloc (sizeof (GNUNET_HashCode)); + memcpy (r->key, &msg->key, sizeof (GNUNET_HashCode)); + } + GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, r); + // FIXME add remove somewhere + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Task run to check for messages that need to be sent to a client. + * + * @param client a ClientList, containing the client and any messages to be sent to it + */ +static void +process_pending_messages (struct ClientList *client); + + +/** + * Callback called as a result of issuing a GNUNET_SERVER_notify_transmit_ready + * request. A ClientList is passed as closure, take the head of the list + * and copy it into buf, which has the result of sending the message to the + * client. + * + * @param cls closure to this call + * @param size maximum number of bytes available to send + * @param buf where to copy the actual message to + * + * @return the number of bytes actually copied, 0 indicates failure + */ +static size_t +send_reply_to_client (void *cls, size_t size, void *buf) +{ + struct ClientList *client = cls; + char *cbuf = buf; + struct PendingMessage *reply; + size_t off; + size_t msize; + + client->transmit_handle = NULL; + if (buf == NULL) + { + /* client disconnected */ +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client %p disconnected, pending messages will be discarded\n", + client->client_handle); +#endif + return 0; + } + off = 0; + while ((NULL != (reply = client->pending_head)) && + (size >= off + (msize = ntohs (reply->msg->size)))) + { + GNUNET_CONTAINER_DLL_remove (client->pending_head, client->pending_tail, + reply); + memcpy (&cbuf[off], reply->msg, msize); + GNUNET_free (reply); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes to client %p\n", + msize, client->client_handle); +#endif + off += msize; + } + process_pending_messages (client); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitted %u/%u bytes to client %p\n", + (unsigned int) off, (unsigned int) size, client->client_handle); +#endif + return off; +} + + +/** + * Task run to check for messages that need to be sent to a client. + * + * @param client a ClientList, containing the client and any messages to be sent to it + */ +static void +process_pending_messages (struct ClientList *client) +{ + if ((client->pending_head == NULL) || (client->transmit_handle != NULL)) + { +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Not asking for transmission to %p now: %s\n", + client->client_handle, + client->pending_head == + NULL ? "no more messages" : "request already pending"); +#endif + return; + } +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking for transmission of %u bytes to client %p\n", + ntohs (client->pending_head->msg->size), client->client_handle); +#endif + client->transmit_handle = + GNUNET_SERVER_notify_transmit_ready (client->client_handle, + ntohs (client->pending_head-> + msg->size), + GNUNET_TIME_UNIT_FOREVER_REL, + &send_reply_to_client, client); +} + + +/** + * Add a PendingMessage to the clients list of messages to be sent + * + * @param client the active client to send the message to + * @param pending_message the actual message to send + */ +static void +add_pending_message (struct ClientList *client, + struct PendingMessage *pending_message) +{ + GNUNET_CONTAINER_DLL_insert_tail (client->pending_head, client->pending_tail, + pending_message); + process_pending_messages (client); +} + + +/** + * Closure for 'forward_reply' + */ +struct ForwardReplyContext +{ + + /** + * Actual message to send to matching clients. + */ + struct PendingMessage *pm; + + /** + * Embedded payload. + */ + const void *data; + + /** + * Type of the data. + */ + enum GNUNET_BLOCK_Type type; + + /** + * Number of bytes in data. + */ + size_t data_size; + + /** + * Do we need to copy 'pm' because it was already used? + */ + int do_copy; + +}; + + +/** + * Iterator over hash map entries that send a given reply to + * each of the matching clients. With some tricky recycling + * of the buffer. + * + * @param cls the 'struct ForwardReplyContext' + * @param key current key + * @param value value in the hash map, a ClientQueryRecord + * @return GNUNET_YES (we should continue to iterate), + * if the result is mal-formed, GNUNET_NO + */ +static int +forward_reply (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ForwardReplyContext *frc = cls; + struct ClientQueryRecord *record = value; + struct PendingMessage *pm; + struct GNUNET_DHT_ClientResultMessage *reply; + enum GNUNET_BLOCK_EvaluationResult eval; + int do_free; + GNUNET_HashCode ch; + unsigned int i; + + if ((record->type != GNUNET_BLOCK_TYPE_ANY) && (record->type != frc->type)) + { +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Record type missmatch, not passing request for key %s to local client\n", + GNUNET_h2s (key)); +#endif + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Key match, type mismatches in REPLY to CLIENT"), + 1, GNUNET_NO); + return GNUNET_YES; /* type mismatch */ + } + GNUNET_CRYPTO_hash (frc->data, frc->data_size, &ch); + for (i = 0; i < record->seen_replies_count; i++) + if (0 == memcmp (&record->seen_replies[i], &ch, sizeof (GNUNET_HashCode))) + { +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Duplicate reply, not passing request for key %s to local client\n", + GNUNET_h2s (key)); +#endif + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Duplicate REPLIES to CLIENT request dropped"), + 1, GNUNET_NO); + return GNUNET_YES; /* duplicate */ + } + eval = + GNUNET_BLOCK_evaluate (GDS_block_context, record->type, key, NULL, 0, + record->xquery, record->xquery_size, frc->data, + frc->data_size); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Evaluation result is %d for key %s for local client's query\n", + (int) eval, GNUNET_h2s (key)); +#endif + switch (eval) + { + case GNUNET_BLOCK_EVALUATION_OK_LAST: + do_free = GNUNET_YES; + break; + case GNUNET_BLOCK_EVALUATION_OK_MORE: + GNUNET_array_append (record->seen_replies, record->seen_replies_count, ch); + do_free = GNUNET_NO; + break; + case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: + /* should be impossible to encounter here */ + GNUNET_break (0); + return GNUNET_YES; + case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: + GNUNET_break_op (0); + return GNUNET_NO; + case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: + GNUNET_break (0); + return GNUNET_NO; + case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: + GNUNET_break (0); + return GNUNET_NO; + case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Unsupported block type (%u) in request!\n"), record->type); + return GNUNET_NO; + default: + GNUNET_break (0); + return GNUNET_NO; + } + if (GNUNET_NO == frc->do_copy) + { + /* first time, we can use the original data */ + pm = frc->pm; + frc->do_copy = GNUNET_YES; + } + else + { + /* two clients waiting for same reply, must copy for queueing */ + pm = GNUNET_malloc (sizeof (struct PendingMessage) + + ntohs (frc->pm->msg->size)); + memcpy (pm, frc->pm, + sizeof (struct PendingMessage) + ntohs (frc->pm->msg->size)); + pm->next = pm->prev = NULL; + } + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# RESULTS queued for clients"), 1, + GNUNET_NO); + reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1]; + reply->unique_id = record->unique_id; +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Queueing reply to query %s for client %p\n", GNUNET_h2s (key), + record->client->client_handle); +#endif + add_pending_message (record->client, pm); + if (GNUNET_YES == do_free) + remove_client_records (record->client, key, record); + return GNUNET_YES; +} + + +/** + * Handle a reply we've received from another peer. If the reply + * matches any of our pending queries, forward it to the respective + * client(s). + * + * @param expiration when will the reply expire + * @param key the query this reply is for + * @param get_path_length number of peers in 'get_path' + * @param get_path path the reply took on get + * @param put_path_length number of peers in 'put_path' + * @param put_path path the reply took on put + * @param type type of the reply + * @param data_size number of bytes in 'data' + * @param data application payload data + */ +void +GDS_CLIENTS_handle_reply (struct GNUNET_TIME_Absolute expiration, + const GNUNET_HashCode * key, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *get_path, + unsigned int put_path_length, + const struct GNUNET_PeerIdentity *put_path, + enum GNUNET_BLOCK_Type type, size_t data_size, + const void *data) +{ + struct ForwardReplyContext frc; + struct PendingMessage *pm; + struct GNUNET_DHT_ClientResultMessage *reply; + struct GNUNET_PeerIdentity *paths; + size_t msize; + + if (NULL == GNUNET_CONTAINER_multihashmap_get (forward_map, key)) + { + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# REPLIES ignored for CLIENTS (no match)"), 1, + GNUNET_NO); + return; /* no matching request, fast exit! */ + } + msize = + sizeof (struct GNUNET_DHT_ClientResultMessage) + data_size + + (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity); + if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Could not pass reply to client, message too big!\n")); + return; + } + pm = (struct PendingMessage *) GNUNET_malloc (msize + + sizeof (struct PendingMessage)); + reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1]; + pm->msg = &reply->header; + reply->header.size = htons ((uint16_t) msize); + reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT); + reply->type = htonl (type); + reply->get_path_length = htonl (get_path_length); + reply->put_path_length = htonl (put_path_length); + reply->unique_id = 0; /* filled in later */ + reply->expiration = GNUNET_TIME_absolute_hton (expiration); + reply->key = *key; + paths = (struct GNUNET_PeerIdentity *) &reply[1]; + memcpy (paths, put_path, + sizeof (struct GNUNET_PeerIdentity) * put_path_length); + memcpy (&paths[put_path_length], get_path, + sizeof (struct GNUNET_PeerIdentity) * get_path_length); + memcpy (&paths[get_path_length + put_path_length], data, data_size); + frc.do_copy = GNUNET_NO; + frc.pm = pm; + frc.data = data; + frc.data_size = data_size; + frc.type = type; + GNUNET_CONTAINER_multihashmap_get_multiple (forward_map, key, &forward_reply, + &frc); + if (GNUNET_NO == frc.do_copy) + { + /* did not match any of the requests, free! */ + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# REPLIES ignored for CLIENTS (no match)"), 1, + GNUNET_NO); + GNUNET_free (pm); + } +} + + +/** + * Check if some client is monitoring messages of this type and notify + * him in that case. + * + * @param mtype Type of the DHT message. + * @param exp When will this value expire. + * @param key Key of the result/request. + * @param putl number of entries in get_path. + * @param put_path peers on the PUT path (or NULL if not recorded). + * @param getl number of entries in get_path. + * @param get_path Peers on reply path (or NULL if not recorded). + * @param desired_replication_level Desired replication level. + * @param type Type of the result/request. + * @param data Pointer to the result data. + * @param size Number of bytes in data. + */ +void +GDS_CLIENTS_process_monitor (uint16_t mtype, + const struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode *key, + uint32_t putl, + const struct GNUNET_PeerIdentity *put_path, + uint32_t getl, + const struct GNUNET_PeerIdentity *get_path, + uint32_t desired_replication_level, + enum GNUNET_BLOCK_Type type, + const struct GNUNET_MessageHeader *data, + uint16_t size) +{ + struct ClientMonitorRecord *m; + struct ClientList **cl; + unsigned int cl_size; + + cl = NULL; + cl_size = 0; + for (m = monitor_head; NULL != m; m = m->next) + { + if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) && + (NULL == m->key || + memcmp (key, m->key, sizeof(GNUNET_HashCode)) == 0)) + { + struct PendingMessage *pm; + struct GNUNET_DHT_MonitorMessage *mmsg; + struct GNUNET_PeerIdentity *path; + size_t msize; + unsigned int i; + + /* Don't send duplicates */ + for (i = 0; i < cl_size; i++) + if (cl[i] == m->client) + break; + if (i < cl_size) + continue; + GNUNET_array_append (cl, cl_size, m->client); + + msize = size; + msize += (getl + putl) * sizeof (struct GNUNET_PeerIdentity); + msize += sizeof (struct GNUNET_DHT_MonitorMessage); + msize += sizeof (struct PendingMessage); + pm = (struct PendingMessage *) GNUNET_malloc (msize); + mmsg = (struct GNUNET_DHT_MonitorMessage *) &pm[1]; + pm->msg = (struct GNUNET_MessageHeader *) mmsg; + mmsg->header.size = htons (msize - sizeof (struct PendingMessage)); + mmsg->header.type = htons (mtype); + mmsg->expiration = GNUNET_TIME_absolute_hton(exp); + memcpy (&mmsg->key, key, sizeof (GNUNET_HashCode)); + mmsg->put_path_length = htonl(putl); + mmsg->get_path_length = htonl(getl); + mmsg->desired_replication_level = htonl (desired_replication_level); + path = (struct GNUNET_PeerIdentity *) &mmsg[1]; + if (putl > 0) + { + memcpy (path, put_path, putl * sizeof (struct GNUNET_PeerIdentity)); + path = &path[putl]; + } + if (getl > 0) + memcpy (path, get_path, getl * sizeof (struct GNUNET_PeerIdentity)); + if (size > 0) + memcpy (&path[getl], data, size); + add_pending_message (m->client, pm); + } + } + GNUNET_free_non_null (cl); +} + + +/** + * Initialize client subsystem. + * + * @param server the initialized server + */ +void +GDS_CLIENTS_init (struct GNUNET_SERVER_Handle *server) +{ + static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = { + {&handle_dht_local_put, NULL, + GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT, 0}, + {&handle_dht_local_get, NULL, + GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET, 0}, + {&handle_dht_local_get_stop, NULL, + GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP, + sizeof (struct GNUNET_DHT_ClientGetStopMessage)}, + {&handle_dht_local_monitor, NULL, + GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET, + sizeof (struct GNUNET_DHT_MonitorMessage)}, + {NULL, NULL, 0, 0} + }; + forward_map = GNUNET_CONTAINER_multihashmap_create (1024); + retry_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + GNUNET_SERVER_add_handlers (server, plugin_handlers); + GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); +} + + +/** + * Shutdown client subsystem. + */ +void +GDS_CLIENTS_done () +{ + GNUNET_assert (client_head == NULL); + GNUNET_assert (client_tail == NULL); + if (GNUNET_SCHEDULER_NO_TASK != retry_task) + { + GNUNET_SCHEDULER_cancel (retry_task); + retry_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (retry_heap)); + GNUNET_CONTAINER_heap_destroy (retry_heap); + retry_heap = NULL; + GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (forward_map)); + GNUNET_CONTAINER_multihashmap_destroy (forward_map); + forward_map = NULL; +} + +/* end of gnunet-service-dht_clients.c */ diff --git a/src/dht/gnunet-service-dht_clients.h b/src/dht/gnunet-service-dht_clients.h new file mode 100644 index 0000000..a477456 --- /dev/null +++ b/src/dht/gnunet-service-dht_clients.h @@ -0,0 +1,103 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_clients.h + * @brief GNUnet DHT service's client management code + * @author Christian Grothoff + * @author Nathan Evans + */ +#ifndef GNUNET_SERVICE_DHT_CLIENT_H +#define GNUNET_SERVICE_DHT_CLIENT_H + +#include "gnunet_util_lib.h" +#include "gnunet_block_lib.h" + +/** + * Handle a reply we've received from another peer. If the reply + * matches any of our pending queries, forward it to the respective + * client(s). + * + * @param expiration when will the reply expire + * @param key the query this reply is for + * @param get_path_length number of peers in 'get_path' + * @param get_path path the reply took on get + * @param put_path_length number of peers in 'put_path' + * @param put_path path the reply took on put + * @param type type of the reply + * @param data_size number of bytes in 'data' + * @param data application payload data + */ +void +GDS_CLIENTS_handle_reply (struct GNUNET_TIME_Absolute expiration, + const GNUNET_HashCode * key, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *get_path, + unsigned int put_path_length, + const struct GNUNET_PeerIdentity *put_path, + enum GNUNET_BLOCK_Type type, size_t data_size, + const void *data); + + +/** + * Check if some client is monitoring messages of this type and notify + * him in that case. + * + * @param mtype Type of the DHT message. + * @param exp When will this value expire. + * @param key Key of the result/request. + * @param putl number of entries in get_path. + * @param put_path peers on the PUT path (or NULL if not recorded). + * @param getl number of entries in get_path. + * @param get_path Peers on reply path (or NULL if not recorded). + * @param desired_replication_level Desired replication level. + * @param type Type of the result/request. + * @param data Pointer to the result data. + * @param size Number of bytes in data. + */ +void +GDS_CLIENTS_process_monitor (uint16_t mtype, + const struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode *key, + uint32_t putl, + const struct GNUNET_PeerIdentity *put_path, + uint32_t getl, + const struct GNUNET_PeerIdentity *get_path, + uint32_t desired_replication_level, + enum GNUNET_BLOCK_Type type, + const struct GNUNET_MessageHeader *data, + uint16_t size); + +/** + * Initialize client subsystem. + * + * @param server the initialized server + */ +void +GDS_CLIENTS_init (struct GNUNET_SERVER_Handle *server); + + +/** + * Shutdown client subsystem. + */ +void +GDS_CLIENTS_done (void); + +#endif diff --git a/src/dht/gnunet-service-dht_datacache.c b/src/dht/gnunet-service-dht_datacache.c new file mode 100644 index 0000000..82cd067 --- /dev/null +++ b/src/dht/gnunet-service-dht_datacache.c @@ -0,0 +1,309 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_datacache.c + * @brief GNUnet DHT service's datacache integration + * @author Christian Grothoff + * @author Nathan Evans + */ +#include "platform.h" +#include "gnunet_datacache_lib.h" +#include "gnunet-service-dht_clients.h" +#include "gnunet-service-dht_datacache.h" +#include "gnunet-service-dht_routing.h" +#include "gnunet-service-dht.h" + + +/** + * Handle to the datacache service (for inserting/retrieving data) + */ +static struct GNUNET_DATACACHE_Handle *datacache; + + +/** + * Entry for inserting data into datacache from the DHT. + */ +struct DHTPutEntry +{ + /** + * Size of data. + */ + uint16_t data_size; + + /** + * Length of recorded path. + */ + uint16_t path_length; + + /* PATH ENTRIES */ + + /* PUT DATA */ + +}; + + +/** + * Handle a datum we've received from another peer. Cache if + * possible. + * + * @param expiration when will the reply expire + * @param key the query this reply is for + * @param put_path_length number of peers in 'put_path' + * @param put_path path the reply took on put + * @param type type of the reply + * @param data_size number of bytes in 'data' + * @param data application payload data + */ +void +GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration, + const GNUNET_HashCode * key, + unsigned int put_path_length, + const struct GNUNET_PeerIdentity *put_path, + enum GNUNET_BLOCK_Type type, size_t data_size, + const void *data) +{ + size_t plen = + data_size + put_path_length * sizeof (struct GNUNET_PeerIdentity) + + sizeof (struct DHTPutEntry); + char buf[plen]; + struct DHTPutEntry *pe; + struct GNUNET_PeerIdentity *pp; + + if (datacache == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("%s request received, but have no datacache!\n"), "PUT"); + return; + } + if (data_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + /* Put size is actual data size plus struct overhead plus path length (if any) */ + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# ITEMS stored in datacache"), 1, + GNUNET_NO); + pe = (struct DHTPutEntry *) buf; + pe->data_size = htons (data_size); + pe->path_length = htons ((uint16_t) put_path_length); + pp = (struct GNUNET_PeerIdentity *) &pe[1]; + memcpy (pp, put_path, put_path_length * sizeof (struct GNUNET_PeerIdentity)); + memcpy (&pp[put_path_length], data, data_size); + (void) GNUNET_DATACACHE_put (datacache, key, plen, (const char *) pe, type, + expiration); +} + + +/** + * Context containing information about a GET request. + */ +struct GetRequestContext +{ + /** + * extended query (see gnunet_block_lib.h). + */ + const void *xquery; + + /** + * Bloomfilter to filter out duplicate replies (updated) + */ + struct GNUNET_CONTAINER_BloomFilter **reply_bf; + + /** + * The key this request was about + */ + GNUNET_HashCode key; + + /** + * Number of bytes in xquery. + */ + size_t xquery_size; + + /** + * Mutator value for the reply_bf, see gnunet_block_lib.h + */ + uint32_t reply_bf_mutator; + + /** + * Return value to give back. + */ + enum GNUNET_BLOCK_EvaluationResult eval; +}; + + +/** + * Iterator for local get request results, + * + * @param cls closure for iterator, a DatacacheGetContext + * @param exp when does this value expire? + * @param key the key this data is stored under + * @param size the size of the data identified by key + * @param data the actual data + * @param type the type of the data + * + * @return GNUNET_OK to continue iteration, anything else + * to stop iteration. + */ +static int +datacache_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, size_t size, + const char *data, enum GNUNET_BLOCK_Type type) +{ + struct GetRequestContext *ctx = cls; + const struct DHTPutEntry *pe; + const struct GNUNET_PeerIdentity *pp; + const char *rdata; + size_t rdata_size; + uint16_t put_path_length; + enum GNUNET_BLOCK_EvaluationResult eval; + + pe = (const struct DHTPutEntry *) data; + put_path_length = ntohs (pe->path_length); + rdata_size = ntohs (pe->data_size); + + if (size != + sizeof (struct DHTPutEntry) + rdata_size + + (put_path_length * sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break (0); + return GNUNET_OK; + } + pp = (const struct GNUNET_PeerIdentity *) &pe[1]; + rdata = (const char *) &pp[put_path_length]; + eval = + GNUNET_BLOCK_evaluate (GDS_block_context, type, key, ctx->reply_bf, + ctx->reply_bf_mutator, ctx->xquery, + ctx->xquery_size, rdata, rdata_size); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found reply for query %s in datacache, evaluation result is %d\n", + GNUNET_h2s (key), (int) eval); +#endif + ctx->eval = eval; + switch (eval) + { + case GNUNET_BLOCK_EVALUATION_OK_LAST: + case GNUNET_BLOCK_EVALUATION_OK_MORE: + /* forward to local clients */ + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Good RESULTS found in datacache"), 1, + GNUNET_NO); + GDS_CLIENTS_handle_reply (exp, key, 0, NULL, put_path_length, pp, type, + rdata_size, rdata); + /* forward to other peers */ + GDS_ROUTING_process (type, exp, key, put_path_length, pp, 0, NULL, rdata, + rdata_size); + break; + case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Duplicate RESULTS found in datacache"), 1, + GNUNET_NO); + break; + case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Invalid RESULTS found in datacache"), 1, + GNUNET_NO); + break; + case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: + GNUNET_break (0); + break; + case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: + GNUNET_break_op (0); + return GNUNET_SYSERR; + case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Unsupported RESULTS found in datacache"), 1, + GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Unsupported block type (%u) in local response!\n"), type); + break; + } + return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK; +} + + +/** + * Handle a GET request we've received from another peer. + * + * @param key the query + * @param type requested data type + * @param xquery extended query + * @param xquery_size number of bytes in xquery + * @param reply_bf where the reply bf is (to be) stored, possibly updated, can be NULL + * @param reply_bf_mutator mutation value for reply_bf + * @return evaluation result for the local replies + */ +enum GNUNET_BLOCK_EvaluationResult +GDS_DATACACHE_handle_get (const GNUNET_HashCode * key, + enum GNUNET_BLOCK_Type type, const void *xquery, + size_t xquery_size, + struct GNUNET_CONTAINER_BloomFilter **reply_bf, + uint32_t reply_bf_mutator) +{ + struct GetRequestContext ctx; + + if (datacache == NULL) + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# GET requests given to datacache"), + 1, GNUNET_NO); + ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + ctx.key = *key; + ctx.xquery = xquery; + ctx.xquery_size = xquery_size; + ctx.reply_bf = reply_bf; + ctx.reply_bf_mutator = reply_bf_mutator; + (void) GNUNET_DATACACHE_get (datacache, key, type, &datacache_get_iterator, + &ctx); + return ctx.eval; +} + + +/** + * Initialize datacache subsystem. + */ +void +GDS_DATACACHE_init () +{ + datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache"); +} + + +/** + * Shutdown datacache subsystem. + */ +void +GDS_DATACACHE_done () +{ + if (datacache != NULL) + { + GNUNET_DATACACHE_destroy (datacache); + datacache = NULL; + } +} + + +/* end of gnunet-service-dht_datacache.c */ diff --git a/src/dht/gnunet-service-dht_datacache.h b/src/dht/gnunet-service-dht_datacache.h new file mode 100644 index 0000000..926ad53 --- /dev/null +++ b/src/dht/gnunet-service-dht_datacache.h @@ -0,0 +1,86 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_datacache.h + * @brief GNUnet DHT service's datacache integration + * @author Christian Grothoff + * @author Nathan Evans + */ +#ifndef GNUNET_SERVICE_DHT_DATACACHE_H +#define GNUNET_SERVICE_DHT_DATACACHE_H + +#include "gnunet_util_lib.h" +#include "gnunet_block_lib.h" + +/** + * Handle a datum we've received from another peer. Cache if + * possible. + * + * @param expiration when will the reply expire + * @param key the query this reply is for + * @param put_path_length number of peers in 'put_path' + * @param put_path path the reply took on put + * @param type type of the reply + * @param data_size number of bytes in 'data' + * @param data application payload data + */ +void +GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration, + const GNUNET_HashCode * key, + unsigned int put_path_length, + const struct GNUNET_PeerIdentity *put_path, + enum GNUNET_BLOCK_Type type, size_t data_size, + const void *data); + + +/** + * Handle a GET request we've received from another peer. + * + * @param key the query + * @param type requested data type + * @param xquery extended query + * @param xquery_size number of bytes in xquery + * @param reply_bf where the reply bf is (to be) stored, possibly updated!, can be NULL + * @param reply_bf_mutator mutation value for reply_bf + * @return evaluation result for the local replies + */ +enum GNUNET_BLOCK_EvaluationResult +GDS_DATACACHE_handle_get (const GNUNET_HashCode * key, + enum GNUNET_BLOCK_Type type, const void *xquery, + size_t xquery_size, + struct GNUNET_CONTAINER_BloomFilter **reply_bf, + uint32_t reply_bf_mutator); + + +/** + * Initialize datacache subsystem. + */ +void +GDS_DATACACHE_init (void); + + +/** + * Shutdown datacache subsystem. + */ +void +GDS_DATACACHE_done (void); + +#endif diff --git a/src/dht/gnunet-service-dht_hello.c b/src/dht/gnunet-service-dht_hello.c new file mode 100644 index 0000000..b9cc450 --- /dev/null +++ b/src/dht/gnunet-service-dht_hello.c @@ -0,0 +1,135 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_hello.c + * @brief GNUnet DHT integration with peerinfo + * @author Christian Grothoff + * + * TODO: + * - consider adding mechanism to remove expired HELLOs + */ +#include "platform.h" +#include "gnunet-service-dht.h" +#include "gnunet-service-dht_hello.h" +#include "gnunet_peerinfo_service.h" + + +/** + * Handle for peerinfo notifications. + */ +static struct GNUNET_PEERINFO_NotifyContext *pnc; + +/** + * Hash map of peers to HELLOs. + */ +static struct GNUNET_CONTAINER_MultiHashMap *peer_to_hello; + + +/** + * Obtain a peer's HELLO if available + * + * @param peer peer to look for a HELLO from + * @return HELLO for the given peer + */ +const struct GNUNET_HELLO_Message * +GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer) +{ + if (NULL == peer_to_hello) + return NULL; + return GNUNET_CONTAINER_multihashmap_get (peer_to_hello, &peer->hashPubKey); +} + + +/** + * Function called for each HELLO known to PEERINFO. + * + * @param cls closure + * @param peer id of the peer, NULL for last call + * @param hello hello message for the peer (can be NULL) + * @param err_msg error message (not used) + */ +static void +process_hello (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, const char *err_msg) +{ + struct GNUNET_TIME_Absolute ex; + struct GNUNET_HELLO_Message *hm; + + if (hello == NULL) + return; + ex = GNUNET_HELLO_get_last_expiration (hello); + if (GNUNET_TIME_absolute_get_remaining (ex).rel_value == 0) + return; + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# HELLOs obtained from peerinfo"), 1, + GNUNET_NO); + hm = GNUNET_CONTAINER_multihashmap_get (peer_to_hello, &peer->hashPubKey); + GNUNET_free_non_null (hm); + hm = GNUNET_malloc (GNUNET_HELLO_size (hello)); + memcpy (hm, hello, GNUNET_HELLO_size (hello)); + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONTAINER_multihashmap_put (peer_to_hello, + &peer->hashPubKey, hm, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); +} + + +/** + * Initialize HELLO subsystem. + */ +void +GDS_HELLO_init () +{ + pnc = GNUNET_PEERINFO_notify (GDS_cfg, &process_hello, NULL); + peer_to_hello = GNUNET_CONTAINER_multihashmap_create (256); +} + + +/** + * Free memory occopied by the HELLO. + */ +static int +free_hello (void *cls, const GNUNET_HashCode * key, void *hello) +{ + GNUNET_free (hello); + return GNUNET_OK; +} + + +/** + * Shutdown HELLO subsystem. + */ +void +GDS_HELLO_done () +{ + if (NULL != pnc) + { + GNUNET_PEERINFO_notify_cancel (pnc); + pnc = NULL; + } + if (NULL != peer_to_hello) + { + GNUNET_CONTAINER_multihashmap_iterate (peer_to_hello, &free_hello, NULL); + GNUNET_CONTAINER_multihashmap_destroy (peer_to_hello); + } +} + +/* end of gnunet-service-dht_hello.c */ diff --git a/src/dht/gnunet-service-dht_hello.h b/src/dht/gnunet-service-dht_hello.h new file mode 100644 index 0000000..04a6a49 --- /dev/null +++ b/src/dht/gnunet-service-dht_hello.h @@ -0,0 +1,55 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_hello.h + * @brief GNUnet DHT integration with peerinfo + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_DHT_HELLO_H +#define GNUNET_SERVICE_DHT_HELLO_H + +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" + +/** + * Obtain a peer's HELLO if available + * + * @param peer peer to look for a HELLO from + * @return HELLO for the given peer + */ +const struct GNUNET_HELLO_Message * +GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer); + + +/** + * Initialize HELLO subsystem. + */ +void +GDS_HELLO_init (void); + + +/** + * Shutdown HELLO subsystem. + */ +void +GDS_HELLO_done (void); + +#endif diff --git a/src/dht/gnunet-service-dht_neighbours.c b/src/dht/gnunet-service-dht_neighbours.c new file mode 100644 index 0000000..4ea5dd6 --- /dev/null +++ b/src/dht/gnunet-service-dht_neighbours.c @@ -0,0 +1,2029 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_neighbours.c + * @brief GNUnet DHT service's bucket and neighbour management code + * @author Christian Grothoff + * @author Nathan Evans + */ + +#include "platform.h" +#include "gnunet_block_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" +#include "gnunet_constants.h" +#include "gnunet_protocols.h" +#include "gnunet_nse_service.h" +#include "gnunet_ats_service.h" +#include "gnunet_core_service.h" +#include "gnunet_datacache_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet-service-dht.h" +#include "gnunet-service-dht_clients.h" +#include "gnunet-service-dht_datacache.h" +#include "gnunet-service-dht_hello.h" +#include "gnunet-service-dht_neighbours.h" +#include "gnunet-service-dht_nse.h" +#include "gnunet-service-dht_routing.h" +#include +#include "dht.h" + +/** + * How many buckets will we allow total. + */ +#define MAX_BUCKETS sizeof (GNUNET_HashCode) * 8 + +/** + * What is the maximum number of peers in a given bucket. + */ +#define DEFAULT_BUCKET_SIZE 8 + +/** + * Desired replication level for FIND PEER requests + */ +#define FIND_PEER_REPLICATION_LEVEL 4 + +/** + * Maximum allowed replication level for all requests. + */ +#define MAXIMUM_REPLICATION_LEVEL 16 + +/** + * How often to update our preference levels for peers in our routing tables. + */ +#define DHT_DEFAULT_PREFERENCE_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2) + +/** + * How long at least to wait before sending another find peer request. + */ +#define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) + +/** + * How long at most to wait before sending another find peer request. + */ +#define DHT_MAXIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 10) + +/** + * How long at most to wait for transmission of a GET request to another peer? + */ +#define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2) + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * P2P PUT message + */ +struct PeerPutMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DHT_P2P_PUT + */ + struct GNUNET_MessageHeader header; + + /** + * Processing options + */ + uint32_t options GNUNET_PACKED; + + /** + * Content type. + */ + uint32_t type GNUNET_PACKED; + + /** + * Hop count + */ + uint32_t hop_count GNUNET_PACKED; + + /** + * Replication level for this message + */ + uint32_t desired_replication_level GNUNET_PACKED; + + /** + * Length of the PUT path that follows (if tracked). + */ + uint32_t put_path_length GNUNET_PACKED; + + /** + * When does the content expire? + */ + struct GNUNET_TIME_AbsoluteNBO expiration_time; + + /** + * Bloomfilter (for peer identities) to stop circular routes + */ + char bloomfilter[DHT_BLOOM_SIZE]; + + /** + * The key we are storing under. + */ + GNUNET_HashCode key; + + /* put path (if tracked) */ + + /* Payload */ + +}; + + +/** + * P2P Result message + */ +struct PeerResultMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Content type. + */ + uint32_t type GNUNET_PACKED; + + /** + * Length of the PUT path that follows (if tracked). + */ + uint32_t put_path_length GNUNET_PACKED; + + /** + * Length of the GET path that follows (if tracked). + */ + uint32_t get_path_length GNUNET_PACKED; + + /** + * When does the content expire? + */ + struct GNUNET_TIME_AbsoluteNBO expiration_time; + + /** + * The key of the corresponding GET request. + */ + GNUNET_HashCode key; + + /* put path (if tracked) */ + + /* get path (if tracked) */ + + /* Payload */ + +}; + + +/** + * P2P GET message + */ +struct PeerGetMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DHT_P2P_GET + */ + struct GNUNET_MessageHeader header; + + /** + * Processing options + */ + uint32_t options GNUNET_PACKED; + + /** + * Desired content type. + */ + uint32_t type GNUNET_PACKED; + + /** + * Hop count + */ + uint32_t hop_count GNUNET_PACKED; + + /** + * Desired replication level for this request. + */ + uint32_t desired_replication_level GNUNET_PACKED; + + /** + * Size of the extended query. + */ + uint32_t xquery_size; + + /** + * Bloomfilter mutator. + */ + uint32_t bf_mutator; + + /** + * Bloomfilter (for peer identities) to stop circular routes + */ + char bloomfilter[DHT_BLOOM_SIZE]; + + /** + * The key we are looking for. + */ + GNUNET_HashCode key; + + /* xquery */ + + /* result bloomfilter */ + +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Linked list of messages to send to a particular other peer. + */ +struct P2PPendingMessage +{ + /** + * Pointer to next item in the list + */ + struct P2PPendingMessage *next; + + /** + * Pointer to previous item in the list + */ + struct P2PPendingMessage *prev; + + /** + * Message importance level. FIXME: used? useful? + */ + unsigned int importance; + + /** + * When does this message time out? + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Actual message to be sent, allocated at the end of the struct: + * // msg = (cast) &pm[1]; + * // memcpy (&pm[1], data, len); + */ + const struct GNUNET_MessageHeader *msg; + +}; + + +/** + * Entry for a peer in a bucket. + */ +struct PeerInfo +{ + /** + * Next peer entry (DLL) + */ + struct PeerInfo *next; + + /** + * Prev peer entry (DLL) + */ + struct PeerInfo *prev; + + /** + * Count of outstanding messages for peer. FIXME: NEEDED? + * FIXME: bound queue size!? + */ + unsigned int pending_count; + + /** + * Head of pending messages to be sent to this peer. + */ + struct P2PPendingMessage *head; + + /** + * Tail of pending messages to be sent to this peer. + */ + struct P2PPendingMessage *tail; + + /** + * Core handle for sending messages to this peer. + */ + struct GNUNET_CORE_TransmitHandle *th; + + /** + * Task for scheduling preference updates + */ + GNUNET_SCHEDULER_TaskIdentifier preference_task; + + /** + * What is the identity of the peer? + */ + struct GNUNET_PeerIdentity id; + +#if 0 + /** + * What is the average latency for replies received? + */ + struct GNUNET_TIME_Relative latency; + + /** + * Transport level distance to peer. + */ + unsigned int distance; +#endif + +}; + + +/** + * Peers are grouped into buckets. + */ +struct PeerBucket +{ + /** + * Head of DLL + */ + struct PeerInfo *head; + + /** + * Tail of DLL + */ + struct PeerInfo *tail; + + /** + * Number of peers in the bucket. + */ + unsigned int peers_size; +}; + + +/** + * The lowest currently used bucket, initially 0 (for 0-bits matching bucket). + */ +static unsigned int closest_bucket; + +/** + * How many peers have we added since we sent out our last + * find peer request? + */ +static unsigned int newly_found_peers; + +/** + * The buckets. Array of size MAX_BUCKET_SIZE. Offset 0 means 0 bits matching. + */ +static struct PeerBucket k_buckets[MAX_BUCKETS]; + +/** + * Hash map of all known peers, for easy removal from k_buckets on disconnect. + */ +static struct GNUNET_CONTAINER_MultiHashMap *all_known_peers; + +/** + * Maximum size for each bucket. + */ +static unsigned int bucket_size = DEFAULT_BUCKET_SIZE; + +/** + * Task that sends FIND PEER requests. + */ +static GNUNET_SCHEDULER_TaskIdentifier find_peer_task; + +/** + * Identity of this peer. + */ +static struct GNUNET_PeerIdentity my_identity; + +/** + * Handle to CORE. + */ +static struct GNUNET_CORE_Handle *coreAPI; + +/** + * Handle to ATS. + */ +static struct GNUNET_ATS_PerformanceHandle *atsAPI; + + + +/** + * Find the optimal bucket for this key. + * + * @param hc the hashcode to compare our identity to + * @return the proper bucket index, or GNUNET_SYSERR + * on error (same hashcode) + */ +static int +find_bucket (const GNUNET_HashCode * hc) +{ + unsigned int bits; + + bits = GNUNET_CRYPTO_hash_matching_bits (&my_identity.hashPubKey, hc); + if (bits == MAX_BUCKETS) + { + /* How can all bits match? Got my own ID? */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + return MAX_BUCKETS - bits - 1; +} + + +/** + * Let GNUnet core know that we like the given peer. + * + * @param cls the 'struct PeerInfo' of the peer + * @param tc scheduler context. + */ +static void +update_core_preference (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerInfo *peer = cls; + uint64_t preference; + unsigned int matching; + int bucket; + + peer->preference_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + matching = + GNUNET_CRYPTO_hash_matching_bits (&my_identity.hashPubKey, + &peer->id.hashPubKey); + if (matching >= 64) + matching = 63; + bucket = find_bucket (&peer->id.hashPubKey); + if (bucket == GNUNET_SYSERR) + preference = 0; + else + { + GNUNET_assert (k_buckets[bucket].peers_size != 0); + preference = (1LL << matching) / k_buckets[bucket].peers_size; + } + if (preference == 0) + { + peer->preference_task = + GNUNET_SCHEDULER_add_delayed (DHT_DEFAULT_PREFERENCE_INTERVAL, + &update_core_preference, peer); + return; + } + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# Preference updates given to core"), + 1, GNUNET_NO); + GNUNET_ATS_change_preference (atsAPI, &peer->id, + GNUNET_ATS_PREFERENCE_BANDWIDTH, + (double) preference, GNUNET_ATS_PREFERENCE_END); + peer->preference_task = + GNUNET_SCHEDULER_add_delayed (DHT_DEFAULT_PREFERENCE_INTERVAL, + &update_core_preference, peer); + + +} + + +/** + * Closure for 'add_known_to_bloom'. + */ +struct BloomConstructorContext +{ + /** + * Bloom filter under construction. + */ + struct GNUNET_CONTAINER_BloomFilter *bloom; + + /** + * Mutator to use. + */ + uint32_t bf_mutator; +}; + + +/** + * Add each of the peers we already know to the bloom filter of + * the request so that we don't get duplicate HELLOs. + * + * @param cls the 'struct BloomConstructorContext'. + * @param key peer identity to add to the bloom filter + * @param value value the peer information (unused) + * @return GNUNET_YES (we should continue to iterate) + */ +static int +add_known_to_bloom (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct BloomConstructorContext *ctx = cls; + GNUNET_HashCode mh; + + GNUNET_BLOCK_mingle_hash (key, ctx->bf_mutator, &mh); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding known peer (%s) to bloomfilter for FIND PEER with mutation %u\n", + GNUNET_h2s (key), ctx->bf_mutator); +#endif + GNUNET_CONTAINER_bloomfilter_add (ctx->bloom, &mh); + return GNUNET_YES; +} + + +/** + * Task to send a find peer message for our own peer identifier + * so that we can find the closest peers in the network to ourselves + * and attempt to connect to them. + * + * @param cls closure for this task + * @param tc the context under which the task is running + */ +static void +send_find_peer_message (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TIME_Relative next_send_time; + struct BloomConstructorContext bcc; + struct GNUNET_CONTAINER_BloomFilter *peer_bf; + + find_peer_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + if (newly_found_peers > bucket_size) + { + /* If we are finding many peers already, no need to send out our request right now! */ + find_peer_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &send_find_peer_message, NULL); + newly_found_peers = 0; + return; + } + bcc.bf_mutator = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); + bcc.bloom = + GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, + GNUNET_CONSTANTS_BLOOMFILTER_K); + GNUNET_CONTAINER_multihashmap_iterate (all_known_peers, &add_known_to_bloom, + &bcc); + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# FIND PEER messages initiated"), 1, + GNUNET_NO); + peer_bf = + GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, + GNUNET_CONSTANTS_BLOOMFILTER_K); + // FIXME: pass priority!? + GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_HELLO, + GNUNET_DHT_RO_FIND_PEER, + FIND_PEER_REPLICATION_LEVEL, 0, + &my_identity.hashPubKey, NULL, 0, bcc.bloom, + bcc.bf_mutator, peer_bf); + GNUNET_CONTAINER_bloomfilter_free (peer_bf); + GNUNET_CONTAINER_bloomfilter_free (bcc.bloom); + /* schedule next round */ + next_send_time.rel_value = + DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value + + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + DHT_MAXIMUM_FIND_PEER_INTERVAL.rel_value / + (newly_found_peers + 1)); + newly_found_peers = 0; + find_peer_task = + GNUNET_SCHEDULER_add_delayed (next_send_time, &send_find_peer_message, + NULL); +} + + +/** + * Method called whenever a peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + */ +static void +handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct PeerInfo *ret; + int peer_bucket; + + /* Check for connect to self message */ + if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) + return; +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected %s to %s\n", + GNUNET_i2s (&my_identity), GNUNET_h2s (&peer->hashPubKey)); +#endif + if (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (all_known_peers, + &peer->hashPubKey)) + { + GNUNET_break (0); + return; + } + GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Peers connected"), 1, + GNUNET_NO); + peer_bucket = find_bucket (&peer->hashPubKey); + GNUNET_assert ((peer_bucket >= 0) && (peer_bucket < MAX_BUCKETS)); + ret = GNUNET_malloc (sizeof (struct PeerInfo)); +#if 0 + ret->latency = latency; + ret->distance = distance; +#endif + ret->id = *peer; + GNUNET_CONTAINER_DLL_insert_tail (k_buckets[peer_bucket].head, + k_buckets[peer_bucket].tail, ret); + k_buckets[peer_bucket].peers_size++; + closest_bucket = GNUNET_MAX (closest_bucket, peer_bucket); + if ((peer_bucket > 0) && (k_buckets[peer_bucket].peers_size <= bucket_size)) + { + ret->preference_task = + GNUNET_SCHEDULER_add_now (&update_core_preference, ret); + newly_found_peers++; + } + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (all_known_peers, + &peer->hashPubKey, ret, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + if (1 == GNUNET_CONTAINER_multihashmap_size (all_known_peers)) + { + /* got a first connection, good time to start with FIND PEER requests... */ + find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message, NULL); + } +} + + +/** + * Method called whenever a peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerInfo *to_remove; + int current_bucket; + struct P2PPendingMessage *pos; + unsigned int discarded; + + /* Check for disconnect from self message */ + if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) + return; +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnected %s from %s\n", + GNUNET_i2s (&my_identity), GNUNET_h2s (&peer->hashPubKey)); +#endif + to_remove = + GNUNET_CONTAINER_multihashmap_get (all_known_peers, &peer->hashPubKey); + if (NULL == to_remove) + { + GNUNET_break (0); + return; + } + GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Peers connected"), -1, + GNUNET_NO); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (all_known_peers, + &peer->hashPubKey, + to_remove)); + if (GNUNET_SCHEDULER_NO_TASK != to_remove->preference_task) + { + GNUNET_SCHEDULER_cancel (to_remove->preference_task); + to_remove->preference_task = GNUNET_SCHEDULER_NO_TASK; + } + current_bucket = find_bucket (&to_remove->id.hashPubKey); + GNUNET_assert (current_bucket >= 0); + GNUNET_CONTAINER_DLL_remove (k_buckets[current_bucket].head, + k_buckets[current_bucket].tail, to_remove); + GNUNET_assert (k_buckets[current_bucket].peers_size > 0); + k_buckets[current_bucket].peers_size--; + while ((closest_bucket > 0) && (k_buckets[closest_bucket].peers_size == 0)) + closest_bucket--; + + if (to_remove->th != NULL) + { + GNUNET_CORE_notify_transmit_ready_cancel (to_remove->th); + to_remove->th = NULL; + } + discarded = 0; + while (NULL != (pos = to_remove->head)) + { + GNUNET_CONTAINER_DLL_remove (to_remove->head, to_remove->tail, pos); + discarded++; + GNUNET_free (pos); + } + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Queued messages discarded (peer disconnected)"), + discarded, GNUNET_NO); + GNUNET_free (to_remove); +} + + +/** + * Called when core is ready to send a message we asked for + * out to the destination. + * + * @param cls the 'struct PeerInfo' of the target peer + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +core_transmit_notify (void *cls, size_t size, void *buf) +{ + struct PeerInfo *peer = cls; + char *cbuf = buf; + struct P2PPendingMessage *pending; + size_t off; + size_t msize; + + peer->th = NULL; + while ((NULL != (pending = peer->head)) && + (GNUNET_TIME_absolute_get_remaining (pending->timeout).rel_value == 0)) + { + peer->pending_count--; + GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, pending); + GNUNET_free (pending); + } + if (pending == NULL) + { + /* no messages pending */ + return 0; + } + if (buf == NULL) + { + peer->th = + GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_YES, + pending->importance, + GNUNET_TIME_absolute_get_remaining + (pending->timeout), &peer->id, + ntohs (pending->msg->size), + &core_transmit_notify, peer); + GNUNET_break (NULL != peer->th); + return 0; + } + off = 0; + while ((NULL != (pending = peer->head)) && + (size - off >= (msize = ntohs (pending->msg->size)))) + { + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Bytes transmitted to other peers"), msize, + GNUNET_NO); + memcpy (&cbuf[off], pending->msg, msize); + off += msize; + peer->pending_count--; + GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, pending); + GNUNET_free (pending); + } + if (peer->head != NULL) + { + peer->th = + GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_YES, + pending->importance, + GNUNET_TIME_absolute_get_remaining + (pending->timeout), &peer->id, msize, + &core_transmit_notify, peer); + GNUNET_break (NULL != peer->th); + } + return off; +} + + +/** + * Transmit all messages in the peer's message queue. + * + * @param peer message queue to process + */ +static void +process_peer_queue (struct PeerInfo *peer) +{ + struct P2PPendingMessage *pending; + + if (NULL == (pending = peer->head)) + return; + if (NULL != peer->th) + return; + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Bytes of bandwdith requested from core"), + ntohs (pending->msg->size), GNUNET_NO); + peer->th = + GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_YES, + pending->importance, + GNUNET_TIME_absolute_get_remaining + (pending->timeout), &peer->id, + ntohs (pending->msg->size), + &core_transmit_notify, peer); + GNUNET_break (NULL != peer->th); +} + + +/** + * To how many peers should we (on average) forward the request to + * obtain the desired target_replication count (on average). + * + * @param hop_count number of hops the message has traversed + * @param target_replication the number of total paths desired + * @return Some number of peers to forward the message to + */ +static unsigned int +get_forward_count (uint32_t hop_count, uint32_t target_replication) +{ + uint32_t random_value; + uint32_t forward_count; + float target_value; + + if (hop_count > GDS_NSE_get () * 6.0) + { + /* forcefully terminate */ + return 0; + } + if (hop_count > GDS_NSE_get () * 4.0) + { + /* Once we have reached our ideal number of hops, only forward to 1 peer */ + return 1; + } + /* bound by system-wide maximum */ + target_replication = + GNUNET_MIN (MAXIMUM_REPLICATION_LEVEL, target_replication); + target_value = + 1 + (target_replication - 1.0) / (GDS_NSE_get () + + ((float) (target_replication - 1.0) * + hop_count)); + /* Set forward count to floor of target_value */ + forward_count = (uint32_t) target_value; + /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */ + target_value = target_value - forward_count; + random_value = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); + if (random_value < (target_value * UINT32_MAX)) + forward_count++; + return forward_count; +} + + +/** + * Compute the distance between have and target as a 32-bit value. + * Differences in the lower bits must count stronger than differences + * in the higher bits. + * + * @return 0 if have==target, otherwise a number + * that is larger as the distance between + * the two hash codes increases + */ +static unsigned int +get_distance (const GNUNET_HashCode * target, const GNUNET_HashCode * have) +{ + unsigned int bucket; + unsigned int msb; + unsigned int lsb; + unsigned int i; + + /* We have to represent the distance between two 2^9 (=512)-bit + * numbers as a 2^5 (=32)-bit number with "0" being used for the + * two numbers being identical; furthermore, we need to + * guarantee that a difference in the number of matching + * bits is always represented in the result. + * + * We use 2^32/2^9 numerical values to distinguish between + * hash codes that have the same LSB bit distance and + * use the highest 2^9 bits of the result to signify the + * number of (mis)matching LSB bits; if we have 0 matching + * and hence 512 mismatching LSB bits we return -1 (since + * 512 itself cannot be represented with 9 bits) */ + + /* first, calculate the most significant 9 bits of our + * result, aka the number of LSBs */ + bucket = GNUNET_CRYPTO_hash_matching_bits (target, have); + /* bucket is now a value between 0 and 512 */ + if (bucket == 512) + return 0; /* perfect match */ + if (bucket == 0) + return (unsigned int) -1; /* LSB differs; use max (if we did the bit-shifting + * below, we'd end up with max+1 (overflow)) */ + + /* calculate the most significant bits of the final result */ + msb = (512 - bucket) << (32 - 9); + /* calculate the 32-9 least significant bits of the final result by + * looking at the differences in the 32-9 bits following the + * mismatching bit at 'bucket' */ + lsb = 0; + for (i = bucket + 1; + (i < sizeof (GNUNET_HashCode) * 8) && (i < bucket + 1 + 32 - 9); i++) + { + if (GNUNET_CRYPTO_hash_get_bit (target, i) != + GNUNET_CRYPTO_hash_get_bit (have, i)) + lsb |= (1 << (bucket + 32 - 9 - i)); /* first bit set will be 10, + * last bit set will be 31 -- if + * i does not reach 512 first... */ + } + return msb | lsb; +} + + +/** + * Check whether my identity is closer than any known peers. If a + * non-null bloomfilter is given, check if this is the closest peer + * that hasn't already been routed to. + * + * @param key hash code to check closeness to + * @param bloom bloomfilter, exclude these entries from the decision + * @return GNUNET_YES if node location is closest, + * GNUNET_NO otherwise. + */ +static int +am_closest_peer (const GNUNET_HashCode * key, + const struct GNUNET_CONTAINER_BloomFilter *bloom) +{ + int bits; + int other_bits; + int bucket_num; + int count; + struct PeerInfo *pos; + + if (0 == memcmp (&my_identity.hashPubKey, key, sizeof (GNUNET_HashCode))) + return GNUNET_YES; + bucket_num = find_bucket (key); + GNUNET_assert (bucket_num >= 0); + bits = GNUNET_CRYPTO_hash_matching_bits (&my_identity.hashPubKey, key); + pos = k_buckets[bucket_num].head; + count = 0; + while ((pos != NULL) && (count < bucket_size)) + { + if ((bloom != NULL) && + (GNUNET_YES == + GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))) + { + pos = pos->next; + continue; /* Skip already checked entries */ + } + other_bits = GNUNET_CRYPTO_hash_matching_bits (&pos->id.hashPubKey, key); + if (other_bits > bits) + return GNUNET_NO; + if (other_bits == bits) /* We match the same number of bits */ + return GNUNET_YES; + pos = pos->next; + } + /* No peers closer, we are the closest! */ + return GNUNET_YES; +} + + +/** + * Select a peer from the routing table that would be a good routing + * destination for sending a message for "key". The resulting peer + * must not be in the set of blocked peers.

+ * + * Note that we should not ALWAYS select the closest peer to the + * target, peers further away from the target should be chosen with + * exponentially declining probability. + * + * FIXME: double-check that this is fine + * + * + * @param key the key we are selecting a peer to route to + * @param bloom a bloomfilter containing entries this request has seen already + * @param hops how many hops has this message traversed thus far + * @return Peer to route to, or NULL on error + */ +static struct PeerInfo * +select_peer (const GNUNET_HashCode * key, + const struct GNUNET_CONTAINER_BloomFilter *bloom, uint32_t hops) +{ + unsigned int bc; + unsigned int count; + unsigned int selected; + struct PeerInfo *pos; + unsigned int dist; + unsigned int smallest_distance; + struct PeerInfo *chosen; + + if (hops >= GDS_NSE_get ()) + { + /* greedy selection (closest peer that is not in bloomfilter) */ + smallest_distance = UINT_MAX; + chosen = NULL; + for (bc = 0; bc <= closest_bucket; bc++) + { + pos = k_buckets[bc].head; + count = 0; + while ((pos != NULL) && (count < bucket_size)) + { + if ((bloom == NULL) || + (GNUNET_NO == + GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))) + { + dist = get_distance (key, &pos->id.hashPubKey); + if (dist < smallest_distance) + { + chosen = pos; + smallest_distance = dist; + } + } + else + { +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Excluded peer `%s' due to BF match in greedy routing for %s\n", + GNUNET_i2s (&pos->id), GNUNET_h2s (key)); +#endif + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Peers excluded from routing due to Bloomfilter"), + 1, GNUNET_NO); + } + count++; + pos = pos->next; + } + } + if (NULL == chosen) + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# Peer selection failed"), 1, + GNUNET_NO); + return chosen; + } + + /* select "random" peer */ + /* count number of peers that are available and not filtered */ + count = 0; + for (bc = 0; bc <= closest_bucket; bc++) + { + pos = k_buckets[bc].head; + while ((pos != NULL) && (count < bucket_size)) + { + if ((bloom != NULL) && + (GNUNET_YES == + GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))) + { + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Peers excluded from routing due to Bloomfilter"), + 1, GNUNET_NO); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Excluded peer `%s' due to BF match in random routing for %s\n", + GNUNET_i2s (&pos->id), GNUNET_h2s (key)); +#endif + pos = pos->next; + continue; /* Ignore bloomfiltered peers */ + } + count++; + pos = pos->next; + } + } + if (count == 0) /* No peers to select from! */ + { + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# Peer selection failed"), 1, + GNUNET_NO); + return NULL; + } + /* Now actually choose a peer */ + selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, count); + count = 0; + for (bc = 0; bc <= closest_bucket; bc++) + { + pos = k_buckets[bc].head; + while ((pos != NULL) && (count < bucket_size)) + { + if ((bloom != NULL) && + (GNUNET_YES == + GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))) + { + pos = pos->next; + continue; /* Ignore bloomfiltered peers */ + } + if (0 == selected--) + return pos; + pos = pos->next; + } + } + GNUNET_break (0); + return NULL; +} + + +/** + * Compute the set of peers that the given request should be + * forwarded to. + * + * @param key routing key + * @param bloom bloom filter excluding peers as targets, all selected + * peers will be added to the bloom filter + * @param hop_count number of hops the request has traversed so far + * @param target_replication desired number of replicas + * @param targets where to store an array of target peers (to be + * free'd by the caller) + * @return number of peers returned in 'targets'. + */ +static unsigned int +get_target_peers (const GNUNET_HashCode * key, + struct GNUNET_CONTAINER_BloomFilter *bloom, + uint32_t hop_count, uint32_t target_replication, + struct PeerInfo ***targets) +{ + unsigned int ret; + unsigned int off; + struct PeerInfo **rtargets; + struct PeerInfo *nxt; + + GNUNET_assert (NULL != bloom); + ret = get_forward_count (hop_count, target_replication); + if (ret == 0) + { + *targets = NULL; + return 0; + } + rtargets = GNUNET_malloc (sizeof (struct PeerInfo *) * ret); + for (off = 0; off < ret; off++) + { + nxt = select_peer (key, bloom, hop_count); + if (nxt == NULL) + break; + rtargets[off] = nxt; + GNUNET_break (GNUNET_NO == + GNUNET_CONTAINER_bloomfilter_test (bloom, + &nxt->id.hashPubKey)); + GNUNET_CONTAINER_bloomfilter_add (bloom, &rtargets[off]->id.hashPubKey); + } +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Selected %u/%u peers at hop %u for %s (target was %u)\n", off, + GNUNET_CONTAINER_multihashmap_size (all_known_peers), + (unsigned int) hop_count, GNUNET_h2s (key), ret); +#endif + if (0 == off) + { + GNUNET_free (rtargets); + *targets = NULL; + return 0; + } + *targets = rtargets; + return off; +} + + +/** + * Perform a PUT operation. Forwards the given request to other + * peers. Does not store the data locally. Does not give the + * data to local clients. May do nothing if this is the only + * peer in the network (or if we are the closest peer in the + * network). + * + * @param type type of the block + * @param options routing options + * @param desired_replication_level desired replication count + * @param expiration_time when does the content expire + * @param hop_count how many hops has this message traversed so far + * @param bf Bloom filter of peers this PUT has already traversed + * @param key key for the content + * @param put_path_length number of entries in put_path + * @param put_path peers this request has traversed so far (if tracked) + * @param data payload to store + * @param data_size number of bytes in data + */ +void +GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type type, + enum GNUNET_DHT_RouteOption options, + uint32_t desired_replication_level, + struct GNUNET_TIME_Absolute expiration_time, + uint32_t hop_count, + struct GNUNET_CONTAINER_BloomFilter *bf, + const GNUNET_HashCode * key, + unsigned int put_path_length, + struct GNUNET_PeerIdentity *put_path, + const void *data, size_t data_size) +{ + unsigned int target_count; + unsigned int i; + struct PeerInfo **targets; + struct PeerInfo *target; + struct P2PPendingMessage *pending; + size_t msize; + struct PeerPutMessage *ppm; + struct GNUNET_PeerIdentity *pp; + + GNUNET_assert (NULL != bf); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding myself (%s) to PUT bloomfilter for %s\n", + GNUNET_i2s (&my_identity), GNUNET_h2s (key)); +#endif + GNUNET_CONTAINER_bloomfilter_add (bf, &my_identity.hashPubKey); + GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# PUT requests routed"), + 1, GNUNET_NO); + target_count = + get_target_peers (key, bf, hop_count, desired_replication_level, + &targets); + if (0 == target_count) + { +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Routing PUT for %s terminates after %u hops at %s\n", + GNUNET_h2s (key), (unsigned int) hop_count, + GNUNET_i2s (&my_identity)); +#endif + return; + } + msize = + put_path_length * sizeof (struct GNUNET_PeerIdentity) + data_size + + sizeof (struct PeerPutMessage); + if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + put_path_length = 0; + msize = data_size + sizeof (struct PeerPutMessage); + } + if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + GNUNET_free (targets); + return; + } + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# PUT messages queued for transmission"), + target_count, GNUNET_NO); + for (i = 0; i < target_count; i++) + { + target = targets[i]; +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Routing PUT for %s after %u hops to %s\n", GNUNET_h2s (key), + (unsigned int) hop_count, GNUNET_i2s (&target->id)); +#endif + pending = GNUNET_malloc (sizeof (struct P2PPendingMessage) + msize); + pending->importance = 0; /* FIXME */ + pending->timeout = expiration_time; + ppm = (struct PeerPutMessage *) &pending[1]; + pending->msg = &ppm->header; + ppm->header.size = htons (msize); + ppm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_PUT); + ppm->options = htonl (options); + ppm->type = htonl (type); + ppm->hop_count = htonl (hop_count + 1); + ppm->desired_replication_level = htonl (desired_replication_level); + ppm->put_path_length = htonl (put_path_length); + ppm->expiration_time = GNUNET_TIME_absolute_hton (expiration_time); + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_bloomfilter_test (bf, + &target->id.hashPubKey)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_bloomfilter_get_raw_data (bf, + ppm->bloomfilter, + DHT_BLOOM_SIZE)); + ppm->key = *key; + pp = (struct GNUNET_PeerIdentity *) &ppm[1]; + memcpy (pp, put_path, + sizeof (struct GNUNET_PeerIdentity) * put_path_length); + memcpy (&pp[put_path_length], data, data_size); + GNUNET_CONTAINER_DLL_insert_tail (target->head, target->tail, pending); + target->pending_count++; + process_peer_queue (target); + } + GNUNET_free (targets); +} + + +/** + * Perform a GET operation. Forwards the given request to other + * peers. Does not lookup the key locally. May do nothing if this is + * the only peer in the network (or if we are the closest peer in the + * network). + * + * @param type type of the block + * @param options routing options + * @param desired_replication_level desired replication count + * @param hop_count how many hops did this request traverse so far? + * @param key key for the content + * @param xquery extended query + * @param xquery_size number of bytes in xquery + * @param reply_bf bloomfilter to filter duplicates + * @param reply_bf_mutator mutator for reply_bf + * @param peer_bf filter for peers not to select (again) + */ +void +GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type, + enum GNUNET_DHT_RouteOption options, + uint32_t desired_replication_level, + uint32_t hop_count, const GNUNET_HashCode * key, + const void *xquery, size_t xquery_size, + const struct GNUNET_CONTAINER_BloomFilter *reply_bf, + uint32_t reply_bf_mutator, + struct GNUNET_CONTAINER_BloomFilter *peer_bf) +{ + unsigned int target_count; + unsigned int i; + struct PeerInfo **targets; + struct PeerInfo *target; + struct P2PPendingMessage *pending; + size_t msize; + struct PeerGetMessage *pgm; + char *xq; + size_t reply_bf_size; + + GNUNET_assert (NULL != peer_bf); + GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# GET requests routed"), + 1, GNUNET_NO); + target_count = + get_target_peers (key, peer_bf, hop_count, desired_replication_level, + &targets); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding myself (%s) to GET bloomfilter for %s\n", + GNUNET_i2s (&my_identity), GNUNET_h2s (key)); +#endif + GNUNET_CONTAINER_bloomfilter_add (peer_bf, &my_identity.hashPubKey); + if (0 == target_count) + { +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Routing GET for %s terminates after %u hops at %s\n", + GNUNET_h2s (key), (unsigned int) hop_count, + GNUNET_i2s (&my_identity)); +#endif + return; + } + reply_bf_size = GNUNET_CONTAINER_bloomfilter_get_size (reply_bf); + msize = xquery_size + sizeof (struct PeerGetMessage) + reply_bf_size; + if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + GNUNET_free (targets); + return; + } + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# GET messages queued for transmission"), + target_count, GNUNET_NO); + /* forward request */ + for (i = 0; i < target_count; i++) + { + target = targets[i]; +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Routing GET for %s after %u hops to %s\n", GNUNET_h2s (key), + (unsigned int) hop_count, GNUNET_i2s (&target->id)); +#endif + pending = GNUNET_malloc (sizeof (struct P2PPendingMessage) + msize); + pending->importance = 0; /* FIXME */ + pending->timeout = GNUNET_TIME_relative_to_absolute (GET_TIMEOUT); + pgm = (struct PeerGetMessage *) &pending[1]; + pending->msg = &pgm->header; + pgm->header.size = htons (msize); + pgm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_GET); + pgm->options = htonl (options); + pgm->type = htonl (type); + pgm->hop_count = htonl (hop_count + 1); + pgm->desired_replication_level = htonl (desired_replication_level); + pgm->xquery_size = htonl (xquery_size); + pgm->bf_mutator = reply_bf_mutator; + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_bloomfilter_test (peer_bf, + &target->id.hashPubKey)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_bloomfilter_get_raw_data (peer_bf, + pgm->bloomfilter, + DHT_BLOOM_SIZE)); + pgm->key = *key; + xq = (char *) &pgm[1]; + memcpy (xq, xquery, xquery_size); + if (NULL != reply_bf) + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_bloomfilter_get_raw_data (reply_bf, + &xq + [xquery_size], + reply_bf_size)); + GNUNET_CONTAINER_DLL_insert_tail (target->head, target->tail, pending); + target->pending_count++; + process_peer_queue (target); + } + GNUNET_free (targets); +} + + +/** + * Handle a reply (route to origin). Only forwards the reply back to + * the given peer. Does not do local caching or forwarding to local + * clients. + * + * @param target neighbour that should receive the block (if still connected) + * @param type type of the block + * @param expiration_time when does the content expire + * @param key key for the content + * @param put_path_length number of entries in put_path + * @param put_path peers the original PUT traversed (if tracked) + * @param get_path_length number of entries in put_path + * @param get_path peers this reply has traversed so far (if tracked) + * @param data payload of the reply + * @param data_size number of bytes in data + */ +void +GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target, + enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute expiration_time, + const GNUNET_HashCode * key, + unsigned int put_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *get_path, + const void *data, size_t data_size) +{ + struct PeerInfo *pi; + struct P2PPendingMessage *pending; + size_t msize; + struct PeerResultMessage *prm; + struct GNUNET_PeerIdentity *paths; + + msize = + data_size + sizeof (struct PeerResultMessage) + (get_path_length + + put_path_length) * + sizeof (struct GNUNET_PeerIdentity); + if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || + (get_path_length > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || + (put_path_length > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || + (data_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)) + { + GNUNET_break (0); + return; + } + pi = GNUNET_CONTAINER_multihashmap_get (all_known_peers, &target->hashPubKey); + if (NULL == pi) + { + /* peer disconnected in the meantime, drop reply */ + return; + } + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# RESULT messages queued for transmission"), 1, + GNUNET_NO); + pending = GNUNET_malloc (sizeof (struct P2PPendingMessage) + msize); + pending->importance = 0; /* FIXME */ + pending->timeout = expiration_time; + prm = (struct PeerResultMessage *) &pending[1]; + pending->msg = &prm->header; + prm->header.size = htons (msize); + prm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT); + prm->type = htonl (type); + prm->put_path_length = htonl (put_path_length); + prm->get_path_length = htonl (get_path_length); + prm->expiration_time = GNUNET_TIME_absolute_hton (expiration_time); + prm->key = *key; + paths = (struct GNUNET_PeerIdentity *) &prm[1]; + memcpy (paths, put_path, + put_path_length * sizeof (struct GNUNET_PeerIdentity)); + memcpy (&paths[put_path_length], get_path, + get_path_length * sizeof (struct GNUNET_PeerIdentity)); + memcpy (&paths[put_path_length + get_path_length], data, data_size); + GNUNET_CONTAINER_DLL_insert (pi->head, pi->tail, pending); + pi->pending_count++; + process_peer_queue (pi); +} + + +/** + * To be called on core init/fail. + * + * @param cls service closure + * @param server handle to the server for this service + * @param identity the public identity of this peer + */ +static void +core_init (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *identity) +{ + GNUNET_assert (server != NULL); + my_identity = *identity; +} + + +/** + * Core handler for p2p put requests. + * + * @param cls closure + * @param peer sender of the request + * @param message message + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_dht_p2p_put (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + const struct PeerPutMessage *put; + const struct GNUNET_PeerIdentity *put_path; + const void *payload; + uint32_t putlen; + uint16_t msize; + size_t payload_size; + enum GNUNET_DHT_RouteOption options; + struct GNUNET_CONTAINER_BloomFilter *bf; + GNUNET_HashCode test_key; + + msize = ntohs (message->size); + if (msize < sizeof (struct PeerPutMessage)) + { + GNUNET_break_op (0); + return GNUNET_YES; + } + put = (const struct PeerPutMessage *) message; + putlen = ntohl (put->put_path_length); + if ((msize < + sizeof (struct PeerPutMessage) + + putlen * sizeof (struct GNUNET_PeerIdentity)) || + (putlen > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break_op (0); + return GNUNET_YES; + } + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# P2P PUT requests received"), 1, + GNUNET_NO); + put_path = (const struct GNUNET_PeerIdentity *) &put[1]; + payload = &put_path[putlen]; + options = ntohl (put->options); + payload_size = + msize - (sizeof (struct PeerPutMessage) + + putlen * sizeof (struct GNUNET_PeerIdentity)); + switch (GNUNET_BLOCK_get_key + (GDS_block_context, ntohl (put->type), payload, payload_size, + &test_key)) + { + case GNUNET_YES: + if (0 != memcmp (&test_key, &put->key, sizeof (GNUNET_HashCode))) + { + GNUNET_break_op (0); + return GNUNET_YES; + } + break; + case GNUNET_NO: + GNUNET_break_op (0); + return GNUNET_YES; + case GNUNET_SYSERR: + /* cannot verify, good luck */ + break; + } +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PUT for %s at %s\n", + GNUNET_h2s (&put->key), GNUNET_i2s (&my_identity)); +#endif + bf = GNUNET_CONTAINER_bloomfilter_init (put->bloomfilter, DHT_BLOOM_SIZE, + GNUNET_CONSTANTS_BLOOMFILTER_K); + GNUNET_break_op (GNUNET_YES == + GNUNET_CONTAINER_bloomfilter_test (bf, &peer->hashPubKey)); + { + struct GNUNET_PeerIdentity pp[putlen + 1]; + + /* extend 'put path' by sender */ + if (0 != (options & GNUNET_DHT_RO_RECORD_ROUTE)) + { + memcpy (pp, put_path, putlen * sizeof (struct GNUNET_PeerIdentity)); + pp[putlen] = *peer; + putlen++; + } + else + putlen = 0; + + /* give to local clients */ + GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (put->expiration_time), + &put->key, 0, NULL, putlen, pp, ntohl (put->type), + payload_size, payload); + /* store locally */ + if ((0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) || + (am_closest_peer (&put->key, bf))) + GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh + (put->expiration_time), &put->key, putlen, pp, + ntohl (put->type), payload_size, payload); + /* route to other peers */ + GDS_NEIGHBOURS_handle_put (ntohl (put->type), options, + ntohl (put->desired_replication_level), + GNUNET_TIME_absolute_ntoh (put->expiration_time), + ntohl (put->hop_count), bf, &put->key, putlen, + pp, payload, payload_size); + } + GNUNET_CONTAINER_bloomfilter_free (bf); + GDS_CLIENTS_process_monitor (GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT, + GNUNET_TIME_absolute_ntoh (put->expiration_time), &put->key, + putlen, put_path, 0, NULL, ntohl(put->desired_replication_level), + ntohl (put->type), payload, payload_size); + return GNUNET_YES; +} + + +/** + * We have received a FIND PEER request. Send matching + * HELLOs back. + * + * @param sender sender of the FIND PEER request + * @param key peers close to this key are desired + * @param bf peers matching this bf are excluded + * @param bf_mutator mutator for bf + */ +static void +handle_find_peer (const struct GNUNET_PeerIdentity *sender, + const GNUNET_HashCode * key, + struct GNUNET_CONTAINER_BloomFilter *bf, uint32_t bf_mutator) +{ + int bucket_idx; + struct PeerBucket *bucket; + struct PeerInfo *peer; + unsigned int choice; + GNUNET_HashCode mhash; + const struct GNUNET_HELLO_Message *hello; + + /* first, check about our own HELLO */ + if (NULL != GDS_my_hello) + { + GNUNET_BLOCK_mingle_hash (&my_identity.hashPubKey, bf_mutator, &mhash); + if ((NULL == bf) || + (GNUNET_YES != GNUNET_CONTAINER_bloomfilter_test (bf, &mhash))) + { + GDS_NEIGHBOURS_handle_reply (sender, GNUNET_BLOCK_TYPE_DHT_HELLO, + GNUNET_TIME_relative_to_absolute + (GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION), + key, 0, NULL, 0, NULL, GDS_my_hello, + GNUNET_HELLO_size ((const struct + GNUNET_HELLO_Message *) + GDS_my_hello)); + } + else + { + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# FIND PEER requests ignored due to Bloomfilter"), + 1, GNUNET_NO); + } + } + else + { + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# FIND PEER requests ignored due to lack of HELLO"), + 1, GNUNET_NO); + } + + /* then, also consider sending a random HELLO from the closest bucket */ + if (0 == memcmp (&my_identity.hashPubKey, key, sizeof (GNUNET_HashCode))) + bucket_idx = closest_bucket; + else + bucket_idx = GNUNET_MIN (closest_bucket, find_bucket (key)); + if (bucket_idx == GNUNET_SYSERR) + return; + bucket = &k_buckets[bucket_idx]; + if (bucket->peers_size == 0) + return; + choice = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, bucket->peers_size); + peer = bucket->head; + while (choice > 0) + { + GNUNET_assert (peer != NULL); + peer = peer->next; + choice--; + } + choice = bucket->peers_size; + do + { + peer = peer->next; + if (choice-- == 0) + return; /* no non-masked peer available */ + if (peer == NULL) + peer = bucket->head; + GNUNET_BLOCK_mingle_hash (&peer->id.hashPubKey, bf_mutator, &mhash); + hello = GDS_HELLO_get (&peer->id); + } + while ((hello == NULL) || + (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (bf, &mhash))); + GDS_NEIGHBOURS_handle_reply (sender, GNUNET_BLOCK_TYPE_DHT_HELLO, + GNUNET_TIME_relative_to_absolute + (GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION), key, + 0, NULL, 0, NULL, hello, + GNUNET_HELLO_size (hello)); +} + + +/** + * Core handler for p2p get requests. + * + * @param cls closure + * @param peer sender of the request + * @param message message + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_dht_p2p_get (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct PeerGetMessage *get; + uint32_t xquery_size; + size_t reply_bf_size; + uint16_t msize; + enum GNUNET_BLOCK_Type type; + enum GNUNET_DHT_RouteOption options; + enum GNUNET_BLOCK_EvaluationResult eval; + struct GNUNET_CONTAINER_BloomFilter *reply_bf; + struct GNUNET_CONTAINER_BloomFilter *peer_bf; + const char *xquery; + + GNUNET_break (0 != + memcmp (peer, &my_identity, + sizeof (struct GNUNET_PeerIdentity))); + /* parse and validate message */ + msize = ntohs (message->size); + if (msize < sizeof (struct PeerGetMessage)) + { + GNUNET_break_op (0); + return GNUNET_YES; + } + get = (struct PeerGetMessage *) message; + xquery_size = ntohl (get->xquery_size); + if (msize < sizeof (struct PeerGetMessage) + xquery_size) + { + GNUNET_break_op (0); + return GNUNET_YES; + } + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# P2P GET requests received"), 1, + GNUNET_NO); + reply_bf_size = msize - (sizeof (struct PeerGetMessage) + xquery_size); + type = ntohl (get->type); + options = ntohl (get->options); + xquery = (const char *) &get[1]; + reply_bf = NULL; + if (reply_bf_size > 0) + reply_bf = + GNUNET_CONTAINER_bloomfilter_init (&xquery[xquery_size], reply_bf_size, + GNUNET_CONSTANTS_BLOOMFILTER_K); + eval = + GNUNET_BLOCK_evaluate (GDS_block_context, type, &get->key, &reply_bf, + get->bf_mutator, xquery, xquery_size, NULL, 0); + if (eval != GNUNET_BLOCK_EVALUATION_REQUEST_VALID) + { + /* request invalid or block type not supported */ + GNUNET_break_op (eval == GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED); + if (NULL != reply_bf) + GNUNET_CONTAINER_bloomfilter_free (reply_bf); + return GNUNET_YES; + } + peer_bf = + GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter, DHT_BLOOM_SIZE, + GNUNET_CONSTANTS_BLOOMFILTER_K); + GNUNET_break_op (GNUNET_YES == + GNUNET_CONTAINER_bloomfilter_test (peer_bf, + &peer->hashPubKey)); + /* remember request for routing replies */ + GDS_ROUTING_add (peer, type, options, &get->key, xquery, xquery_size, + reply_bf, get->bf_mutator); +#if DEBUG_DHT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GET for %s at %s after %u hops\n", + GNUNET_h2s (&get->key), GNUNET_i2s (&my_identity), + (unsigned int) ntohl (get->hop_count)); +#endif + /* local lookup (this may update the reply_bf) */ + if ((0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) || + (am_closest_peer (&get->key, peer_bf))) + { + if ((0 != (options & GNUNET_DHT_RO_FIND_PEER))) + { + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# P2P FIND PEER requests processed"), 1, + GNUNET_NO); + handle_find_peer (peer, &get->key, reply_bf, get->bf_mutator); + } + else + { + eval = + GDS_DATACACHE_handle_get (&get->key, type, xquery, xquery_size, + &reply_bf, get->bf_mutator); + } + } + else + { + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# P2P GET requests ONLY routed"), + 1, GNUNET_NO); + } + + GDS_CLIENTS_process_monitor (GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET, + GNUNET_TIME_UNIT_FOREVER_ABS, &get->key, 0, NULL, 0, NULL, + ntohl (get->desired_replication_level), type, NULL, 0); + + /* P2P forwarding */ + if (eval != GNUNET_BLOCK_EVALUATION_OK_LAST) + GDS_NEIGHBOURS_handle_get (type, options, + ntohl (get->desired_replication_level), + ntohl (get->hop_count), &get->key, xquery, + xquery_size, reply_bf, get->bf_mutator, peer_bf); + /* clean up */ + if (NULL != reply_bf) + GNUNET_CONTAINER_bloomfilter_free (reply_bf); + GNUNET_CONTAINER_bloomfilter_free (peer_bf); + return GNUNET_YES; +} + + +/** + * Core handler for p2p result messages. + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * @return GNUNET_YES (do not cut p2p connection) + */ +static int +handle_dht_p2p_result (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + const struct PeerResultMessage *prm; + const struct GNUNET_PeerIdentity *put_path; + const struct GNUNET_PeerIdentity *get_path; + const void *data; + uint32_t get_path_length; + uint32_t put_path_length; + uint16_t msize; + size_t data_size; + enum GNUNET_BLOCK_Type type; + + /* parse and validate message */ + msize = ntohs (message->size); + if (msize < sizeof (struct PeerResultMessage)) + { + GNUNET_break_op (0); + return GNUNET_YES; + } + prm = (struct PeerResultMessage *) message; + put_path_length = ntohl (prm->put_path_length); + get_path_length = ntohl (prm->get_path_length); + if ((msize < + sizeof (struct PeerResultMessage) + (get_path_length + + put_path_length) * + sizeof (struct GNUNET_PeerIdentity)) || + (get_path_length > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || + (put_path_length > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break_op (0); + return GNUNET_YES; + } + GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# P2P RESULTS received"), + 1, GNUNET_NO); + put_path = (const struct GNUNET_PeerIdentity *) &prm[1]; + get_path = &put_path[put_path_length]; + type = ntohl (prm->type); + data = (const void *) &get_path[get_path_length]; + data_size = + msize - (sizeof (struct PeerResultMessage) + + (get_path_length + + put_path_length) * sizeof (struct GNUNET_PeerIdentity)); + + /* if we got a HELLO, consider it for our own routing table */ + if (type == GNUNET_BLOCK_TYPE_DHT_HELLO) + { + const struct GNUNET_MessageHeader *h; + struct GNUNET_PeerIdentity pid; + int bucket; + + /* Should be a HELLO, validate and consider using it! */ + if (data_size < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return GNUNET_YES; + } + h = data; + if (data_size != ntohs (h->size)) + { + GNUNET_break_op (0); + return GNUNET_YES; + } + if (GNUNET_OK != + GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) h, &pid)) + { + GNUNET_break_op (0); + return GNUNET_YES; + } + if (0 != memcmp (&my_identity, &pid, sizeof (struct GNUNET_PeerIdentity))) + { + bucket = find_bucket (&pid.hashPubKey); + if ((bucket >= 0) && (k_buckets[bucket].peers_size < bucket_size)) + { + if (NULL != GDS_transport_handle) + { + GNUNET_TRANSPORT_offer_hello (GDS_transport_handle, h, NULL, NULL); + GNUNET_TRANSPORT_try_connect (GDS_transport_handle, &pid); + } + } + } + } + + /* append 'peer' to 'get_path' */ + { + struct GNUNET_PeerIdentity xget_path[get_path_length + 1]; + + memcpy (xget_path, get_path, + get_path_length * sizeof (struct GNUNET_PeerIdentity)); + xget_path[get_path_length] = *peer; + get_path_length++; + + /* forward to local clients */ + GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (prm->expiration_time), + &prm->key, get_path_length, xget_path, + put_path_length, put_path, type, data_size, data); + + /* forward to other peers */ + GDS_ROUTING_process (type, GNUNET_TIME_absolute_ntoh (prm->expiration_time), + &prm->key, put_path_length, put_path, get_path_length, + xget_path, data, data_size); + } + + GDS_CLIENTS_process_monitor (GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP, + GNUNET_TIME_absolute_ntoh (prm->expiration_time), &prm->key, + put_path_length, put_path, get_path_length, get_path, + 0, type, data, data_size); + + return GNUNET_YES; +} + + +/** + * Initialize neighbours subsystem. + * + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GDS_NEIGHBOURS_init () +{ + static struct GNUNET_CORE_MessageHandler core_handlers[] = { + {&handle_dht_p2p_get, GNUNET_MESSAGE_TYPE_DHT_P2P_GET, 0}, + {&handle_dht_p2p_put, GNUNET_MESSAGE_TYPE_DHT_P2P_PUT, 0}, + {&handle_dht_p2p_result, GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT, 0}, + {NULL, 0, 0} + }; + unsigned long long temp_config_num; + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (GDS_cfg, "DHT", "bucket_size", + &temp_config_num)) + bucket_size = (unsigned int) temp_config_num; + atsAPI = GNUNET_ATS_performance_init (GDS_cfg, NULL, NULL); + coreAPI = + GNUNET_CORE_connect (GDS_cfg, 1, NULL, &core_init, &handle_core_connect, + &handle_core_disconnect, NULL, GNUNET_NO, NULL, + GNUNET_NO, core_handlers); + if (coreAPI == NULL) + return GNUNET_SYSERR; + all_known_peers = GNUNET_CONTAINER_multihashmap_create (256); + return GNUNET_OK; +} + + +/** + * Shutdown neighbours subsystem. + */ +void +GDS_NEIGHBOURS_done () +{ + if (coreAPI == NULL) + return; + GNUNET_CORE_disconnect (coreAPI); + coreAPI = NULL; + GNUNET_ATS_performance_done (atsAPI); + atsAPI = NULL; + GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (all_known_peers)); + GNUNET_CONTAINER_multihashmap_destroy (all_known_peers); + all_known_peers = NULL; + if (GNUNET_SCHEDULER_NO_TASK != find_peer_task) + { + GNUNET_SCHEDULER_cancel (find_peer_task); + find_peer_task = GNUNET_SCHEDULER_NO_TASK; + } +} + + +/* end of gnunet-service-dht_neighbours.c */ diff --git a/src/dht/gnunet-service-dht_neighbours.h b/src/dht/gnunet-service-dht_neighbours.h new file mode 100644 index 0000000..b6e0f0e --- /dev/null +++ b/src/dht/gnunet-service-dht_neighbours.h @@ -0,0 +1,138 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_neighbours.h + * @brief GNUnet DHT routing code + * @author Christian Grothoff + * @author Nathan Evans + */ +#ifndef GNUNET_SERVICE_DHT_NEIGHBOURS_H +#define GNUNET_SERVICE_DHT_NEIGHBOURS_H + +#include "gnunet_util_lib.h" +#include "gnunet_block_lib.h" +#include "gnunet_dht_service.h" + +/** + * Perform a PUT operation. Forwards the given request to other + * peers. Does not store the data locally. Does not give the + * data to local clients. May do nothing if this is the only + * peer in the network (or if we are the closest peer in the + * network). + * + * @param type type of the block + * @param options routing options + * @param desired_replication_level desired replication level + * @param expiration_time when does the content expire + * @param hop_count how many hops has this message traversed so far + * @param bf Bloom filter of peers this PUT has already traversed + * @param key key for the content + * @param put_path_length number of entries in put_path + * @param put_path peers this request has traversed so far (if tracked) + * @param data payload to store + * @param data_size number of bytes in data + */ +void +GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type type, + enum GNUNET_DHT_RouteOption options, + uint32_t desired_replication_level, + struct GNUNET_TIME_Absolute expiration_time, + uint32_t hop_count, + struct GNUNET_CONTAINER_BloomFilter *bf, + const GNUNET_HashCode * key, + unsigned int put_path_length, + struct GNUNET_PeerIdentity *put_path, + const void *data, size_t data_size); + + +/** + * Perform a GET operation. Forwards the given request to other + * peers. Does not lookup the key locally. May do nothing if this is + * the only peer in the network (or if we are the closest peer in the + * network). + * + * @param type type of the block + * @param options routing options + * @param desired_replication_level desired replication count + * @param hop_count how many hops did this request traverse so far? + * @param key key for the content + * @param xquery extended query + * @param xquery_size number of bytes in xquery + * @param reply_bf bloomfilter to filter duplicates + * @param reply_bf_mutator mutator for reply_bf + * @param peer_bf filter for peers not to select (again, updated) + */ +void +GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type, + enum GNUNET_DHT_RouteOption options, + uint32_t desired_replication_level, + uint32_t hop_count, const GNUNET_HashCode * key, + const void *xquery, size_t xquery_size, + const struct GNUNET_CONTAINER_BloomFilter *reply_bf, + uint32_t reply_bf_mutator, + struct GNUNET_CONTAINER_BloomFilter *peer_bf); + + +/** + * Handle a reply (route to origin). Only forwards the reply back to + * other peers waiting for it. Does not do local caching or + * forwarding to local clients. + * + * @param target neighbour that should receive the block (if still connected) + * @param type type of the block + * @param expiration_time when does the content expire + * @param key key for the content + * @param put_path_length number of entries in put_path + * @param put_path peers the original PUT traversed (if tracked) + * @param get_path_length number of entries in put_path + * @param get_path peers this reply has traversed so far (if tracked) + * @param data payload of the reply + * @param data_size number of bytes in data + */ +void +GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target, + enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute expiration_time, + const GNUNET_HashCode * key, + unsigned int put_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *get_path, + const void *data, size_t data_size); + + +/** + * Initialize neighbours subsystem. + * + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GDS_NEIGHBOURS_init (void); + + +/** + * Shutdown neighbours subsystem. + */ +void +GDS_NEIGHBOURS_done (void); + + +#endif diff --git a/src/dht/gnunet-service-dht_nse.c b/src/dht/gnunet-service-dht_nse.c new file mode 100644 index 0000000..7779989 --- /dev/null +++ b/src/dht/gnunet-service-dht_nse.c @@ -0,0 +1,101 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_nse.c + * @brief GNUnet DHT integration with NSE + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_nse_service.h" +#include "gnunet-service-dht.h" +#include "gnunet-service-dht_nse.h" + +/** + * log of the current network size estimate, used as the point where + * we switch between random and deterministic routing. Default + * value of 4.0 is used if NSE module is not available (i.e. not + * configured). + */ +static double log_of_network_size_estimate = 4.0; + +/** + * Network size estimation handle. + */ +static struct GNUNET_NSE_Handle *nse; + + +/** + * Callback that is called when network size estimate is updated. + * + * @param cls closure + * @param timestamp time when the estimate was received from the server (or created by the server) + * @param logestimate the log(Base 2) value of the current network size estimate + * @param std_dev standard deviation for the estimate + * + */ +static void +update_network_size_estimate (void *cls, struct GNUNET_TIME_Absolute timestamp, + double logestimate, double std_dev) +{ + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# Network size estimates received"), + 1, GNUNET_NO); + /* do not allow estimates < 0.5 */ + log_of_network_size_estimate = GNUNET_MAX (0.5, logestimate); +} + + +/** + * Return the log of the current network size estimate. + * + * @return log of NSE + */ +double +GDS_NSE_get () +{ + return log_of_network_size_estimate; +} + + +/** + * Initialize NSE subsystem. + */ +void +GDS_NSE_init () +{ + nse = GNUNET_NSE_connect (GDS_cfg, &update_network_size_estimate, NULL); +} + + +/** + * Shutdown NSE subsystem. + */ +void +GDS_NSE_done () +{ + if (NULL != nse) + { + GNUNET_NSE_disconnect (nse); + nse = NULL; + } +} + +/* end of gnunet-service-dht_nse.c */ diff --git a/src/dht/gnunet-service-dht_nse.h b/src/dht/gnunet-service-dht_nse.h new file mode 100644 index 0000000..bddd4bd --- /dev/null +++ b/src/dht/gnunet-service-dht_nse.h @@ -0,0 +1,52 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_nse.h + * @brief GNUnet DHT integration with NSE + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_DHT_NSE_H +#define GNUNET_SERVICE_DHT_NSE_H + + +/** + * Return the log of the current network size estimate. + * + * @return log of NSE + */ +double +GDS_NSE_get (void); + + +/** + * Initialize NSE subsystem. + */ +void +GDS_NSE_init (void); + + +/** + * Shutdown NSE subsystem. + */ +void +GDS_NSE_done (void); + +#endif diff --git a/src/dht/gnunet-service-dht_routing.c b/src/dht/gnunet-service-dht_routing.c new file mode 100644 index 0000000..a880bf7 --- /dev/null +++ b/src/dht/gnunet-service-dht_routing.c @@ -0,0 +1,383 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_routing.c + * @brief GNUnet DHT tracking of requests for routing replies + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-dht_neighbours.h" +#include "gnunet-service-dht_routing.h" +#include "gnunet-service-dht.h" + + +/** + * Number of requests we track at most (for routing replies). + */ +#define DHT_MAX_RECENT (1024 * 16) + + +/** + * Information we keep about all recent GET requests + * so that we can route replies. + */ +struct RecentRequest +{ + + /** + * The peer this request was received from. + */ + struct GNUNET_PeerIdentity peer; + + /** + * Key of this request. + */ + GNUNET_HashCode key; + + /** + * Position of this node in the min heap. + */ + struct GNUNET_CONTAINER_HeapNode *heap_node; + + /** + * Bloomfilter for replies to drop. + */ + struct GNUNET_CONTAINER_BloomFilter *reply_bf; + + /** + * Type of the requested block. + */ + enum GNUNET_BLOCK_Type type; + + /** + * extended query (see gnunet_block_lib.h). Allocated at the + * end of this struct. + */ + const void *xquery; + + /** + * Number of bytes in xquery. + */ + size_t xquery_size; + + /** + * Mutator value for the reply_bf, see gnunet_block_lib.h + */ + uint32_t reply_bf_mutator; + + /** + * Request options. + */ + enum GNUNET_DHT_RouteOption options; + +}; + + +/** + * Recent requests by time inserted. + */ +static struct GNUNET_CONTAINER_Heap *recent_heap; + +/** + * Recently seen requests by key. + */ +static struct GNUNET_CONTAINER_MultiHashMap *recent_map; + + +/** + * Closure for the 'process' function. + */ +struct ProcessContext +{ + /** + * Path of the original PUT + */ + const struct GNUNET_PeerIdentity *put_path; + + /** + * Path of the reply. + */ + const struct GNUNET_PeerIdentity *get_path; + + /** + * Payload of the reply. + */ + const void *data; + + /** + * Expiration time of the result. + */ + struct GNUNET_TIME_Absolute expiration_time; + + /** + * Number of entries in 'put_path'. + */ + unsigned int put_path_length; + + /** + * Number of entries in 'get_path'. + */ + unsigned int get_path_length; + + /** + * Number of bytes in 'data'. + */ + size_t data_size; + + /** + * Type of the reply. + */ + enum GNUNET_BLOCK_Type type; + +}; + + +/** + * Forward the result to the given peer if it matches the request. + * + * @param cls the 'struct ProcessContext' with the result + * @param key the query + * @param value the 'struct RecentRequest' with the request + * @return GNUNET_OK (continue to iterate), + * GNUNET_SYSERR if the result is malformed or type unsupported + */ +static int +process (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ProcessContext *pc = cls; + struct RecentRequest *rr = value; + enum GNUNET_BLOCK_EvaluationResult eval; + unsigned int gpl; + unsigned int ppl; + GNUNET_HashCode hc; + const GNUNET_HashCode *eval_key; + + if ((rr->type != GNUNET_BLOCK_TYPE_ANY) && (rr->type != pc->type)) + return GNUNET_OK; /* type missmatch */ + + if (0 != (rr->options & GNUNET_DHT_RO_RECORD_ROUTE)) + { + gpl = pc->get_path_length; + ppl = pc->put_path_length; + } + else + { + gpl = 0; + ppl = 0; + } + if ((0 != (rr->options & GNUNET_DHT_RO_FIND_PEER)) && + (pc->type == GNUNET_BLOCK_TYPE_DHT_HELLO)) + { + /* key may not match HELLO, which is OK since + * the search is approximate. Still, the evaluation + * would fail since the match is not exact. So + * we fake it by changing the key to the actual PID ... */ + GNUNET_BLOCK_get_key (GDS_block_context, GNUNET_BLOCK_TYPE_DHT_HELLO, + pc->data, pc->data_size, &hc); + eval_key = &hc; + } + else + { + eval_key = key; + } + eval = + GNUNET_BLOCK_evaluate (GDS_block_context, pc->type, eval_key, + &rr->reply_bf, rr->reply_bf_mutator, rr->xquery, + rr->xquery_size, pc->data, pc->data_size); + switch (eval) + { + case GNUNET_BLOCK_EVALUATION_OK_MORE: + case GNUNET_BLOCK_EVALUATION_OK_LAST: + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Good REPLIES matched against routing table"), + 1, GNUNET_NO); + GDS_NEIGHBOURS_handle_reply (&rr->peer, pc->type, pc->expiration_time, key, + ppl, pc->put_path, gpl, pc->get_path, pc->data, + pc->data_size); + break; + case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Duplicate REPLIES matched against routing table"), + 1, GNUNET_NO); + return GNUNET_OK; + case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Invalid REPLIES matched against routing table"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: + case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: + GNUNET_break (0); + return GNUNET_OK; + case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Unsupported REPLIES matched against routing table"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + default: + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Handle a reply (route to origin). Only forwards the reply back to + * other peers waiting for it. Does not do local caching or + * forwarding to local clients. Essentially calls + * GDS_NEIGHBOURS_handle_reply for all peers that sent us a matching + * request recently. + * + * @param type type of the block + * @param expiration_time when does the content expire + * @param key key for the content + * @param put_path_length number of entries in put_path + * @param put_path peers the original PUT traversed (if tracked) + * @param get_path_length number of entries in put_path + * @param get_path peers this reply has traversed so far (if tracked) + * @param data payload of the reply + * @param data_size number of bytes in data + */ +void +GDS_ROUTING_process (enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute expiration_time, + const GNUNET_HashCode * key, unsigned int put_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *get_path, + const void *data, size_t data_size) +{ + struct ProcessContext pc; + + pc.type = type; + pc.expiration_time = expiration_time; + pc.put_path_length = put_path_length; + pc.put_path = put_path; + pc.get_path_length = get_path_length; + pc.get_path = get_path; + pc.data = data; + pc.data_size = data_size; + GNUNET_CONTAINER_multihashmap_get_multiple (recent_map, key, &process, &pc); +} + + +/** + * Add a new entry to our routing table. + * + * @param sender peer that originated the request + * @param type type of the block + * @param options options for processing + * @param key key for the content + * @param xquery extended query + * @param xquery_size number of bytes in xquery + * @param reply_bf bloomfilter to filter duplicates + * @param reply_bf_mutator mutator for reply_bf +*/ +void +GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender, + enum GNUNET_BLOCK_Type type, + enum GNUNET_DHT_RouteOption options, + const GNUNET_HashCode * key, const void *xquery, + size_t xquery_size, + const struct GNUNET_CONTAINER_BloomFilter *reply_bf, + uint32_t reply_bf_mutator) +{ + struct RecentRequest *recent_req; + + while (GNUNET_CONTAINER_heap_get_size (recent_heap) >= DHT_MAX_RECENT) + { + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Entries removed from routing table"), 1, + GNUNET_NO); + recent_req = GNUNET_CONTAINER_heap_peek (recent_heap); + GNUNET_assert (recent_req != NULL); + GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node); + GNUNET_CONTAINER_bloomfilter_free (recent_req->reply_bf); + GNUNET_free (recent_req); + } + + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop ("# Entries added to routing table"), + 1, GNUNET_NO); + recent_req = GNUNET_malloc (sizeof (struct RecentRequest) + xquery_size); + recent_req->peer = *sender; + recent_req->key = *key; + recent_req->heap_node = + GNUNET_CONTAINER_heap_insert (recent_heap, recent_req, + GNUNET_TIME_absolute_get ().abs_value); + recent_req->reply_bf = GNUNET_CONTAINER_bloomfilter_copy (reply_bf); + recent_req->type = type; + recent_req->options = options; + recent_req->xquery = &recent_req[1]; + recent_req->xquery_size = xquery_size; + recent_req->reply_bf_mutator = reply_bf_mutator; + GNUNET_CONTAINER_multihashmap_put (recent_map, key, recent_req, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + + +} + + +/** + * Initialize routing subsystem. + */ +void +GDS_ROUTING_init () +{ + recent_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + recent_map = GNUNET_CONTAINER_multihashmap_create (DHT_MAX_RECENT * 4 / 3); +} + + +/** + * Shutdown routing subsystem. + */ +void +GDS_ROUTING_done () +{ + struct RecentRequest *recent_req; + + while (GNUNET_CONTAINER_heap_get_size (recent_heap) > 0) + { + GNUNET_STATISTICS_update (GDS_stats, + gettext_noop + ("# Entries removed from routing table"), 1, + GNUNET_NO); + recent_req = GNUNET_CONTAINER_heap_peek (recent_heap); + GNUNET_assert (recent_req != NULL); + GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node); + GNUNET_CONTAINER_bloomfilter_free (recent_req->reply_bf); + GNUNET_free (recent_req); + } + GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (recent_heap)); + GNUNET_CONTAINER_heap_destroy (recent_heap); + recent_heap = NULL; + GNUNET_CONTAINER_multihashmap_destroy (recent_map); + recent_map = NULL; +} + +/* end of gnunet-service-dht_routing.c */ diff --git a/src/dht/gnunet-service-dht_routing.h b/src/dht/gnunet-service-dht_routing.h new file mode 100644 index 0000000..9b12c71 --- /dev/null +++ b/src/dht/gnunet-service-dht_routing.h @@ -0,0 +1,96 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/gnunet-service-dht_routing.h + * @brief GNUnet DHT tracking of requests for routing replies + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_DHT_ROUTING_H +#define GNUNET_SERVICE_DHT_ROUTING_H + +#include "gnunet_util_lib.h" +#include "gnunet_block_lib.h" +#include "gnunet_dht_service.h" + + +/** + * Handle a reply (route to origin). Only forwards the reply back to + * other peers waiting for it. Does not do local caching or + * forwarding to local clients. Essentially calls + * GDS_NEIGHBOURS_handle_reply for all peers that sent us a matching + * request recently. + * + * @param type type of the block + * @param expiration_time when does the content expire + * @param key key for the content + * @param put_path_length number of entries in put_path + * @param put_path peers the original PUT traversed (if tracked) + * @param get_path_length number of entries in put_path + * @param get_path peers this reply has traversed so far (if tracked) + * @param data payload of the reply + * @param data_size number of bytes in data + */ +void +GDS_ROUTING_process (enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute expiration_time, + const GNUNET_HashCode * key, unsigned int put_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *get_path, + const void *data, size_t data_size); + + +/** + * Add a new entry to our routing table. + * + * @param sender peer that originated the request + * @param type type of the block + * @param options options for processing + * @param key key for the content + * @param xquery extended query + * @param xquery_size number of bytes in xquery + * @param reply_bf bloomfilter to filter duplicates + * @param reply_bf_mutator mutator for reply_bf +*/ +void +GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender, + enum GNUNET_BLOCK_Type type, + enum GNUNET_DHT_RouteOption options, + const GNUNET_HashCode * key, const void *xquery, + size_t xquery_size, + const struct GNUNET_CONTAINER_BloomFilter *reply_bf, + uint32_t reply_bf_mutator); + + +/** + * Initialize routing subsystem. + */ +void +GDS_ROUTING_init (void); + + +/** + * Shutdown routing subsystem. + */ +void +GDS_ROUTING_done (void); + +#endif diff --git a/src/dht/multipeer_topo.dat b/src/dht/multipeer_topo.dat new file mode 100644 index 0000000..1233e6b --- /dev/null +++ b/src/dht/multipeer_topo.dat @@ -0,0 +1,31 @@ +10 +1:2 +2:3 +3:4 +4:5 +5:6 +6:7 +7:8 +8:9 +9:10 +10:1 +4:2 +5:3 +6:4 +7:5 +8:6 +9:7 +10:8 +1:9 +2:10 +3:1 +6:2 +7:3 +8:4 +9:5 +10:6 +1:7 +2:8 +3:9 +4:10 +5:1 diff --git a/src/dht/plugin_block_dht.c b/src/dht/plugin_block_dht.c new file mode 100644 index 0000000..19467b9 --- /dev/null +++ b/src/dht/plugin_block_dht.c @@ -0,0 +1,181 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dht/plugin_block_dht.c + * @brief block plugin for DHT internals (right now, find-peer requests only); + * other plugins should be used to store "useful" data in the + * DHT (see fs block plugin) + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_hello_lib.h" +#include "gnunet_block_plugin.h" + +#define DEBUG_DHT GNUNET_EXTRA_LOGGING + + +/** + * Function called to validate a reply or a request. For + * request evaluation, simply pass "NULL" for the reply_block. + * + * @param cls closure + * @param type block type + * @param query original query (hash) + * @param bf pointer to bloom filter associated with query; possibly updated (!) + * @param bf_mutator mutation value for bf + * @param xquery extended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in reply block + * @return characterization of result + */ +static enum GNUNET_BLOCK_EvaluationResult +block_plugin_dht_evaluate (void *cls, enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode * query, + struct GNUNET_CONTAINER_BloomFilter **bf, + int32_t bf_mutator, const void *xquery, + size_t xquery_size, const void *reply_block, + size_t reply_block_size) +{ + GNUNET_HashCode mhash; + const struct GNUNET_HELLO_Message *hello; + struct GNUNET_PeerIdentity pid; + const struct GNUNET_MessageHeader *msg; + + if (type != GNUNET_BLOCK_TYPE_DHT_HELLO) + return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; + if (xquery_size != 0) + return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; + if (reply_block_size == 0) + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + if (reply_block_size < sizeof (struct GNUNET_MessageHeader)) + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + msg = reply_block; + if (reply_block_size != ntohs (msg->size)) + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + hello = reply_block; + if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + if (NULL != bf) + { + GNUNET_BLOCK_mingle_hash (&pid.hashPubKey, bf_mutator, &mhash); + if (NULL != *bf) + { + if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) + return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; + } + else + { + *bf = + GNUNET_CONTAINER_bloomfilter_init (NULL, 8, + GNUNET_CONSTANTS_BLOOMFILTER_K); + } + GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash); + } + return GNUNET_BLOCK_EVALUATION_OK_MORE; +} + + +/** + * Function called to obtain the key for a block. + * + * @param cls closure + * @param type block type + * @param block block to get the key for + * @param block_size number of bytes in block + * @param key set to the key (query) for the given block + * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported + * (or if extracting a key from a block of this type does not work) + */ +static int +block_plugin_dht_get_key (void *cls, enum GNUNET_BLOCK_Type type, + const void *block, size_t block_size, + GNUNET_HashCode * key) +{ + const struct GNUNET_MessageHeader *msg; + const struct GNUNET_HELLO_Message *hello; + struct GNUNET_PeerIdentity *pid; + + if (type != GNUNET_BLOCK_TYPE_DHT_HELLO) + return GNUNET_SYSERR; + if (block_size < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht", + _("Block not of type %u\n"), GNUNET_BLOCK_TYPE_DHT_HELLO); + return GNUNET_NO; + } + msg = block; + if (block_size != ntohs (msg->size)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht", + _("Size mismatch for block\n"), + GNUNET_BLOCK_TYPE_DHT_HELLO); + return GNUNET_NO; + } + hello = block; + pid = (struct GNUNET_PeerIdentity *) key; + if (GNUNET_OK != GNUNET_HELLO_get_id (hello, pid)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht", + _("Block of type %u is malformed\n"), + GNUNET_BLOCK_TYPE_DHT_HELLO); + return GNUNET_NO; + } + return GNUNET_OK; +} + + +/** + * Entry point for the plugin. + */ +void * +libgnunet_plugin_block_dht_init (void *cls) +{ + static enum GNUNET_BLOCK_Type types[] = + { + GNUNET_BLOCK_TYPE_DHT_HELLO, + GNUNET_BLOCK_TYPE_ANY /* end of list */ + }; + struct GNUNET_BLOCK_PluginFunctions *api; + + api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); + api->evaluate = &block_plugin_dht_evaluate; + api->get_key = &block_plugin_dht_get_key; + api->types = types; + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +libgnunet_plugin_block_dht_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + +/* end of plugin_block_dht.c */ diff --git a/src/dht/test_dht_2dtorus.conf b/src/dht/test_dht_2dtorus.conf new file mode 100644 index 0000000..d420b29 --- /dev/null +++ b/src/dht/test_dht_2dtorus.conf @@ -0,0 +1,87 @@ +[PATHS] +SERVICEHOME = /tmp/test_dht_topo/ +DEFAULTCONFIG = test_dht_2dtours.conf + +[arm] +PORT = 10010 +DEFAULTSERVICES = core dht +#DEBUG = YES + +[statistics] +AUTOSTART = YES +PORT = 10000 + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 10001 + +[dns] +AUTOSTART = NO +PORT = 10011 + +[transport] +PORT = 10002 +AUTOSTART = YES + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +AUTOSTART = YES +PORT = 10003 + +[peerinfo] +AUTOSTART = YES +PORT = 10004 + +[testing] +NUM_PEERS = 16 +WEAKRANDOM = YES +TOPOLOGY = NONE +CONNECT_TOPOLOGY = 2D_TORUS +BLACKLIST_TOPOLOGY = 2D_TORUS +#TOPOLOGY_FILE = small.dat +#CONNECT_TOPOLOGY = ERDOS_RENYI +#CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM +#CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 +#PERCENTAGE = 3 +#PROBABILITY = .1 +F2F = NO +CONNECT_TIMEOUT = 60 s +CONNECT_ATTEMPTS = 3 +DEBUG = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat +MAX_CONCURRENT_SSH = 10 +USE_PROGRESSBARS = YES +PEERGROUP_TIMEOUT = 2400 s +TOPOLOGY_OUTPUT_FILE = 2dtorus_topo_initial +MAX_OUTSTANDING_CONNECTIONS = 75 +#SINGLE_PEERINFO_PER_HOST = YES +#NUM_PEERINFO_PER_HOST = 10 +#SINGLE_STATISTICS_PER_HOST = YES +#NUM_STATISTICS_PER_HOST = 10 +DELETE_FILES = YES + +[test_dht_topo] +CONNECTION_LIMIT = 16 +#DATA_OUTPUT_FILE=data_output + + +[nse] +WORKDELAY = 500 ms +INTERVAL = 60 s +WORKBITS = 0 diff --git a/src/dht/test_dht_api.c b/src/dht/test_dht_api.c new file mode 100644 index 0000000..182856a --- /dev/null +++ b/src/dht/test_dht_api.c @@ -0,0 +1,339 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dht/test_dht_api.c + * @brief base test case for dht api + * + * This test case tests DHT api to DUMMY DHT service communication. + * + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_hello_lib.h" + +#define VERBOSE GNUNET_NO + +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we really give up on a particular testcase portion? + */ +#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) + +/** + * How long until we give up on any particular operation (and retry)? + */ +#define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) + +#define MTYPE 12345 + +struct RetryContext +{ + /** + * When to really abort the operation. + */ + struct GNUNET_TIME_Absolute real_timeout; + + /** + * What timeout to set for the current attempt (increases) + */ + struct GNUNET_TIME_Relative next_timeout; + + /** + * The context of the peer we are dealing with. + */ + struct PeerContext *peer_ctx; + + /** + * The task identifier of the retry task, so it can be cancelled. + */ + GNUNET_SCHEDULER_TaskIdentifier retry_task; + +}; + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_DHT_Handle *dht_handle; + struct GNUNET_PeerIdentity id; + struct GNUNET_DHT_GetHandle *get_handle; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +struct RetryContext retry_context; + + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_DHT_disconnect (p1.dht_handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "DHT disconnected, returning success!\n"); + ok = 0; +} + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + GNUNET_OS_process_wait (p->arm_proc); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +end_badly () +{ + /* do work here */ +#if VERBOSE + FPRINTF (stderr, "%s", "Ending on an unhappy note.\n"); +#endif + + if ((retry_context.peer_ctx != NULL) && + (retry_context.peer_ctx->get_handle != NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping get request!\n"); + GNUNET_DHT_get_stop (retry_context.peer_ctx->get_handle); + } + if (retry_context.retry_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (retry_context.retry_task); + GNUNET_DHT_disconnect (p1.dht_handle); + ok = 1; +} + + +/** + * Signature of the main function of a task. + * + * @param cls closure + * @param tc context information (why was this task triggered now) + */ +static void +test_get_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerContext *peer = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_get_stop!\n"); + if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0) + { + GNUNET_break (0); + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } + GNUNET_assert (peer->dht_handle != NULL); + GNUNET_DHT_get_stop (peer->get_handle); + peer->get_handle = NULL; + GNUNET_SCHEDULER_add_now (&end, &p1); +} + + +static void +test_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test_get_iterator called (we got a result), stopping get request!\n"); + + GNUNET_SCHEDULER_add_continuation (&test_get_stop, &p1, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + +/** + * Signature of the main function of a task. + * + * @param cls closure + * @param tc context information (why was this task triggered now) + */ +static void +test_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerContext *peer = cls; + GNUNET_HashCode hash; + + memset (&hash, 42, sizeof (GNUNET_HashCode)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_get!\n"); + + GNUNET_assert (peer->dht_handle != NULL); + retry_context.real_timeout = GNUNET_TIME_relative_to_absolute (TOTAL_TIMEOUT); + retry_context.next_timeout = BASE_TIMEOUT; + + peer->get_handle = + GNUNET_DHT_get_start (peer->dht_handle, TOTAL_TIMEOUT, + GNUNET_BLOCK_TYPE_TEST, &hash, 1, + GNUNET_DHT_RO_NONE, NULL, 0, &test_get_iterator, + NULL); + + if (peer->get_handle == NULL) + { + GNUNET_break (0); + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, &p1); + return; + } + + retry_context.peer_ctx = peer; +} + +/** + * Signature of the main function of a task. + * + * @param cls closure + * @param tc context information (why was this task triggered now) + */ +static void +test_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerContext *peer = cls; + GNUNET_HashCode hash; + char *data; + size_t data_size = 42; + + memset (&hash, 42, sizeof (GNUNET_HashCode)); + data = GNUNET_malloc (data_size); + memset (data, 43, data_size); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_put!\n"); + peer->dht_handle = GNUNET_DHT_connect (peer->cfg, 100); + + GNUNET_assert (peer->dht_handle != NULL); + + GNUNET_DHT_put (peer->dht_handle, &hash, 1, GNUNET_DHT_RO_NONE, + GNUNET_BLOCK_TYPE_TEST, data_size, data, + GNUNET_TIME_relative_to_absolute (TOTAL_TIMEOUT), + TOTAL_TIMEOUT, &test_get, &p1); + GNUNET_free (data); +} + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE_ARM + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_assert (ok == 1); + OKPP; + + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 1), &end_badly, + NULL); + + setup_peer (&p1, "test_dht_api_peer1.conf"); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), &test_put, &p1); +} + +static int +check () +{ + + char *const argv[] = { "test-dht-api", + "-c", + "test_dht_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-dht-api", "nohelp", options, &run, &ok); + stop_arm (&p1); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-dht-api", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-dht-peer-1"); + + return ret; +} + +/* end of test_dht_api.c */ diff --git a/src/dht/test_dht_api_data.conf b/src/dht/test_dht_api_data.conf new file mode 100644 index 0000000..0e34eb7 --- /dev/null +++ b/src/dht/test_dht_api_data.conf @@ -0,0 +1,85 @@ +[PATHS] +SERVICEHOME = /tmp/test-dht-api/ +DEFAULTCONFIG = test_dht_api_data.conf + +[fs] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO + +[datastore-sqlite] +FILENAME = $SERVICEHOME/datastore/sqlite.db + +[datastore] +AUTOSTART = NO + +[topology] +TARGET-CONNECTION-COUNT = 16 +AUTOCONNECT = YES +FRIENDS-ONLY = NO +MINIMUM-FRIENDS = 0 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +PORT = 2092 + +[dht] +DEBUG = NO +PORT = 12370 + +[block] +plugins = dht test + +[transport] +plugins = tcp +DEBUG = NO +NEIGHBOUR_LIMIT = 50 +PORT = 2091 + +[peerinfo] +PORT = 2090 + +[resolver] +PORT = 2089 + +[statistics] +PORT = 2088 + +[arm] +DEFAULTSERVICES = +PORT = 2087 + +[transport-tcp] +TIMEOUT = 300 s +PORT = 2094 + +[TESTING] +WEAKRANDOM = NO +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[dns] +AUTOSTART = NO + + + +[nse] +AUTOSTART = NO + + diff --git a/src/dht/test_dht_api_peer1.conf b/src/dht/test_dht_api_peer1.conf new file mode 100644 index 0000000..cacc4da --- /dev/null +++ b/src/dht/test_dht_api_peer1.conf @@ -0,0 +1,76 @@ +[fs] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 2100 +BINARY = gnunet-service-dht + +[block] +plugins = dht test + +[dhtcache] +QUOTA = 1 MB +DATABASE = sqlite + +[transport] +PLUGINS = tcp +DEBUG = NO +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +NEIGHBOUR_LIMIT = 50 +PORT = 12365 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +PORT = 12092 + +[arm] +DEFAULTSERVICES = core +PORT = 12366 +DEBUG = NO + +[transport-tcp] +TIMEOUT = 300 s +PORT = 12368 +BINDTO = 127.0.0.1 + +[TESTING] +WEAKRANDOM = YES + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[PATHS] +DEFAULTCONFIG = test_dht_api_peer1.conf +SERVICEHOME = /tmp/test-gnunetd-dht-peer-1/ + + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[dns] +AUTOSTART = NO + + + +[nse] +AUTOSTART = NO + + diff --git a/src/dht/test_dht_line.conf b/src/dht/test_dht_line.conf new file mode 100644 index 0000000..8bcb12c --- /dev/null +++ b/src/dht/test_dht_line.conf @@ -0,0 +1,87 @@ +[PATHS] +SERVICEHOME = /tmp/test_dht_topo/ +DEFAULTCONFIG = test_dht_line.conf + +[arm] +PORT = 10010 +DEFAULTSERVICES = core dht +#DEBUG = YES + +[statistics] +AUTOSTART = YES +PORT = 10000 + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 10001 + +[dns] +AUTOSTART = NO +PORT = 10011 + +[transport] +PORT = 10002 +AUTOSTART = YES + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +AUTOSTART = YES +PORT = 10003 + +[peerinfo] +AUTOSTART = YES +PORT = 10004 + +[testing] +NUM_PEERS = 5 +WEAKRANDOM = YES +TOPOLOGY = NONE +CONNECT_TOPOLOGY = LINE +BLACKLIST_TOPOLOGY = LINE +#TOPOLOGY_FILE = small.dat +#CONNECT_TOPOLOGY = ERDOS_RENYI +#CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM +#CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 +#PERCENTAGE = 3 +#PROBABILITY = .1 +F2F = NO +CONNECT_TIMEOUT = 60 s +CONNECT_ATTEMPTS = 3 +DEBUG = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat +MAX_CONCURRENT_SSH = 10 +USE_PROGRESSBARS = YES +PEERGROUP_TIMEOUT = 2400 s +TOPOLOGY_OUTPUT_FILE = line_topo_initial +MAX_OUTSTANDING_CONNECTIONS = 75 +#SINGLE_PEERINFO_PER_HOST = YES +#NUM_PEERINFO_PER_HOST = 10 +#SINGLE_STATISTICS_PER_HOST = YES +#NUM_STATISTICS_PER_HOST = 10 +DELETE_FILES = YES + +[test_dht_topo] +CONNECTION_LIMIT = 5 +#DATA_OUTPUT_FILE=data_output + + +[nse] +WORKDELAY = 500 ms +INTERVAL = 60 s +WORKBITS = 0 diff --git a/src/dht/test_dht_monitor.c b/src/dht/test_dht_monitor.c new file mode 100644 index 0000000..63af7e9 --- /dev/null +++ b/src/dht/test_dht_monitor.c @@ -0,0 +1,624 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dht/test_dht_monitor.c + * + * @brief Test for the dht service: store, retrieve and monitor in a line. + * TODO: update this description + * Each peer stores it own ID in the DHT and then a different peer tries to + * retrieve that key from it. The GET starts after a first round of PUTS has + * been made. Periodically, each peer stores its ID into the DHT. If after + * a timeout no result has been returned, the test fails. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_dht_service.h" + +#define VERBOSE GNUNET_YES + +#define REMOVE_DIR GNUNET_YES + + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) + +#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +#define PUT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) + +static int ok; + +/** + * Be verbose + */ +static int verbose; + +/** + * Total number of peers in the test. + */ +static unsigned long long num_peers; + +/** + * Global configuration file + */ +static struct GNUNET_CONFIGURATION_Handle *testing_cfg; + +/** + * Total number of currently running peers. + */ +static unsigned long long peers_running; + +/** + * Total number of connections in the whole network. + */ +static unsigned int total_connections; + +/** + * The currently running peer group. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * File to report results to. + */ +static struct GNUNET_DISK_FileHandle *output_file; + +/** + * File to log connection info, statistics to. + */ +static struct GNUNET_DISK_FileHandle *data_file; + +/** + * Task called to disconnect peers. + */ +static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +/** + * Task To perform tests + */ +static GNUNET_SCHEDULER_TaskIdentifier test_task; + +/** + * Task to do DHT_puts + */ +static GNUNET_SCHEDULER_TaskIdentifier put_task; + +/** + * Task called to shutdown test. + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; + +static char *topology_file; + +struct GNUNET_TESTING_Daemon *d1; + +struct GNUNET_TESTING_Daemon *d2; + +struct GNUNET_DHT_Handle **hs; + +struct GNUNET_DHT_MonitorHandle **mhs; + +struct GNUNET_DHT_GetHandle *get_h_far; + +const char *id_origin = "FC74"; +const char *id_far = "2UVH"; + +struct GNUNET_TESTING_Daemon *d_far; +struct GNUNET_TESTING_Daemon *o; + +unsigned int monitor_counter; + +int in_test; + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Shutdown of peers failed!\n"); +#endif + ok++; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: All peers successfully shut down!\n"); +#endif + } + GNUNET_CONFIGURATION_destroy (testing_cfg); +} + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n"); +#endif + + if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (data_file != NULL) + GNUNET_DISK_file_close (data_file); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +static void +disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: disconnecting peers\n"); + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_cancel (put_task); + if (NULL != get_h_far) + GNUNET_DHT_get_stop (get_h_far); + for (i = 0; i < num_peers; i++) + { + GNUNET_DHT_disconnect (hs[i]); + } + GNUNET_SCHEDULER_cancel (shutdown_handle); + shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); +} + +static void +dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: ************* FOUND!!! ***********\n"); + if (sizeof (GNUNET_HashCode) == size) + { + const GNUNET_HashCode *h = data; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Contents: %s\n", + GNUNET_h2s_full (h)); + + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: PATH: (get %u, put %u)\n", + get_path_length, put_path_length); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: LOCAL\n"); + for (i = get_path_length - 1; i >= 0; i--) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", + GNUNET_i2s (&get_path[i])); + } + for (i = put_path_length - 1; i >= 0; i--) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", + GNUNET_i2s (&put_path[i])); + } + if (monitor_counter >= get_path_length + put_path_length) + { + ok = 0; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "expected at least %u hops, got %u\n", + get_path_length + put_path_length, monitor_counter); + } + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "expected at least %u hops, got %u\n", + get_path_length + put_path_length, monitor_counter); + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); +} + +/** + * Start test: start GET request from the first node in the line looking for + * the ID of the last node in the line. + * + * @param cls Closure (not used). + * @param tc Task context. + */ +static void +do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + return; + } + + in_test = GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: test_task\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: looking for %s\n", + GNUNET_h2s_full (&d_far->id.hashPubKey)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: from %s\n", + GNUNET_h2s_full (&o->id.hashPubKey)); + get_h_far = GNUNET_DHT_get_start (hs[0], GNUNET_TIME_UNIT_FOREVER_REL, /* timeout */ + GNUNET_BLOCK_TYPE_TEST, /* type */ + &d_far->id.hashPubKey, /*key to search */ + 4U, /* replication level */ + GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, /* xquery */ + 0, /* xquery bits */ + &dht_get_id_handler, NULL); + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &disconnect_peers, NULL); +} + + +/** + * Periodic function used to put the ID of the far peer in the DHT. + * + * @param cls Closure (not used). + * @param tc Task context. + */ +static void +put_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_Daemon *d; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + put_task = GNUNET_SCHEDULER_NO_TASK; + return; + } + + d = GNUNET_TESTING_daemon_get (pg, 4); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: putting into DHT: %s\n", + GNUNET_h2s_full (&d->id.hashPubKey)); + GNUNET_DHT_put (hs[4], &d->id.hashPubKey, 10U, + GNUNET_DHT_RO_RECORD_ROUTE | + GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, + GNUNET_BLOCK_TYPE_TEST, sizeof (struct GNUNET_PeerIdentity), + (const char *) &d->id, GNUNET_TIME_UNIT_FOREVER_ABS, + GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); + + put_task = GNUNET_SCHEDULER_add_delayed (PUT_FREQUENCY, &put_id, NULL); +} + +/** + * Callback called on each request going through the DHT. + * Prints the info about the intercepted packet and increments a counter. + * + * @param cls Closure (long) # of daemon that got the monitor event. + * @param mtype Type of the DHT message monitored. + * @param exp When will this value expire. + * @param key Key of the result/request. + * @param get_path Peers on reply path (or NULL if not recorded). + * @param get_path_length number of entries in get_path. + * @param put_path peers on the PUT path (or NULL if not recorded). + * @param put_path_length number of entries in get_path. + * @param desired_replication_level Desired replication level. + * @param type Type of the result/request. + * @param data Pointer to the result data. + * @param size Number of bytes in data. + */ +void +monitor_dht_cb (void *cls, + uint16_t mtype, + struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity * get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity * put_path, + unsigned int put_path_length, + uint32_t desired_replication_level, + enum GNUNET_DHT_RouteOption options, + enum GNUNET_BLOCK_Type type, + const void *data, + size_t size) +{ + const char *s_key; + const char *mtype_s; + unsigned int i; + + i = (unsigned int) (long) cls; + s_key = GNUNET_h2s(key); + switch (mtype) + { + case 149: + mtype_s = "GET "; + break; + case 150: + mtype_s = "RESULT"; + break; + case 151: + mtype_s = "PUT "; + break; + default: + GNUNET_break (0); + mtype_s = "UNKNOWN!!!"; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%u got a message of type %s for key %s\n", + i, mtype_s, s_key); + + if ((mtype == GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET || + mtype == GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT) && + strncmp (s_key, id_far, 4) == 0 && in_test == GNUNET_YES) + monitor_counter++; +} + + +/** + * peergroup_ready: start test when all peers are connected + * + * @param cls closure + * @param emsg error message + */ +static void +peergroup_ready (void *cls, const char *emsg) +{ + struct GNUNET_TESTING_Daemon *d; + char *buf; + int buf_len; + unsigned int i; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n", + emsg); + ok++; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "************************************************************\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Peer Group started successfully!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Have %u connections\n", + total_connections); +#endif + + if (data_file != NULL) + { + buf = NULL; + buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections); + if (buf_len > 0) + GNUNET_DISK_file_write (data_file, buf, buf_len); + GNUNET_free (buf); + } + peers_running = GNUNET_TESTING_daemons_running (pg); + + GNUNET_assert (peers_running == num_peers); + hs = GNUNET_malloc (num_peers * sizeof (struct GNUNET_DHT_Handle *)); + mhs = GNUNET_malloc (num_peers * sizeof (struct GNUNET_DHT_MonitorHandle *)); + d_far = o = NULL; + o = GNUNET_TESTING_daemon_get (pg, 0); + d_far = GNUNET_TESTING_daemon_get (pg, 4); + + for (i = 0; i < num_peers; i++) + { + d = GNUNET_TESTING_daemon_get (pg, i); + hs[i] = GNUNET_DHT_connect (d->cfg, 32); + mhs[i] = GNUNET_DHT_monitor_start(hs[i], GNUNET_BLOCK_TYPE_ANY, NULL, + &monitor_dht_cb, (void *)(long)i); + } + + if ((NULL == o) || (NULL == d_far)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "test: Error getting daemons from pg\n"); + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); + return; + } + monitor_counter = 0; + put_task = GNUNET_SCHEDULER_add_now (&put_id, NULL); + test_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 2), &do_test, + NULL); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &disconnect_peers, NULL); + +} + + +/** + * Function that will be called whenever two daemons are connected by + * the testing library. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param first_cfg config for the first daemon + * @param second_cfg config for the second daemon + * @param first_daemon handle for the first daemon + * @param second_daemon handle for the second daemon + * @param emsg error message (NULL on success) + */ +static void +connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) +{ + + if (emsg == NULL) + { + total_connections++; + GNUNET_PEER_intern (first); + GNUNET_PEER_intern (second); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Problem with new connection (%s)\n", emsg); + } + +} + + +/** + * run: load configuration options and schedule test to run (start peergroup) + * @param cls closure + * @param args argv + * @param cfgfile configuration file name (can be NULL) + * @param cfg configuration handle + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *temp_str; + struct GNUNET_TESTING_Host *hosts; + char *data_filename; + + ok = 1; + testing_cfg = GNUNET_CONFIGURATION_dup (cfg); + + GNUNET_log_setup ("test_dht_monitor", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", "YES"); +#endif + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", + "num_peers", &num_peers)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option TESTING:NUM_PEERS is required!\n"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing", + "topology_output_file", + &topology_file)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option test_dht_monitor:topology_output_file is required!\n"); + return; + } + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_dht_topo", + "data_output_file", + &data_filename)) + { + data_file = + GNUNET_DISK_file_open (data_filename, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (data_file == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", + data_filename); + GNUNET_free (data_filename); + } + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "test_dht_topo", + "output_file", &temp_str)) + { + output_file = + GNUNET_DISK_file_open (temp_str, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (output_file == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", + temp_str); + } + GNUNET_free_non_null (temp_str); + + hosts = GNUNET_TESTING_hosts_load (testing_cfg); + + pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, + &connect_cb, &peergroup_ready, NULL, + hosts); + GNUNET_assert (pg != NULL); + shutdown_handle = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, NULL); +} + + + +/** + * test_dht_monitor command line options + */ +static struct GNUNET_GETOPT_CommandLineOption options[] = { + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END +}; + + +/** + * Main: start test + */ +int +main (int xargc, char *xargv[]) +{ + char *const argv[] = { "test-dht-monitor", + "-c", + "test_dht_line.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + + in_test = GNUNET_NO; + GNUNET_PROGRAM_run (sizeof (argv) / sizeof (char *) - 1, argv, + "test_dht_monitor", + gettext_noop ("Test dht monitoring in a line."), + options, &run, NULL); +#if REMOVE_DIR + GNUNET_DISK_directory_remove ("/tmp/test_dht_monitor"); +#endif + if (0 != ok) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n"); + } + return ok; +} + +/* end of test_dht_monitor.c */ diff --git a/src/dht/test_dht_multipeer.c b/src/dht/test_dht_multipeer.c new file mode 100644 index 0000000..94e39d2 --- /dev/null +++ b/src/dht/test_dht_multipeer.c @@ -0,0 +1,872 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dht/test_dht_multipeer.c + * @brief testcase for testing DHT service with + * multiple peers. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_dht_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_NO + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 30) + +/* Timeout for waiting for replies to get requests */ +#define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 300) + +/* */ +#define START_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) + +/* Timeout for waiting for gets to complete */ +#define GET_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 50) + +/* Timeout for waiting for puts to complete */ +#define PUT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 50) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 10 + +#define TEST_DATA_SIZE 8 + +#define MAX_OUTSTANDING_PUTS 100 + +#define MAX_OUTSTANDING_GETS 100 + +#define PATH_TRACKING GNUNET_NO + + + +struct TestPutContext +{ + /** + * This is a linked list + */ + struct TestPutContext *next; + + /** + * This is a linked list + */ + struct TestPutContext *prev; + + /** + * Handle to the first peers DHT service (via the API) + */ + struct GNUNET_DHT_Handle *dht_handle; + + /** + * Handle to the PUT peer daemon + */ + struct GNUNET_TESTING_Daemon *daemon; + + /** + * Identifier for this PUT + */ + uint32_t uid; + + /** + * Task handle for processing of the put. + */ + GNUNET_SCHEDULER_TaskIdentifier task; +}; + + +struct TestGetContext +{ + /** + * This is a linked list + */ + struct TestGetContext *next; + + /** + * This is a linked list + */ + struct TestGetContext *prev; + + /** + * Handle to the first peers DHT service (via the API) + */ + struct GNUNET_DHT_Handle *dht_handle; + + /** + * Handle for the DHT get request + */ + struct GNUNET_DHT_GetHandle *get_handle; + + /** + * Handle to the GET peer daemon + */ + struct GNUNET_TESTING_Daemon *daemon; + + /** + * Identifier for this GET + */ + uint32_t uid; + + /** + * Task for disconnecting DHT handles (and stopping GET) + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Whether or not this request has been fulfilled already. + */ + int succeeded; +}; + + +/** + * List of GETS to perform + */ +static struct TestGetContext *all_gets_head; + +/** + * List of GETS to perform + */ +static struct TestGetContext *all_gets_tail; + +/** + * List of PUTS to perform + */ +static struct TestPutContext *all_puts_head; + +/** + * List of PUTS to perform + */ +static struct TestPutContext *all_puts_tail; + +/** + * Handle to the set of all peers run for this test. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Total number of peers to run, set based on config file. + */ +static unsigned long long num_peers; + +/** + * How many puts do we currently have in flight? + */ +static unsigned long long outstanding_puts; + +/** + * How many puts are done? + */ +static unsigned long long puts_completed; + +/** + * How many puts do we currently have in flight? + */ +static unsigned long long outstanding_gets; + +/** + * How many gets are done? + */ +static unsigned long long gets_completed; + +/** + * How many gets failed? + */ +static unsigned long long gets_failed; + +/** + * Directory to remove on shutdown. + */ +static char *test_directory; + +/** + * Option to use when routing. + */ +static enum GNUNET_DHT_RouteOption route_option; + +/** + * Task handle to use to schedule test failure / success. + */ +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +/** + * Task handle to use to schedule test shutdown + */ +GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + +/** + * Global return value (0 for success, anything else for failure) + */ +static int ok; + + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + FPRINTF (stderr, "Failed to shutdown testing topology: %s\n", emsg); + if (ok == 0) + ok = 2; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown callback completed.\n"); +} + +static void +do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) == 0) + { + if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) + { + GNUNET_SCHEDULER_cancel(shutdown_task); + shutdown_task = GNUNET_SCHEDULER_NO_TASK; + } + } + else + { + shutdown_task = GNUNET_SCHEDULER_NO_TASK ; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown requested.\n"); + if (NULL != pg) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + pg = NULL; +} + + +/** + * Master context for 'stat_run'. + */ +struct StatMaster +{ + struct GNUNET_STATISTICS_Handle *stat; + unsigned int daemon; + unsigned int value; +}; + +struct StatValues +{ + const char *subsystem; + const char *name; + unsigned long long total; +}; + +/** + * Statistics we print out. + */ +static struct StatValues stats[] = { + {"core", "# bytes decrypted", 0}, + {"core", "# bytes encrypted", 0}, + {"core", "# type maps received", 0}, + {"core", "# session keys confirmed via PONG", 0}, + {"core", "# entries in session map", 0}, + {"core", "# key exchanges initiated", 0}, + {"core", "# send requests dropped (disconnected)", 0}, + {"core", "# transmissions delayed due to corking", 0}, + {"core", "# messages discarded (expired prior to transmission)", 0}, + {"core", "# messages discarded (disconnected)", 0}, + {"core", "# discarded CORE_SEND requests", 0}, + {"core", "# discarded lower priority CORE_SEND requests", 0}, + {"transport", "# bytes received via TCP", 0}, + {"transport", "# bytes transmitted via TCP", 0}, + {"dht", "# PUT messages queued for transmission", 0}, + {"dht", "# P2P PUT requests received", 0}, + {"dht", "# GET messages queued for transmission", 0}, + {"dht", "# P2P GET requests received", 0}, + {"dht", "# RESULT messages queued for transmission", 0}, + {"dht", "# P2P RESULTS received", 0}, + {"dht", "# Queued messages discarded (peer disconnected)", 0}, + {"dht", "# Peers excluded from routing due to Bloomfilter", 0}, + {"dht", "# Peer selection failed", 0}, + {"dht", "# FIND PEER requests ignored due to Bloomfilter", 0}, + {"dht", "# FIND PEER requests ignored due to lack of HELLO", 0}, + {"dht", "# P2P FIND PEER requests processed", 0}, + {"dht", "# P2P GET requests ONLY routed", 0}, + {"dht", "# Preference updates given to core", 0}, + {"dht", "# REPLIES ignored for CLIENTS (no match)", 0}, + {"dht", "# GET requests from clients injected", 0}, + {"dht", "# GET requests received from clients", 0}, + {"dht", "# GET STOP requests received from clients", 0}, + {"dht", "# ITEMS stored in datacache", 0}, + {"dht", "# Good RESULTS found in datacache", 0}, + {"dht", "# GET requests given to datacache", 0}, + {NULL, NULL, 0} +}; + + +/** + * Callback function to process statistic values. + * + * @param cls closure + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +print_stat (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + struct StatMaster *sm = cls; + + stats[sm->value].total += value; + FPRINTF (stderr, "Peer %2u: %12s/%50s = %12llu\n", sm->daemon, subsystem, + name, (unsigned long long) value); + return GNUNET_OK; +} + + +/** + * Function that gathers stats from all daemons. + */ +static void +stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Function called when GET operation on stats is done. + */ +static void +get_done (void *cls, int success) +{ + struct StatMaster *sm = cls; + + GNUNET_break (GNUNET_OK == success); + sm->value++; + GNUNET_SCHEDULER_add_now (&stat_run, sm); +} + + +/** + * Function that gathers stats from all daemons. + */ +static void +stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct StatMaster *sm = cls; + unsigned int i; + + die_task = GNUNET_SCHEDULER_NO_TASK; + if (stats[sm->value].name != NULL) + { + GNUNET_STATISTICS_get (sm->stat, +#if 0 + NULL, NULL, +#else + stats[sm->value].subsystem, stats[sm->value].name, +#endif + GNUNET_TIME_UNIT_FOREVER_REL, &get_done, &print_stat, + sm); + return; + } + GNUNET_STATISTICS_destroy (sm->stat, GNUNET_NO); + sm->value = 0; + sm->daemon++; + if (sm->daemon == num_peers) + { + GNUNET_free (sm); + i = 0; + while (stats[i].name != NULL) + { + FPRINTF (stderr, "Total : %12s/%50s = %12llu\n", stats[i].subsystem, + stats[i].name, (unsigned long long) stats[i].total); + i++; + } + die_task = GNUNET_SCHEDULER_add_now (&do_stop, NULL); + return; + } + sm->stat = + GNUNET_STATISTICS_create ("", + GNUNET_TESTING_daemon_get (pg, + sm->daemon)->cfg); + die_task = GNUNET_SCHEDULER_add_now (&stat_run, sm); +} + + +/** + * Function scheduled to be run on the successful completion of this + * testcase. + */ +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestPutContext *test_put; + struct TestGetContext *test_get; + struct StatMaster *sm; + + die_task = GNUNET_SCHEDULER_NO_TASK; + while (NULL != (test_put = all_puts_head)) + { + if (test_put->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (test_put->task); + if (test_put->dht_handle != NULL) + GNUNET_DHT_disconnect (test_put->dht_handle); + GNUNET_CONTAINER_DLL_remove (all_puts_head, all_puts_tail, test_put); + GNUNET_free (test_put); + } + + while (NULL != (test_get = all_gets_head)) + { + if (test_get->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (test_get->task); + if (test_get->get_handle != NULL) + GNUNET_DHT_get_stop (test_get->get_handle); + if (test_get->dht_handle != NULL) + GNUNET_DHT_disconnect (test_get->dht_handle); + GNUNET_CONTAINER_DLL_remove (all_gets_head, all_gets_tail, test_get); + GNUNET_free (test_get); + } + sm = GNUNET_malloc (sizeof (struct StatMaster)); + sm->stat = + GNUNET_STATISTICS_create ("", + GNUNET_TESTING_daemon_get (pg, + sm->daemon)->cfg); + die_task = GNUNET_SCHEDULER_add_now (&stat_run, sm); +} + + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + const char *emsg = cls; + struct TestPutContext *test_put; + struct TestGetContext *test_get; + + die_task = GNUNET_SCHEDULER_NO_TASK; + FPRINTF (stderr, "Failing test with error: `%s'!\n", emsg); + while (NULL != (test_put = all_puts_head)) + { + if (test_put->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (test_put->task); + if (test_put->dht_handle != NULL) + GNUNET_DHT_disconnect (test_put->dht_handle); + GNUNET_CONTAINER_DLL_remove (all_puts_head, all_puts_tail, test_put); + GNUNET_free (test_put); + } + + while (NULL != (test_get = all_gets_head)) + { + if (test_get->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (test_get->task); + if (test_get->get_handle != NULL) + GNUNET_DHT_get_stop (test_get->get_handle); + if (test_get->dht_handle != NULL) + GNUNET_DHT_disconnect (test_get->dht_handle); + GNUNET_CONTAINER_DLL_remove (all_gets_head, all_gets_tail, test_get); + GNUNET_free (test_get); + } + ok = 1; + /* testing_peergroup will do that in its own end_badly() handler */ + /*GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); */ + pg = NULL; +} + + +/** + * Task to release get handle. + */ +static void +get_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestGetContext *test_get = cls; + GNUNET_HashCode search_key; /* Key stored under */ + char original_data[TEST_DATA_SIZE]; /* Made up data to store */ + + test_get->task = GNUNET_SCHEDULER_NO_TASK; + memset (original_data, test_get->uid, sizeof (original_data)); + GNUNET_CRYPTO_hash (original_data, TEST_DATA_SIZE, &search_key); + if (test_get->succeeded != GNUNET_YES) + { + gets_failed++; + FPRINTF (stderr, "Get from peer %s for key %s failed!\n", + GNUNET_i2s (&test_get->daemon->id), GNUNET_h2s (&search_key)); + } + GNUNET_assert (test_get->get_handle != NULL); + GNUNET_DHT_get_stop (test_get->get_handle); + test_get->get_handle = NULL; + + outstanding_gets--; /* GET is really finished */ + GNUNET_DHT_disconnect (test_get->dht_handle); + test_get->dht_handle = NULL; + + GNUNET_CONTAINER_DLL_remove (all_gets_head, all_gets_tail, test_get); + GNUNET_free (test_get); + if ((gets_failed > 10) && (outstanding_gets == 0)) + { + /* Had more than 10% failures */ + FPRINTF (stderr, "%llu gets succeeded, %llu gets failed!\n", gets_completed, + gets_failed); + GNUNET_SCHEDULER_cancel (die_task); + ok = 1; + die_task = + GNUNET_SCHEDULER_add_now (&finish_testing, "not all gets succeeded"); + return; + } + if ((gets_completed + gets_failed == num_peers * num_peers) && (outstanding_gets == 0)) /* All gets successful */ + { + FPRINTF (stderr, "%llu gets succeeded, %llu gets failed!\n", gets_completed, + gets_failed); + GNUNET_SCHEDULER_cancel (die_task); + ok = 0; + die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } +} + + +/** + * Iterator called if the GET request initiated returns a response. + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +static void +get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + struct TestGetContext *test_get = cls; + GNUNET_HashCode search_key; /* Key stored under */ + char original_data[TEST_DATA_SIZE]; /* Made up data to store */ + + memset (original_data, test_get->uid, sizeof (original_data)); + GNUNET_CRYPTO_hash (original_data, TEST_DATA_SIZE, &search_key); + if (test_get->succeeded == GNUNET_YES) + return; /* Get has already been successful, probably ending now */ + +#if PATH_TRACKING + if (put_path != NULL) + { + unsigned int i; + + FPRINTF (stderr, "PUT (%u) Path: ", test_get->uid); + for (i = 0; i < put_path_length; i++) + FPRINTF (stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s (&put_path[i])); + FPRINTF (stderr, "%s", "\n"); + } + if (get_path != NULL) + { + unsigned int i; + + FPRINTF (stderr, "GET (%u) Path: ", test_get->uid); + for (i = 0; i < get_path_length; i++) + FPRINTF (stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s (&get_path[i])); + FPRINTF (stderr, "%s%s\n", get_path_length > 0 ? "->" : "", + GNUNET_i2s (&test_get->daemon->id)); + } +#endif + + if ((0 != memcmp (&search_key, key, sizeof (GNUNET_HashCode))) || + (0 != memcmp (original_data, data, sizeof (original_data)))) + { + FPRINTF (stderr, "%s", "Key or data is not the same as was inserted!\n"); + return; + } + gets_completed++; + test_get->succeeded = GNUNET_YES; + GNUNET_SCHEDULER_cancel (test_get->task); + test_get->task = GNUNET_SCHEDULER_add_now (&get_stop_task, test_get); +} + + +/** + * Set up some data, and call API PUT function + */ +static void +do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestGetContext *test_get = cls; + GNUNET_HashCode key; /* Made up key to store data under */ + char data[TEST_DATA_SIZE]; /* Made up data to store */ + + if (outstanding_gets > MAX_OUTSTANDING_GETS) + { + test_get->task = + GNUNET_SCHEDULER_add_delayed (GET_DELAY, &do_get, test_get); + return; + } + memset (data, test_get->uid, sizeof (data)); + GNUNET_CRYPTO_hash (data, TEST_DATA_SIZE, &key); + test_get->dht_handle = GNUNET_DHT_connect (test_get->daemon->cfg, 10); + GNUNET_assert (test_get->dht_handle != NULL); + outstanding_gets++; + test_get->get_handle = + GNUNET_DHT_get_start (test_get->dht_handle, GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_BLOCK_TYPE_TEST, &key, 1, route_option, NULL, + 0, &get_result_iterator, test_get); + test_get->task = + GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &get_stop_task, test_get); +} + + +/** + * Task to release DHT handles for PUT + */ +static void +put_disconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestPutContext *test_put = cls; + + test_put->task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_DHT_disconnect (test_put->dht_handle); + test_put->dht_handle = NULL; + GNUNET_CONTAINER_DLL_remove (all_puts_head, all_puts_tail, test_put); + GNUNET_free (test_put); +} + + +/** + * Schedule the GET requests + */ +static void +start_gets (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned long long i; + unsigned long long j; + struct TestGetContext *test_get; + +#if VERBOSE + FPRINTF (stderr, "Issuing %llu GETs\n", + (unsigned long long) (num_peers * num_peers)); +#endif + for (i = 0; i < num_peers; i++) + for (j = 0; j < num_peers; j++) + { + test_get = GNUNET_malloc (sizeof (struct TestGetContext)); + test_get->uid = i + j * num_peers; + test_get->daemon = GNUNET_TESTING_daemon_get (pg, j); + GNUNET_CONTAINER_DLL_insert (all_gets_head, all_gets_tail, test_get); + test_get->task = GNUNET_SCHEDULER_add_now (&do_get, test_get); + } +} + + +/** + * Called when the PUT request has been transmitted to the DHT service. + */ +static void +put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestPutContext *test_put = cls; + + outstanding_puts--; + puts_completed++; + if (GNUNET_SCHEDULER_NO_TASK != test_put->task) + { + GNUNET_SCHEDULER_cancel (test_put->task); + } + test_put->task = GNUNET_SCHEDULER_add_now (&put_disconnect_task, test_put); + if (puts_completed != num_peers * num_peers) + return; + + GNUNET_assert (outstanding_puts == 0); + GNUNET_SCHEDULER_add_delayed (START_DELAY, &start_gets, NULL); +} + + +/** + * Set up some data, and call API PUT function + */ +static void +do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestPutContext *test_put = cls; + GNUNET_HashCode key; /* Made up key to store data under */ + char data[TEST_DATA_SIZE]; /* Made up data to store */ + + test_put->task = GNUNET_SCHEDULER_NO_TASK; + if (outstanding_puts > MAX_OUTSTANDING_PUTS) + { + test_put->task = + GNUNET_SCHEDULER_add_delayed (PUT_DELAY, &do_put, test_put); + return; + } + memset (data, test_put->uid, sizeof (data)); + GNUNET_CRYPTO_hash (data, TEST_DATA_SIZE, &key); + test_put->dht_handle = GNUNET_DHT_connect (test_put->daemon->cfg, 10); + GNUNET_assert (test_put->dht_handle != NULL); + outstanding_puts++; +#if VERBOSE > 2 + FPRINTF (stderr, "PUT %u at `%s'\n", test_put->uid, + GNUNET_i2s (&test_put->daemon->id)); +#endif + GNUNET_DHT_put (test_put->dht_handle, &key, 1, route_option, + GNUNET_BLOCK_TYPE_TEST, sizeof (data), data, + GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_REL, + &put_finished, test_put); + test_put->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &put_disconnect_task, test_put); +} + + +static void +run_dht_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned long long i; + struct TestPutContext *test_put; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + ok = 1; + return; + } +#if PATH_TRACKING + route_option = + GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE; +#else + route_option = GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE; +#endif + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "from setup puts/gets"); + FPRINTF (stderr, "Issuing %llu PUTs (one per peer)\n", + (unsigned long long) (num_peers * num_peers)); + for (i = 0; i < num_peers * num_peers; i++) + { + test_put = GNUNET_malloc (sizeof (struct TestPutContext)); + test_put->uid = i; + test_put->daemon = GNUNET_TESTING_daemon_get (pg, i % num_peers); + test_put->task = GNUNET_SCHEDULER_add_now (&do_put, test_put); + GNUNET_CONTAINER_DLL_insert (all_puts_head, all_puts_tail, test_put); + } +} + + +/** + * This function is called once testing has finished setting up the topology. + * + * @param cls unused + * @param emsg variable is NULL on success (peers connected), and non-NULL on + * failure (peers failed to connect). + */ +static void +startup_done (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + FPRINTF (stderr, "Failed to setup topology: %s\n", emsg); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, "topology setup failed"); + return; + } + die_task = + GNUNET_SCHEDULER_add_delayed (START_DELAY, &run_dht_test, + "from setup puts/gets"); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + GNUNET_break (0); + ok = 404; + return; + } + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + pg = GNUNET_TESTING_peergroup_start (cfg, num_peers, TIMEOUT, NULL, + &startup_done, NULL, NULL); + GNUNET_assert (NULL != pg); + shutdown_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, + &do_stop, NULL); +} + + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-dht-multipeer", /* Name to give running binary */ + "-c", + "test_dht_multipeer_data.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-dht-multipeer", "nohelp", options, &run, &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-dht-multipeer': Failed with error code %d\n", ret); + } + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + + + GNUNET_log_setup ("test-dht-multipeer", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + return ret; +} + +/* end of test_dht_multipeer.c */ diff --git a/src/dht/test_dht_multipeer_data.conf b/src/dht/test_dht_multipeer_data.conf new file mode 100644 index 0000000..ff87698 --- /dev/null +++ b/src/dht/test_dht_multipeer_data.conf @@ -0,0 +1,128 @@ +[fs] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO + +[dht] +DEBUG = NO +STOP_ON_CLOSEST = YES +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +#BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/dht/.libs/gnunet-service-dht +#PREFIX = xterm -T dht -e gdb --args +#PREFIX = valgrind --log-file=dht_%p +CONFIG = $DEFAULTCONFIG +HOME = $SERVICEHOME +HOSTNAME = localhost +PORT = 2100 +STOP_FOUND = YES +USE_MAX_HOPS = YES +MAX_HOPS = 16 +CONVERGE_BINARY = YES +CONVERGE_MODIFIER = 4 + +[block] +plugins = test dht + +[dhtcache] +QUOTA = 1 MB +DATABASE = sqlite + +[transport] +PLUGINS = tcp +DEBUG = NO +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +NEIGHBOUR_LIMIT = 50 +BINARY = gnunet-service-transport +CONFIG = $DEFAULTCONFIG +HOME = $SERVICEHOME +HOSTNAME = localhost +PORT = 12365 + +[DHTLOG] +PLUGIN = mysql_dump + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +BINARY = gnunet-service-core +CONFIG = $DEFAULTCONFIG +HOME = $SERVICEHOME +HOSTNAME = localhost +PORT = 12092 +DEBUG = NO + +[arm] +DEFAULTSERVICES = dht core +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +BINARY = gnunet-service-arm +CONFIG = $DEFAULTCONFIG +HOME = $SERVICEHOME +HOSTNAME = localhost +PORT = 12366 +DEBUG = NO + +[transport-tcp] +TIMEOUT = 300 s +PORT = 12368 +BINDTO = 127.0.0.1 + +[DHT_TESTING] +MYSQL_LOGGING_EXTENDED = NO +MYSQL_LOGGING = NO +NUM_GETS = 5 +NUM_PUTS = 5 + +[TESTING] +TOPOLOGY = FROM_FILE +# file contains a ring +CONNECT_TOPOLOGY = NONE +# None == use all allowed connections +# BLACKLIST_TOPOLOGY = X +# No additional restrictions... + +TOPOLOGY_FILE = multipeer_topo.dat +MAX_CONCURRENT_SSH = 1 +PEERGROUP_TIMEOUT = 2400 s +USE_PROGRESSBARS = YES +#CONNECT_TOPOLOGY_OPTION = CONNECT_RANDOM_SUBSET +#CONNECT_TOPOLOGY_OPTION_MODIFIER = 2 +#LOGNMODIFIER = .65 +#PERCENTAGE = .75 +WEAKRANDOM = YES +NUM_PEERS = 10 +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[PATHS] +DEFAULTCONFIG = test_dht_multipeer_data.conf +SERVICEHOME = /tmp/test-dht-multipeer/ + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[dns] +AUTOSTART = NO + + + +[nse] +AUTOSTART = NO + + diff --git a/src/dht/test_dht_tools.sh b/src/dht/test_dht_tools.sh new file mode 100755 index 0000000..f83c26a --- /dev/null +++ b/src/dht/test_dht_tools.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +out=`mktemp /tmp/test-gnunet-dht-logXXXXXXXX` +tempcfg=`mktemp /tmp/test_dht_api_peer1.XXXXXXXX` +checkout="check.out" +armexe="gnunet-arm -c $tempcfg " +putexe="gnunet-dht-put -c $tempcfg " +getexe="gnunet-dht-get -c $tempcfg " +peerinfo="gnunet-peerinfo -c $tempcfg -sq" +stop_arm() +{ + if ! $armexe $DEBUG -e -d > $out ; then + echo "FAIL: error running $armexe" + echo "Command output was:" + cat $out + rm -f $out $tempcfg + exit 1 + fi + rm -f $out $tempcfg +} + +cp test_dht_api_peer1.conf $tempcfg + +echo -n "TEST: Generating hostkey..." +if ! $peerinfo > $out ; then + echo "FAIL: error running $peerinfo" + echo "Command output was:" + cat $out + exit 1 +fi +echo "PASS" + +echo -n "TEST: Starting ARM..." +if ! $armexe $DEBUG -s > $out ; then + echo "FAIL: error running $armexe" + echo "Command output was:" + cat $out + stop_arm + exit 1 +fi +echo "PASS" +sleep 1 + +echo -n "TEST: Testing put..." +if ! $putexe -k testkey -d testdata -t 8 > $out ; then + echo "FAIL: error running $putexe" + echo "Command output was:" + cat $out + stop_arm + exit 1 +fi +echo "PASS" +sleep 1 + +echo -n "TEST: Testing get..." +echo "Result 0, type 8:" > $checkout +echo "testdata" >> $checkout + +if ! $getexe -k testkey -T 5 -t 8 > $out ; then + echo "FAIL: error running $putexe" + echo "Command output was:" + cat $out + stop_arm + exit 1 +fi + +if ! diff --strip-trailing-cr -q $out $checkout ; then + echo "FAIL: $out and $checkout differ" + stop_arm + exit 1 +fi +echo "PASS" +stop_arm diff --git a/src/dht/test_dht_topo.c b/src/dht/test_dht_topo.c new file mode 100644 index 0000000..81dc7cb --- /dev/null +++ b/src/dht/test_dht_topo.c @@ -0,0 +1,662 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dht/test_dht_topo.c + * + * @brief Test for the dht service: store and retrieve in various topologies. + * Each peer stores it own ID in the DHT and then a different peer tries to + * retrieve that key from it. The GET starts after a first round of PUTS has + * been made. Periodically, each peer stores its ID into the DHT. If after + * a timeout no result has been returned, the test fails. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_dht_service.h" + +#define VERBOSE GNUNET_NO + +#define REMOVE_DIR GNUNET_YES + +/** + * DIFFERENT TESTS TO RUN + */ +#define LINE 0 +#define TORUS 1 + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) + +#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +#define PUT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +/** + * Result of the test. + */ +static int ok; + +/** + * Be verbose + */ +static int verbose; + +/** + * Total number of peers in the test. + */ +static unsigned long long num_peers; + +/** + * Global configuration file + */ +static struct GNUNET_CONFIGURATION_Handle *testing_cfg; + +/** + * Total number of currently running peers. + */ +static unsigned long long peers_running; + +/** + * Total number of connections in the whole network. + */ +static unsigned int total_connections; + +/** + * The currently running peer group. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * File to report results to. + */ +static struct GNUNET_DISK_FileHandle *output_file; + +/** + * File to log connection info, statistics to. + */ +static struct GNUNET_DISK_FileHandle *data_file; + +/** + * Task called to disconnect peers. + */ +static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +/** + * Task To perform tests + */ +static GNUNET_SCHEDULER_TaskIdentifier test_task; + +/** + * Task to do DHT_puts + */ +static GNUNET_SCHEDULER_TaskIdentifier put_task; + +/** + * Task called to shutdown test. + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; + +static char *topology_file; + +struct GNUNET_TESTING_Daemon *d1; + +struct GNUNET_TESTING_Daemon *d2; + +struct GNUNET_DHT_Handle **hs; + +struct GNUNET_DHT_GetHandle *get_h; + +struct GNUNET_DHT_GetHandle *get_h_2; + +struct GNUNET_DHT_GetHandle *get_h_far; + +int found_1; +int found_2; +int found_far; + +/** + * Which topology are we to run + */ +static int test_topology; + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + ok++; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All peers successfully shut down!\n"); +#endif + } + GNUNET_CONFIGURATION_destroy (testing_cfg); +} + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); +#endif + + if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (data_file != NULL) + GNUNET_DISK_file_close (data_file); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +static void +disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnecting peers\n"); + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_cancel (put_task); + if (NULL != get_h) + GNUNET_DHT_get_stop (get_h); + if (NULL != get_h_2) + GNUNET_DHT_get_stop (get_h_2); + if (NULL != get_h_far) + GNUNET_DHT_get_stop (get_h_far); + for (i = 0; i < num_peers; i++) + { + GNUNET_DHT_disconnect (hs[i]); + } + GNUNET_SCHEDULER_cancel (shutdown_handle); + shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); +} + +static void +dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + int i; + + if (sizeof (GNUNET_HashCode) == size) + { + const GNUNET_HashCode *h = data; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Contents: %s\n", + GNUNET_h2s_full (h)); + + } + else + { + GNUNET_break(0); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH: (get %u, put %u)\n", + get_path_length, put_path_length); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " LOCAL\n"); + for (i = get_path_length - 1; i >= 0; i--) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n", + GNUNET_i2s (&get_path[i])); + } + for (i = put_path_length - 1; i >= 0; i--) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n", + GNUNET_i2s (&put_path[i])); + } + switch ((long)cls) + { + case 1: + found_1++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "FOUND 1!\n"); + break; + case 2: + found_2++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "FOUND 2!\n"); + break; + case 3: + found_far++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "FOUND FAR!\n"); + break; + default: + GNUNET_break(0); + } + if (TORUS == test_topology && + (found_1 == 0 || found_2 == 0 || found_far == 0)) + return; + ok = 0; + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); +} + +static void +do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_Daemon *d; + struct GNUNET_TESTING_Daemon *d2; + struct GNUNET_TESTING_Daemon *d_far; + struct GNUNET_TESTING_Daemon *o; + struct GNUNET_TESTING_Daemon *aux; + const char *id_aux; + const char *id_origin = "FC74"; + const char *id_near = "9P6V"; + const char *id_near2 = "2GDS"; + const char *id_far = "KPST"; + unsigned int i; + + d = d2 = d_far = o = NULL; + found_1 = found_2 = found_far = 0; + if (LINE == test_topology) + { + o = GNUNET_TESTING_daemon_get (pg, 0); + d = GNUNET_TESTING_daemon_get (pg, 4); + } + else if (TORUS == test_topology) + { + for (i = 0; i < num_peers; i++) + { + aux = GNUNET_TESTING_daemon_get (pg, i); + id_aux = GNUNET_i2s (&aux->id); + if (strcmp (id_aux, id_origin) == 0) + o = aux; + if (strcmp (id_aux, id_far) == 0) + d_far = aux; + if (strcmp (id_aux, id_near) == 0) + d = aux; + if (strcmp (id_aux, id_near2) == 0) + d2 = aux; + } + if ((NULL == o) || (NULL == d) || (NULL == d2) || (NULL == d_far)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Peers not found (hostkey file changed?)\n"); + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); + return; + } + } + else + { + GNUNET_assert (0); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\ntest: from %s\n", + GNUNET_h2s_full (&o->id.hashPubKey)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " looking for %s\n", + GNUNET_h2s_full (&d->id.hashPubKey)); + get_h = GNUNET_DHT_get_start (hs[0], GNUNET_TIME_UNIT_FOREVER_REL, /* timeout */ + GNUNET_BLOCK_TYPE_TEST, /* type */ + &d->id.hashPubKey, /*key to search */ + 4U, /* replication level */ + GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, /* xquery */ + 0, /* xquery bits */ + &dht_get_id_handler, (void *)1); + if (TORUS == test_topology) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " looking for %s\n", + GNUNET_h2s_full (&d2->id.hashPubKey)); + get_h_2 = GNUNET_DHT_get_start (hs[0], GNUNET_TIME_UNIT_FOREVER_REL, /* timeout */ + GNUNET_BLOCK_TYPE_TEST, /* type */ + &d2->id.hashPubKey, /*key to search */ + 4U, /* replication level */ + GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, /* xquery */ + 0, /* xquery bits */ + &dht_get_id_handler, (void *)2); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " looking for %s\n", + GNUNET_h2s_full (&d_far->id.hashPubKey)); + get_h_far = GNUNET_DHT_get_start (hs[0], GNUNET_TIME_UNIT_FOREVER_REL, /* timeout */ + GNUNET_BLOCK_TYPE_TEST, /* type */ + &d_far->id.hashPubKey, /*key to search */ + 4U, /* replication level */ + GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, /* xquery */ + 0, /* xquery bits */ + &dht_get_id_handler, (void *)3); + } + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &disconnect_peers, NULL); +} + +/** + * Task to put the id of each peer into teh DHT. + * + * @param cls Closure (unused) + * @param tc Task context + * + */ +static void +put_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_Daemon *d; + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "putting id's in DHT\n"); + for (i = 0; i < num_peers; i++) + { + d = GNUNET_TESTING_daemon_get (pg, i); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " putting into DHT: %s\n", + GNUNET_h2s_full (&d->id.hashPubKey)); + GNUNET_DHT_put (hs[i], &d->id.hashPubKey, 10U, + GNUNET_DHT_RO_RECORD_ROUTE | + GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, + GNUNET_BLOCK_TYPE_TEST, sizeof (struct GNUNET_PeerIdentity), + (const char *) &d->id, GNUNET_TIME_UNIT_FOREVER_ABS, + GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); + + } + put_task = GNUNET_SCHEDULER_add_delayed (PUT_FREQUENCY, &put_id, NULL); + if (GNUNET_SCHEDULER_NO_TASK == test_task) + test_task = GNUNET_SCHEDULER_add_now (&do_test, NULL); +} + + +/** + * peergroup_ready: start test when all peers are connected + * + * @param cls closure + * @param emsg error message + * + */ +static void +peergroup_ready (void *cls, const char *emsg) +{ + struct GNUNET_TESTING_Daemon *d; + char *buf; + int buf_len; + unsigned int i; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n", + emsg); + ok++; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "************************************************************\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer Group started successfully!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %u connections\n", + total_connections); +#endif + + if (data_file != NULL) + { + buf = NULL; + buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections); + if (buf_len > 0) + GNUNET_DISK_file_write (data_file, buf, buf_len); + GNUNET_free (buf); + } + peers_running = GNUNET_TESTING_daemons_running (pg); + + GNUNET_assert (peers_running == num_peers); + hs = GNUNET_malloc (num_peers * sizeof (struct GNUNET_DHT_Handle *)); + for (i = 0; i < num_peers; i++) + { + d = GNUNET_TESTING_daemon_get (pg, i); + hs[i] = GNUNET_DHT_connect (d->cfg, 32); + } + + test_task = GNUNET_SCHEDULER_NO_TASK; + put_task = GNUNET_SCHEDULER_add_now (&put_id, NULL); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &disconnect_peers, NULL); + +} + + +/** + * Function that will be called whenever two daemons are connected by + * the testing library. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param first_cfg config for the first daemon + * @param second_cfg config for the second daemon + * @param first_daemon handle for the first daemon + * @param second_daemon handle for the second daemon + * @param emsg error message (NULL on success) + */ +static void +connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) +{ + + if (emsg == NULL) + { + total_connections++; + GNUNET_PEER_intern (first); + GNUNET_PEER_intern (second); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Problem with new connection (%s)\n", emsg); + } + +} + + +/** + * run: load configuration options and schedule test to run (start peergroup) + * @param cls closure + * @param args argv + * @param cfgfile configuration file name (can be NULL) + * @param cfg configuration handle + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *temp_str; + struct GNUNET_TESTING_Host *hosts; + char *data_filename; + + ok = 1; + testing_cfg = GNUNET_CONFIGURATION_dup (cfg); + + GNUNET_log_setup ("test_dht_topo", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", "YES"); +#endif + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", + "num_peers", &num_peers)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option TESTING:NUM_PEERS is required!\n"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing", + "topology_output_file", + &topology_file)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option test_dht_topo:topology_output_file is required!\n"); + return; + } + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_dht_topo", + "data_output_file", + &data_filename)) + { + data_file = + GNUNET_DISK_file_open (data_filename, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (data_file == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", + data_filename); + GNUNET_free (data_filename); + } + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "test_dht_topo", + "output_file", &temp_str)) + { + output_file = + GNUNET_DISK_file_open (temp_str, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (output_file == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", + temp_str); + } + GNUNET_free_non_null (temp_str); + + hosts = GNUNET_TESTING_hosts_load (testing_cfg); + + pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, + &connect_cb, &peergroup_ready, NULL, + hosts); + GNUNET_assert (pg != NULL); + shutdown_handle = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, NULL); +} + + + +/** + * test_dht_2d command line options + */ +static struct GNUNET_GETOPT_CommandLineOption options[] = { + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END +}; + + +/** + * Main: start test + */ +int +main (int xargc, char *xargv[]) +{ + char *const argv_torus[] = { "test-dht-2dtorus", + "-c", + "test_dht_2dtorus.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + char *const argv_line[] = { "test-dht-line", + "-c", + "test_dht_line.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + char *const *argv; + int argc; + + if (strstr (xargv[0], "test_dht_2dtorus") != NULL) + { + argv = argv_torus; + argc = sizeof (argv_torus) / sizeof (char *); + test_topology = TORUS; + } + else if (strstr (xargv[0], "test_dht_line") != NULL) + { + argv = argv_line; + argc = sizeof (argv_line) / sizeof (char *); + test_topology = LINE; + } + else + { + GNUNET_break (0); + return 1; + } + GNUNET_PROGRAM_run (argc - 1, argv, + xargv[0], + gettext_noop ("Test dht in different topologies."), + options, + &run, NULL); +#if REMOVE_DIR + GNUNET_DISK_directory_remove ("/tmp/test_dht_topo"); +#endif + if (found_1 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ID 1 not found!\n"); + } + if (TORUS == test_topology) + { + if (found_2 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ID 2 not found!\n"); + } + if (found_far == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ID far not found!\n"); + } + } + return ok; +} + +/* end of test_dht_topo.c */ diff --git a/src/dht/test_dht_twopeer.c b/src/dht/test_dht_twopeer.c new file mode 100644 index 0000000..a3b6e4a --- /dev/null +++ b/src/dht/test_dht_twopeer.c @@ -0,0 +1,513 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dht/test_dht_twopeer.c + * @brief base testcase for testing DHT service with + * two running peers + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_dht_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_NO + +#define MAX_GET_ATTEMPTS 10 + +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) + +#define DEFAULT_NUM_PEERS 2 + +/* Structs */ + +struct PeerGetContext +{ + struct GNUNET_PeerIdentity *peer; + + struct GNUNET_DHT_Handle *dht_handle; + + struct GNUNET_DHT_GetHandle *get_handle; + + unsigned int get_attempts; + + GNUNET_SCHEDULER_TaskIdentifier retry_task; +}; + +/* Globals */ +static char *test_directory; + +static struct PeerGetContext curr_get_ctx; + +static unsigned int expected_connections; + +static unsigned long long peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +static unsigned long long num_peers; + +static unsigned int total_gets; + +static unsigned int gets_succeeded; + +static unsigned int total_connections; + +static unsigned int failed_connections; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static int ok; + +static struct GNUNET_PeerIdentity peer1id; + +static struct GNUNET_PeerIdentity peer2id; + +static struct GNUNET_DHT_Handle *peer1dht; + +static struct GNUNET_DHT_Handle *peer2dht; + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + if (ok == 0) + ok = 2; + } +} + +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (pg != NULL); + GNUNET_assert (peer1dht != NULL); + GNUNET_assert (peer2dht != NULL); + GNUNET_DHT_disconnect (peer1dht); + GNUNET_DHT_disconnect (peer2dht); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + pg = NULL; + ok = 0; +} + +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (peer1dht != NULL) + GNUNET_DHT_disconnect (peer1dht); + + if (peer2dht != NULL) + GNUNET_DHT_disconnect (peer2dht); + + if (pg != NULL) + { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + pg = NULL; + } + + if (curr_get_ctx.retry_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (curr_get_ctx.retry_task); + curr_get_ctx.retry_task = GNUNET_SCHEDULER_NO_TASK; + } +} + + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + const char *emsg = cls; + + FPRINTF (stderr, "Error: %s\n", emsg); + if (curr_get_ctx.retry_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (curr_get_ctx.retry_task); + curr_get_ctx.retry_task = GNUNET_SCHEDULER_NO_TASK; + } + if (curr_get_ctx.get_handle != NULL) + { + GNUNET_DHT_get_stop (curr_get_ctx.get_handle); + } + + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + + +/* Forward declaration */ +static void +do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Iterator called on each result obtained for a DHT + * operation that expects a reply + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +static void +get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + struct PeerGetContext *get_context = cls; + + if (0 != + memcmp (&get_context->peer->hashPubKey, key, sizeof (GNUNET_HashCode))) + { + FPRINTF (stderr, "%s", "??\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Key returned is not the same key as was searched for!\n"); + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "key mismatch in get response!\n"); + return; + } + if (get_context->retry_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (get_context->retry_task); + get_context->retry_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (get_context->peer == &peer2id) + { + get_context->peer = &peer1id; + get_context->dht_handle = peer2dht; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received first correct GET request response!\n"); + GNUNET_DHT_get_stop (get_context->get_handle); + GNUNET_SCHEDULER_add_now (&do_get, get_context); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received second correct GET request response!\n"); + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_DHT_get_stop (get_context->get_handle); + die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } + +} + +static void +stop_retry_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +static void +get_stop_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerGetContext *get_context = cls; + + if (get_context->get_attempts >= MAX_GET_ATTEMPTS) + { + FPRINTF (stderr, "%s", "?\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Too many attempts failed, ending test!\n", + get_context->get_attempts); + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "GET attempt failed, ending test!\n"); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Get attempt %u failed, retrying request!\n", + get_context->get_attempts); + FPRINTF (stderr, "%s", "."); + get_context->get_attempts++; + get_context->retry_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 60), + &stop_retry_get, get_context); + get_context->get_handle = + GNUNET_DHT_get_start (get_context->dht_handle, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + GNUNET_BLOCK_TYPE_DHT_HELLO, + &get_context->peer->hashPubKey, 1, + GNUNET_DHT_RO_NONE, NULL, 0, &get_result_iterator, + get_context); +} + + +static void +stop_retry_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerGetContext *get_context = cls; + + get_context->retry_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Get attempt %u failed, canceling request!\n", + get_context->get_attempts); + GNUNET_DHT_get_stop (get_context->get_handle); + get_context->get_handle = NULL; + GNUNET_SCHEDULER_add_now (&get_stop_finished, get_context); +} + + +static void +do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerGetContext *get_context = cls; + + get_context->retry_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 10), + &stop_retry_get, get_context); + get_context->get_handle = + GNUNET_DHT_get_start (get_context->dht_handle, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + GNUNET_BLOCK_TYPE_DHT_HELLO, + &get_context->peer->hashPubKey, 1, + GNUNET_DHT_RO_FIND_PEER, NULL, 0, + &get_result_iterator, get_context); +} + + +static void +topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connected peer %s to peer %s, distance %u\n", + first_daemon->shortname, second_daemon->shortname, distance); + } + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); +#endif + } + + if (total_connections == expected_connections) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number! Starting next phase of testing.\n", + total_connections); +#endif + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "Timeout trying to GET"); + + curr_get_ctx.dht_handle = peer1dht; + curr_get_ctx.peer = &peer2id; + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 2), &do_get, + &curr_get_ctx); + } + else if (total_connections + failed_connections == expected_connections) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many failed connections)"); + } +} + + +static void +connect_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + expected_connections = -1; + if ((pg != NULL) && (peers_left == 0)) + expected_connections = + GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_CLIQUE, + GNUNET_TESTING_TOPOLOGY_OPTION_ALL, + 0.0, TIMEOUT, 12, NULL, NULL); + + GNUNET_SCHEDULER_cancel (die_task); + if (expected_connections == GNUNET_SYSERR) + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from connect topology (bad return)"); + else + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "from connect topology (timeout)"); +} + + +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + FPRINTF (stderr, "Failed to start daemon: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); + if (peers_left == num_peers) + { + memcpy (&peer1id, id, sizeof (struct GNUNET_PeerIdentity)); + peer1dht = GNUNET_DHT_connect (cfg, 100); + if (peer1dht == NULL) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); + } + } + else + { + memcpy (&peer2id, id, sizeof (struct GNUNET_PeerIdentity)); + peer2dht = GNUNET_DHT_connect (cfg, 100); + if (peer2dht == NULL) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); + } + } + + + peers_left--; + + if (peers_left == 0) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now connecting peers!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "from peers_started_callback"); + + GNUNET_SCHEDULER_add_now (&connect_topology, NULL); + ok = 0; + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + peers_left = num_peers; + total_gets = num_peers; + gets_succeeded = 0; + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + pg = GNUNET_TESTING_daemons_start (cfg, num_peers, 10, num_peers, TIMEOUT, + NULL, NULL, &peers_started_callback, NULL, + &topology_callback, NULL, NULL); + +} + +static int +check () +{ + int ret; + + char *const argv[] = { "test-dht-twopeer", + "-c", + "test_dht_twopeer_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-dht-twopeer", "nohelp", options, &run, &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-dht-twopeer': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-dht-twopeer", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + return ret; +} + +/* end of test_dht_twopeer.c */ diff --git a/src/dht/test_dht_twopeer_data.conf b/src/dht/test_dht_twopeer_data.conf new file mode 100644 index 0000000..ba1e22b --- /dev/null +++ b/src/dht/test_dht_twopeer_data.conf @@ -0,0 +1,74 @@ +[PATHS] +DEFAULTCONFIG = test_dht_twopeer_data.conf +SERVICEHOME = /tmp/test-dht-twopeer/ + +[resolver] +AUTOSTART = YES + +[dht] +DEBUG = NO +AUTOSTART = YES +#PREFIX = xterm -T dht -e gdb --args +PORT = 2100 +BINARY = gnunet-service-dht + +[block] +plugins = test dht dns + +[dhtcache] +QUOTA = 1 MB +DATABASE = sqlite + +[transport] +PLUGINS = tcp +DEBUG = NO +NEIGHBOUR_LIMIT = 50 +PORT = 12365 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +HOSTNAME = localhost +PORT = 12092 + +[arm] +DEFAULTSERVICES = core +PORT = 12366 +DEBUG = NO + +[transport-tcp] +TIMEOUT = 300 s +PORT = 12368 +BINDTO = 127.0.0.1 + +[TESTING] +WEAKRANDOM = YES +NUM_PEERS = 2 +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[dns] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[fs] +AUTOSTART = NO + diff --git a/src/dht/test_dht_twopeer_get_put.c b/src/dht/test_dht_twopeer_get_put.c new file mode 100644 index 0000000..0bb9fac --- /dev/null +++ b/src/dht/test_dht_twopeer_get_put.c @@ -0,0 +1,605 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dht/test_dht_twopeer_get_put.c + * @brief base testcase for testing DHT service with + * two running peers. + * + * This testcase starts peers using the GNUNET_TESTING_daemons_start + * function call. On peer start, connects to the peers DHT service + * by calling GNUNET_DHT_connected. Once notified about all peers + * being started (by the peers_started_callback function), calls + * GNUNET_TESTING_connect_topology, which connects the peers in a + * "straight line" topology. On notification that all peers have + * been properly connected, calls the do_get function which initiates + * a GNUNET_DHT_get from the *second* peer. Once the GNUNET_DHT_get + * function starts, runs the do_put function to insert data at the first peer. + * If the GET is successful, schedules finish_testing + * to stop the test and shut down peers. If GET is unsuccessful + * after GET_TIMEOUT seconds, prints an error message and shuts down + * the peers. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_dht_service.h" +#include "block_dns.h" +#include "gnunet_signatures.h" + +/* DEFINES */ +#define VERBOSE GNUNET_NO + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 40) + +/* Timeout for waiting for replies to get requests */ +#define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +#define DNS GNUNET_NO + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +/** + * Variable used to store the number of connections we should wait for. + */ +static unsigned int expected_connections; + +/** + * Variable used to keep track of how many peers aren't yet started. + */ +static unsigned long long peers_left; + +/** + * Handle to the set of all peers run for this test. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Global handle we will use for GET requests. + */ +struct GNUNET_DHT_GetHandle *global_get_handle; + + +/** + * Total number of peers to run, set based on config file. + */ +static unsigned long long num_peers; + +/** + * Global used to count how many connections we have currently + * been notified about (how many times has topology_callback been called + * with success?) + */ +static unsigned int total_connections; + +/** + * Global used to count how many failed connections we have + * been notified about (how many times has topology_callback + * been called with failure?) + */ +static unsigned int failed_connections; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +#if DNS +struct GNUNET_DNS_Record data; +#endif + +/** + * Peer identity of the first peer started. + */ +static struct GNUNET_PeerIdentity peer1id; + +/** + * Peer identity of the second peer started. + */ +static struct GNUNET_PeerIdentity peer2id; + +/** + * Handle to the first peers DHT service (via the API) + */ +static struct GNUNET_DHT_Handle *peer1dht; + +/** + * Handle to the second peers DHT service (via the API) + */ +static struct GNUNET_DHT_Handle *peer2dht; + +static void +do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + if (ok == 0) + ok = 2; + } +} + +/** + * Function scheduled to be run on the successful completion of this + * testcase. Specifically, called when our get request completes. + */ +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (pg != NULL); + GNUNET_assert (peer1dht != NULL); + GNUNET_assert (peer2dht != NULL); + GNUNET_DHT_disconnect (peer1dht); + GNUNET_DHT_disconnect (peer2dht); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 0; +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (peer1dht != NULL) + GNUNET_DHT_disconnect (peer1dht); + + if (peer2dht != NULL) + GNUNET_DHT_disconnect (peer2dht); + + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failing test with error: `%s'!\n", + (char *) cls); + if (global_get_handle != NULL) + { + GNUNET_DHT_get_stop (global_get_handle); + global_get_handle = NULL; + } + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +/** + * Iterator called if the GET request initiated returns a response. + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +void +get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_size, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_size, enum GNUNET_BLOCK_Type type, + size_t size, const void *result_data) +{ + GNUNET_HashCode original_key; /* Key data was stored data under */ + char original_data[4]; /* Made up data that was stored */ + + memset (&original_key, 42, sizeof (GNUNET_HashCode)); /* Set the key to what it was set to previously */ + memset (original_data, 43, sizeof (original_data)); + +#if DNS + if ((sizeof (original_data) != size) || + (0 != memcmp (&data.service_descriptor, key, sizeof (GNUNET_HashCode))) || + (0 != memcmp ((char *) &data, result_data, sizeof (original_data)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Key or data is not the same as was inserted!\n"); + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_badly, + "key or data mismatch in get response!\n"); + return; + } +#else + if ((sizeof (original_data) != size) || + (0 != memcmp (&original_key, key, sizeof (GNUNET_HashCode))) || + (0 != memcmp (original_data, result_data, sizeof (original_data)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Key or data is not the same as was inserted!\n"); + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_badly, + "key or data mismatch in get response!\n"); + return; + } +#endif + + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_DHT_get_stop (global_get_handle); + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); +} + +/** + * Start the GET request for the same key/data that was inserted. + */ +static void +do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_HashCode key; /* Key for data lookup */ + +#if DNS + memcpy (&key, &data.service_descriptor, sizeof (GNUNET_HashCode)); +#else + memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to the same thing as when data was inserted */ +#endif + global_get_handle = + GNUNET_DHT_get_start (peer2dht, GNUNET_TIME_relative_get_forever (), +#if DNS + GNUNET_BLOCK_TYPE_DNS, +#else + GNUNET_BLOCK_TYPE_TEST, +#endif + &key, 1, GNUNET_DHT_RO_NONE, NULL, 0, + &get_result_iterator, NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 10), &do_put, NULL); +} + +/** + * Called when the PUT request has been transmitted to the DHT service. + * Schedule the GET request for some time in the future. + */ +static void +put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &end_badly, + "waiting for get response (data not found)"); +} + + +#if !DNS +/** + * Set up some data, and call API PUT function + */ +static void +do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_HashCode key; /* Made up key to store data under */ + char data[4]; /* Made up data to store */ + + memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to something simple so we can issue GET request */ + memset (data, 43, sizeof (data)); + + /* Insert the data at the first peer */ + GNUNET_DHT_put (peer1dht, &key, 1, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_TEST, + sizeof (data), data, GNUNET_TIME_UNIT_FOREVER_ABS, + GNUNET_TIME_UNIT_FOREVER_REL, &put_finished, NULL); +} +#else + +/** + * Set up some data, and call API PUT function + */ +static void +do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *name = "philipptoelke.gnunet."; + size_t size = sizeof (struct GNUNET_DNS_Record); + + memset (&data, 0, size); + + data.purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature)); + data.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_DNS_RECORD; + + GNUNET_CRYPTO_hash (name, strlen (name) + 1, &data.service_descriptor); + + data.service_type = htonl (GNUNET_DNS_SERVICE_TYPE_UDP); + data.ports = htons (69); + + char *keyfile; + + GNUNET_asprintf (&keyfile, "/tmp/test_dns_data_key"); + struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key = + GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_free (keyfile); + GNUNET_assert (my_private_key != NULL); + + GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &data.peer); + + data.expiration_time = + GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS); + + /* Sign the block */ + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_sign (my_private_key, &data.purpose, &data.signature)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not sign DNS_Record\n"); + return; + } + GNUNET_CRYPTO_rsa_key_free (my_private_key); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting with key %08x\n", + *((unsigned int *) &data.service_descriptor)); + + GNUNET_DHT_put (peer1dht, &data.service_descriptor, DEFAULT_PUT_REPLICATION, + GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_DNS, size, + (char *) &data, + GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), + GNUNET_TIME_UNIT_MINUTES, &put_finished, NULL); +} +#endif + +/** + * This function is called whenever a connection attempt is finished between two of + * the started peers (started with GNUNET_TESTING_daemons_start). The total + * number of times this function is called should equal the number returned + * from the GNUNET_TESTING_connect_topology call. + * + * The emsg variable is NULL on success (peers connected), and non-NULL on + * failure (peers failed to connect). + */ +void +topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connected peer %s to peer %s, distance %u\n", + first_daemon->shortname, second_daemon->shortname, distance); +#endif + } +#if VERBOSE + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + } +#endif + + if (total_connections == expected_connections) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number! Starting next phase of testing.\n", + total_connections); +#endif + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from test gets"); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 2), &do_get, NULL); + } + else if (total_connections + failed_connections == expected_connections) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many failed connections)"); + } +} + + +/** + * Callback which is called whenever a peer is started (as a result of the + * GNUNET_TESTING_daemons_start call. + * + * @param cls closure argument given to GNUNET_TESTING_daemons_start + * @param id the GNUNET_PeerIdentity of the started peer + * @param cfg the configuration for this specific peer (needed to connect + * to the DHT) + * @param d the handle to the daemon started + * @param emsg NULL if peer started, non-NULL on error + */ +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); + + /* This is the first peer started */ + if (peers_left == num_peers) + { + memcpy (&peer1id, id, sizeof (struct GNUNET_PeerIdentity)); /* Save the peer id */ + peer1dht = GNUNET_DHT_connect (cfg, 100); /* Connect to the first peers DHT service */ + if (peer1dht == NULL) /* If DHT connect failed */ + { + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); + } + } + else /* This is the second peer started */ + { + memcpy (&peer2id, id, sizeof (struct GNUNET_PeerIdentity)); /* Same as for first peer... */ + peer2dht = GNUNET_DHT_connect (cfg, 100); + if (peer2dht == NULL) + { + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); + } + } + + /* Decrement number of peers left to start */ + peers_left--; + + if (peers_left == 0) /* Indicates all peers started */ + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now connecting peers!\n", num_peers); +#endif + expected_connections = -1; + if ((pg != NULL)) /* Sanity check */ + { + /* Connect peers in a "straight line" topology, return the number of expected connections */ + expected_connections = + GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, + GNUNET_TESTING_TOPOLOGY_OPTION_ALL, + 0.0, TIMEOUT, 12, NULL, NULL); + } + + /* Cancel current timeout fail task */ + GNUNET_SCHEDULER_cancel (die_task); + if (expected_connections == GNUNET_SYSERR) /* Some error happened */ + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from connect topology (bad return)"); + + /* Schedule timeout on failure task */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "from connect topology (timeout)"); + ok = 0; + } +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + /* Get number of peers to start from configuration (should be two) */ + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + /* Set peers_left so we know when all peers started */ + peers_left = num_peers; + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start num_peers peers, call peers_started_callback on peer start, topology_callback on peer connect */ + /* Read the API documentation for other parameters! */ + pg = GNUNET_TESTING_daemons_start (cfg, num_peers, 2, 2, TIMEOUT, NULL, NULL, + &peers_started_callback, NULL, + &topology_callback, NULL, NULL); + +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-dht-twopeer-get-put", /* Name to give running binary */ + "-c", + "test_dht_twopeer_data.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-dht-twopeer-get-put", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-dht-twopeer': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-dht-twopeer", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + return ret; +} + +/* end of test_dht_twopeer_get_put.c */ diff --git a/src/dht/test_dht_twopeer_path_tracking.c b/src/dht/test_dht_twopeer_path_tracking.c new file mode 100644 index 0000000..6e764a3 --- /dev/null +++ b/src/dht/test_dht_twopeer_path_tracking.c @@ -0,0 +1,522 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dht/test_dht_twopeer_path_tracking.c + * @brief testcase for testing DHT service with + * two running peers, logging the path of the dht requests. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_dht_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_NO + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) + +/* Timeout for waiting for replies to get requests */ +#define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +/** + * Variable used to store the number of connections we should wait for. + */ +static unsigned int expected_connections; + +/** + * Variable used to keep track of how many peers aren't yet started. + */ +static unsigned long long peers_left; + +/** + * Handle to the set of all peers run for this test. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Global handle we will use for GET requests. + */ +struct GNUNET_DHT_GetHandle *global_get_handle; + + +/** + * Total number of peers to run, set based on config file. + */ +static unsigned long long num_peers; + +/** + * Global used to count how many connections we have currently + * been notified about (how many times has topology_callback been called + * with success?) + */ +static unsigned int total_connections; + +/** + * Global used to count how many failed connections we have + * been notified about (how many times has topology_callback + * been called with failure?) + */ +static unsigned int failed_connections; + +/** + * Task handle to use to schedule test failure + */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +/** + * Global return value (0 for success, anything else for failure) + */ +static int ok; + +/** + * Peer identity of the first peer started. + */ +static struct GNUNET_PeerIdentity peer1id; + +/** + * Peer identity of the second peer started. + */ +static struct GNUNET_PeerIdentity peer2id; + +/** + * Handle to the first peers DHT service (via the API) + */ +static struct GNUNET_DHT_Handle *peer1dht; + +/** + * Handle to the second peers DHT service (via the API) + */ +static struct GNUNET_DHT_Handle *peer2dht; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + if (ok == 0) + ok = 2; + } +} + +/** + * Function scheduled to be run on the successful completion of this + * testcase. Specifically, called when our get request completes. + */ +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (pg != NULL); + GNUNET_assert (peer1dht != NULL); + GNUNET_assert (peer2dht != NULL); + GNUNET_DHT_disconnect (peer1dht); + GNUNET_DHT_disconnect (peer2dht); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 0; +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (peer1dht != NULL) + GNUNET_DHT_disconnect (peer1dht); + + if (peer2dht != NULL) + GNUNET_DHT_disconnect (peer2dht); + + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failing test with error: `%s'!\n", + (char *) cls); + if (global_get_handle != NULL) + { + GNUNET_DHT_get_stop (global_get_handle); + global_get_handle = NULL; + } + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +/** + * Iterator called if the GET request initiated returns a response. + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +static void +get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + GNUNET_HashCode original_key; /* Key data was stored data under */ + char original_data[4]; /* Made up data that was stored */ + + memset (&original_key, 42, sizeof (GNUNET_HashCode)); /* Set the key to what it was set to previously */ + memset (original_data, 43, sizeof (original_data)); +#if VERBOSE + unsigned int i; +#endif + + if ((0 != memcmp (&original_key, key, sizeof (GNUNET_HashCode))) || + (0 != memcmp (original_data, data, sizeof (original_data)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Key or data is not the same as was inserted!\n"); + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_badly, + "key or data mismatch in get response!\n"); + return; + } + +#if VERBOSE + if (put_path != NULL) + { + FPRINTF (stderr, "%s", "PUT Path: "); + for (i = 0; i < put_path_length; i++) + FPRINTF (stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s (&put_path[i])); + FPRINTF (stderr, "%s", "\n"); + } + if (get_path != NULL) + { + FPRINTF (stderr, "%s", "GET Path: "); + for (i = 0; i < get_path_length; i++) + FPRINTF (stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s (&get_path[i])); + FPRINTF (stderr, "%s", "\n"); + } +#endif + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct GET response!\n"); + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_DHT_get_stop (global_get_handle); + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); +} + + +/** + * Called when the PUT request has been transmitted to the DHT service. + * Schedule the GET request for some time in the future. + */ +static void +put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_HashCode key; /* Key for data lookup */ + + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &end_badly, + "waiting for get response (data not found)"); + memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to the same thing as when data was inserted */ + global_get_handle = + GNUNET_DHT_get_start (peer2dht, GNUNET_TIME_relative_get_forever (), + GNUNET_BLOCK_TYPE_TEST, &key, 1, + GNUNET_DHT_RO_RECORD_ROUTE, NULL, 0, + &get_result_iterator, NULL); +} + +/** + * Set up some data, and call API PUT function + */ +static void +do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_HashCode key; /* Made up key to store data under */ + char data[4]; /* Made up data to store */ + + memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to something simple so we can issue GET request */ + memset (data, 43, sizeof (data)); + + /* Insert the data at the first peer */ + GNUNET_DHT_put (peer1dht, &key, 1, GNUNET_DHT_RO_RECORD_ROUTE, + GNUNET_BLOCK_TYPE_TEST, sizeof (data), data, + GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_REL, + &put_finished, NULL); +} + +/** + * This function is called whenever a connection attempt is finished between two of + * the started peers (started with GNUNET_TESTING_daemons_start). The total + * number of times this function is called should equal the number returned + * from the GNUNET_TESTING_connect_topology call. + * + * The emsg variable is NULL on success (peers connected), and non-NULL on + * failure (peers failed to connect). + */ +static void +topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connected peer %s to peer %s, distance %u\n", + first_daemon->shortname, second_daemon->shortname, distance); +#endif + } +#if VERBOSE + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + } +#endif + + if (total_connections == expected_connections) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number! Starting next phase of testing.\n", + total_connections); +#endif + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from test gets"); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 2), &do_put, NULL); + } + else if (total_connections + failed_connections == expected_connections) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many failed connections)"); + } +} + + +/** + * Callback which is called whenever a peer is started (as a result of the + * GNUNET_TESTING_daemons_start call. + * + * @param cls closure argument given to GNUNET_TESTING_daemons_start + * @param id the GNUNET_PeerIdentity of the started peer + * @param cfg the configuration for this specific peer (needed to connect + * to the DHT) + * @param d the handle to the daemon started + * @param emsg NULL if peer started, non-NULL on error + */ +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); + + /* This is the first peer started */ + if (peers_left == num_peers) + { + memcpy (&peer1id, id, sizeof (struct GNUNET_PeerIdentity)); /* Save the peer id */ + peer1dht = GNUNET_DHT_connect (cfg, 100); /* Connect to the first peers DHT service */ + if (peer1dht == NULL) /* If DHT connect failed */ + { + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); + } + } + else /* This is the second peer started */ + { + memcpy (&peer2id, id, sizeof (struct GNUNET_PeerIdentity)); /* Same as for first peer... */ + peer2dht = GNUNET_DHT_connect (cfg, 100); + if (peer2dht == NULL) + { + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); + } + } + + /* Decrement number of peers left to start */ + peers_left--; + + if (peers_left == 0) /* Indicates all peers started */ + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now connecting peers!\n", num_peers); +#endif + expected_connections = -1; + if ((pg != NULL)) /* Sanity check */ + { + /* Connect peers in a "straight line" topology, return the number of expected connections */ + expected_connections = + GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, + GNUNET_TESTING_TOPOLOGY_OPTION_ALL, + 0.0, TIMEOUT, 2, NULL, NULL); + } + + /* Cancel current timeout fail task */ + GNUNET_SCHEDULER_cancel (die_task); + if (expected_connections == GNUNET_SYSERR) /* Some error happened */ + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from connect topology (bad return)"); + + /* Schedule timeout on failure task */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "from connect topology (timeout)"); + ok = 0; + } +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + /* Get number of peers to start from configuration (should be two) */ + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + /* Set peers_left so we know when all peers started */ + peers_left = num_peers; + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start num_peers peers, call peers_started_callback on peer start, topology_callback on peer connect */ + /* Read the API documentation for other parameters! */ + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ + peers_left, /* Number of outstanding connections */ + peers_left, /* Number of parallel ssh connections, or peers being started at once */ + TIMEOUT, NULL, NULL, + &peers_started_callback, NULL, + &topology_callback, NULL, NULL); + +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-dht-twopeer-put-get", /* Name to give running binary */ + "-c", + "test_dht_twopeer_data.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-dht-twopeer-put-get", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-dht-twopeer': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-dht-twopeer", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + return ret; +} + +/* end of test_dht_twopeer_put_get.c */ diff --git a/src/dht/test_dht_twopeer_put_get.c b/src/dht/test_dht_twopeer_put_get.c new file mode 100644 index 0000000..48bf9f8 --- /dev/null +++ b/src/dht/test_dht_twopeer_put_get.c @@ -0,0 +1,512 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dht/test_dht_twopeer_put_get.c + * @brief base testcase for testing DHT service with + * two running peers. + * + * This testcase starts peers using the GNUNET_TESTING_daemons_start + * function call. On peer start, connects to the peers DHT service + * by calling GNUNET_DHT_connected. Once notified about all peers + * being started (by the peers_started_callback function), calls + * GNUNET_TESTING_connect_topology, which connects the peers in a + * "straight line" topology. On notification that all peers have + * been properly connected, runs the do_put function to insert data + * at the first peer. Once the GNUNET_DHT_put function completes, + * calls the do_get function which initiates a GNUNET_DHT_get from + * the *second* peer. If the GET is successful, schedules finish_testing + * to stop the test and shut down peers. If GET is unsuccessful + * after GET_TIMEOUT seconds, prints an error message and shuts down + * the peers. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_dht_service.h" +#include "block_dns.h" +#include "gnunet_signatures.h" + +/* DEFINES */ +#define VERBOSE GNUNET_NO + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) + +/* Timeout for waiting for replies to get requests */ +#define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +/** + * Variable used to store the number of connections we should wait for. + */ +static unsigned int expected_connections; + +/** + * Variable used to keep track of how many peers aren't yet started. + */ +static unsigned long long peers_left; + +/** + * Handle to the set of all peers run for this test. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Global handle we will use for GET requests. + */ +struct GNUNET_DHT_GetHandle *global_get_handle; + + +/** + * Total number of peers to run, set based on config file. + */ +static unsigned long long num_peers; + +/** + * Global used to count how many connections we have currently + * been notified about (how many times has topology_callback been called + * with success?) + */ +static unsigned int total_connections; + +/** + * Global used to count how many failed connections we have + * been notified about (how many times has topology_callback + * been called with failure?) + */ +static unsigned int failed_connections; + +/* Task handle to use to schedule test failure */ +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +/** + * Peer identity of the first peer started. + */ +static struct GNUNET_PeerIdentity peer1id; + +/** + * Peer identity of the second peer started. + */ +static struct GNUNET_PeerIdentity peer2id; + +/** + * Handle to the first peers DHT service (via the API) + */ +static struct GNUNET_DHT_Handle *peer1dht; + +/** + * Handle to the second peers DHT service (via the API) + */ +static struct GNUNET_DHT_Handle *peer2dht; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + if (ok == 0) + ok = 2; + } +} + +/** + * Function scheduled to be run on the successful completion of this + * testcase. Specifically, called when our get request completes. + */ +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (pg != NULL); + GNUNET_assert (peer1dht != NULL); + GNUNET_assert (peer2dht != NULL); + GNUNET_DHT_disconnect (peer1dht); + GNUNET_DHT_disconnect (peer2dht); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 0; +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (peer1dht != NULL) + GNUNET_DHT_disconnect (peer1dht); + + if (peer2dht != NULL) + GNUNET_DHT_disconnect (peer2dht); + + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failing test with error: `%s'!\n", + (char *) cls); + if (global_get_handle != NULL) + { + GNUNET_DHT_get_stop (global_get_handle); + global_get_handle = NULL; + } + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +/** + * Iterator called if the GET request initiated returns a response. + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +static void +get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_size, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_size, enum GNUNET_BLOCK_Type type, + size_t size, const void *result_data) +{ + GNUNET_HashCode original_key; /* Key data was stored data under */ + char original_data[4]; /* Made up data that was stored */ + + memset (&original_key, 42, sizeof (GNUNET_HashCode)); /* Set the key to what it was set to previously */ + memset (original_data, 43, sizeof (original_data)); + + if ((sizeof (original_data) != size) || + (0 != memcmp (&original_key, key, sizeof (GNUNET_HashCode))) || + (0 != memcmp (original_data, result_data, sizeof (original_data)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Key or data is not the same as was inserted!\n"); + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_badly, + "key or data mismatch in get response!\n"); + return; + } + + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_DHT_get_stop (global_get_handle); + global_get_handle = NULL; + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); +} + + +/** + * Called when the PUT request has been transmitted to the DHT service. + * Schedule the GET request for some time in the future. + */ +static void +put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_HashCode key; /* Key for data lookup */ + + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &end_badly, + "waiting for get response (data not found)"); + + memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to the same thing as when data was inserted */ + global_get_handle = + GNUNET_DHT_get_start (peer2dht, GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_BLOCK_TYPE_TEST, &key, 1, GNUNET_DHT_RO_NONE, + NULL, 0, &get_result_iterator, NULL); +} + + +/** + * Set up some data, and call API PUT function + */ +static void +do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_HashCode key; /* Made up key to store data under */ + char data[4]; /* Made up data to store */ + + memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to something simple so we can issue GET request */ + memset (data, 43, sizeof (data)); + + /* Insert the data at the first peer */ + GNUNET_DHT_put (peer1dht, &key, 1, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_TEST, + sizeof (data), data, GNUNET_TIME_UNIT_FOREVER_ABS, + GNUNET_TIME_UNIT_FOREVER_REL, &put_finished, NULL); +} + + +/** + * This function is called whenever a connection attempt is finished between two of + * the started peers (started with GNUNET_TESTING_daemons_start). The total + * number of times this function is called should equal the number returned + * from the GNUNET_TESTING_connect_topology call. + * + * The emsg variable is NULL on success (peers connected), and non-NULL on + * failure (peers failed to connect). + */ +static void +topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connected peer %s to peer %s, distance %u\n", + first_daemon->shortname, second_daemon->shortname, distance); +#endif + } +#if VERBOSE + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + } +#endif + + if (total_connections == expected_connections) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number! Starting next phase of testing.\n", + total_connections); +#endif + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from test gets"); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_put, NULL); + } + else if (total_connections + failed_connections == expected_connections) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many failed connections)"); + } +} + + +/** + * Callback which is called whenever a peer is started (as a result of the + * GNUNET_TESTING_daemons_start call. + * + * @param cls closure argument given to GNUNET_TESTING_daemons_start + * @param id the GNUNET_PeerIdentity of the started peer + * @param cfg the configuration for this specific peer (needed to connect + * to the DHT) + * @param d the handle to the daemon started + * @param emsg NULL if peer started, non-NULL on error + */ +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); + + /* This is the first peer started */ + if (peers_left == num_peers) + { + memcpy (&peer1id, id, sizeof (struct GNUNET_PeerIdentity)); /* Save the peer id */ + peer1dht = GNUNET_DHT_connect (cfg, 100); /* Connect to the first peers DHT service */ + if (peer1dht == NULL) /* If DHT connect failed */ + { + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); + } + } + else /* This is the second peer started */ + { + memcpy (&peer2id, id, sizeof (struct GNUNET_PeerIdentity)); /* Same as for first peer... */ + peer2dht = GNUNET_DHT_connect (cfg, 100); + if (peer2dht == NULL) + { + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); + } + } + + /* Decrement number of peers left to start */ + peers_left--; + + if (peers_left == 0) /* Indicates all peers started */ + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now connecting peers!\n", num_peers); +#endif + expected_connections = -1; + if ((pg != NULL)) /* Sanity check */ + { + /* Connect peers in a "straight line" topology, return the number of expected connections */ + expected_connections = + GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, + GNUNET_TESTING_TOPOLOGY_OPTION_ALL, + 0.0, TIMEOUT, 12, NULL, NULL); + } + + /* Cancel current timeout fail task */ + GNUNET_SCHEDULER_cancel (die_task); + if (expected_connections == GNUNET_SYSERR) /* Some error happened */ + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from connect topology (bad return)"); + + /* Schedule timeout on failure task */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "from connect topology (timeout)"); + ok = 0; + } +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + /* Get number of peers to start from configuration (should be two) */ + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + /* Set peers_left so we know when all peers started */ + peers_left = num_peers; + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start num_peers peers, call peers_started_callback on peer start, topology_callback on peer connect */ + /* Read the API documentation for other parameters! */ + pg = GNUNET_TESTING_daemons_start (cfg, num_peers, 2, 2, TIMEOUT, NULL, NULL, + &peers_started_callback, NULL, + &topology_callback, NULL, NULL); + +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-dht-twopeer-put-get", /* Name to give running binary */ + "-c", + "test_dht_twopeer_data.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-dht-twopeer-put-get", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-dht-twopeer': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-dht-twopeer", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + return ret; +} + +/* end of test_dht_twopeer_put_get.c */ diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am new file mode 100644 index 0000000..5bc8709 --- /dev/null +++ b/src/dns/Makefile.am @@ -0,0 +1,111 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +plugindir = $(libdir)/gnunet + +pkgcfg_DATA = \ + dns.conf + +if LINUX +HIJACKBIN = gnunet-helper-dns +install-exec-hook: + $(SUDO_BINARY) chown root $(bindir)/gnunet-helper-dns || true + $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-helper-dns || true + $(SUDO_BINARY) chmod 4750 $(bindir)/gnunet-helper-dns || true + $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-service-dns || true + $(SUDO_BINARY) chmod 2750 $(bindir)/gnunet-service-dns || true +else +install-exec-hook: +endif + +lib_LTLIBRARIES = \ + libgnunetdnsparser.la \ + libgnunetdns.la + +bin_PROGRAMS = \ + gnunet-service-dns $(HIJACKBIN) + +noinst_PROGRAMS = \ + gnunet-dns-monitor gnunet-dns-redirector + +plugin_LTLIBRARIES = \ + libgnunet_plugin_block_dns.la + +check_SCRIPTS = \ + test_gnunet_dns.sh + + +gnunet_helper_dns_SOURCES = \ + gnunet-helper-dns.c + + +gnunet_dns_monitor_SOURCES = \ + gnunet-dns-monitor.c +gnunet_dns_monitor_LDADD = \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_dns_monitor_DEPENDENCIES = \ + libgnunetdnsparser.la \ + libgnunetdns.la + +gnunet_dns_redirector_SOURCES = \ + gnunet-dns-redirector.c +gnunet_dns_redirector_LDADD = \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_dns_redirector_DEPENDENCIES = \ + libgnunetdnsparser.la \ + libgnunetdns.la + +gnunet_service_dns_SOURCES = \ + gnunet-service-dns.c +gnunet_service_dns_LDADD = \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +libgnunetdnsparser_la_SOURCES = \ + dnsparser.c +libgnunetdnsparser_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +libgnunetdnsparser_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +libgnunetdns_la_SOURCES = \ + dns_api.c dns.h +libgnunetdns_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +libgnunetdns_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +libgnunet_plugin_block_dns_la_SOURCES = \ + plugin_block_dns.c +libgnunet_plugin_block_dns_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_block_dns_la_LDFLAGS = \ + $(top_builddir)/src/block/$(GN_PLUGIN_LDFLAGS) + + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +endif + +EXTRA_DIST = \ + $(check_SCRIPTS) diff --git a/src/dns/Makefile.in b/src/dns/Makefile.in new file mode 100644 index 0000000..ee45c56 --- /dev/null +++ b/src/dns/Makefile.in @@ -0,0 +1,1017 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-dns$(EXEEXT) $(am__EXEEXT_1) +noinst_PROGRAMS = gnunet-dns-monitor$(EXEEXT) \ + gnunet-dns-redirector$(EXEEXT) +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_SCRIPTS) +subdir = src/dns +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/dns.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = dns.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) +libgnunet_plugin_block_dns_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunet_plugin_block_dns_la_OBJECTS = plugin_block_dns.lo +libgnunet_plugin_block_dns_la_OBJECTS = \ + $(am_libgnunet_plugin_block_dns_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_block_dns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_block_dns_la_LDFLAGS) $(LDFLAGS) -o $@ +libgnunetdns_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunetdns_la_OBJECTS = dns_api.lo +libgnunetdns_la_OBJECTS = $(am_libgnunetdns_la_OBJECTS) +libgnunetdns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetdns_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +libgnunetdnsparser_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunetdnsparser_la_OBJECTS = dnsparser.lo +libgnunetdnsparser_la_OBJECTS = $(am_libgnunetdnsparser_la_OBJECTS) +libgnunetdnsparser_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetdnsparser_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-dns$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am_gnunet_dns_monitor_OBJECTS = gnunet-dns-monitor.$(OBJEXT) +gnunet_dns_monitor_OBJECTS = $(am_gnunet_dns_monitor_OBJECTS) +am__DEPENDENCIES_1 = +am_gnunet_dns_redirector_OBJECTS = gnunet-dns-redirector.$(OBJEXT) +gnunet_dns_redirector_OBJECTS = $(am_gnunet_dns_redirector_OBJECTS) +am_gnunet_helper_dns_OBJECTS = gnunet-helper-dns.$(OBJEXT) +gnunet_helper_dns_OBJECTS = $(am_gnunet_helper_dns_OBJECTS) +gnunet_helper_dns_LDADD = $(LDADD) +am_gnunet_service_dns_OBJECTS = gnunet-service-dns.$(OBJEXT) +gnunet_service_dns_OBJECTS = $(am_gnunet_service_dns_OBJECTS) +gnunet_service_dns_DEPENDENCIES = \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunet_plugin_block_dns_la_SOURCES) \ + $(libgnunetdns_la_SOURCES) $(libgnunetdnsparser_la_SOURCES) \ + $(gnunet_dns_monitor_SOURCES) $(gnunet_dns_redirector_SOURCES) \ + $(gnunet_helper_dns_SOURCES) $(gnunet_service_dns_SOURCES) +DIST_SOURCES = $(libgnunet_plugin_block_dns_la_SOURCES) \ + $(libgnunetdns_la_SOURCES) $(libgnunetdnsparser_la_SOURCES) \ + $(gnunet_dns_monitor_SOURCES) $(gnunet_dns_redirector_SOURCES) \ + $(gnunet_helper_dns_SOURCES) $(gnunet_service_dns_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +pkgcfgdir = $(pkgdatadir)/config.d/ +plugindir = $(libdir)/gnunet +pkgcfg_DATA = \ + dns.conf + +@LINUX_TRUE@HIJACKBIN = gnunet-helper-dns +lib_LTLIBRARIES = \ + libgnunetdnsparser.la \ + libgnunetdns.la + +plugin_LTLIBRARIES = \ + libgnunet_plugin_block_dns.la + +check_SCRIPTS = \ + test_gnunet_dns.sh + +gnunet_helper_dns_SOURCES = \ + gnunet-helper-dns.c + +gnunet_dns_monitor_SOURCES = \ + gnunet-dns-monitor.c + +gnunet_dns_monitor_LDADD = \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_dns_monitor_DEPENDENCIES = \ + libgnunetdnsparser.la \ + libgnunetdns.la + +gnunet_dns_redirector_SOURCES = \ + gnunet-dns-redirector.c + +gnunet_dns_redirector_LDADD = \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_dns_redirector_DEPENDENCIES = \ + libgnunetdnsparser.la \ + libgnunetdns.la + +gnunet_service_dns_SOURCES = \ + gnunet-service-dns.c + +gnunet_service_dns_LDADD = \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +libgnunetdnsparser_la_SOURCES = \ + dnsparser.c + +libgnunetdnsparser_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) + +libgnunetdnsparser_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +libgnunetdns_la_SOURCES = \ + dns_api.c dns.h + +libgnunetdns_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) + +libgnunetdns_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +libgnunet_plugin_block_dns_la_SOURCES = \ + plugin_block_dns.c + +libgnunet_plugin_block_dns_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_block_dns_la_LDFLAGS = \ + $(top_builddir)/src/block/$(GN_PLUGIN_LDFLAGS) + +EXTRA_DIST = \ + $(check_SCRIPTS) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/dns/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/dns/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +dns.conf: $(top_builddir)/config.status $(srcdir)/dns.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_block_dns.la: $(libgnunet_plugin_block_dns_la_OBJECTS) $(libgnunet_plugin_block_dns_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_block_dns_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_dns_la_OBJECTS) $(libgnunet_plugin_block_dns_la_LIBADD) $(LIBS) +libgnunetdns.la: $(libgnunetdns_la_OBJECTS) $(libgnunetdns_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetdns_la_LINK) -rpath $(libdir) $(libgnunetdns_la_OBJECTS) $(libgnunetdns_la_LIBADD) $(LIBS) +libgnunetdnsparser.la: $(libgnunetdnsparser_la_OBJECTS) $(libgnunetdnsparser_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetdnsparser_la_LINK) -rpath $(libdir) $(libgnunetdnsparser_la_OBJECTS) $(libgnunetdnsparser_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-dns-monitor$(EXEEXT): $(gnunet_dns_monitor_OBJECTS) $(gnunet_dns_monitor_DEPENDENCIES) + @rm -f gnunet-dns-monitor$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_dns_monitor_OBJECTS) $(gnunet_dns_monitor_LDADD) $(LIBS) +gnunet-dns-redirector$(EXEEXT): $(gnunet_dns_redirector_OBJECTS) $(gnunet_dns_redirector_DEPENDENCIES) + @rm -f gnunet-dns-redirector$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_dns_redirector_OBJECTS) $(gnunet_dns_redirector_LDADD) $(LIBS) +gnunet-helper-dns$(EXEEXT): $(gnunet_helper_dns_OBJECTS) $(gnunet_helper_dns_DEPENDENCIES) + @rm -f gnunet-helper-dns$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_helper_dns_OBJECTS) $(gnunet_helper_dns_LDADD) $(LIBS) +gnunet-service-dns$(EXEEXT): $(gnunet_service_dns_OBJECTS) $(gnunet_service_dns_DEPENDENCIES) + @rm -f gnunet-service-dns$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_dns_OBJECTS) $(gnunet_service_dns_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsparser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-dns-monitor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-dns-redirector.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-dns.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dns.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_dns.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-noinstPROGRAMS clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-noinstPROGRAMS clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-exec-hook install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-pkgcfgDATA install-pluginLTLIBRARIES install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + +@LINUX_TRUE@install-exec-hook: +@LINUX_TRUE@ $(SUDO_BINARY) chown root $(bindir)/gnunet-helper-dns || true +@LINUX_TRUE@ $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-helper-dns || true +@LINUX_TRUE@ $(SUDO_BINARY) chmod 4750 $(bindir)/gnunet-helper-dns || true +@LINUX_TRUE@ $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-service-dns || true +@LINUX_TRUE@ $(SUDO_BINARY) chmod 2750 $(bindir)/gnunet-service-dns || true +@LINUX_FALSE@install-exec-hook: + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/dns/dns.conf.in b/src/dns/dns.conf.in new file mode 100644 index 0000000..d2c6795 --- /dev/null +++ b/src/dns/dns.conf.in @@ -0,0 +1,44 @@ +[dns] +AUTOSTART = YES +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dns +UNIXPATH = /tmp/gnunet-service-dns.sock + +# Access to this service can compromise all DNS queries in this +# system. Thus access should be restricted to the same UID. +# (see https://gnunet.org/gnunet-access-control-model) +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +# As there is no sufficiently restrictive access control for TCP, +# we never use it, even if @UNIXONLY@ is not set (just to be safe) +@UNIXONLY@ PORT = 0 + +# This option should be set to YES to allow the DNS service to +# perform lookups against the locally configured DNS resolver. +# (set to "NO" if no normal ISP is locally available and thus +# requests for normal ".com"/".org"/etc. must be routed via +# the GNUnet VPN (the GNUNET PT daemon then needs to be configured +# to intercept and route DNS queries via mesh). +PROVIDE_EXIT = YES + +# Name of the virtual interface we use to intercept DNS traffic. +IFNAME = gnunet-dns + +# Use RFC 3849-style documentation IPv6 address (RFC 4773 might provide an alternative in the future) +# FIXME: or just default to a site-local address scope as we do for VPN!? +IPV6ADDR = 2001:DB8::1 +IPV6PREFIX = 126 + +# Use RFC 3927-style link-local address +IPV4ADDR = 169.254.1.1 +IPV4MASK = 255.255.0.0 + +# Enable GNUnet-wide DNS-EXIT service by setting this value to the IP address (IPv4 or IPv6) +# of a DNS resolver to use. Only works if "PROVIDE_EXIT" is also set to YES. Must absolutely +# NOT be an address of any of GNUnet's virtual tunnel interfaces. Use a well-known +# public DNS resolver or your ISP's resolver from /etc/resolv.conf. +# DNS_EXIT = 8.8.8.8 + diff --git a/src/dns/dns.h b/src/dns/dns.h new file mode 100644 index 0000000..2b0ad03 --- /dev/null +++ b/src/dns/dns.h @@ -0,0 +1,101 @@ +/* + This file is part of GNUnet + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file dns/dns.h + * @brief IPC messages between DNS API and DNS service + * @author Christian Grothoff + */ +#ifndef DNS_NEW_H +#define DNS_NEW_H + +GNUNET_NETWORK_STRUCT_BEGIN + + +/** + * Message from client to DNS service to register itself. + */ +struct GNUNET_DNS_Register +{ + /** + * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT + */ + struct GNUNET_MessageHeader header; + + /** + * NBO encoding of 'enum GNUNET_DNS_Flags' for the client. + */ + uint32_t flags; +}; + + +/** + * Message from DNS service to client: please handle a request. + */ +struct GNUNET_DNS_Request +{ + /** + * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Unique request ID. + */ + uint64_t request_id GNUNET_PACKED; + + /* followed by original DNS request (without UDP header) */ + +}; + + +/** + * Message from client to DNS service: here is my reply. + */ +struct GNUNET_DNS_Response +{ + /** + * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE + */ + struct GNUNET_MessageHeader header; + + /** + * Zero to drop, 1 for no change (no payload), 2 for update (message has payload). + */ + uint32_t drop_flag GNUNET_PACKED; + + /** + * Unique request ID. + */ + uint64_t request_id GNUNET_PACKED; + + /* followed by original DNS request (without UDP header) */ + +}; + + +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/dns/dns_api.c b/src/dns/dns_api.c new file mode 100644 index 0000000..a280265 --- /dev/null +++ b/src/dns/dns_api.c @@ -0,0 +1,522 @@ +/* + This file is part of GNUnet + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file dns/dns_api.c + * @brief API to access the DNS service. + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_dns_service.h" +#include "dns.h" + + +/** + * Reply to send to service. + */ +struct ReplyQueueEntry +{ + /** + * Kept in DLL. + */ + struct ReplyQueueEntry *next; + + /** + * Kept in DLL. + */ + struct ReplyQueueEntry *prev; + + /** + * Message to transmit, allocated at the end of this struct. + */ + const struct GNUNET_MessageHeader *msg; + +}; + + +/** + * Handle to identify an individual DNS request. + */ +struct GNUNET_DNS_RequestHandle +{ + + /** + * Handle to DNS API. + */ + struct GNUNET_DNS_Handle *dh; + + /** + * Stored in network byte order (as for us, it is just a random number). + */ + uint64_t request_id; + + /** + * Re-connect counter, to make sure we did not reconnect in the meantime. + */ + uint32_t generation; + +}; + + +/** + * DNS handle + */ +struct GNUNET_DNS_Handle +{ + + /** + * Connection to DNS service, or NULL. + */ + struct GNUNET_CLIENT_Connection *dns_connection; + + /** + * Handle to active transmission request, or NULL. + */ + struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle; + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Function to call to get replies. + */ + GNUNET_DNS_RequestHandler rh; + + /** + * Closure for 'rh'. + */ + void *rh_cls; + + /** + * Head of replies to transmit. + */ + struct ReplyQueueEntry *rq_head; + + /** + * Tail of replies to transmit. + */ + struct ReplyQueueEntry *rq_tail; + + /** + * Task to reconnect to the service. + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * Re-connect counter, to make sure we did not reconnect in the meantime. + */ + uint32_t generation; + + /** + * Flags for events we care about. + */ + enum GNUNET_DNS_Flags flags; + + /** + * Did we start the receive loop yet? + */ + int in_receive; + + /** + * Number of GNUNET_DNS_RequestHandles we have outstanding. Must be 0 before + * we can be disconnected. + */ + unsigned int pending_requests; +}; + + +/** + * Add the given reply to our transmission queue and trigger sending if needed. + * + * @param dh handle with the connection + * @param qe reply to queue + */ +static void +queue_reply (struct GNUNET_DNS_Handle *dh, + struct ReplyQueueEntry *qe); + + +/** + * Reconnect to the DNS service. + * + * @param cls handle with the connection to connect + * @param tc scheduler context (unused) + */ +static void +reconnect (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_DNS_Handle *dh = cls; + struct ReplyQueueEntry *qe; + struct GNUNET_DNS_Register *msg; + + dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + dh->dns_connection = GNUNET_CLIENT_connect ("dns", dh->cfg); + if (NULL == dh->dns_connection) + return; + dh->generation++; + qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + + sizeof (struct GNUNET_DNS_Register)); + msg = (struct GNUNET_DNS_Register*) &qe[1]; + qe->msg = &msg->header; + msg->header.size = htons (sizeof (struct GNUNET_DNS_Register)); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT); + msg->flags = htonl (dh->flags); + queue_reply (dh, qe); +} + + +/** + * Disconnect from the DNS service. + * + * @param dh handle with the connection to disconnect + */ +static void +disconnect (struct GNUNET_DNS_Handle *dh) +{ + struct ReplyQueueEntry *qe; + + if (NULL != dh->dns_transmit_handle) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (dh->dns_transmit_handle); + dh->dns_transmit_handle = NULL; + } + if (NULL != dh->dns_connection) + { + GNUNET_CLIENT_disconnect (dh->dns_connection, GNUNET_NO); + dh->dns_connection = NULL; + } + while (NULL != (qe = dh->rq_head)) + { + GNUNET_CONTAINER_DLL_remove (dh->rq_head, + dh->rq_tail, + qe); + GNUNET_free (qe); + } + dh->in_receive = GNUNET_NO; +} + + +/** + * This receives packets from the DNS service and calls the application to + * handle it. + * + * @param cls the struct GNUNET_DNS_Handle + * @param msg message from the service (request) + */ +static void +request_handler (void *cls, + const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_DNS_Handle *dh = cls; + const struct GNUNET_DNS_Request *req; + struct GNUNET_DNS_RequestHandle *rh; + size_t payload_length; + + /* the service disconnected, reconnect after short wait */ + if (msg == NULL) + { + disconnect (dh); + dh->reconnect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &reconnect, dh); + return; + } + if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST) || + (ntohs (msg->size) < sizeof (struct GNUNET_DNS_Request)) ) + { + /* the service did something strange, reconnect immediately */ + GNUNET_break (0); + disconnect (dh); + dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); + return; + } + req = (const struct GNUNET_DNS_Request *) msg; + GNUNET_break (ntohl (req->reserved) == 0); + payload_length = ntohs (req->header.size) - sizeof (struct GNUNET_DNS_Request); + GNUNET_CLIENT_receive (dh->dns_connection, + &request_handler, dh, + GNUNET_TIME_UNIT_FOREVER_REL); + + /* finally, pass request to callback for answers */ + rh = GNUNET_malloc (sizeof (struct GNUNET_DNS_RequestHandle)); + rh->dh =dh; + rh->request_id = req->request_id; + rh->generation = dh->generation; + dh->pending_requests++; + dh->rh (dh->rh_cls, + rh, + payload_length, + (const char*) &req[1]); +} + + +/** + * Callback called by notify_transmit_ready; sends DNS replies + * to the DNS service. + * + * @param cls the struct GNUNET_DNS_Handle + * @param size number of bytes available in buf + * @param buf where to copy the message for transmission + * @return number of bytes copied to buf + */ +static size_t +send_response (void *cls, size_t size, void *buf) +{ + struct GNUNET_DNS_Handle *dh = cls; + struct ReplyQueueEntry *qe; + size_t len; + + dh->dns_transmit_handle = NULL; + if (NULL == buf) + { + disconnect (dh); + dh->reconnect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &reconnect, dh); + return 0; + } + qe = dh->rq_head; + if (NULL == qe) + return 0; + len = ntohs (qe->msg->size); + if (len > size) + { + dh->dns_transmit_handle = + GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, + len, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, + &send_response, dh); + return 0; + } + memcpy (buf, qe->msg, len); + GNUNET_CONTAINER_DLL_remove (dh->rq_head, + dh->rq_tail, + qe); + GNUNET_free (qe); + if (GNUNET_NO == dh->in_receive) + { + dh->in_receive = GNUNET_YES; + GNUNET_CLIENT_receive (dh->dns_connection, + &request_handler, dh, + GNUNET_TIME_UNIT_FOREVER_REL); + } + if (NULL != (qe = dh->rq_head)) + { + dh->dns_transmit_handle = + GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, + ntohs (qe->msg->size), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, + &send_response, dh); + } + return len; +} + + +/** + * Add the given reply to our transmission queue and trigger sending if needed. + * + * @param dh handle with the connection + * @param qe reply to queue + */ +static void +queue_reply (struct GNUNET_DNS_Handle *dh, + struct ReplyQueueEntry *qe) +{ + if (NULL == dh->dns_connection) + { + GNUNET_free (qe); + return; + } + GNUNET_CONTAINER_DLL_insert_tail (dh->rq_head, + dh->rq_tail, + qe); + if (NULL != dh->dns_transmit_handle) + return; + /* trigger sending */ + dh->dns_transmit_handle = + GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, + ntohs (dh->rq_head->msg->size), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, + &send_response, dh); +} + + +/** + * If a GNUNET_DNS_RequestHandler calls this function, the request is + * given to other clients or the global DNS for resolution. Once a + * global response has been obtained, the request handler is AGAIN + * called to give it a chance to observe and modify the response after + * the "normal" resolution. It is not legal for the request handler + * to call this function if a response is already present. + * + * @param rh request that should now be forwarded + */ +void +GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh) +{ + struct ReplyQueueEntry *qe; + struct GNUNET_DNS_Response *resp; + + GNUNET_assert (0 < rh->dh->pending_requests--); + if (rh->generation != rh->dh->generation) + { + GNUNET_free (rh); + return; + } + qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + + sizeof (struct GNUNET_DNS_Response)); + resp = (struct GNUNET_DNS_Response*) &qe[1]; + qe->msg = &resp->header; + resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); + resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); + resp->drop_flag = htonl (1); + resp->request_id = rh->request_id; + queue_reply (rh->dh, qe); + GNUNET_free (rh); +} + + +/** + * If a GNUNET_DNS_RequestHandler calls this function, the request is + * to be dropped and no response should be generated. + * + * @param rh request that should now be dropped + */ +void +GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh) +{ + struct ReplyQueueEntry *qe; + struct GNUNET_DNS_Response *resp; + + GNUNET_assert (0 < rh->dh->pending_requests--); + if (rh->generation != rh->dh->generation) + { + GNUNET_free (rh); + return; + } + qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + + sizeof (struct GNUNET_DNS_Response)); + resp = (struct GNUNET_DNS_Response*) &qe[1]; + qe->msg = &resp->header; + resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); + resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); + resp->request_id = rh->request_id; + resp->drop_flag = htonl (0); + queue_reply (rh->dh, qe); + GNUNET_free (rh); +} + + +/** + * If a GNUNET_DNS_RequestHandler calls this function, the request is + * supposed to be answered with the data provided to this call (with + * the modifications the function might have made). + * + * @param rh request that should now be answered + * @param reply_length size of reply (uint16_t to force sane size) + * @param reply reply data + */ +void +GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, + uint16_t reply_length, + const char *reply) +{ + struct ReplyQueueEntry *qe; + struct GNUNET_DNS_Response *resp; + + GNUNET_assert (0 < rh->dh->pending_requests--); + if (rh->generation != rh->dh->generation) + { + GNUNET_free (rh); + return; + } + if (reply_length + sizeof (struct GNUNET_DNS_Response) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + GNUNET_free (rh); + return; + } + qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + + sizeof (struct GNUNET_DNS_Response) + reply_length); + resp = (struct GNUNET_DNS_Response*) &qe[1]; + qe->msg = &resp->header; + resp->header.size = htons (sizeof (struct GNUNET_DNS_Response) + reply_length); + resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); + resp->drop_flag = htonl (2); + resp->request_id = rh->request_id; + memcpy (&resp[1], reply, reply_length); + queue_reply (rh->dh, qe); + GNUNET_free (rh); +} + + +/** + * Connect to the service-dns + * + * @param cfg configuration to use + * @param flags when to call rh + * @param rh function to call with DNS requests + * @param rh_cls closure to pass to rh + * @return DNS handle + */ +struct GNUNET_DNS_Handle * +GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + enum GNUNET_DNS_Flags flags, + GNUNET_DNS_RequestHandler rh, + void *rh_cls) +{ + struct GNUNET_DNS_Handle *dh; + + dh = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); + dh->cfg = cfg; + dh->flags = flags; + dh->rh = rh; + dh->rh_cls = rh_cls; + dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); + return dh; +} + + +/** + * Disconnect from the DNS service. + * + * @param dh DNS handle + */ +void +GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh) +{ + if (GNUNET_SCHEDULER_NO_TASK != dh->reconnect_task) + { + GNUNET_SCHEDULER_cancel (dh->reconnect_task); + dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + disconnect (dh); + /* make sure client has no pending requests left over! */ + GNUNET_assert (0 == dh->pending_requests); + GNUNET_free (dh); +} + +/* end of dns_api_new.c */ diff --git a/src/dns/dnsparser.c b/src/dns/dnsparser.c new file mode 100644 index 0000000..0e658bd --- /dev/null +++ b/src/dns/dnsparser.c @@ -0,0 +1,796 @@ +/* + This file is part of GNUnet + (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file dns/dnsparser.c + * @brief helper library to parse DNS packets. + * @author Philipp Toelke + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_dnsparser_lib.h" + + +// DNS-Stuff +GNUNET_NETWORK_STRUCT_BEGIN +/* FIXME: replace this one with the one from tcpip_tun.h! */ +struct GNUNET_TUN_DnsHeader +{ + uint16_t id GNUNET_PACKED; + struct GNUNET_DNSPARSER_Flags flags; + uint16_t query_count GNUNET_PACKED; // number of questions + uint16_t answer_rcount GNUNET_PACKED; // number of answers + uint16_t authority_rcount GNUNET_PACKED; // number of authority-records + uint16_t additional_rcount GNUNET_PACKED; // number of additional records +}; + +struct query_line +{ + uint16_t type GNUNET_PACKED; + uint16_t class GNUNET_PACKED; +}; + +struct record_line +{ + uint16_t type GNUNET_PACKED; + uint16_t class GNUNET_PACKED; + uint32_t ttl GNUNET_PACKED; + uint16_t data_len GNUNET_PACKED; +}; + +struct soa_data +{ + uint32_t serial GNUNET_PACKED; + uint32_t refresh GNUNET_PACKED; + uint32_t retry GNUNET_PACKED; + uint32_t expire GNUNET_PACKED; + uint32_t minimum GNUNET_PACKED; +}; + +GNUNET_NETWORK_STRUCT_END + + +/** + * Parse name inside of a DNS query or record. + * + * @param udp_payload entire UDP payload + * @param udp_payload_length length of udp_payload + * @param off pointer to the offset of the name to parse in the udp_payload (to be + * incremented by the size of the name) + * @param depth current depth of our recursion (to prevent stack overflow) + * @return name as 0-terminated C string on success, NULL if the payload is malformed + */ +static char * +parse_name (const char *udp_payload, + size_t udp_payload_length, + size_t *off, + unsigned int depth) +{ + const uint8_t *input = (const uint8_t *) udp_payload; + char *ret; + char *tmp; + char *xstr; + uint8_t len; + size_t xoff; + + ret = GNUNET_strdup (""); + while (1) + { + if (*off >= udp_payload_length) + goto error; + len = input[*off]; + if (0 == len) + { + (*off)++; + break; + } + if (len < 64) + { + if (*off + 1 + len > udp_payload_length) + goto error; + GNUNET_asprintf (&tmp, + "%s%.*s.", + ret, + (int) len, + &udp_payload[*off + 1]); + GNUNET_free (ret); + ret = tmp; + *off += 1 + len; + } + else if ((64 | 128) == (len & (64 | 128)) ) + { + if (depth > 32) + goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */ + /* pointer to string */ + if (*off + 1 > udp_payload_length) + goto error; + xoff = ((len - (64 | 128)) << 8) + input[*off+1]; + xstr = parse_name (udp_payload, + udp_payload_length, + &xoff, + depth + 1); + if (NULL == xstr) + goto error; + GNUNET_asprintf (&tmp, + "%s%s.", + ret, + xstr); + GNUNET_free (ret); + GNUNET_free (xstr); + ret = tmp; + if (strlen (ret) > udp_payload_length) + goto error; /* we are looping (building an infinite string) */ + *off += 2; + /* pointers always terminate names */ + break; + } + else + { + /* neither pointer nor inline string, not supported... */ + goto error; + } + } + if (0 < strlen(ret)) + ret[strlen(ret)-1] = '\0'; /* eat tailing '.' */ + return ret; + error: + GNUNET_free (ret); + return NULL; +} + + +/** + * Parse a DNS query entry. + * + * @param udp_payload entire UDP payload + * @param udp_payload_length length of udp_payload + * @param off pointer to the offset of the query to parse in the udp_payload (to be + * incremented by the size of the query) + * @param q where to write the query information + * @return GNUNET_OK on success, GNUNET_SYSERR if the query is malformed + */ +static int +parse_query (const char *udp_payload, + size_t udp_payload_length, + size_t *off, + struct GNUNET_DNSPARSER_Query *q) +{ + char *name; + struct query_line ql; + + name = parse_name (udp_payload, + udp_payload_length, + off, 0); + if (NULL == name) + return GNUNET_SYSERR; + q->name = name; + if (*off + sizeof (struct query_line) > udp_payload_length) + return GNUNET_SYSERR; + memcpy (&ql, &udp_payload[*off], sizeof (ql)); + *off += sizeof (ql); + q->type = ntohs (ql.type); + q->class = ntohs (ql.class); + return GNUNET_OK; +} + + +/** + * Parse a DNS record entry. + * + * @param udp_payload entire UDP payload + * @param udp_payload_length length of udp_payload + * @param off pointer to the offset of the record to parse in the udp_payload (to be + * incremented by the size of the record) + * @param r where to write the record information + * @return GNUNET_OK on success, GNUNET_SYSERR if the record is malformed + */ +static int +parse_record (const char *udp_payload, + size_t udp_payload_length, + size_t *off, + struct GNUNET_DNSPARSER_Record *r) +{ + char *name; + struct record_line rl; + size_t old_off; + struct soa_data soa; + uint16_t mxpref; + uint16_t data_len; + + name = parse_name (udp_payload, + udp_payload_length, + off, 0); + if (NULL == name) + return GNUNET_SYSERR; + r->name = name; + if (*off + sizeof (struct record_line) > udp_payload_length) + return GNUNET_SYSERR; + memcpy (&rl, &udp_payload[*off], sizeof (rl)); + (*off) += sizeof (rl); + r->type = ntohs (rl.type); + r->class = ntohs (rl.class); + r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, + ntohl (rl.ttl))); + data_len = ntohs (rl.data_len); + if (*off + data_len > udp_payload_length) + return GNUNET_SYSERR; + switch (r->type) + { + case GNUNET_DNSPARSER_TYPE_NS: + case GNUNET_DNSPARSER_TYPE_CNAME: + case GNUNET_DNSPARSER_TYPE_PTR: + old_off = *off; + r->data.hostname = parse_name (udp_payload, + udp_payload_length, + off, 0); + if ( (NULL == r->data.hostname) || + (old_off + data_len != *off) ) + return GNUNET_SYSERR; + return GNUNET_OK; + case GNUNET_DNSPARSER_TYPE_SOA: + old_off = *off; + r->data.soa = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_SoaRecord)); + r->data.soa->mname = parse_name (udp_payload, + udp_payload_length, + off, 0); + r->data.soa->rname = parse_name (udp_payload, + udp_payload_length, + off, 0); + if ( (NULL == r->data.soa->mname) || + (NULL == r->data.soa->rname) || + (*off + sizeof (struct soa_data) > udp_payload_length) ) + return GNUNET_SYSERR; + memcpy (&soa, &udp_payload[*off], sizeof (struct soa_data)); + r->data.soa->serial = ntohl (soa.serial); + r->data.soa->refresh = ntohl (soa.refresh); + r->data.soa->retry = ntohl (soa.retry); + r->data.soa->expire = ntohl (soa.expire); + r->data.soa->minimum_ttl = ntohl (soa.minimum); + (*off) += sizeof (struct soa_data); + if (old_off + data_len != *off) + return GNUNET_SYSERR; + return GNUNET_OK; + case GNUNET_DNSPARSER_TYPE_MX: + old_off = *off; + if (*off + sizeof (uint16_t) > udp_payload_length) + return GNUNET_SYSERR; + memcpy (&mxpref, &udp_payload[*off], sizeof (uint16_t)); + (*off) += sizeof (uint16_t); + r->data.mx = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_MxRecord)); + r->data.mx->preference = ntohs (mxpref); + r->data.mx->mxhost = parse_name (udp_payload, + udp_payload_length, + off, 0); + if (old_off + data_len != *off) + return GNUNET_SYSERR; + return GNUNET_OK; + default: + r->data.raw.data = GNUNET_malloc (data_len); + r->data.raw.data_len = data_len; + memcpy (r->data.raw.data, &udp_payload[*off], data_len); + break; + } + (*off) += data_len; + return GNUNET_OK; +} + + +/** + * Parse a UDP payload of a DNS packet in to a nice struct for further + * processing and manipulation. + * + * @param udp_payload wire-format of the DNS packet + * @param udp_payload_length number of bytes in udp_payload + * @return NULL on error, otherwise the parsed packet + */ +struct GNUNET_DNSPARSER_Packet * +GNUNET_DNSPARSER_parse (const char *udp_payload, + size_t udp_payload_length) +{ + struct GNUNET_DNSPARSER_Packet *p; + const struct GNUNET_TUN_DnsHeader *dns; + size_t off; + unsigned int n; + unsigned int i; + + if (udp_payload_length < sizeof (struct GNUNET_TUN_DnsHeader)) + return NULL; + dns = (const struct GNUNET_TUN_DnsHeader *) udp_payload; + off = sizeof (struct GNUNET_TUN_DnsHeader); + p = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_Packet)); + p->flags = dns->flags; + p->id = dns->id; + n = ntohs (dns->query_count); + if (n > 0) + { + p->queries = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Query)); + p->num_queries = n; + for (i=0;iqueries[i])) + goto error; + } + n = ntohs (dns->answer_rcount); + if (n > 0) + { + p->answers = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); + p->num_answers = n; + for (i=0;ianswers[i])) + goto error; + } + n = ntohs (dns->authority_rcount); + if (n > 0) + { + p->authority_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); + p->num_authority_records = n; + for (i=0;iauthority_records[i])) + goto error; + } + n = ntohs (dns->additional_rcount); + if (n > 0) + { + p->additional_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); + p->num_additional_records = n; + for (i=0;iadditional_records[i])) + goto error; + } + return p; + error: + GNUNET_DNSPARSER_free_packet (p); + return NULL; +} + + +/** + * Free SOA information record. + * + * @param soa record to free + */ +static void +free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa) +{ + if (NULL == soa) + return; + GNUNET_free_non_null (soa->mname); + GNUNET_free_non_null (soa->rname); + GNUNET_free (soa); +} + + +/** + * Free MX information record. + * + * @param mx record to free + */ +static void +free_mx (struct GNUNET_DNSPARSER_MxRecord *mx) +{ + if (NULL == mx) + return; + GNUNET_free_non_null (mx->mxhost); + GNUNET_free (mx); +} + + +static void +free_record (struct GNUNET_DNSPARSER_Record *r) +{ + GNUNET_free_non_null (r->name); + switch (r->type) + { + case GNUNET_DNSPARSER_TYPE_MX: + free_mx (r->data.mx); + break; + case GNUNET_DNSPARSER_TYPE_SOA: + free_soa (r->data.soa); + break; + case GNUNET_DNSPARSER_TYPE_NS: + case GNUNET_DNSPARSER_TYPE_CNAME: + case GNUNET_DNSPARSER_TYPE_PTR: + GNUNET_free_non_null (r->data.hostname); + break; + default: + GNUNET_free_non_null (r->data.raw.data); + break; + } +} + + +/** + * Free memory taken by a packet. + * + * @param p packet to free + */ +void +GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p) +{ + unsigned int i; + + for (i=0;inum_queries;i++) + GNUNET_free_non_null (p->queries[i].name); + GNUNET_free_non_null (p->queries); + for (i=0;inum_answers;i++) + free_record (&p->answers[i]); + GNUNET_free_non_null (p->answers); + for (i=0;inum_authority_records;i++) + free_record (&p->authority_records[i]); + GNUNET_free_non_null (p->authority_records); + for (i=0;inum_additional_records;i++) + free_record (&p->additional_records[i]); + GNUNET_free_non_null (p->additional_records); + GNUNET_free (p); +} + + +/* ********************** DNS packet assembly code **************** */ + + +/** + * Add a DNS name to the UDP packet at the given location. + * + * @param dst where to write the name + * @param dst_len number of bytes in dst + * @param off pointer to offset where to write the name (increment by bytes used) + * must not be changed if there is an error + * @param name name to write + * @return GNUNET_SYSERR if 'name' is invalid + * GNUNET_NO if 'name' did not fit + * GNUNET_OK if 'name' was added to 'dst' + */ +static int +add_name (char *dst, + size_t dst_len, + size_t *off, + const char *name) +{ + const char *dot; + size_t start; + size_t pos; + size_t len; + + if (NULL == name) + return GNUNET_SYSERR; + start = *off; + if (start + strlen (name) + 2 > dst_len) + return GNUNET_NO; + pos = start; + do + { + dot = strchr (name, '.'); + if (NULL == dot) + len = strlen (name); + else + len = dot - name; + if ( (len >= 64) || (len == 0) ) + return GNUNET_NO; /* segment too long or empty */ + dst[pos++] = (char) (uint8_t) len; + memcpy (&dst[pos], name, len); + pos += len; + name += len + 1; /* also skip dot */ + } + while (NULL != dot); + dst[pos++] = '\0'; /* terminator */ + *off = pos; + return GNUNET_OK; +} + + +/** + * Add a DNS query to the UDP packet at the given location. + * + * @param dst where to write the query + * @param dst_len number of bytes in dst + * @param off pointer to offset where to write the query (increment by bytes used) + * must not be changed if there is an error + * @param query query to write + * @return GNUNET_SYSERR if 'query' is invalid + * GNUNET_NO if 'query' did not fit + * GNUNET_OK if 'query' was added to 'dst' + */ +static int +add_query (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_Query *query) +{ + int ret; + struct query_line ql; + + ret = add_name (dst, dst_len - sizeof (struct query_line), off, query->name); + if (ret != GNUNET_OK) + return ret; + ql.type = htons (query->type); + ql.class = htons (query->class); + memcpy (&dst[*off], &ql, sizeof (ql)); + (*off) += sizeof (ql); + return GNUNET_OK; +} + + +/** + * Add an MX record to the UDP packet at the given location. + * + * @param dst where to write the mx record + * @param dst_len number of bytes in dst + * @param off pointer to offset where to write the mx information (increment by bytes used); + * can also change if there was an error + * @param mx mx information to write + * @return GNUNET_SYSERR if 'mx' is invalid + * GNUNET_NO if 'mx' did not fit + * GNUNET_OK if 'mx' was added to 'dst' + */ +static int +add_mx (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_MxRecord *mx) +{ + uint16_t mxpref; + + if (*off + sizeof (uint16_t) > dst_len) + return GNUNET_NO; + mxpref = htons (mx->preference); + memcpy (&dst[*off], &mxpref, sizeof (mxpref)); + (*off) += sizeof (mxpref); + return add_name (dst, dst_len, off, mx->mxhost); +} + + +/** + * Add an SOA record to the UDP packet at the given location. + * + * @param dst where to write the SOA record + * @param dst_len number of bytes in dst + * @param off pointer to offset where to write the SOA information (increment by bytes used) + * can also change if there was an error + * @param soa SOA information to write + * @return GNUNET_SYSERR if 'soa' is invalid + * GNUNET_NO if 'soa' did not fit + * GNUNET_OK if 'soa' was added to 'dst' + */ +static int +add_soa (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_SoaRecord *soa) +{ + struct soa_data sd; + int ret; + + if ( (GNUNET_OK != (ret = add_name (dst, + dst_len, + off, + soa->mname))) || + (GNUNET_OK != (ret = add_name (dst, + dst_len, + off, + soa->rname)) ) ) + return ret; + if (*off + sizeof (struct soa_data) > dst_len) + return GNUNET_NO; + sd.serial = htonl (soa->serial); + sd.refresh = htonl (soa->refresh); + sd.retry = htonl (soa->retry); + sd.expire = htonl (soa->expire); + sd.minimum = htonl (soa->minimum_ttl); + memcpy (&dst[*off], &sd, sizeof (sd)); + (*off) += sizeof (sd); + return GNUNET_OK; +} + + +/** + * Add a DNS record to the UDP packet at the given location. + * + * @param dst where to write the query + * @param dst_len number of bytes in dst + * @param off pointer to offset where to write the query (increment by bytes used) + * must not be changed if there is an error + * @param record record to write + * @return GNUNET_SYSERR if 'record' is invalid + * GNUNET_NO if 'record' did not fit + * GNUNET_OK if 'record' was added to 'dst' + */ +static int +add_record (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_Record *record) +{ + int ret; + size_t start; + size_t pos; + struct record_line rl; + + start = *off; + ret = add_name (dst, dst_len - sizeof (struct record_line), off, record->name); + if (ret != GNUNET_OK) + return ret; + /* '*off' is now the position where we will need to write the record line */ + + pos = *off + sizeof (struct record_line); + switch (record->type) + { + case GNUNET_DNSPARSER_TYPE_MX: + ret = add_mx (dst, dst_len, &pos, record->data.mx); + break; + case GNUNET_DNSPARSER_TYPE_SOA: + ret = add_soa (dst, dst_len, &pos, record->data.soa); + break; + case GNUNET_DNSPARSER_TYPE_NS: + case GNUNET_DNSPARSER_TYPE_CNAME: + case GNUNET_DNSPARSER_TYPE_PTR: + ret = add_name (dst, dst_len, &pos, record->data.hostname); + break; + default: + if (pos + record->data.raw.data_len > dst_len) + { + ret = GNUNET_NO; + break; + } + memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len); + pos += record->data.raw.data_len; + ret = GNUNET_OK; + break; + } + if (ret != GNUNET_OK) + { + *off = start; + return GNUNET_NO; + } + + if (pos - (*off + sizeof (struct record_line)) > UINT16_MAX) + { + /* record data too long */ + *off = start; + return GNUNET_NO; + } + rl.type = htons (record->type); + rl.class = htons (record->class); + rl.ttl = htonl (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000); /* in seconds */ + rl.data_len = htons ((uint16_t) (pos - (*off + sizeof (struct record_line)))); + memcpy (&dst[*off], &rl, sizeof (struct record_line)); + *off = pos; + return GNUNET_OK; +} + + +/** + * Given a DNS packet, generate the corresponding UDP payload. + * Note that we do not attempt to pack the strings with pointers + * as this would complicate the code and this is about being + * simple and secure, not fast, fancy and broken like bind. + * + * @param p packet to pack + * @param max maximum allowed size for the resulting UDP payload + * @param buf set to a buffer with the packed message + * @param buf_length set to the length of buf + * @return GNUNET_SYSERR if 'p' is invalid + * GNUNET_NO if 'p' was truncated (but there is still a result in 'buf') + * GNUNET_OK if 'p' was packed completely into '*buf' + */ +int +GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p, + uint16_t max, + char **buf, + size_t *buf_length) +{ + struct GNUNET_TUN_DnsHeader dns; + size_t off; + char tmp[max]; + unsigned int i; + int ret; + int trc; + + if ( (p->num_queries > UINT16_MAX) || + (p->num_answers > UINT16_MAX) || + (p->num_authority_records > UINT16_MAX) || + (p->num_additional_records > UINT16_MAX) ) + return GNUNET_SYSERR; + dns.id = p->id; + dns.flags = p->flags; + dns.query_count = htons (p->num_queries); + dns.answer_rcount = htons (p->num_answers); + dns.authority_rcount = htons (p->num_authority_records); + dns.additional_rcount = htons (p->num_additional_records); + + off = sizeof (struct GNUNET_TUN_DnsHeader); + trc = GNUNET_NO; + for (i=0;inum_queries;i++) + { + ret = add_query (tmp, sizeof (tmp), &off, &p->queries[i]); + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; + if (GNUNET_NO == ret) + { + dns.query_count = htons ((uint16_t) (i-1)); + trc = GNUNET_YES; + break; + } + } + for (i=0;inum_answers;i++) + { + ret = add_record (tmp, sizeof (tmp), &off, &p->answers[i]); + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; + if (GNUNET_NO == ret) + { + dns.answer_rcount = htons ((uint16_t) (i-1)); + trc = GNUNET_YES; + break; + } + } + for (i=0;inum_authority_records;i++) + { + ret = add_record (tmp, sizeof (tmp), &off, &p->authority_records[i]); + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; + if (GNUNET_NO == ret) + { + dns.authority_rcount = htons ((uint16_t) (i-1)); + trc = GNUNET_YES; + break; + } + } + for (i=0;inum_additional_records;i++) + { + ret = add_record (tmp, sizeof (tmp), &off, &p->additional_records[i]); + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; + if (GNUNET_NO == ret) + { + dns.additional_rcount = htons (i-1); + trc = GNUNET_YES; + break; + } + } + + if (GNUNET_YES == trc) + dns.flags.message_truncated = 1; + memcpy (tmp, &dns, sizeof (struct GNUNET_TUN_DnsHeader)); + + *buf = GNUNET_malloc (off); + *buf_length = off; + memcpy (*buf, tmp, off); + if (GNUNET_YES == trc) + return GNUNET_NO; + return GNUNET_OK; +} + +/* end of dnsparser.c */ diff --git a/src/dns/gnunet-dns-monitor.c b/src/dns/gnunet-dns-monitor.c new file mode 100644 index 0000000..82715aa --- /dev/null +++ b/src/dns/gnunet-dns-monitor.c @@ -0,0 +1,353 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/dns/gnunet-dns-monitor.c + * @brief Tool to monitor DNS queries + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_dns_service.h" +#include "gnunet_dnsparser_lib.h" + +/** + * Handle to transport service. + */ +static struct GNUNET_DNS_Handle *handle; + +/** + * Option -i. + */ +static int inbound_only; + +/** + * Option -o. + */ +static int outbound_only; + +/** + * Global return value (0 success). + */ +static int ret; + +/** + * Selected level of verbosity. + */ +static int verbosity; + + +/** + * Convert numeric DNS record type to a string. + * + * @param type type to convert + * @return type as string, only valid until the next call to this function + */ +static const char * +get_type (uint16_t type) +{ + static char buf[6]; + switch (type) + { + case GNUNET_DNSPARSER_TYPE_A: return "A"; + case GNUNET_DNSPARSER_TYPE_NS: return "NS"; + case GNUNET_DNSPARSER_TYPE_CNAME: return "CNAME"; + case GNUNET_DNSPARSER_TYPE_SOA: return "SOA"; + case GNUNET_DNSPARSER_TYPE_PTR: return "PTR"; + case GNUNET_DNSPARSER_TYPE_MX: return "MX"; + case GNUNET_DNSPARSER_TYPE_TXT: return "TXT"; + case GNUNET_DNSPARSER_TYPE_AAAA: return "AAAA"; + } + GNUNET_snprintf (buf, sizeof (buf), "%u", (unsigned int) type); + return buf; +} + + +/** + * Convert numeric DNS record class to a string. + * + * @param class class to convert + * @return class as string, only valid until the next call to this function + */ +static const char * +get_class (uint16_t class) +{ + static char buf[6]; + switch (class) + { + case GNUNET_DNSPARSER_CLASS_INTERNET: return "IN"; + case GNUNET_DNSPARSER_CLASS_CHAOS: return "CHAOS"; + case GNUNET_DNSPARSER_CLASS_HESIOD: return "HESIOD"; + } + GNUNET_snprintf (buf, sizeof (buf), "%u", (unsigned int) class); + return buf; +} + + +/** + * Output the given DNS query to stdout. + * + * @param query query to display. + */ +static void +display_query (const struct GNUNET_DNSPARSER_Query *query) +{ + fprintf (stdout, + "\t\t%s %s: %s\n", + get_class (query->class), + get_type (query->type), + query->name); +} + + +/** + * Output the given DNS record to stdout. + * + * @param record record to display. + */ +static void +display_record (const struct GNUNET_DNSPARSER_Record *record) +{ + const char *format; + char buf[INET6_ADDRSTRLEN]; + char *tmp; + + tmp = NULL; + switch (record->type) + { + case GNUNET_DNSPARSER_TYPE_A: + if (record->data.raw.data_len != sizeof (struct in_addr)) + format = ""; + else + format = inet_ntop (AF_INET, record->data.raw.data, buf, sizeof (buf)); + break; + case GNUNET_DNSPARSER_TYPE_AAAA: + if (record->data.raw.data_len != sizeof (struct in6_addr)) + format = ""; + else + format = inet_ntop (AF_INET6, record->data.raw.data, buf, sizeof (buf)); + break; + case GNUNET_DNSPARSER_TYPE_NS: + case GNUNET_DNSPARSER_TYPE_CNAME: + case GNUNET_DNSPARSER_TYPE_PTR: + format = record->data.hostname; + break; + case GNUNET_DNSPARSER_TYPE_SOA: + if (record->data.soa == NULL) + format = ""; + else + { + GNUNET_asprintf (&tmp, + "origin: %s, mail: %s, serial = %u, refresh = %u s, retry = %u s, expire = %u s, minimum = %u s", + record->data.soa->mname, + record->data.soa->rname, + (unsigned int) record->data.soa->serial, + (unsigned int) record->data.soa->refresh, + (unsigned int) record->data.soa->retry, + (unsigned int) record->data.soa->expire, + (unsigned int) record->data.soa->minimum_ttl); + format = tmp; + } + break; + case GNUNET_DNSPARSER_TYPE_MX: + if (record->data.mx == NULL) + format = ""; + else + { + GNUNET_asprintf (&tmp, + "%u: %s", + record->data.mx->preference, + record->data.mx->mxhost); + format = tmp; + } + break; + case GNUNET_DNSPARSER_TYPE_TXT: + GNUNET_asprintf (&tmp, + "%.*s", + (unsigned int) record->data.raw.data_len, + record->data.raw.data); + format = tmp; + break; + default: + format = ""; + break; + } + fprintf (stdout, + "\t\t%s %s: %s = %s (%u s)\n", + get_class (record->class), + get_type (record->type), + record->name, + format, + (unsigned int) (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000)); + GNUNET_free_non_null (tmp); +} + + +/** + * Signature of a function that is called whenever the DNS service + * encounters a DNS request and needs to do something with it. The + * function has then the chance to generate or modify the response by + * calling one of the three "GNUNET_DNS_request_*" continuations. + * + * When a request is intercepted, this function is called first to + * give the client a chance to do the complete address resolution; + * "rdata" will be NULL for this first call for a DNS request, unless + * some other client has already filled in a response. + * + * If multiple clients exist, all of them are called before the global + * DNS. The global DNS is only called if all of the clients' + * functions call GNUNET_DNS_request_forward. Functions that call + * GNUNET_DNS_request_forward will be called again before a final + * response is returned to the application. If any of the clients' + * functions call GNUNET_DNS_request_drop, the response is dropped. + * + * @param cls closure + * @param rh request handle to user for reply + * @param request_length number of bytes in request + * @param request udp payload of the DNS request + */ +static void +display_request (void *cls, + struct GNUNET_DNS_RequestHandle *rh, + size_t request_length, + const char *request) +{ + static const char *return_codes[] = + { + "No error", "Format error", "Server failure", "Name error", + "Not implemented", "Refused", "YXDomain", "YXRRset", + "NXRRset", "NOT AUTH", "NOT ZONE", "", + "", "", "", "" + }; + static const char *op_codes[] = + { + "Query", "Inverse query", "Status", "", + "", "", "", "", + "", "", "", "", + "", "", "", "" + }; + struct GNUNET_DNSPARSER_Packet *p; + unsigned int i; + + p = GNUNET_DNSPARSER_parse (request, request_length); + if (NULL == p) + { + fprintf (stderr, "Received malformed DNS packet!\n"); + // FIXME: drop instead? + GNUNET_DNS_request_forward (rh); + return; + } + fprintf (stdout, + "%s with ID: %5u Flags: %s%s%s%s%s%s, Return Code: %s, Opcode: %s\n", + p->flags.query_or_response ? "Response" : "Query", + p->id, + p->flags.recursion_desired ? "RD " : "", + p->flags.message_truncated ? "MT " : "", + p->flags.authoritative_answer ? "AA " : "", + p->flags.checking_disabled ? "CD " : "", + p->flags.authenticated_data ? "AD " : "", + p->flags.recursion_available ? "RA " : "", + return_codes[p->flags.return_code & 15], + op_codes[p->flags.opcode & 15]); + if (p->num_queries > 0) + fprintf (stdout, + "\tQueries:\n"); + for (i=0;inum_queries;i++) + display_query (&p->queries[i]); + + if (p->num_answers > 0) + fprintf (stdout, + "\tAnswers:\n"); + for (i=0;inum_answers;i++) + display_record (&p->answers[i]); + fprintf (stdout, "\n"); + GNUNET_DNSPARSER_free_packet (p); + GNUNET_DNS_request_forward (rh); +} + + +/** + * Shutdown. + */ +static void +do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != handle) + { + GNUNET_DNS_disconnect (handle); + handle = NULL; + } +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + enum GNUNET_DNS_Flags flags; + + flags = GNUNET_DNS_FLAG_REQUEST_MONITOR | GNUNET_DNS_FLAG_RESPONSE_MONITOR; + if (inbound_only | outbound_only) + flags = 0; + if (inbound_only) + flags |= GNUNET_DNS_FLAG_REQUEST_MONITOR; + if (outbound_only) + flags |= GNUNET_DNS_FLAG_RESPONSE_MONITOR; + handle = + GNUNET_DNS_connect (cfg, + flags, + &display_request, + NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &do_disconnect, NULL); +} + + +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'i', "inbound-only", NULL, + gettext_noop ("only monitor DNS queries"), + 0, &GNUNET_GETOPT_set_one, &inbound_only}, + {'o', "outbound-only", NULL, + gettext_noop ("only monitor DNS replies"), + 0, &GNUNET_GETOPT_set_one, &outbound_only}, + GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-dns-monitor", + gettext_noop + ("Monitor DNS queries."), options, + &run, NULL)) ? ret : 1; +} + + +/* end of gnunet-dns-monitor.c */ diff --git a/src/dns/gnunet-dns-redirector.c b/src/dns/gnunet-dns-redirector.c new file mode 100644 index 0000000..a45b896 --- /dev/null +++ b/src/dns/gnunet-dns-redirector.c @@ -0,0 +1,252 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/dns/gnunet-dns-redirector.c + * @brief Tool to change DNS replies (for testing) + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_dns_service.h" +#include "gnunet_dnsparser_lib.h" + +/** + * Handle to DNS service. + */ +static struct GNUNET_DNS_Handle *handle; + +/** + * New target for A records. + */ +static char *n4; + +/** + * New target for AAAA records. + */ +static char *n6; + +/** + * Global return value (0 success). + */ +static int ret; + +/** + * Selected level of verbosity. + */ +static int verbosity; + + +/** + * Modify the given DNS record. + * + * @param record record to modify + */ +static void +modify_record (const struct GNUNET_DNSPARSER_Record *record) +{ + char buf[INET6_ADDRSTRLEN]; + + switch (record->type) + { + case GNUNET_DNSPARSER_TYPE_A: + if (record->data.raw.data_len != sizeof (struct in_addr)) + return; + if (NULL != n4) + { + if (verbosity > 1) + fprintf (stderr, + "Changing A record from `%s' to `%s'\n", + inet_ntop (AF_INET, record->data.raw.data, buf, sizeof (buf)), + n4); + GNUNET_assert (1 == inet_pton (AF_INET, n4, record->data.raw.data)); + } + break; + case GNUNET_DNSPARSER_TYPE_AAAA: + if (record->data.raw.data_len != sizeof (struct in6_addr)) + return; + if (NULL != n6) + { + if (verbosity > 1) + fprintf (stderr, + "Changing AAAA record from `%s' to `%s'\n", + inet_ntop (AF_INET6, record->data.raw.data, buf, sizeof (buf)), + n6); + GNUNET_assert (1 == inet_pton (AF_INET6, n6, record->data.raw.data)); + } + break; + case GNUNET_DNSPARSER_TYPE_NS: + case GNUNET_DNSPARSER_TYPE_CNAME: + case GNUNET_DNSPARSER_TYPE_PTR: + case GNUNET_DNSPARSER_TYPE_SOA: + case GNUNET_DNSPARSER_TYPE_MX: + case GNUNET_DNSPARSER_TYPE_TXT: + break; + default: + break; + } +} + + +/** + * Signature of a function that is called whenever the DNS service + * encounters a DNS request and needs to do something with it. The + * function has then the chance to generate or modify the response by + * calling one of the three "GNUNET_DNS_request_*" continuations. + * + * When a request is intercepted, this function is called first to + * give the client a chance to do the complete address resolution; + * "rdata" will be NULL for this first call for a DNS request, unless + * some other client has already filled in a response. + * + * If multiple clients exist, all of them are called before the global + * DNS. The global DNS is only called if all of the clients' + * functions call GNUNET_DNS_request_forward. Functions that call + * GNUNET_DNS_request_forward will be called again before a final + * response is returned to the application. If any of the clients' + * functions call GNUNET_DNS_request_drop, the response is dropped. + * + * @param cls closure + * @param rh request handle to user for reply + * @param request_length number of bytes in request + * @param request udp payload of the DNS request + */ +static void +modify_request (void *cls, + struct GNUNET_DNS_RequestHandle *rh, + size_t request_length, + const char *request) +{ + struct GNUNET_DNSPARSER_Packet *p; + unsigned int i; + char *buf; + size_t len; + int ret; + + p = GNUNET_DNSPARSER_parse (request, request_length); + if (NULL == p) + { + fprintf (stderr, "Received malformed DNS packet, leaving it untouched\n"); + GNUNET_DNS_request_forward (rh); + return; + } + for (i=0;inum_answers;i++) + modify_record (&p->answers[i]); + buf = NULL; + ret = GNUNET_DNSPARSER_pack (p, 1024, &buf, &len); + GNUNET_DNSPARSER_free_packet (p); + if (GNUNET_OK != ret) + { + if (GNUNET_NO == ret) + fprintf (stderr, + "Modified DNS response did not fit, keeping old response\n"); + else + GNUNET_break (0); /* our modifications should have been sane! */ + GNUNET_DNS_request_forward (rh); + } + else + { + if (verbosity > 0) + fprintf (stdout, + "Injecting modified DNS response\n"); + GNUNET_DNS_request_answer (rh, len, buf); + } + GNUNET_free_non_null (buf); +} + + +/** + * Shutdown. + */ +static void +do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != handle) + { + GNUNET_DNS_disconnect (handle); + handle = NULL; + } +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct in_addr i4; + struct in6_addr i6; + if ( (n4 != NULL) && + (1 != inet_pton (AF_INET, n4, &i4)) ) + { + fprintf (stderr, + "`%s' is nto a valid IPv4 address!\n", + n4); + return; + } + if ( (n6 != NULL) && + (1 != inet_pton (AF_INET6, n6, &i6)) ) + { + fprintf (stderr, + "`%s' is nto a valid IPv6 address!\n", + n6); + return; + } + + handle = + GNUNET_DNS_connect (cfg, + GNUNET_DNS_FLAG_POST_RESOLUTION, + &modify_request, + NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &do_disconnect, NULL); +} + + +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'4', "ipv4", "IPV4", + gettext_noop ("set A records"), + 1, &GNUNET_GETOPT_set_string, &n4}, + {'6', "ipv4", "IPV6", + gettext_noop ("set AAAA records"), + 1, &GNUNET_GETOPT_set_string, &n6}, + GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-dns-redirector", + gettext_noop + ("Change DNS replies to point elsewhere."), options, + &run, NULL)) ? ret : 1; +} + + +/* end of gnunet-dns-redirector.c */ diff --git a/src/dns/gnunet-helper-dns.c b/src/dns/gnunet-helper-dns.c new file mode 100644 index 0000000..dfeb45a --- /dev/null +++ b/src/dns/gnunet-helper-dns.c @@ -0,0 +1,961 @@ +/* + This file is part of GNUnet. + (C) 2010, 2011, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dns/gnunet-helper-dns.c + * @brief helper to install firewall rules to hijack all DNS traffic + * and send it to our virtual interface (except for DNS traffic + * that originates on the specified port). We then + * allow interacting with our virtual interface via stdin/stdout. + * @author Philipp Tölke + * @author Christian Grothoff + * + * This program alters the Linux firewall rules so that DNS traffic + * that ordinarily exits the system can be intercepted and managed by + * a virtual interface. In order to achieve this, DNS traffic is + * marked with the DNS_MARK given in below and re-routed to a custom + * table with the DNS_TABLE ID given below. Systems and + * administrators must take care to not cause conflicts with these + * values (it was deemed safest to hardcode them as passing these + * values as arguments might permit messing with arbitrary firewall + * rules, which would be dangerous). Traffic coming from the same + * group ID as the effective group ID that this process is running + * as is not intercepted. + * + * The code first sets up the virtual interface, then begins to + * redirect the DNS traffic to it, and then on errors or SIGTERM shuts + * down the virtual interface and removes the rules for the traffic + * redirection. + * + * + * Note that having this binary SUID is only partially safe: it will + * allow redirecting (and intercepting / mangling) of all DNS traffic + * originating from this system by any user who is able to run it. + * Furthermore, this code will make it trivial to DoS all DNS traffic + * originating from the current system, simply by sending it to + * nowhere (redirect stdout to /dev/null). + * + * Naturally, neither of these problems can be helped as this is the + * fundamental purpose of the binary. Certifying that this code is + * "safe" thus only means that it doesn't allow anything else (such + * as local priv. escalation, etc.). + * + * The following list of people have reviewed this code and considered + * it safe (within specifications) since the last modification (if you + * reviewed it, please have your name added to the list): + * + * - Christian Grothoff + */ +#include "platform.h" + +#include + +/** + * Need 'struct GNUNET_MessageHeader'. + */ +#include "gnunet_common.h" + +/** + * Need DNS message types. + */ +#include "gnunet_protocols.h" + +/** + * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) + */ +#define MAX_SIZE 65536 + +#ifndef _LINUX_IN6_H +/** + * This is in linux/include/net/ipv6.h, but not always exported... + */ +struct in6_ifreq +{ + struct in6_addr ifr6_addr; + uint32_t ifr6_prefixlen; + unsigned int ifr6_ifindex; +}; +#endif + +/** + * Name and full path of IPTABLES binary. + */ +static const char *sbin_iptables; + +/** + * Name and full path of IPTABLES binary. + */ +static const char *sbin_ip; + +/** + * Port for DNS traffic. + */ +#define DNS_PORT "53" + +/** + * Marker we set for our hijacked DNS traffic. We use GNUnet's + * port (2086) plus the DNS port (53) in HEX to make a 32-bit mark + * (which is hopefully long enough to not collide); so + * 0x08260035 = 136708149 (hopefully unique enough...). + */ +#define DNS_MARK "136708149" + +/** + * Table we use for our DNS rules. 0-255 is the range and + * 0, 253, 254 and 255 are already reserved. As this is about + * DNS and as "53" is likely (fingers crossed!) high enough to + * not usually conflict with a normal user's setup, we use 53 + * to give a hint that this has something to do with DNS. + */ +#define DNS_TABLE "53" + + +/** + * Control pipe for shutdown via signal. [0] is the read end, + * [1] is the write end. + */ +static int cpipe[2]; + + +/** + * Signal handler called to initiate "nice" shutdown. Signals select + * loop via non-bocking pipe 'cpipe'. + * + * @param signal signal number of the signal (not used) + */ +static void +signal_handler (int signal) +{ + /* ignore return value, as the signal handler could theoretically + be called many times before the shutdown can actually happen */ + (void) write (cpipe[1], "K", 1); +} + + +/** + * Run the given command and wait for it to complete. + * + * @param file name of the binary to run + * @param cmd command line arguments (as given to 'execv') + * @return 0 on success, 1 on any error + */ +static int +fork_and_exec (const char *file, + char *const cmd[]) +{ + int status; + pid_t pid; + pid_t ret; + + pid = fork (); + if (-1 == pid) + { + fprintf (stderr, + "fork failed: %s\n", + strerror (errno)); + return 1; + } + if (0 == pid) + { + /* we are the child process */ + /* close stdin/stdout to not cause interference + with the helper's main protocol! */ + (void) close (0); + (void) close (1); + (void) execv (file, cmd); + /* can only get here on error */ + fprintf (stderr, + "exec `%s' failed: %s\n", + file, + strerror (errno)); + _exit (1); + } + /* keep running waitpid as long as the only error we get is 'EINTR' */ + while ( (-1 == (ret = waitpid (pid, &status, 0))) && + (errno == EINTR) ); + if (-1 == ret) + { + fprintf (stderr, + "waitpid failed: %s\n", + strerror (errno)); + return 1; + } + if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) + return 1; + /* child process completed and returned success, we're happy */ + return 0; +} + + +/** + * Creates a tun-interface called dev; + * + * @param dev is asumed to point to a char[IFNAMSIZ] + * if *dev == '\\0', uses the name supplied by the kernel; + * @return the fd to the tun or -1 on error + */ +static int +init_tun (char *dev) +{ + struct ifreq ifr; + int fd; + + if (NULL == dev) + { + errno = EINVAL; + return -1; + } + + if (-1 == (fd = open ("/dev/net/tun", O_RDWR))) + { + fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun", + strerror (errno)); + return -1; + } + + if (fd >= FD_SETSIZE) + { + fprintf (stderr, "File descriptor to large: %d", fd); + (void) close (fd); + return -1; + } + + memset (&ifr, 0, sizeof (ifr)); + ifr.ifr_flags = IFF_TUN; + + if ('\0' != *dev) + strncpy (ifr.ifr_name, dev, IFNAMSIZ); + + if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr)) + { + fprintf (stderr, "Error with ioctl on `%s': %s\n", "/dev/net/tun", + strerror (errno)); + (void) close (fd); + return -1; + } + strcpy (dev, ifr.ifr_name); + return fd; +} + + +/** + * @brief Sets the IPv6-Address given in address on the interface dev + * + * @param dev the interface to configure + * @param address the IPv6-Address + * @param prefix_len the length of the network-prefix + */ +static void +set_address6 (const char *dev, const char *address, unsigned long prefix_len) +{ + struct ifreq ifr; + struct in6_ifreq ifr6; + struct sockaddr_in6 sa6; + int fd; + + /* + * parse the new address + */ + memset (&sa6, 0, sizeof (struct sockaddr_in6)); + sa6.sin6_family = AF_INET6; + if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr)) + { + fprintf (stderr, "Failed to parse address `%s': %s\n", address, + strerror (errno)); + exit (1); + } + + if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0))) + { + fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); + exit (1); + } + + memset (&ifr, 0, sizeof (struct ifreq)); + /* + * Get the index of the if + */ + strncpy (ifr.ifr_name, dev, IFNAMSIZ); + if (-1 == ioctl (fd, SIOGIFINDEX, &ifr)) + { + fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); + (void) close (fd); + exit (1); + } + + memset (&ifr6, 0, sizeof (struct in6_ifreq)); + ifr6.ifr6_addr = sa6.sin6_addr; + ifr6.ifr6_ifindex = ifr.ifr_ifindex; + ifr6.ifr6_prefixlen = prefix_len; + + /* + * Set the address + */ + if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Get the flags + */ + if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Add the UP and RUNNING flags + */ + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + if (0 != close (fd)) + { + fprintf (stderr, "close failed: %s\n", strerror (errno)); + exit (1); + } +} + + +/** + * @brief Sets the IPv4-Address given in address on the interface dev + * + * @param dev the interface to configure + * @param address the IPv4-Address + * @param mask the netmask + */ +static void +set_address4 (const char *dev, const char *address, const char *mask) +{ + int fd; + struct sockaddr_in *addr; + struct ifreq ifr; + + memset (&ifr, 0, sizeof (struct ifreq)); + addr = (struct sockaddr_in *) &(ifr.ifr_addr); + addr->sin_family = AF_INET; + + /* + * Parse the address + */ + if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr)) + { + fprintf (stderr, "Failed to parse address `%s': %s\n", address, + strerror (errno)); + exit (1); + } + + if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0))) + { + fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); + exit (1); + } + + strncpy (ifr.ifr_name, dev, IFNAMSIZ); + + /* + * Set the address + */ + if (-1 == ioctl (fd, SIOCSIFADDR, &ifr)) + { + fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Parse the netmask + */ + addr = (struct sockaddr_in *) &(ifr.ifr_netmask); + if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr)) + { + fprintf (stderr, "Failed to parse address `%s': %s\n", mask, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Set the netmask + */ + if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Get the flags + */ + if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Add the UP and RUNNING flags + */ + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + if (0 != close (fd)) + { + fprintf (stderr, "close failed: %s\n", strerror (errno)); + (void) close (fd); + exit (1); + } +} + + +/** + * Start forwarding to and from the tunnel. This function runs with + * "reduced" priviledges (saved UID is still 0, but effective UID is + * the real user ID). + * + * @param fd_tun tunnel FD + */ +static void +run (int fd_tun) +{ + /* + * The buffer filled by reading from fd_tun + */ + unsigned char buftun[MAX_SIZE]; + ssize_t buftun_size = 0; + unsigned char *buftun_read = NULL; + + /* + * The buffer filled by reading from stdin + */ + unsigned char bufin[MAX_SIZE]; + ssize_t bufin_size = 0; + size_t bufin_rpos = 0; + unsigned char *bufin_read = NULL; + fd_set fds_w; + fd_set fds_r; + int max; + + while (1) + { + FD_ZERO (&fds_w); + FD_ZERO (&fds_r); + + /* + * We are supposed to read and the buffer is empty + * -> select on read from tun + */ + if (0 == buftun_size) + FD_SET (fd_tun, &fds_r); + + /* + * We are supposed to read and the buffer is not empty + * -> select on write to stdout + */ + if (0 != buftun_size) + FD_SET (1, &fds_w); + + /* + * We are supposed to write and the buffer is empty + * -> select on read from stdin + */ + if (NULL == bufin_read) + FD_SET (0, &fds_r); + + /* + * We are supposed to write and the buffer is not empty + * -> select on write to tun + */ + if (NULL != bufin_read) + FD_SET (fd_tun, &fds_w); + + FD_SET (cpipe[0], &fds_r); + max = (fd_tun > cpipe[0]) ? fd_tun : cpipe[0]; + + int r = select (max + 1, &fds_r, &fds_w, NULL, NULL); + + if (-1 == r) + { + if (EINTR == errno) + continue; + fprintf (stderr, "select failed: %s\n", strerror (errno)); + return; + } + + if (r > 0) + { + if (FD_ISSET (cpipe[0], &fds_r)) + return; /* aborted by signal */ + + if (FD_ISSET (fd_tun, &fds_r)) + { + buftun_size = + read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader), + MAX_SIZE - sizeof (struct GNUNET_MessageHeader)); + if (-1 == buftun_size) + { + if ( (errno == EINTR) || + (errno == EAGAIN) ) + continue; + fprintf (stderr, "read-error: %s\n", strerror (errno)); + return; + } + if (0 == buftun_size) + { + fprintf (stderr, "EOF on tun\n"); + return; + } + buftun_read = buftun; + { + struct GNUNET_MessageHeader *hdr = + (struct GNUNET_MessageHeader *) buftun; + buftun_size += sizeof (struct GNUNET_MessageHeader); + hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); + hdr->size = htons (buftun_size); + } + } + else if (FD_ISSET (1, &fds_w)) + { + ssize_t written = write (1, buftun_read, buftun_size); + + if (-1 == written) + { + if ( (errno == EINTR) || + (errno == EAGAIN) ) + continue; + fprintf (stderr, "write-error to stdout: %s\n", strerror (errno)); + return; + } + if (0 == written) + { + fprintf (stderr, "write returned 0\n"); + return; + } + buftun_size -= written; + buftun_read += written; + } + + if (FD_ISSET (0, &fds_r)) + { + bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos); + if (-1 == bufin_size) + { + bufin_read = NULL; + if ( (errno == EINTR) || + (errno == EAGAIN) ) + continue; + fprintf (stderr, "read-error: %s\n", strerror (errno)); + return; + } + if (0 == bufin_size) + { + bufin_read = NULL; + fprintf (stderr, "EOF on stdin\n"); + return; + } + { + struct GNUNET_MessageHeader *hdr; + +PROCESS_BUFFER: + bufin_rpos += bufin_size; + if (bufin_rpos < sizeof (struct GNUNET_MessageHeader)) + continue; + hdr = (struct GNUNET_MessageHeader *) bufin; + if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_DNS_HELPER) + { + fprintf (stderr, "protocol violation!\n"); + return; + } + if (ntohs (hdr->size) > bufin_rpos) + continue; + bufin_read = bufin + sizeof (struct GNUNET_MessageHeader); + bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader); + bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader); + } + } + else if (FD_ISSET (fd_tun, &fds_w)) + { + ssize_t written = write (fd_tun, bufin_read, bufin_size); + + if (-1 == written) + { + if ( (errno == EINTR) || + (errno == EAGAIN) ) + continue; + fprintf (stderr, "write-error to tun: %s\n", strerror (errno)); + return; + } + if (0 == written) + { + fprintf (stderr, "write returned 0\n"); + return; + } + { + bufin_size -= written; + bufin_read += written; + if (0 == bufin_size) + { + memmove (bufin, bufin_read, bufin_rpos); + bufin_read = NULL; /* start reading again */ + bufin_size = 0; + goto PROCESS_BUFFER; + } + } + } + } + } +} + + +/** + * Main function of "gnunet-helper-dns", which opens a VPN tunnel interface, + * redirects all outgoing DNS traffic (except from the specified port) to that + * interface and then passes traffic from and to the interface via stdin/stdout. + * + * Once stdin/stdout close or have other errors, the tunnel is closed and the + * DNS traffic redirection is stopped. + * + * @param argc number of arguments + * @param argv 0: binary name (should be "gnunet-helper-vpn") + * 1: tunnel interface name (typically "gnunet-dns") + * 2: IPv6 address for the tunnel ("FE80::1") + * 3: IPv6 netmask length in bits ("64") + * 4: IPv4 address for the tunnel ("1.2.3.4") + * 5: IPv4 netmask ("255.255.0.0") + * @return 0 on success, otherwise code indicating type of error: + * 1 wrong number of arguments + * 2 invalid arguments (i.e. port number / prefix length wrong) + * 3 iptables not executable + * 4 ip not executable + * 5 failed to initialize tunnel interface + * 6 failed to initialize control pipe + * 8 failed to change routing table, cleanup successful + * 9-23 failed to change routing table and failed to undo some changes to routing table + * 24 failed to drop privs + * 25-39 failed to drop privs and then failed to undo some changes to routing table + * 40 failed to regain privs + * 41-55 failed to regain prisv and then failed to undo some changes to routing table + * 255 failed to handle kill signal properly + */ +int +main (int argc, char *const*argv) +{ + int r; + char dev[IFNAMSIZ]; + char mygid[32]; + int fd_tun; + + if (6 != argc) + { + fprintf (stderr, "Fatal: must supply 6 arguments!\n"); + return 1; + } + + /* verify that the binaries were care about are executable */ + if (0 == access ("/sbin/iptables", X_OK)) + sbin_iptables = "/sbin/iptables"; + else if (0 == access ("/usr/sbin/iptables", X_OK)) + sbin_iptables = "/usr/sbin/iptables"; + else + { + fprintf (stderr, + "Fatal: executable iptables not found in approved directories: %s\n", + strerror (errno)); + return 3; + } + if (0 == access ("/sbin/ip", X_OK)) + sbin_ip = "/sbin/ip"; + else if (0 == access ("/usr/sbin/ip", X_OK)) + sbin_ip = "/usr/sbin/ip"; + else + { + fprintf (stderr, + "Fatal: executable ip not found in approved directories: %s\n", + strerror (errno)); + return 4; + } + + /* setup 'mygid' string */ + snprintf (mygid, sizeof (mygid), "%d", (int) getegid()); + + /* do not die on SIGPIPE */ + if (SIG_ERR == signal (SIGPIPE, SIG_IGN)) + { + fprintf (stderr, "Failed to protect against SIGPIPE: %s\n", + strerror (errno)); + return 7; + } + + /* setup pipe to shutdown nicely on SIGINT */ + if (0 != pipe (cpipe)) + { + fprintf (stderr, + "Fatal: could not setup control pipe: %s\n", + strerror (errno)); + return 6; + } + if (cpipe[0] >= FD_SETSIZE) + { + fprintf (stderr, "Pipe file descriptor to large: %d", cpipe[0]); + (void) close (cpipe[0]); + (void) close (cpipe[1]); + return 6; + } + { + /* make pipe non-blocking, as we theoretically could otherwise block + in the signal handler */ + int flags = fcntl (cpipe[1], F_GETFL); + if (-1 == flags) + { + fprintf (stderr, "Failed to read flags for pipe: %s", strerror (errno)); + (void) close (cpipe[0]); + (void) close (cpipe[1]); + return 6; + } + flags |= O_NONBLOCK; + if (0 != fcntl (cpipe[1], F_SETFL, flags)) + { + fprintf (stderr, "Failed to make pipe non-blocking: %s", strerror (errno)); + (void) close (cpipe[0]); + (void) close (cpipe[1]); + return 6; + } + } + if ( (SIG_ERR == signal (SIGTERM, &signal_handler)) || + (SIG_ERR == signal (SIGINT, &signal_handler)) || + (SIG_ERR == signal (SIGHUP, &signal_handler)) ) + { + fprintf (stderr, + "Fatal: could not initialize signal handler: %s\n", + strerror (errno)); + (void) close (cpipe[0]); + (void) close (cpipe[1]); + return 7; + } + + + /* get interface name */ + strncpy (dev, argv[1], IFNAMSIZ); + dev[IFNAMSIZ - 1] = '\0'; + + /* now open virtual interface (first part that requires root) */ + if (-1 == (fd_tun = init_tun (dev))) + { + fprintf (stderr, "Fatal: could not initialize tun-interface\n"); + (void) signal (SIGTERM, SIG_IGN); + (void) signal (SIGINT, SIG_IGN); + (void) signal (SIGHUP, SIG_IGN); + (void) close (cpipe[0]); + (void) close (cpipe[1]); + return 5; + } + + /* now set interface addresses */ + { + const char *address = argv[2]; + long prefix_len = atol (argv[3]); + + if ((prefix_len < 1) || (prefix_len > 127)) + { + fprintf (stderr, "Fatal: prefix_len out of range\n"); + (void) signal (SIGTERM, SIG_IGN); + (void) signal (SIGINT, SIG_IGN); + (void) signal (SIGHUP, SIG_IGN); + (void) close (cpipe[0]); + (void) close (cpipe[1]); + return 2; + } + set_address6 (dev, address, prefix_len); + } + + { + const char *address = argv[4]; + const char *mask = argv[5]; + + set_address4 (dev, address, mask); + } + + /* update routing tables -- next part why we need SUID! */ + /* Forward everything from our EGID (which should only be held + by the 'gnunet-service-dns') and with destination + to port 53 on UDP, without hijacking */ + r = 8; /* failed to fully setup routing table */ + { + char *const mangle_args[] = + { + "iptables", "-m", "owner", "-t", "mangle", "-I", "OUTPUT", "1", "-p", + "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j", + "ACCEPT", NULL + }; + if (0 != fork_and_exec (sbin_iptables, mangle_args)) + goto cleanup_rest; + } + /* Mark all of the other DNS traffic using our mark DNS_MARK */ + { + char *const mark_args[] = + { + "iptables", "-t", "mangle", "-I", "OUTPUT", "2", "-p", + "udp", "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, + NULL + }; + if (0 != fork_and_exec (sbin_iptables, mark_args)) + goto cleanup_mangle_1; + } + /* Forward all marked DNS traffic to our DNS_TABLE */ + { + char *const forward_args[] = + { + "ip", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL + }; + if (0 != fork_and_exec (sbin_ip, forward_args)) + goto cleanup_mark_2; + } + /* Finally, add rule in our forwarding table to pass to our virtual interface */ + { + char *const route_args[] = + { + "ip", "route", "add", "default", "dev", dev, + "table", DNS_TABLE, NULL + }; + if (0 != fork_and_exec (sbin_ip, route_args)) + goto cleanup_forward_3; + } + + /* drop privs *except* for the saved UID; this is not perfect, but better + than doing nothing */ + uid_t uid = getuid (); +#ifdef HAVE_SETRESUID + if (0 != setresuid (uid, uid, 0)) + { + fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); + r = 24; + goto cleanup_route_4; + } +#else + /* Note: no 'setuid' here as we must keep our saved UID as root */ + if (0 != seteuid (uid)) + { + fprintf (stderr, "Failed to seteuid: %s\n", strerror (errno)); + r = 24; + goto cleanup_route_4; + } +#endif + + r = 0; /* did fully setup routing table (if nothing else happens, we were successful!) */ + + /* now forward until we hit a problem */ + run (fd_tun); + + /* now need to regain privs so we can remove the firewall rules we added! */ +#ifdef HAVE_SETRESUID + if (0 != setresuid (uid, 0, 0)) + { + fprintf (stderr, "Failed to setresuid back to root: %s\n", strerror (errno)); + r = 40; + goto cleanup_route_4; + } +#else + if (0 != seteuid (0)) + { + fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno)); + r = 40; + goto cleanup_route_4; + } +#endif + + /* update routing tables again -- this is why we could not fully drop privs */ + /* now undo updating of routing tables; normal exit or clean-up-on-error case */ + cleanup_route_4: + { + char *const route_clean_args[] = + { + "ip", "route", "del", "default", "dev", dev, + "table", DNS_TABLE, NULL + }; + if (0 != fork_and_exec (sbin_ip, route_clean_args)) + r += 1; + } + cleanup_forward_3: + { + char *const forward_clean_args[] = + { + "ip", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL + }; + if (0 != fork_and_exec (sbin_ip, forward_clean_args)) + r += 2; + } + cleanup_mark_2: + { + char *const mark_clean_args[] = + { + "iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", + "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, NULL + }; + if (0 != fork_and_exec (sbin_iptables, mark_clean_args)) + r += 4; + } + cleanup_mangle_1: + { + char *const mangle_clean_args[] = + { + "iptables", "-m", "owner", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", + "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT", + NULL + }; + if (0 != fork_and_exec (sbin_iptables, mangle_clean_args)) + r += 8; + } + + cleanup_rest: + /* close virtual interface */ + (void) close (fd_tun); + /* remove signal handler so we can close the pipes */ + (void) signal (SIGTERM, SIG_IGN); + (void) signal (SIGINT, SIG_IGN); + (void) signal (SIGHUP, SIG_IGN); + (void) close (cpipe[0]); + (void) close (cpipe[1]); + return r; +} + +/* end of gnunet-helper-dns.c */ diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c new file mode 100644 index 0000000..1f48b10 --- /dev/null +++ b/src/dns/gnunet-service-dns.c @@ -0,0 +1,1667 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dns/gnunet-service-dns.c + * @brief service to intercept and modify DNS queries (and replies) of this system + * @author Christian Grothoff + * + * For "secure" interaction with the legacy DNS system, we permit + * replies only to arrive within a 5s window (and they must match + * ports, IPs and request IDs). Furthermore, we let the OS pick a + * source port, opening up to 128 sockets per address family (IPv4 or + * IPv6). Those sockets are closed if they are not in use for 5s + * (which means they will be freshly randomized afterwards). For new + * requests, we pick a random slot in the array with 128 socket slots + * (and re-use an existing socket if the slot is still in use). Thus + * each request will be given one of 128 random source ports, and the + * 128 random source ports will also change "often" (less often if the + * system is very busy, each time if we are mostly idle). At the same + * time, the system will never use more than 256 UDP sockets. + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_applications.h" +#include "gnunet_constants.h" +#include "gnunet_protocols.h" +#include "gnunet_signatures.h" +#include "dns.h" +#include "gnunet_dns_service.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_mesh_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_tun_lib.h" + + +/** + * Timeout for an external (Internet-DNS) DNS resolution + */ +#define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +/** + * How many DNS sockets do we open at most at the same time? + * (technical socket maximum is this number x2 for IPv4+IPv6) + */ +#define DNS_SOCKET_MAX 128 + +/** + * Phases each request goes through. + */ +enum RequestPhase +{ + /** + * Request has just been received. + */ + RP_INIT, + + /** + * Showing the request to all monitor clients. If + * client list is empty, will enter QUERY phase. + */ + RP_REQUEST_MONITOR, + + /** + * Showing the request to PRE-RESOLUTION clients to find an answer. + * If client list is empty, will trigger global DNS request. + */ + RP_QUERY, + + /** + * Global Internet query is now pending. + */ + RP_INTERNET_DNS, + + /** + * Client (or global DNS request) has resulted in a response. + * Forward to all POST-RESOLUTION clients. If client list is empty, + * will enter RESPONSE_MONITOR phase. + */ + RP_MODIFY, + + /** + * Showing the request to all monitor clients. If + * client list is empty, give the result to the hijacker (and be done). + */ + RP_RESPONSE_MONITOR, + + /** + * Some client has told us to drop the request. + */ + RP_DROP +}; + + +/** + * Entry we keep for each client. + */ +struct ClientRecord +{ + /** + * Kept in doubly-linked list. + */ + struct ClientRecord *next; + + /** + * Kept in doubly-linked list. + */ + struct ClientRecord *prev; + + /** + * Handle to the client. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Flags for the client. + */ + enum GNUNET_DNS_Flags flags; + +}; + + +/** + * UDP socket we are using for sending DNS requests to the Internet. + */ +struct RequestSocket +{ + + /** + * UDP socket we use for this request for IPv4 + */ + struct GNUNET_NETWORK_Handle *dnsout4; + + /** + * UDP socket we use for this request for IPv6 + */ + struct GNUNET_NETWORK_Handle *dnsout6; + + /** + * Task for reading from dnsout4 and dnsout6. + */ + GNUNET_SCHEDULER_TaskIdentifier read_task; + + /** + * When should this socket be closed? + */ + struct GNUNET_TIME_Absolute timeout; +}; + + +/** + * Entry we keep for each active request. + */ +struct RequestRecord +{ + + /** + * List of clients that still need to see this request (each entry + * is set to NULL when the client is done). + */ + struct ClientRecord **client_wait_list; + + /** + * Payload of the UDP packet (the UDP payload), can be either query + * or already the response. + */ + char *payload; + + /** + * Socket we are using to transmit this request (must match if we receive + * a response). Must NOT be freed as part of this request record (as it + * might be shared with other requests). + */ + struct GNUNET_NETWORK_Handle *dnsout; + + /** + * Source address of the original request (for sending response). + */ + struct sockaddr_storage src_addr; + + /** + * Destination address of the original request (for potential use as exit). + */ + struct sockaddr_storage dst_addr; + + /** + * When should this request time out? + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * ID of this request, also basis for hashing. Lowest 16 bit will + * be our message ID when doing a global DNS request and our index + * into the 'requests' array. + */ + uint64_t request_id; + + /** + * Number of bytes in payload. + */ + size_t payload_length; + + /** + * Length of the client wait list. + */ + unsigned int client_wait_list_length; + + /** + * In which phase this this request? + */ + enum RequestPhase phase; + +}; + + +/** + * State we keep for each DNS tunnel that terminates at this node. + */ +struct TunnelState +{ + + /** + * Associated MESH tunnel. + */ + struct GNUNET_MESH_Tunnel *tunnel; + + /** + * Active request for sending a reply. + */ + struct GNUNET_MESH_TransmitHandle *th; + + /** + * DNS reply ready for transmission. + */ + char *reply; + + /** + * Socket we are using to transmit this request (must match if we receive + * a response). Must NOT be freed as part of this request record (as it + * might be shared with other requests). + */ + struct GNUNET_NETWORK_Handle *dnsout; + + /** + * Address we sent the DNS request to. + */ + struct sockaddr_storage addr; + + /** + * When should this request time out? + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Number of bytes in 'addr'. + */ + socklen_t addrlen; + + /** + * Number of bytes in 'reply'. + */ + size_t reply_length; + + /** + * Original DNS request ID as used by the client. + */ + uint16_t original_id; + + /** + * DNS request ID that we used for forwarding. + */ + uint16_t my_id; +}; + + +/** + * The configuration to use + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Statistics. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * Handle to DNS hijacker helper process ("gnunet-helper-dns"). + */ +static struct GNUNET_HELPER_Handle *hijacker; + +/** + * Command-line arguments we are giving to the hijacker process. + */ +static char *helper_argv[7]; + +/** + * Head of DLL of clients we consult. + */ +static struct ClientRecord *clients_head; + +/** + * Tail of DLL of clients we consult. + */ +static struct ClientRecord *clients_tail; + +/** + * Our notification context. + */ +static struct GNUNET_SERVER_NotificationContext *nc; + +/** + * Array of all open requests. + */ +static struct RequestRecord requests[UINT16_MAX + 1]; + +/** + * Array of all open requests from tunnels. + */ +static struct TunnelState *tunnels[UINT16_MAX + 1]; + +/** + * Array of all open sockets for DNS requests. + */ +static struct RequestSocket sockets[DNS_SOCKET_MAX]; + +/** + * Generator for unique request IDs. + */ +static uint64_t request_id_gen; + +/** + * IP address to use for the DNS server if we are a DNS exit service + * (for VPN via mesh); otherwise NULL. + */ +static char *dns_exit; + +/** + * Handle to the MESH service (for receiving DNS queries), or NULL + * if we are not a DNS exit. + */ +static struct GNUNET_MESH_Handle *mesh; + + +/** + * We're done with a RequestSocket, close it for now. + * + * @param rs request socket to clean up + */ +static void +cleanup_rs (struct RequestSocket *rs) +{ + if (NULL != rs->dnsout4) + { + GNUNET_NETWORK_socket_close (rs->dnsout4); + rs->dnsout4 = NULL; + } + if (NULL != rs->dnsout6) + { + GNUNET_NETWORK_socket_close (rs->dnsout6); + rs->dnsout6 = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != rs->read_task) + { + GNUNET_SCHEDULER_cancel (rs->read_task); + rs->read_task = GNUNET_SCHEDULER_NO_TASK; + } +} + + +/** + * We're done processing a DNS request, free associated memory. + * + * @param rr request to clean up + */ +static void +cleanup_rr (struct RequestRecord *rr) +{ + GNUNET_free_non_null (rr->payload); + rr->payload = NULL; + rr->payload_length = 0; + GNUNET_array_grow (rr->client_wait_list, + rr->client_wait_list_length, + 0); +} + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +cleanup_task (void *cls GNUNET_UNUSED, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned int i; + + GNUNET_HELPER_stop (hijacker); + hijacker = NULL; + for (i=0;i<7;i++) + GNUNET_free_non_null (helper_argv[i]); + for (i=0;i<=UINT16_MAX;i++) + cleanup_rr (&requests[i]); + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + stats = NULL; + } + if (NULL != dns_exit) + { + GNUNET_free (dns_exit); + dns_exit = NULL; + } + if (NULL != mesh) + { + GNUNET_MESH_disconnect(mesh); + mesh = NULL; + } +} + + +/** + * Open source port for sending DNS requests + * + * @param af AF_INET or AF_INET6 + * @return GNUNET_OK on success + */ +static struct GNUNET_NETWORK_Handle * +open_socket (int af) +{ + struct sockaddr_in a4; + struct sockaddr_in6 a6; + struct sockaddr *sa; + socklen_t alen; + struct GNUNET_NETWORK_Handle *ret; + + ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0); + if (NULL == ret) + return NULL; + switch (af) + { + case AF_INET: + memset (&a4, 0, alen = sizeof (struct sockaddr_in)); + sa = (struct sockaddr *) &a4; + break; + case AF_INET6: + memset (&a6, 0, alen = sizeof (struct sockaddr_in6)); + sa = (struct sockaddr *) &a6; + break; + default: + GNUNET_break (0); + GNUNET_NETWORK_socket_close (ret); + return NULL; + } + sa->sa_family = af; + if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret, + sa, + alen)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not bind to any port: %s\n"), + STRERROR (errno)); + GNUNET_NETWORK_socket_close (ret); + return NULL; + } + return ret; +} + + +/** + * We're done with some request, finish processing. + * + * @param rr request send to the network or just clean up. + */ +static void +request_done (struct RequestRecord *rr) +{ + struct GNUNET_MessageHeader *hdr; + size_t reply_len; + uint16_t source_port; + uint16_t destination_port; + + GNUNET_array_grow (rr->client_wait_list, + rr->client_wait_list_length, + 0); + if (RP_RESPONSE_MONITOR != rr->phase) + { + /* no response, drop */ + cleanup_rr (rr); + return; + } + + /* send response via hijacker */ + reply_len = sizeof (struct GNUNET_MessageHeader); + reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader); + switch (rr->src_addr.ss_family) + { + case AF_INET: + reply_len += sizeof (struct GNUNET_TUN_IPv4Header); + break; + case AF_INET6: + reply_len += sizeof (struct GNUNET_TUN_IPv6Header); + break; + default: + GNUNET_break (0); + cleanup_rr (rr); + return; + } + reply_len += sizeof (struct GNUNET_TUN_UdpHeader); + reply_len += rr->payload_length; + if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + /* response too big, drop */ + GNUNET_break (0); /* how can this be? */ + cleanup_rr(rr); + return; + } + { + char buf[reply_len]; + size_t off; + struct GNUNET_TUN_IPv4Header ip4; + struct GNUNET_TUN_IPv6Header ip6; + + /* first, GNUnet message header */ + hdr = (struct GNUNET_MessageHeader*) buf; + hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); + hdr->size = htons ((uint16_t) reply_len); + off = sizeof (struct GNUNET_MessageHeader); + + /* first, TUN header */ + { + struct GNUNET_TUN_Layer2PacketHeader tun; + + tun.flags = htons (0); + if (rr->src_addr.ss_family == AF_INET) + tun.proto = htons (ETH_P_IPV4); + else + tun.proto = htons (ETH_P_IPV6); + memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader)); + off += sizeof (struct GNUNET_TUN_Layer2PacketHeader); + } + + /* now IP header */ + switch (rr->src_addr.ss_family) + { + case AF_INET: + { + struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr; + struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr; + + source_port = dst->sin_port; + destination_port = src->sin_port; + GNUNET_TUN_initialize_ipv4_header (&ip4, + IPPROTO_UDP, + reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header), + &dst->sin_addr, + &src->sin_addr); + memcpy (&buf[off], &ip4, sizeof (ip4)); + off += sizeof (ip4); + } + break; + case AF_INET6: + { + struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr; + struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr; + + source_port = dst->sin6_port; + destination_port = src->sin6_port; + GNUNET_TUN_initialize_ipv6_header (&ip6, + IPPROTO_UDP, + reply_len - sizeof (struct GNUNET_TUN_IPv6Header), + &dst->sin6_addr, + &src->sin6_addr); + memcpy (&buf[off], &ip6, sizeof (ip6)); + off += sizeof (ip6); + } + break; + default: + GNUNET_assert (0); + } + + /* now UDP header */ + { + struct GNUNET_TUN_UdpHeader udp; + + udp.source_port = source_port; + udp.destination_port = destination_port; + udp.len = htons (reply_len - off); + if (AF_INET == rr->src_addr.ss_family) + GNUNET_TUN_calculate_udp4_checksum (&ip4, + &udp, + rr->payload, + rr->payload_length); + else + GNUNET_TUN_calculate_udp6_checksum (&ip6, + &udp, + rr->payload, + rr->payload_length); + memcpy (&buf[off], &udp, sizeof (udp)); + off += sizeof (udp); + } + + /* now DNS payload */ + { + memcpy (&buf[off], rr->payload, rr->payload_length); + off += rr->payload_length; + } + /* final checks & sending */ + GNUNET_assert (off == reply_len); + GNUNET_HELPER_send (hijacker, + hdr, + GNUNET_YES, + NULL, NULL); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS requests answered via TUN interface"), + 1, GNUNET_NO); + } + /* clean up, we're done */ + cleanup_rr (rr); +} + + +/** + * Show the payload of the given request record to the client + * (and wait for a response). + * + * @param rr request to send to client + * @param client client to send the response to + */ +static void +send_request_to_client (struct RequestRecord *rr, + struct GNUNET_SERVER_Client *client) +{ + char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length]; + struct GNUNET_DNS_Request *req; + + if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + cleanup_rr (rr); + return; + } + req = (struct GNUNET_DNS_Request*) buf; + req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST); + req->header.size = htons (sizeof (buf)); + req->reserved = htonl (0); + req->request_id = rr->request_id; + memcpy (&req[1], rr->payload, rr->payload_length); + GNUNET_SERVER_notification_context_unicast (nc, + client, + &req->header, + GNUNET_NO); +} + + +/** + * Read a DNS response from the (unhindered) UDP-Socket + * + * @param cls socket to read from + * @param tc scheduler context (must be shutdown or read ready) + */ +static void +read_response (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Get a socket of the specified address family to send out a + * UDP DNS request to the Internet. + * + * @param af desired address family + * @return NULL on error (given AF not "supported") + */ +static struct GNUNET_NETWORK_Handle * +get_request_socket (int af) +{ + struct RequestSocket *rs; + struct GNUNET_NETWORK_FDSet *rset; + static struct GNUNET_NETWORK_Handle *ret; + + rs = &sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, + DNS_SOCKET_MAX)]; + rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT); + switch (af) + { + case AF_INET: + if (NULL == rs->dnsout4) + rs->dnsout4 = open_socket (AF_INET); + ret = rs->dnsout4; + break; + case AF_INET6: + if (NULL == rs->dnsout6) + rs->dnsout6 = open_socket (AF_INET6); + ret = rs->dnsout6; + break; + default: + return NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != rs->read_task) + { + GNUNET_SCHEDULER_cancel (rs->read_task); + rs->read_task = GNUNET_SCHEDULER_NO_TASK; + } + if ( (NULL == rs->dnsout4) && + (NULL == rs->dnsout6) ) + return NULL; + rset = GNUNET_NETWORK_fdset_create (); + if (NULL != rs->dnsout4) + GNUNET_NETWORK_fdset_set (rset, rs->dnsout4); + if (NULL != rs->dnsout6) + GNUNET_NETWORK_fdset_set (rset, rs->dnsout6); + rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + REQUEST_TIMEOUT, + rset, + NULL, + &read_response, rs); + GNUNET_NETWORK_fdset_destroy (rset); + return ret; +} + + +/** + * A client has completed its processing for this + * request. Move on. + * + * @param rr request to process further + */ +static void +next_phase (struct RequestRecord *rr) +{ + struct ClientRecord *cr; + int nz; + unsigned int j; + socklen_t salen; + + if (rr->phase == RP_DROP) + { + cleanup_rr (rr); + return; + } + nz = -1; + for (j=0;jclient_wait_list_length;j++) + { + if (NULL != rr->client_wait_list[j]) + { + nz = (int) j; + break; + } + } + if (-1 != nz) + { + send_request_to_client (rr, rr->client_wait_list[nz]->client); + return; + } + /* done with current phase, advance! */ + switch (rr->phase) + { + case RP_INIT: + rr->phase = RP_REQUEST_MONITOR; + for (cr = clients_head; NULL != cr; cr = cr->next) + { + if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR)) + GNUNET_array_append (rr->client_wait_list, + rr->client_wait_list_length, + cr); + } + next_phase (rr); + return; + case RP_REQUEST_MONITOR: + rr->phase = RP_QUERY; + for (cr = clients_head; NULL != cr; cr = cr->next) + { + if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION)) + GNUNET_array_append (rr->client_wait_list, + rr->client_wait_list_length, + cr); + } + next_phase (rr); + return; + case RP_QUERY: + switch (rr->dst_addr.ss_family) + { + case AF_INET: + salen = sizeof (struct sockaddr_in); + break; + case AF_INET6: + salen = sizeof (struct sockaddr_in6); + break; + default: + GNUNET_assert (0); + } + + rr->phase = RP_INTERNET_DNS; + rr->dnsout = get_request_socket (rr->dst_addr.ss_family); + if (NULL == rr->dnsout) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS exit failed (failed to open socket)"), + 1, GNUNET_NO); + cleanup_rr (rr); + return; + } + GNUNET_NETWORK_socket_sendto (rr->dnsout, + rr->payload, + rr->payload_length, + (struct sockaddr*) &rr->dst_addr, + salen); + rr->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT); + return; + case RP_INTERNET_DNS: + rr->phase = RP_MODIFY; + for (cr = clients_head; NULL != cr; cr = cr->next) + { + if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION)) + GNUNET_array_append (rr->client_wait_list, + rr->client_wait_list_length, + cr); + } + next_phase (rr); + return; + case RP_MODIFY: + rr->phase = RP_RESPONSE_MONITOR; + for (cr = clients_head; NULL != cr; cr = cr->next) + { + if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR)) + GNUNET_array_append (rr->client_wait_list, + rr->client_wait_list_length, + cr); + } + next_phase (rr); + return; + case RP_RESPONSE_MONITOR: + request_done (rr); + break; + case RP_DROP: + cleanup_rr (rr); + break; + default: + GNUNET_break (0); + cleanup_rr (rr); + break; + } +} + + +/** + * A client disconnected, clean up after it. + * + * @param cls unused + * @param client handle of client that disconnected + */ +static void +client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct ClientRecord *cr; + struct RequestRecord *rr; + unsigned int i; + unsigned int j; + + for (cr = clients_head; NULL != cr; cr = cr->next) + { + if (cr->client == client) + { + GNUNET_SERVER_client_drop (client); + GNUNET_CONTAINER_DLL_remove (clients_head, + clients_tail, + cr); + for (i=0;iclient_wait_list_length) + continue; /* not in use */ + for (j=0;jclient_wait_list_length;j++) + { + if (rr->client_wait_list[j] == cr) + { + rr->client_wait_list[j] = NULL; + next_phase (rr); + } + } + } + GNUNET_free (cr); + return; + } + } +} + + +/** + * We got a reply from DNS for a request of a MESH tunnel. Send it + * via the tunnel (after changing the request ID back). + * + * @param cls the 'struct TunnelState' + * @param size number of bytes available in buf + * @param buf where to copy the reply + * @return number of bytes written to buf + */ +static size_t +transmit_reply_to_mesh (void *cls, + size_t size, + void *buf) +{ + struct TunnelState *ts = cls; + size_t off; + size_t ret; + char *cbuf = buf; + struct GNUNET_MessageHeader hdr; + struct GNUNET_TUN_DnsHeader dns; + + ts->th = NULL; + GNUNET_assert (ts->reply != NULL); + if (size == 0) + return 0; + ret = sizeof (struct GNUNET_MessageHeader) + ts->reply_length; + GNUNET_assert (ret <= size); + hdr.size = htons (ret); + hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET); + memcpy (&dns, ts->reply, sizeof (dns)); + dns.id = ts->original_id; + off = 0; + memcpy (&cbuf[off], &hdr, sizeof (hdr)); + off += sizeof (hdr); + memcpy (&cbuf[off], &dns, sizeof (dns)); + off += sizeof (dns); + memcpy (&cbuf[off], &ts->reply[sizeof (dns)], ts->reply_length - sizeof (dns)); + off += ts->reply_length - sizeof (dns); + GNUNET_free (ts->reply); + ts->reply = NULL; + ts->reply_length = 0; + GNUNET_assert (ret == off); + return ret; +} + + +/** + * Actually do the reading of a DNS packet from our UDP socket and see + * if we have a valid, matching, pending request. + * + * @param dnsout socket to read from + * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket) + */ +static int +do_dns_read (struct GNUNET_NETWORK_Handle *dnsout) +{ + struct sockaddr_storage addr; + socklen_t addrlen; + struct GNUNET_TUN_DnsHeader *dns; + struct RequestRecord *rr; + struct TunnelState *ts; + ssize_t r; + int len; + +#ifndef MINGW + if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) + { + /* conservative choice: */ + len = UINT16_MAX; + } +#else + /* port the code above? */ + len = UINT16_MAX; +#endif + + { + unsigned char buf[len]; + + addrlen = sizeof (addr); + memset (&addr, 0, sizeof (addr)); + r = GNUNET_NETWORK_socket_recvfrom (dnsout, + buf, sizeof (buf), + (struct sockaddr*) &addr, &addrlen); + if (-1 == r) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); + GNUNET_NETWORK_socket_close (dnsout); + return GNUNET_SYSERR; + } + if (sizeof (struct GNUNET_TUN_DnsHeader) > r) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Received DNS response that is too small (%u bytes)"), + r); + return GNUNET_NO; + } + dns = (struct GNUNET_TUN_DnsHeader *) buf; + /* Handle case that this is a reply to a request from a MESH DNS tunnel */ + ts = tunnels[dns->id]; + if ( (NULL == ts) || + (ts->dnsout != dnsout) || + (addrlen != ts->addrlen) || + (0 != memcmp (&ts->addr, + &addr, + addrlen)) || + (0 == GNUNET_TIME_absolute_get_remaining (ts->timeout).rel_value) ) + ts = NULL; /* DNS responder address missmatch */ + if (NULL != ts) + { + tunnels[dns->id] = NULL; + GNUNET_free_non_null (ts->reply); + ts->reply = GNUNET_malloc (r); + ts->reply_length = r; + memcpy (ts->reply, dns, r); + if (ts->th != NULL) + GNUNET_MESH_notify_transmit_ready_cancel (ts->th); + ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, + GNUNET_NO, 0, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, + sizeof (struct GNUNET_MessageHeader) + r, + &transmit_reply_to_mesh, + ts); + } + /* Handle case that this is a reply to a local request (intercepted from TUN interface) */ + rr = &requests[dns->id]; + if ( (rr->phase != RP_INTERNET_DNS) || + (rr->dnsout != dnsout) || + (0 != memcmp (&rr->dst_addr, + &addr, + addrlen)) || + (0 == GNUNET_TIME_absolute_get_remaining (rr->timeout).rel_value) ) + { + if (NULL == ts) + { + /* unexpected / bogus reply */ + GNUNET_STATISTICS_update (stats, + gettext_noop ("# External DNS response discarded (no matching request)"), + 1, GNUNET_NO); + } + return GNUNET_NO; + } + GNUNET_free_non_null (rr->payload); + rr->payload = GNUNET_malloc (r); + memcpy (rr->payload, buf, r); + rr->payload_length = r; + next_phase (rr); + } + return GNUNET_OK; +} + + +/** + * Read a DNS response from the (unhindered) UDP-Socket + * + * @param cls socket to read from + * @param tc scheduler context (must be shutdown or read ready) + */ +static void +read_response (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct RequestSocket *rs = cls; + struct GNUNET_NETWORK_FDSet *rset; + + rs->read_task = GNUNET_SCHEDULER_NO_TASK; + if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) + { + /* timeout or shutdown */ + cleanup_rs (rs); + return; + } + /* read and process ready sockets */ + if ((NULL != rs->dnsout4) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) && + (GNUNET_SYSERR == do_dns_read (rs->dnsout4))) + rs->dnsout4 = NULL; + if ((NULL != rs->dnsout6) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) && + (GNUNET_SYSERR == do_dns_read (rs->dnsout6))) + rs->dnsout6 = NULL; + + /* re-schedule read task */ + rset = GNUNET_NETWORK_fdset_create (); + if (NULL != rs->dnsout4) + GNUNET_NETWORK_fdset_set (rset, rs->dnsout4); + if (NULL != rs->dnsout6) + GNUNET_NETWORK_fdset_set (rset, rs->dnsout6); + rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_absolute_get_remaining (rs->timeout), + rset, + NULL, + &read_response, rs); + GNUNET_NETWORK_fdset_destroy (rset); +} + + +/** + * We got a new client. Make sure all new DNS requests pass by its desk. + * + * @param cls unused + * @param client the new client + * @param message the init message (unused) + */ +static void +handle_client_init (void *cls GNUNET_UNUSED, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct ClientRecord *cr; + const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message; + + cr = GNUNET_malloc (sizeof (struct ClientRecord)); + cr->client = client; + cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags); + GNUNET_SERVER_client_keep (client); + GNUNET_CONTAINER_DLL_insert (clients_head, + clients_tail, + cr); + GNUNET_SERVER_notification_context_add (nc, client); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * We got a response from a client. + * + * @param cls unused + * @param client the client + * @param message the response + */ +static void +handle_client_response (void *cls GNUNET_UNUSED, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_DNS_Response *resp; + struct RequestRecord *rr; + unsigned int i; + uint16_t msize; + uint16_t off; + + msize = ntohs (message->size); + if (msize < sizeof (struct GNUNET_DNS_Response)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + resp = (const struct GNUNET_DNS_Response*) message; + off = (uint16_t) resp->request_id; + rr = &requests[off]; + if (rr->request_id != resp->request_id) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Client response discarded (no matching request)"), + 1, GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + for (i=0;iclient_wait_list_length;i++) + { + if (NULL == rr->client_wait_list[i]) + continue; + if (rr->client_wait_list[i]->client != client) + continue; + rr->client_wait_list[i] = NULL; + switch (ntohl (resp->drop_flag)) + { + case 0: /* drop */ + rr->phase = RP_DROP; + break; + case 1: /* no change */ + break; + case 2: /* update */ + msize -= sizeof (struct GNUNET_DNS_Response); + if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) || + (RP_REQUEST_MONITOR == rr->phase) || + (RP_RESPONSE_MONITOR == rr->phase) ) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + next_phase (rr); + return; + } + GNUNET_free_non_null (rr->payload); +#if DEBUG_DNS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Changing DNS reply according to client specifications\n")); +#endif + rr->payload = GNUNET_malloc (msize); + rr->payload_length = msize; + memcpy (rr->payload, &resp[1], msize); + if (rr->phase == RP_QUERY) + { + /* clear wait list, we're moving to MODIFY phase next */ + GNUNET_array_grow (rr->client_wait_list, + rr->client_wait_list_length, + 0); + } + /* if query changed to answer, move past DNS resolution phase... */ + if ( (RP_QUERY == rr->phase) && + (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) && + ((struct GNUNET_DNSPARSER_Flags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1) + { + rr->phase = RP_INTERNET_DNS; + GNUNET_array_grow (rr->client_wait_list, + rr->client_wait_list_length, + 0); + } + break; + } + next_phase (rr); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + /* odd, client was not on our list for the request, that ought + to be an error */ + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); +} + + +/** + * Functions with this signature are called whenever a complete + * message is received by the tokenizer from the DNS hijack process. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message, a DNS request we should handle + */ +static void +process_helper_messages (void *cls GNUNET_UNUSED, void *client, + const struct GNUNET_MessageHeader *message) +{ + uint16_t msize; + const struct GNUNET_TUN_Layer2PacketHeader *tun; + const struct GNUNET_TUN_IPv4Header *ip4; + const struct GNUNET_TUN_IPv6Header *ip6; + const struct GNUNET_TUN_UdpHeader *udp; + const struct GNUNET_TUN_DnsHeader *dns; + struct RequestRecord *rr; + struct sockaddr_in *srca4; + struct sockaddr_in6 *srca6; + struct sockaddr_in *dsta4; + struct sockaddr_in6 *dsta6; + + msize = ntohs (message->size); + if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header)) + { + /* non-IP packet received on TUN!? */ + GNUNET_break (0); + return; + } + msize -= sizeof (struct GNUNET_MessageHeader); + tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1]; + msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader); + switch (ntohs (tun->proto)) + { + case ETH_P_IPV4: + ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1]; + if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) || + (ip4->version != 4) || + (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) || + (ntohs(ip4->total_length) != msize) || + (ip4->protocol != IPPROTO_UDP) ) + { + /* non-IP/UDP packet received on TUN (or with options) */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Received malformed IPv4-UDP packet on TUN interface.\n")); + return; + } + udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1]; + msize -= sizeof (struct GNUNET_TUN_IPv4Header); + break; + case ETH_P_IPV6: + ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1]; + if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) || + (ip6->version != 6) || + (ntohs (ip6->payload_length) != msize) || + (ip6->next_header != IPPROTO_UDP) ) + { + /* non-IP/UDP packet received on TUN (or with extensions) */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Received malformed IPv6-UDP packet on TUN interface.\n")); + return; + } + udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1]; + msize -= sizeof (struct GNUNET_TUN_IPv6Header); + break; + default: + /* non-IP packet received on TUN!? */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Got non-IP packet with %u bytes and protocol %u from TUN\n"), + (unsigned int) msize, + ntohs (tun->proto)); + return; + } + if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader)) + { + /* non-DNS packet received on TUN, ignore */ + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Non-DNS UDP packet received via TUN interface"), + 1, GNUNET_NO); + return; + } + msize -= sizeof (struct GNUNET_TUN_UdpHeader); + dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1]; + rr = &requests[dns->id]; + + /* clean up from previous request */ + GNUNET_free_non_null (rr->payload); + rr->payload = NULL; + GNUNET_array_grow (rr->client_wait_list, + rr->client_wait_list_length, + 0); + + /* setup new request */ + rr->phase = RP_INIT; + switch (ntohs (tun->proto)) + { + case ETH_P_IPV4: + { + srca4 = (struct sockaddr_in*) &rr->src_addr; + dsta4 = (struct sockaddr_in*) &rr->dst_addr; + memset (srca4, 0, sizeof (struct sockaddr_in)); + memset (dsta4, 0, sizeof (struct sockaddr_in)); + srca4->sin_family = AF_INET; + dsta4->sin_family = AF_INET; + srca4->sin_addr = ip4->source_address; + dsta4->sin_addr = ip4->destination_address; + srca4->sin_port = udp->source_port; + dsta4->sin_port = udp->destination_port; +#if HAVE_SOCKADDR_IN_SIN_LEN + srca4->sin_len = sizeof (struct sockaddr_in); + dsta4->sin_len = sizeof (struct sockaddr_in); +#endif + } + break; + case ETH_P_IPV6: + { + srca6 = (struct sockaddr_in6*) &rr->src_addr; + dsta6 = (struct sockaddr_in6*) &rr->dst_addr; + memset (srca6, 0, sizeof (struct sockaddr_in6)); + memset (dsta6, 0, sizeof (struct sockaddr_in6)); + srca6->sin6_family = AF_INET6; + dsta6->sin6_family = AF_INET6; + srca6->sin6_addr = ip6->source_address; + dsta6->sin6_addr = ip6->destination_address; + srca6->sin6_port = udp->source_port; + dsta6->sin6_port = udp->destination_port; +#if HAVE_SOCKADDR_IN_SIN_LEN + srca6->sin6_len = sizeof (struct sockaddr_in6); + dsta6->sin6_len = sizeof (struct sockaddr_in6); +#endif + } + break; + default: + GNUNET_assert (0); + } + rr->payload = GNUNET_malloc (msize); + rr->payload_length = msize; + memcpy (rr->payload, dns, msize); + rr->request_id = dns->id | (request_id_gen << 16); + request_id_gen++; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS requests received via TUN interface"), + 1, GNUNET_NO); + /* start request processing state machine */ + next_phase (rr); +} + + +/** + * Process a request via mesh to perform a DNS query. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *ts = *tunnel_ctx; + const struct GNUNET_TUN_DnsHeader *dns; + size_t mlen = ntohs (message->size); + size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader); + char buf[dlen]; + struct GNUNET_TUN_DnsHeader *dout; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + struct sockaddr *so; + socklen_t salen; + + if (dlen < sizeof (struct GNUNET_TUN_DnsHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + dns = (const struct GNUNET_TUN_DnsHeader *) &message[1]; + ts->original_id = dns->id; + if (tunnels[ts->my_id] == ts) + tunnels[ts->my_id] = NULL; + ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT16_MAX + 1); + tunnels[ts->my_id] = ts; + memcpy (buf, dns, dlen); + dout = (struct GNUNET_TUN_DnsHeader*) buf; + dout->id = ts->my_id; + memset (&v4, 0, sizeof (v4)); + memset (&v6, 0, sizeof (v6)); + if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr)) + { + salen = sizeof (v4); + v4.sin_family = AF_INET; + v4.sin_port = htons (53); +#if HAVE_SOCKADDR_IN_SIN_LEN + v4.sin_len = (u_char) salen; +#endif + so = (struct sockaddr *) &v4; + ts->dnsout = get_request_socket (AF_INET); + } + else if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr)) + { + salen = sizeof (v6); + v6.sin6_family = AF_INET6; + v6.sin6_port = htons (53); +#if HAVE_SOCKADDR_IN_SIN_LEN + v6.sin6_len = (u_char) salen; +#endif + so = (struct sockaddr *) &v6; + ts->dnsout = get_request_socket (AF_INET6); + } + else + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (NULL == ts->dnsout) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Configured DNS exit `%s' is not working / valid.\n"), + dns_exit); + return GNUNET_SYSERR; + } + memcpy (&ts->addr, + so, + salen); + ts->addrlen = salen; + GNUNET_NETWORK_socket_sendto (ts->dnsout, + buf, dlen, so, salen); + ts->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT); + return GNUNET_OK; +} + + +/** + * Callback from GNUNET_MESH for new tunnels. + * + * @param cls closure + * @param tunnel new handle to the tunnel + * @param initiator peer that started the tunnel + * @param ats performance information for the tunnel + * @return initial tunnel context for the tunnel + */ +static void * +accept_dns_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED, + const struct GNUNET_ATS_Information *ats GNUNET_UNUSED) +{ + struct TunnelState *ts = GNUNET_malloc (sizeof (struct TunnelState)); + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Inbound MESH tunnels created"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received inbound tunnel from `%s'\n", + GNUNET_i2s (initiator)); + ts->tunnel = tunnel; + return ts; +} + + +/** + * Function called by mesh whenever an inbound tunnel is destroyed. + * Should clean up any associated state. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end (henceforth invalid) + * @param tunnel_ctx place where local state associated + * with the tunnel is stored + */ +static void +destroy_dns_tunnel (void *cls GNUNET_UNUSED, + const struct GNUNET_MESH_Tunnel *tunnel, + void *tunnel_ctx) +{ + struct TunnelState *ts = tunnel_ctx; + + if (tunnels[ts->my_id] == ts) + tunnels[ts->my_id] = NULL; + if (NULL != ts->th) + GNUNET_MESH_notify_transmit_ready_cancel (ts->th); + GNUNET_free_non_null (ts->reply); + GNUNET_free (ts); +} + + +/** + * @param cls closure + * @param server the initialized server + * @param cfg_ configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg_) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + /* callback, cls, type, size */ + {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, + sizeof (struct GNUNET_DNS_Register)}, + {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0}, + {NULL, NULL, 0, 0} + }; + char *ifc_name; + char *ipv4addr; + char *ipv4mask; + char *ipv6addr; + char *ipv6prefix; + struct in_addr dns_exit4; + struct in6_addr dns_exit6; + + cfg = cfg_; + stats = GNUNET_STATISTICS_create ("dns", cfg); + nc = GNUNET_SERVER_notification_context_create (server, 1); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, + cls); + if ( (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) && + ( (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "dns", + "DNS_EXIT", + &dns_exit)) || + ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) && + (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Configured to provide DNS exit, but no valid DNS server configured!\n")); + GNUNET_free_non_null (dns_exit); + dns_exit = NULL; + } + + helper_argv[0] = GNUNET_strdup ("gnunet-dns"); + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'IFNAME' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + helper_argv[1] = ifc_name; + if ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR", + &ipv6addr)) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'IPV6ADDR' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + helper_argv[2] = ipv6addr; + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX", + &ipv6prefix)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'IPV6PREFIX' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + helper_argv[3] = ipv6prefix; + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR", + &ipv4addr)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'IPV4ADDR' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + helper_argv[4] = ipv4addr; + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK", + &ipv4mask)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'IPV4MASK' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + helper_argv[5] = ipv4mask; + helper_argv[6] = NULL; + + if (NULL != dns_exit) + { + static struct GNUNET_MESH_MessageHandler mesh_handlers[] = { + {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0}, + {NULL, 0, 0} + }; + static GNUNET_MESH_ApplicationType mesh_types[] = { + GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER, + GNUNET_APPLICATION_TYPE_END + }; + mesh = GNUNET_MESH_connect (cfg, + 1, NULL, + &accept_dns_tunnel, + &destroy_dns_tunnel, + mesh_handlers, + mesh_types); + } + hijacker = GNUNET_HELPER_start ("gnunet-helper-dns", + helper_argv, + &process_helper_messages, + NULL); + GNUNET_SERVER_add_handlers (server, handlers); + GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); +} + + +/** + * The main function for the dns service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; +} + + +/* end of gnunet-service-dns.c */ diff --git a/src/dns/plugin_block_dns.c b/src/dns/plugin_block_dns.c new file mode 100644 index 0000000..96a4dc0 --- /dev/null +++ b/src/dns/plugin_block_dns.c @@ -0,0 +1,170 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dns/plugin_block_dns.c + * @brief block plugin for storing .gnunet-bindings + * @author Philipp Tölke + */ + +#include "platform.h" +#include "gnunet_block_plugin.h" +#include "block_dns.h" +#include "gnunet_signatures.h" + +#define DEBUG_DHT GNUNET_EXTRA_LOGGING + +/** + * Function called to validate a reply or a request. For + * request evaluation, simply pass "NULL" for the reply_block. + * + * @param cls closure + * @param type block type + * @param query original query (hash) + * @param bf pointer to bloom filter associated with query; possibly updated (!) + * @param bf_mutator mutation value for bf + * @param xquery extended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in reply block + * @return characterization of result + */ +static enum GNUNET_BLOCK_EvaluationResult +block_plugin_dns_evaluate (void *cls, enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode * query, + struct GNUNET_CONTAINER_BloomFilter **bf, + int32_t bf_mutator, const void *xquery, + size_t xquery_size, const void *reply_block, + size_t reply_block_size) +{ + switch (type) + { + case GNUNET_BLOCK_TYPE_DNS: + if (xquery_size != 0) + return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; + + if (reply_block_size == 0) + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + + if (reply_block_size != sizeof (struct GNUNET_DNS_Record)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "DNS-Block is invalid: reply_block_size=%d != %d\n", + reply_block_size, sizeof (struct GNUNET_DNS_Record)); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + + const struct GNUNET_DNS_Record *rec = reply_block; + + if (ntohl (rec->purpose.size) != + sizeof (struct GNUNET_DNS_Record) - + sizeof (struct GNUNET_CRYPTO_RsaSignature)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "DNS-Block is invalid: rec->purpose.size=%d != %d\n", + ntohl (rec->purpose.size), + sizeof (struct GNUNET_DNS_Record) - + sizeof (struct GNUNET_CRYPTO_RsaSignature)); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + + if (GNUNET_TIME_relative_get_zero ().rel_value == + GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh + (rec->expiration_time)).rel_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DNS-Block is invalid: Timeout\n"); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (htonl (GNUNET_SIGNATURE_PURPOSE_DNS_RECORD), + &rec->purpose, &rec->signature, &rec->peer)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "DNS-Block is invalid: invalid signature\n"); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + + /* How to decide whether there are no more? */ + return GNUNET_BLOCK_EVALUATION_OK_MORE; + default: + return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; + } +} + + +/** + * Function called to obtain the key for a block. + * + * @param cls closure + * @param type block type + * @param block block to get the key for + * @param block_size number of bytes in block + * @param key set to the key (query) for the given block + * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported + * (or if extracting a key from a block of this type does not work) + */ +static int +block_plugin_dns_get_key (void *cls, enum GNUNET_BLOCK_Type type, + const void *block, size_t block_size, + GNUNET_HashCode * key) +{ + if (type != GNUNET_BLOCK_TYPE_DNS) + return GNUNET_SYSERR; + const struct GNUNET_DNS_Record *rec = block; + + memcpy (key, &rec->service_descriptor, sizeof (GNUNET_HashCode)); + return GNUNET_OK; +} + +/** + * Entry point for the plugin. + */ +void * +libgnunet_plugin_block_dns_init (void *cls) +{ + static enum GNUNET_BLOCK_Type types[] = + { + GNUNET_BLOCK_TYPE_DNS, + GNUNET_BLOCK_TYPE_ANY /* end of list */ + }; + struct GNUNET_BLOCK_PluginFunctions *api; + + api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); + api->evaluate = &block_plugin_dns_evaluate; + api->get_key = &block_plugin_dns_get_key; + api->types = types; + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +libgnunet_plugin_block_dns_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + +/* end of plugin_block_dns.c */ diff --git a/src/dns/test_gnunet_dns.sh b/src/dns/test_gnunet_dns.sh new file mode 100755 index 0000000..35585d4 --- /dev/null +++ b/src/dns/test_gnunet_dns.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +ME=`whoami` +if [ "$ME" != "root" ] +then + echo "This test only works if run as root. Skipping." + exit 0 +fi +export PATH=".:$PATH" +gnunet-service-dns -c dns.conf & +gnunet-dns-redirector -c dns.conf -4 127.0.0.1 & +sleep 1 +LO=`nslookup gnunet.org | grep Address | tail -n1` +if [ "$LO" != "Address: 127.0.0.1" ] +then + echo "Fail: $LO" +fi +kill `jobs -p` diff --git a/src/dv/Makefile.am b/src/dv/Makefile.am new file mode 100644 index 0000000..e0cd2e4 --- /dev/null +++ b/src/dv/Makefile.am @@ -0,0 +1,79 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +plugindir = $(libdir)/gnunet + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + dv.conf + +lib_LTLIBRARIES = libgnunetdv.la + +plugin_LTLIBRARIES = libgnunet_plugin_transport_dv.la + +libgnunetdv_la_SOURCES = \ + dv_api.c dv.h +libgnunetdv_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(GN_LIBINTL) $(XLIB) +libgnunetdv_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + + +bin_PROGRAMS = \ + gnunet-service-dv + +gnunet_service_dv_SOURCES = \ + gnunet-service-dv.c +gnunet_service_dv_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/dv/libgnunetdv.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_service_dv_DEPENDENCIES = \ + libgnunetdv.la + +libgnunet_plugin_transport_dv_la_SOURCES = \ + plugin_transport_dv.c +libgnunet_plugin_transport_dv_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/dv/libgnunetdv.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_transport_dv_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) +libgnunet_plugin_transport_dv_la_DEPENDENCIES = \ + libgnunetdv.la + +check_PROGRAMS = \ + test_transport_api_dv +# test_dv_topology + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +endif + +test_transport_api_dv_SOURCES = \ + test_transport_api_dv.c +test_transport_api_dv_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +EXTRA_DIST = \ + test_transport_dv_data.conf diff --git a/src/dv/Makefile.in b/src/dv/Makefile.in new file mode 100644 index 0000000..93f5228 --- /dev/null +++ b/src/dv/Makefile.in @@ -0,0 +1,955 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-dv$(EXEEXT) +check_PROGRAMS = test_transport_api_dv$(EXEEXT) +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +subdir = src/dv +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/dv.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = dv.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) +am_libgnunet_plugin_transport_dv_la_OBJECTS = plugin_transport_dv.lo +libgnunet_plugin_transport_dv_la_OBJECTS = \ + $(am_libgnunet_plugin_transport_dv_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_transport_dv_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_transport_dv_la_LDFLAGS) $(LDFLAGS) -o $@ +am__DEPENDENCIES_1 = +libgnunetdv_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgnunetdv_la_OBJECTS = dv_api.lo +libgnunetdv_la_OBJECTS = $(am_libgnunetdv_la_OBJECTS) +libgnunetdv_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetdv_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_service_dv_OBJECTS = gnunet-service-dv.$(OBJEXT) +gnunet_service_dv_OBJECTS = $(am_gnunet_service_dv_OBJECTS) +am_test_transport_api_dv_OBJECTS = test_transport_api_dv.$(OBJEXT) +test_transport_api_dv_OBJECTS = $(am_test_transport_api_dv_OBJECTS) +test_transport_api_dv_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunet_plugin_transport_dv_la_SOURCES) \ + $(libgnunetdv_la_SOURCES) $(gnunet_service_dv_SOURCES) \ + $(test_transport_api_dv_SOURCES) +DIST_SOURCES = $(libgnunet_plugin_transport_dv_la_SOURCES) \ + $(libgnunetdv_la_SOURCES) $(gnunet_service_dv_SOURCES) \ + $(test_transport_api_dv_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +plugindir = $(libdir)/gnunet +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + dv.conf + +lib_LTLIBRARIES = libgnunetdv.la +plugin_LTLIBRARIES = libgnunet_plugin_transport_dv.la +libgnunetdv_la_SOURCES = \ + dv_api.c dv.h + +libgnunetdv_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(GN_LIBINTL) $(XLIB) + +libgnunetdv_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +gnunet_service_dv_SOURCES = \ + gnunet-service-dv.c + +gnunet_service_dv_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/dv/libgnunetdv.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_service_dv_DEPENDENCIES = \ + libgnunetdv.la + +libgnunet_plugin_transport_dv_la_SOURCES = \ + plugin_transport_dv.c + +libgnunet_plugin_transport_dv_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/dv/libgnunetdv.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_transport_dv_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_dv_la_DEPENDENCIES = \ + libgnunetdv.la + +test_transport_api_dv_SOURCES = \ + test_transport_api_dv.c + +test_transport_api_dv_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +EXTRA_DIST = \ + test_transport_dv_data.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/dv/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/dv/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +dv.conf: $(top_builddir)/config.status $(srcdir)/dv.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_transport_dv.la: $(libgnunet_plugin_transport_dv_la_OBJECTS) $(libgnunet_plugin_transport_dv_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_transport_dv_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_dv_la_OBJECTS) $(libgnunet_plugin_transport_dv_la_LIBADD) $(LIBS) +libgnunetdv.la: $(libgnunetdv_la_OBJECTS) $(libgnunetdv_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetdv_la_LINK) -rpath $(libdir) $(libgnunetdv_la_OBJECTS) $(libgnunetdv_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-service-dv$(EXEEXT): $(gnunet_service_dv_OBJECTS) $(gnunet_service_dv_DEPENDENCIES) + @rm -f gnunet-service-dv$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_dv_OBJECTS) $(gnunet_service_dv_LDADD) $(LIBS) +test_transport_api_dv$(EXEEXT): $(test_transport_api_dv_OBJECTS) $(test_transport_api_dv_DEPENDENCIES) + @rm -f test_transport_api_dv$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_dv_OBJECTS) $(test_transport_api_dv_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dv_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_dv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_dv.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-pkgcfgDATA \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/dv/dv.conf.in b/src/dv/dv.conf.in new file mode 100644 index 0000000..93278df --- /dev/null +++ b/src/dv/dv.conf.in @@ -0,0 +1,18 @@ +[dv] +AUTOSTART = YES +DEBUG = NO +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +BINARY = gnunet-service-dv +CONFIG = $DEFAULTCONFIG +HOME = $SERVICEHOME +HOSTNAME = localhost +@UNIXONLY@ PORT = 2571 +UNIXPATH = /tmp/gnunet-service-dv.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +# ACCEPT_FROM = +# ACCEPT_FROM6 = +# REJECT_FROM = +# REJECT_FROM6 = +# BINDTO = diff --git a/src/dv/dv.h b/src/dv/dv.h new file mode 100644 index 0000000..0d42505 --- /dev/null +++ b/src/dv/dv.h @@ -0,0 +1,275 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Christian Grothoff + * @author NOT Nathan Evans + * @file dv/dv.h + */ +#ifndef DV_H +#define DV_H + +#include "gnunet_common.h" + +#define DEBUG_DV_GOSSIP GNUNET_EXTRA_LOGGING +#define DEBUG_DV_GOSSIP_SEND GNUNET_EXTRA_LOGGING +#define DEBUG_DV_GOSSIP_RECEIPT GNUNET_EXTRA_LOGGING +#define DEBUG_DV_MESSAGES GNUNET_EXTRA_LOGGING +#define DEBUG_DV GNUNET_EXTRA_LOGGING +#define DEBUG_DV_PEER_NUMBERS GNUNET_EXTRA_LOGGING +#define DEBUG_MESSAGE_DROP GNUNET_EXTRA_LOGGING + +typedef void (*GNUNET_DV_MessageReceivedHandler) (void *cls, + struct GNUNET_PeerIdentity * + sender, char *msg, + size_t msg_len, + uint32_t distance, + char *sender_address, + size_t sender_address_len); + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * DV Message, contains a message that was received + * via DV for this peer! Internal. + * + * Sender address is copied to the end of this struct, + * followed by the actual message received. + */ +struct GNUNET_DV_MessageReceived +{ + /** + * Type: GNUNET_MESSAGE_TYPE_TRANSPORT_DV_MESSAGE + */ + struct GNUNET_MessageHeader header; + + /** + * The sender of the message + */ + struct GNUNET_PeerIdentity sender; + + /** + * The length of the message that was sent (appended to this end of struct) + */ + uint32_t msg_len; + + /** + * The distance to the peer that we received the message from + */ + uint32_t distance; + +}; + + +/** + * DV Message, indicates that we have learned of a new DV level peer. + * Internal. + * + * Sender address is copied to the end of this struct. + */ +struct GNUNET_DV_ConnectMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_TRANSPORT_DV_MESSAGE + */ + struct GNUNET_MessageHeader header; + + /** + * The sender of the message + */ + struct GNUNET_PeerIdentity *sender; + + /** + * The message that was sent + */ + struct GNUNET_MessageHeader *msg; + + /** + * The distance to the peer that we received the message from + */ + uint32_t distance; + + /** + * Length of the sender address, appended to end of this message + */ + uint32_t sender_address_len; + +}; + +/** + * Message to return result from a send attempt. + * Internal. + */ +struct GNUNET_DV_SendResultMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DV_SEND_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique ID for attempted sent message. + */ + uint32_t uid; + + /** + * Result of attempted send, 0 for send okay, + * 1 for failure of any reason. + */ + uint32_t result; +}; + +/** + * Message to send a message over DV via a specific peer. + * Internal. + */ +struct GNUNET_DV_SendMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DV_SEND + */ + struct GNUNET_MessageHeader header; + + /** + * Intended final recipient of this message + */ + struct GNUNET_PeerIdentity target; + + /** + * Message priority + */ + uint32_t priority; + + /** + * Unique ID for this message, for confirm callback. + */ + uint32_t uid; + + /** + * How long can we delay sending? + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Size of the address (appended to end of struct) + */ + uint32_t addrlen; + + /** + * The message(s) to be sent. + */ + char *msgbuf; + + /* + * Sender, appended to end of struct tells via whom + * to send this message. + */ + +}; + +/** + * Message that gets sent between nodes updating dv infos + */ +typedef struct +{ + /* Message Header */ + struct GNUNET_MessageHeader header; + + /** + * Cost from received from node to neighbor node, takes distance into account + */ + uint32_t cost GNUNET_PACKED; + + /** + * Identity of neighbor we learned information about + */ + struct GNUNET_PeerIdentity neighbor; + + /** + * PublicKey of neighbor. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + + /** + * Neighbor ID to use when sending to this peer + */ + uint32_t neighbor_id GNUNET_PACKED; + +} p2p_dv_MESSAGE_NeighborInfo; + +/** + * Message that gets sent between nodes carrying information + */ +typedef struct +{ + struct GNUNET_MessageHeader header; + + /** + * Unique ID for this message. Will be zero unless + * message tracking is desired. + */ + uint32_t uid GNUNET_PACKED; + + /** + * Identity of peer that ultimately sent the message. + * Should be looked up in the set of 'neighbor_id's of + * the referring peer. + */ + uint32_t sender GNUNET_PACKED; + + /** + * Identity of neighbor this message is going to. Should + * be looked up in the set of our own identifiers for + * neighbors! + */ + uint32_t recipient GNUNET_PACKED; + +} p2p_dv_MESSAGE_Data; + +/** + * Message that gets sent between nodes indicating a peer + * was disconnected. + */ +typedef struct +{ + struct GNUNET_MessageHeader header; + + /** + * Identity of neighbor that was disconnected. + */ + uint32_t peer_id GNUNET_PACKED; + +} p2p_dv_MESSAGE_Disconnect; +GNUNET_NETWORK_STRUCT_END + +struct GNUNET_DV_Handle * +GNUNET_DV_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_DV_MessageReceivedHandler receive_handler, + void *receive_handler_cls); + +/** + * Disconnect from the DV service + * + * @param handle the current handle to the service to disconnect + */ +void +GNUNET_DV_disconnect (struct GNUNET_DV_Handle *handle); + +#endif diff --git a/src/dv/dv_api.c b/src/dv/dv_api.c new file mode 100644 index 0000000..876282e --- /dev/null +++ b/src/dv/dv_api.c @@ -0,0 +1,628 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dv/dv_api.c + * @brief library to access the DV service + * @author Christian Grothoff + * @author Nathan Evans + */ +#include "platform.h" +#include "gnunet_bandwidth_lib.h" +#include "gnunet_client_lib.h" +#include "gnunet_constants.h" +#include "gnunet_container_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_dv_service.h" +#include "dv.h" +#include "gnunet_transport_plugin.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "dv-api",__VA_ARGS__) + +/** + * Store ready to send messages + */ +struct PendingMessages +{ + /** + * Linked list of pending messages + */ + struct PendingMessages *next; + + /** + * Message that is pending + */ + struct GNUNET_DV_SendMessage *msg; + + /** + * Timeout for this message + */ + struct GNUNET_TIME_Absolute timeout; + +}; + +/** + * Handle for the service. + */ +struct GNUNET_DV_Handle +{ + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Socket (if available). + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Currently pending transmission request. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * List of the currently pending messages for the DV service. + */ + struct PendingMessages *pending_list; + + /** + * Message we are currently sending. + */ + struct PendingMessages *current; + + /** + * Handler for messages we receive from the DV service + */ + GNUNET_DV_MessageReceivedHandler receive_handler; + + /** + * Closure for the receive handler + */ + void *receive_cls; + + /** + * Current unique ID + */ + uint32_t uid_gen; + + /** + * Hashmap containing outstanding send requests awaiting confirmation. + */ + struct GNUNET_CONTAINER_MultiHashMap *send_callbacks; + +}; + + +struct StartContext +{ + /** + * Start message + */ + struct GNUNET_MessageHeader *message; + + /** + * Handle to service, in case of timeout + */ + struct GNUNET_DV_Handle *handle; +}; + +struct SendCallbackContext +{ + /** + * The continuation to call once a message is confirmed sent (or failed) + */ + GNUNET_TRANSPORT_TransmitContinuation cont; + + /** + * Closure to call with send continuation. + */ + void *cont_cls; + + /** + * Target of the message. + */ + struct GNUNET_PeerIdentity target; +}; + +/** + * Convert unique ID to hash code. + * + * @param uid unique ID to convert + * @param hash set to uid (extended with zeros) + */ +static void +hash_from_uid (uint32_t uid, GNUNET_HashCode * hash) +{ + memset (hash, 0, sizeof (GNUNET_HashCode)); + *((uint32_t *) hash) = uid; +} + +/** + * Try to (re)connect to the dv service. + * + * @param ret handle to the (disconnected) dv service + * + * @return GNUNET_YES on success, GNUNET_NO on failure. + */ +static int +try_connect (struct GNUNET_DV_Handle *ret) +{ + if (ret->client != NULL) + return GNUNET_OK; + ret->client = GNUNET_CLIENT_connect ("dv", ret->cfg); + if (ret->client != NULL) + return GNUNET_YES; +#if DEBUG_DV_MESSAGES + LOG (GNUNET_ERROR_TYPE_DEBUG, _("Failed to connect to the dv service!\n")); +#endif + return GNUNET_NO; +} + +static void +process_pending_message (struct GNUNET_DV_Handle *handle); + +/** + * Send complete, schedule next + * + * @param handle handle to the dv service + * @param code return code for send (unused) + */ +static void +finish (struct GNUNET_DV_Handle *handle, int code) +{ + struct PendingMessages *pos = handle->current; + + handle->current = NULL; + process_pending_message (handle); + + GNUNET_free (pos->msg); + GNUNET_free (pos); +} + +/** + * Notification that we can send data + * + * @param cls handle to the dv service (struct GNUNET_DV_Handle) + * @param size how many bytes can we send + * @param buf where to copy the message to send + * + * @return how many bytes we copied to buf + */ +static size_t +transmit_pending (void *cls, size_t size, void *buf) +{ + struct GNUNET_DV_Handle *handle = cls; + size_t ret; + size_t tsize; + +#if DEBUG_DV + if (handle->current != NULL) + LOG (GNUNET_ERROR_TYPE_DEBUG, + "DV API: Transmit pending called with message type %d\n", + ntohs (handle->current->msg->header.type)); +#endif + + if (buf == NULL) + { +#if DEBUG_DV + LOG (GNUNET_ERROR_TYPE_DEBUG, "DV API: Transmit pending FAILED!\n\n\n"); +#endif + finish (handle, GNUNET_SYSERR); + return 0; + } + handle->th = NULL; + + ret = 0; + + if (handle->current != NULL) + { + tsize = ntohs (handle->current->msg->header.size); + if (size >= tsize) + { + memcpy (buf, handle->current->msg, tsize); +#if DEBUG_DV + LOG (GNUNET_ERROR_TYPE_DEBUG, + "DV API: Copied %d bytes into buffer!\n\n\n", tsize); +#endif + finish (handle, GNUNET_OK); + return tsize; + } + + } + + return ret; +} + +/** + * Try to send messages from list of messages to send + * + * @param handle handle to the distance vector service + */ +static void +process_pending_message (struct GNUNET_DV_Handle *handle) +{ + + if (handle->current != NULL) + return; /* action already pending */ + if (GNUNET_YES != try_connect (handle)) + { + finish (handle, GNUNET_SYSERR); + return; + } + + /* schedule next action */ + handle->current = handle->pending_list; + if (NULL == handle->current) + { + return; + } + handle->pending_list = handle->pending_list->next; + handle->current->next = NULL; + + if (NULL == + (handle->th = + GNUNET_CLIENT_notify_transmit_ready (handle->client, + ntohs (handle->current->msg-> + header.size), + handle->current->msg->timeout, + GNUNET_YES, &transmit_pending, + handle))) + { +#if DEBUG_DV + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to transmit request to dv service.\n"); +#endif + finish (handle, GNUNET_SYSERR); + } +} + +/** + * Add a pending message to the linked list + * + * @param handle handle to the specified DV api + * @param msg the message to add to the list + */ +static void +add_pending (struct GNUNET_DV_Handle *handle, struct GNUNET_DV_SendMessage *msg) +{ + struct PendingMessages *new_message; + struct PendingMessages *pos; + struct PendingMessages *last; + + new_message = GNUNET_malloc (sizeof (struct PendingMessages)); + new_message->msg = msg; + + if (handle->pending_list != NULL) + { + pos = handle->pending_list; + while (pos != NULL) + { + last = pos; + pos = pos->next; + } + last->next = new_message; + } + else + { + handle->pending_list = new_message; + } + + process_pending_message (handle); +} + +/** + * Handles a message sent from the DV service to us. + * Parse it out and give it to the plugin. + * + * @param cls the handle to the DV API + * @param msg the message that was received + */ +void +handle_message_receipt (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_DV_Handle *handle = cls; + struct GNUNET_DV_MessageReceived *received_msg; + struct GNUNET_DV_SendResultMessage *send_result_msg; + size_t packed_msg_len; + size_t sender_address_len; + char *sender_address; + char *packed_msg; + char *packed_msg_start; + GNUNET_HashCode uidhash; + struct SendCallbackContext *send_ctx; + + if (msg == NULL) + { +#if DEBUG_DV_MESSAGES + LOG (GNUNET_ERROR_TYPE_DEBUG, "DV_API receive: connection closed\n"); +#endif + return; /* Connection closed? */ + } + + GNUNET_assert ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE) + || (ntohs (msg->type) == + GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT)); + + switch (ntohs (msg->type)) + { + case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE: + if (ntohs (msg->size) < sizeof (struct GNUNET_DV_MessageReceived)) + return; + + received_msg = (struct GNUNET_DV_MessageReceived *) msg; + packed_msg_len = ntohl (received_msg->msg_len); + sender_address_len = + ntohs (msg->size) - packed_msg_len - + sizeof (struct GNUNET_DV_MessageReceived); + GNUNET_assert (sender_address_len > 0); + sender_address = GNUNET_malloc (sender_address_len); + memcpy (sender_address, &received_msg[1], sender_address_len); + packed_msg_start = (char *) &received_msg[1]; + packed_msg = GNUNET_malloc (packed_msg_len); + memcpy (packed_msg, &packed_msg_start[sender_address_len], packed_msg_len); + +#if DEBUG_DV_MESSAGES + LOG (GNUNET_ERROR_TYPE_DEBUG, + "DV_API receive: packed message type: %d or %d\n", + ntohs (((struct GNUNET_MessageHeader *) packed_msg)->type), + ((struct GNUNET_MessageHeader *) packed_msg)->type); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "DV_API receive: message sender reported as %s\n", + GNUNET_i2s (&received_msg->sender)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "DV_API receive: distance is %u\n", + ntohl (received_msg->distance)); +#endif + + handle->receive_handler (handle->receive_cls, &received_msg->sender, + packed_msg, packed_msg_len, + ntohl (received_msg->distance), sender_address, + sender_address_len); + + GNUNET_free (sender_address); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT: + if (ntohs (msg->size) < sizeof (struct GNUNET_DV_SendResultMessage)) + return; + + send_result_msg = (struct GNUNET_DV_SendResultMessage *) msg; + hash_from_uid (ntohl (send_result_msg->uid), &uidhash); + send_ctx = + GNUNET_CONTAINER_multihashmap_get (handle->send_callbacks, &uidhash); + + if ((send_ctx != NULL) && (send_ctx->cont != NULL)) + { + if (ntohl (send_result_msg->result) == 0) + { + send_ctx->cont (send_ctx->cont_cls, &send_ctx->target, GNUNET_OK); + } + else + { + send_ctx->cont (send_ctx->cont_cls, &send_ctx->target, GNUNET_SYSERR); + } + } + GNUNET_free_non_null (send_ctx); + break; + default: + break; + } + GNUNET_CLIENT_receive (handle->client, &handle_message_receipt, handle, + GNUNET_TIME_UNIT_FOREVER_REL); +} + +/** + * Send a message from the plugin to the DV service indicating that + * a message should be sent via DV to some peer. + * + * @param dv_handle the handle to the DV api + * @param target the final target of the message + * @param msgbuf the msg(s) to send + * @param msgbuf_size the size of msgbuf + * @param priority priority to pass on to core when sending the message + * @param timeout how long can this message be delayed (pass through to core) + * @param addr the address of this peer (internally known to DV) + * @param addrlen the length of the peer address + * @param cont continuation to call once the message has been sent (or failed) + * @param cont_cls closure for continuation + * + */ +int +GNUNET_DV_send (struct GNUNET_DV_Handle *dv_handle, + const struct GNUNET_PeerIdentity *target, const char *msgbuf, + size_t msgbuf_size, unsigned int priority, + struct GNUNET_TIME_Relative timeout, const void *addr, + size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont, + void *cont_cls) +{ + struct GNUNET_DV_SendMessage *msg; + struct SendCallbackContext *send_ctx; + char *end_of_message; + GNUNET_HashCode uidhash; + int msize; + +#if DEBUG_DV_MESSAGES + dv_handle->uid_gen = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, UINT32_MAX); +#else + dv_handle->uid_gen++; +#endif + + msize = sizeof (struct GNUNET_DV_SendMessage) + addrlen + msgbuf_size; + msg = GNUNET_malloc (msize); + msg->header.size = htons (msize); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND); + memcpy (&msg->target, target, sizeof (struct GNUNET_PeerIdentity)); + msg->priority = htonl (priority); + msg->timeout = timeout; + msg->addrlen = htonl (addrlen); + msg->uid = htonl (dv_handle->uid_gen); + memcpy (&msg[1], addr, addrlen); + end_of_message = (char *) &msg[1]; + end_of_message = &end_of_message[addrlen]; + memcpy (end_of_message, msgbuf, msgbuf_size); + add_pending (dv_handle, msg); + send_ctx = GNUNET_malloc (sizeof (struct SendCallbackContext)); + send_ctx->cont = cont; + send_ctx->cont_cls = cont_cls; + memcpy (&send_ctx->target, target, sizeof (struct GNUNET_PeerIdentity)); + hash_from_uid (dv_handle->uid_gen, &uidhash); + GNUNET_CONTAINER_multihashmap_put (dv_handle->send_callbacks, &uidhash, + send_ctx, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + + return GNUNET_OK; +} + +/** + * Callback to transmit a start message to + * the DV service, once we can send + * + * @param cls struct StartContext + * @param size how much can we send + * @param buf where to copy the message + * + * @return number of bytes copied to buf + */ +static size_t +transmit_start (void *cls, size_t size, void *buf) +{ + struct StartContext *start_context = cls; + struct GNUNET_DV_Handle *handle = start_context->handle; + size_t tsize; + +#if DEBUG_DV + LOG (GNUNET_ERROR_TYPE_DEBUG, "DV API: sending start request to service\n"); +#endif + if (buf == NULL) + { + GNUNET_free (start_context->message); + GNUNET_free (start_context); + GNUNET_DV_disconnect (handle); + return 0; + } + + tsize = ntohs (start_context->message->size); + if (size >= tsize) + { + memcpy (buf, start_context->message, tsize); + GNUNET_free (start_context->message); + GNUNET_free (start_context); + GNUNET_CLIENT_receive (handle->client, &handle_message_receipt, handle, + GNUNET_TIME_UNIT_FOREVER_REL); + + + return tsize; + } + + return 0; +} + +/** + * Connect to the DV service + * + * @param cfg the configuration to use + * @param receive_handler method call when on receipt from the service + * @param receive_handler_cls closure for receive_handler + * + * @return handle to the DV service + */ +struct GNUNET_DV_Handle * +GNUNET_DV_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_DV_MessageReceivedHandler receive_handler, + void *receive_handler_cls) +{ + struct GNUNET_DV_Handle *handle; + struct GNUNET_MessageHeader *start_message; + struct StartContext *start_context; + + handle = GNUNET_malloc (sizeof (struct GNUNET_DV_Handle)); + + handle->cfg = cfg; + handle->pending_list = NULL; + handle->current = NULL; + handle->th = NULL; + handle->client = GNUNET_CLIENT_connect ("dv", cfg); + handle->receive_handler = receive_handler; + handle->receive_cls = receive_handler_cls; + + if (handle->client == NULL) + { + GNUNET_free (handle); + return NULL; + } + + start_message = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader)); + start_message->size = htons (sizeof (struct GNUNET_MessageHeader)); + start_message->type = htons (GNUNET_MESSAGE_TYPE_DV_START); + + start_context = GNUNET_malloc (sizeof (struct StartContext)); + start_context->handle = handle; + start_context->message = start_message; + GNUNET_CLIENT_notify_transmit_ready (handle->client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 60), + GNUNET_YES, &transmit_start, + start_context); + + handle->send_callbacks = GNUNET_CONTAINER_multihashmap_create (100); + + return handle; +} + +/** + * Disconnect from the DV service + * + * @param handle the current handle to the service to disconnect + */ +void +GNUNET_DV_disconnect (struct GNUNET_DV_Handle *handle) +{ + struct PendingMessages *pos; + + GNUNET_assert (handle != NULL); + + if (handle->th != NULL) /* We have a live transmit request in the Aether */ + { + GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); + handle->th = NULL; + } + if (handle->current != NULL) /* We are trying to send something now, clean it up */ + GNUNET_free (handle->current); + while (NULL != (pos = handle->pending_list)) /* Remove all pending sends from the list */ + { + handle->pending_list = pos->next; + GNUNET_free (pos); + } + if (handle->client != NULL) /* Finally, disconnect from the service */ + { + GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO); + handle->client = NULL; + } + + GNUNET_free (handle); +} + +/* end of dv_api.c */ diff --git a/src/dv/gnunet-service-dv.c b/src/dv/gnunet-service-dv.c new file mode 100644 index 0000000..50aac09 --- /dev/null +++ b/src/dv/gnunet-service-dv.c @@ -0,0 +1,3335 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dv/gnunet-service-dv.c + * @brief the distance vector service, primarily handles gossip of nearby + * peers and sending/receiving DV messages from core and decapsulating + * them + * + * @author Christian Grothoff + * @author Nathan Evans + * + */ +#include "platform.h" +#include "gnunet_client_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_service_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_signal_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_statistics_service.h" +#include "dv.h" + +/** + * For testing mostly, remember only the + * shortest path to a distant neighbor. + */ +#define AT_MOST_ONE GNUNET_NO + +#define USE_PEER_ID GNUNET_YES + +/** + * How many outstanding messages (unknown sender) will we allow per peer? + */ +#define MAX_OUTSTANDING_MESSAGES 5 + +/** + * How often do we check about sending out more peer information (if + * we are connected to no peers previously). + */ +#define GNUNET_DV_DEFAULT_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500000) + +/** + * How long do we wait at most between sending out information? + */ +#define GNUNET_DV_MAX_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500000) + +/** + * How long can we have not heard from a peer and + * still have it in our tables? + */ +#define GNUNET_DV_PEER_EXPIRATION_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1000)) + +/** + * Priority for gossip. + */ +#define GNUNET_DV_DHT_GOSSIP_PRIORITY (GNUNET_EXTREME_PRIORITY / 10) + +/** + * How often should we check if expiration time has elapsed for + * some peer? + */ +#define GNUNET_DV_MAINTAIN_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)) + +/** + * How long to allow a message to be delayed? + */ +#define DV_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)) + +/** + * Priority to use for DV data messages. + */ +#define DV_PRIORITY 0 + +/** + * The cost to a direct neighbor. We used to use 0, but 1 makes more sense. + */ +#define DIRECT_NEIGHBOR_COST 1 + +/** + * The default number of direct connections to store in DV (max) + */ +#define DEFAULT_DIRECT_CONNECTIONS 50 + +/** + * The default size of direct + extended peers in DV (max) + */ +#define DEFAULT_DV_SIZE 100 + +/** + * The default fisheye depth, from how many hops away will + * we keep peers? + */ +#define DEFAULT_FISHEYE_DEPTH 4 + +/** + * Linked list of messages to send to clients. + */ +struct PendingMessage +{ + /** + * Pointer to next item in the list + */ + struct PendingMessage *next; + + /** + * Pointer to previous item in the list + */ + struct PendingMessage *prev; + + /** + * The PeerIdentity to send to + */ + struct GNUNET_PeerIdentity recipient; + + /** + * The result of message sending. + */ + struct GNUNET_DV_SendResultMessage *send_result; + + /** + * Message importance level. + */ + unsigned int importance; + + /** + * Size of message. + */ + unsigned int msg_size; + + /** + * How long to wait before sending message. + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Actual message to be sent; // avoid allocation + */ + const struct GNUNET_MessageHeader *msg; // msg = (cast) &pm[1]; // memcpy (&pm[1], data, len); + +}; + +struct FastGossipNeighborList +{ + /** + * Next element of DLL + */ + struct FastGossipNeighborList *next; + + /** + * Prev element of DLL + */ + struct FastGossipNeighborList *prev; + + /** + * The neighbor to gossip about + */ + struct DistantNeighbor *about; +}; + +/** + * Context created whenever a direct peer connects to us, + * used to gossip other peers to it. + */ +struct NeighborSendContext +{ + /** + * The peer we will gossip to. + */ + struct DirectNeighbor *toNeighbor; + + /** + * The task associated with this context. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Head of DLL of peers to gossip about + * as fast as possible to this peer, for initial + * set up. + */ + struct FastGossipNeighborList *fast_gossip_list_head; + + /** + * Tail of DLL of peers to gossip about + * as fast as possible to this peer, for initial + * set up. + */ + struct FastGossipNeighborList *fast_gossip_list_tail; + +}; + + +/** + * Struct to hold information for updating existing neighbors + */ +struct NeighborUpdateInfo +{ + /** + * Cost + */ + unsigned int cost; + + /** + * The existing neighbor + */ + struct DistantNeighbor *neighbor; + + /** + * The referrer of the possibly existing peer + */ + struct DirectNeighbor *referrer; + + /** + * The time we heard about this peer + */ + struct GNUNET_TIME_Absolute now; + + /** + * Peer id this peer uses to refer to neighbor. + */ + unsigned int referrer_peer_id; + +}; + +/** + * Struct to store a single message received with + * an unknown sender. + */ +struct UnknownSenderMessage +{ + /** + * Message sender (immediate) + */ + struct GNUNET_PeerIdentity sender; + + /** + * The actual message received + */ + struct GNUNET_MessageHeader *message; + + /** + * Latency of connection + */ + struct GNUNET_TIME_Relative latency; + + /** + * Distance to destination + */ + uint32_t distance; + + /** + * Unknown sender id + */ + uint32_t sender_id; +}; + +/** + * Struct where actual neighbor information is stored, + * referenced by min_heap and max_heap. Freeing dealt + * with when items removed from hashmap. + */ +struct DirectNeighbor +{ + /** + * Identity of neighbor. + */ + struct GNUNET_PeerIdentity identity; + + /** + * PublicKey of neighbor. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + + /** + * Head of DLL of nodes that this direct neighbor referred to us. + */ + struct DistantNeighbor *referee_head; + + /** + * Tail of DLL of nodes that this direct neighbor referred to us. + */ + struct DistantNeighbor *referee_tail; + + /** + * The sending context for gossiping peers to this neighbor. + */ + struct NeighborSendContext *send_context; + + /** + * Is this one of the direct neighbors that we are "hiding" + * from DV? + */ + int hidden; + + /** + * Save messages immediately from this direct neighbor from a + * distan peer we don't know on the chance that it will be + * gossiped about and we can deliver the message. + */ + struct UnknownSenderMessage pending_messages[MAX_OUTSTANDING_MESSAGES]; +}; + + +/** + * Struct where actual neighbor information is stored, + * referenced by min_heap and max_heap. Freeing dealt + * with when items removed from hashmap. + */ +struct DistantNeighbor +{ + /** + * We keep distant neighbor's of the same referrer in a DLL. + */ + struct DistantNeighbor *next; + + /** + * We keep distant neighbor's of the same referrer in a DLL. + */ + struct DistantNeighbor *prev; + + /** + * Node in min heap + */ + struct GNUNET_CONTAINER_HeapNode *min_loc; + + /** + * Node in max heap + */ + struct GNUNET_CONTAINER_HeapNode *max_loc; + + /** + * Identity of referrer (next hop towards 'neighbor'). + */ + struct DirectNeighbor *referrer; + + /** + * Identity of neighbor. + */ + struct GNUNET_PeerIdentity identity; + + /** + * PublicKey of neighbor. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey; + + /** + * Last time we received routing information from this peer + */ + struct GNUNET_TIME_Absolute last_activity; + + /** + * Last time we sent routing information about this peer + */ + struct GNUNET_TIME_Absolute last_gossip; + + /** + * Cost to neighbor, used for actual distance vector computations + */ + unsigned int cost; + + /** + * Random identifier *we* use for this peer, to be used as shortcut + * instead of sending full peer id for each message + */ + unsigned int our_id; + + /** + * Random identifier the *referrer* uses for this peer. + */ + unsigned int referrer_id; + + /** + * Is this one of the direct neighbors that we are "hiding" + * from DV? + */ + int hidden; + +}; + +struct PeerIteratorContext +{ + /** + * The actual context, to be freed later. + */ + struct GNUNET_PEERINFO_IteratorContext *ic; + + /** + * The neighbor about which we are concerned. + */ + struct DirectNeighbor *neighbor; + + /** + * The distant neighbor entry for this direct neighbor. + */ + struct DistantNeighbor *distant; + +}; + +/** + * Context used for creating hello messages when + * gossips are received. + */ +struct HelloContext +{ + /** + * Identity of distant neighbor. + */ + struct GNUNET_PeerIdentity distant_peer; + + /** + * Identity of direct neighbor, via which we send this message. + */ + const struct GNUNET_PeerIdentity *direct_peer; + + /** + * How many addresses do we need to add (always starts at 1, then set to 0) + */ + int addresses_to_add; + +}; + +struct DV_SendContext +{ + /** + * The distant peer (should always match) + */ + struct GNUNET_PeerIdentity *distant_peer; + + /** + * The direct peer, we need to verify the referrer of. + */ + struct GNUNET_PeerIdentity *direct_peer; + + /** + * The message to be sent + */ + struct GNUNET_MessageHeader *message; + + /** + * The pre-built send result message. Simply needs to be queued + * and freed once send has been called! + */ + struct GNUNET_DV_SendResultMessage *send_result; + + /** + * The size of the message being sent, may be larger + * than message->header.size because it's multiple + * messages packed into one! + */ + size_t message_size; + + /** + * How important is this message? + */ + unsigned int importance; + + /** + * Timeout for this message + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Unique ID for DV message + */ + unsigned int uid; +}; + +struct FindDestinationContext +{ + unsigned int tid; + struct DistantNeighbor *dest; +}; + +struct FindIDContext +{ + unsigned int tid; + struct GNUNET_PeerIdentity *dest; + const struct GNUNET_PeerIdentity *via; +}; + +struct DisconnectContext +{ + /** + * Distant neighbor to get pid from. + */ + struct DistantNeighbor *distant; + + /** + * Direct neighbor that disconnected. + */ + struct DirectNeighbor *direct; +}; + +struct TokenizedMessageContext +{ + /** + * Immediate sender of this message + */ + const struct GNUNET_PeerIdentity *peer; + + /** + * Distant sender of the message + */ + struct DistantNeighbor *distant; + + /** + * Uid for this set of messages + */ + uint32_t uid; +}; + +/** + * Context for finding the least cost peer to send to. + * Transport selection can only go so far. + */ +struct FindLeastCostContext +{ + struct DistantNeighbor *target; + unsigned int least_cost; +}; + +/** + * Handle to the core service api. + */ +static struct GNUNET_CORE_Handle *coreAPI; + +/** + * Stream tokenizer to handle messages coming in from core. + */ +static struct GNUNET_SERVER_MessageStreamTokenizer *coreMST; + +/** + * The identity of our peer. + */ +static struct GNUNET_PeerIdentity my_identity; + +/** + * The configuration for this service. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + + +/** + * The client, the DV plugin connected to us. Hopefully + * this client will never change, although if the plugin dies + * and returns for some reason it may happen. + */ +static struct GNUNET_SERVER_Client *client_handle; + +/** + * Task to run when we shut down, cleaning up all our trash + */ +static GNUNET_SCHEDULER_TaskIdentifier cleanup_task; + +static size_t default_dv_priority = 0; + +static char *my_short_id; + +/** + * Transmit handle to the plugin. + */ +static struct GNUNET_CONNECTION_TransmitHandle *plugin_transmit_handle; + +/** + * Head of DLL for client messages + */ +static struct PendingMessage *plugin_pending_head; + +/** + * Tail of DLL for client messages + */ +static struct PendingMessage *plugin_pending_tail; + +/** + * Handle to the peerinfo service + */ +static struct GNUNET_PEERINFO_Handle *peerinfo_handle; + +/** + * Transmit handle to core service. + */ +static struct GNUNET_CORE_TransmitHandle *core_transmit_handle; + +/** + * Head of DLL for core messages + */ +static struct PendingMessage *core_pending_head; + +/** + * Tail of DLL for core messages + */ +static struct PendingMessage *core_pending_tail; + +/** + * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for all + * directly connected peers. + */ +static struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors; + +/** + * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for + * peers connected via DV (extended neighborhood). Does ALSO + * include any peers that are in 'direct_neighbors'; for those + * peers, the cost will be zero and the referrer all zeros. + */ +static struct GNUNET_CONTAINER_MultiHashMap *extended_neighbors; + +/** + * We use the min heap (min refers to cost) to prefer + * gossipping about peers with small costs. + */ +static struct GNUNET_CONTAINER_Heap *neighbor_min_heap; + +/** + * We use the max heap (max refers to cost) for general + * iterations over all peers and to remove the most costly + * connection if we have too many. + */ +static struct GNUNET_CONTAINER_Heap *neighbor_max_heap; + +/** + * Handle for the statistics service. + */ +struct GNUNET_STATISTICS_Handle *stats; + +/** + * How far out to keep peers we learn about. + */ +static unsigned long long fisheye_depth; + +/** + * How many peers to store at most. + */ +static unsigned long long max_table_size; + +/** + * We've been given a target ID based on the random numbers that + * we assigned to our DV-neighborhood. Find the entry for the + * respective neighbor. + */ +static int +find_destination (void *cls, struct GNUNET_CONTAINER_HeapNode *node, + void *element, GNUNET_CONTAINER_HeapCostType cost) +{ + struct FindDestinationContext *fdc = cls; + struct DistantNeighbor *dn = element; + + if (fdc->tid != dn->our_id) + return GNUNET_YES; + fdc->dest = dn; + return GNUNET_NO; +} + + +/** + * We've been given a target ID based on the random numbers that + * we assigned to our DV-neighborhood. Find the entry for the + * respective neighbor. + */ +static int +find_specific_id (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct FindIDContext *fdc = cls; + struct DistantNeighbor *dn = value; + + if (memcmp + (&dn->referrer->identity, fdc->via, + sizeof (struct GNUNET_PeerIdentity)) == 0) + { + fdc->tid = dn->referrer_id; + return GNUNET_NO; + } + return GNUNET_YES; +} + +/** + * Find a distant peer whose referrer_id matches what we're + * looking for. For looking up a peer we've gossipped about + * but is now disconnected. Need to do this because we don't + * want to remove those that may be accessible via a different + * route. + */ +static int +find_distant_peer (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct FindDestinationContext *fdc = cls; + struct DistantNeighbor *distant = value; + + if (fdc->tid == distant->referrer_id) + { + fdc->dest = distant; + return GNUNET_NO; + } + return GNUNET_YES; +} + +/** + * Function called to notify a client about the socket + * begin ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +size_t +transmit_to_plugin (void *cls, size_t size, void *buf) +{ + char *cbuf = buf; + struct PendingMessage *reply; + size_t off; + size_t msize; + + if (buf == NULL) + { + /* client disconnected */ +#if DEBUG_DV_MESSAGES + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: %s buffer was NULL (client disconnect?)\n", my_short_id, + "transmit_to_plugin"); +#endif + return 0; + } + plugin_transmit_handle = NULL; + off = 0; + while ((NULL != (reply = plugin_pending_head)) && + (size >= off + (msize = ntohs (reply->msg->size)))) + { + GNUNET_CONTAINER_DLL_remove (plugin_pending_head, plugin_pending_tail, + reply); + memcpy (&cbuf[off], reply->msg, msize); + GNUNET_free (reply); + off += msize; + } + + if (plugin_pending_head != NULL) + plugin_transmit_handle = + GNUNET_SERVER_notify_transmit_ready (client_handle, + ntohs (plugin_pending_head->msg-> + size), + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_to_plugin, NULL); + + return off; +} + +/** + * Send a message to the dv plugin. + * + * @param sender the direct sender of the message + * @param message the message to send to the plugin + * (may be an encapsulated type) + * @param message_size the size of the message to be sent + * @param distant_neighbor the original sender of the message + * @param cost the cost to the original sender of the message + */ +void +send_to_plugin (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, size_t message_size, + struct GNUNET_PeerIdentity *distant_neighbor, size_t cost) +{ + struct GNUNET_DV_MessageReceived *received_msg; + struct PendingMessage *pending_message; + char *sender_address; + size_t sender_address_len; + char *packed_msg_start; + int size; + +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "send_to_plugin called with peer %s as sender\n", + GNUNET_i2s (distant_neighbor)); +#endif + + if (memcmp (sender, distant_neighbor, sizeof (struct GNUNET_PeerIdentity)) != + 0) + { + sender_address_len = sizeof (struct GNUNET_PeerIdentity) * 2; + sender_address = GNUNET_malloc (sender_address_len); + memcpy (sender_address, distant_neighbor, + sizeof (struct GNUNET_PeerIdentity)); + memcpy (&sender_address[sizeof (struct GNUNET_PeerIdentity)], sender, + sizeof (struct GNUNET_PeerIdentity)); + } + else + { + sender_address_len = sizeof (struct GNUNET_PeerIdentity); + sender_address = GNUNET_malloc (sender_address_len); + memcpy (sender_address, sender, sizeof (struct GNUNET_PeerIdentity)); + } + + size = + sizeof (struct GNUNET_DV_MessageReceived) + sender_address_len + + message_size; + received_msg = GNUNET_malloc (size); + received_msg->header.size = htons (size); + received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE); + received_msg->distance = htonl (cost); + received_msg->msg_len = htonl (message_size); + /* Set the sender in this message to be the original sender! */ + memcpy (&received_msg->sender, distant_neighbor, + sizeof (struct GNUNET_PeerIdentity)); + /* Copy the intermediate sender to the end of the message, this is how the transport identifies this peer */ + memcpy (&received_msg[1], sender_address, sender_address_len); + GNUNET_free (sender_address); + /* Copy the actual message after the sender */ + packed_msg_start = (char *) &received_msg[1]; + packed_msg_start = &packed_msg_start[sender_address_len]; + memcpy (packed_msg_start, message, message_size); + pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size); + pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; + memcpy (&pending_message[1], received_msg, size); + GNUNET_free (received_msg); + + GNUNET_CONTAINER_DLL_insert_after (plugin_pending_head, plugin_pending_tail, + plugin_pending_tail, pending_message); + + if (client_handle != NULL) + { + if (plugin_transmit_handle == NULL) + { + plugin_transmit_handle = + GNUNET_SERVER_notify_transmit_ready (client_handle, size, + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_to_plugin, NULL); + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to queue message for plugin, client_handle not yet set (how?)!\n"); + } +} + +/* Declare here so retry_core_send is aware of it */ +size_t +core_transmit_notify (void *cls, size_t size, void *buf); + +/** + * Try to send another message from our core sending list + */ +static void +try_core_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PendingMessage *pending; + + pending = core_pending_head; + + if (core_transmit_handle != NULL) + return; /* Message send already in progress */ + + if ((pending != NULL) && (coreAPI != NULL)) + core_transmit_handle = + GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_YES, + pending->importance, + pending->timeout, + &pending->recipient, + pending->msg_size, + &core_transmit_notify, NULL); +} + + +/** + * Function called to notify a client about the socket + * being ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure (NULL) + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +size_t +core_transmit_notify (void *cls, size_t size, void *buf) +{ + char *cbuf = buf; + struct PendingMessage *pending; + struct PendingMessage *client_reply; + size_t off; + size_t msize; + + if (buf == NULL) + { + /* client disconnected */ +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s': buffer was NULL\n", "DHT"); +#endif + return 0; + } + + core_transmit_handle = NULL; + off = 0; + pending = core_pending_head; + if ((pending != NULL) && (size >= (msize = ntohs (pending->msg->size)))) + { +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "`%s' : transmit_notify (core) called with size %d\n", + "dv service", msize); +#endif + GNUNET_CONTAINER_DLL_remove (core_pending_head, core_pending_tail, pending); + if (pending->send_result != NULL) /* Will only be non-null if a real client asked for this send */ + { + client_reply = + GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct GNUNET_DV_SendResultMessage)); + client_reply->msg = (struct GNUNET_MessageHeader *) &client_reply[1]; + memcpy (&client_reply[1], pending->send_result, + sizeof (struct GNUNET_DV_SendResultMessage)); + GNUNET_free (pending->send_result); + + GNUNET_CONTAINER_DLL_insert_after (plugin_pending_head, + plugin_pending_tail, + plugin_pending_tail, client_reply); + if (client_handle != NULL) + { + if (plugin_transmit_handle == NULL) + { + plugin_transmit_handle = + GNUNET_SERVER_notify_transmit_ready (client_handle, + sizeof (struct + GNUNET_DV_SendResultMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_to_plugin, NULL); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to queue message for plugin, must be one in progress already!!\n"); + } + } + } + memcpy (&cbuf[off], pending->msg, msize); + GNUNET_free (pending); + off += msize; + } + /*reply = core_pending_head; */ + + GNUNET_SCHEDULER_add_now (&try_core_send, NULL); + /*if (reply != NULL) + * core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, GNUNET_YES, reply->importance, reply->timeout, &reply->recipient, reply->msg_size, &core_transmit_notify, NULL); */ + + return off; +} + + +/** + * Send a DV data message via DV. + * + * @param sender the original sender of the message + * @param recipient the next hop recipient, may be our direct peer, maybe not + * @param send_context the send context + */ +static int +send_message_via (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_PeerIdentity *recipient, + struct DV_SendContext *send_context) +{ + p2p_dv_MESSAGE_Data *toSend; + unsigned int msg_size; + unsigned int recipient_id; + unsigned int sender_id; + struct DistantNeighbor *source; + struct PendingMessage *pending_message; + struct FindIDContext find_context; + +#if DEBUG_DV + char shortname[5]; +#endif + + msg_size = send_context->message_size + sizeof (p2p_dv_MESSAGE_Data); + + find_context.dest = send_context->distant_peer; + find_context.via = recipient; + find_context.tid = 0; + GNUNET_CONTAINER_multihashmap_get_multiple (extended_neighbors, + &send_context-> + distant_peer->hashPubKey, + &find_specific_id, &find_context); + + if (find_context.tid == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: find_specific_id failed to find peer!\n", my_short_id); + /* target unknown to us, drop! */ + return GNUNET_SYSERR; + } + recipient_id = find_context.tid; + + if (0 == (memcmp (&my_identity, sender, sizeof (struct GNUNET_PeerIdentity)))) + { + sender_id = 0; + source = + GNUNET_CONTAINER_multihashmap_get (extended_neighbors, + &sender->hashPubKey); + if (source != NULL) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: send_message_via found %s, myself in extended peer list???\n", + my_short_id, GNUNET_i2s (&source->identity)); + } + else + { + source = + GNUNET_CONTAINER_multihashmap_get (extended_neighbors, + &sender->hashPubKey); + if (source == NULL) + { + /* sender unknown to us, drop! */ + return GNUNET_SYSERR; + } + sender_id = source->our_id; + } + + pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); + pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; + pending_message->send_result = send_context->send_result; + memcpy (&pending_message->recipient, recipient, + sizeof (struct GNUNET_PeerIdentity)); + pending_message->msg_size = msg_size; + pending_message->importance = send_context->importance; + pending_message->timeout = send_context->timeout; + toSend = (p2p_dv_MESSAGE_Data *) pending_message->msg; + toSend->header.size = htons (msg_size); + toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA); + toSend->sender = htonl (sender_id); + toSend->recipient = htonl (recipient_id); +#if DEBUG_DV_MESSAGES + toSend->uid = send_context->uid; /* Still sent around in network byte order */ +#else + toSend->uid = htonl (0); +#endif + + memcpy (&toSend[1], send_context->message, send_context->message_size); + +#if DEBUG_DV + memcpy (&shortname, GNUNET_i2s (send_context->distant_peer), 4); + shortname[4] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Notifying core of send to destination `%s' via `%s' size %u\n", + "DV", &shortname, GNUNET_i2s (recipient), msg_size); +#endif + + GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail, + core_pending_tail, pending_message); + + GNUNET_SCHEDULER_add_now (try_core_send, NULL); + + return GNUNET_YES; +} + +/** + * Given a FindLeastCostContext, and a set + * of peers that match the target, return the cheapest. + * + * @param cls closure, a struct FindLeastCostContext + * @param key the key identifying the target peer + * @param value the target peer + * + * @return GNUNET_YES to continue iteration, GNUNET_NO to stop + */ +static int +find_least_cost_peer (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct FindLeastCostContext *find_context = cls; + struct DistantNeighbor *dn = value; + + if (dn->cost < find_context->least_cost) + { + find_context->target = dn; + } + if (dn->cost == DIRECT_NEIGHBOR_COST) + return GNUNET_NO; + return GNUNET_YES; +} + +/** + * Send a DV data message via DV. + * + * @param recipient the ultimate recipient of this message + * @param sender the original sender of the message + * @param specific_neighbor the specific neighbor to send this message via + * @param message the packed message + * @param message_size size of the message + * @param importance what priority to send this message with + * @param uid the unique identifier of this message (or 0 for none) + * @param timeout how long to possibly delay sending this message + */ +static int +send_message (const struct GNUNET_PeerIdentity *recipient, + const struct GNUNET_PeerIdentity *sender, + const struct DistantNeighbor *specific_neighbor, + const struct GNUNET_MessageHeader *message, size_t message_size, + unsigned int importance, unsigned int uid, + struct GNUNET_TIME_Relative timeout) +{ + p2p_dv_MESSAGE_Data *toSend; + unsigned int msg_size; + unsigned int cost; + unsigned int recipient_id; + unsigned int sender_id; + struct DistantNeighbor *target; + struct DistantNeighbor *source; + struct PendingMessage *pending_message; + struct FindLeastCostContext find_least_ctx; + +#if DEBUG_DV_PEER_NUMBERS + struct GNUNET_CRYPTO_HashAsciiEncoded encPeerFrom; + struct GNUNET_CRYPTO_HashAsciiEncoded encPeerTo; + struct GNUNET_CRYPTO_HashAsciiEncoded encPeerVia; +#endif + msg_size = message_size + sizeof (p2p_dv_MESSAGE_Data); + + find_least_ctx.least_cost = -1; + find_least_ctx.target = NULL; + /* + * Need to find the least cost peer, lest the transport selection keep + * picking the same DV route for the same destination which results + * in messages looping forever. Relatively cheap, we don't iterate + * over all known peers, just those that apply. + */ + GNUNET_CONTAINER_multihashmap_get_multiple (extended_neighbors, + &recipient->hashPubKey, + &find_least_cost_peer, + &find_least_ctx); + target = find_least_ctx.target; + + if (target == NULL) + { + /* target unknown to us, drop! */ + return GNUNET_SYSERR; + } + recipient_id = target->referrer_id; + + source = + GNUNET_CONTAINER_multihashmap_get (extended_neighbors, + &sender->hashPubKey); + if (source == NULL) + { + if (0 != + (memcmp (&my_identity, sender, sizeof (struct GNUNET_PeerIdentity)))) + { + /* sender unknown to us, drop! */ + return GNUNET_SYSERR; + } + sender_id = 0; /* 0 == us */ + } + else + { + /* find out the number that we use when we gossip about + * the sender */ + sender_id = source->our_id; + } + +#if DEBUG_DV_PEER_NUMBERS + GNUNET_CRYPTO_hash_to_enc (&source->identity.hashPubKey, &encPeerFrom); + GNUNET_CRYPTO_hash_to_enc (&target->referrer->identity.hashPubKey, + &encPeerVia); + encPeerFrom.encoding[4] = '\0'; + encPeerVia.encoding[4] = '\0'; +#endif + if ((sender_id != 0) && + (0 == + memcmp (&source->identity, &target->referrer->identity, + sizeof (struct GNUNET_PeerIdentity)))) + { + return 0; + } + + cost = target->cost; + pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); + pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; + pending_message->send_result = NULL; + pending_message->importance = importance; + pending_message->timeout = timeout; + memcpy (&pending_message->recipient, &target->referrer->identity, + sizeof (struct GNUNET_PeerIdentity)); + pending_message->msg_size = msg_size; + toSend = (p2p_dv_MESSAGE_Data *) pending_message->msg; + toSend->header.size = htons (msg_size); + toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA); + toSend->sender = htonl (sender_id); + toSend->recipient = htonl (recipient_id); +#if DEBUG_DV_MESSAGES + toSend->uid = htonl (uid); +#else + toSend->uid = htonl (0); +#endif + +#if DEBUG_DV_PEER_NUMBERS + GNUNET_CRYPTO_hash_to_enc (&target->identity.hashPubKey, &encPeerTo); + encPeerTo.encoding[4] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Sending DATA message. Sender id %u, source %s, destination %s, via %s\n", + GNUNET_i2s (&my_identity), sender_id, &encPeerFrom, &encPeerTo, + &encPeerVia); +#endif + memcpy (&toSend[1], message, message_size); + if ((source != NULL) && (source->pkey == NULL)) /* Test our hypothesis about message failures! */ + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: Sending message, but anticipate recipient will not know sender!!!\n\n\n", + my_short_id); + } + GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail, + core_pending_tail, pending_message); +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Notifying core of send size %d to destination `%s'\n", + "DV SEND MESSAGE", msg_size, GNUNET_i2s (recipient)); +#endif + + GNUNET_SCHEDULER_add_now (try_core_send, NULL); + return (int) cost; +} + +#if USE_PEER_ID +struct CheckPeerContext +{ + /** + * Peer we found + */ + struct DistantNeighbor *peer; + + /** + * Sender id to search for + */ + unsigned int sender_id; +}; + +/** + * Iterator over hash map entries. + * + * @param cls closure + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +int +checkPeerID (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct CheckPeerContext *ctx = cls; + struct DistantNeighbor *distant = value; + + if (memcmp (key, &ctx->sender_id, sizeof (unsigned int)) == 0) + { + ctx->peer = distant; + return GNUNET_NO; + } + return GNUNET_YES; + +} +#endif + + +/** + * Handler for messages parsed out by the tokenizer from + * DV DATA received for this peer. + * + * @param cls NULL + * @param client the TokenizedMessageContext which contains message information + * @param message the actual message + */ +void +tokenized_message_handler (void *cls, void *client, + const struct GNUNET_MessageHeader *message) +{ + struct TokenizedMessageContext *ctx = client; + + GNUNET_break_op (ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP); + GNUNET_break_op (ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_DATA); + if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP) && + (ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_DATA)) + { +#if DEBUG_DV_MESSAGES + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Receives %s message for me, uid %u, size %d, type %d cost %u from %s!\n", + my_short_id, "DV DATA", ctx->uid, ntohs (message->size), + ntohs (message->type), ctx->distant->cost, + GNUNET_i2s (&ctx->distant->identity)); +#endif + GNUNET_assert (memcmp + (ctx->peer, &ctx->distant->identity, + sizeof (struct GNUNET_PeerIdentity)) != 0); + send_to_plugin (ctx->peer, message, ntohs (message->size), + &ctx->distant->identity, ctx->distant->cost); + } +} + +#if DELAY_FORWARDS +struct DelayedMessageContext +{ + struct GNUNET_PeerIdentity dest; + struct GNUNET_PeerIdentity sender; + struct GNUNET_MessageHeader *message; + size_t message_size; + uint32_t uid; +}; + +void +send_message_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct DelayedMessageContext *msg_ctx = cls; + + if (msg_ctx != NULL) + { + send_message (&msg_ctx->dest, &msg_ctx->sender, NULL, msg_ctx->message, + msg_ctx->message_size, default_dv_priority, msg_ctx->uid, + GNUNET_TIME_relative_get_forever ()); + GNUNET_free (msg_ctx->message); + GNUNET_free (msg_ctx); + } +} +#endif + +/** + * Get distance information from 'atsi'. + * + * @param atsi performance data + * @param atsi_count number of entries in atsi + * @return connected transport distance + */ +static uint32_t +get_atsi_distance (const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + unsigned int i; + + for (i = 0; i < atsi_count; i++) + if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DISTANCE) + return ntohl (atsi->value); + /* FIXME: we do not have distance data? Assume direct neighbor. */ + return DIRECT_NEIGHBOR_COST; +} + +/** + * Find latency information in 'atsi'. + * + * @param atsi performance data + * @param atsi_count number of entries in atsi + * @return connection latency + */ +static struct GNUNET_TIME_Relative +get_atsi_latency (const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + unsigned int i; + + for (i = 0; i < atsi_count; i++) + if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DELAY) + return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + ntohl (atsi->value)); + GNUNET_break (0); + /* how can we not have latency data? */ + return GNUNET_TIME_UNIT_SECONDS; +} + +/** + * Core handler for dv data messages. Whatever this message + * contains all we really have to do is rip it out of its + * DV layering and give it to our pal the DV plugin to report + * in with. + * + * @param cls closure + * @param peer peer which sent the message (immediate sender) + * @param message the message + * @param atsi transport ATS information (latency, distance, etc.) + * @param atsi_count number of entries in atsi + */ +static int +handle_dv_data_message (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + const p2p_dv_MESSAGE_Data *incoming = (const p2p_dv_MESSAGE_Data *) message; + const struct GNUNET_MessageHeader *packed_message; + struct DirectNeighbor *dn; + struct DistantNeighbor *pos; + unsigned int sid; /* Sender id */ + unsigned int tid; /* Target id */ + struct GNUNET_PeerIdentity *original_sender; + struct GNUNET_PeerIdentity *destination; + struct FindDestinationContext fdc; + struct TokenizedMessageContext tkm_ctx; + int i; + int found_pos; + +#if DELAY_FORWARDS + struct DelayedMessageContext *delayed_context; +#endif +#if USE_PEER_ID + struct CheckPeerContext checkPeerCtx; +#endif +#if DEBUG_DV_MESSAGES + char *sender_id; +#endif + int ret; + size_t packed_message_size; + char *cbuf; + uint32_t distance; /* Distance information */ + struct GNUNET_TIME_Relative latency; /* Latency information */ + + packed_message_size = + ntohs (incoming->header.size) - sizeof (p2p_dv_MESSAGE_Data); +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Receives DATA message from %s size %d, packed size %d!\n", + my_short_id, GNUNET_i2s (peer), ntohs (incoming->header.size), + packed_message_size); +#endif + + if (ntohs (incoming->header.size) < + sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader)) + { +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "`%s': Message sizes don't add up, total size %u, expected at least %u!\n", + "dv service", ntohs (incoming->header.size), + sizeof (p2p_dv_MESSAGE_Data) + + sizeof (struct GNUNET_MessageHeader)); +#endif + return GNUNET_SYSERR; + } + + /* Iterate over ATS_Information to get distance and latency */ + latency = get_atsi_latency (atsi, atsi_count); + distance = get_atsi_distance (atsi, atsi_count); + dn = GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey); + if (dn == NULL) + return GNUNET_OK; + + sid = ntohl (incoming->sender); +#if USE_PEER_ID + if (sid != 0) + { + checkPeerCtx.sender_id = sid; + checkPeerCtx.peer = NULL; + GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &checkPeerID, + &checkPeerCtx); + pos = checkPeerCtx.peer; + } + else + { + pos = + GNUNET_CONTAINER_multihashmap_get (extended_neighbors, + &peer->hashPubKey); + } +#else + pos = dn->referee_head; + while ((NULL != pos) && (pos->referrer_id != sid)) + pos = pos->next; +#endif + + if (pos == NULL) + { +#if DEBUG_DV_MESSAGES + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: unknown sender (%u), Message uid %u from %s!\n", + my_short_id, ntohl (incoming->sender), ntohl (incoming->uid), + GNUNET_i2s (&dn->identity)); + pos = dn->referee_head; + while ((NULL != pos) && (pos->referrer_id != sid)) + { + sender_id = GNUNET_strdup (GNUNET_i2s (&pos->identity)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I know sender %u %s\n", + pos->referrer_id, sender_id); + GNUNET_free (sender_id); + pos = pos->next; + } +#endif + + found_pos = -1; + for (i = 0; i < MAX_OUTSTANDING_MESSAGES; i++) + { + if (dn->pending_messages[i].sender_id == 0) + { + found_pos = i; + break; + } + } + + if (found_pos == -1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: Too many unknown senders (%u), ignoring message! Message uid %llu from %s!\n", + my_short_id, ntohl (incoming->sender), ntohl (incoming->uid), + GNUNET_i2s (&dn->identity)); + } + else + { + dn->pending_messages[found_pos].message = + GNUNET_malloc (ntohs (message->size)); + memcpy (dn->pending_messages[found_pos].message, message, + ntohs (message->size)); + dn->pending_messages[found_pos].distance = distance; + dn->pending_messages[found_pos].latency = latency; + memcpy (&dn->pending_messages[found_pos].sender, peer, + sizeof (struct GNUNET_PeerIdentity)); + dn->pending_messages[found_pos].sender_id = sid; + } + /* unknown sender */ + return GNUNET_OK; + } + original_sender = &pos->identity; + tid = ntohl (incoming->recipient); + if (tid == 0) + { + /* 0 == us */ + cbuf = (char *) &incoming[1]; + + tkm_ctx.peer = peer; + tkm_ctx.distant = pos; + tkm_ctx.uid = ntohl (incoming->uid); + if (GNUNET_OK != + GNUNET_SERVER_mst_receive (coreMST, &tkm_ctx, cbuf, packed_message_size, + GNUNET_NO, GNUNET_NO)) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: %s Received corrupt data, discarding!", my_short_id, + "DV SERVICE"); + } + return GNUNET_OK; + } + else + { + packed_message = (struct GNUNET_MessageHeader *) &incoming[1]; + } + + /* FIXME: this is the *only* per-request operation we have in DV + * that is O(n) in relation to the number of connected peers; a + * hash-table lookup could easily solve this (minor performance + * issue) */ + fdc.tid = tid; + fdc.dest = NULL; + GNUNET_CONTAINER_heap_iterate (neighbor_max_heap, &find_destination, &fdc); + +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Receives %s message for someone else!\n", "dv", "DV DATA"); +#endif + + if (fdc.dest == NULL) + { +#if DEBUG_DV_MESSAGES + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Receives %s message uid %u for someone we don't know (id %u)!\n", + my_short_id, "DV DATA", ntohl (incoming->uid), tid); +#endif + return GNUNET_OK; + } + destination = &fdc.dest->identity; + + if (0 == memcmp (destination, peer, sizeof (struct GNUNET_PeerIdentity))) + { + /* FIXME: create stat: routing loop-discard! */ + +#if DEBUG_DV_MESSAGES + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: DROPPING MESSAGE uid %u type %d, routing loop! Message immediately from %s!\n", + my_short_id, ntohl (incoming->uid), + ntohs (packed_message->type), GNUNET_i2s (&dn->identity)); +#endif + return GNUNET_OK; + } + + /* At this point we have a message, and we need to forward it on to the + * next DV hop. + */ +#if DEBUG_DV_MESSAGES + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: FORWARD %s message for %s, uid %u, size %d type %d, cost %u!\n", + my_short_id, "DV DATA", GNUNET_i2s (destination), + ntohl (incoming->uid), ntohs (packed_message->size), + ntohs (packed_message->type), pos->cost); +#endif + +#if DELAY_FORWARDS + if (GNUNET_TIME_absolute_get_duration (pos->last_gossip).abs_value < + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2).abs_value) + { + delayed_context = GNUNET_malloc (sizeof (struct DelayedMessageContext)); + memcpy (&delayed_context->dest, destination, + sizeof (struct GNUNET_PeerIdentity)); + memcpy (&delayed_context->sender, original_sender, + sizeof (struct GNUNET_PeerIdentity)); + delayed_context->message = GNUNET_malloc (packed_message_size); + memcpy (delayed_context->message, packed_message, packed_message_size); + delayed_context->message_size = packed_message_size; + delayed_context->uid = ntohl (incoming->uid); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 2500), + &send_message_delayed, delayed_context); + return GNUNET_OK; + } + else +#endif + { + ret = + send_message (destination, original_sender, NULL, packed_message, + packed_message_size, default_dv_priority, + ntohl (incoming->uid), + GNUNET_TIME_relative_get_forever ()); + } + if (ret != GNUNET_SYSERR) + return GNUNET_OK; + else + { +#if DEBUG_MESSAGE_DROP + char *direct_id = GNUNET_strdup (GNUNET_i2s (&dn->identity)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: DROPPING MESSAGE type %d, forwarding failed! Message immediately from %s!\n", + GNUNET_i2s (&my_identity), + ntohs (((struct GNUNET_MessageHeader *) &incoming[1])->type), + direct_id); + GNUNET_free (direct_id); +#endif + return GNUNET_SYSERR; + } +} + +#if DEBUG_DV +/** + * Iterator over hash map entries. + * + * @param cls closure (NULL) + * @param key current key code + * @param value value in the hash map (DistantNeighbor) + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +int +print_neighbors (void *cls, const GNUNET_HashCode * key, void *abs_value) +{ + struct DistantNeighbor *distant_neighbor = abs_value; + char my_shortname[5]; + char referrer_shortname[5]; + + memcpy (&my_shortname, GNUNET_i2s (&my_identity), 4); + my_shortname[4] = '\0'; + memcpy (&referrer_shortname, + GNUNET_i2s (&distant_neighbor->referrer->identity), 4); + referrer_shortname[4] = '\0'; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`%s' %s: Peer `%s', distance %d, referrer `%s' pkey: %s\n", + &my_shortname, "DV", GNUNET_i2s (&distant_neighbor->identity), + distant_neighbor->cost, &referrer_shortname, + distant_neighbor->pkey == NULL ? "no" : "yes"); + return GNUNET_YES; +} +#endif + +/** + * Scheduled task which gossips about known direct peers to other connected + * peers. Will run until called with reason shutdown. + */ +static void +neighbor_send_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NeighborSendContext *send_context = cls; + +#if DEBUG_DV_GOSSIP_SEND + char *encPeerAbout; + char *encPeerTo; +#endif + struct DistantNeighbor *about; + struct DirectNeighbor *to; + struct FastGossipNeighborList *about_list; + + p2p_dv_MESSAGE_NeighborInfo *message; + struct PendingMessage *pending_message; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { +#if DEBUG_DV_GOSSIP + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Called with reason shutdown, shutting down!\n", + GNUNET_i2s (&my_identity)); +#endif + return; + } + + if (send_context->fast_gossip_list_head != NULL) + { + about_list = send_context->fast_gossip_list_head; + about = about_list->about; + GNUNET_CONTAINER_DLL_remove (send_context->fast_gossip_list_head, + send_context->fast_gossip_list_tail, + about_list); + GNUNET_free (about_list); + } + else + { + /* FIXME: this may become a problem, because the heap walk has only one internal "walker". This means + * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default + * values for all connected peers) there may be a serious bias as to which peers get gossiped about! + * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as + * part of the walk_get_next call. Then the heap would have to keep a list of walks, or reset the walk + * whenever a modification has been detected. Yuck either way. Perhaps we could iterate over the heap + * once to get a list of peers to gossip about and gossip them over time... But then if one goes away + * in the mean time that becomes nasty. For now we'll just assume that the walking is done + * asynchronously enough to avoid major problems (-; + * + * NOTE: probably fixed once we decided send rate based on allowed bandwidth. + */ + about = GNUNET_CONTAINER_heap_walk_get_next (neighbor_min_heap); + } + to = send_context->toNeighbor; + + if ((about != NULL) && (to != about->referrer /* split horizon */ ) && +#if SUPPORT_HIDING + (about->hidden == GNUNET_NO) && +#endif + (to != NULL) && + (0 != + memcmp (&about->identity, &to->identity, + sizeof (struct GNUNET_PeerIdentity))) && (about->pkey != NULL)) + { +#if DEBUG_DV_GOSSIP_SEND + encPeerAbout = GNUNET_strdup (GNUNET_i2s (&about->identity)); + encPeerTo = GNUNET_strdup (GNUNET_i2s (&to->identity)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Sending info about peer %s id %u to directly connected peer %s\n", + GNUNET_i2s (&my_identity), encPeerAbout, about->our_id, + encPeerTo); + GNUNET_free (encPeerAbout); + GNUNET_free (encPeerTo); +#endif + about->last_gossip = GNUNET_TIME_absolute_get (); + pending_message = + GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (p2p_dv_MESSAGE_NeighborInfo)); + pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; + pending_message->importance = default_dv_priority; + pending_message->timeout = GNUNET_TIME_relative_get_forever (); + memcpy (&pending_message->recipient, &to->identity, + sizeof (struct GNUNET_PeerIdentity)); + pending_message->msg_size = sizeof (p2p_dv_MESSAGE_NeighborInfo); + message = (p2p_dv_MESSAGE_NeighborInfo *) pending_message->msg; + message->header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo)); + message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_GOSSIP); + message->cost = htonl (about->cost); + message->neighbor_id = htonl (about->our_id); + + memcpy (&message->pkey, about->pkey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + memcpy (&message->neighbor, &about->identity, + sizeof (struct GNUNET_PeerIdentity)); + + GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail, + core_pending_tail, pending_message); + + GNUNET_SCHEDULER_add_now (try_core_send, NULL); + /*if (core_transmit_handle == NULL) + * core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, GNUNET_YES, default_dv_priority, GNUNET_TIME_relative_get_forever(), &to->identity, sizeof(p2p_dv_MESSAGE_NeighborInfo), &core_transmit_notify, NULL); */ + + } + + if (send_context->fast_gossip_list_head != NULL) /* If there are other peers in the fast list, schedule right away */ + { +#if DEBUG_DV_PEER_NUMBERS + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "DV SERVICE: still in fast send mode\n"); +#endif + send_context->task = + GNUNET_SCHEDULER_add_now (&neighbor_send_task, send_context); + } + else + { +#if DEBUG_DV_PEER_NUMBERS + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "DV SERVICE: entering slow send mode\n"); +#endif + send_context->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_DV_DEFAULT_SEND_INTERVAL, + &neighbor_send_task, send_context); + } + + return; +} + + +/** + * Handle START-message. This is the first message sent to us + * by the client (can only be one!). + * + * @param cls closure (always NULL) + * @param client identification of the client + * @param message the actual message + */ +static void +handle_start (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' request from client\n", + "START"); +#endif + + client_handle = client; + + GNUNET_SERVER_client_keep (client_handle); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + +#if UNSIMPLER +/** + * Iterate over hash map entries for a distant neighbor, + * if direct neighbor matches context call send message + * + * @param cls closure, a DV_SendContext + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +int +send_iterator (void *cls, const GNUNET_HashCode * key, void *abs_value) +{ + struct DV_SendContext *send_context = cls; + struct DistantNeighbor *distant_neighbor = abs_value; + + if (memcmp (distant_neighbor->referrer, send_context->direct_peer, sizeof (struct GNUNET_PeerIdentity)) == 0) /* They match, send and free */ + { + send_message_via (&my_identity, distant_neighbor, send_context); + return GNUNET_NO; + } + return GNUNET_YES; +} +#endif + +/** + * Service server's handler for message send requests (which come + * bubbling up to us through the DV plugin). + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +void +handle_dv_send_message (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_DV_SendMessage *send_msg; + struct GNUNET_DV_SendResultMessage *send_result_msg; + struct PendingMessage *pending_message; + size_t address_len; + size_t message_size; + struct GNUNET_PeerIdentity *destination; + struct GNUNET_PeerIdentity *direct; + struct GNUNET_MessageHeader *message_buf; + char *temp_pos; + int offset; + static struct GNUNET_CRYPTO_HashAsciiEncoded dest_hash; + struct DV_SendContext *send_context; + +#if DEBUG_DV_MESSAGES + char *cbuf; + struct GNUNET_MessageHeader *packed_message; +#endif + + if (client_handle == NULL) + { + client_handle = client; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Setting initial client handle, never received `%s' message?\n", + "dv", "START"); + } + else if (client_handle != client) + { + client_handle = client; + /* What should we do in this case, assert fail or just log the warning? */ +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Setting client handle (was a different client!)!\n", "dv"); +#endif + } + + GNUNET_assert (ntohs (message->size) > sizeof (struct GNUNET_DV_SendMessage)); + send_msg = (struct GNUNET_DV_SendMessage *) message; + + address_len = ntohl (send_msg->addrlen); + GNUNET_assert (address_len == sizeof (struct GNUNET_PeerIdentity) * 2); + message_size = + ntohs (message->size) - sizeof (struct GNUNET_DV_SendMessage) - + address_len; + destination = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); + direct = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); + message_buf = GNUNET_malloc (message_size); + + temp_pos = (char *) &send_msg[1]; /* Set pointer to end of message */ + offset = 0; /* Offset starts at zero */ + + memcpy (destination, &temp_pos[offset], sizeof (struct GNUNET_PeerIdentity)); + offset += sizeof (struct GNUNET_PeerIdentity); + + memcpy (direct, &temp_pos[offset], sizeof (struct GNUNET_PeerIdentity)); + offset += sizeof (struct GNUNET_PeerIdentity); + + + memcpy (message_buf, &temp_pos[offset], message_size); + if (memcmp + (&send_msg->target, destination, + sizeof (struct GNUNET_PeerIdentity)) != 0) + { + GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */ + dest_hash.encoding[4] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: asked to send message to `%s', but address is for `%s'!", + "DV SERVICE", GNUNET_i2s (&send_msg->target), + (const char *) &dest_hash.encoding); + } + +#if DEBUG_DV_MESSAGES + cbuf = (char *) message_buf; + offset = 0; + while (offset < message_size) + { + packed_message = (struct GNUNET_MessageHeader *) &cbuf[offset]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: DV PLUGIN SEND uid %u type %d to %s\n", my_short_id, + ntohl (send_msg->uid), ntohs (packed_message->type), + GNUNET_i2s (destination)); + offset += ntohs (packed_message->size); + } + /*GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s: DV PLUGIN SEND uid %u type %d to %s\n", my_short_id, ntohl(send_msg->uid), ntohs(message_buf->type), GNUNET_i2s(destination)); */ +#endif + GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */ + dest_hash.encoding[4] = '\0'; + send_context = GNUNET_malloc (sizeof (struct DV_SendContext)); + + send_result_msg = GNUNET_malloc (sizeof (struct GNUNET_DV_SendResultMessage)); + send_result_msg->header.size = + htons (sizeof (struct GNUNET_DV_SendResultMessage)); + send_result_msg->header.type = + htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT); + send_result_msg->uid = send_msg->uid; /* No need to ntohl->htonl this */ + + send_context->importance = ntohl (send_msg->priority); + send_context->timeout = send_msg->timeout; + send_context->direct_peer = direct; + send_context->distant_peer = destination; + send_context->message = message_buf; + send_context->message_size = message_size; + send_context->send_result = send_result_msg; +#if DEBUG_DV_MESSAGES + send_context->uid = send_msg->uid; +#endif + + if (send_message_via (&my_identity, direct, send_context) != GNUNET_YES) + { + send_result_msg->result = htons (1); + pending_message = + GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct GNUNET_DV_SendResultMessage)); + pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; + memcpy (&pending_message[1], send_result_msg, + sizeof (struct GNUNET_DV_SendResultMessage)); + GNUNET_free (send_result_msg); + + GNUNET_CONTAINER_DLL_insert_after (plugin_pending_head, plugin_pending_tail, + plugin_pending_tail, pending_message); + + if (client_handle != NULL) + { + if (plugin_transmit_handle == NULL) + { + plugin_transmit_handle = + GNUNET_SERVER_notify_transmit_ready (client_handle, + sizeof (struct + GNUNET_DV_SendResultMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_to_plugin, NULL); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to queue message for plugin, must be one in progress already!!\n"); + } + } + GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */ + dest_hash.encoding[4] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s DV SEND failed to send message to destination `%s' via `%s'\n", + my_short_id, (const char *) &dest_hash.encoding, + GNUNET_i2s (direct)); + } + + /* In bizarro world GNUNET_SYSERR indicates that we succeeded */ +#if UNSIMPLER + if (GNUNET_SYSERR != + GNUNET_CONTAINER_multihashmap_get_multiple (extended_neighbors, + &destination->hashPubKey, + &send_iterator, send_context)) + { + send_result_msg->result = htons (1); + pending_message = + GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct GNUNET_DV_SendResultMessage)); + pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; + memcpy (&pending_message[1], send_result_msg, + sizeof (struct GNUNET_DV_SendResultMessage)); + GNUNET_free (send_result_msg); + + GNUNET_CONTAINER_DLL_insert_after (plugin_pending_head, plugin_pending_tail, + plugin_pending_tail, pending_message); + + if (client_handle != NULL) + { + if (plugin_transmit_handle == NULL) + { + plugin_transmit_handle = + GNUNET_SERVER_notify_transmit_ready (client_handle, + sizeof (struct + GNUNET_DV_SendResultMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_to_plugin, NULL); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to queue message for plugin, must be one in progress already!!\n"); + } + } + GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */ + dest_hash.encoding[4] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s DV SEND failed to send message to destination `%s' via `%s'\n", + my_short_id, (const char *) &dest_hash.encoding, + GNUNET_i2s (direct)); + } +#endif + GNUNET_free (message_buf); + GNUNET_free (send_context); + GNUNET_free (direct); + GNUNET_free (destination); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + +/** Forward declarations **/ +static int +handle_dv_gossip_message (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count); + +static int +handle_dv_disconnect_message (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count); +/** End forward declarations **/ + + +/** + * List of handlers for the messages understood by this + * service. + * + * Hmm... will we need to register some handlers with core and + * some handlers with our server here? Because core should be + * getting the incoming DV messages (from whichever lower level + * transport) and then our server should be getting messages + * from the dv_plugin, right? + */ +static struct GNUNET_CORE_MessageHandler core_handlers[] = { + {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0}, + {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0}, + {&handle_dv_disconnect_message, GNUNET_MESSAGE_TYPE_DV_DISCONNECT, 0}, + {NULL, 0, 0} +}; + +static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = { + {&handle_dv_send_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0}, + {&handle_start, NULL, GNUNET_MESSAGE_TYPE_DV_START, 0}, + {NULL, NULL, 0, 0} +}; + +/** + * Free a DistantNeighbor node, including removing it + * from the referer's list. + */ +static void +distant_neighbor_free (struct DistantNeighbor *referee) +{ + struct DirectNeighbor *referrer; + + referrer = referee->referrer; + if (referrer != NULL) + { + GNUNET_CONTAINER_DLL_remove (referrer->referee_head, referrer->referee_tail, + referee); + } + GNUNET_CONTAINER_heap_remove_node (referee->max_loc); + GNUNET_CONTAINER_heap_remove_node (referee->min_loc); + GNUNET_CONTAINER_multihashmap_remove_all (extended_neighbors, + &referee->identity.hashPubKey); + GNUNET_free_non_null (referee->pkey); + GNUNET_free (referee); +} + +/** + * Free a DirectNeighbor node, including removing it + * from the referer's list. + */ +static void +direct_neighbor_free (struct DirectNeighbor *direct) +{ + struct NeighborSendContext *send_context; + struct FastGossipNeighborList *about_list; + struct FastGossipNeighborList *prev_about; + + send_context = direct->send_context; + + if (send_context->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_context->task); + + about_list = send_context->fast_gossip_list_head; + while (about_list != NULL) + { + GNUNET_CONTAINER_DLL_remove (send_context->fast_gossip_list_head, + send_context->fast_gossip_list_tail, + about_list); + prev_about = about_list; + about_list = about_list->next; + GNUNET_free (prev_about); + } + GNUNET_free (send_context); + GNUNET_free (direct); +} + +/** + * Multihashmap iterator for sending out disconnect messages + * for a peer. + * + * @param cls the peer that was disconnected + * @param key key value stored under + * @param value the direct neighbor to send disconnect to + * + * @return GNUNET_YES to continue iteration, GNUNET_NO to stop + */ +static int +schedule_disconnect_messages (void *cls, const GNUNET_HashCode * key, + void *value) +{ + struct DisconnectContext *disconnect_context = cls; + struct DirectNeighbor *disconnected = disconnect_context->direct; + struct DirectNeighbor *notify = value; + struct PendingMessage *pending_message; + p2p_dv_MESSAGE_Disconnect *disconnect_message; + + if (memcmp + (¬ify->identity, &disconnected->identity, + sizeof (struct GNUNET_PeerIdentity)) == 0) + return GNUNET_YES; /* Don't send disconnect message to peer that disconnected! */ + + pending_message = + GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (p2p_dv_MESSAGE_Disconnect)); + pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; + pending_message->importance = default_dv_priority; + pending_message->timeout = GNUNET_TIME_relative_get_forever (); + memcpy (&pending_message->recipient, ¬ify->identity, + sizeof (struct GNUNET_PeerIdentity)); + pending_message->msg_size = sizeof (p2p_dv_MESSAGE_Disconnect); + disconnect_message = (p2p_dv_MESSAGE_Disconnect *) pending_message->msg; + disconnect_message->header.size = htons (sizeof (p2p_dv_MESSAGE_Disconnect)); + disconnect_message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT); + disconnect_message->peer_id = htonl (disconnect_context->distant->our_id); + + GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail, + core_pending_tail, pending_message); + + GNUNET_SCHEDULER_add_now (try_core_send, NULL); + /*if (core_transmit_handle == NULL) + * core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, GNUNET_YES, default_dv_priority, GNUNET_TIME_relative_get_forever(), ¬ify->identity, sizeof(p2p_dv_MESSAGE_Disconnect), &core_transmit_notify, NULL); */ + + return GNUNET_YES; +} + +/** + * Multihashmap iterator for freeing extended neighbors. + * + * @param cls NULL + * @param key key value stored under + * @param value the distant neighbor to be freed + * + * @return GNUNET_YES to continue iteration, GNUNET_NO to stop + */ +static int +free_extended_neighbors (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct DistantNeighbor *distant = value; + + distant_neighbor_free (distant); + return GNUNET_YES; +} + +/** + * Multihashmap iterator for freeing direct neighbors. + * + * @param cls NULL + * @param key key value stored under + * @param value the direct neighbor to be freed + * + * @return GNUNET_YES to continue iteration, GNUNET_NO to stop + */ +static int +free_direct_neighbors (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct DirectNeighbor *direct = value; + + direct_neighbor_free (direct); + return GNUNET_YES; +} + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "calling CORE_DISCONNECT\n"); + GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &print_neighbors, + NULL); +#endif + GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, + &free_extended_neighbors, NULL); + GNUNET_CONTAINER_multihashmap_destroy (extended_neighbors); + GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, + &free_direct_neighbors, NULL); + GNUNET_CONTAINER_multihashmap_destroy (direct_neighbors); + + GNUNET_CONTAINER_heap_destroy (neighbor_max_heap); + GNUNET_CONTAINER_heap_destroy (neighbor_min_heap); + + GNUNET_CORE_disconnect (coreAPI); + coreAPI = NULL; + GNUNET_PEERINFO_disconnect (peerinfo_handle); + GNUNET_SERVER_mst_destroy (coreMST); + GNUNET_free_non_null (my_short_id); +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CORE_DISCONNECT completed\n"); +#endif +} + +/** + * To be called on core init/fail. + */ +void +core_init (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *identity) +{ + + if (server == NULL) + { + GNUNET_SCHEDULER_cancel (cleanup_task); + GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + return; + } +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Core connection initialized, I am peer: %s\n", "dv", + GNUNET_i2s (identity)); +#endif + memcpy (&my_identity, identity, sizeof (struct GNUNET_PeerIdentity)); + my_short_id = GNUNET_strdup (GNUNET_i2s (&my_identity)); + coreAPI = server; +} + + +#if PKEY_NO_NEIGHBOR_ON_ADD +/** + * Iterator over hash map entries. + * + * @param cls closure + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +add_pkey_to_extended (void *cls, const GNUNET_HashCode * key, void *abs_value) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey = cls; + struct DistantNeighbor *distant_neighbor = abs_value; + + if (distant_neighbor->pkey == NULL) + { + distant_neighbor->pkey = + GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + memcpy (distant_neighbor->pkey, pkey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + } + + return GNUNET_YES; +} +#endif + +/** + * Iterator over hash map entries. + * + * @param cls closure + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +update_matching_neighbors (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct NeighborUpdateInfo *update_info = cls; + struct DistantNeighbor *distant_neighbor = value; + + if (update_info->referrer == distant_neighbor->referrer) /* Direct neighbor matches, update it's info and return GNUNET_NO */ + { + /* same referrer, cost change! */ + GNUNET_CONTAINER_heap_update_cost (neighbor_max_heap, + update_info->neighbor->max_loc, + update_info->cost); + GNUNET_CONTAINER_heap_update_cost (neighbor_min_heap, + update_info->neighbor->min_loc, + update_info->cost); + update_info->neighbor->last_activity = update_info->now; + update_info->neighbor->cost = update_info->cost; + update_info->neighbor->referrer_id = update_info->referrer_peer_id; + return GNUNET_NO; + } + + return GNUNET_YES; +} + + +/** + * Iterate over all current direct peers, add DISTANT newly connected + * peer to the fast gossip list for that peer so we get DV routing + * information out as fast as possible! + * + * @param cls the newly connected neighbor we will gossip about + * @param key the hashcode of the peer + * @param value the direct neighbor we should gossip to + * + * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise + */ +static int +add_distant_all_direct_neighbors (void *cls, const GNUNET_HashCode * key, + void *value) +{ + struct DirectNeighbor *direct = (struct DirectNeighbor *) value; + struct DistantNeighbor *distant = (struct DistantNeighbor *) cls; + struct NeighborSendContext *send_context = direct->send_context; + struct FastGossipNeighborList *gossip_entry; + +#if DEBUG_DV + char *encPeerAbout; + char *encPeerTo; +#endif + + if (distant == NULL) + { + return GNUNET_YES; + } + + if (memcmp + (&direct->identity, &distant->identity, + sizeof (struct GNUNET_PeerIdentity)) == 0) + { + return GNUNET_YES; /* Don't gossip to a peer about itself! */ + } + +#if SUPPORT_HIDING + if (distant->hidden == GNUNET_YES) + return GNUNET_YES; /* This peer should not be gossipped about (hidden) */ +#endif + gossip_entry = GNUNET_malloc (sizeof (struct FastGossipNeighborList)); + gossip_entry->about = distant; + + GNUNET_CONTAINER_DLL_insert_after (send_context->fast_gossip_list_head, + send_context->fast_gossip_list_tail, + send_context->fast_gossip_list_tail, + gossip_entry); +#if DEBUG_DV + encPeerAbout = GNUNET_strdup (GNUNET_i2s (&distant->identity)); + encPeerTo = GNUNET_strdup (GNUNET_i2s (&direct->identity)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Fast send info about peer %s id %u for directly connected peer %s\n", + GNUNET_i2s (&my_identity), encPeerAbout, distant->our_id, + encPeerTo); + GNUNET_free (encPeerAbout); + GNUNET_free (encPeerTo); +#endif + /*if (send_context->task != GNUNET_SCHEDULER_NO_TASK) + * GNUNET_SCHEDULER_cancel(send_context->task); */ + + send_context->task = + GNUNET_SCHEDULER_add_now (&neighbor_send_task, send_context); + return GNUNET_YES; +} + +/** + * Callback for hello address creation. + * + * @param cls closure, a struct HelloContext + * @param max maximum number of bytes that can be written to buf + * @param buf where to write the address information + * + * @return number of bytes written, 0 to signal the + * end of the iteration. + */ +static size_t +generate_hello_address (void *cls, size_t max, void *buf) +{ + struct HelloContext *hello_context = cls; + struct GNUNET_HELLO_Address hello_address; + char *addr_buffer; + size_t offset; + size_t size; + size_t ret; + + if (hello_context->addresses_to_add == 0) + return 0; + + /* Hello "address" will be concatenation of distant peer and direct peer identities */ + size = 2 * sizeof (struct GNUNET_PeerIdentity); + GNUNET_assert (max >= size); + + addr_buffer = GNUNET_malloc (size); + offset = 0; + /* Copy the distant peer identity to buffer */ + memcpy (addr_buffer, &hello_context->distant_peer, + sizeof (struct GNUNET_PeerIdentity)); + offset += sizeof (struct GNUNET_PeerIdentity); + /* Copy the direct peer identity to buffer */ + memcpy (&addr_buffer[offset], hello_context->direct_peer, + sizeof (struct GNUNET_PeerIdentity)); + memset (&hello_address.peer, 0, sizeof (struct GNUNET_PeerIdentity)); + hello_address.address = addr_buffer; + hello_address.transport_name = "dv"; + hello_address.address_length = size; + ret = + GNUNET_HELLO_add_address (&hello_address, + GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_UNIT_HOURS), buf, max); + + hello_context->addresses_to_add--; + + GNUNET_free (addr_buffer); + return ret; +} + + +/** + * Handles when a peer is either added due to being newly connected + * or having been gossiped about, also called when the cost for a neighbor + * needs to be updated. + * + * @param peer identity of the peer whose info is being added/updated + * @param pkey public key of the peer whose info is being added/updated + * @param referrer_peer_id id to use when sending to 'peer' + * @param referrer if this is a gossiped peer, who did we hear it from? + * @param cost the cost of communicating with this peer via 'referrer' + * + * @return the added neighbor, the updated neighbor or NULL (neighbor + * not added) + */ +static struct DistantNeighbor * +addUpdateNeighbor (const struct GNUNET_PeerIdentity *peer, + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey, + unsigned int referrer_peer_id, + struct DirectNeighbor *referrer, unsigned int cost) +{ + struct DistantNeighbor *neighbor; + struct DistantNeighbor *max; + struct GNUNET_TIME_Absolute now; + struct NeighborUpdateInfo *neighbor_update; + struct HelloContext *hello_context; + struct GNUNET_HELLO_Message *hello_msg; + unsigned int our_id; + char *addr1; + char *addr2; + int i; + +#if DEBUG_DV_PEER_NUMBERS + char *encAbout; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s Received sender id (%u)!\n", + "DV SERVICE", referrer_peer_id); +#endif + + now = GNUNET_TIME_absolute_get (); + neighbor = + GNUNET_CONTAINER_multihashmap_get (extended_neighbors, &peer->hashPubKey); + neighbor_update = GNUNET_malloc (sizeof (struct NeighborUpdateInfo)); + neighbor_update->neighbor = neighbor; + neighbor_update->cost = cost; + neighbor_update->now = now; + neighbor_update->referrer = referrer; + neighbor_update->referrer_peer_id = referrer_peer_id; + + if (neighbor != NULL) + { +#if USE_PEER_ID + memcpy (&our_id, &neighbor->identity, sizeof (unsigned int)); +#else + our_id = neighbor->our_id; +#endif + } + else + { +#if USE_PEER_ID + memcpy (&our_id, peer, sizeof (unsigned int)); +#else + our_id = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, + RAND_MAX - 1) + 1; +#endif + } + + /* Either we do not know this peer, or we already do but via a different immediate peer */ + if ((neighbor == NULL) || + (GNUNET_CONTAINER_multihashmap_get_multiple + (extended_neighbors, &peer->hashPubKey, &update_matching_neighbors, + neighbor_update) != GNUNET_SYSERR)) + { +#if AT_MOST_ONE + if ((neighbor != NULL) && (cost < neighbor->cost)) /* New cost is less than old, remove old */ + { + distant_neighbor_free (neighbor); + } + else if (neighbor != NULL) /* Only allow one DV connection to each peer */ + { + return NULL; + } +#endif + /* new neighbor! */ + if (cost > fisheye_depth) + { + /* too costly */ + GNUNET_free (neighbor_update); + return NULL; + } + +#if DEBUG_DV_PEER_NUMBERS + encAbout = GNUNET_strdup (GNUNET_i2s (peer)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: %s Chose NEW id (%u) for peer %s!\n", + GNUNET_i2s (&my_identity), "DV SERVICE", our_id, encAbout); + GNUNET_free (encAbout); +#endif + + if (max_table_size <= + GNUNET_CONTAINER_multihashmap_size (extended_neighbors)) + { + /* remove most expensive entry */ + max = GNUNET_CONTAINER_heap_peek (neighbor_max_heap); + GNUNET_assert (max != NULL); + if (cost > max->cost) + { + /* new entry most expensive, don't create */ + GNUNET_free (neighbor_update); + return NULL; + } + if (max->cost > 1) + { + /* only free if this is not a direct connection; + * we could theoretically have more direct + * connections than DV entries allowed total! */ + distant_neighbor_free (max); + } + } + + neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor)); + GNUNET_CONTAINER_DLL_insert (referrer->referee_head, referrer->referee_tail, + neighbor); + neighbor->max_loc = + GNUNET_CONTAINER_heap_insert (neighbor_max_heap, neighbor, cost); + neighbor->min_loc = + GNUNET_CONTAINER_heap_insert (neighbor_min_heap, neighbor, cost); + neighbor->referrer = referrer; + memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity)); + if (pkey != NULL) /* pkey will be null on direct neighbor addition */ + { + neighbor->pkey = + GNUNET_malloc (sizeof + (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + memcpy (neighbor->pkey, pkey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + } + else + neighbor->pkey = pkey; + + neighbor->last_activity = now; + neighbor->cost = cost; + neighbor->referrer_id = referrer_peer_id; + neighbor->our_id = our_id; + neighbor->hidden = + (cost == + DIRECT_NEIGHBOR_COST) + ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) == + 0) : GNUNET_NO; + + GNUNET_CONTAINER_multihashmap_put (extended_neighbors, &peer->hashPubKey, + neighbor, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + if (referrer_peer_id != 0) + { + for (i = 0; i < MAX_OUTSTANDING_MESSAGES; i++) + { + if (referrer->pending_messages[i].sender_id == referrer_peer_id) /* We have a queued message from just learned about peer! */ + { +#if DEBUG_DV_MESSAGES + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: learned about peer %llu from which we have a previous unknown message, processing!\n", + my_short_id, referrer_peer_id); +#endif + struct GNUNET_ATS_Information atsi[2]; + + atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); + atsi[0].value = htonl (referrer->pending_messages[i].distance); + atsi[1].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); + atsi[1].value = + htonl ((uint32_t) referrer->pending_messages[i]. + latency.rel_value); + handle_dv_data_message (NULL, &referrer->pending_messages[i].sender, + referrer->pending_messages[i].message, atsi, + 2); + GNUNET_free (referrer->pending_messages[i].message); + referrer->pending_messages[i].sender_id = 0; + } + } + } + if ((cost != DIRECT_NEIGHBOR_COST) && (neighbor->pkey != NULL)) + { + /* Added neighbor, now send HELLO to transport */ + hello_context = GNUNET_malloc (sizeof (struct HelloContext)); + hello_context->direct_peer = &referrer->identity; + memcpy (&hello_context->distant_peer, peer, + sizeof (struct GNUNET_PeerIdentity)); + hello_context->addresses_to_add = 1; + hello_msg = + GNUNET_HELLO_create (pkey, &generate_hello_address, hello_context); + GNUNET_assert (memcmp + (hello_context->direct_peer, &hello_context->distant_peer, + sizeof (struct GNUNET_PeerIdentity)) != 0); + addr1 = GNUNET_strdup (GNUNET_i2s (hello_context->direct_peer)); + addr2 = GNUNET_strdup (GNUNET_i2s (&hello_context->distant_peer)); +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: GIVING HELLO size %d for %s via %s to TRANSPORT\n", + my_short_id, GNUNET_HELLO_size (hello_msg), addr2, addr1); +#endif + GNUNET_free (addr1); + GNUNET_free (addr2); + send_to_plugin (hello_context->direct_peer, + GNUNET_HELLO_get_header (hello_msg), + GNUNET_HELLO_size (hello_msg), + &hello_context->distant_peer, cost); + GNUNET_free (hello_context); + GNUNET_free (hello_msg); + } + + } + else + { +#if DEBUG_DV_GOSSIP + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Already know peer %s distance %d, referrer id %d!\n", "dv", + GNUNET_i2s (peer), cost, referrer_peer_id); +#endif + } +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Size of extended_neighbors is %d\n", + "dv", GNUNET_CONTAINER_multihashmap_size (extended_neighbors)); +#endif + + GNUNET_free (neighbor_update); + return neighbor; +} + + +/** + * Core handler for dv disconnect messages. These will be used + * by us to tell transport via the dv plugin that a peer can + * no longer be contacted by us via a certain address. We should + * then propagate these messages on, given that the distance to + * the peer indicates we would have gossiped about it to others. + * + * @param cls closure + * @param peer peer which sent the message (immediate sender) + * @param message the message + * @param atsi performance data + * @param atsi_count number of entries in atsi + */ +static int +handle_dv_disconnect_message (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct DirectNeighbor *referrer; + struct DistantNeighbor *distant; + p2p_dv_MESSAGE_Disconnect *enc_message = + (p2p_dv_MESSAGE_Disconnect *) message; + + if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_Disconnect)) + { + return GNUNET_SYSERR; /* invalid message */ + } + + referrer = + GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey); + if (referrer == NULL) + return GNUNET_OK; + + distant = referrer->referee_head; + while (distant != NULL) + { + if (distant->referrer_id == ntohl (enc_message->peer_id)) + { + distant_neighbor_free (distant); + distant = referrer->referee_head; + } + else + distant = distant->next; + } + + return GNUNET_OK; +} + + +/** + * Core handler for dv gossip messages. These will be used + * by us to create a HELLO message for the newly peer containing + * which direct peer we can connect through, and what the cost + * is. This HELLO will then be scheduled for validation by the + * transport service so that it can be used by all others. + * + * @param cls closure + * @param peer peer which sent the message (immediate sender) + * @param message the message + * @param atsi performance data + * @param atsi_count number of entries in atsi + */ +static int +handle_dv_gossip_message (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct DirectNeighbor *referrer; + p2p_dv_MESSAGE_NeighborInfo *enc_message = + (p2p_dv_MESSAGE_NeighborInfo *) message; + + if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_NeighborInfo)) + { + return GNUNET_SYSERR; /* invalid message */ + } + +#if DEBUG_DV_GOSSIP_RECEIPT + char *encPeerAbout; + char *encPeerFrom; + + encPeerAbout = GNUNET_strdup (GNUNET_i2s (&enc_message->neighbor)); + encPeerFrom = GNUNET_strdup (GNUNET_i2s (peer)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Received %s message from peer %s about peer %s id %u distance %d!\n", + GNUNET_i2s (&my_identity), "DV GOSSIP", encPeerFrom, encPeerAbout, + ntohl (enc_message->neighbor_id), ntohl (enc_message->cost) + 1); + GNUNET_free (encPeerAbout); + GNUNET_free (encPeerFrom); +#endif + + referrer = + GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey); + if (referrer == NULL) + return GNUNET_OK; + + addUpdateNeighbor (&enc_message->neighbor, &enc_message->pkey, + ntohl (enc_message->neighbor_id), referrer, + ntohl (enc_message->cost) + 1); + + return GNUNET_OK; +} + + +/** + * Iterate over all currently known peers, add them to the + * fast gossip list for this peer so we get DV routing information + * out as fast as possible! + * + * @param cls the direct neighbor we will gossip to + * @param key the hashcode of the peer + * @param value the distant neighbor we should add to the list + * + * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise + */ +static int +add_all_extended_peers (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct NeighborSendContext *send_context = (struct NeighborSendContext *) cls; + struct DistantNeighbor *distant = (struct DistantNeighbor *) value; + struct FastGossipNeighborList *gossip_entry; + + if (memcmp + (&send_context->toNeighbor->identity, &distant->identity, + sizeof (struct GNUNET_PeerIdentity)) == 0) + return GNUNET_YES; /* Don't gossip to a peer about itself! */ + +#if SUPPORT_HIDING + if (distant->hidden == GNUNET_YES) + return GNUNET_YES; /* This peer should not be gossipped about (hidden) */ +#endif + gossip_entry = GNUNET_malloc (sizeof (struct FastGossipNeighborList)); + gossip_entry->about = distant; + + GNUNET_CONTAINER_DLL_insert_after (send_context->fast_gossip_list_head, + send_context->fast_gossip_list_tail, + send_context->fast_gossip_list_tail, + gossip_entry); + + return GNUNET_YES; +} + +#if INSANE_GOSSIP +/** + * Iterator over hash map entries. + * + * @param cls closure + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +gossip_all_to_all_iterator (void *cls, const GNUNET_HashCode * key, + void *abs_value) +{ + struct DirectNeighbor *direct = abs_value; + + GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, + &add_all_extended_peers, + direct->send_context); + + if (direct->send_context->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (direct->send_context->task); + + direct->send_context->task = + GNUNET_SCHEDULER_add_now (&neighbor_send_task, direct->send_context); + return GNUNET_YES; +} + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +gossip_all_to_all (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, + &gossip_all_to_all_iterator, NULL); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + &gossip_all_to_all, NULL); + +} +#endif +/** + * Iterate over all current direct peers, add newly connected peer + * to the fast gossip list for that peer so we get DV routing + * information out as fast as possible! + * + * @param cls the newly connected neighbor we will gossip about + * @param key the hashcode of the peer + * @param value the direct neighbor we should gossip to + * + * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise + */ +static int +add_all_direct_neighbors (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct DirectNeighbor *direct = (struct DirectNeighbor *) value; + struct DirectNeighbor *to = (struct DirectNeighbor *) cls; + struct DistantNeighbor *distant; + struct NeighborSendContext *send_context = direct->send_context; + struct FastGossipNeighborList *gossip_entry; + char *direct_id; + + + distant = + GNUNET_CONTAINER_multihashmap_get (extended_neighbors, + &to->identity.hashPubKey); + if (distant == NULL) + { + return GNUNET_YES; + } + + if (memcmp + (&direct->identity, &to->identity, + sizeof (struct GNUNET_PeerIdentity)) == 0) + { + return GNUNET_YES; /* Don't gossip to a peer about itself! */ + } + +#if SUPPORT_HIDING + if (distant->hidden == GNUNET_YES) + return GNUNET_YES; /* This peer should not be gossipped about (hidden) */ +#endif + direct_id = GNUNET_strdup (GNUNET_i2s (&direct->identity)); +#if DEBUG_DV_GOSSIP + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: adding peer %s to fast send list for %s\n", my_short_id, + GNUNET_i2s (&distant->identity), direct_id); +#endif + GNUNET_free (direct_id); + gossip_entry = GNUNET_malloc (sizeof (struct FastGossipNeighborList)); + gossip_entry->about = distant; + + GNUNET_CONTAINER_DLL_insert_after (send_context->fast_gossip_list_head, + send_context->fast_gossip_list_tail, + send_context->fast_gossip_list_tail, + gossip_entry); + if (send_context->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_context->task); + + send_context->task = + GNUNET_SCHEDULER_add_now (&neighbor_send_task, send_context); + //tc.reason = GNUNET_SCHEDULER_REASON_TIMEOUT; + //neighbor_send_task(send_context, &tc); + return GNUNET_YES; +} + +/** + * Type of an iterator over the hosts. Note that each + * host will be called with each available protocol. + * + * @param cls closure + * @param peer id of the peer, NULL for last call + * @param hello hello message for the peer (can be NULL) + * @param err_msg NULL if successful, otherwise contains error message + */ +static void +process_peerinfo (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, const char *err_msg) +{ + struct PeerIteratorContext *peerinfo_iterator = cls; + struct DirectNeighbor *neighbor = peerinfo_iterator->neighbor; + struct DistantNeighbor *distant = peerinfo_iterator->distant; + +#if DEBUG_DV_PEER_NUMBERS + char *neighbor_pid; +#endif + int sent; + + if (err_msg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Error in communication with PEERINFO service\n")); + /* return; */ + } + if (peer == NULL) + { + if (distant->pkey == NULL) + { +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to get peerinfo information for this peer, retrying!\n"); +#endif + peerinfo_iterator->ic = + GNUNET_PEERINFO_iterate (peerinfo_handle, + &peerinfo_iterator->neighbor->identity, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 3), + &process_peerinfo, peerinfo_iterator); + } + else + { + GNUNET_free (peerinfo_iterator); + } + return; + } + + if (memcmp + (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity) != 0)) + return; + + if ((hello != NULL) && + (GNUNET_HELLO_get_key (hello, &neighbor->pkey) == GNUNET_OK)) + { + if (distant->pkey == NULL) + { + distant->pkey = + GNUNET_malloc (sizeof + (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + memcpy (distant->pkey, &neighbor->pkey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + } + + sent = + GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, + &add_all_extended_peers, + neighbor->send_context); + if (stats != NULL) + { + GNUNET_STATISTICS_update (stats, + "# distant peers gossiped to direct neighbors", + sent, GNUNET_NO); + } +#if DEBUG_DV_PEER_NUMBERS + neighbor_pid = GNUNET_strdup (GNUNET_i2s (&neighbor->identity)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Gossipped %d extended peers to %s\n", + GNUNET_i2s (&my_identity), sent, neighbor_pid); +#endif + sent = + GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, + &add_all_direct_neighbors, + neighbor); + if (stats != NULL) + { + GNUNET_STATISTICS_update (stats, + "# direct peers gossiped to direct neighbors", + sent, GNUNET_NO); + } +#if DEBUG_DV_PEER_NUMBERS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Gossipped about %s to %d direct peers\n", + GNUNET_i2s (&my_identity), neighbor_pid, sent); + GNUNET_free (neighbor_pid); +#endif + neighbor->send_context->task = + GNUNET_SCHEDULER_add_now (&neighbor_send_task, neighbor->send_context); + } +} + + +/** + * Method called whenever a peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of entries in atsi + */ +static void +handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct DirectNeighbor *neighbor; + struct DistantNeighbor *about; + struct PeerIteratorContext *peerinfo_iterator; + int sent; + + uint32_t distance; + + /* Check for connect to self message */ + if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + + distance = get_atsi_distance (atsi, atsi_count); + if ((distance == DIRECT_NEIGHBOR_COST) && + (GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey) + == NULL)) + { + peerinfo_iterator = GNUNET_malloc (sizeof (struct PeerIteratorContext)); + neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor)); + neighbor->send_context = + GNUNET_malloc (sizeof (struct NeighborSendContext)); + neighbor->send_context->toNeighbor = neighbor; + memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity)); + + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONTAINER_multihashmap_put (direct_neighbors, + &peer->hashPubKey, + neighbor, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + about = addUpdateNeighbor (peer, NULL, 0, neighbor, DIRECT_NEIGHBOR_COST); + peerinfo_iterator->distant = about; + peerinfo_iterator->neighbor = neighbor; + peerinfo_iterator->ic = + GNUNET_PEERINFO_iterate (peerinfo_handle, peer, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 3), + &process_peerinfo, peerinfo_iterator); + + if ((about != NULL) && (about->pkey == NULL)) + { +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Newly added peer %s has NULL pkey!\n", GNUNET_i2s (peer)); +#endif + } + else if (about != NULL) + { + GNUNET_free (peerinfo_iterator); + } + } + else + { + about = + GNUNET_CONTAINER_multihashmap_get (extended_neighbors, + &peer->hashPubKey); + if ((GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey) + == NULL) && (about != NULL)) + { + sent = + GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, + &add_distant_all_direct_neighbors, + about); + if (stats != NULL) + GNUNET_STATISTICS_update (stats, + "# direct peers gossiped to new direct neighbors", + sent, GNUNET_NO); + } +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Distance (%d) greater than %d or already know about peer (%s), not re-adding!\n", + "dv", distance, DIRECT_NEIGHBOR_COST, GNUNET_i2s (peer)); +#endif + return; + } +} + +/** + * Method called whenever a given peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +void +handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct DirectNeighbor *neighbor; + struct DistantNeighbor *referee; + struct FindDestinationContext fdc; + struct DisconnectContext disconnect_context; + struct PendingMessage *pending_pos; + +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Receives core peer disconnect message!\n", "dv"); +#endif + + /* Check for disconnect from self message */ + if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + + neighbor = + GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey); + + if (neighbor == NULL) + { + return; + } + + pending_pos = core_pending_head; + while (NULL != pending_pos) + { + if (0 == + memcmp (&pending_pos->recipient, &neighbor->identity, + sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_CONTAINER_DLL_remove (core_pending_head, core_pending_tail, + pending_pos); + pending_pos = core_pending_head; + } + else + pending_pos = pending_pos->next; + } + + while (NULL != (referee = neighbor->referee_head)) + distant_neighbor_free (referee); + + fdc.dest = NULL; + fdc.tid = 0; + + GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &find_distant_peer, + &fdc); + + if (fdc.dest != NULL) + { + disconnect_context.direct = neighbor; + disconnect_context.distant = fdc.dest; + GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, + &schedule_disconnect_messages, + &disconnect_context); + } + + GNUNET_assert (neighbor->referee_tail == NULL); + if (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_remove (direct_neighbors, &peer->hashPubKey, + neighbor)) + { + GNUNET_break (0); + } + if ((neighbor->send_context != NULL) && + (neighbor->send_context->task != GNUNET_SCHEDULER_NO_TASK)) + GNUNET_SCHEDULER_cancel (neighbor->send_context->task); + GNUNET_free (neighbor); +} + + +/** + * Process dv requests. + * + * @param cls closure + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + unsigned long long max_hosts; + + cfg = c; + + /* FIXME: Read from config, or calculate, or something other than this! */ + max_hosts = DEFAULT_DIRECT_CONNECTIONS; + max_table_size = DEFAULT_DV_SIZE; + fisheye_depth = DEFAULT_FISHEYE_DEPTH; + + if (GNUNET_CONFIGURATION_have_value (cfg, "dv", "max_direct_connections")) + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, "dv", + "max_direct_connections", + &max_hosts)); + + if (GNUNET_CONFIGURATION_have_value (cfg, "dv", "max_total_connections")) + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, "dv", + "max_total_connections", + &max_table_size)); + + + if (GNUNET_CONFIGURATION_have_value (cfg, "dv", "fisheye_depth")) + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, "dv", + "fisheye_depth", + &fisheye_depth)); + + neighbor_min_heap = + GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + neighbor_max_heap = + GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); + + direct_neighbors = GNUNET_CONTAINER_multihashmap_create (max_hosts); + extended_neighbors = + GNUNET_CONTAINER_multihashmap_create (max_table_size * 3); + + GNUNET_SERVER_add_handlers (server, plugin_handlers); + coreAPI = GNUNET_CORE_connect (cfg, 1, NULL, /* FIXME: anything we want to pass around? */ + &core_init, &handle_core_connect, + &handle_core_disconnect, NULL, GNUNET_NO, NULL, + GNUNET_NO, core_handlers); + + if (coreAPI == NULL) + return; + + coreMST = GNUNET_SERVER_mst_create (&tokenized_message_handler, NULL); + + peerinfo_handle = GNUNET_PEERINFO_connect (cfg); + + if (peerinfo_handle == NULL) + { + GNUNET_CORE_disconnect (coreAPI); + return; + } + + /* Scheduled the task to clean up when shutdown is called */ + cleanup_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, NULL); +} + + +/** + * The main function for the dv service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "dv", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; +} diff --git a/src/dv/plugin_transport_dv.c b/src/dv/plugin_transport_dv.c new file mode 100644 index 0000000..8ee49c5 --- /dev/null +++ b/src/dv/plugin_transport_dv.c @@ -0,0 +1,452 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dv/plugin_transport_dv.c + * @brief DV transport service, takes incoming DV requests and deals with + * the DV service + * @author Nathan Evans + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_protocols.h" +#include "gnunet_connection_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_service_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_dv_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" +#include "dv.h" + +#define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin; + + +/** + * Session handle for connections. + */ +struct Session +{ + + /** + * Stored in a linked list. + */ + struct Session *next; + + /** + * Pointer to the global plugin struct. + */ + struct Plugin *plugin; + + /** + * The client (used to identify this connection) + */ + /* void *client; */ + + /** + * Continuation function to call once the transmission buffer + * has again space available. NULL if there is no + * continuation to call. + */ + GNUNET_TRANSPORT_TransmitContinuation transmit_cont; + + /** + * Closure for transmit_cont. + */ + void *transmit_cont_cls; + + /** + * To whom are we talking to (set to our identity + * if we are still waiting for the welcome message) + */ + struct GNUNET_PeerIdentity sender; + + /** + * At what time did we reset last_received last? + */ + struct GNUNET_TIME_Absolute last_quota_update; + + /** + * How many bytes have we received since the "last_quota_update" + * timestamp? + */ + uint64_t last_received; + + /** + * Number of bytes per ms that this peer is allowed + * to send to us. + */ + uint32_t quota; + +}; + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin +{ + /** + * Our environment. + */ + struct GNUNET_TRANSPORT_PluginEnvironment *env; + + /** + * List of open sessions. + */ + struct Session *sessions; + + /** + * Our server. + */ + //struct GNUNET_SERVER_Handle *server; + + /* + * Handle to the running service. + */ + //struct GNUNET_SERVICE_Context *service; + + /** + * Copy of the handler array where the closures are + * set to this struct's instance. + */ + struct GNUNET_SERVER_MessageHandler *handlers; + + /** + * Handle to the DV service + */ + struct GNUNET_DV_Handle *dv_handle; + +}; + +/** + * Handler for messages received from the DV service. + */ +void +handle_dv_message_received (void *cls, struct GNUNET_PeerIdentity *sender, + char *msg, size_t msg_len, uint32_t distance, + char *sender_address, size_t sender_address_len) +{ + struct Plugin *plugin = cls; + +#if DEBUG_DV_MESSAGES + char *my_id; + + my_id = GNUNET_strdup (GNUNET_i2s (plugin->env->my_identity)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "plugin_transport_dv", + _("%s Received message from %s of type %d, distance %u!\n"), + my_id, GNUNET_i2s (sender), + ntohs (((struct GNUNET_MessageHeader *) msg)->type), + distance); + if (sender_address_len == (2 * sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "plugin_transport_dv", + "Parsed sender address: %s:%s\n", + GNUNET_i2s ((struct GNUNET_PeerIdentity *) sender_address), + GNUNET_h2s (& + ((struct GNUNET_PeerIdentity *) + &sender_address[sizeof + (struct + GNUNET_PeerIdentity)])->hashPubKey)); + } + + GNUNET_free_non_null (my_id); +#endif + struct GNUNET_ATS_Information ats[1]; + + ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); + ats[0].value = htonl (distance); + + plugin->env->receive (plugin->env->cls, sender, + (struct GNUNET_MessageHeader *) msg, + (const struct GNUNET_ATS_Information *) &ats, 1, NULL, + sender_address, sender_address_len); + +} + + +/* Question: how does the transport service learn of a newly connected (gossipped about) + * DV peer? Should the plugin (here) create a HELLO for that peer and send it along, + * or should the DV service create a HELLO and send it to us via the other part? + */ + +/** + * Function that can be used by the transport service to transmit + * a message using the plugin. + * + * @param cls closure + * @param session the session used + * @param priority how important is the message + * @param msgbuf the message to transmit + * @param msgbuf_size number of bytes in 'msgbuf' + * @param timeout when should we time out + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...) + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV) + */ +static ssize_t +dv_plugin_send (void *cls, + struct Session *session, + const char *msgbuf, size_t msgbuf_size, unsigned int priority, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + int ret = -1; +#if 0 + struct Plugin *plugin = cls; + + ret = + GNUNET_DV_send (plugin->dv_handle, &session->sender, + msgbuf, msgbuf_size, priority, + timeout, addr, addrlen, cont, cont_cls); +#endif + return ret; +} + + + +/** + * Function that can be used to force the plugin to disconnect + * from the given peer and cancel all previous transmissions + * (and their continuations). + * + * @param cls closure + * @param target peer from which to disconnect + */ +static void +dv_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +{ + // struct Plugin *plugin = cls; + // TODO: Add message type to send to dv service to "disconnect" a peer +} + + +/** + * Convert the transports address to a nice, human-readable + * format. + * + * @param cls closure + * @param type name of the transport that generated the address + * @param addr one of the addresses of the host, NULL for the last address + * the specific address format depends on the transport + * @param addrlen length of the address + * @param numeric should (IP) addresses be displayed in numeric form? + * @param timeout after how long should we give up? + * @param asc function to call on each string + * @param asc_cls closure for asc + */ +static void +dv_plugin_address_pretty_printer (void *cls, const char *type, const void *addr, + size_t addrlen, int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressStringCallback asc, + void *asc_cls) +{ + char *dest_peer; + char *via_peer; + char *print_string; + char *addr_buf = (char *) addr; + + if (addrlen != sizeof (struct GNUNET_PeerIdentity) * 2) + { + asc (asc_cls, NULL); + } + else + { + dest_peer = + GNUNET_strdup (GNUNET_i2s ((struct GNUNET_PeerIdentity *) addr)); + via_peer = + GNUNET_strdup (GNUNET_i2s + ((struct GNUNET_PeerIdentity *) + &addr_buf[sizeof (struct GNUNET_PeerIdentity)])); + GNUNET_asprintf (&print_string, "DV Peer `%s' via peer`%s'", dest_peer, + via_peer); + asc (asc_cls, print_string); + asc (asc_cls, NULL); + GNUNET_free (via_peer); + GNUNET_free (dest_peer); + GNUNET_free (print_string); + } +} + +/** + * Convert the DV address to a pretty string. + * + * @param cls closure + * @param addr the (hopefully) DV address + * @param addrlen the length of the address + * + * @return string representing the DV address + */ +static const char * +address_to_string (void *cls, const void *addr, size_t addrlen) +{ + static char return_buffer[2 * 4 + 2]; // Two four character peer identity prefixes a ':' and '\0' + + struct GNUNET_CRYPTO_HashAsciiEncoded peer_hash; + struct GNUNET_CRYPTO_HashAsciiEncoded via_hash; + struct GNUNET_PeerIdentity *peer; + struct GNUNET_PeerIdentity *via; + char *addr_buf = (char *) addr; + + if (addrlen == (2 * sizeof (struct GNUNET_PeerIdentity))) + { + peer = (struct GNUNET_PeerIdentity *) addr_buf; + via = + (struct GNUNET_PeerIdentity *) + &addr_buf[sizeof (struct GNUNET_PeerIdentity)]; + + GNUNET_CRYPTO_hash_to_enc (&peer->hashPubKey, &peer_hash); + peer_hash.encoding[4] = '\0'; + GNUNET_CRYPTO_hash_to_enc (&via->hashPubKey, &via_hash); + via_hash.encoding[4] = '\0'; + GNUNET_snprintf (return_buffer, sizeof (return_buffer), "%s:%s", &peer_hash, + &via_hash); + } + else + return NULL; + + return return_buffer; +} + +/** + * Another peer has suggested an address for this peer and transport + * plugin. Check that this could be a valid address. This function + * is not expected to 'validate' the address in the sense of trying to + * connect to it but simply to see if the binary format is technically + * legal for establishing a connection to this peer (and make sure that + * the address really corresponds to our network connection/settings + * and not some potential man-in-the-middle). + * + * @param cls closure + * @param addr pointer to the address + * @param addrlen length of addr + * @return GNUNET_OK if this is a plausible address for this peer + * and transport, GNUNET_SYSERR if not + * + */ +static int +dv_plugin_check_address (void *cls, const void *addr, size_t addrlen) +{ + struct Plugin *plugin = cls; + + /* Verify that the first peer of this address matches our peer id! */ + if ((addrlen != (2 * sizeof (struct GNUNET_PeerIdentity))) || + (0 != + memcmp (addr, plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Address not correct size or identity doesn't match ours!\n", + GNUNET_i2s (plugin->env->my_identity)); + if (addrlen == (2 * sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer in address is %s\n", + GNUNET_i2s (addr)); + } + return GNUNET_SYSERR; + } + + return GNUNET_OK; +} + + + +/** + * Create a new session to transmit data to the target + * This session will used to send data to this peer and the plugin will + * notify us by calling the env->session_end function + * + * @param cls the plugin + * @param target the neighbour id + * @param addr pointer to the address + * @param addrlen length of addr + * @return the session if the address is valid, NULL otherwise + */ +static struct Session * +dv_get_session (void *cls, + const struct GNUNET_HELLO_Address *address) +{ + return NULL; +} + + +/** + * Entry point for the plugin. + */ +void * +libgnunet_plugin_transport_dv_init (void *cls) +{ + struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; + struct GNUNET_TRANSPORT_PluginFunctions *api; + struct Plugin *plugin; + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + + plugin->dv_handle = + GNUNET_DV_connect (env->cfg, &handle_dv_message_received, plugin); + + if (plugin->dv_handle == NULL) + { + GNUNET_free (plugin); + return NULL; + } + + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = plugin; + api->send = &dv_plugin_send; + api->disconnect = &dv_plugin_disconnect; + api->address_pretty_printer = &dv_plugin_address_pretty_printer; + api->check_address = &dv_plugin_check_address; + api->address_to_string = &address_to_string; + api->get_session = dv_get_session; + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +libgnunet_plugin_transport_dv_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + if (plugin->dv_handle != NULL) + GNUNET_DV_disconnect (plugin->dv_handle); + + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + +/* end of plugin_transport_dv.c */ diff --git a/src/dv/test_transport_api_dv.c b/src/dv/test_transport_api_dv.c new file mode 100644 index 0000000..386ea5f --- /dev/null +++ b/src/dv/test_transport_api_dv.c @@ -0,0 +1,1247 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file dv/test_transport_api_dv.c + * @brief base testcase for testing distance vector transport + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" + +#define VERBOSE 1 + +#define TEST_ALL GNUNET_NO + +/** + * How long until we fail the whole testcase? + */ +#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) + +/** + * How long until we give up on starting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 500) + +#define DEFAULT_NUM_PEERS 4 + +#define DEFAULT_ADDITIONAL_MESSAGES 2 + +#define MAX_OUTSTANDING_CONNECTIONS 100 + +static float fail_percentage = 0.00; + +static int ok; + +static unsigned long long num_additional_messages; + +static unsigned long long num_peers; + +static unsigned int total_connections; + +static unsigned int failed_connections; + +static unsigned int total_server_connections; + +static unsigned int total_messages_received; + +static unsigned int total_other_expected_messages; + +static unsigned int temp_total_other_messages; + +static unsigned int total_other_messages; + +static unsigned int expected_messages; + +static unsigned int expected_connections; + +static unsigned long long peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +const struct GNUNET_CONFIGURATION_Handle *main_cfg; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static char *dotOutFileName = "topology.dot"; + +static FILE *dotOutFile; + +static char *blacklist_transports; + +static int transmit_ready_scheduled; + +static int transmit_ready_failed; + +static int transmit_ready_called; + +static enum GNUNET_TESTING_Topology topology; + +static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ + +static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ + +static enum GNUNET_TESTING_TopologyOption connect_topology_option = + GNUNET_TESTING_TOPOLOGY_OPTION_ALL; + +static double connect_topology_option_modifier = 0.0; + +static char *test_directory; + +struct GNUNET_CONTAINER_MultiHashMap *peer_daemon_hash; + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct GNUNET_TestMessage +{ + /** + * Header of the message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this message. + */ + uint32_t uid; +}; +GNUNET_NETWORK_STRUCT_END + +struct PeerContext +{ + /* This is a linked list */ + struct PeerContext *next; + + /** + * Handle to the daemon + */ + struct GNUNET_TESTING_Daemon *daemon; + + /* Handle to the peer core */ + struct GNUNET_CORE_Handle *peer_handle; +}; + +static struct PeerContext *all_peers; + +struct TestMessageContext +{ + /* This is a linked list */ + struct TestMessageContext *next; + + /* Handle to the sending peer core */ + struct GNUNET_CORE_Handle *peer1handle; + + /* Handle to the receiving peer core */ + struct GNUNET_CORE_Handle *peer2handle; + + /* Handle to the sending peer daemon */ + struct GNUNET_TESTING_Daemon *peer1; + + /* Handle to the receiving peer daemon */ + struct GNUNET_TESTING_Daemon *peer2; + + /* Identifier for this message, so we don't disconnect other peers! */ + uint32_t uid; + + /* Task for disconnecting cores, allow task to be cancelled on shutdown */ + GNUNET_SCHEDULER_TaskIdentifier disconnect_task; +}; + +static struct TestMessageContext *test_messages; + +static struct TestMessageContext *other_test_messages; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (pg != NULL); + struct PeerContext *peer_pos; + struct PeerContext *free_peer_pos; + struct TestMessageContext *pos; + struct TestMessageContext *free_pos; + + die_task = GNUNET_SCHEDULER_NO_TASK; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Called finish testing, stopping daemons.\n"); +#endif + peer_pos = all_peers; + while (peer_pos != NULL) + { + if (peer_pos->peer_handle != NULL) + GNUNET_CORE_disconnect (peer_pos->peer_handle); + free_peer_pos = peer_pos; + peer_pos = peer_pos->next; + GNUNET_free (free_peer_pos); + } + all_peers = NULL; + + pos = test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); + } + GNUNET_free (free_pos); + } + + pos = other_test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); + } + GNUNET_free (free_pos); + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", + transmit_ready_scheduled, transmit_ready_failed, + transmit_ready_called); +#endif + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); +#endif + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); +#endif + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } + + ok = 0; +} + + +static void +disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestMessageContext *pos = cls; + + /* Disconnect from the respective cores */ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n", + GNUNET_i2s (&pos->peer1->id)); +#endif + if (pos->peer1handle != NULL) + GNUNET_CORE_disconnect (pos->peer1handle); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); +#endif + if (pos->peer2handle != NULL) + GNUNET_CORE_disconnect (pos->peer2handle); + /* Set handles to NULL so test case can be ended properly */ + pos->peer1handle = NULL; + pos->peer2handle = NULL; + pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK; + /* Decrement total connections so new can be established */ + total_server_connections -= 2; +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *msg = cls; + struct TestMessageContext *pos; + struct TestMessageContext *free_pos; + struct PeerContext *peer_pos; + struct PeerContext *free_peer_pos; + + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "End badly was called (%s)... stopping daemons.\n", msg); + + peer_pos = all_peers; + while (peer_pos != NULL) + { + if (peer_pos->peer_handle != NULL) + GNUNET_CORE_disconnect (peer_pos->peer_handle); + free_peer_pos = peer_pos; + peer_pos = peer_pos->next; + GNUNET_free (free_peer_pos); + } + all_peers = NULL; + + pos = test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + GNUNET_free (free_pos); + } + + pos = other_test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); + } + GNUNET_free (free_pos); + } + + if (pg != NULL) + { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 7331; /* Opposite of leet */ + } + else + ok = 401; /* Never got peers started */ + + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } +} + +static void +send_other_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Get distance information from 'atsi'. + * + * @param atsi performance data + * @return connected transport distance + */ +static uint32_t +get_atsi_distance (const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + unsigned int i; + + for (i = 0; i < atsi_count; i++) + { + if (ntohl (atsi->type) == GNUNET_ATS_QUALITY_NET_DISTANCE) + return ntohl (atsi->value); + } + + GNUNET_break (0); + /* FIXME: we do not have distance data? Assume direct neighbor. */ + return 1; +} + + +static int +process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct TestMessageContext *pos = cls; + struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message; + +#if VERBOSE + uint32_t distance; +#endif + if (pos->uid != ntohl (msg->uid)) + return GNUNET_OK; + +#if VERBOSE + distance = get_atsi_distance (atsi, atsi_count); +#endif + GNUNET_assert (0 == + memcmp (peer, &pos->peer1->id, + sizeof (struct GNUNET_PeerIdentity))); + if (total_other_expected_messages == 0) + { + total_messages_received++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received message from `%4s', type %d, uid %u, distance %u.\n", + GNUNET_i2s (peer), ntohs (message->type), ntohl (msg->uid), + distance); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total messages received %d, expected %d.\n", + total_messages_received, expected_messages); +#endif + } + else + { + total_other_messages++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received message from `%4s', type %d, uid %u, distance %u.\n", + GNUNET_i2s (peer), ntohs (message->type), ntohl (msg->uid), + distance); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total OTHER messages received %d, expected %d.\n", + total_other_messages, total_other_expected_messages); +#endif + } + + if ((total_messages_received == expected_messages) && + (total_other_messages == 0)) + { + GNUNET_SCHEDULER_cancel (die_task); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling timeout from DV connections.\n"); +#endif + die_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, + "waiting for DV peers to connect!"); + } + else if ((total_other_expected_messages > 0) && + (total_other_messages == total_other_expected_messages)) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } + else + { + pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos); + } + + return GNUNET_OK; +} + +static size_t +transmit_ready (void *cls, size_t size, void *buf) +{ + struct GNUNET_TestMessage *m; + struct TestMessageContext *pos = cls; + + GNUNET_assert (buf != NULL); + m = (struct GNUNET_TestMessage *) buf; + m->header.type = htons (MTYPE); + m->header.size = htons (sizeof (struct GNUNET_TestMessage)); + m->uid = htonl (pos->uid); + transmit_ready_called++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", + GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled, + transmit_ready_called); +#endif + return sizeof (struct GNUNET_TestMessage); +} + + +static struct GNUNET_CORE_MessageHandler no_handlers[] = { + {NULL, 0, 0} +}; + +static struct GNUNET_CORE_MessageHandler handlers[] = { + {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)}, + {NULL, 0, 0} +}; + +/** + * Notify of all peer1's peers, once peer 2 is found, schedule connect + * to peer two for message send. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data for the connection + * @param atsi_count number of ATS information included + */ +static void +connect_notify_peer2 (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct TestMessageContext *pos = cls; + + if (0 == memcmp (&pos->peer1->id, peer, sizeof (struct GNUNET_PeerIdentity))) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core connection from `%s' to `%4s' verfied, sending message!\n", + GNUNET_i2s (&pos->peer2->id), GNUNET_h2s (&peer->hashPubKey)); +#endif + if (NULL == + GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, + TIMEOUT, &pos->peer2->id, + sizeof (struct GNUNET_TestMessage), + &transmit_ready, pos)) + { + /* This probably shouldn't happen, but it does (timing issue?) */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); + transmit_ready_failed++; + total_other_expected_messages--; + } + else + { + transmit_ready_scheduled++; + } + } +} + +static void +init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core connection to `%4s' established, awaiting connections.\n", + GNUNET_i2s (my_identity)); +#endif + total_server_connections++; +} + +/** + * Notify of all peer1's peers, once peer 2 is found, schedule connect + * to peer two for message send. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data for the connection + * @param atsi_count number of atsi datums + */ +static void +connect_notify_peer1 (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct TestMessageContext *pos = cls; + + if (0 == memcmp (&pos->peer2->id, peer, sizeof (struct GNUNET_PeerIdentity))) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core connection from `%s' to `%4s' verified.\n", + GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey)); +#endif + /* + * Connect to the receiving peer + */ + pos->peer2handle = + GNUNET_CORE_connect (pos->peer2->cfg, 1, pos, &init_notify_peer2, + &connect_notify_peer2, NULL, NULL, GNUNET_YES, + NULL, GNUNET_YES, handlers); + } +} + +static void +init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + total_server_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core connection to `%4s' established, awaiting connections...\n", + GNUNET_i2s (my_identity)); +#endif +} + + +static void +send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestMessageContext *pos = cls; + + if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL)) + return; + + if (die_task == GNUNET_SCHEDULER_NO_TASK) + { + die_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, + "from create topology (timeout)"); + } + + if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS) + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), + &send_test_messages, pos); + return; /* Otherwise we'll double schedule messages here! */ + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attempting to send test message from %s to %s\n", + pos->peer1->shortname, pos->peer2->shortname); +#endif + /* + * Connect to the sending peer + */ + pos->peer1handle = + GNUNET_CORE_connect (pos->peer1->cfg, 1, pos, &init_notify_peer1, + &connect_notify_peer1, NULL, NULL, GNUNET_NO, NULL, + GNUNET_NO, no_handlers); + + GNUNET_assert (pos->peer1handle != NULL); + + if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS) + { + GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next); + } + else + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), + &send_test_messages, pos->next); + } +} + +static void +send_other_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestMessageContext *pos; + struct TestMessageContext *free_pos; + struct PeerContext *peer_pos; + +#if TEST_ALL + struct PeerContext *inner_peer_pos; + struct TestMessageContext *temp_context; +#endif + peer_pos = all_peers; + while (peer_pos != NULL) + { + if (peer_pos->peer_handle != NULL) + { + GNUNET_CORE_disconnect (peer_pos->peer_handle); + peer_pos->peer_handle = NULL; + } +#if TEST_ALL + inner_peer_pos = all_peers; + while (inner_peer_pos != NULL) + { + if (inner_peer_pos != peer_pos) + { + temp_total_other_messages++; + temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); + temp_context->peer1 = peer_pos->daemon; + temp_context->peer2 = inner_peer_pos->daemon; + temp_context->next = other_test_messages; + temp_context->uid = total_connections + temp_total_other_messages; + temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; + other_test_messages = temp_context; + } + inner_peer_pos = inner_peer_pos->next; + } +#endif + peer_pos = peer_pos->next; + } + all_peers = NULL; + + pos = test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); + } + GNUNET_free (free_pos); + } + test_messages = NULL; + + total_other_expected_messages = temp_total_other_messages; + if (total_other_expected_messages == 0) + { + GNUNET_SCHEDULER_add_now (&end_badly, + "send_other_messages had 0 messages to send, no DV connections made!"); + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Preparing to send %d other test messages\n", + total_other_expected_messages); +#endif + + GNUNET_SCHEDULER_add_now (&send_test_messages, other_test_messages); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 250), &end_badly, + "from send_other_messages"); +} + +static void +topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + struct TestMessageContext *temp_context; + + if (emsg == NULL) + { + total_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connected peer %s to peer %s, distance %u\n", + first_daemon->shortname, second_daemon->shortname, distance); +#endif + temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); + temp_context->peer1 = first_daemon; + temp_context->peer2 = second_daemon; + temp_context->next = test_messages; + temp_context->uid = total_connections; + temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; + test_messages = temp_context; + expected_messages++; + } +#if VERBOSE + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + } +#endif + + if (total_connections == expected_connections) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %u total connections, which is our target number! Calling send messages.\n", + total_connections); +#endif + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); + } + else if (total_connections + failed_connections == expected_connections) + { + if (failed_connections < + (unsigned int) (fail_percentage * total_connections)) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + /* FIXME: ret value!? */ GNUNET_SCHEDULER_add_now (&send_test_messages, + test_messages); + } + else + { + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many failed connections)"); + } + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Have %d total connections, %d failed connections, Want %d (at least %d)\n", + total_connections, failed_connections, expected_connections, + expected_connections - + (unsigned int) (fail_percentage * expected_connections)); +#endif + } +} + + +/** + * Method called whenever a given peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data about this peer's connection + * @param atsi_count number of atsi datums + * + */ +static void +all_connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_TESTING_Daemon *d = cls; + struct GNUNET_TESTING_Daemon *second_daemon; + char *second_shortname; + +#if !TEST_ALL + struct TestMessageContext *temp_context; +#endif + uint32_t distance; + + if (0 == memcmp (&d->id, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + second_shortname = GNUNET_strdup (GNUNET_i2s (peer)); + distance = get_atsi_distance (atsi, atsi_count); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connected peer %s to peer %s, distance %u\n", d->shortname, + second_shortname, distance); +#endif + + second_daemon = + GNUNET_CONTAINER_multihashmap_get (peer_daemon_hash, &peer->hashPubKey); + + if (second_daemon == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Couldn't find second peer!\n"); + GNUNET_free (second_shortname); + return; + } +#if !TEST_ALL + if (distance > 1) + { + temp_total_other_messages++; + temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); + temp_context->peer1 = d; + temp_context->peer2 = second_daemon; + temp_context->next = other_test_messages; + temp_context->uid = total_connections + temp_total_other_messages; + temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; + other_test_messages = temp_context; + } +#endif + + if (dotOutFile != NULL) + { + if (distance == 1) + FPRINTF (dotOutFile, "\tn%s -- n%s;\n", d->shortname, second_shortname); + else if (distance == 2) + FPRINTF (dotOutFile, "\tn%s -- n%s [color=blue];\n", d->shortname, + second_shortname); + else if (distance == 3) + FPRINTF (dotOutFile, "\tn%s -- n%s [color=red];\n", d->shortname, + second_shortname); + else if (distance == 4) + FPRINTF (dotOutFile, "\tn%s -- n%s [color=green];\n", d->shortname, + second_shortname); + else + FPRINTF (dotOutFile, "\tn%s -- n%s [color=brown];\n", d->shortname, + second_shortname); + } + GNUNET_free (second_shortname); + + if (temp_total_other_messages == num_additional_messages) + { + /* FIXME: ret value!? */ GNUNET_SCHEDULER_add_now (&send_other_messages, + NULL); + } +} + +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct PeerContext *new_peer; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", + (num_peers - peers_left) + 1, num_peers); +#endif + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONTAINER_multihashmap_put (peer_daemon_hash, + &id->hashPubKey, d, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + + new_peer = GNUNET_malloc (sizeof (struct PeerContext)); + new_peer->peer_handle = + GNUNET_CORE_connect (cfg, 1, d, NULL, &all_connect_handler, NULL, NULL, + GNUNET_NO, NULL, GNUNET_NO, no_handlers); + new_peer->daemon = d; + new_peer->next = all_peers; + all_peers = new_peer; + peers_left--; + + if (peers_left == 0) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now creating topology!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + expected_connections = -1; + if ((pg != NULL) && (peers_left == 0)) + { + expected_connections = + GNUNET_TESTING_connect_topology (pg, connection_topology, + connect_topology_option, + connect_topology_option_modifier, + TIMEOUT, 12, NULL, NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", + expected_connections); +#endif + } + + if (expected_connections == GNUNET_SYSERR) + { + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from connect topology (bad return)"); + } + else + { + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, + "from connect topology (timeout)"); + } + ok = 0; + } +} + +/** + * Callback indicating that the hostkey was created for a peer. + * + * @param cls NULL + * @param id the peer identity + * @param d the daemon handle (pretty useless at this point, remove?) + * @param emsg non-null on failure + */ +static void +hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Hostkey callback received error: %s\n", emsg); + } + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostkey created for peer `%s'\n", + GNUNET_i2s (id)); +#endif + peers_left--; + if (peers_left == 0) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d hostkeys created, now creating topology!\n", num_peers); +#endif + if (GNUNET_SCHEDULER_NO_TASK != die_task) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + } + /* create topology */ + peers_left = num_peers; /* Reset counter */ + if (GNUNET_TESTING_create_topology + (pg, topology, blacklist_topology, + blacklist_transports) != GNUNET_SYSERR) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Topology set up, now starting peers!\n"); +#endif + GNUNET_TESTING_daemons_continue_startup (pg); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, + "from continue startup (timeout)"); + } + else + { + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from create topology (bad return)"); + } + ok = 0; + } +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *topology_str; + char *connect_topology_str; + char *blacklist_topology_str; + char *connect_topology_option_str; + char *connect_topology_option_modifier_string; + + ok = 1; + + dotOutFile = fopen (dotOutFileName, "w"); + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "strict graph G {\n"); + } + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting daemons based on config file %s\n", cfgfile); +#endif + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", + &topology_str)) && + (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + topology_str, "TESTING", "TOPOLOGY"); + topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ + } + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology", + &connect_topology_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&connection_topology, + connect_topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology `%s' given for section %s option %s\n", + connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); + } + GNUNET_free_non_null (connect_topology_str); + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option", + &connect_topology_option_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_option_get (&connect_topology_option, + connect_topology_option_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology option `%s' given for section %s option %s\n", + connect_topology_option_str, "TESTING", + "CONNECT_TOPOLOGY_OPTION"); + connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ + } + GNUNET_free_non_null (connect_topology_option_str); + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option_modifier", + &connect_topology_option_modifier_string)) + { + if (sscanf + (connect_topology_option_modifier_string, "%lf", + &connect_topology_option_modifier) != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + connect_topology_option_modifier_string, + "connect_topology_option_modifier", "TESTING"); + } + GNUNET_free (connect_topology_option_modifier_string); + } + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_transports", + &blacklist_transports)) + blacklist_transports = NULL; + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_topology", + &blacklist_topology_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&blacklist_topology, + blacklist_topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); + } + GNUNET_free_non_null (topology_str); + GNUNET_free_non_null (blacklist_topology_str); + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", + "additional_messages", + &num_additional_messages)) + num_additional_messages = DEFAULT_ADDITIONAL_MESSAGES; + + main_cfg = cfg; + + GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); + peers_left = num_peers; + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + peer_daemon_hash = GNUNET_CONTAINER_multihashmap_create (peers_left); + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ + peers_left, /* Number of outstanding connections */ + peers_left, /* Number of parallel ssh connections, or peers being started at once */ + TIMEOUT, &hostkey_callback, NULL, + &peers_started_callback, NULL, + &topology_callback, NULL, NULL); + +} + +static int +check () +{ + int ret; + + char *const argv[] = { "test-transport-dv", + "-c", + "test_transport_dv_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-transport-dv", "nohelp", options, &run, &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-transport-dv': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-transport-dv", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + return ret; +} + +/* end of test_transport_api_dv.c */ diff --git a/src/dv/test_transport_dv_data.conf b/src/dv/test_transport_dv_data.conf new file mode 100644 index 0000000..80eb873 --- /dev/null +++ b/src/dv/test_transport_dv_data.conf @@ -0,0 +1,79 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunet-dv-testing/ +DEFAULTCONFIG = test_transport_dv_data.conf + +[resolver] +PORT = 2564 + +[transport] +DEBUG = YES +PORT = 2565 +PLUGINS = tcp dv +BLACKLIST_FILE = $SERVICEHOME/blacklist +BINARY = gnunet-service-transport +USE_LOCALADDR = NO + +[arm] +PORT = 2566 +DEFAULTSERVICES = + +[statistics] +PORT = 2567 + +[transport-tcp] +PORT = 2568 +BINDTO = 127.0.0.1 + +[transport-udp] +PORT = 2568 + +[peerinfo] +PORT = 2569 + +[core] +PORT = 2570 + +[dv] +AUTOSTART = YES +DEBUG = NO +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +BINARY = gnunet-service-dv +CONFIG = $DEFAULTCONFIG +HOME = $SERVICEHOME +HOSTNAME = localhost +PORT = 2571 + +[testing] +NUM_PEERS = 3 +ADDITIONAL_MESSAGES = 10 +DEBUG = NO +WEAKRANDOM = YES +TOPOLOGY = CLIQUE +CONNECT_TOPOLOGY = LINE +BLACKLIST_TOPOLOGY = LINE +BLACKLIST_TRANSPORTS = tcp +F2F = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat + +[fs] +AUTOSTART = NO + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[dns] +AUTOSTART = NO + + + +[nse] +AUTOSTART = NO + + diff --git a/src/exit/Makefile.am b/src/exit/Makefile.am new file mode 100644 index 0000000..5a047a1 --- /dev/null +++ b/src/exit/Makefile.am @@ -0,0 +1,43 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +plugindir = $(libdir)/gnunet + +dist_pkgcfg_DATA = \ + exit.conf + +if LINUX +EXITBIN = gnunet-helper-exit +install-exec-hook: + $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-exit || true + $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-exit || true +else +install-exec-hook: +endif + + +bin_PROGRAMS = \ + gnunet-daemon-exit $(EXITBIN) + + +gnunet_helper_exit_SOURCES = \ + gnunet-helper-exit.c + +gnunet_daemon_exit_SOURCES = \ + gnunet-daemon-exit.c exit.h +gnunet_daemon_exit_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(GN_LIBINTL) diff --git a/src/exit/Makefile.in b/src/exit/Makefile.in new file mode 100644 index 0000000..8e334e2 --- /dev/null +++ b/src/exit/Makefile.in @@ -0,0 +1,714 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-daemon-exit$(EXEEXT) $(am__EXEEXT_1) +subdir = src/exit +DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-exit$(EXEEXT) +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_daemon_exit_OBJECTS = gnunet-daemon-exit.$(OBJEXT) +gnunet_daemon_exit_OBJECTS = $(am_gnunet_daemon_exit_OBJECTS) +am__DEPENDENCIES_1 = +gnunet_daemon_exit_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am_gnunet_helper_exit_OBJECTS = gnunet-helper-exit.$(OBJEXT) +gnunet_helper_exit_OBJECTS = $(am_gnunet_helper_exit_OBJECTS) +gnunet_helper_exit_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(gnunet_daemon_exit_SOURCES) $(gnunet_helper_exit_SOURCES) +DIST_SOURCES = $(gnunet_daemon_exit_SOURCES) \ + $(gnunet_helper_exit_SOURCES) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +DATA = $(dist_pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +pkgcfgdir = $(pkgdatadir)/config.d/ +plugindir = $(libdir)/gnunet +dist_pkgcfg_DATA = \ + exit.conf + +@LINUX_TRUE@EXITBIN = gnunet-helper-exit +gnunet_helper_exit_SOURCES = \ + gnunet-helper-exit.c + +gnunet_daemon_exit_SOURCES = \ + gnunet-daemon-exit.c exit.h + +gnunet_daemon_exit_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(GN_LIBINTL) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/exit/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/exit/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-daemon-exit$(EXEEXT): $(gnunet_daemon_exit_OBJECTS) $(gnunet_daemon_exit_DEPENDENCIES) + @rm -f gnunet-daemon-exit$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_daemon_exit_OBJECTS) $(gnunet_daemon_exit_LDADD) $(LIBS) +gnunet-helper-exit$(EXEEXT): $(gnunet_helper_exit_OBJECTS) $(gnunet_helper_exit_DEPENDENCIES) + @rm -f gnunet-helper-exit$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_helper_exit_OBJECTS) $(gnunet_helper_exit_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-daemon-exit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-exit.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-dist_pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA + +.MAKE: install-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am \ + install-dist_pkgcfgDATA install-dvi install-dvi-am \ + install-exec install-exec-am install-exec-hook install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA + +@LINUX_TRUE@install-exec-hook: +@LINUX_TRUE@ $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-exit || true +@LINUX_TRUE@ $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-exit || true +@LINUX_FALSE@install-exec-hook: + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/exit/exit.conf b/src/exit/exit.conf new file mode 100644 index 0000000..0d48de9 --- /dev/null +++ b/src/exit/exit.conf @@ -0,0 +1,47 @@ +[exit] +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-exit + +# IPv6 address for the TUN interface (must be changed as this +# must be within the global IPv6 range of your system!) +IPV6ADDR = 2001:DB8::1 + +# Prefix for our IPv6 subnet on the TUN interface. +IPV6PREFIX = 64 + +# IPv4 address to use on our TUN interface (may need to be +# changed to avoid conflicts with existing addresses on your system). +# Use RFC 3927-style link-local address +IPV4ADDR = 169.254.86.1 + +# Netmask for the IPv4 subnet on the TUN interface. +IPV4MASK = 255.255.255.0 + + +# Name of the (virtual) tunnel interface the exit daemon will manage +TUN_IFNAME = exit-gnunet + +# Name of the "real" interface that IPv4 traffic from this system will +# leave from; this is the name of the interface where we need to +# enable NAT on postrouting (typically something like 'eth0' or 'eth1' +# or 'wlan0'). Not needed if EXIT_IPv4 is disabled AND if all +# offered services run on 'localhost'. In this case, the value +# of the option can instead be set to "%" (to not enable NAT on any +# interface). +EXIT_IFNAME = eth0 + +# Set this to YES to allow exiting this system via IPv4 to the Internet +EXIT_IPV4 = NO + +# Set this to YES to allow exiting this system via IPv6 to the Internet +EXIT_IPV6 = NO + +# For IPv4-services offered by this peer, we need to at least enable IPv4 +ENABLE_IPV4 = YES + +# For IPv6-services offered by this peer, we need to at least enable IPv6 +ENABLE_IPV6 = YES + + +# Maximum number of concurrent connections this exit supports. +MAX_CONNECTIONS = 256 diff --git a/src/exit/exit.h b/src/exit/exit.h new file mode 100644 index 0000000..dcc50f1 --- /dev/null +++ b/src/exit/exit.h @@ -0,0 +1,313 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file exit/exit.h + * @brief format for mesh messages exchanged between VPN service and exit daemon + * @author Christian Grothoff + */ +#ifndef EXIT_H +#define EXIT_H + +#include "gnunet_util_lib.h" + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message send via mesh to an exit daemon to initiate forwarding of + * TCP data to a local service. + */ +struct GNUNET_EXIT_TcpServiceStartMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START + */ + struct GNUNET_MessageHeader header; + + /** + * Always 0. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Identification for the desired service. + */ + GNUNET_HashCode service_descriptor GNUNET_PACKED; + + /** + * Skeleton of the TCP header to send. Port numbers are to + * be replaced and the checksum may be updated as necessary. + */ + struct GNUNET_TUN_TcpHeader tcp_header; + + /* followed by TCP payload */ +}; + + +/** + * Message send via mesh to an exit daemon to initiate forwarding of + * TCP data to the Internet. + */ +struct GNUNET_EXIT_TcpInternetStartMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START + */ + struct GNUNET_MessageHeader header; + + /** + * Address family, AF_INET or AF_INET6, in network byte order. + */ + int32_t af GNUNET_PACKED; + + /** + * Skeleton of the TCP header to send. Port numbers are to + * be replaced and the checksum may be updated as necessary. + */ + struct GNUNET_TUN_TcpHeader tcp_header; + + /* followed by IP address of the destination; either + 'struct in_addr' or 'struct in6_addr', depending on af */ + + /* followed by TCP payload */ +}; + + +/** + * Message send via mesh between VPN and entry and an exit daemon to + * transmit TCP data between the VPN entry and an exit session. This + * format is used for both Internet-exits and service-exits and + * in both directions (VPN to exit and exit to VPN). + */ +struct GNUNET_EXIT_TcpDataMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_TCP_DATA + */ + struct GNUNET_MessageHeader header; + + /** + * Always 0. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Skeleton of the TCP header to send. Port numbers are to + * be replaced and the checksum may be updated as necessary. (The destination port number should not be changed, as it contains the desired destination port.) + */ + struct GNUNET_TUN_TcpHeader tcp_header; + + /* followed by TCP payload */ +}; + + +/** + * Message send via mesh to an exit daemon to send + * UDP data to a local service. + */ +struct GNUNET_EXIT_UdpServiceMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE + */ + struct GNUNET_MessageHeader header; + + /** + * Source port to use for the UDP request (0 to use a random port). In NBO. + */ + uint16_t source_port GNUNET_PACKED; + + /** + * Destination port to use for the UDP request. In NBO. + */ + uint16_t destination_port GNUNET_PACKED; + + /** + * Identification for the desired service. + */ + GNUNET_HashCode service_descriptor GNUNET_PACKED; + + /* followed by UDP payload */ +}; + + +/** + * Message send via mesh to an exit daemon to forward + * UDP data to the Internet. + */ +struct GNUNET_EXIT_UdpInternetMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET + */ + struct GNUNET_MessageHeader header; + + /** + * Address family, AF_INET or AF_INET6, in network byte order. + */ + int32_t af GNUNET_PACKED; + + /** + * Source port to use for the UDP request (0 to use a random port). In NBO. + */ + uint16_t source_port GNUNET_PACKED; + + /** + * Destination port to use for the UDP request. In NBO. + */ + uint16_t destination_port GNUNET_PACKED; + + /* followed by IP address of the destination; either + 'struct in_addr' or 'struct in6_addr', depending on af */ + + /* followed by UDP payload */ +}; + + +/** + * Message send from exit daemon back to the UDP entry point + * (used for both Internet and Service exit replies). + */ +struct GNUNET_EXIT_UdpReplyMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY + */ + struct GNUNET_MessageHeader header; + + /** + * Source port to use for the UDP reply (0 to use the same + * port as for the original request). In NBO. + */ + uint16_t source_port GNUNET_PACKED; + + /** + * Destination port to use for the UDP reply (0 to use the same + * port as for the original request). In NBO. + */ + uint16_t destination_port GNUNET_PACKED; + + /* followed by UDP payload */ +}; + + +/** + * Message send via mesh to an exit daemon to send + * ICMP data to a local service. + */ +struct GNUNET_EXIT_IcmpServiceMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE + */ + struct GNUNET_MessageHeader header; + + /** + * Address family, AF_INET or AF_INET6, in network byte order. This + * AF value determines if the 'icmp_header' is ICMPv4 or ICMPv6. + * The receiver (exit) may still have to translate (PT) to the services' + * ICMP version (if possible). + */ + int32_t af GNUNET_PACKED; + + /** + * Identification for the desired service. + */ + GNUNET_HashCode service_descriptor GNUNET_PACKED; + + /** + * ICMP header to use. + */ + struct GNUNET_TUN_IcmpHeader icmp_header; + + /* followed by ICMP payload; however, for certain ICMP message + types where the payload is the original IP packet, the payload + is omitted as it is useless for the receiver (who will need + to create some fake payload manually) */ +}; + + +/** + * Message send via mesh to an exit daemon to forward + * ICMP data to the Internet. + */ +struct GNUNET_EXIT_IcmpInternetMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET + */ + struct GNUNET_MessageHeader header; + + /** + * Address family, AF_INET or AF_INET6, in network byte order. + * Determines both the ICMP version used in the 'icmp_header' and + * the IP address format that is used for the target IP. If + * PT is necessary, the sender has already done it. + */ + int32_t af GNUNET_PACKED; + + /** + * ICMP header to use. Must match the target 'af' given + * above. + */ + struct GNUNET_TUN_IcmpHeader icmp_header; + + /* followed by IP address of the destination; either + 'struct in_addr' or 'struct in6_addr', depending on af */ + + /* followed by ICMP payload; however, for certain ICMP message + types where the payload is the original IP packet, the payload + is omitted as it is useless for the receiver (who will need + to create some fake payload manually) */ +}; + + +/** + * Message send via mesh to the vpn service to send + * ICMP data to the VPN's TUN interface. + */ +struct GNUNET_EXIT_IcmpToVPNMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN + */ + struct GNUNET_MessageHeader header; + + /** + * Address family, AF_INET or AF_INET6, in network byte order. + * Useful to determine if this is an ICMPv4 or ICMPv6 header. + */ + int32_t af GNUNET_PACKED; + + /** + * ICMP header to use. ICMPv4 or ICMPv6, depending on 'af'. + */ + struct GNUNET_TUN_IcmpHeader icmp_header; + + /* followed by ICMP payload; however, for certain ICMP message + types where the payload is the original IP packet, the payload + is omitted as it is useless for the receiver (who will need + to create some fake payload manually) */ +}; + + +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c new file mode 100644 index 0000000..3bf26d7 --- /dev/null +++ b/src/exit/gnunet-daemon-exit.c @@ -0,0 +1,3240 @@ +/* + This file is part of GNUnet. + (C) 2010, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file exit/gnunet-daemon-exit.c + * @brief tool to allow IP traffic exit from the GNUnet mesh to the Internet + * @author Philipp Toelke + * @author Christian Grothoff + * + * TODO: + * - test + * + * Design: + * - which code should advertise services? the service model is right + * now a bit odd, especially as this code DOES the exit and knows + * the DNS "name", but OTOH this is clearly NOT the place to advertise + * the service's existence; maybe the daemon should turn into a + * service with an API to add local-exit services dynamically? + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_applications.h" +#include "gnunet_mesh_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_constants.h" +#include "gnunet_tun_lib.h" +#include "exit.h" + +/** + * Information about an address. + */ +struct SocketAddress +{ + /** + * AF_INET or AF_INET6. + */ + int af; + + /** + * Remote address information. + */ + union + { + /** + * Address, if af is AF_INET. + */ + struct in_addr ipv4; + + /** + * Address, if af is AF_INET6. + */ + struct in6_addr ipv6; + } address; + + /** + * IPPROTO_TCP or IPPROTO_UDP; + */ + uint8_t proto; + + /** + * Remote port, in host byte order! + */ + uint16_t port; + +}; + +/** + * This struct is saved into the services-hashmap to represent + * a service this peer is specifically offering an exit for + * (for a specific domain name). + */ +struct LocalService +{ + + /** + * Remote address to use for the service. + */ + struct SocketAddress address; + + /** + * DNS name of the service. + */ + char *name; + + /** + * Port I am listening on within GNUnet for this service, in host + * byte order. (as we may redirect ports). + */ + uint16_t my_port; + +}; + +/** + * Information we use to track a connection (the classical 6-tuple of + * IP-version, protocol, source-IP, destination-IP, source-port and + * destinatin-port. + */ +struct RedirectInformation +{ + + /** + * Address information for the other party (equivalent of the + * arguments one would give to "connect"). + */ + struct SocketAddress remote_address; + + /** + * Address information we used locally (AF and proto must match + * "remote_address"). Equivalent of the arguments one would give to + * "bind". + */ + struct SocketAddress local_address; + + /* + Note 1: additional information might be added here in the + future to support protocols that require special handling, + such as ftp/tftp + + Note 2: we might also sometimes not match on all components + of the tuple, to support protocols where things do not always + fully map. + */ +}; + + +/** + * Queue of messages to a tunnel. + */ +struct TunnelMessageQueue +{ + /** + * This is a doubly-linked list. + */ + struct TunnelMessageQueue *next; + + /** + * This is a doubly-linked list. + */ + struct TunnelMessageQueue *prev; + + /** + * Payload to send via the tunnel. + */ + const void *payload; + + /** + * Number of bytes in 'payload'. + */ + size_t len; +}; + + +/** + * This struct is saved into connections_map to allow finding the + * right tunnel given an IP packet from TUN. It is also associated + * with the tunnel's closure so we can find it again for the next + * message from the tunnel. + */ +struct TunnelState +{ + /** + * Mesh tunnel that is used for this connection. + */ + struct GNUNET_MESH_Tunnel *tunnel; + + /** + * Heap node for this state in the connections_heap. + */ + struct GNUNET_CONTAINER_HeapNode *heap_node; + + /** + * Key this state has in the connections_map. + */ + GNUNET_HashCode state_key; + + /** + * Associated service record, or NULL for no service. + */ + struct LocalService *serv; + + /** + * Head of DLL of messages for this tunnel. + */ + struct TunnelMessageQueue *head; + + /** + * Tail of DLL of messages for this tunnel. + */ + struct TunnelMessageQueue *tail; + + /** + * Active tunnel transmission request (or NULL). + */ + struct GNUNET_MESH_TransmitHandle *th; + + /** + * Primary redirection information for this connection. + */ + struct RedirectInformation ri; + +}; + + +/** + * Return value from 'main'. + */ +static int global_ret; + +/** + * The handle to the configuration used throughout the process + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * The handle to the helper + */ +static struct GNUNET_HELPER_Handle *helper_handle; + +/** + * Arguments to the exit helper. + */ +static char *exit_argv[8]; + +/** + * IPv6 address of our TUN interface. + */ +static struct in6_addr exit_ipv6addr; + +/** + * IPv6 prefix (0..127) from configuration file. + */ +static unsigned long long ipv6prefix; + +/** + * IPv4 address of our TUN interface. + */ +static struct in_addr exit_ipv4addr; + +/** + * IPv4 netmask of our TUN interface. + */ +static struct in_addr exit_ipv4mask; + + +/** + * Statistics. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * The handle to mesh + */ +static struct GNUNET_MESH_Handle *mesh_handle; + +/** + * This hashmaps contains the mapping from peer, service-descriptor, + * source-port and destination-port to a struct TunnelState + */ +static struct GNUNET_CONTAINER_MultiHashMap *connections_map; + +/** + * Heap so we can quickly find "old" connections. + */ +static struct GNUNET_CONTAINER_Heap *connections_heap; + +/** + * If there are at least this many connections, old ones will be removed + */ +static long long unsigned int max_connections; + +/** + * This hashmaps saves interesting things about the configured UDP services + */ +static struct GNUNET_CONTAINER_MultiHashMap *udp_services; + +/** + * This hashmaps saves interesting things about the configured TCP services + */ +static struct GNUNET_CONTAINER_MultiHashMap *tcp_services; + +/** + * Are we an IPv4-exit? + */ +static int ipv4_exit; + +/** + * Are we an IPv6-exit? + */ +static int ipv6_exit; + +/** + * Do we support IPv4 at all on the TUN interface? + */ +static int ipv4_enabled; + +/** + * Do we support IPv6 at all on the TUN interface? + */ +static int ipv6_enabled; + + +/** + * Given IP information about a connection, calculate the respective + * hash we would use for the 'connections_map'. + * + * @param hash resulting hash + * @param ri information about the connection + */ +static void +hash_redirect_info (GNUNET_HashCode *hash, + const struct RedirectInformation *ri) +{ + char *off; + + memset (hash, 0, sizeof (GNUNET_HashCode)); + /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash, + so we put the IP address in there (and hope for few collisions) */ + off = (char*) hash; + switch (ri->remote_address.af) + { + case AF_INET: + memcpy (off, &ri->remote_address.address.ipv4, sizeof (struct in_addr)); + off += sizeof (struct in_addr); + break; + case AF_INET6: + memcpy (off, &ri->remote_address.address.ipv6, sizeof (struct in6_addr)); + off += sizeof (struct in_addr); + break; + default: + GNUNET_assert (0); + } + memcpy (off, &ri->remote_address.port, sizeof (uint16_t)); + off += sizeof (uint16_t); + switch (ri->local_address.af) + { + case AF_INET: + memcpy (off, &ri->local_address.address.ipv4, sizeof (struct in_addr)); + off += sizeof (struct in_addr); + break; + case AF_INET6: + memcpy (off, &ri->local_address.address.ipv6, sizeof (struct in6_addr)); + off += sizeof (struct in_addr); + break; + default: + GNUNET_assert (0); + } + memcpy (off, &ri->local_address.port, sizeof (uint16_t)); + off += sizeof (uint16_t); + memcpy (off, &ri->remote_address.proto, sizeof (uint8_t)); + off += sizeof (uint8_t); +} + + +/** + * Get our connection tracking state. Warns if it does not exists, + * refreshes the timestamp if it does exist. + * + * @param af address family + * @param protocol IPPROTO_UDP or IPPROTO_TCP + * @param destination_ip target IP + * @param destination_port target port + * @param local_ip local IP + * @param local_port local port + * @param state_key set to hash's state if non-NULL + * @return NULL if we have no tracking information for this tuple + */ +static struct TunnelState * +get_redirect_state (int af, + int protocol, + const void *destination_ip, + uint16_t destination_port, + const void *local_ip, + uint16_t local_port, + GNUNET_HashCode *state_key) +{ + struct RedirectInformation ri; + GNUNET_HashCode key; + struct TunnelState *state; + + if ( ( (af == AF_INET) && (protocol == IPPROTO_ICMP) ) || + ( (af == AF_INET6) && (protocol == IPPROTO_ICMPV6) ) ) + { + /* ignore ports */ + destination_port = 0; + local_port = 0; + } + ri.remote_address.af = af; + if (af == AF_INET) + ri.remote_address.address.ipv4 = *((struct in_addr*) destination_ip); + else + ri.remote_address.address.ipv6 = * ((struct in6_addr*) destination_ip); + ri.remote_address.port = destination_port; + ri.remote_address.proto = protocol; + ri.local_address.af = af; + if (af == AF_INET) + ri.local_address.address.ipv4 = *((struct in_addr*) local_ip); + else + ri.local_address.address.ipv6 = * ((struct in6_addr*) local_ip); + ri.local_address.port = local_port; + ri.local_address.proto = protocol; + hash_redirect_info (&key, &ri); + if (NULL != state_key) + *state_key = key; + state = GNUNET_CONTAINER_multihashmap_get (connections_map, &key); + if (NULL == state) + return NULL; + /* Mark this connection as freshly used */ + if (NULL == state_key) + GNUNET_CONTAINER_heap_update_cost (connections_heap, + state->heap_node, + GNUNET_TIME_absolute_get ().abs_value); + return state; +} + + +/** + * Given a service descriptor and a destination port, find the + * respective service entry. + * + * @param service_map map of services (TCP or UDP) + * @param desc service descriptor + * @param destination_port destination port + * @return NULL if we are not aware of such a service + */ +static struct LocalService * +find_service (struct GNUNET_CONTAINER_MultiHashMap *service_map, + const GNUNET_HashCode *desc, + uint16_t destination_port) +{ + char key[sizeof (GNUNET_HashCode) + sizeof (uint16_t)]; + + memcpy (&key[0], &destination_port, sizeof (uint16_t)); + memcpy (&key[sizeof(uint16_t)], desc, sizeof (GNUNET_HashCode)); + return GNUNET_CONTAINER_multihashmap_get (service_map, + (GNUNET_HashCode *) key); +} + + +/** + * Free memory associated with a service record. + * + * @param cls unused + * @param key service descriptor + * @param value service record to free + * @return GNUNET_OK + */ +static int +free_service_record (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct LocalService *service = value; + + GNUNET_free_non_null (service->name); + GNUNET_free (service); + return GNUNET_OK; +} + + +/** + * Given a service descriptor and a destination port, find the + * respective service entry. + * + * @param service_map map of services (TCP or UDP) + * @param name name of the service + * @param destination_port destination port + * @param service service information record to store (service->name will be set). + */ +static void +store_service (struct GNUNET_CONTAINER_MultiHashMap *service_map, + const char *name, + uint16_t destination_port, + struct LocalService *service) +{ + char key[sizeof (GNUNET_HashCode) + sizeof (uint16_t)]; + GNUNET_HashCode desc; + + GNUNET_CRYPTO_hash (name, strlen (name) + 1, &desc); + service->name = GNUNET_strdup (name); + memcpy (&key[0], &destination_port, sizeof (uint16_t)); + memcpy (&key[sizeof(uint16_t)], &desc, sizeof (GNUNET_HashCode)); + if (GNUNET_OK != + GNUNET_CONTAINER_multihashmap_put (service_map, + (GNUNET_HashCode *) key, + service, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) + { + free_service_record (NULL, (GNUNET_HashCode *) key, service); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Got duplicate service records for `%s:%u'\n"), + name, + (unsigned int) destination_port); + } +} + + +/** + * MESH is ready to receive a message for the tunnel. Transmit it. + * + * @param cls the 'struct TunnelState'. + * @param size number of bytes available in buf + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +send_to_peer_notify_callback (void *cls, size_t size, void *buf) +{ + struct TunnelState *s = cls; + struct GNUNET_MESH_Tunnel *tunnel = s->tunnel; + struct TunnelMessageQueue *tnq; + + s->th = NULL; + tnq = s->head; + if (NULL == tnq) + return 0; + if (0 == size) + { + s->th = GNUNET_MESH_notify_transmit_ready (tunnel, + GNUNET_NO /* corking */, + 0 /* priority */, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, + tnq->len, + &send_to_peer_notify_callback, + s); + return 0; + } + GNUNET_assert (size >= tnq->len); + memcpy (buf, tnq->payload, tnq->len); + size = tnq->len; + GNUNET_CONTAINER_DLL_remove (s->head, + s->tail, + tnq); + GNUNET_free (tnq); + if (NULL != (tnq = s->head)) + s->th = GNUNET_MESH_notify_transmit_ready (tunnel, + GNUNET_NO /* corking */, + 0 /* priority */, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, + tnq->len, + &send_to_peer_notify_callback, + s); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes transmitted via mesh tunnels"), + size, GNUNET_NO); + return size; +} + + +/** + * Send the given packet via the mesh tunnel. + * + * @param mesh_tunnel destination + * @param tnq message to queue + */ +static void +send_packet_to_mesh_tunnel (struct GNUNET_MESH_Tunnel *mesh_tunnel, + struct TunnelMessageQueue *tnq) +{ + struct TunnelState *s; + + s = GNUNET_MESH_tunnel_get_data (mesh_tunnel); + GNUNET_assert (NULL != s); + GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, tnq); + if (NULL == s->th) + s->th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, GNUNET_NO /* cork */, 0 /* priority */, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, tnq->len, + &send_to_peer_notify_callback, + s); +} + + +/** + * @brief Handles an ICMP packet received from the helper. + * + * @param icmp A pointer to the Packet + * @param pktlen number of bytes in 'icmp' + * @param af address family (AFINET or AF_INET6) + * @param destination_ip destination IP-address of the IP packet (should + * be our local address) + * @param source_ip original source IP-address of the IP packet (should + * be the original destination address) + */ +static void +icmp_from_helper (const struct GNUNET_TUN_IcmpHeader *icmp, + size_t pktlen, + int af, + const void *destination_ip, + const void *source_ip) +{ + struct TunnelState *state; + struct TunnelMessageQueue *tnq; + struct GNUNET_EXIT_IcmpToVPNMessage *i2v; + const struct GNUNET_TUN_IPv4Header *ipv4; + const struct GNUNET_TUN_IPv6Header *ipv6; + const struct GNUNET_TUN_UdpHeader *udp; + size_t mlen; + uint16_t source_port; + uint16_t destination_port; + uint8_t protocol; + + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received ICMP packet going from %s to %s\n", + inet_ntop (af, + source_ip, + sbuf, sizeof (sbuf)), + inet_ntop (af, + destination_ip, + dbuf, sizeof (dbuf))); + } + if (pktlen < sizeof (struct GNUNET_TUN_IcmpHeader)) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + + /* Find out if this is an ICMP packet in response to an existing + TCP/UDP packet and if so, figure out ports / protocol of the + existing session from the IP data in the ICMP payload */ + source_port = 0; + destination_port = 0; + switch (af) + { + case AF_INET: + protocol = IPPROTO_ICMP; + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: + case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: + break; + case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: + case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: + case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: + if (pktlen < + sizeof (struct GNUNET_TUN_IcmpHeader) + + sizeof (struct GNUNET_TUN_IPv4Header) + 8) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + ipv4 = (const struct GNUNET_TUN_IPv4Header *) &icmp[1]; + protocol = ipv4->protocol; + /* could be TCP or UDP, but both have the ports in the right + place, so that doesn't matter here */ + udp = (const struct GNUNET_TUN_UdpHeader *) &ipv4[1]; + /* swap ports, as they are from the original message */ + destination_port = ntohs (udp->source_port); + source_port = ntohs (udp->destination_port); + /* throw away ICMP payload, won't be useful for the other side anyway */ + pktlen = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + default: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return; + } + break; + case AF_INET6: + protocol = IPPROTO_ICMPV6; + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: + case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: + case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: + case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: + if (pktlen < + sizeof (struct GNUNET_TUN_IcmpHeader) + + sizeof (struct GNUNET_TUN_IPv6Header) + 8) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + ipv6 = (const struct GNUNET_TUN_IPv6Header *) &icmp[1]; + protocol = ipv6->next_header; + /* could be TCP or UDP, but both have the ports in the right + place, so that doesn't matter here */ + udp = (const struct GNUNET_TUN_UdpHeader *) &ipv6[1]; + /* swap ports, as they are from the original message */ + destination_port = ntohs (udp->source_port); + source_port = ntohs (udp->destination_port); + /* throw away ICMP payload, won't be useful for the other side anyway */ + pktlen = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: + case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: + break; + default: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return; + } + break; + default: + GNUNET_assert (0); + } + switch (protocol) + { + case IPPROTO_ICMP: + state = get_redirect_state (af, IPPROTO_ICMP, + source_ip, 0, + destination_ip, 0, + NULL); + break; + case IPPROTO_ICMPV6: + state = get_redirect_state (af, IPPROTO_ICMPV6, + source_ip, 0, + destination_ip, 0, + NULL); + break; + case IPPROTO_UDP: + state = get_redirect_state (af, IPPROTO_UDP, + source_ip, + source_port, + destination_ip, + destination_port, + NULL); + break; + case IPPROTO_TCP: + state = get_redirect_state (af, IPPROTO_TCP, + source_ip, + source_port, + destination_ip, + destination_port, + NULL); + break; + default: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMP packets dropped (not allowed)"), + 1, GNUNET_NO); + return; + } + if (NULL == state) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("ICMP Packet dropped, have no matching connection information\n")); + return; + } + mlen = sizeof (struct GNUNET_EXIT_IcmpToVPNMessage) + pktlen - sizeof (struct GNUNET_TUN_IcmpHeader); + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueue) + mlen); + tnq->payload = &tnq[1]; + tnq->len = mlen; + i2v = (struct GNUNET_EXIT_IcmpToVPNMessage *) &tnq[1]; + i2v->header.size = htons ((uint16_t) mlen); + i2v->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN); + i2v->af = htonl (af); + memcpy (&i2v->icmp_header, + icmp, + pktlen); + send_packet_to_mesh_tunnel (state->tunnel, + tnq); +} + + +/** + * @brief Handles an UDP packet received from the helper. + * + * @param udp A pointer to the Packet + * @param pktlen number of bytes in 'udp' + * @param af address family (AFINET or AF_INET6) + * @param destination_ip destination IP-address of the IP packet (should + * be our local address) + * @param source_ip original source IP-address of the IP packet (should + * be the original destination address) + */ +static void +udp_from_helper (const struct GNUNET_TUN_UdpHeader *udp, + size_t pktlen, + int af, + const void *destination_ip, + const void *source_ip) +{ + struct TunnelState *state; + struct TunnelMessageQueue *tnq; + struct GNUNET_EXIT_UdpReplyMessage *urm; + size_t mlen; + + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received UDP packet going from %s:%u to %s:%u\n", + inet_ntop (af, + source_ip, + sbuf, sizeof (sbuf)), + (unsigned int) ntohs (udp->source_port), + inet_ntop (af, + destination_ip, + dbuf, sizeof (dbuf)), + (unsigned int) ntohs (udp->destination_port)); + } + if (pktlen < sizeof (struct GNUNET_TUN_UdpHeader)) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + if (pktlen != ntohs (udp->len)) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + state = get_redirect_state (af, IPPROTO_UDP, + source_ip, + ntohs (udp->source_port), + destination_ip, + ntohs (udp->destination_port), + NULL); + if (NULL == state) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("UDP Packet dropped, have no matching connection information\n")); + return; + } + mlen = sizeof (struct GNUNET_EXIT_UdpReplyMessage) + pktlen - sizeof (struct GNUNET_TUN_UdpHeader); + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueue) + mlen); + tnq->payload = &tnq[1]; + tnq->len = mlen; + urm = (struct GNUNET_EXIT_UdpReplyMessage *) &tnq[1]; + urm->header.size = htons ((uint16_t) mlen); + urm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY); + urm->source_port = htons (0); + urm->destination_port = htons (0); + memcpy (&urm[1], + &udp[1], + pktlen - sizeof (struct GNUNET_TUN_UdpHeader)); + send_packet_to_mesh_tunnel (state->tunnel, + tnq); +} + + +/** + * @brief Handles a TCP packet received from the helper. + * + * @param tcp A pointer to the Packet + * @param pktlen the length of the packet, including its TCP header + * @param af address family (AFINET or AF_INET6) + * @param destination_ip destination IP-address of the IP packet (should + * be our local address) + * @param source_ip original source IP-address of the IP packet (should + * be the original destination address) + */ +static void +tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp, + size_t pktlen, + int af, + const void *destination_ip, + const void *source_ip) +{ + struct TunnelState *state; + char buf[pktlen]; + struct GNUNET_TUN_TcpHeader *mtcp; + struct GNUNET_EXIT_TcpDataMessage *tdm; + struct TunnelMessageQueue *tnq; + size_t mlen; + + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received TCP packet with %u bytes going from %s:%u to %s:%u\n", + pktlen - sizeof (struct GNUNET_TUN_TcpHeader), + inet_ntop (af, + source_ip, + sbuf, sizeof (sbuf)), + (unsigned int) ntohs (tcp->source_port), + inet_ntop (af, + destination_ip, + dbuf, sizeof (dbuf)), + (unsigned int) ntohs (tcp->destination_port)); + } + if (pktlen < sizeof (struct GNUNET_TUN_TcpHeader)) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + state = get_redirect_state (af, IPPROTO_TCP, + source_ip, + ntohs (tcp->source_port), + destination_ip, + ntohs (tcp->destination_port), + NULL); + if (NULL == state) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("TCP Packet dropped, have no matching connection information\n")); + + return; + } + /* mug port numbers and crc to avoid information leakage; + sender will need to lookup the correct values anyway */ + memcpy (buf, tcp, pktlen); + mtcp = (struct GNUNET_TUN_TcpHeader *) buf; + mtcp->source_port = 0; + mtcp->destination_port = 0; + mtcp->crc = 0; + + mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + (pktlen - sizeof (struct GNUNET_TUN_TcpHeader)); + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueue) + mlen); + tnq->payload = &tnq[1]; + tnq->len = mlen; + tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1]; + tdm->header.size = htons ((uint16_t) mlen); + tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN); + tdm->reserved = htonl (0); + memcpy (&tdm->tcp_header, + buf, + pktlen); + send_packet_to_mesh_tunnel (state->tunnel, + tnq); +} + + +/** + * Receive packets from the helper-process + * + * @param cls unused + * @param client unsued + * @param message message received from helper + */ +static void +message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun; + size_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got %u-byte message of type %u from gnunet-helper-exit\n", + ntohs (message->size), + ntohs (message->type)); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Packets received from TUN"), + 1, GNUNET_NO); + if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) + { + GNUNET_break (0); + return; + } + size = ntohs (message->size); + if (size < sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + return; + } + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from TUN"), + size, GNUNET_NO); + pkt_tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1]; + size -= sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader); + switch (ntohs (pkt_tun->proto)) + { + case ETH_P_IPV4: + { + const struct GNUNET_TUN_IPv4Header *pkt4; + + if (size < sizeof (struct GNUNET_TUN_IPv4Header)) + { + /* Kernel to blame? */ + GNUNET_break (0); + return; + } + pkt4 = (const struct GNUNET_TUN_IPv4Header *) &pkt_tun[1]; + if (size != ntohs (pkt4->total_length)) + { + /* Kernel to blame? */ + GNUNET_break (0); + return; + } + if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("IPv4 packet options received. Ignored.\n")); + return; + } + + size -= sizeof (struct GNUNET_TUN_IPv4Header); + switch (pkt4->protocol) + { + case IPPROTO_UDP: + udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt4[1], size, + AF_INET, + &pkt4->destination_address, + &pkt4->source_address); + break; + case IPPROTO_TCP: + tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt4[1], size, + AF_INET, + &pkt4->destination_address, + &pkt4->source_address); + break; + case IPPROTO_ICMP: + icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt4[1], size, + AF_INET, + &pkt4->destination_address, + &pkt4->source_address); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("IPv4 packet with unsupported next header %u received. Ignored.\n"), + (int) pkt4->protocol); + return; + } + } + break; + case ETH_P_IPV6: + { + const struct GNUNET_TUN_IPv6Header *pkt6; + + if (size < sizeof (struct GNUNET_TUN_IPv6Header)) + { + /* Kernel to blame? */ + GNUNET_break (0); + return; + } + pkt6 = (struct GNUNET_TUN_IPv6Header *) &pkt_tun[1]; + if (size != ntohs (pkt6->payload_length) + sizeof (struct GNUNET_TUN_IPv6Header)) + { + /* Kernel to blame? */ + GNUNET_break (0); + return; + } + size -= sizeof (struct GNUNET_TUN_IPv6Header); + switch (pkt6->next_header) + { + case IPPROTO_UDP: + udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt6[1], size, + AF_INET6, + &pkt6->destination_address, + &pkt6->source_address); + break; + case IPPROTO_TCP: + tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt6[1], size, + AF_INET6, + &pkt6->destination_address, + &pkt6->source_address); + break; + case IPPROTO_ICMPV6: + icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt6[1], size, + AF_INET6, + &pkt6->destination_address, + &pkt6->source_address); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("IPv6 packet with unsupported next header %d received. Ignored.\n"), + pkt6->next_header); + return; + } + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Packet from unknown protocol %u received. Ignored.\n"), + ntohs (pkt_tun->proto)); + break; + } +} + + +/** + * We need to create a (unique) fresh local address (IP+port). + * Fill one in. + * + * @param af desired address family + * @param proto desired protocol (IPPROTO_UDP or IPPROTO_TCP) + * @param local_address address to initialize + */ +static void +setup_fresh_address (int af, + uint8_t proto, + struct SocketAddress *local_address) +{ + local_address->af = af; + local_address->proto = (uint8_t) proto; + /* default "local" port range is often 32768--61000, + so we pick a random value in that range */ + if ( ( (af == AF_INET) && (proto == IPPROTO_ICMP) ) || + ( (af == AF_INET6) && (proto == IPPROTO_ICMPV6) ) ) + local_address->port = 0; + else + local_address->port + = (uint16_t) 32768 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + 28232); + switch (af) + { + case AF_INET: + { + struct in_addr addr; + struct in_addr mask; + struct in_addr rnd; + + addr = exit_ipv4addr; + mask = exit_ipv4mask; + if (0 == ~mask.s_addr) + { + /* only one valid IP anyway */ + local_address->address.ipv4 = addr; + return; + } + /* Given 192.168.0.1/255.255.0.0, we want a mask + of '192.168.255.255', thus: */ + mask.s_addr = addr.s_addr | ~mask.s_addr; + /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */ + do + { + rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT32_MAX); + local_address->address.ipv4.s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr; + } + while ( (local_address->address.ipv4.s_addr == addr.s_addr) || + (local_address->address.ipv4.s_addr == mask.s_addr) ); + } + break; + case AF_INET6: + { + struct in6_addr addr; + struct in6_addr mask; + struct in6_addr rnd; + int i; + + addr = exit_ipv6addr; + GNUNET_assert (ipv6prefix < 128); + if (ipv6prefix == 127) + { + /* only one valid IP anyway */ + local_address->address.ipv6 = addr; + return; + } + /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF, + thus: */ + mask = addr; + for (i=127;i>=ipv6prefix;i--) + mask.s6_addr[i / 8] |= (1 << (i % 8)); + + /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */ + do + { + for (i=0;i<16;i++) + { + rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + 256); + local_address->address.ipv6.s6_addr[i] + = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i]; + } + } + while ( (0 == memcmp (&local_address->address.ipv6, + &addr, + sizeof (struct in6_addr))) || + (0 == memcmp (&local_address->address.ipv6, + &mask, + sizeof (struct in6_addr))) ); + } + break; + default: + GNUNET_assert (0); + } +} + + +/** + * We are starting a fresh connection (TCP or UDP) and need + * to pick a source port and IP address (within the correct + * range and address family) to associate replies with the + * connection / correct mesh tunnel. This function generates + * a "fresh" source IP and source port number for a connection + * After picking a good source address, this function sets up + * the state in the 'connections_map' and 'connections_heap' + * to allow finding the state when needed later. The function + * also makes sure that we remain within memory limits by + * cleaning up 'old' states. + * + * @param state skeleton state to setup a record for; should + * 'state->ri.remote_address' filled in so that + * this code can determine which AF/protocol is + * going to be used (the 'tunnel' should also + * already be set); after calling this function, + * heap_node and the local_address will be + * also initialized (heap_node != NULL can be + * used to test if a state has been fully setup). + */ +static void +setup_state_record (struct TunnelState *state) +{ + GNUNET_HashCode key; + struct TunnelState *s; + + /* generate fresh, unique address */ + do + { + if (NULL == state->serv) + setup_fresh_address (state->ri.remote_address.af, + state->ri.remote_address.proto, + &state->ri.local_address); + else + setup_fresh_address (state->serv->address.af, + state->serv->address.proto, + &state->ri.local_address); + } while (NULL != get_redirect_state (state->ri.remote_address.af, + state->ri.remote_address.proto, + &state->ri.remote_address.address, + state->ri.remote_address.port, + &state->ri.local_address.address, + state->ri.local_address.port, + &key)); + { + char buf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Picked local address %s:%u for new connection\n", + inet_ntop (state->ri.local_address.af, + &state->ri.local_address.address, + buf, sizeof (buf)), + (unsigned int) state->ri.local_address.port); + } + state->state_key = key; + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (connections_map, + &key, state, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + state->heap_node = GNUNET_CONTAINER_heap_insert (connections_heap, + state, + GNUNET_TIME_absolute_get ().abs_value); + while (GNUNET_CONTAINER_heap_get_size (connections_heap) > max_connections) + { + s = GNUNET_CONTAINER_heap_remove_root (connections_heap); + GNUNET_assert (state != s); + s->heap_node = NULL; + GNUNET_MESH_tunnel_destroy (s->tunnel); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (connections_map, + &s->state_key, + s)); + GNUNET_free (s); + } +} + + +/** + * Prepare an IPv4 packet for transmission via the TUN interface. + * Initializes the IP header and calculates checksums (IP+UDP/TCP). + * For UDP, the UDP header will be fully created, whereas for TCP + * only the ports and checksum will be filled in. So for TCP, + * a skeleton TCP header must be part of the provided payload. + * + * @param payload payload of the packet (starting with UDP payload or + * TCP header, depending on protocol) + * @param payload_length number of bytes in 'payload' + * @param protocol IPPROTO_UDP or IPPROTO_TCP + * @param tcp_header skeleton of the TCP header, NULL for UDP + * @param src_address source address to use (IP and port) + * @param dst_address destination address to use (IP and port) + * @param pkt4 where to write the assembled packet; must + * contain enough space for the IP header, UDP/TCP header + * AND the payload + */ +static void +prepare_ipv4_packet (const void *payload, size_t payload_length, + int protocol, + const struct GNUNET_TUN_TcpHeader *tcp_header, + const struct SocketAddress *src_address, + const struct SocketAddress *dst_address, + struct GNUNET_TUN_IPv4Header *pkt4) +{ + size_t len; + + len = payload_length; + switch (protocol) + { + case IPPROTO_UDP: + len += sizeof (struct GNUNET_TUN_UdpHeader); + break; + case IPPROTO_TCP: + len += sizeof (struct GNUNET_TUN_TcpHeader); + GNUNET_assert (NULL != tcp_header); + break; + default: + GNUNET_break (0); + return; + } + if (len + sizeof (struct GNUNET_TUN_IPv4Header) > UINT16_MAX) + { + GNUNET_break (0); + return; + } + + GNUNET_TUN_initialize_ipv4_header (pkt4, + protocol, + len, + &src_address->address.ipv4, + &dst_address->address.ipv4); + switch (protocol) + { + case IPPROTO_UDP: + { + struct GNUNET_TUN_UdpHeader *pkt4_udp = (struct GNUNET_TUN_UdpHeader *) &pkt4[1]; + + pkt4_udp->source_port = htons (src_address->port); + pkt4_udp->destination_port = htons (dst_address->port); + pkt4_udp->len = htons ((uint16_t) payload_length); + GNUNET_TUN_calculate_udp4_checksum (pkt4, + pkt4_udp, + payload, payload_length); + memcpy (&pkt4_udp[1], payload, payload_length); + } + break; + case IPPROTO_TCP: + { + struct GNUNET_TUN_TcpHeader *pkt4_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt4[1]; + + *pkt4_tcp = *tcp_header; + pkt4_tcp->source_port = htons (src_address->port); + pkt4_tcp->destination_port = htons (dst_address->port); + GNUNET_TUN_calculate_tcp4_checksum (pkt4, + pkt4_tcp, + payload, + payload_length); + memcpy (&pkt4_tcp[1], payload, payload_length); + } + break; + default: + GNUNET_assert (0); + } +} + + +/** + * Prepare an IPv6 packet for transmission via the TUN interface. + * Initializes the IP header and calculates checksums (IP+UDP/TCP). + * For UDP, the UDP header will be fully created, whereas for TCP + * only the ports and checksum will be filled in. So for TCP, + * a skeleton TCP header must be part of the provided payload. + * + * @param payload payload of the packet (starting with UDP payload or + * TCP header, depending on protocol) + * @param payload_length number of bytes in 'payload' + * @param protocol IPPROTO_UDP or IPPROTO_TCP + * @param tcp_header skeleton TCP header data to send, NULL for UDP + * @param src_address source address to use (IP and port) + * @param dst_address destination address to use (IP and port) + * @param pkt6 where to write the assembled packet; must + * contain enough space for the IP header, UDP/TCP header + * AND the payload + */ +static void +prepare_ipv6_packet (const void *payload, size_t payload_length, + int protocol, + const struct GNUNET_TUN_TcpHeader *tcp_header, + const struct SocketAddress *src_address, + const struct SocketAddress *dst_address, + struct GNUNET_TUN_IPv6Header *pkt6) +{ + size_t len; + + len = payload_length; + switch (protocol) + { + case IPPROTO_UDP: + len += sizeof (struct GNUNET_TUN_UdpHeader); + break; + case IPPROTO_TCP: + len += sizeof (struct GNUNET_TUN_TcpHeader); + break; + default: + GNUNET_break (0); + return; + } + if (len > UINT16_MAX) + { + GNUNET_break (0); + return; + } + + GNUNET_TUN_initialize_ipv6_header (pkt6, + protocol, + len, + &src_address->address.ipv6, + &dst_address->address.ipv6); + + switch (protocol) + { + case IPPROTO_UDP: + { + struct GNUNET_TUN_UdpHeader *pkt6_udp = (struct GNUNET_TUN_UdpHeader *) &pkt6[1]; + + pkt6_udp->source_port = htons (src_address->port); + pkt6_udp->destination_port = htons (dst_address->port); + pkt6_udp->len = htons ((uint16_t) payload_length); + GNUNET_TUN_calculate_udp6_checksum (pkt6, + pkt6_udp, + payload, + payload_length); + memcpy (&pkt6_udp[1], payload, payload_length); + } + break; + case IPPROTO_TCP: + { + struct GNUNET_TUN_TcpHeader *pkt6_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt6[1]; + + /* memcpy first here as some TCP header fields are initialized this way! */ + *pkt6_tcp = *tcp_header; + pkt6_tcp->source_port = htons (src_address->port); + pkt6_tcp->destination_port = htons (dst_address->port); + GNUNET_TUN_calculate_tcp6_checksum (pkt6, + pkt6_tcp, + payload, + payload_length); + memcpy (&pkt6_tcp[1], payload, payload_length); + } + break; + default: + GNUNET_assert (0); + break; + } +} + + +/** + * Send a TCP packet via the TUN interface. + * + * @param destination_address IP and port to use for the TCP packet's destination + * @param source_address IP and port to use for the TCP packet's source + * @param tcp_header header template to use + * @param payload payload of the TCP packet + * @param payload_length number of bytes in 'payload' + */ +static void +send_tcp_packet_via_tun (const struct SocketAddress *destination_address, + const struct SocketAddress *source_address, + const struct GNUNET_TUN_TcpHeader *tcp_header, + const void *payload, size_t payload_length) +{ + size_t len; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP packets sent via TUN"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending packet with %u bytes TCP payload via TUN\n", + (unsigned int) payload_length); + len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); + switch (source_address->af) + { + case AF_INET: + len += sizeof (struct GNUNET_TUN_IPv4Header); + break; + case AF_INET6: + len += sizeof (struct GNUNET_TUN_IPv6Header); + break; + default: + GNUNET_break (0); + return; + } + len += sizeof (struct GNUNET_TUN_TcpHeader); + len += payload_length; + if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + { + char buf[len]; + struct GNUNET_MessageHeader *hdr; + struct GNUNET_TUN_Layer2PacketHeader *tun; + + hdr = (struct GNUNET_MessageHeader *) buf; + hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + hdr->size = htons (len); + tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; + tun->flags = htons (0); + switch (source_address->af) + { + case AF_INET: + { + struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; + + tun->proto = htons (ETH_P_IPV4); + prepare_ipv4_packet (payload, payload_length, + IPPROTO_TCP, + tcp_header, + source_address, + destination_address, + ipv4); + } + break; + case AF_INET6: + { + struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1]; + + tun->proto = htons (ETH_P_IPV6); + prepare_ipv6_packet (payload, payload_length, + IPPROTO_TCP, + tcp_header, + source_address, + destination_address, + ipv6); + } + break; + default: + GNUNET_assert (0); + break; + } + (void) GNUNET_HELPER_send (helper_handle, + (const struct GNUNET_MessageHeader*) buf, + GNUNET_YES, + NULL, NULL); + } +} + + +/** + * Process a request via mesh to send a request to a TCP service + * offered by this system. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_tcp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx GNUNET_UNUSED, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *state = *tunnel_ctx; + const struct GNUNET_EXIT_TcpServiceStartMessage *start; + uint16_t pkt_len = ntohs (message->size); + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP service creation requests received via mesh"), + 1, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + /* check that we got at least a valid header */ + if (pkt_len < sizeof (struct GNUNET_EXIT_TcpServiceStartMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + start = (const struct GNUNET_EXIT_TcpServiceStartMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_TcpServiceStartMessage); + if ( (NULL == state) || + (NULL != state->serv) || + (NULL != state->heap_node) ) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (start->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_break_op (ntohl (start->reserved) == 0); + /* setup fresh connection */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received data from %s for forwarding to TCP service %s on port %u\n", + GNUNET_i2s (sender), + GNUNET_h2s (&start->service_descriptor), + (unsigned int) ntohs (start->tcp_header.destination_port)); + if (NULL == (state->serv = find_service (tcp_services, &start->service_descriptor, + ntohs (start->tcp_header.destination_port)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("No service found for %s on port %d!\n"), + "TCP", + ntohs (start->tcp_header.destination_port)); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP requests dropped (no such service)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + state->ri.remote_address = state->serv->address; + setup_state_record (state); + send_tcp_packet_via_tun (&state->ri.remote_address, + &state->ri.local_address, + &start->tcp_header, + &start[1], pkt_len); + return GNUNET_YES; +} + + +/** + * Process a request to forward TCP data to the Internet via this peer. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_tcp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx GNUNET_UNUSED, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *state = *tunnel_ctx; + const struct GNUNET_EXIT_TcpInternetStartMessage *start; + uint16_t pkt_len = ntohs (message->size); + const struct in_addr *v4; + const struct in6_addr *v6; + const void *payload; + int af; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP IP-exit creation requests received via mesh"), + 1, GNUNET_NO); + if (pkt_len < sizeof (struct GNUNET_EXIT_TcpInternetStartMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + start = (const struct GNUNET_EXIT_TcpInternetStartMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_TcpInternetStartMessage); + if ( (NULL == state) || + (NULL != state->serv) || + (NULL != state->heap_node) ) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (start->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + af = (int) ntohl (start->af); + state->ri.remote_address.af = af; + switch (af) + { + case AF_INET: + if (pkt_len < sizeof (struct in_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! ipv4_exit) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + v4 = (const struct in_addr*) &start[1]; + payload = &v4[1]; + pkt_len -= sizeof (struct in_addr); + state->ri.remote_address.address.ipv4 = *v4; + break; + case AF_INET6: + if (pkt_len < sizeof (struct in6_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! ipv6_exit) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + v6 = (const struct in6_addr*) &start[1]; + payload = &v6[1]; + pkt_len -= sizeof (struct in6_addr); + state->ri.remote_address.address.ipv6 = *v6; + break; + default: + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + { + char buf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received data from %s for starting TCP stream to %s:%u\n", + GNUNET_i2s (sender), + inet_ntop (af, + &state->ri.remote_address.address, + buf, sizeof (buf)), + (unsigned int) ntohs (start->tcp_header.destination_port)); + } + state->ri.remote_address.proto = IPPROTO_TCP; + state->ri.remote_address.port = ntohs (start->tcp_header.destination_port); + setup_state_record (state); + send_tcp_packet_via_tun (&state->ri.remote_address, + &state->ri.local_address, + &start->tcp_header, + payload, pkt_len); + return GNUNET_YES; +} + + +/** + * Process a request to forward TCP data on an established + * connection via this peer. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_tcp_data (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx GNUNET_UNUSED, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *state = *tunnel_ctx; + const struct GNUNET_EXIT_TcpDataMessage *data; + uint16_t pkt_len = ntohs (message->size); + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP data requests received via mesh"), + 1, GNUNET_NO); + if (pkt_len < sizeof (struct GNUNET_EXIT_TcpDataMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + data = (const struct GNUNET_EXIT_TcpDataMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_TcpDataMessage); + if ( (NULL == state) || + (NULL == state->heap_node) ) + { + /* connection should have been up! */ + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP DATA requests dropped (no session)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + GNUNET_break_op (ntohl (data->reserved) == 0); + { + char buf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received additional %u bytes of data from %s for TCP stream to %s:%u\n", + pkt_len, + GNUNET_i2s (sender), + inet_ntop (state->ri.remote_address.af, + &state->ri.remote_address.address, + buf, sizeof (buf)), + (unsigned int) state->ri.remote_address.port); + } + + send_tcp_packet_via_tun (&state->ri.remote_address, + &state->ri.local_address, + &data->tcp_header, + &data[1], pkt_len); + return GNUNET_YES; +} + + +/** + * Send an ICMP packet via the TUN interface. + * + * @param destination_address IP to use for the ICMP packet's destination + * @param source_address IP to use for the ICMP packet's source + * @param icmp_header ICMP header to send + * @param payload payload of the ICMP packet (does NOT include ICMP header) + * @param payload_length number of bytes of data in payload + */ +static void +send_icmp_packet_via_tun (const struct SocketAddress *destination_address, + const struct SocketAddress *source_address, + const struct GNUNET_TUN_IcmpHeader *icmp_header, + const void *payload, size_t payload_length) +{ + size_t len; + struct GNUNET_TUN_IcmpHeader *icmp; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMP packets sent via TUN"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending packet with %u bytes ICMP payload via TUN\n", + (unsigned int) payload_length); + len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); + switch (destination_address->af) + { + case AF_INET: + len += sizeof (struct GNUNET_TUN_IPv4Header); + break; + case AF_INET6: + len += sizeof (struct GNUNET_TUN_IPv6Header); + break; + default: + GNUNET_break (0); + return; + } + len += sizeof (struct GNUNET_TUN_IcmpHeader); + len += payload_length; + if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + { + char buf[len]; + struct GNUNET_MessageHeader *hdr; + struct GNUNET_TUN_Layer2PacketHeader *tun; + + hdr= (struct GNUNET_MessageHeader *) buf; + hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + hdr->size = htons (len); + tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; + tun->flags = htons (0); + switch (source_address->af) + { + case AF_INET: + { + struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; + + tun->proto = htons (ETH_P_IPV4); + GNUNET_TUN_initialize_ipv4_header (ipv4, + IPPROTO_ICMP, + sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length, + &source_address->address.ipv4, + &destination_address->address.ipv4); + icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv4[1]; + } + break; + case AF_INET6: + { + struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1]; + + tun->proto = htons (ETH_P_IPV6); + GNUNET_TUN_initialize_ipv6_header (ipv6, + IPPROTO_ICMPV6, + sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length, + &source_address->address.ipv6, + &destination_address->address.ipv6); + icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv6[1]; + } + break; + default: + GNUNET_assert (0); + break; + } + *icmp = *icmp_header; + memcpy (&icmp[1], + payload, + payload_length); + GNUNET_TUN_calculate_icmp_checksum (icmp, + payload, + payload_length); + (void) GNUNET_HELPER_send (helper_handle, + (const struct GNUNET_MessageHeader*) buf, + GNUNET_YES, + NULL, NULL); + } +} + + +/** + * Synthesize a plausible ICMP payload for an ICMPv4 error + * response on the given tunnel. + * + * @param state tunnel information + * @param ipp IPv6 header to fill in (ICMP payload) + * @param udp "UDP" header to fill in (ICMP payload); might actually + * also be the first 8 bytes of the TCP header + */ +static void +make_up_icmpv4_payload (struct TunnelState *state, + struct GNUNET_TUN_IPv4Header *ipp, + struct GNUNET_TUN_UdpHeader *udp) +{ + GNUNET_TUN_initialize_ipv4_header (ipp, + state->ri.remote_address.proto, + sizeof (struct GNUNET_TUN_TcpHeader), + &state->ri.remote_address.address.ipv4, + &state->ri.local_address.address.ipv4); + udp->source_port = htons (state->ri.remote_address.port); + udp->destination_port = htons (state->ri.local_address.port); + udp->len = htons (0); + udp->crc = htons (0); +} + + +/** + * Synthesize a plausible ICMP payload for an ICMPv6 error + * response on the given tunnel. + * + * @param state tunnel information + * @param ipp IPv6 header to fill in (ICMP payload) + * @param udp "UDP" header to fill in (ICMP payload); might actually + * also be the first 8 bytes of the TCP header + */ +static void +make_up_icmpv6_payload (struct TunnelState *state, + struct GNUNET_TUN_IPv6Header *ipp, + struct GNUNET_TUN_UdpHeader *udp) +{ + GNUNET_TUN_initialize_ipv6_header (ipp, + state->ri.remote_address.proto, + sizeof (struct GNUNET_TUN_TcpHeader), + &state->ri.remote_address.address.ipv6, + &state->ri.local_address.address.ipv6); + udp->source_port = htons (state->ri.remote_address.port); + udp->destination_port = htons (state->ri.local_address.port); + udp->len = htons (0); + udp->crc = htons (0); +} + + +/** + * Process a request to forward ICMP data to the Internet via this peer. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_icmp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx GNUNET_UNUSED, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *state = *tunnel_ctx; + const struct GNUNET_EXIT_IcmpInternetMessage *msg; + uint16_t pkt_len = ntohs (message->size); + const struct in_addr *v4; + const struct in6_addr *v6; + const void *payload; + char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8]; + int af; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMP IP-exit requests received via mesh"), + 1, GNUNET_NO); + if (pkt_len < sizeof (struct GNUNET_EXIT_IcmpInternetMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + msg = (const struct GNUNET_EXIT_IcmpInternetMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_IcmpInternetMessage); + + af = (int) ntohl (msg->af); + if ( (NULL != state->heap_node) && + (af != state->ri.remote_address.af) ) + { + /* other peer switched AF on this tunnel; not allowed */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + switch (af) + { + case AF_INET: + if (pkt_len < sizeof (struct in_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! ipv4_exit) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + v4 = (const struct in_addr*) &msg[1]; + payload = &v4[1]; + pkt_len -= sizeof (struct in_addr); + state->ri.remote_address.address.ipv4 = *v4; + if (NULL == state->heap_node) + { + state->ri.remote_address.af = af; + state->ri.remote_address.proto = IPPROTO_ICMP; + setup_state_record (state); + } + /* check that ICMP type is something we want to support + and possibly make up payload! */ + switch (msg->icmp_header.type) + { + case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: + case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: + break; + case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: + case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: + case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: + if (0 != pkt_len) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + /* make up payload */ + { + struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) buf; + struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; + + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + pkt_len = sizeof (struct GNUNET_TUN_IPv4Header) + 8; + make_up_icmpv4_payload (state, + ipp, + udp); + payload = ipp; + } + break; + default: + GNUNET_break_op (0); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + /* end AF_INET */ + break; + case AF_INET6: + if (pkt_len < sizeof (struct in6_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! ipv6_exit) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + v6 = (const struct in6_addr*) &msg[1]; + payload = &v6[1]; + pkt_len -= sizeof (struct in6_addr); + state->ri.remote_address.address.ipv6 = *v6; + if (NULL == state->heap_node) + { + state->ri.remote_address.af = af; + state->ri.remote_address.proto = IPPROTO_ICMPV6; + setup_state_record (state); + } + /* check that ICMP type is something we want to support + and possibly make up payload! */ + switch (msg->icmp_header.type) + { + case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: + case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: + break; + case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: + case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: + case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: + case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: + if (0 != pkt_len) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + /* make up payload */ + { + struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) buf; + struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; + + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + pkt_len = sizeof (struct GNUNET_TUN_IPv6Header) + 8; + make_up_icmpv6_payload (state, + ipp, + udp); + payload = ipp; + } + break; + default: + GNUNET_break_op (0); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + /* end AF_INET6 */ + break; + default: + /* bad AF */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + { + char buf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received ICMP data from %s for forwarding to %s\n", + GNUNET_i2s (sender), + inet_ntop (af, + &state->ri.remote_address.address, + buf, sizeof (buf))); + } + send_icmp_packet_via_tun (&state->ri.remote_address, + &state->ri.local_address, + &msg->icmp_header, + payload, pkt_len); + return GNUNET_YES; +} + + +/** + * Setup ICMP payload for ICMP error messages. Called + * for both IPv4 and IPv6 addresses. + * + * @param state context for creating the IP Packet + * @param buf where to create the payload, has at least + * sizeof (struct GNUNET_TUN_IPv6Header) + 8 bytes + * @return number of bytes of payload we created in buf + */ +static uint16_t +make_up_icmp_service_payload (struct TunnelState *state, + char *buf) +{ + switch (state->serv->address.af) + { + case AF_INET: + { + struct GNUNET_TUN_IPv4Header *ipv4; + struct GNUNET_TUN_UdpHeader *udp; + + ipv4 = (struct GNUNET_TUN_IPv4Header *)buf; + udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1]; + make_up_icmpv4_payload (state, + ipv4, + udp); + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + return sizeof (struct GNUNET_TUN_IPv4Header) + 8; + } + break; + case AF_INET6: + { + struct GNUNET_TUN_IPv6Header *ipv6; + struct GNUNET_TUN_UdpHeader *udp; + + ipv6 = (struct GNUNET_TUN_IPv6Header *)buf; + udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1]; + make_up_icmpv6_payload (state, + ipv6, + udp); + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + return sizeof (struct GNUNET_TUN_IPv6Header) + 8; + } + break; + default: + GNUNET_break (0); + } + return 0; +} + + +/** + * Process a request via mesh to send ICMP data to a service + * offered by this system. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_icmp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *state = *tunnel_ctx; + const struct GNUNET_EXIT_IcmpServiceMessage *msg; + uint16_t pkt_len = ntohs (message->size); + struct GNUNET_TUN_IcmpHeader icmp; + char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8]; + const void *payload; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMP service requests received via mesh"), + 1, GNUNET_NO); + /* check that we got at least a valid header */ + if (pkt_len < sizeof (struct GNUNET_EXIT_IcmpServiceMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + msg = (const struct GNUNET_EXIT_IcmpServiceMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_IcmpServiceMessage); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received data from %s for forwarding to ICMP service %s\n", + GNUNET_i2s (sender), + GNUNET_h2s (&msg->service_descriptor)); + if (NULL == state->serv) + { + /* first packet to service must not be ICMP (cannot determine service!) */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + icmp = msg->icmp_header; + payload = &msg[1]; + state->ri.remote_address = state->serv->address; + setup_state_record (state); + + /* check that ICMP type is something we want to support, + perform ICMP PT if needed ans possibly make up payload */ + switch (msg->af) + { + case AF_INET: + switch (msg->icmp_header.type) + { + case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: + if (state->serv->address.af == AF_INET6) + icmp.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY; + break; + case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: + if (state->serv->address.af == AF_INET6) + icmp.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST; + break; + case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: + if (state->serv->address.af == AF_INET6) + icmp.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; + if (0 != pkt_len) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + payload = buf; + pkt_len = make_up_icmp_service_payload (state, buf); + break; + case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: + if (state->serv->address.af == AF_INET6) + icmp.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED; + if (0 != pkt_len) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + payload = buf; + pkt_len = make_up_icmp_service_payload (state, buf); + break; + case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: + if (state->serv->address.af == AF_INET6) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"), + 1, GNUNET_NO); + return GNUNET_OK; + } + if (0 != pkt_len) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + payload = buf; + pkt_len = make_up_icmp_service_payload (state, buf); + break; + default: + GNUNET_break_op (0); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + /* end of AF_INET */ + break; + case AF_INET6: + switch (msg->icmp_header.type) + { + case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: + if (state->serv->address.af == AF_INET) + icmp.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY; + break; + case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: + if (state->serv->address.af == AF_INET) + icmp.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST; + break; + case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: + if (state->serv->address.af == AF_INET) + icmp.type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE; + if (0 != pkt_len) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + payload = buf; + pkt_len = make_up_icmp_service_payload (state, buf); + break; + case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: + if (state->serv->address.af == AF_INET) + icmp.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED; + if (0 != pkt_len) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + payload = buf; + pkt_len = make_up_icmp_service_payload (state, buf); + break; + case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: + case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: + if (state->serv->address.af == AF_INET) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), + 1, GNUNET_NO); + return GNUNET_OK; + } + if (0 != pkt_len) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + payload = buf; + pkt_len = make_up_icmp_service_payload (state, buf); + break; + default: + GNUNET_break_op (0); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + /* end of AF_INET6 */ + break; + default: + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + send_icmp_packet_via_tun (&state->ri.remote_address, + &state->ri.local_address, + &icmp, + payload, pkt_len); + return GNUNET_YES; +} + + +/** + * Send a UDP packet via the TUN interface. + * + * @param destination_address IP and port to use for the UDP packet's destination + * @param source_address IP and port to use for the UDP packet's source + * @param payload payload of the UDP packet (does NOT include UDP header) + * @param payload_length number of bytes of data in payload + */ +static void +send_udp_packet_via_tun (const struct SocketAddress *destination_address, + const struct SocketAddress *source_address, + const void *payload, size_t payload_length) +{ + size_t len; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP packets sent via TUN"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending packet with %u bytes UDP payload via TUN\n", + (unsigned int) payload_length); + len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); + switch (source_address->af) + { + case AF_INET: + len += sizeof (struct GNUNET_TUN_IPv4Header); + break; + case AF_INET6: + len += sizeof (struct GNUNET_TUN_IPv6Header); + break; + default: + GNUNET_break (0); + return; + } + len += sizeof (struct GNUNET_TUN_UdpHeader); + len += payload_length; + if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + { + char buf[len]; + struct GNUNET_MessageHeader *hdr; + struct GNUNET_TUN_Layer2PacketHeader *tun; + + hdr= (struct GNUNET_MessageHeader *) buf; + hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + hdr->size = htons (len); + tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; + tun->flags = htons (0); + switch (source_address->af) + { + case AF_INET: + { + struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; + + tun->proto = htons (ETH_P_IPV4); + prepare_ipv4_packet (payload, payload_length, + IPPROTO_UDP, + NULL, + source_address, + destination_address, + ipv4); + } + break; + case AF_INET6: + { + struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1]; + + tun->proto = htons (ETH_P_IPV6); + prepare_ipv6_packet (payload, payload_length, + IPPROTO_UDP, + NULL, + source_address, + destination_address, + ipv6); + } + break; + default: + GNUNET_assert (0); + break; + } + (void) GNUNET_HELPER_send (helper_handle, + (const struct GNUNET_MessageHeader*) buf, + GNUNET_YES, + NULL, NULL); + } +} + + +/** + * Process a request to forward UDP data to the Internet via this peer. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_udp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx GNUNET_UNUSED, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *state = *tunnel_ctx; + const struct GNUNET_EXIT_UdpInternetMessage *msg; + uint16_t pkt_len = ntohs (message->size); + const struct in_addr *v4; + const struct in6_addr *v6; + const void *payload; + int af; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP IP-exit requests received via mesh"), + 1, GNUNET_NO); + if (pkt_len < sizeof (struct GNUNET_EXIT_UdpInternetMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + msg = (const struct GNUNET_EXIT_UdpInternetMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_UdpInternetMessage); + af = (int) ntohl (msg->af); + state->ri.remote_address.af = af; + switch (af) + { + case AF_INET: + if (pkt_len < sizeof (struct in_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! ipv4_exit) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + v4 = (const struct in_addr*) &msg[1]; + payload = &v4[1]; + pkt_len -= sizeof (struct in_addr); + state->ri.remote_address.address.ipv4 = *v4; + break; + case AF_INET6: + if (pkt_len < sizeof (struct in6_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! ipv6_exit) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + v6 = (const struct in6_addr*) &msg[1]; + payload = &v6[1]; + pkt_len -= sizeof (struct in6_addr); + state->ri.remote_address.address.ipv6 = *v6; + break; + default: + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + { + char buf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received data from %s for forwarding to UDP %s:%u\n", + GNUNET_i2s (sender), + inet_ntop (af, + &state->ri.remote_address.address, + buf, sizeof (buf)), + (unsigned int) ntohs (msg->destination_port)); + } + state->ri.remote_address.proto = IPPROTO_UDP; + state->ri.remote_address.port = msg->destination_port; + if (NULL == state->heap_node) + setup_state_record (state); + if (0 != ntohs (msg->source_port)) + state->ri.local_address.port = msg->source_port; + send_udp_packet_via_tun (&state->ri.remote_address, + &state->ri.local_address, + payload, pkt_len); + return GNUNET_YES; +} + + +/** + * Process a request via mesh to send a request to a UDP service + * offered by this system. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_udp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *state = *tunnel_ctx; + const struct GNUNET_EXIT_UdpServiceMessage *msg; + uint16_t pkt_len = ntohs (message->size); + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP service requests received via mesh"), + 1, GNUNET_NO); + /* check that we got at least a valid header */ + if (pkt_len < sizeof (struct GNUNET_EXIT_UdpServiceMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + msg = (const struct GNUNET_EXIT_UdpServiceMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_UdpServiceMessage); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received data from %s for forwarding to UDP service %s on port %u\n", + GNUNET_i2s (sender), + GNUNET_h2s (&msg->service_descriptor), + (unsigned int) ntohs (msg->destination_port)); + if (NULL == (state->serv = find_service (udp_services, &msg->service_descriptor, + ntohs (msg->destination_port)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("No service found for %s on port %d!\n"), + "UDP", + ntohs (msg->destination_port)); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP requests dropped (no such service)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + state->ri.remote_address = state->serv->address; + setup_state_record (state); + if (0 != ntohs (msg->source_port)) + state->ri.local_address.port = msg->source_port; + send_udp_packet_via_tun (&state->ri.remote_address, + &state->ri.local_address, + &msg[1], pkt_len); + return GNUNET_YES; +} + + +/** + * Callback from GNUNET_MESH for new tunnels. + * + * @param cls closure + * @param tunnel new handle to the tunnel + * @param initiator peer that started the tunnel + * @param atsi performance information for the tunnel + * @return initial tunnel context for the tunnel + */ +static void * +new_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *s = GNUNET_malloc (sizeof (struct TunnelState)); + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Inbound MESH tunnels created"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received inbound tunnel from `%s'\n", + GNUNET_i2s (initiator)); + s->tunnel = tunnel; + return s; +} + + +/** + * Function called by mesh whenever an inbound tunnel is destroyed. + * Should clean up any associated state. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end (henceforth invalid) + * @param tunnel_ctx place where local state associated + * with the tunnel is stored + */ +static void +clean_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel, + void *tunnel_ctx) +{ + struct TunnelState *s = tunnel_ctx; + struct TunnelMessageQueue *tnq; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Tunnel destroyed\n"); + while (NULL != (tnq = s->head)) + { + GNUNET_CONTAINER_DLL_remove (s->head, + s->tail, + tnq); + GNUNET_free (tnq); + } + if (s->heap_node != NULL) + { + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (connections_map, + &s->state_key, + s)); + GNUNET_CONTAINER_heap_remove_node (s->heap_node); + s->heap_node = NULL; + } + if (NULL != s->th) + { + GNUNET_MESH_notify_transmit_ready_cancel (s->th); + s->th = NULL; + } + GNUNET_free (s); +} + + +/** + * Function that frees everything from a hashmap + * + * @param cls unused + * @param hash key + * @param value value to free + */ +static int +free_iterate (void *cls GNUNET_UNUSED, + const GNUNET_HashCode * hash GNUNET_UNUSED, void *value) +{ + GNUNET_free (value); + return GNUNET_YES; +} + + +/** + * Function scheduled as very last function, cleans up after us + */ +static void +cleanup (void *cls GNUNET_UNUSED, + const struct GNUNET_SCHEDULER_TaskContext *tskctx) +{ + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Exit service is shutting down now\n"); + if (helper_handle != NULL) + { + GNUNET_HELPER_stop (helper_handle); + helper_handle = NULL; + } + if (mesh_handle != NULL) + { + GNUNET_MESH_disconnect (mesh_handle); + mesh_handle = NULL; + } + if (NULL != connections_map) + { + GNUNET_CONTAINER_multihashmap_iterate (connections_map, &free_iterate, NULL); + GNUNET_CONTAINER_multihashmap_destroy (connections_map); + connections_map = NULL; + } + if (NULL != connections_heap) + { + GNUNET_CONTAINER_heap_destroy (connections_heap); + connections_heap = NULL; + } + if (NULL != tcp_services) + { + GNUNET_CONTAINER_multihashmap_iterate (tcp_services, &free_service_record, NULL); + GNUNET_CONTAINER_multihashmap_destroy (tcp_services); + tcp_services = NULL; + } + if (NULL != udp_services) + { + GNUNET_CONTAINER_multihashmap_iterate (udp_services, &free_service_record, NULL); + GNUNET_CONTAINER_multihashmap_destroy (udp_services); + udp_services = NULL; + } + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + stats = NULL; + } + for (i=0;i<8;i++) + GNUNET_free_non_null (exit_argv[i]); +} + + +/** + * Add services to the service map. + * + * @param proto IPPROTO_TCP or IPPROTO_UDP + * @param cpy copy of the service descriptor (can be mutilated) + * @param name DNS name of the service + */ +static void +add_services (int proto, + char *cpy, + const char *name) +{ + char *redirect; + char *hostname; + char *hostport; + struct LocalService *serv; + + for (redirect = strtok (cpy, " "); redirect != NULL; + redirect = strtok (NULL, " ")) + { + if (NULL == (hostname = strstr (redirect, ":"))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "option `%s' for domain `%s' is not formatted correctly!\n", + redirect, + name); + continue; + } + hostname[0] = '\0'; + hostname++; + if (NULL == (hostport = strstr (hostname, ":"))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "option `%s' for domain `%s' is not formatted correctly!\n", + redirect, + name); + continue; + } + hostport[0] = '\0'; + hostport++; + + int local_port = atoi (redirect); + int remote_port = atoi (hostport); + + if (!((local_port > 0) && (local_port < 65536))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`%s' is not a valid port number (for domain `%s')!", redirect, + name); + continue; + } + if (!((remote_port > 0) && (remote_port < 65536))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`%s' is not a valid port number (for domain `%s')!", hostport, + name); + continue; + } + + serv = GNUNET_malloc (sizeof (struct LocalService)); + serv->my_port = (uint16_t) local_port; + serv->address.port = remote_port; + if (0 == strcmp ("localhost4", hostname)) + { + const char *ip4addr = exit_argv[4]; + + serv->address.af = AF_INET; + GNUNET_assert (1 != inet_pton (AF_INET, ip4addr, &serv->address.address.ipv4)); + } + else if (0 == strcmp ("localhost6", hostname)) + { + const char *ip6addr = exit_argv[2]; + + serv->address.af = AF_INET6; + GNUNET_assert (1 == inet_pton (AF_INET6, ip6addr, &serv->address.address.ipv6)); + } + else + { + struct addrinfo *res; + int ret; + + ret = getaddrinfo (hostname, NULL, NULL, &res); + if ( (ret != 0) || (res == NULL) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("No addresses found for hostname `%s' of service `%s'!\n"), + hostname, + name); + GNUNET_free (serv); + continue; + } + + serv->address.af = res->ai_family; + switch (res->ai_family) + { + case AF_INET: + if (! ipv4_enabled) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Service `%s' configured for IPv4, but IPv4 is disabled!\n"), + name); + freeaddrinfo (res); + GNUNET_free (serv); + continue; + } + serv->address.address.ipv4 = ((struct sockaddr_in *) res->ai_addr)->sin_addr; + break; + case AF_INET6: + if (! ipv6_enabled) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Service `%s' configured for IPv4, but IPv4 is disabled!\n"), + name); + freeaddrinfo (res); + GNUNET_free (serv); + continue; + } + serv->address.address.ipv6 = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; + break; + default: + freeaddrinfo (res); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("No IP addresses found for hostname `%s' of service `%s'!\n"), + hostname, + name); + GNUNET_free (serv); + continue; + } + freeaddrinfo (res); + } + store_service ((IPPROTO_UDP == proto) ? udp_services : tcp_services, + name, + local_port, + serv); + } +} + + +/** + * Reads the configuration servicecfg and populates udp_services + * + * @param cls unused + * @param section name of section in config, equal to hostname + */ +static void +read_service_conf (void *cls GNUNET_UNUSED, const char *section) +{ + char *cpy; + + if ((strlen (section) < 8) || + (0 != strcmp (".gnunet.", section + (strlen (section) - 8)))) + return; + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, section, "UDP_REDIRECTS", + &cpy)) + { + add_services (IPPROTO_UDP, cpy, section); + GNUNET_free (cpy); + } + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, section, "TCP_REDIRECTS", + &cpy)) + { + add_services (IPPROTO_TCP, cpy, section); + GNUNET_free (cpy); + } +} + + +/** + * Test if the given AF is supported by this system. + * + * @param af to test + * @return GNUNET_OK if the AF is supported + */ +static int +test_af (int af) +{ + int s; + + s = socket (af, SOCK_STREAM, 0); + if (-1 == s) + { + if (EAFNOSUPPORT == errno) + return GNUNET_NO; + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "socket"); + return GNUNET_SYSERR; + } + close (s); + return GNUNET_OK; +} + + +/** + * @brief Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg_ configuration + */ +static void +run (void *cls, char *const *args GNUNET_UNUSED, + const char *cfgfile GNUNET_UNUSED, + const struct GNUNET_CONFIGURATION_Handle *cfg_) +{ + static struct GNUNET_MESH_MessageHandler handlers[] = { + {&receive_icmp_service, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE, 0}, + {&receive_icmp_remote, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET, 0}, + {&receive_udp_service, GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE, 0}, + {&receive_udp_remote, GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET, 0}, + {&receive_tcp_service, GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START, 0}, + {&receive_tcp_remote, GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START, 0}, + {&receive_tcp_data, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT, 0}, + {NULL, 0, 0} + }; + + static GNUNET_MESH_ApplicationType apptypes[] = { + GNUNET_APPLICATION_TYPE_END, + GNUNET_APPLICATION_TYPE_END, + GNUNET_APPLICATION_TYPE_END + }; + unsigned int app_idx; + char *exit_ifname; + char *tun_ifname; + char *ipv6addr; + char *ipv6prefix_s; + char *ipv4addr; + char *ipv4mask; + + if (GNUNET_YES != + GNUNET_OS_check_helper_binary ("gnunet-helper-exit")) + { + fprintf (stderr, + "`%s' is not SUID, refusing to run.\n", + "gnunet-helper-exit"); + global_ret = 1; + return; + } + cfg = cfg_; + stats = GNUNET_STATISTICS_create ("exit", cfg); + ipv4_exit = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "EXIT_IPV4"); + ipv6_exit = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "EXIT_IPV6"); + ipv4_enabled = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_IPV4"); + ipv6_enabled = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_IPV6"); + + if ( (ipv4_exit || ipv4_enabled) && + GNUNET_OK != test_af (AF_INET)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("This system does not support IPv4, will disable IPv4 functions despite them being enabled in the configuration\n")); + ipv4_exit = GNUNET_NO; + ipv4_enabled = GNUNET_NO; + } + if ( (ipv6_exit || ipv6_enabled) && + GNUNET_OK != test_af (AF_INET6)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("This system does not support IPv6, will disable IPv6 functions despite them being enabled in the configuration\n")); + ipv6_exit = GNUNET_NO; + ipv6_enabled = GNUNET_NO; + } + if (ipv4_exit && (! ipv4_enabled)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use ENABLE_IPv4=YES\n")); + ipv4_enabled = GNUNET_YES; + } + if (ipv6_exit && (! ipv6_enabled)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use ENABLE_IPv6=YES\n")); + ipv6_enabled = GNUNET_YES; + } + if (! (ipv4_enabled || ipv6_enabled)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No useful service enabled. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + app_idx = 0; + if (GNUNET_YES == ipv4_exit) + { + apptypes[app_idx] = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY; + app_idx++; + } + if (GNUNET_YES == ipv6_exit) + { + apptypes[app_idx] = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY; + app_idx++; + } + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "MAX_CONNECTIONS", + &max_connections)) + max_connections = 1024; + exit_argv[0] = GNUNET_strdup ("exit-gnunet"); + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "TUN_IFNAME", &tun_ifname)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'TUN_IFNAME' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[1] = tun_ifname; + if (ipv4_enabled) + { + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "EXIT_IFNAME", &exit_ifname)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'EXIT_IFNAME' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[2] = exit_ifname; + } + else + { + exit_argv[2] = GNUNET_strdup ("%"); + } + + + if (GNUNET_YES == ipv6_enabled) + { + if ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR", + &ipv6addr) || + (1 != inet_pton (AF_INET6, ipv6addr, &exit_ipv6addr))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No valid entry 'IPV6ADDR' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[3] = ipv6addr; + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6PREFIX", + &ipv6prefix_s)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'IPV6PREFIX' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[4] = ipv6prefix_s; + if ( (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "exit", + "IPV6PREFIX", + &ipv6prefix)) || + (ipv6prefix >= 127) ) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + } + else + { + /* IPv6 explicitly disabled */ + exit_argv[3] = GNUNET_strdup ("-"); + exit_argv[4] = GNUNET_strdup ("-"); + } + if (GNUNET_YES == ipv4_enabled) + { + if ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR", + &ipv4addr) || + (1 != inet_pton (AF_INET, ipv4addr, &exit_ipv4addr))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No valid entry for 'IPV4ADDR' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[5] = ipv4addr; + if ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK", + &ipv4mask) || + (1 != inet_pton (AF_INET, ipv4mask, &exit_ipv4mask))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No valid entry 'IPV4MASK' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[6] = ipv4mask; + } + else + { + /* IPv4 explicitly disabled */ + exit_argv[5] = GNUNET_strdup ("-"); + exit_argv[6] = GNUNET_strdup ("-"); + } + exit_argv[7] = NULL; + + udp_services = GNUNET_CONTAINER_multihashmap_create (65536); + tcp_services = GNUNET_CONTAINER_multihashmap_create (65536); + GNUNET_CONFIGURATION_iterate_sections (cfg, &read_service_conf, NULL); + + connections_map = GNUNET_CONTAINER_multihashmap_create (65536); + connections_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + mesh_handle + = GNUNET_MESH_connect (cfg, 42 /* queue size */, NULL, + &new_tunnel, + &clean_tunnel, handlers, + apptypes); + if (NULL == mesh_handle) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + helper_handle = GNUNET_HELPER_start ("gnunet-helper-exit", + exit_argv, + &message_token, NULL); +} + + +/** + * The main function + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-exit", + gettext_noop + ("Daemon to run to provide an IP exit node for the VPN"), + options, &run, NULL)) ? global_ret : 1; +} + + +/* end of gnunet-daemon-exit.c */ diff --git a/src/exit/gnunet-helper-exit.c b/src/exit/gnunet-helper-exit.c new file mode 100644 index 0000000..573bb7a --- /dev/null +++ b/src/exit/gnunet-helper-exit.c @@ -0,0 +1,767 @@ +/* + This file is part of GNUnet. + (C) 2010, 2011, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file exit/gnunet-helper-exit.c + * + * @brief the helper for exit nodes. Opens a virtual + * network-interface, sends data received on the if to stdout, sends + * data received on stdin to the interface. The code also enables + * IPv4/IPv6 forwarding and NAT on the current system (the latter on + * an interface specified on the command-line); these changes to the + * network configuration are NOT automatically undone when the program + * is stopped (this is because we cannot be sure that some other + * application didn't enable them before or after us; also, these + * changes should be mostly harmless as it simply turns the system + * into a router). + * + * @author Philipp Tölke + * @author Christian Grothoff + * + * The following list of people have reviewed this code and considered + * it safe since the last modification (if you reviewed it, please + * have your name added to the list): + * + * - Philipp Tölke + */ +#include "platform.h" +#include + +/** + * Need 'struct GNUNET_MessageHeader'. + */ +#include "gnunet_common.h" + +/** + * Need VPN message types. + */ +#include "gnunet_protocols.h" + +/** + * Should we print (interesting|debug) messages that can happen during + * normal operation? + */ +#define DEBUG GNUNET_NO + +/** + * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) + */ +#define MAX_SIZE 65536 + +/** + * Path to 'sysctl' binary. + */ +static const char *sbin_sysctl; + +/** + * Path to 'iptables' binary. + */ +static const char *sbin_iptables; + + +#ifndef _LINUX_IN6_H +/** + * This is in linux/include/net/ipv6.h, but not always exported... + */ +struct in6_ifreq +{ + struct in6_addr ifr6_addr; + __u32 ifr6_prefixlen; + int ifr6_ifindex; +}; +#endif + + + +/** + * Run the given command and wait for it to complete. + * + * @param file name of the binary to run + * @param cmd command line arguments (as given to 'execv') + * @return 0 on success, 1 on any error + */ +static int +fork_and_exec (const char *file, + char *const cmd[]) +{ + int status; + pid_t pid; + pid_t ret; + + pid = fork (); + if (-1 == pid) + { + fprintf (stderr, + "fork failed: %s\n", + strerror (errno)); + return 1; + } + if (0 == pid) + { + /* we are the child process */ + /* close stdin/stdout to not cause interference + with the helper's main protocol! */ + (void) close (0); + (void) close (1); + (void) execv (file, cmd); + /* can only get here on error */ + fprintf (stderr, + "exec `%s' failed: %s\n", + file, + strerror (errno)); + _exit (1); + } + /* keep running waitpid as long as the only error we get is 'EINTR' */ + while ( (-1 == (ret = waitpid (pid, &status, 0))) && + (errno == EINTR) ); + if (-1 == ret) + { + fprintf (stderr, + "waitpid failed: %s\n", + strerror (errno)); + return 1; + } + if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) + return 1; + /* child process completed and returned success, we're happy */ + return 0; +} + + +/** + * Creates a tun-interface called dev; + * + * @param dev is asumed to point to a char[IFNAMSIZ] + * if *dev == '\\0', uses the name supplied by the kernel; + * @return the fd to the tun or -1 on error + */ +static int +init_tun (char *dev) +{ + struct ifreq ifr; + int fd; + + if (NULL == dev) + { + errno = EINVAL; + return -1; + } + + if (-1 == (fd = open ("/dev/net/tun", O_RDWR))) + { + fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun", + strerror (errno)); + return -1; + } + + if (fd >= FD_SETSIZE) + { + fprintf (stderr, "File descriptor to large: %d", fd); + (void) close (fd); + return -1; + } + + memset (&ifr, 0, sizeof (ifr)); + ifr.ifr_flags = IFF_TUN; + + if ('\0' != *dev) + strncpy (ifr.ifr_name, dev, IFNAMSIZ); + + if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr)) + { + fprintf (stderr, + "Error with ioctl on `%s': %s\n", "/dev/net/tun", + strerror (errno)); + (void) close (fd); + return -1; + } + strcpy (dev, ifr.ifr_name); + return fd; +} + + +/** + * @brief Sets the IPv6-Address given in address on the interface dev + * + * @param dev the interface to configure + * @param address the IPv6-Address + * @param prefix_len the length of the network-prefix + */ +static void +set_address6 (const char *dev, const char *address, unsigned long prefix_len) +{ + struct ifreq ifr; + struct sockaddr_in6 sa6; + int fd; + struct in6_ifreq ifr6; + + /* + * parse the new address + */ + memset (&sa6, 0, sizeof (struct sockaddr_in6)); + sa6.sin6_family = AF_INET6; + if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr)) + { + fprintf (stderr, "Failed to parse address `%s': %s\n", address, + strerror (errno)); + exit (1); + } + + if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0))) + { + fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); + exit (1); + } + + memset (&ifr, 0, sizeof (struct ifreq)); + /* + * Get the index of the if + */ + strncpy (ifr.ifr_name, dev, IFNAMSIZ); + if (-1 == ioctl (fd, SIOGIFINDEX, &ifr)) + { + fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); + (void) close (fd); + exit (1); + } + + memset (&ifr6, 0, sizeof (struct in6_ifreq)); + ifr6.ifr6_addr = sa6.sin6_addr; + ifr6.ifr6_ifindex = ifr.ifr_ifindex; + ifr6.ifr6_prefixlen = prefix_len; + + /* + * Set the address + */ + if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Get the flags + */ + if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Add the UP and RUNNING flags + */ + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + if (0 != close (fd)) + { + fprintf (stderr, "close failed: %s\n", strerror (errno)); + exit (1); + } +} + + +/** + * @brief Sets the IPv4-Address given in address on the interface dev + * + * @param dev the interface to configure + * @param address the IPv4-Address + * @param mask the netmask + */ +static void +set_address4 (const char *dev, const char *address, const char *mask) +{ + int fd; + struct sockaddr_in *addr; + struct ifreq ifr; + + memset (&ifr, 0, sizeof (struct ifreq)); + addr = (struct sockaddr_in *) &(ifr.ifr_addr); + addr->sin_family = AF_INET; + + /* + * Parse the address + */ + if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr)) + { + fprintf (stderr, "Failed to parse address `%s': %s\n", address, + strerror (errno)); + exit (1); + } + + if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0))) + { + fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); + exit (1); + } + + strncpy (ifr.ifr_name, dev, IFNAMSIZ); + + /* + * Set the address + */ + if (-1 == ioctl (fd, SIOCSIFADDR, &ifr)) + { + fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Parse the netmask + */ + addr = (struct sockaddr_in *) &(ifr.ifr_netmask); + if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr)) + { + fprintf (stderr, "Failed to parse address `%s': %s\n", mask, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Set the netmask + */ + if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Get the flags + */ + if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Add the UP and RUNNING flags + */ + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + if (0 != close (fd)) + { + fprintf (stderr, "close failed: %s\n", strerror (errno)); + (void) close (fd); + exit (1); + } +} + + +/** + * Start forwarding to and from the tunnel. + * + * @param fd_tun tunnel FD + */ +static void +run (int fd_tun) +{ + /* + * The buffer filled by reading from fd_tun + */ + unsigned char buftun[MAX_SIZE]; + ssize_t buftun_size = 0; + unsigned char *buftun_read = NULL; + + /* + * The buffer filled by reading from stdin + */ + unsigned char bufin[MAX_SIZE]; + ssize_t bufin_size = 0; + size_t bufin_rpos = 0; + unsigned char *bufin_read = NULL; + + fd_set fds_w; + fd_set fds_r; + + /* read refers to reading from fd_tun, writing to stdout */ + int read_open = 1; + + /* write refers to reading from stdin, writing to fd_tun */ + int write_open = 1; + + while ((1 == read_open) || (1 == write_open)) + { + FD_ZERO (&fds_w); + FD_ZERO (&fds_r); + + /* + * We are supposed to read and the buffer is empty + * -> select on read from tun + */ + if (read_open && (0 == buftun_size)) + FD_SET (fd_tun, &fds_r); + + /* + * We are supposed to read and the buffer is not empty + * -> select on write to stdout + */ + if (read_open && (0 != buftun_size)) + FD_SET (1, &fds_w); + + /* + * We are supposed to write and the buffer is empty + * -> select on read from stdin + */ + if (write_open && (NULL == bufin_read)) + FD_SET (0, &fds_r); + + /* + * We are supposed to write and the buffer is not empty + * -> select on write to tun + */ + if (write_open && (NULL != bufin_read)) + FD_SET (fd_tun, &fds_w); + + int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL); + + if (-1 == r) + { + if (EINTR == errno) + continue; + fprintf (stderr, "select failed: %s\n", strerror (errno)); + exit (1); + } + + if (r > 0) + { + if (FD_ISSET (fd_tun, &fds_r)) + { + buftun_size = + read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader), + MAX_SIZE - sizeof (struct GNUNET_MessageHeader)); + if (-1 == buftun_size) + { + fprintf (stderr, "read-error: %s\n", strerror (errno)); + shutdown (fd_tun, SHUT_RD); + shutdown (1, SHUT_WR); + read_open = 0; + buftun_size = 0; + } + else if (0 == buftun_size) + { +#if DEBUG + fprintf (stderr, "EOF on tun\n"); +#endif + shutdown (fd_tun, SHUT_RD); + shutdown (1, SHUT_WR); + read_open = 0; + buftun_size = 0; + } + else + { + buftun_read = buftun; + struct GNUNET_MessageHeader *hdr = + (struct GNUNET_MessageHeader *) buftun; + buftun_size += sizeof (struct GNUNET_MessageHeader); + hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + hdr->size = htons (buftun_size); + } + } + else if (FD_ISSET (1, &fds_w)) + { + ssize_t written = write (1, buftun_read, buftun_size); + + if (-1 == written) + { +#if !DEBUG + if (errno != EPIPE) +#endif + fprintf (stderr, "write-error to stdout: %s\n", strerror (errno)); + shutdown (fd_tun, SHUT_RD); + shutdown (1, SHUT_WR); + read_open = 0; + buftun_size = 0; + } + else if (0 == written) + { + fprintf (stderr, "write returned 0!?\n"); + exit (1); + } + else + { + buftun_size -= written; + buftun_read += written; + } + } + + if (FD_ISSET (0, &fds_r)) + { + bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos); + if (-1 == bufin_size) + { + fprintf (stderr, "read-error: %s\n", strerror (errno)); + shutdown (0, SHUT_RD); + shutdown (fd_tun, SHUT_WR); + write_open = 0; + bufin_size = 0; + } + else if (0 == bufin_size) + { +#if DEBUG + fprintf (stderr, "EOF on stdin\n"); +#endif + shutdown (0, SHUT_RD); + shutdown (fd_tun, SHUT_WR); + write_open = 0; + bufin_size = 0; + } + else + { + struct GNUNET_MessageHeader *hdr; + +PROCESS_BUFFER: + bufin_rpos += bufin_size; + if (bufin_rpos < sizeof (struct GNUNET_MessageHeader)) + continue; + hdr = (struct GNUNET_MessageHeader *) bufin; + if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) + { + fprintf (stderr, "protocol violation!\n"); + exit (1); + } + if (ntohs (hdr->size) > bufin_rpos) + continue; + bufin_read = bufin + sizeof (struct GNUNET_MessageHeader); + bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader); + bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader); + } + } + else if (FD_ISSET (fd_tun, &fds_w)) + { + ssize_t written = write (fd_tun, bufin_read, bufin_size); + + if (-1 == written) + { + fprintf (stderr, "write-error to tun: %s\n", strerror (errno)); + shutdown (0, SHUT_RD); + shutdown (fd_tun, SHUT_WR); + write_open = 0; + bufin_size = 0; + } + else if (0 == written) + { + fprintf (stderr, "write returned 0!?\n"); + exit (1); + } + else + { + bufin_size -= written; + bufin_read += written; + if (0 == bufin_size) + { + memmove (bufin, bufin_read, bufin_rpos); + bufin_read = NULL; /* start reading again */ + bufin_size = 0; + goto PROCESS_BUFFER; + } + } + } + } + } +} + + +/** + * Open VPN tunnel interface. + * + * @param argc must be 6 + * @param argv 0: binary name ("gnunet-helper-exit") + * 1: tunnel interface name ("gnunet-exit") + * 2: IPv4 "physical" interface name ("eth0"), or "%" to not do IPv4 NAT + * 3: IPv6 address ("::1"), or "-" to skip IPv6 + * 4: IPv6 netmask length in bits ("64") [ignored if #4 is "-"] + * 5: IPv4 address ("1.2.3.4"), or "-" to skip IPv4 + * 6: IPv4 netmask ("255.255.0.0") [ignored if #4 is "-"] + */ +int +main (int argc, char **argv) +{ + char dev[IFNAMSIZ]; + int fd_tun; + int global_ret; + + if (7 != argc) + { + fprintf (stderr, "Fatal: must supply 6 arguments!\n"); + return 1; + } + if ( (0 == strcmp (argv[3], "-")) && + (0 == strcmp (argv[5], "-")) ) + { + fprintf (stderr, "Fatal: disabling both IPv4 and IPv6 makes no sense.\n"); + return 1; + } + if (0 == access ("/sbin/iptables", X_OK)) + sbin_iptables = "/sbin/iptables"; + else if (0 == access ("/usr/sbin/iptables", X_OK)) + sbin_iptables = "/usr/sbin/iptables"; + else + { + fprintf (stderr, + "Fatal: executable iptables not found in approved directories: %s\n", + strerror (errno)); + return 1; + } + if (0 == access ("/sbin/sysctl", X_OK)) + sbin_sysctl = "/sbin/sysctl"; + else if (0 == access ("/usr/sbin/sysctl", X_OK)) + sbin_sysctl = "/usr/sbin/sysctl"; + else + { + fprintf (stderr, + "Fatal: executable sysctl not found in approved directories: %s\n", + strerror (errno)); + return 1; + } + + strncpy (dev, argv[1], IFNAMSIZ); + dev[IFNAMSIZ - 1] = '\0'; + + if (-1 == (fd_tun = init_tun (dev))) + { + fprintf (stderr, + "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n", + dev, + argv[3], + argv[4], + argv[5], + argv[6]); + return 1; + } + + if (0 != strcmp (argv[3], "-")) + { + { + const char *address = argv[3]; + long prefix_len = atol (argv[4]); + + if ((prefix_len < 1) || (prefix_len > 127)) + { + fprintf (stderr, "Fatal: prefix_len out of range\n"); + return 1; + } + set_address6 (dev, address, prefix_len); + } + { + char *const sysctl_args[] = + { + "sysctl", "-w", "net.ipv6.conf.all.forwarding=1", NULL + }; + if (0 != fork_and_exec (sbin_sysctl, + sysctl_args)) + { + fprintf (stderr, + "Failed to enable IPv6 forwarding. Will continue anyway.\n"); + } + } + } + + if (0 != strcmp (argv[5], "-")) + { + { + const char *address = argv[5]; + const char *mask = argv[6]; + + set_address4 (dev, address, mask); + } + { + char *const sysctl_args[] = + { + "sysctl", "-w", "net.ipv4.ip_forward=1", NULL + }; + if (0 != fork_and_exec (sbin_sysctl, + sysctl_args)) + { + fprintf (stderr, + "Failed to enable IPv4 forwarding. Will continue anyway.\n"); + } + } + if (0 != strcmp (argv[2], "%")) + { + char *const iptables_args[] = + { + "iptables", "-t", "nat", "-A", "POSTROUTING", "-o", argv[2], "-j", "MASQUERADE", NULL + }; + if (0 != fork_and_exec (sbin_iptables, + iptables_args)) + { + fprintf (stderr, + "Failed to enable IPv4 masquerading (NAT). Will continue anyway.\n"); + } + } + } + + uid_t uid = getuid (); +#ifdef HAVE_SETRESUID + if (0 != setresuid (uid, uid, uid)) + { + fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); + global_ret = 2; + goto cleanup; + } +#else + if (0 != (setuid (uid) | seteuid (uid))) + { + fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); + global_ret = 2; + goto cleanup; + } +#endif + + if (SIG_ERR == signal (SIGPIPE, SIG_IGN)) + { + fprintf (stderr, "Failed to protect against SIGPIPE: %s\n", + strerror (errno)); + /* no exit, we might as well die with SIGPIPE should it ever happen */ + } + run (fd_tun); + global_ret = 0; + cleanup: + close (fd_tun); + return global_ret; +} + +/* end of gnunet-helper-exit.c */ diff --git a/src/fragmentation/Makefile.am b/src/fragmentation/Makefile.am new file mode 100644 index 0000000..1cdbefc --- /dev/null +++ b/src/fragmentation/Makefile.am @@ -0,0 +1,36 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage +endif + +lib_LTLIBRARIES = libgnunetfragmentation.la + +libgnunetfragmentation_la_SOURCES = \ + fragmentation.c fragmentation.h \ + defragmentation.c +libgnunetfragmentation_la_LIBADD = -lm \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunetfragmentation_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +check_PROGRAMS = \ + test_fragmentation + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_fragmentation_SOURCES = \ + test_fragmentation.c +test_fragmentation_LDADD = \ + $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = test_fragmentation_data.conf \ No newline at end of file diff --git a/src/fragmentation/Makefile.in b/src/fragmentation/Makefile.in new file mode 100644 index 0000000..2ccad77 --- /dev/null +++ b/src/fragmentation/Makefile.in @@ -0,0 +1,785 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +check_PROGRAMS = test_fragmentation$(EXEEXT) +subdir = src/fragmentation +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libgnunetfragmentation_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunetfragmentation_la_OBJECTS = fragmentation.lo \ + defragmentation.lo +libgnunetfragmentation_la_OBJECTS = \ + $(am_libgnunetfragmentation_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetfragmentation_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetfragmentation_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_test_fragmentation_OBJECTS = test_fragmentation.$(OBJEXT) +test_fragmentation_OBJECTS = $(am_test_fragmentation_OBJECTS) +test_fragmentation_DEPENDENCIES = \ + $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetfragmentation_la_SOURCES) \ + $(test_fragmentation_SOURCES) +DIST_SOURCES = $(libgnunetfragmentation_la_SOURCES) \ + $(test_fragmentation_SOURCES) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage +lib_LTLIBRARIES = libgnunetfragmentation.la +libgnunetfragmentation_la_SOURCES = \ + fragmentation.c fragmentation.h \ + defragmentation.c + +libgnunetfragmentation_la_LIBADD = -lm \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunetfragmentation_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_fragmentation_SOURCES = \ + test_fragmentation.c + +test_fragmentation_LDADD = \ + $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = test_fragmentation_data.conf +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/fragmentation/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/fragmentation/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetfragmentation.la: $(libgnunetfragmentation_la_OBJECTS) $(libgnunetfragmentation_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetfragmentation_la_LINK) -rpath $(libdir) $(libgnunetfragmentation_la_OBJECTS) $(libgnunetfragmentation_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +test_fragmentation$(EXEEXT): $(test_fragmentation_OBJECTS) $(test_fragmentation_DEPENDENCIES) + @rm -f test_fragmentation$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fragmentation_OBJECTS) $(test_fragmentation_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defragmentation.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fragmentation.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fragmentation.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-libLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/fragmentation/defragmentation.c b/src/fragmentation/defragmentation.c new file mode 100644 index 0000000..b07f204 --- /dev/null +++ b/src/fragmentation/defragmentation.c @@ -0,0 +1,547 @@ +/* + This file is part of GNUnet + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file src/fragmentation/defragmentation.c + * @brief library to help defragment messages + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_fragmentation_lib.h" +#include "fragmentation.h" + +/** + * Timestamps for fragments. + */ +struct FragTimes +{ + /** + * The time the fragment was received. + */ + struct GNUNET_TIME_Absolute time; + + /** + * Number of the bit for the fragment (in [0,..,63]). + */ + unsigned int bit; +}; + + +/** + * Information we keep for one message that is being assembled. Note + * that we keep the context around even after the assembly is done to + * handle 'stray' messages that are received 'late'. A message + * context is ONLY discarded when the queue gets too big. + */ +struct MessageContext +{ + /** + * This is a DLL. + */ + struct MessageContext *next; + + /** + * This is a DLL. + */ + struct MessageContext *prev; + + /** + * Associated defragmentation context. + */ + struct GNUNET_DEFRAGMENT_Context *dc; + + /** + * Pointer to the assembled message, allocated at the + * end of this struct. + */ + const struct GNUNET_MessageHeader *msg; + + /** + * Last time we received any update for this message + * (least-recently updated message will be discarded + * if we hit the queue size). + */ + struct GNUNET_TIME_Absolute last_update; + + /** + * Task scheduled for transmitting the next ACK to the + * other peer. + */ + GNUNET_SCHEDULER_TaskIdentifier ack_task; + + /** + * When did we receive which fragment? Used to calculate + * the time we should send the ACK. + */ + struct FragTimes frag_times[64]; + + /** + * Which fragments have we gotten yet? bits that are 1 + * indicate missing fragments. + */ + uint64_t bits; + + /** + * Unique ID for this message. + */ + uint32_t fragment_id; + + /** + * Which 'bit' did the last fragment we received correspond to? + */ + unsigned int last_bit; + + /** + * For the current ACK round, which is the first relevant + * offset in 'frag_times'? + */ + unsigned int frag_times_start_offset; + + /** + * Which offset whould we write the next frag value into + * in the 'frag_times' array? All smaller entries are valid. + */ + unsigned int frag_times_write_offset; + + /** + * Total size of the message that we are assembling. + */ + uint16_t total_size; + +}; + + +/** + * Defragmentation context (one per connection). + */ +struct GNUNET_DEFRAGMENT_Context +{ + + /** + * For statistics. + */ + struct GNUNET_STATISTICS_Handle *stats; + + /** + * Head of list of messages we're defragmenting. + */ + struct MessageContext *head; + + /** + * Tail of list of messages we're defragmenting. + */ + struct MessageContext *tail; + + /** + * Closure for 'proc' and 'ackp'. + */ + void *cls; + + /** + * Function to call with defragmented messages. + */ + GNUNET_FRAGMENT_MessageProcessor proc; + + /** + * Function to call with acknowledgements. + */ + GNUNET_DEFRAGMENT_AckProcessor ackp; + + /** + * Running average of the latency (delay between messages) for this + * connection. + */ + struct GNUNET_TIME_Relative latency; + + /** + * num_msgs how many fragmented messages + * to we defragment at most at the same time? + */ + unsigned int num_msgs; + + /** + * Current number of messages in the 'struct MessageContext' + * DLL (smaller or equal to 'num_msgs'). + */ + unsigned int list_size; + + /** + * Maximum message size for each fragment. + */ + uint16_t mtu; +}; + + +/** + * Create a defragmentation context. + * + * @param stats statistics context + * @param mtu the maximum message size for each fragment + * @param num_msgs how many fragmented messages + * to we defragment at most at the same time? + * @param cls closure for proc and ackp + * @param proc function to call with defragmented messages + * @param ackp function to call with acknowledgements (to send + * back to the other side) + * @return the defragmentation context + */ +struct GNUNET_DEFRAGMENT_Context * +GNUNET_DEFRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats, + uint16_t mtu, unsigned int num_msgs, + void *cls, + GNUNET_FRAGMENT_MessageProcessor proc, + GNUNET_DEFRAGMENT_AckProcessor ackp) +{ + struct GNUNET_DEFRAGMENT_Context *dc; + + dc = GNUNET_malloc (sizeof (struct GNUNET_DEFRAGMENT_Context)); + dc->stats = stats; + dc->cls = cls; + dc->proc = proc; + dc->ackp = ackp; + dc->num_msgs = num_msgs; + dc->mtu = mtu; + dc->latency = GNUNET_TIME_UNIT_SECONDS; /* start with likely overestimate */ + return dc; +} + + +/** + * Destroy the given defragmentation context. + * + * @param dc defragmentation context + */ +void +GNUNET_DEFRAGMENT_context_destroy (struct GNUNET_DEFRAGMENT_Context *dc) +{ + struct MessageContext *mc; + + while (NULL != (mc = dc->head)) + { + GNUNET_CONTAINER_DLL_remove (dc->head, dc->tail, mc); + dc->list_size--; + if (GNUNET_SCHEDULER_NO_TASK != mc->ack_task) + { + GNUNET_SCHEDULER_cancel (mc->ack_task); + mc->ack_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (mc); + } + GNUNET_assert (0 == dc->list_size); + GNUNET_free (dc); +} + + +/** + * Send acknowledgement to the other peer now. + * + * @param cls the message context + * @param tc the scheduler context + */ +static void +send_ack (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct MessageContext *mc = cls; + struct GNUNET_DEFRAGMENT_Context *dc = mc->dc; + struct FragmentAcknowledgement fa; + + mc->ack_task = GNUNET_SCHEDULER_NO_TASK; + fa.header.size = htons (sizeof (struct FragmentAcknowledgement)); + fa.header.type = htons (GNUNET_MESSAGE_TYPE_FRAGMENT_ACK); + fa.fragment_id = htonl (mc->fragment_id); + fa.bits = GNUNET_htonll (mc->bits); + GNUNET_STATISTICS_update (mc->dc->stats, + _("# acknowledgements sent for fragment"), 1, + GNUNET_NO); + dc->ackp (dc->cls, mc->fragment_id, &fa.header); +} + + +/** + * This function is from the GNU Scientific Library, linear/fit.c, + * (C) 2000 Brian Gough + */ +static void +gsl_fit_mul (const double *x, const size_t xstride, const double *y, + const size_t ystride, const size_t n, double *c1, double *cov_11, + double *sumsq) +{ + double m_x = 0, m_y = 0, m_dx2 = 0, m_dxdy = 0; + + size_t i; + + for (i = 0; i < n; i++) + { + m_x += (x[i * xstride] - m_x) / (i + 1.0); + m_y += (y[i * ystride] - m_y) / (i + 1.0); + } + + for (i = 0; i < n; i++) + { + const double dx = x[i * xstride] - m_x; + const double dy = y[i * ystride] - m_y; + + m_dx2 += (dx * dx - m_dx2) / (i + 1.0); + m_dxdy += (dx * dy - m_dxdy) / (i + 1.0); + } + + /* In terms of y = b x */ + + { + double s2 = 0, d2 = 0; + double b = (m_x * m_y + m_dxdy) / (m_x * m_x + m_dx2); + + *c1 = b; + + /* Compute chi^2 = \sum (y_i - b * x_i)^2 */ + + for (i = 0; i < n; i++) + { + const double dx = x[i * xstride] - m_x; + const double dy = y[i * ystride] - m_y; + const double d = (m_y - b * m_x) + dy - b * dx; + + d2 += d * d; + } + + s2 = d2 / (n - 1.0); /* chisq per degree of freedom */ + + *cov_11 = s2 * 1.0 / (n * (m_x * m_x + m_dx2)); + + *sumsq = d2; + } +} + + +/** + * Estimate the latency between messages based on the most recent + * message time stamps. + * + * @param mc context with time stamps + * @return average delay between time stamps (based on least-squares fit) + */ +static struct GNUNET_TIME_Relative +estimate_latency (struct MessageContext *mc) +{ + struct FragTimes *first; + size_t total = mc->frag_times_write_offset - mc->frag_times_start_offset; + double x[total]; + double y[total]; + size_t i; + double c1; + double cov11; + double sumsq; + struct GNUNET_TIME_Relative ret; + + first = &mc->frag_times[mc->frag_times_start_offset]; + GNUNET_assert (total > 1); + for (i = 0; i < total; i++) + { + x[i] = (double) i; + y[i] = (double) (first[i].time.abs_value - first[0].time.abs_value); + } + gsl_fit_mul (x, 1, y, 1, total, &c1, &cov11, &sumsq); + c1 += sqrt (sumsq); /* add 1 std dev */ + ret.rel_value = (uint64_t) c1; + if (ret.rel_value == 0) + ret = GNUNET_TIME_UNIT_MILLISECONDS; /* always at least 1 */ + return ret; +}; + + +/** + * Discard the message context that was inactive for the longest time. + * + * @param dc defragmentation context + */ +static void +discard_oldest_mc (struct GNUNET_DEFRAGMENT_Context *dc) +{ + struct MessageContext *old; + struct MessageContext *pos; + + old = NULL; + pos = dc->head; + while (NULL != pos) + { + if ((old == NULL) || + (old->last_update.abs_value > pos->last_update.abs_value)) + old = pos; + pos = pos->next; + } + GNUNET_assert (NULL != old); + GNUNET_CONTAINER_DLL_remove (dc->head, dc->tail, old); + dc->list_size--; + if (GNUNET_SCHEDULER_NO_TASK != old->ack_task) + { + GNUNET_SCHEDULER_cancel (old->ack_task); + old->ack_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (old); +} + + +/** + * We have received a fragment. Process it. + * + * @param dc the context + * @param msg the message that was received + * @return GNUNET_OK on success, GNUNET_NO if this was a duplicate, GNUNET_SYSERR on error + */ +int +GNUNET_DEFRAGMENT_process_fragment (struct GNUNET_DEFRAGMENT_Context *dc, + const struct GNUNET_MessageHeader *msg) +{ + struct MessageContext *mc; + const struct FragmentHeader *fh; + uint16_t msize; + uint16_t foff; + uint32_t fid; + char *mbuf; + unsigned int bit; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Relative delay; + unsigned int bc; + unsigned int b; + unsigned int n; + int duplicate; + + if (ntohs (msg->size) < sizeof (struct FragmentHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (ntohs (msg->size) > dc->mtu) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + fh = (const struct FragmentHeader *) msg; + msize = ntohs (fh->total_size); + if (msize < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + fid = ntohl (fh->fragment_id); + foff = ntohs (fh->offset); + if (foff >= msize) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (0 != (foff % (dc->mtu - sizeof (struct FragmentHeader)))) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_STATISTICS_update (dc->stats, _("# fragments received"), 1, GNUNET_NO); + mc = dc->head; + while ((NULL != mc) && (fid != mc->fragment_id)) + mc = mc->next; + bit = foff / (dc->mtu - sizeof (struct FragmentHeader)); + if (bit * (dc->mtu - sizeof (struct FragmentHeader)) + ntohs (msg->size) - + sizeof (struct FragmentHeader) > msize) + { + /* payload extends past total message size */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if ((NULL != mc) && (msize != mc->total_size)) + { + /* inconsistent message size */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + now = GNUNET_TIME_absolute_get (); + if (NULL == mc) + { + mc = GNUNET_malloc (sizeof (struct MessageContext) + msize); + mc->msg = (const struct GNUNET_MessageHeader *) &mc[1]; + mc->dc = dc; + mc->total_size = msize; + mc->fragment_id = fid; + mc->last_update = now; + n = (msize + dc->mtu - sizeof (struct FragmentHeader) - 1) / (dc->mtu - + sizeof (struct + FragmentHeader)); + if (n == 64) + mc->bits = UINT64_MAX; /* set all 64 bit */ + else + mc->bits = (1LL << n) - 1; /* set lowest 'bits' bit */ + if (dc->list_size >= dc->num_msgs) + discard_oldest_mc (dc); + GNUNET_CONTAINER_DLL_insert (dc->head, dc->tail, mc); + dc->list_size++; + } + + /* copy data to 'mc' */ + if (0 != (mc->bits & (1LL << bit))) + { + mc->bits -= 1LL << bit; + mbuf = (char *) &mc[1]; + memcpy (&mbuf[bit * (dc->mtu - sizeof (struct FragmentHeader))], &fh[1], + ntohs (msg->size) - sizeof (struct FragmentHeader)); + mc->last_update = now; + if (bit < mc->last_bit) + mc->frag_times_start_offset = mc->frag_times_write_offset; + mc->last_bit = bit; + mc->frag_times[mc->frag_times_write_offset].time = now; + mc->frag_times[mc->frag_times_write_offset].bit = bit; + mc->frag_times_write_offset++; + duplicate = GNUNET_NO; + } + else + { + duplicate = GNUNET_YES; + GNUNET_STATISTICS_update (dc->stats, _("# duplicate fragments received"), 1, + GNUNET_NO); + } + + /* count number of missing fragments */ + bc = 0; + for (b = 0; b < 64; b++) + if (0 != (mc->bits & (1LL << b))) + bc++; + + /* notify about complete message */ + if ((duplicate == GNUNET_NO) && (0 == mc->bits)) + { + GNUNET_STATISTICS_update (dc->stats, _("# messages defragmented"), 1, + GNUNET_NO); + /* message complete, notify! */ + dc->proc (dc->cls, mc->msg); + } + /* send ACK */ + if (mc->frag_times_write_offset - mc->frag_times_start_offset > 1) + dc->latency = estimate_latency (mc); + delay = GNUNET_TIME_relative_multiply (dc->latency, bc + 1); + if ((0 == mc->bits) || (GNUNET_YES == duplicate)) /* message complete or duplicate, ACK now! */ + { + delay = GNUNET_TIME_UNIT_ZERO; + } + if (GNUNET_SCHEDULER_NO_TASK != mc->ack_task) + GNUNET_SCHEDULER_cancel (mc->ack_task); + mc->ack_task = GNUNET_SCHEDULER_add_delayed (delay, &send_ack, mc); + if (duplicate == GNUNET_YES) + return GNUNET_NO; + return GNUNET_YES; +} + +/* end of defragmentation.c */ diff --git a/src/fragmentation/fragmentation.c b/src/fragmentation/fragmentation.c new file mode 100644 index 0000000..8fab3fe --- /dev/null +++ b/src/fragmentation/fragmentation.c @@ -0,0 +1,405 @@ +/* + This file is part of GNUnet + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file src/fragmentation/fragmentation.c + * @brief library to help fragment messages + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_fragmentation_lib.h" +#include "gnunet_protocols.h" +#include "fragmentation.h" + + +/** + * Fragmentation context. + */ +struct GNUNET_FRAGMENT_Context +{ + /** + * Statistics to use. + */ + struct GNUNET_STATISTICS_Handle *stats; + + /** + * Tracker for flow control. + */ + struct GNUNET_BANDWIDTH_Tracker *tracker; + + /** + * Current expected delay for ACKs. + */ + struct GNUNET_TIME_Relative delay; + + /** + * Next allowed transmission time. + */ + struct GNUNET_TIME_Absolute delay_until; + + /** + * Time we transmitted the last message of the last round. + */ + struct GNUNET_TIME_Absolute last_round; + + /** + * Message to fragment (allocated at the end of this struct). + */ + const struct GNUNET_MessageHeader *msg; + + /** + * Function to call for transmissions. + */ + GNUNET_FRAGMENT_MessageProcessor proc; + + /** + * Closure for 'proc'. + */ + void *proc_cls; + + /** + * Bitfield, set to 1 for each unacknowledged fragment. + */ + uint64_t acks; + + /** + * Bitfield with all possible bits for 'acks' (used to mask the + * ack we get back). + */ + uint64_t acks_mask; + + /** + * Task performing work for the fragmenter. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Our fragmentation ID. (chosen at random) + */ + uint32_t fragment_id; + + /** + * Round-robin selector for the next transmission. + */ + unsigned int next_transmission; + + /** + * How many rounds of transmission have we completed so far? + */ + unsigned int num_rounds; + + /** + * GNUNET_YES if we called 'proc' and are now waiting for 'GNUNET_FRAGMENT_transmission_done' + */ + int8_t proc_busy; + + /** + * GNUNET_YES if we are waiting for an ACK. + */ + int8_t wack; + + /** + * Target fragment size. + */ + uint16_t mtu; + +}; + + +/** + * Transmit the next fragment to the other peer. + * + * @param cls the 'struct GNUNET_FRAGMENT_Context' + * @param tc scheduler context + */ +static void +transmit_next (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FRAGMENT_Context *fc = cls; + char msg[fc->mtu]; + const char *mbuf; + struct FragmentHeader *fh; + struct GNUNET_TIME_Relative delay; + unsigned int bit; + size_t size; + size_t fsize; + int wrap; + + fc->task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (GNUNET_NO == fc->proc_busy); + if (0 == fc->acks) + return; /* all done */ + + /* calculate delay */ + wrap = 0; + while (0 == (fc->acks & (1LL << fc->next_transmission))) + { + fc->next_transmission = (fc->next_transmission + 1) % 64; + wrap |= (fc->next_transmission == 0); + } + bit = fc->next_transmission; + size = ntohs (fc->msg->size); + if (bit == size / (fc->mtu - sizeof (struct FragmentHeader))) + fsize = + (size % (fc->mtu - sizeof (struct FragmentHeader))) + + sizeof (struct FragmentHeader); + else + fsize = fc->mtu; + if (fc->tracker != NULL) + delay = GNUNET_BANDWIDTH_tracker_get_delay (fc->tracker, fsize); + else + delay = GNUNET_TIME_UNIT_ZERO; + if (delay.rel_value > 0) + { + fc->task = GNUNET_SCHEDULER_add_delayed (delay, &transmit_next, fc); + return; + } + fc->next_transmission = (fc->next_transmission + 1) % 64; + wrap |= (fc->next_transmission == 0); + + /* assemble fragmentation message */ + mbuf = (const char *) &fc[1]; + fh = (struct FragmentHeader *) msg; + fh->header.size = htons (fsize); + fh->header.type = htons (GNUNET_MESSAGE_TYPE_FRAGMENT); + fh->fragment_id = htonl (fc->fragment_id); + fh->total_size = fc->msg->size; /* already in big-endian */ + fh->offset = htons ((fc->mtu - sizeof (struct FragmentHeader)) * bit); + memcpy (&fh[1], &mbuf[bit * (fc->mtu - sizeof (struct FragmentHeader))], + fsize - sizeof (struct FragmentHeader)); + if (NULL != fc->tracker) + GNUNET_BANDWIDTH_tracker_consume (fc->tracker, fsize); + GNUNET_STATISTICS_update (fc->stats, _("# fragments transmitted"), 1, + GNUNET_NO); + if (0 != fc->last_round.abs_value) + GNUNET_STATISTICS_update (fc->stats, _("# fragments retransmitted"), 1, + GNUNET_NO); + + /* select next message to calculate delay */ + bit = fc->next_transmission; + size = ntohs (fc->msg->size); + if (bit == size / (fc->mtu - sizeof (struct FragmentHeader))) + fsize = size % (fc->mtu - sizeof (struct FragmentHeader)); + else + fsize = fc->mtu; + if (NULL != fc->tracker) + delay = GNUNET_BANDWIDTH_tracker_get_delay (fc->tracker, fsize); + else + delay = GNUNET_TIME_UNIT_ZERO; + if (wrap) + { + /* full round transmitted wait 2x delay for ACK before going again */ + fc->num_rounds++; + delay = + GNUNET_TIME_relative_max (GNUNET_TIME_relative_multiply (delay, 2), + GNUNET_TIME_relative_multiply (fc->delay, + fc->num_rounds)); + /* never use zero, need some time for ACK always */ + delay = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, delay); + fc->last_round = GNUNET_TIME_absolute_get (); + fc->wack = GNUNET_YES; + } + fc->proc_busy = GNUNET_YES; + fc->delay_until = GNUNET_TIME_relative_to_absolute (delay); + fc->proc (fc->proc_cls, &fh->header); +} + + +/** + * Create a fragmentation context for the given message. + * Fragments the message into fragments of size "mtu" or + * less. Calls 'proc' on each un-acknowledged fragment, + * using both the expected 'delay' between messages and + * acknowledgements and the given 'tracker' to guide the + * frequency of calls to 'proc'. + * + * @param stats statistics context + * @param mtu the maximum message size for each fragment + * @param tracker bandwidth tracker to use for flow control (can be NULL) + * @param delay expected delay between fragment transmission + * and ACK based on previous messages + * @param msg the message to fragment + * @param proc function to call for each fragment to transmit + * @param proc_cls closure for proc + * @return the fragmentation context + */ +struct GNUNET_FRAGMENT_Context * +GNUNET_FRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats, + uint16_t mtu, + struct GNUNET_BANDWIDTH_Tracker *tracker, + struct GNUNET_TIME_Relative delay, + const struct GNUNET_MessageHeader *msg, + GNUNET_FRAGMENT_MessageProcessor proc, + void *proc_cls) +{ + struct GNUNET_FRAGMENT_Context *fc; + size_t size; + uint64_t bits; + + GNUNET_STATISTICS_update (stats, _("# messages fragmented"), 1, GNUNET_NO); + GNUNET_assert (mtu >= 1024 + sizeof (struct FragmentHeader)); + size = ntohs (msg->size); + GNUNET_STATISTICS_update (stats, _("# total size of fragmented messages"), + size, GNUNET_NO); + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + fc = GNUNET_malloc (sizeof (struct GNUNET_FRAGMENT_Context) + size); + fc->stats = stats; + fc->mtu = mtu; + fc->tracker = tracker; + fc->delay = delay; + fc->msg = (const struct GNUNET_MessageHeader *) &fc[1]; + fc->proc = proc; + fc->proc_cls = proc_cls; + fc->fragment_id = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); + memcpy (&fc[1], msg, size); + bits = + (size + mtu - sizeof (struct FragmentHeader) - 1) / (mtu - + sizeof (struct + FragmentHeader)); + GNUNET_assert (bits <= 64); + if (bits == 64) + fc->acks_mask = UINT64_MAX; /* set all 64 bit */ + else + fc->acks_mask = (1LL << bits) - 1; /* set lowest 'bits' bit */ + fc->acks = fc->acks_mask; + fc->task = GNUNET_SCHEDULER_add_now (&transmit_next, fc); + return fc; +} + + +/** + * Continuation to call from the 'proc' function after the fragment + * has been transmitted (and hence the next fragment can now be + * given to proc). + * + * @param fc fragmentation context + */ +void +GNUNET_FRAGMENT_context_transmission_done (struct GNUNET_FRAGMENT_Context *fc) +{ + GNUNET_assert (fc->proc_busy == GNUNET_YES); + fc->proc_busy = GNUNET_NO; + GNUNET_assert (fc->task == GNUNET_SCHEDULER_NO_TASK); + fc->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (fc->delay_until), &transmit_next, fc); +} + + +/** + * Process an acknowledgement message we got from the other + * side (to control re-transmits). + * + * @param fc fragmentation context + * @param msg acknowledgement message we received + * @return GNUNET_OK if this ack completes the work of the 'fc' + * (all fragments have been received); + * GNUNET_NO if more messages are pending + * GNUNET_SYSERR if this ack is not valid for this fc + */ +int +GNUNET_FRAGMENT_process_ack (struct GNUNET_FRAGMENT_Context *fc, + const struct GNUNET_MessageHeader *msg) +{ + const struct FragmentAcknowledgement *fa; + uint64_t abits; + struct GNUNET_TIME_Relative ndelay; + + if (sizeof (struct FragmentAcknowledgement) != ntohs (msg->size)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + fa = (const struct FragmentAcknowledgement *) msg; + if (ntohl (fa->fragment_id) != fc->fragment_id) + return GNUNET_SYSERR; /* not our ACK */ + abits = GNUNET_ntohll (fa->bits); + if ((GNUNET_YES == fc->wack) && (abits == (fc->acks & abits))) + { + /* normal ACK, can update running average of delay... */ + fc->wack = GNUNET_NO; + ndelay = GNUNET_TIME_absolute_get_duration (fc->last_round); + fc->delay.rel_value = + (ndelay.rel_value * fc->num_rounds + 3 * fc->delay.rel_value) / 4; + } + GNUNET_STATISTICS_update (fc->stats, + _("# fragment acknowledgements received"), 1, + GNUNET_NO); + if (abits != (fc->acks & abits)) + { + /* ID collission or message reordering, count! This should be rare! */ + GNUNET_STATISTICS_update (fc->stats, + _("# bits removed from fragmentation ACKs"), 1, + GNUNET_NO); + } + fc->acks = abits & fc->acks_mask; + if (0 != fc->acks) + { + /* more to transmit, do so right now (if tracker permits...) */ + if (fc->task != GNUNET_SCHEDULER_NO_TASK) + { + /* schedule next transmission now, no point in waiting... */ + GNUNET_SCHEDULER_cancel (fc->task); + fc->task = GNUNET_SCHEDULER_add_now (&transmit_next, fc); + } + else + { + /* only case where there is no task should be if we're waiting + * for the right to transmit again (proc_busy set to YES) */ + GNUNET_assert (GNUNET_YES == fc->proc_busy); + } + return GNUNET_NO; + } + + /* all done */ + GNUNET_STATISTICS_update (fc->stats, + _("# fragmentation transmissions completed"), 1, + GNUNET_NO); + if (fc->task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (fc->task); + fc->task = GNUNET_SCHEDULER_NO_TASK; + } + return GNUNET_OK; +} + + +/** + * Destroy the given fragmentation context (stop calling 'proc', free + * resources). + * + * @param fc fragmentation context + * @return average delay between transmission and ACK for the + * last message, FOREVER if the message was not fully transmitted + */ +struct GNUNET_TIME_Relative +GNUNET_FRAGMENT_context_destroy (struct GNUNET_FRAGMENT_Context *fc) +{ + struct GNUNET_TIME_Relative ret; + + if (fc->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (fc->task); + ret = fc->delay; + GNUNET_free (fc); + return ret; +} + + +/* end of fragmentation.c */ diff --git a/src/fragmentation/fragmentation.h b/src/fragmentation/fragmentation.h new file mode 100644 index 0000000..2f3ea67 --- /dev/null +++ b/src/fragmentation/fragmentation.h @@ -0,0 +1,89 @@ +/* + This file is part of GNUnet + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file src/fragmentation/fragmentation.h + * @brief library to help fragment messages + * @author Christian Grothoff + */ +#ifndef FRAGMENTATION_H +#define FRAGMENTATION_H +#include "platform.h" +#include "gnunet_fragmentation_lib.h" + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Header for a message fragment. Followed by the + * original message. + */ +struct FragmentHeader +{ + + /** + * Message header. + */ + struct GNUNET_MessageHeader header; + + /** + * Unique fragment ID. + */ + uint32_t fragment_id; + + /** + * Total message size of the original message. + */ + uint16_t total_size; + + /** + * Absolute offset (in bytes) of this fragment in the original + * message. Will be a multiple of the MTU. + */ + uint16_t offset; + +}; + + +/** + * Message fragment acknowledgement. + */ +struct FragmentAcknowledgement +{ + + /** + * Message header. + */ + struct GNUNET_MessageHeader header; + + /** + * Unique fragment ID. + */ + uint32_t fragment_id; + + /** + * Bits that are being acknowledged, in big-endian. + * (bits that are set correspond to fragments that + * have not yet been received). + */ + uint64_t bits; + +}; +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/fragmentation/test_fragmentation.c b/src/fragmentation/test_fragmentation.c new file mode 100644 index 0000000..c409bf3 --- /dev/null +++ b/src/fragmentation/test_fragmentation.c @@ -0,0 +1,261 @@ +/* + This file is part of GNUnet + (C) 2004, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fragmentation/test_fragmentation.c + * @brief test for fragmentation.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_fragmentation_lib.h" + +#define VERBOSE GNUNET_NO + +#define DETAILS GNUNET_NO + +/** + * Number of messages to transmit (note: each uses ~32k memory!) + */ +#define NUM_MSGS 5000 + +/** + * MTU to force on fragmentation (must be > 1k + 12) + */ +#define MTU 1111 + +/** + * Simulate dropping of 1 out of how many messages? (must be > 1) + */ +#define DROPRATE 10 + +static int ret = 1; + +static unsigned int dups; + +static unsigned int fragc; + +static unsigned int frag_drops; + +static unsigned int acks; + +static unsigned int ack_drops; + +static struct GNUNET_DEFRAGMENT_Context *defrag; + +static struct GNUNET_BANDWIDTH_Tracker trackers[NUM_MSGS]; + +static struct GNUNET_FRAGMENT_Context *frags[NUM_MSGS]; + +static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned int i; + + ret = 0; + shutdown_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_DEFRAGMENT_context_destroy (defrag); + defrag = NULL; + for (i = 0; i < NUM_MSGS; i++) + { + if (frags[i] == NULL) + continue; + GNUNET_FRAGMENT_context_destroy (frags[i]); + frags[i] = NULL; + } +} + + +static void +proc_msgs (void *cls, const struct GNUNET_MessageHeader *hdr) +{ + static unsigned int total; + unsigned int i; + const char *buf; + +#if DETAILS + FPRINTF (stderr, "%s", "!"); /* message complete, good! */ +#endif + buf = (const char *) hdr; + for (i = sizeof (struct GNUNET_MessageHeader); i < ntohs (hdr->size); i++) + GNUNET_assert (buf[i] == (char) i); + total++; +#if ! DETAILS + if (0 == (total % (NUM_MSGS / 100))) + FPRINTF (stderr, "%s", "."); +#endif + /* tolerate 10% loss, i.e. due to duplicate fragment IDs */ + if ((total >= NUM_MSGS - (NUM_MSGS / 10)) && (ret != 0)) + { + if (GNUNET_SCHEDULER_NO_TASK == shutdown_task) + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + } +} + + +/** + * Process ACK (by passing to fragmenter) + */ +static void +proc_acks (void *cls, uint32_t msg_id, const struct GNUNET_MessageHeader *hdr) +{ + unsigned int i; + int ret; + + if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE)) + { + ack_drops++; + return; /* random drop */ + } + for (i = 0; i < NUM_MSGS; i++) + { + if (frags[i] == NULL) + continue; + ret = GNUNET_FRAGMENT_process_ack (frags[i], hdr); + if (ret == GNUNET_OK) + { +#if DETAILS + FPRINTF (stderr, "%s", "@"); /* good ACK */ +#endif + GNUNET_FRAGMENT_context_destroy (frags[i]); + frags[i] = NULL; + acks++; + return; + } + if (ret == GNUNET_NO) + { +#if DETAILS + FPRINTF (stderr, "%s", "@"); /* good ACK */ +#endif + acks++; + return; + } + } +#if DETAILS + FPRINTF (stderr, "%s", "_"); /* BAD: ack that nobody feels responsible for... */ +#endif +} + + +/** + * Process fragment (by passing to defrag). + */ +static void +proc_frac (void *cls, const struct GNUNET_MessageHeader *hdr) +{ + struct GNUNET_FRAGMENT_Context **fc = cls; + int ret; + + GNUNET_FRAGMENT_context_transmission_done (*fc); + if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE)) + { + frag_drops++; + return; /* random drop */ + } + if (NULL == defrag) + { + FPRINTF (stderr, "%s", "E"); /* Error: frag after shutdown!? */ + return; + } + ret = GNUNET_DEFRAGMENT_process_fragment (defrag, hdr); + if (ret == GNUNET_NO) + { +#if DETAILS + FPRINTF (stderr, "%s", "?"); /* duplicate fragment */ +#endif + dups++; + } + else if (ret == GNUNET_OK) + { +#if DETAILS + FPRINTF (stderr, "%s", "."); /* good fragment */ +#endif + fragc++; + } +} + + +/** + * Main function run with scheduler. + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + unsigned int i; + struct GNUNET_MessageHeader *msg; + char buf[MTU + 32 * 1024]; + + defrag = GNUNET_DEFRAGMENT_context_create (NULL, MTU, NUM_MSGS /* enough space for all */ + , NULL, &proc_msgs, &proc_acks); + for (i = 0; i < sizeof (buf); i++) + buf[i] = (char) i; + msg = (struct GNUNET_MessageHeader *) buf; + for (i = 0; i < NUM_MSGS; i++) + { + msg->type = htons ((uint16_t) i); + msg->size = + htons (sizeof (struct GNUNET_MessageHeader) + (17 * i) % (32 * 1024)); + frags[i] = GNUNET_FRAGMENT_context_create (NULL /* no stats */ , + MTU, &trackers[i], + GNUNET_TIME_UNIT_SECONDS, msg, + &proc_frac, &frags[i]); + } +} + + +int +main (int argc, char *argv[]) +{ + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + char *const argv_prog[] = { + "test-fragmentation", + "-c", + "test_fragmentation_data.conf", + "-L", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL + }; + unsigned int i; + + GNUNET_log_setup ("test-fragmentation", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + for (i = 0; i < NUM_MSGS; i++) + GNUNET_BANDWIDTH_tracker_init (&trackers[i], + GNUNET_BANDWIDTH_value_init ((i + 1) * 1024), + 100); + GNUNET_PROGRAM_run (5, argv_prog, "test-fragmentation", "nohelp", options, + &run, NULL); + FPRINTF (stderr, + "\nHad %u good fragments, %u duplicate fragments, %u acks and %u simulated drops of acks\n", + fragc, dups, acks, ack_drops); + return ret; +} diff --git a/src/fragmentation/test_fragmentation_data.conf b/src/fragmentation/test_fragmentation_data.conf new file mode 100644 index 0000000..c236f68 --- /dev/null +++ b/src/fragmentation/test_fragmentation_data.conf @@ -0,0 +1,5 @@ + +[nse] +AUTOSTART = NO + + diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am new file mode 100644 index 0000000..0de739d --- /dev/null +++ b/src/fs/Makefile.am @@ -0,0 +1,466 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + fs.conf + +plugindir = $(libdir)/gnunet + + +lib_LTLIBRARIES = libgnunetfs.la + +plugin_LTLIBRARIES = \ + libgnunet_plugin_block_fs.la + +noinst_LIBRARIES = libgnunetfstest.a + +libgnunetfs_la_SOURCES = \ + fs_api.c fs_api.h fs.h \ + fs_directory.c \ + fs_dirmetascan.c \ + fs_download.c \ + fs_file_information.c \ + fs_getopt.c \ + fs_list_indexed.c \ + fs_publish.c \ + fs_publish_ksk.c \ + fs_misc.c \ + fs_namespace.c \ + fs_namespace_advertise.c \ + fs_search.c \ + fs_sharetree.c \ + fs_tree.c fs_tree.h \ + fs_unindex.c \ + fs_uri.c + +libgnunetfs_la_LIBADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) -lunistring -lextractor + +libgnunetfs_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 2:0:0 + + +libgnunetfstest_a_SOURCES = \ + fs_test_lib.c fs_test_lib.h + +libgnunetfstest_a_LIBADD = \ + $(top_builddir)/src/testing/libgnunettesting.la + +bin_PROGRAMS = \ + gnunet-directory \ + gnunet-download \ + gnunet-publish \ + gnunet-helper-fs-publish \ + gnunet-pseudonym \ + gnunet-search \ + gnunet-service-fs \ + gnunet-fs \ + gnunet-unindex + +bin_SCRIPTS = \ + gnunet-download-manager.scm + +gnunet_directory_SOURCES = \ + gnunet-directory.c +gnunet_directory_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) +gnunet_directory_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_fs_SOURCES = \ + gnunet-fs.c +gnunet_fs_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) +gnunet_fs_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_download_SOURCES = \ + gnunet-download.c +gnunet_download_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_download_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_publish_SOURCES = \ + gnunet-publish.c +gnunet_publish_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) +gnunet_publish_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_helper_fs_publish_SOURCES = \ + gnunet-helper-fs-publish.c +gnunet_helper_fs_publish_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) +gnunet_helper_fs_publish_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_pseudonym_SOURCES = \ + gnunet-pseudonym.c +gnunet_pseudonym_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) +gnunet_pseudonym_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_search_SOURCES = \ + gnunet-search.c +gnunet_search_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) +gnunet_search_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_service_fs_SOURCES = \ + gnunet-service-fs.c gnunet-service-fs.h \ + gnunet-service-fs_cp.c gnunet-service-fs_cp.h \ + gnunet-service-fs_indexing.c gnunet-service-fs_indexing.h \ + gnunet-service-fs_lc.c gnunet-service-fs_lc.h \ + gnunet-service-fs_pe.c gnunet-service-fs_pe.h \ + gnunet-service-fs_pr.c gnunet-service-fs_pr.h \ + gnunet-service-fs_push.c gnunet-service-fs_push.h \ + gnunet-service-fs_put.c gnunet-service-fs_put.h +gnunet_service_fs_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/ats/libgnunetats.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) -lm +gnunet_service_fs_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_unindex_SOURCES = \ + gnunet-unindex.c +gnunet_unindex_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_unindex_DEPENDENCIES = \ + libgnunetfs.la + + +libgnunet_plugin_block_fs_la_SOURCES = \ + plugin_block_fs.c +libgnunet_plugin_block_fs_la_LIBADD = \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_block_fs_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) +libgnunet_plugin_block_fs_la_DEPENDENCIES = \ + $(top_builddir)/src/block/libgnunetblock.la + + + +if HAVE_BENCHMARKS + FS_BENCHMARKS = \ + perf_gnunet_service_fs_p2p \ + perf_gnunet_service_fs_p2p_dht \ + perf_gnunet_service_fs_p2p_index \ + perf_gnunet_service_fs_p2p_trust +endif + +check_PROGRAMS = \ + test_fs_directory \ + test_fs_download \ + test_fs_download_indexed \ + test_fs_download_persistence \ + test_fs_file_information \ + test_fs_getopt \ + test_fs_list_indexed \ + test_fs_namespace \ + test_fs_namespace_list_updateable \ + test_fs_publish \ + test_fs_publish_persistence \ + test_fs_search \ + test_fs_search_persistence \ + test_fs_start_stop \ + test_fs_test_lib \ + test_fs_unindex \ + test_fs_unindex_persistence \ + test_fs_uri \ + test_gnunet_service_fs_migration \ + test_gnunet_service_fs_p2p \ + $(FS_BENCHMARKS) + + +if HAVE_PYTHON_PEXPECT +check_SCRIPTS = \ + test_gnunet_fs_psd.py \ + test_gnunet_fs_rec.py \ + test_gnunet_fs_idx.py \ + test_gnunet_fs_ns.py +endif + + +if ENABLE_TEST_RUN +TESTS = \ + test_fs_directory \ + test_fs_download \ + test_fs_download_indexed \ + test_fs_download_persistence \ + test_fs_file_information \ + test_fs_list_indexed \ + test_fs_namespace \ + test_fs_namespace_list_updateable \ + test_fs_publish \ + test_fs_publish_persistence \ + test_fs_search \ + test_fs_search_persistence \ + test_fs_start_stop \ + test_fs_unindex \ + test_fs_unindex_persistence \ + test_fs_uri \ + test_fs_test_lib \ + test_gnunet_service_fs_migration \ + test_gnunet_service_fs_p2p \ + perf_gnunet_service_fs_p2p \ + perf_gnunet_service_fs_p2p_index \ + perf_gnunet_service_fs_p2p_trust \ + $(check_SCRIPTS) +endif + + + + +test_fs_directory_SOURCES = \ + test_fs_directory.c +test_fs_directory_LDADD = \ + -lextractor \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_download_SOURCES = \ + test_fs_download.c +test_fs_download_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_download_indexed_SOURCES = \ + test_fs_download_indexed.c +test_fs_download_indexed_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_download_persistence_SOURCES = \ + test_fs_download_persistence.c +test_fs_download_persistence_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_file_information_SOURCES = \ + test_fs_file_information.c +test_fs_file_information_LDADD = \ + -lextractor \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_getopt_SOURCES = \ + test_fs_getopt.c +test_fs_getopt_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_list_indexed_SOURCES = \ + test_fs_list_indexed.c +test_fs_list_indexed_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_namespace_SOURCES = \ + test_fs_namespace.c +test_fs_namespace_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_namespace_list_updateable_SOURCES = \ + test_fs_namespace_list_updateable.c +test_fs_namespace_list_updateable_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_publish_SOURCES = \ + test_fs_publish.c +test_fs_publish_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_publish_persistence_SOURCES = \ + test_fs_publish_persistence.c +test_fs_publish_persistence_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_search_SOURCES = \ + test_fs_search.c +test_fs_search_LDADD = $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_search_persistence_SOURCES = \ + test_fs_search_persistence.c +test_fs_search_persistence_LDADD = $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_start_stop_SOURCES = \ + test_fs_start_stop.c +test_fs_start_stop_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_unindex_SOURCES = \ + test_fs_unindex.c +test_fs_unindex_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_unindex_persistence_SOURCES = \ + test_fs_unindex_persistence.c +test_fs_unindex_persistence_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_uri_SOURCES = \ + test_fs_uri.c +test_fs_uri_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_test_lib_SOURCES = \ + test_fs_test_lib.c +test_fs_test_lib_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_service_fs_p2p_SOURCES = \ + test_gnunet_service_fs_p2p.c +test_gnunet_service_fs_p2p_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_service_fs_migration_SOURCES = \ + test_gnunet_service_fs_migration.c +test_gnunet_service_fs_migration_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_gnunet_service_fs_p2p_SOURCES = \ + perf_gnunet_service_fs_p2p.c +perf_gnunet_service_fs_p2p_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_gnunet_service_fs_p2p_index_SOURCES = \ + perf_gnunet_service_fs_p2p.c +perf_gnunet_service_fs_p2p_index_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_gnunet_service_fs_p2p_dht_SOURCES = \ + perf_gnunet_service_fs_p2p.c +perf_gnunet_service_fs_p2p_dht_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_gnunet_service_fs_p2p_trust_SOURCES = \ + perf_gnunet_service_fs_p2p_trust.c +perf_gnunet_service_fs_p2p_trust_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + + +do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' + +test_gnunet_fs_psd.py: test_gnunet_fs_psd.py.in Makefile + $(do_subst) < $(srcdir)/test_gnunet_fs_psd.py.in > test_gnunet_fs_psd.py + chmod +x test_gnunet_fs_psd.py + +test_gnunet_fs_rec.py: test_gnunet_fs_rec.py.in Makefile + $(do_subst) < $(srcdir)/test_gnunet_fs_rec.py.in > test_gnunet_fs_rec.py + chmod +x test_gnunet_fs_rec.py + +test_gnunet_fs_ns.py: test_gnunet_fs_ns.py.in Makefile + $(do_subst) < $(srcdir)/test_gnunet_fs_ns.py.in > test_gnunet_fs_ns.py + chmod +x test_gnunet_fs_ns.py + +test_gnunet_fs_idx.py: test_gnunet_fs_idx.py.in Makefile + $(do_subst) < $(srcdir)/test_gnunet_fs_idx.py.in > test_gnunet_fs_idx.py + chmod +x test_gnunet_fs_idx.py + + +EXTRA_DIST = \ + test_fs_defaults.conf \ + fs_test_lib_data.conf \ + test_fs_data.conf \ + test_fs_download_data.conf \ + test_fs_file_information_data.conf \ + fs_test_lib_data.conf \ + test_fs_list_indexed_data.conf \ + test_fs_namespace_data.conf \ + test_fs_publish_data.conf \ + test_fs_search_data.conf \ + test_fs_unindex_data.conf \ + test_fs_uri_data.conf \ + test_gnunet_service_fs_migration_data.conf \ + test_gnunet_fs_idx_data.conf \ + test_gnunet_fs_ns_data.conf \ + test_gnunet_fs_psd_data.conf \ + test_gnunet_fs_rec_data.conf \ + test_gnunet_fs_rec_data.tgz \ + test_gnunet_fs_psd.py.in \ + test_gnunet_fs_rec.py.in \ + test_gnunet_fs_ns.py.in \ + test_gnunet_fs_idx.py.in \ + $(bin_SCRIPTS) + +CLEANFILES = $(check_SCRIPTS) diff --git a/src/fs/Makefile.in b/src/fs/Makefile.in new file mode 100644 index 0000000..cbc844e --- /dev/null +++ b/src/fs/Makefile.in @@ -0,0 +1,1788 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-directory$(EXEEXT) gnunet-download$(EXEEXT) \ + gnunet-publish$(EXEEXT) gnunet-helper-fs-publish$(EXEEXT) \ + gnunet-pseudonym$(EXEEXT) gnunet-search$(EXEEXT) \ + gnunet-service-fs$(EXEEXT) gnunet-fs$(EXEEXT) \ + gnunet-unindex$(EXEEXT) +check_PROGRAMS = test_fs_directory$(EXEEXT) test_fs_download$(EXEEXT) \ + test_fs_download_indexed$(EXEEXT) \ + test_fs_download_persistence$(EXEEXT) \ + test_fs_file_information$(EXEEXT) test_fs_getopt$(EXEEXT) \ + test_fs_list_indexed$(EXEEXT) test_fs_namespace$(EXEEXT) \ + test_fs_namespace_list_updateable$(EXEEXT) \ + test_fs_publish$(EXEEXT) test_fs_publish_persistence$(EXEEXT) \ + test_fs_search$(EXEEXT) test_fs_search_persistence$(EXEEXT) \ + test_fs_start_stop$(EXEEXT) test_fs_test_lib$(EXEEXT) \ + test_fs_unindex$(EXEEXT) test_fs_unindex_persistence$(EXEEXT) \ + test_fs_uri$(EXEEXT) test_gnunet_service_fs_migration$(EXEEXT) \ + test_gnunet_service_fs_p2p$(EXEEXT) $(am__EXEEXT_1) +@ENABLE_TEST_RUN_TRUE@TESTS = test_fs_directory$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_download$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_download_indexed$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_download_persistence$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_file_information$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_list_indexed$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_namespace$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_namespace_list_updateable$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_publish$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_publish_persistence$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_search$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_search_persistence$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_start_stop$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_unindex$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_unindex_persistence$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_uri$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_fs_test_lib$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_gnunet_service_fs_migration$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_gnunet_service_fs_p2p$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ perf_gnunet_service_fs_p2p$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ perf_gnunet_service_fs_p2p_index$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ perf_gnunet_service_fs_p2p_trust$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ $(check_SCRIPTS) +subdir = src/fs +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/fs.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = fs.conf +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_$(V)) +am__v_AR_ = $(am__v_AR_$(AM_DEFAULT_VERBOSITY)) +am__v_AR_0 = @echo " AR " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +libgnunetfstest_a_AR = $(AR) $(ARFLAGS) +libgnunetfstest_a_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la +am_libgnunetfstest_a_OBJECTS = fs_test_lib.$(OBJEXT) +libgnunetfstest_a_OBJECTS = $(am_libgnunetfstest_a_OBJECTS) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) +am_libgnunet_plugin_block_fs_la_OBJECTS = plugin_block_fs.lo +libgnunet_plugin_block_fs_la_OBJECTS = \ + $(am_libgnunet_plugin_block_fs_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_block_fs_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunet_plugin_block_fs_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__DEPENDENCIES_1 = +libgnunetfs_la_DEPENDENCIES = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgnunetfs_la_OBJECTS = fs_api.lo fs_directory.lo \ + fs_dirmetascan.lo fs_download.lo fs_file_information.lo \ + fs_getopt.lo fs_list_indexed.lo fs_publish.lo \ + fs_publish_ksk.lo fs_misc.lo fs_namespace.lo \ + fs_namespace_advertise.lo fs_search.lo fs_sharetree.lo \ + fs_tree.lo fs_unindex.lo fs_uri.lo +libgnunetfs_la_OBJECTS = $(am_libgnunetfs_la_OBJECTS) +libgnunetfs_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetfs_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +@HAVE_BENCHMARKS_TRUE@am__EXEEXT_1 = \ +@HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p$(EXEEXT) \ +@HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_dht$(EXEEXT) \ +@HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_index$(EXEEXT) \ +@HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_trust$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_directory_OBJECTS = gnunet-directory.$(OBJEXT) +gnunet_directory_OBJECTS = $(am_gnunet_directory_OBJECTS) +am_gnunet_download_OBJECTS = gnunet-download.$(OBJEXT) +gnunet_download_OBJECTS = $(am_gnunet_download_OBJECTS) +am_gnunet_fs_OBJECTS = gnunet-fs.$(OBJEXT) +gnunet_fs_OBJECTS = $(am_gnunet_fs_OBJECTS) +am_gnunet_helper_fs_publish_OBJECTS = \ + gnunet-helper-fs-publish.$(OBJEXT) +gnunet_helper_fs_publish_OBJECTS = \ + $(am_gnunet_helper_fs_publish_OBJECTS) +am_gnunet_pseudonym_OBJECTS = gnunet-pseudonym.$(OBJEXT) +gnunet_pseudonym_OBJECTS = $(am_gnunet_pseudonym_OBJECTS) +am_gnunet_publish_OBJECTS = gnunet-publish.$(OBJEXT) +gnunet_publish_OBJECTS = $(am_gnunet_publish_OBJECTS) +am_gnunet_search_OBJECTS = gnunet-search.$(OBJEXT) +gnunet_search_OBJECTS = $(am_gnunet_search_OBJECTS) +am_gnunet_service_fs_OBJECTS = gnunet-service-fs.$(OBJEXT) \ + gnunet-service-fs_cp.$(OBJEXT) \ + gnunet-service-fs_indexing.$(OBJEXT) \ + gnunet-service-fs_lc.$(OBJEXT) gnunet-service-fs_pe.$(OBJEXT) \ + gnunet-service-fs_pr.$(OBJEXT) \ + gnunet-service-fs_push.$(OBJEXT) \ + gnunet-service-fs_put.$(OBJEXT) +gnunet_service_fs_OBJECTS = $(am_gnunet_service_fs_OBJECTS) +am_gnunet_unindex_OBJECTS = gnunet-unindex.$(OBJEXT) +gnunet_unindex_OBJECTS = $(am_gnunet_unindex_OBJECTS) +am_perf_gnunet_service_fs_p2p_OBJECTS = \ + perf_gnunet_service_fs_p2p.$(OBJEXT) +perf_gnunet_service_fs_p2p_OBJECTS = \ + $(am_perf_gnunet_service_fs_p2p_OBJECTS) +perf_gnunet_service_fs_p2p_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_gnunet_service_fs_p2p_dht_OBJECTS = \ + perf_gnunet_service_fs_p2p.$(OBJEXT) +perf_gnunet_service_fs_p2p_dht_OBJECTS = \ + $(am_perf_gnunet_service_fs_p2p_dht_OBJECTS) +perf_gnunet_service_fs_p2p_dht_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_gnunet_service_fs_p2p_index_OBJECTS = \ + perf_gnunet_service_fs_p2p.$(OBJEXT) +perf_gnunet_service_fs_p2p_index_OBJECTS = \ + $(am_perf_gnunet_service_fs_p2p_index_OBJECTS) +perf_gnunet_service_fs_p2p_index_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_gnunet_service_fs_p2p_trust_OBJECTS = \ + perf_gnunet_service_fs_p2p_trust.$(OBJEXT) +perf_gnunet_service_fs_p2p_trust_OBJECTS = \ + $(am_perf_gnunet_service_fs_p2p_trust_OBJECTS) +perf_gnunet_service_fs_p2p_trust_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_directory_OBJECTS = test_fs_directory.$(OBJEXT) +test_fs_directory_OBJECTS = $(am_test_fs_directory_OBJECTS) +test_fs_directory_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_download_OBJECTS = test_fs_download.$(OBJEXT) +test_fs_download_OBJECTS = $(am_test_fs_download_OBJECTS) +test_fs_download_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_download_indexed_OBJECTS = \ + test_fs_download_indexed.$(OBJEXT) +test_fs_download_indexed_OBJECTS = \ + $(am_test_fs_download_indexed_OBJECTS) +test_fs_download_indexed_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_download_persistence_OBJECTS = \ + test_fs_download_persistence.$(OBJEXT) +test_fs_download_persistence_OBJECTS = \ + $(am_test_fs_download_persistence_OBJECTS) +test_fs_download_persistence_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_file_information_OBJECTS = \ + test_fs_file_information.$(OBJEXT) +test_fs_file_information_OBJECTS = \ + $(am_test_fs_file_information_OBJECTS) +test_fs_file_information_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_getopt_OBJECTS = test_fs_getopt.$(OBJEXT) +test_fs_getopt_OBJECTS = $(am_test_fs_getopt_OBJECTS) +test_fs_getopt_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_list_indexed_OBJECTS = test_fs_list_indexed.$(OBJEXT) +test_fs_list_indexed_OBJECTS = $(am_test_fs_list_indexed_OBJECTS) +test_fs_list_indexed_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_namespace_OBJECTS = test_fs_namespace.$(OBJEXT) +test_fs_namespace_OBJECTS = $(am_test_fs_namespace_OBJECTS) +test_fs_namespace_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_namespace_list_updateable_OBJECTS = \ + test_fs_namespace_list_updateable.$(OBJEXT) +test_fs_namespace_list_updateable_OBJECTS = \ + $(am_test_fs_namespace_list_updateable_OBJECTS) +test_fs_namespace_list_updateable_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_publish_OBJECTS = test_fs_publish.$(OBJEXT) +test_fs_publish_OBJECTS = $(am_test_fs_publish_OBJECTS) +test_fs_publish_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_publish_persistence_OBJECTS = \ + test_fs_publish_persistence.$(OBJEXT) +test_fs_publish_persistence_OBJECTS = \ + $(am_test_fs_publish_persistence_OBJECTS) +test_fs_publish_persistence_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_search_OBJECTS = test_fs_search.$(OBJEXT) +test_fs_search_OBJECTS = $(am_test_fs_search_OBJECTS) +test_fs_search_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_search_persistence_OBJECTS = \ + test_fs_search_persistence.$(OBJEXT) +test_fs_search_persistence_OBJECTS = \ + $(am_test_fs_search_persistence_OBJECTS) +test_fs_search_persistence_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_start_stop_OBJECTS = test_fs_start_stop.$(OBJEXT) +test_fs_start_stop_OBJECTS = $(am_test_fs_start_stop_OBJECTS) +test_fs_start_stop_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_test_lib_OBJECTS = test_fs_test_lib.$(OBJEXT) +test_fs_test_lib_OBJECTS = $(am_test_fs_test_lib_OBJECTS) +test_fs_test_lib_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_unindex_OBJECTS = test_fs_unindex.$(OBJEXT) +test_fs_unindex_OBJECTS = $(am_test_fs_unindex_OBJECTS) +test_fs_unindex_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_unindex_persistence_OBJECTS = \ + test_fs_unindex_persistence.$(OBJEXT) +test_fs_unindex_persistence_OBJECTS = \ + $(am_test_fs_unindex_persistence_OBJECTS) +test_fs_unindex_persistence_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_fs_uri_OBJECTS = test_fs_uri.$(OBJEXT) +test_fs_uri_OBJECTS = $(am_test_fs_uri_OBJECTS) +test_fs_uri_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_gnunet_service_fs_migration_OBJECTS = \ + test_gnunet_service_fs_migration.$(OBJEXT) +test_gnunet_service_fs_migration_OBJECTS = \ + $(am_test_gnunet_service_fs_migration_OBJECTS) +test_gnunet_service_fs_migration_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_gnunet_service_fs_p2p_OBJECTS = \ + test_gnunet_service_fs_p2p.$(OBJEXT) +test_gnunet_service_fs_p2p_OBJECTS = \ + $(am_test_gnunet_service_fs_p2p_OBJECTS) +test_gnunet_service_fs_p2p_DEPENDENCIES = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la +SCRIPTS = $(bin_SCRIPTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetfstest_a_SOURCES) \ + $(libgnunet_plugin_block_fs_la_SOURCES) \ + $(libgnunetfs_la_SOURCES) $(gnunet_directory_SOURCES) \ + $(gnunet_download_SOURCES) $(gnunet_fs_SOURCES) \ + $(gnunet_helper_fs_publish_SOURCES) \ + $(gnunet_pseudonym_SOURCES) $(gnunet_publish_SOURCES) \ + $(gnunet_search_SOURCES) $(gnunet_service_fs_SOURCES) \ + $(gnunet_unindex_SOURCES) \ + $(perf_gnunet_service_fs_p2p_SOURCES) \ + $(perf_gnunet_service_fs_p2p_dht_SOURCES) \ + $(perf_gnunet_service_fs_p2p_index_SOURCES) \ + $(perf_gnunet_service_fs_p2p_trust_SOURCES) \ + $(test_fs_directory_SOURCES) $(test_fs_download_SOURCES) \ + $(test_fs_download_indexed_SOURCES) \ + $(test_fs_download_persistence_SOURCES) \ + $(test_fs_file_information_SOURCES) $(test_fs_getopt_SOURCES) \ + $(test_fs_list_indexed_SOURCES) $(test_fs_namespace_SOURCES) \ + $(test_fs_namespace_list_updateable_SOURCES) \ + $(test_fs_publish_SOURCES) \ + $(test_fs_publish_persistence_SOURCES) \ + $(test_fs_search_SOURCES) \ + $(test_fs_search_persistence_SOURCES) \ + $(test_fs_start_stop_SOURCES) $(test_fs_test_lib_SOURCES) \ + $(test_fs_unindex_SOURCES) \ + $(test_fs_unindex_persistence_SOURCES) $(test_fs_uri_SOURCES) \ + $(test_gnunet_service_fs_migration_SOURCES) \ + $(test_gnunet_service_fs_p2p_SOURCES) +DIST_SOURCES = $(libgnunetfstest_a_SOURCES) \ + $(libgnunet_plugin_block_fs_la_SOURCES) \ + $(libgnunetfs_la_SOURCES) $(gnunet_directory_SOURCES) \ + $(gnunet_download_SOURCES) $(gnunet_fs_SOURCES) \ + $(gnunet_helper_fs_publish_SOURCES) \ + $(gnunet_pseudonym_SOURCES) $(gnunet_publish_SOURCES) \ + $(gnunet_search_SOURCES) $(gnunet_service_fs_SOURCES) \ + $(gnunet_unindex_SOURCES) \ + $(perf_gnunet_service_fs_p2p_SOURCES) \ + $(perf_gnunet_service_fs_p2p_dht_SOURCES) \ + $(perf_gnunet_service_fs_p2p_index_SOURCES) \ + $(perf_gnunet_service_fs_p2p_trust_SOURCES) \ + $(test_fs_directory_SOURCES) $(test_fs_download_SOURCES) \ + $(test_fs_download_indexed_SOURCES) \ + $(test_fs_download_persistence_SOURCES) \ + $(test_fs_file_information_SOURCES) $(test_fs_getopt_SOURCES) \ + $(test_fs_list_indexed_SOURCES) $(test_fs_namespace_SOURCES) \ + $(test_fs_namespace_list_updateable_SOURCES) \ + $(test_fs_publish_SOURCES) \ + $(test_fs_publish_persistence_SOURCES) \ + $(test_fs_search_SOURCES) \ + $(test_fs_search_persistence_SOURCES) \ + $(test_fs_start_stop_SOURCES) $(test_fs_test_lib_SOURCES) \ + $(test_fs_unindex_SOURCES) \ + $(test_fs_unindex_persistence_SOURCES) $(test_fs_uri_SOURCES) \ + $(test_gnunet_service_fs_migration_SOURCES) \ + $(test_gnunet_service_fs_p2p_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + fs.conf + +plugindir = $(libdir)/gnunet +lib_LTLIBRARIES = libgnunetfs.la +plugin_LTLIBRARIES = \ + libgnunet_plugin_block_fs.la + +noinst_LIBRARIES = libgnunetfstest.a +libgnunetfs_la_SOURCES = \ + fs_api.c fs_api.h fs.h \ + fs_directory.c \ + fs_dirmetascan.c \ + fs_download.c \ + fs_file_information.c \ + fs_getopt.c \ + fs_list_indexed.c \ + fs_publish.c \ + fs_publish_ksk.c \ + fs_misc.c \ + fs_namespace.c \ + fs_namespace_advertise.c \ + fs_search.c \ + fs_sharetree.c \ + fs_tree.c fs_tree.h \ + fs_unindex.c \ + fs_uri.c + +libgnunetfs_la_LIBADD = \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) -lunistring -lextractor + +libgnunetfs_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 2:0:0 + +libgnunetfstest_a_SOURCES = \ + fs_test_lib.c fs_test_lib.h + +libgnunetfstest_a_LIBADD = \ + $(top_builddir)/src/testing/libgnunettesting.la + +bin_SCRIPTS = \ + gnunet-download-manager.scm + +gnunet_directory_SOURCES = \ + gnunet-directory.c + +gnunet_directory_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) + +gnunet_directory_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_fs_SOURCES = \ + gnunet-fs.c + +gnunet_fs_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) + +gnunet_fs_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_download_SOURCES = \ + gnunet-download.c + +gnunet_download_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_download_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_publish_SOURCES = \ + gnunet-publish.c + +gnunet_publish_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) + +gnunet_publish_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_helper_fs_publish_SOURCES = \ + gnunet-helper-fs-publish.c + +gnunet_helper_fs_publish_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) + +gnunet_helper_fs_publish_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_pseudonym_SOURCES = \ + gnunet-pseudonym.c + +gnunet_pseudonym_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) + +gnunet_pseudonym_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_search_SOURCES = \ + gnunet-search.c + +gnunet_search_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + -lextractor \ + $(GN_LIBINTL) + +gnunet_search_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_service_fs_SOURCES = \ + gnunet-service-fs.c gnunet-service-fs.h \ + gnunet-service-fs_cp.c gnunet-service-fs_cp.h \ + gnunet-service-fs_indexing.c gnunet-service-fs_indexing.h \ + gnunet-service-fs_lc.c gnunet-service-fs_lc.h \ + gnunet-service-fs_pe.c gnunet-service-fs_pe.h \ + gnunet-service-fs_pr.c gnunet-service-fs_pr.h \ + gnunet-service-fs_push.c gnunet-service-fs_push.h \ + gnunet-service-fs_put.c gnunet-service-fs_put.h + +gnunet_service_fs_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/datastore/libgnunetdatastore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/ats/libgnunetats.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) -lm + +gnunet_service_fs_DEPENDENCIES = \ + libgnunetfs.la + +gnunet_unindex_SOURCES = \ + gnunet-unindex.c + +gnunet_unindex_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_unindex_DEPENDENCIES = \ + libgnunetfs.la + +libgnunet_plugin_block_fs_la_SOURCES = \ + plugin_block_fs.c + +libgnunet_plugin_block_fs_la_LIBADD = \ + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_block_fs_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_block_fs_la_DEPENDENCIES = \ + $(top_builddir)/src/block/libgnunetblock.la + +@HAVE_BENCHMARKS_TRUE@FS_BENCHMARKS = \ +@HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p \ +@HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_dht \ +@HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_index \ +@HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_trust + +@HAVE_PYTHON_PEXPECT_TRUE@check_SCRIPTS = \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_gnunet_fs_psd.py \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_gnunet_fs_rec.py \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_gnunet_fs_idx.py \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_gnunet_fs_ns.py + +test_fs_directory_SOURCES = \ + test_fs_directory.c + +test_fs_directory_LDADD = \ + -lextractor \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_download_SOURCES = \ + test_fs_download.c + +test_fs_download_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_download_indexed_SOURCES = \ + test_fs_download_indexed.c + +test_fs_download_indexed_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_download_persistence_SOURCES = \ + test_fs_download_persistence.c + +test_fs_download_persistence_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_file_information_SOURCES = \ + test_fs_file_information.c + +test_fs_file_information_LDADD = \ + -lextractor \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_getopt_SOURCES = \ + test_fs_getopt.c + +test_fs_getopt_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_list_indexed_SOURCES = \ + test_fs_list_indexed.c + +test_fs_list_indexed_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_namespace_SOURCES = \ + test_fs_namespace.c + +test_fs_namespace_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_namespace_list_updateable_SOURCES = \ + test_fs_namespace_list_updateable.c + +test_fs_namespace_list_updateable_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_publish_SOURCES = \ + test_fs_publish.c + +test_fs_publish_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_publish_persistence_SOURCES = \ + test_fs_publish_persistence.c + +test_fs_publish_persistence_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_search_SOURCES = \ + test_fs_search.c + +test_fs_search_LDADD = $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_search_persistence_SOURCES = \ + test_fs_search_persistence.c + +test_fs_search_persistence_LDADD = $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_start_stop_SOURCES = \ + test_fs_start_stop.c + +test_fs_start_stop_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_unindex_SOURCES = \ + test_fs_unindex.c + +test_fs_unindex_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_unindex_persistence_SOURCES = \ + test_fs_unindex_persistence.c + +test_fs_unindex_persistence_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_uri_SOURCES = \ + test_fs_uri.c + +test_fs_uri_LDADD = \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_fs_test_lib_SOURCES = \ + test_fs_test_lib.c + +test_fs_test_lib_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_service_fs_p2p_SOURCES = \ + test_gnunet_service_fs_p2p.c + +test_gnunet_service_fs_p2p_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_service_fs_migration_SOURCES = \ + test_gnunet_service_fs_migration.c + +test_gnunet_service_fs_migration_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_gnunet_service_fs_p2p_SOURCES = \ + perf_gnunet_service_fs_p2p.c + +perf_gnunet_service_fs_p2p_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_gnunet_service_fs_p2p_index_SOURCES = \ + perf_gnunet_service_fs_p2p.c + +perf_gnunet_service_fs_p2p_index_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_gnunet_service_fs_p2p_dht_SOURCES = \ + perf_gnunet_service_fs_p2p.c + +perf_gnunet_service_fs_p2p_dht_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_gnunet_service_fs_p2p_trust_SOURCES = \ + perf_gnunet_service_fs_p2p_trust.c + +perf_gnunet_service_fs_p2p_trust_LDADD = \ + $(top_builddir)/src/fs/libgnunetfstest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + +do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' +EXTRA_DIST = \ + test_fs_defaults.conf \ + fs_test_lib_data.conf \ + test_fs_data.conf \ + test_fs_download_data.conf \ + test_fs_file_information_data.conf \ + fs_test_lib_data.conf \ + test_fs_list_indexed_data.conf \ + test_fs_namespace_data.conf \ + test_fs_publish_data.conf \ + test_fs_search_data.conf \ + test_fs_unindex_data.conf \ + test_fs_uri_data.conf \ + test_gnunet_service_fs_migration_data.conf \ + test_gnunet_fs_idx_data.conf \ + test_gnunet_fs_ns_data.conf \ + test_gnunet_fs_psd_data.conf \ + test_gnunet_fs_rec_data.conf \ + test_gnunet_fs_rec_data.tgz \ + test_gnunet_fs_psd.py.in \ + test_gnunet_fs_rec.py.in \ + test_gnunet_fs_ns.py.in \ + test_gnunet_fs_idx.py.in \ + $(bin_SCRIPTS) + +CLEANFILES = $(check_SCRIPTS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/fs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/fs/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +fs.conf: $(top_builddir)/config.status $(srcdir)/fs.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libgnunetfstest.a: $(libgnunetfstest_a_OBJECTS) $(libgnunetfstest_a_DEPENDENCIES) + $(AM_V_at)-rm -f libgnunetfstest.a + $(AM_V_AR)$(libgnunetfstest_a_AR) libgnunetfstest.a $(libgnunetfstest_a_OBJECTS) $(libgnunetfstest_a_LIBADD) + $(AM_V_at)$(RANLIB) libgnunetfstest.a +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_block_fs.la: $(libgnunet_plugin_block_fs_la_OBJECTS) $(libgnunet_plugin_block_fs_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_block_fs_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_fs_la_OBJECTS) $(libgnunet_plugin_block_fs_la_LIBADD) $(LIBS) +libgnunetfs.la: $(libgnunetfs_la_OBJECTS) $(libgnunetfs_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetfs_la_LINK) -rpath $(libdir) $(libgnunetfs_la_OBJECTS) $(libgnunetfs_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-directory$(EXEEXT): $(gnunet_directory_OBJECTS) $(gnunet_directory_DEPENDENCIES) + @rm -f gnunet-directory$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_directory_OBJECTS) $(gnunet_directory_LDADD) $(LIBS) +gnunet-download$(EXEEXT): $(gnunet_download_OBJECTS) $(gnunet_download_DEPENDENCIES) + @rm -f gnunet-download$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_download_OBJECTS) $(gnunet_download_LDADD) $(LIBS) +gnunet-fs$(EXEEXT): $(gnunet_fs_OBJECTS) $(gnunet_fs_DEPENDENCIES) + @rm -f gnunet-fs$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_fs_OBJECTS) $(gnunet_fs_LDADD) $(LIBS) +gnunet-helper-fs-publish$(EXEEXT): $(gnunet_helper_fs_publish_OBJECTS) $(gnunet_helper_fs_publish_DEPENDENCIES) + @rm -f gnunet-helper-fs-publish$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_helper_fs_publish_OBJECTS) $(gnunet_helper_fs_publish_LDADD) $(LIBS) +gnunet-pseudonym$(EXEEXT): $(gnunet_pseudonym_OBJECTS) $(gnunet_pseudonym_DEPENDENCIES) + @rm -f gnunet-pseudonym$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_pseudonym_OBJECTS) $(gnunet_pseudonym_LDADD) $(LIBS) +gnunet-publish$(EXEEXT): $(gnunet_publish_OBJECTS) $(gnunet_publish_DEPENDENCIES) + @rm -f gnunet-publish$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_publish_OBJECTS) $(gnunet_publish_LDADD) $(LIBS) +gnunet-search$(EXEEXT): $(gnunet_search_OBJECTS) $(gnunet_search_DEPENDENCIES) + @rm -f gnunet-search$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_search_OBJECTS) $(gnunet_search_LDADD) $(LIBS) +gnunet-service-fs$(EXEEXT): $(gnunet_service_fs_OBJECTS) $(gnunet_service_fs_DEPENDENCIES) + @rm -f gnunet-service-fs$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_fs_OBJECTS) $(gnunet_service_fs_LDADD) $(LIBS) +gnunet-unindex$(EXEEXT): $(gnunet_unindex_OBJECTS) $(gnunet_unindex_DEPENDENCIES) + @rm -f gnunet-unindex$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_unindex_OBJECTS) $(gnunet_unindex_LDADD) $(LIBS) +perf_gnunet_service_fs_p2p$(EXEEXT): $(perf_gnunet_service_fs_p2p_OBJECTS) $(perf_gnunet_service_fs_p2p_DEPENDENCIES) + @rm -f perf_gnunet_service_fs_p2p$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_gnunet_service_fs_p2p_OBJECTS) $(perf_gnunet_service_fs_p2p_LDADD) $(LIBS) +perf_gnunet_service_fs_p2p_dht$(EXEEXT): $(perf_gnunet_service_fs_p2p_dht_OBJECTS) $(perf_gnunet_service_fs_p2p_dht_DEPENDENCIES) + @rm -f perf_gnunet_service_fs_p2p_dht$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_gnunet_service_fs_p2p_dht_OBJECTS) $(perf_gnunet_service_fs_p2p_dht_LDADD) $(LIBS) +perf_gnunet_service_fs_p2p_index$(EXEEXT): $(perf_gnunet_service_fs_p2p_index_OBJECTS) $(perf_gnunet_service_fs_p2p_index_DEPENDENCIES) + @rm -f perf_gnunet_service_fs_p2p_index$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_gnunet_service_fs_p2p_index_OBJECTS) $(perf_gnunet_service_fs_p2p_index_LDADD) $(LIBS) +perf_gnunet_service_fs_p2p_trust$(EXEEXT): $(perf_gnunet_service_fs_p2p_trust_OBJECTS) $(perf_gnunet_service_fs_p2p_trust_DEPENDENCIES) + @rm -f perf_gnunet_service_fs_p2p_trust$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_gnunet_service_fs_p2p_trust_OBJECTS) $(perf_gnunet_service_fs_p2p_trust_LDADD) $(LIBS) +test_fs_directory$(EXEEXT): $(test_fs_directory_OBJECTS) $(test_fs_directory_DEPENDENCIES) + @rm -f test_fs_directory$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_directory_OBJECTS) $(test_fs_directory_LDADD) $(LIBS) +test_fs_download$(EXEEXT): $(test_fs_download_OBJECTS) $(test_fs_download_DEPENDENCIES) + @rm -f test_fs_download$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_download_OBJECTS) $(test_fs_download_LDADD) $(LIBS) +test_fs_download_indexed$(EXEEXT): $(test_fs_download_indexed_OBJECTS) $(test_fs_download_indexed_DEPENDENCIES) + @rm -f test_fs_download_indexed$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_download_indexed_OBJECTS) $(test_fs_download_indexed_LDADD) $(LIBS) +test_fs_download_persistence$(EXEEXT): $(test_fs_download_persistence_OBJECTS) $(test_fs_download_persistence_DEPENDENCIES) + @rm -f test_fs_download_persistence$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_download_persistence_OBJECTS) $(test_fs_download_persistence_LDADD) $(LIBS) +test_fs_file_information$(EXEEXT): $(test_fs_file_information_OBJECTS) $(test_fs_file_information_DEPENDENCIES) + @rm -f test_fs_file_information$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_file_information_OBJECTS) $(test_fs_file_information_LDADD) $(LIBS) +test_fs_getopt$(EXEEXT): $(test_fs_getopt_OBJECTS) $(test_fs_getopt_DEPENDENCIES) + @rm -f test_fs_getopt$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_getopt_OBJECTS) $(test_fs_getopt_LDADD) $(LIBS) +test_fs_list_indexed$(EXEEXT): $(test_fs_list_indexed_OBJECTS) $(test_fs_list_indexed_DEPENDENCIES) + @rm -f test_fs_list_indexed$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_list_indexed_OBJECTS) $(test_fs_list_indexed_LDADD) $(LIBS) +test_fs_namespace$(EXEEXT): $(test_fs_namespace_OBJECTS) $(test_fs_namespace_DEPENDENCIES) + @rm -f test_fs_namespace$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_namespace_OBJECTS) $(test_fs_namespace_LDADD) $(LIBS) +test_fs_namespace_list_updateable$(EXEEXT): $(test_fs_namespace_list_updateable_OBJECTS) $(test_fs_namespace_list_updateable_DEPENDENCIES) + @rm -f test_fs_namespace_list_updateable$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_namespace_list_updateable_OBJECTS) $(test_fs_namespace_list_updateable_LDADD) $(LIBS) +test_fs_publish$(EXEEXT): $(test_fs_publish_OBJECTS) $(test_fs_publish_DEPENDENCIES) + @rm -f test_fs_publish$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_publish_OBJECTS) $(test_fs_publish_LDADD) $(LIBS) +test_fs_publish_persistence$(EXEEXT): $(test_fs_publish_persistence_OBJECTS) $(test_fs_publish_persistence_DEPENDENCIES) + @rm -f test_fs_publish_persistence$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_publish_persistence_OBJECTS) $(test_fs_publish_persistence_LDADD) $(LIBS) +test_fs_search$(EXEEXT): $(test_fs_search_OBJECTS) $(test_fs_search_DEPENDENCIES) + @rm -f test_fs_search$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_search_OBJECTS) $(test_fs_search_LDADD) $(LIBS) +test_fs_search_persistence$(EXEEXT): $(test_fs_search_persistence_OBJECTS) $(test_fs_search_persistence_DEPENDENCIES) + @rm -f test_fs_search_persistence$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_search_persistence_OBJECTS) $(test_fs_search_persistence_LDADD) $(LIBS) +test_fs_start_stop$(EXEEXT): $(test_fs_start_stop_OBJECTS) $(test_fs_start_stop_DEPENDENCIES) + @rm -f test_fs_start_stop$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_start_stop_OBJECTS) $(test_fs_start_stop_LDADD) $(LIBS) +test_fs_test_lib$(EXEEXT): $(test_fs_test_lib_OBJECTS) $(test_fs_test_lib_DEPENDENCIES) + @rm -f test_fs_test_lib$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_test_lib_OBJECTS) $(test_fs_test_lib_LDADD) $(LIBS) +test_fs_unindex$(EXEEXT): $(test_fs_unindex_OBJECTS) $(test_fs_unindex_DEPENDENCIES) + @rm -f test_fs_unindex$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_unindex_OBJECTS) $(test_fs_unindex_LDADD) $(LIBS) +test_fs_unindex_persistence$(EXEEXT): $(test_fs_unindex_persistence_OBJECTS) $(test_fs_unindex_persistence_DEPENDENCIES) + @rm -f test_fs_unindex_persistence$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_unindex_persistence_OBJECTS) $(test_fs_unindex_persistence_LDADD) $(LIBS) +test_fs_uri$(EXEEXT): $(test_fs_uri_OBJECTS) $(test_fs_uri_DEPENDENCIES) + @rm -f test_fs_uri$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_fs_uri_OBJECTS) $(test_fs_uri_LDADD) $(LIBS) +test_gnunet_service_fs_migration$(EXEEXT): $(test_gnunet_service_fs_migration_OBJECTS) $(test_gnunet_service_fs_migration_DEPENDENCIES) + @rm -f test_gnunet_service_fs_migration$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_service_fs_migration_OBJECTS) $(test_gnunet_service_fs_migration_LDADD) $(LIBS) +test_gnunet_service_fs_p2p$(EXEEXT): $(test_gnunet_service_fs_p2p_OBJECTS) $(test_gnunet_service_fs_p2p_DEPENDENCIES) + @rm -f test_gnunet_service_fs_p2p$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_service_fs_p2p_OBJECTS) $(test_gnunet_service_fs_p2p_LDADD) $(LIBS) +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_directory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_dirmetascan.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_download.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_file_information.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_getopt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_list_indexed.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_misc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_namespace.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_namespace_advertise.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_publish.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_publish_ksk.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_search.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_sharetree.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_test_lib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_tree.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_unindex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_uri.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-directory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-download.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-fs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-fs-publish.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-pseudonym.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-publish.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-search.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_cp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_indexing.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_lc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_pe.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_pr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_push.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_put.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-unindex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_gnunet_service_fs_p2p.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_gnunet_service_fs_p2p_trust.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_fs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_directory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_download.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_download_indexed.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_download_persistence.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_file_information.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_getopt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_list_indexed.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_namespace.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_namespace_list_updateable.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_publish.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_publish_persistence.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_search.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_search_persistence.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_start_stop.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_test_lib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_unindex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_unindex_persistence.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_uri.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_service_fs_migration.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_service_fs_p2p.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) \ + $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstLIBRARIES \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-binSCRIPTS \ + install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-libLTLIBRARIES uninstall-pkgcfgDATA \ + uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstLIBRARIES \ + clean-pluginLTLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-binSCRIPTS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-pkgcfgDATA install-pluginLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-binSCRIPTS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + + +test_gnunet_fs_psd.py: test_gnunet_fs_psd.py.in Makefile + $(do_subst) < $(srcdir)/test_gnunet_fs_psd.py.in > test_gnunet_fs_psd.py + chmod +x test_gnunet_fs_psd.py + +test_gnunet_fs_rec.py: test_gnunet_fs_rec.py.in Makefile + $(do_subst) < $(srcdir)/test_gnunet_fs_rec.py.in > test_gnunet_fs_rec.py + chmod +x test_gnunet_fs_rec.py + +test_gnunet_fs_ns.py: test_gnunet_fs_ns.py.in Makefile + $(do_subst) < $(srcdir)/test_gnunet_fs_ns.py.in > test_gnunet_fs_ns.py + chmod +x test_gnunet_fs_ns.py + +test_gnunet_fs_idx.py: test_gnunet_fs_idx.py.in Makefile + $(do_subst) < $(srcdir)/test_gnunet_fs_idx.py.in > test_gnunet_fs_idx.py + chmod +x test_gnunet_fs_idx.py + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/fs/fs.conf.in b/src/fs/fs.conf.in new file mode 100644 index 0000000..48c8b52 --- /dev/null +++ b/src/fs/fs.conf.in @@ -0,0 +1,32 @@ +[fs] +AUTOSTART = YES +INDEXDB = $SERVICEHOME/idxinfo.lst +TRUST = $SERVICEHOME/data/credit/ +IDENTITY_DIR = $SERVICEHOME/identities/ +STATE_DIR = $SERVICEHOME/persistence/ +UPDATE_DIR = $SERVICEHOME/updates/ +@UNIXONLY@ PORT = 2094 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-fs +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; + +DELAY = YES +CONTENT_CACHING = YES +CONTENT_PUSHING = YES + +UNIXPATH = /tmp/gnunet-service-fs.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +# DISABLE_SOCKET_FORWARDING = NO +# DEBUG = YES +MAX_PENDING_REQUESTS = 65536 +# Maximum frequency we're allowed to poll the datastore +# for content for migration (can be used to reduce +# GNUnet's disk-IO rate) +MIN_MIGRATION_DELAY = 100 ms +EXPECTED_NEIGHBOUR_COUNT = 128 + + diff --git a/src/fs/fs.h b/src/fs/fs.h new file mode 100644 index 0000000..059b892 --- /dev/null +++ b/src/fs/fs.h @@ -0,0 +1,332 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs.h + * @brief definitions for the entire fs module + * @author Igor Wronsky, Christian Grothoff + */ +#ifndef FS_H +#define FS_H + +#include "gnunet_constants.h" +#include "gnunet_datastore_service.h" +#include "gnunet_dht_service.h" +#include "gnunet_fs_service.h" +#include "gnunet_block_lib.h" +#include "block_fs.h" + + +/** + * Size of the individual blocks used for file-sharing. + */ +#define DBLOCK_SIZE (32*1024) + +/** + * Blocksize to use when hashing files for indexing (blocksize for IO, + * not for the DBlocks). Larger blocksizes can be more efficient but + * will be more disruptive as far as the scheduler is concerned. + */ +#define HASHING_BLOCKSIZE (1024 * 128) + + +/** + * @brief content hash key + */ +struct ContentHashKey +{ + /** + * Hash of the original content, used for encryption. + */ + GNUNET_HashCode key; + + /** + * Hash of the encrypted content, used for querying. + */ + GNUNET_HashCode query; +}; + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message sent from a GNUnet (fs) publishing activity to the + * gnunet-fs-service to initiate indexing of a file. The service is + * supposed to check if the specified file is available and has the + * same cryptographic hash. It should then respond with either a + * confirmation or a denial. + * + * On OSes where this works, it is considered acceptable if the + * service only checks that the path, device and inode match (it can + * then be assumed that the hash will also match without actually + * computing it; this is an optimization that should be safe given + * that the client is not our adversary). + */ +struct IndexStartMessage +{ + + /** + * Message type will be GNUNET_MESSAGE_TYPE_FS_INDEX_START. + */ + struct GNUNET_MessageHeader header; + + /** + * For alignment. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * ID of device containing the file, as seen by the client. This + * device ID is obtained using a call like "statvfs" (and converting + * the "f_fsid" field to a 32-bit big-endian number). Use 0 if the + * OS does not support this, in which case the service must do a + * full hash recomputation. + */ + uint64_t device GNUNET_PACKED; + + /** + * Inode of the file on the given device, as seen by the client + * ("st_ino" field from "struct stat"). Use 0 if the OS does not + * support this, in which case the service must do a full hash + * recomputation. + */ + uint64_t inode GNUNET_PACKED; + + /** + * Hash of the file that we would like to index. + */ + GNUNET_HashCode file_id; + + /* this is followed by a 0-terminated + * filename of a file with the hash + * "file_id" as seen by the client */ + +}; + + +/** + * Message send by FS service in response to a request + * asking for a list of all indexed files. + */ +struct IndexInfoMessage +{ + /** + * Message type will be + * GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY. + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Hash of the indexed file. + */ + GNUNET_HashCode file_id; + + /* this is followed by a 0-terminated + * filename of a file with the hash + * "file_id" as seen by the client */ + +}; + + +/** + * Message sent from a GNUnet (fs) unindexing activity to the + * gnunet-service-fs to indicate that a file will be unindexed. The + * service is supposed to remove the file from the list of indexed + * files and response with a confirmation message (even if the file + * was already not on the list). + */ +struct UnindexMessage +{ + + /** + * Message type will be + * GNUNET_MESSAGE_TYPE_FS_UNINDEX. + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Hash of the file that we will unindex. + */ + GNUNET_HashCode file_id; + +}; + + +/** + * No options. + */ +#define SEARCH_MESSAGE_OPTION_NONE 0 + +/** + * Only search the local datastore (no network) + */ +#define SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY 1 + +/** + * Request is too large to fit in 64k format. The list of + * already-known search results will be continued in another message + * for the same type/query/target and additional already-known results + * following this one). + */ +#define SEARCH_MESSAGE_OPTION_CONTINUED 2 + + +/** + * Message sent from a GNUnet (fs) search activity to the + * gnunet-service-fs to start a search. + */ +struct SearchMessage +{ + + /** + * Message type will be + * GNUNET_MESSAGE_TYPE_FS_START_SEARCH. + */ + struct GNUNET_MessageHeader header; + + /** + * Bitmask with options. Zero for no options, one for + * loopback-only, two for 'to be continued' (with a second search + * message for the same type/query/target and additional + * already-known results following this one). See + * SEARCH_MESSAGE_OPTION_ defines. + * + * Other bits are currently not defined. + */ + uint32_t options GNUNET_PACKED; + + /** + * Type of the content that we're looking for. + */ + uint32_t type GNUNET_PACKED; + + /** + * Desired anonymity level, big-endian. + */ + uint32_t anonymity_level GNUNET_PACKED; + + /** + * If the request is for a DBLOCK or IBLOCK, this is the identity of + * the peer that is known to have a response. Set to all-zeros if + * such a target is not known (note that even if OUR anonymity + * level is >0 we may happen to know the responder's identity; + * nevertheless, we should probably not use it for a DHT-lookup + * or similar blunt actions in order to avoid exposing ourselves). + *

+ * If the request is for an SBLOCK, this is the identity of the + * pseudonym to which the SBLOCK belongs. + *

+ * If the request is for a KBLOCK, "target" must be all zeros. + */ + GNUNET_HashCode target; + + /** + * Hash of the keyword (aka query) for KBLOCKs; Hash of + * the CHK-encoded block for DBLOCKS and IBLOCKS (aka query) + * and hash of the identifier XORed with the target for + * SBLOCKS (aka query). + */ + GNUNET_HashCode query; + + /* this is followed by the hash codes of already-known + * results (which should hence be excluded from what + * the service returns); naturally, this only applies + * to queries that can have multiple results, such as + * those for KBLOCKS (KSK) and SBLOCKS (SKS) */ +}; + + +/** + * Response from FS service with a result for a previous FS search. + * Note that queries for DBLOCKS and IBLOCKS that have received a + * single response are considered done. This message is transmitted + * between peers. + */ +struct PutMessage +{ + + /** + * Message type will be GNUNET_MESSAGE_TYPE_FS_PUT. + */ + struct GNUNET_MessageHeader header; + + /** + * Type of the block (in big endian). Should never be zero. + */ + uint32_t type GNUNET_PACKED; + + /** + * When does this result expire? + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /* this is followed by the actual encrypted content */ + +}; + +/** + * Response from FS service with a result for a previous FS search. + * Note that queries for DBLOCKS and IBLOCKS that have received a + * single response are considered done. This message is transmitted + * between the service and a client. + */ +struct ClientPutMessage +{ + + /** + * Message type will be GNUNET_MESSAGE_TYPE_FS_PUT. + */ + struct GNUNET_MessageHeader header; + + /** + * Type of the block (in big endian). Should never be zero. + */ + uint32_t type GNUNET_PACKED; + + /** + * When does this result expire? + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /** + * When was the last time we've tried to download this block? + * (FOREVER if unknown/not relevant) + */ + struct GNUNET_TIME_AbsoluteNBO last_transmission; + + /* this is followed by the actual encrypted content */ + +}; +GNUNET_NETWORK_STRUCT_END + + +#endif + +/* end of fs.h */ diff --git a/src/fs/fs_api.c b/src/fs/fs_api.c new file mode 100644 index 0000000..1df9b2e --- /dev/null +++ b/src/fs/fs_api.c @@ -0,0 +1,2824 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_api.c + * @brief main FS functions (master initialization, serialization, deserialization, shared code) + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" +#include "fs_tree.h" + + +/** + * Start the given job (send signal, remove from pending queue, update + * counters and state). + * + * @param qe job to start + */ +static void +start_job (struct GNUNET_FS_QueueEntry *qe) +{ + GNUNET_assert (NULL == qe->client); + qe->client = GNUNET_CLIENT_connect ("fs", qe->h->cfg); + if (qe->client == NULL) + { + GNUNET_break (0); + return; + } + qe->start (qe->cls, qe->client); + qe->start_times++; + qe->h->active_blocks += qe->blocks; + qe->start_time = GNUNET_TIME_absolute_get (); + GNUNET_CONTAINER_DLL_remove (qe->h->pending_head, qe->h->pending_tail, qe); + GNUNET_CONTAINER_DLL_insert_after (qe->h->running_head, qe->h->running_tail, + qe->h->running_tail, qe); +} + + +/** + * Stop the given job (send signal, remove from active queue, update + * counters and state). + * + * @param qe job to stop + */ +static void +stop_job (struct GNUNET_FS_QueueEntry *qe) +{ + qe->client = NULL; + qe->stop (qe->cls); + qe->h->active_downloads--; + qe->h->active_blocks -= qe->blocks; + qe->run_time = + GNUNET_TIME_relative_add (qe->run_time, + GNUNET_TIME_absolute_get_duration + (qe->start_time)); + GNUNET_CONTAINER_DLL_remove (qe->h->running_head, qe->h->running_tail, qe); + GNUNET_CONTAINER_DLL_insert_after (qe->h->pending_head, qe->h->pending_tail, + qe->h->pending_tail, qe); +} + + +/** + * Process the jobs in the job queue, possibly starting some + * and stopping others. + * + * @param cls the 'struct GNUNET_FS_Handle' + * @param tc scheduler context + */ +static void +process_job_queue (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_Handle *h = cls; + struct GNUNET_FS_QueueEntry *qe; + struct GNUNET_FS_QueueEntry *next; + struct GNUNET_TIME_Relative run_time; + struct GNUNET_TIME_Relative restart_at; + struct GNUNET_TIME_Relative rst; + struct GNUNET_TIME_Absolute end_time; + + h->queue_job = GNUNET_SCHEDULER_NO_TASK; + next = h->pending_head; + while (NULL != (qe = next)) + { + next = qe->next; + if (h->running_head == NULL) + { + start_job (qe); + continue; + } + if ((qe->blocks + h->active_blocks <= h->max_parallel_requests) && + (h->active_downloads + 1 <= h->max_parallel_downloads)) + { + start_job (qe); + continue; + } + } + if (h->pending_head == NULL) + return; /* no need to stop anything */ + restart_at = GNUNET_TIME_UNIT_FOREVER_REL; + next = h->running_head; + while (NULL != (qe = next)) + { + next = qe->next; + run_time = + GNUNET_TIME_relative_multiply (h->avg_block_latency, + qe->blocks * qe->start_times); + end_time = GNUNET_TIME_absolute_add (qe->start_time, run_time); + rst = GNUNET_TIME_absolute_get_remaining (end_time); + restart_at = GNUNET_TIME_relative_min (rst, restart_at); + if (rst.rel_value > 0) + continue; + stop_job (qe); + } + h->queue_job = + GNUNET_SCHEDULER_add_delayed (restart_at, &process_job_queue, h); +} + + +/** + * Add a job to the queue. + * + * @param h handle to the overall FS state + * @param start function to call to begin the job + * @param stop function to call to pause the job, or on dequeue (if the job was running) + * @param cls closure for start and stop + * @param blocks number of blocks this jobs uses + * @return queue handle + */ +struct GNUNET_FS_QueueEntry * +GNUNET_FS_queue_ (struct GNUNET_FS_Handle *h, GNUNET_FS_QueueStart start, + GNUNET_FS_QueueStop stop, void *cls, unsigned int blocks) +{ + struct GNUNET_FS_QueueEntry *qe; + + qe = GNUNET_malloc (sizeof (struct GNUNET_FS_QueueEntry)); + qe->h = h; + qe->start = start; + qe->stop = stop; + qe->cls = cls; + qe->queue_time = GNUNET_TIME_absolute_get (); + qe->blocks = blocks; + GNUNET_CONTAINER_DLL_insert_after (h->pending_head, h->pending_tail, + h->pending_tail, qe); + if (h->queue_job != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (h->queue_job); + h->queue_job = GNUNET_SCHEDULER_add_now (&process_job_queue, h); + return qe; +} + + +/** + * Dequeue a job from the queue. + * @param qh handle for the job + */ +void +GNUNET_FS_dequeue_ (struct GNUNET_FS_QueueEntry *qh) +{ + struct GNUNET_FS_Handle *h; + + h = qh->h; + if (qh->client != NULL) + stop_job (qh); + GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, qh); + GNUNET_free (qh); + if (h->queue_job != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (h->queue_job); + h->queue_job = GNUNET_SCHEDULER_add_now (&process_job_queue, h); +} + + +/** + * Create a top-level activity entry. + * + * @param h global fs handle + * @param ssf suspend signal function to use + * @param ssf_cls closure for ssf + * @return fresh top-level activity handle + */ +struct TopLevelActivity * +GNUNET_FS_make_top (struct GNUNET_FS_Handle *h, SuspendSignalFunction ssf, + void *ssf_cls) +{ + struct TopLevelActivity *ret; + + ret = GNUNET_malloc (sizeof (struct TopLevelActivity)); + ret->ssf = ssf; + ret->ssf_cls = ssf_cls; + GNUNET_CONTAINER_DLL_insert (h->top_head, h->top_tail, ret); + return ret; +} + + +/** + * Destroy a top-level activity entry. + * + * @param h global fs handle + * @param top top level activity entry + */ +void +GNUNET_FS_end_top (struct GNUNET_FS_Handle *h, struct TopLevelActivity *top) +{ + GNUNET_CONTAINER_DLL_remove (h->top_head, h->top_tail, top); + GNUNET_free (top); +} + + + +/** + * Closure for "data_reader_file". + */ +struct FileInfo +{ + /** + * Name of the file to read. + */ + char *filename; + + /** + * File descriptor, NULL if it has not yet been opened. + */ + struct GNUNET_DISK_FileHandle *fd; +}; + + +/** + * Function that provides data by reading from a file. + * + * @param cls closure (points to the file information) + * @param offset offset to read from; it is possible + * that the caller might need to go backwards + * a bit at times + * @param max maximum number of bytes that should be + * copied to buf; readers are not allowed + * to provide less data unless there is an error; + * a value of "0" will be used at the end to allow + * the reader to clean up its internal state + * @param buf where the reader should write the data + * @param emsg location for the reader to store an error message + * @return number of bytes written, usually "max", 0 on error + */ +size_t +GNUNET_FS_data_reader_file_ (void *cls, uint64_t offset, size_t max, void *buf, + char **emsg) +{ + struct FileInfo *fi = cls; + ssize_t ret; + + if (max == 0) + { + if (fi->fd != NULL) + GNUNET_DISK_file_close (fi->fd); + GNUNET_free (fi->filename); + GNUNET_free (fi); + return 0; + } + if (fi->fd == NULL) + { + fi->fd = + GNUNET_DISK_file_open (fi->filename, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (fi->fd == NULL) + { + GNUNET_asprintf (emsg, _("Could not open file `%s': %s"), fi->filename, + STRERROR (errno)); + return 0; + } + } + GNUNET_DISK_file_seek (fi->fd, offset, GNUNET_DISK_SEEK_SET); + ret = GNUNET_DISK_file_read (fi->fd, buf, max); + if (ret == -1) + { + GNUNET_asprintf (emsg, _("Could not read file `%s': %s"), fi->filename, + STRERROR (errno)); + return 0; + } + if (ret != max) + { + GNUNET_asprintf (emsg, _("Short read reading from file `%s'!"), + fi->filename); + return 0; + } + return max; +} + + +/** + * Create the closure for the 'GNUNET_FS_data_reader_file_' callback. + * + * @param filename file to read + * @return closure to use, NULL on error + */ +void * +GNUNET_FS_make_file_reader_context_ (const char *filename) +{ + struct FileInfo *fi; + + fi = GNUNET_malloc (sizeof (struct FileInfo)); + fi->filename = GNUNET_STRINGS_filename_expand (filename); + if (fi->filename == NULL) + { + GNUNET_free (fi); + return NULL; + } + return fi; +} + + +/** + * Function that provides data by copying from a buffer. + * + * @param cls closure (points to the buffer) + * @param offset offset to read from; it is possible + * that the caller might need to go backwards + * a bit at times + * @param max maximum number of bytes that should be + * copied to buf; readers are not allowed + * to provide less data unless there is an error; + * a value of "0" will be used at the end to allow + * the reader to clean up its internal state + * @param buf where the reader should write the data + * @param emsg location for the reader to store an error message + * @return number of bytes written, usually "max", 0 on error + */ +size_t +GNUNET_FS_data_reader_copy_ (void *cls, uint64_t offset, size_t max, void *buf, + char **emsg) +{ + char *data = cls; + + if (max == 0) + { + GNUNET_free_non_null (data); + return 0; + } + memcpy (buf, &data[offset], max); + return max; +} + + +/** + * Return the full filename where we would store state information + * (for serialization/deserialization). + * + * @param h master context + * @param ext component of the path + * @param ent entity identifier (or emtpy string for the directory) + * @return NULL on error + */ +static char * +get_serialization_file_name (struct GNUNET_FS_Handle *h, const char *ext, + const char *ent) +{ + char *basename; + char *ret; + + if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) + return NULL; /* persistence not requested */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (h->cfg, "fs", "STATE_DIR", + &basename)) + return NULL; + GNUNET_asprintf (&ret, "%s%s%s%s%s%s%s", basename, DIR_SEPARATOR_STR, + h->client_name, DIR_SEPARATOR_STR, ext, DIR_SEPARATOR_STR, + ent); + GNUNET_free (basename); + return ret; +} + + +/** + * Return the full filename where we would store state information + * (for serialization/deserialization) that is associated with a + * parent operation. + * + * @param h master context + * @param ext component of the path + * @param uni name of the parent operation + * @param ent entity identifier (or emtpy string for the directory) + * @return NULL on error + */ +static char * +get_serialization_file_name_in_dir (struct GNUNET_FS_Handle *h, const char *ext, + const char *uni, const char *ent) +{ + char *basename; + char *ret; + + if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) + return NULL; /* persistence not requested */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (h->cfg, "fs", "STATE_DIR", + &basename)) + return NULL; + GNUNET_asprintf (&ret, "%s%s%s%s%s%s%s.dir%s%s", basename, DIR_SEPARATOR_STR, + h->client_name, DIR_SEPARATOR_STR, ext, DIR_SEPARATOR_STR, + uni, DIR_SEPARATOR_STR, ent); + GNUNET_free (basename); + return ret; +} + + +/** + * Return a read handle for deserialization. + * + * @param h master context + * @param ext component of the path + * @param ent entity identifier (or emtpy string for the directory) + * @return NULL on error + */ +static struct GNUNET_BIO_ReadHandle * +get_read_handle (struct GNUNET_FS_Handle *h, const char *ext, const char *ent) +{ + char *fn; + struct GNUNET_BIO_ReadHandle *ret; + + fn = get_serialization_file_name (h, ext, ent); + if (fn == NULL) + return NULL; + ret = GNUNET_BIO_read_open (fn); + GNUNET_free (fn); + return ret; +} + + +/** + * Return a write handle for serialization. + * + * @param h master context + * @param ext component of the path + * @param ent entity identifier (or emtpy string for the directory) + * @return NULL on error + */ +static struct GNUNET_BIO_WriteHandle * +get_write_handle (struct GNUNET_FS_Handle *h, const char *ext, const char *ent) +{ + char *fn; + struct GNUNET_BIO_WriteHandle *ret; + + fn = get_serialization_file_name (h, ext, ent); + if (fn == NULL) + { + return NULL; + } + ret = GNUNET_BIO_write_open (fn); + if (ret == NULL) + GNUNET_break (0); + GNUNET_free (fn); + return ret; +} + + +/** + * Return a write handle for serialization. + * + * @param h master context + * @param ext component of the path + * @param uni name of parent + * @param ent entity identifier (or emtpy string for the directory) + * @return NULL on error + */ +static struct GNUNET_BIO_WriteHandle * +get_write_handle_in_dir (struct GNUNET_FS_Handle *h, const char *ext, + const char *uni, const char *ent) +{ + char *fn; + struct GNUNET_BIO_WriteHandle *ret; + + fn = get_serialization_file_name_in_dir (h, ext, uni, ent); + if (fn == NULL) + return NULL; + ret = GNUNET_BIO_write_open (fn); + GNUNET_free (fn); + return ret; +} + + +/** + * Remove serialization/deserialization file from disk. + * + * @param h master context + * @param ext component of the path + * @param ent entity identifier + */ +void +GNUNET_FS_remove_sync_file_ (struct GNUNET_FS_Handle *h, const char *ext, + const char *ent) +{ + char *filename; + + if ((NULL == ent) || (0 == strlen (ent))) + { + GNUNET_break (0); + return; + } + filename = get_serialization_file_name (h, ext, ent); + if (filename != NULL) + { + if (0 != UNLINK (filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); + GNUNET_free (filename); + } +} + + +/** + * Remove serialization/deserialization file from disk. + * + * @param h master context + * @param ext component of the path + * @param uni parent name + * @param ent entity identifier + */ +static void +remove_sync_file_in_dir (struct GNUNET_FS_Handle *h, const char *ext, + const char *uni, const char *ent) +{ + char *filename; + + if ((NULL == ent) || (0 == strlen (ent))) + { + GNUNET_break (0); + return; + } + filename = get_serialization_file_name_in_dir (h, ext, uni, ent); + if (filename != NULL) + { + if (0 != UNLINK (filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); + GNUNET_free (filename); + } +} + + +/** + * Remove serialization/deserialization directory from disk. + * + * @param h master context + * @param ext component of the path + * @param uni unique name of parent + */ +void +GNUNET_FS_remove_sync_dir_ (struct GNUNET_FS_Handle *h, const char *ext, + const char *uni) +{ + char *dn; + + if (uni == NULL) + return; + dn = get_serialization_file_name_in_dir (h, ext, uni, ""); + if (dn == NULL) + return; + if ((GNUNET_OK == GNUNET_DISK_directory_test (dn)) && + (GNUNET_OK != GNUNET_DISK_directory_remove (dn))) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dn); + GNUNET_free (dn); +} + + +/** + * Serialize a 'start_time'. Since we use start-times to + * calculate the duration of some operation, we actually + * do not serialize the absolute time but the (relative) + * duration since the start time. When we then + * deserialize the start time, we take the current time and + * subtract that duration so that we get again an absolute + * time stamp that will result in correct performance + * calculations. + * + * @param wh handle for writing + * @param timestamp time to serialize + * @return GNUNET_OK on success + */ +static int +write_start_time (struct GNUNET_BIO_WriteHandle *wh, + struct GNUNET_TIME_Absolute timestamp) +{ + struct GNUNET_TIME_Relative dur; + + dur = GNUNET_TIME_absolute_get_duration (timestamp); + return GNUNET_BIO_write_int64 (wh, dur.rel_value); +} + + +/** + * Serialize a 'start_time'. Since we use start-times to + * calculate the duration of some operation, we actually + * do not serialize the absolute time but the (relative) + * duration since the start time. When we then + * deserialize the start time, we take the current time and + * subtract that duration so that we get again an absolute + * time stamp that will result in correct performance + * calculations. + * + * @param rh handle for reading + * @param timestamp where to write the deserialized timestamp + * @return GNUNET_OK on success + */ +static int +read_start_time (struct GNUNET_BIO_ReadHandle *rh, + struct GNUNET_TIME_Absolute *timestamp) +{ + struct GNUNET_TIME_Relative dur; + + if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dur.rel_value)) + return GNUNET_SYSERR; + *timestamp = GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (), dur); + return GNUNET_OK; +} + + +/** + * Using the given serialization filename, try to deserialize + * the file-information tree associated with it. + * + * @param h master context + * @param filename name of the file (without directory) with + * the infromation + * @return NULL on error + */ +static struct GNUNET_FS_FileInformation * +deserialize_file_information (struct GNUNET_FS_Handle *h, const char *filename); + + +/** + * Using the given serialization filename, try to deserialize + * the file-information tree associated with it. + * + * @param h master context + * @param fn name of the file (without directory) with + * the infromation + * @param rh handle for reading + * @return NULL on error + */ +static struct GNUNET_FS_FileInformation * +deserialize_fi_node (struct GNUNET_FS_Handle *h, const char *fn, + struct GNUNET_BIO_ReadHandle *rh) +{ + struct GNUNET_FS_FileInformation *ret; + struct GNUNET_FS_FileInformation *nxt; + char b; + char *ksks; + char *chks; + char *filename; + uint32_t dsize; + + if (GNUNET_OK != GNUNET_BIO_read (rh, "status flag", &b, sizeof (b))) + { + GNUNET_break (0); + return NULL; + } + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation)); + ret->h = h; + ksks = NULL; + chks = NULL; + filename = NULL; + if ((GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "metadata", &ret->meta)) || + (GNUNET_OK != GNUNET_BIO_read_string (rh, "ksk-uri", &ksks, 32 * 1024)) || + ( (NULL != ksks) && + ( (NULL == (ret->keywords = GNUNET_FS_uri_parse (ksks, NULL))) || + (GNUNET_YES != GNUNET_FS_uri_test_ksk (ret->keywords)) ) ) || + (GNUNET_OK != GNUNET_BIO_read_string (rh, "chk-uri", &chks, 1024)) || + ( (NULL != chks) && + ( (NULL == (ret->chk_uri = GNUNET_FS_uri_parse (chks, NULL))) || + (GNUNET_YES != GNUNET_FS_uri_test_chk (ret->chk_uri))) ) || + (GNUNET_OK != read_start_time (rh, &ret->start_time)) || + (GNUNET_OK != GNUNET_BIO_read_string (rh, "emsg", &ret->emsg, 16 * 1024)) + || (GNUNET_OK != + GNUNET_BIO_read_string (rh, "fn", &ret->filename, 16 * 1024)) || + (GNUNET_OK != + GNUNET_BIO_read_int64 (rh, &ret->bo.expiration_time.abs_value)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &ret->bo.anonymity_level)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &ret->bo.content_priority)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &ret->bo.replication_level))) + { + GNUNET_break (0); + goto cleanup; + } + switch (b) + { + case 0: /* file-insert */ + if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size)) + { + GNUNET_break (0); + goto cleanup; + } + ret->is_directory = GNUNET_NO; + ret->data.file.do_index = GNUNET_NO; + ret->data.file.have_hash = GNUNET_NO; + ret->data.file.index_start_confirmed = GNUNET_NO; + if (GNUNET_NO == ret->is_published) + { + if (NULL == ret->filename) + { + ret->data.file.reader = &GNUNET_FS_data_reader_copy_; + ret->data.file.reader_cls = + GNUNET_malloc_large (ret->data.file.file_size); + if (ret->data.file.reader_cls == NULL) + goto cleanup; + if (GNUNET_OK != + GNUNET_BIO_read (rh, "file-data", ret->data.file.reader_cls, + ret->data.file.file_size)) + { + GNUNET_break (0); + goto cleanup; + } + } + else + { + ret->data.file.reader = &GNUNET_FS_data_reader_file_; + ret->data.file.reader_cls = + GNUNET_FS_make_file_reader_context_ (ret->filename); + } + } + break; + case 1: /* file-index, no hash */ + if (NULL == ret->filename) + { + GNUNET_break (0); + goto cleanup; + } + if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size)) + { + GNUNET_break (0); + goto cleanup; + } + ret->is_directory = GNUNET_NO; + ret->data.file.do_index = GNUNET_YES; + ret->data.file.have_hash = GNUNET_NO; + ret->data.file.index_start_confirmed = GNUNET_NO; + ret->data.file.reader = &GNUNET_FS_data_reader_file_; + ret->data.file.reader_cls = + GNUNET_FS_make_file_reader_context_ (ret->filename); + break; + case 2: /* file-index-with-hash */ + if (NULL == ret->filename) + { + GNUNET_break (0); + goto cleanup; + } + if ((GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size)) || + (GNUNET_OK != + GNUNET_BIO_read (rh, "fileid", &ret->data.file.file_id, + sizeof (GNUNET_HashCode)))) + { + GNUNET_break (0); + goto cleanup; + } + ret->is_directory = GNUNET_NO; + ret->data.file.do_index = GNUNET_YES; + ret->data.file.have_hash = GNUNET_YES; + ret->data.file.index_start_confirmed = GNUNET_NO; + ret->data.file.reader = &GNUNET_FS_data_reader_file_; + ret->data.file.reader_cls = + GNUNET_FS_make_file_reader_context_ (ret->filename); + break; + case 3: /* file-index-with-hash-confirmed */ + if (NULL == ret->filename) + { + GNUNET_break (0); + goto cleanup; + } + if ((GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size)) || + (GNUNET_OK != + GNUNET_BIO_read (rh, "fileid", &ret->data.file.file_id, + sizeof (GNUNET_HashCode)))) + { + GNUNET_break (0); + goto cleanup; + } + ret->is_directory = GNUNET_NO; + ret->data.file.do_index = GNUNET_YES; + ret->data.file.have_hash = GNUNET_YES; + ret->data.file.index_start_confirmed = GNUNET_YES; + ret->data.file.reader = &GNUNET_FS_data_reader_file_; + ret->data.file.reader_cls = + GNUNET_FS_make_file_reader_context_ (ret->filename); + break; + case 4: /* directory */ + ret->is_directory = GNUNET_YES; + if ((GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dsize)) || + (NULL == (ret->data.dir.dir_data = GNUNET_malloc_large (dsize))) || + (GNUNET_OK != + GNUNET_BIO_read (rh, "dir-data", ret->data.dir.dir_data, dsize)) || + (GNUNET_OK != + GNUNET_BIO_read_string (rh, "ent-filename", &filename, 16 * 1024))) + { + GNUNET_break (0); + goto cleanup; + } + ret->data.dir.dir_size = (uint32_t) dsize; + if (filename != NULL) + { + ret->data.dir.entries = deserialize_file_information (h, filename); + GNUNET_free (filename); + filename = NULL; + nxt = ret->data.dir.entries; + while (nxt != NULL) + { + nxt->dir = ret; + nxt = nxt->next; + } + } + break; + default: + GNUNET_break (0); + goto cleanup; + } + ret->serialization = GNUNET_strdup (fn); + if (GNUNET_OK != + GNUNET_BIO_read_string (rh, "nxt-filename", &filename, 16 * 1024)) + { + GNUNET_break (0); + goto cleanup; + } + if (filename != NULL) + { + ret->next = deserialize_file_information (h, filename); + GNUNET_free (filename); + filename = NULL; + } + GNUNET_free_non_null (ksks); + GNUNET_free_non_null (chks); + return ret; +cleanup: + GNUNET_free_non_null (ksks); + GNUNET_free_non_null (chks); + GNUNET_free_non_null (filename); + GNUNET_FS_file_information_destroy (ret, NULL, NULL); + return NULL; +} + + +/** + * Using the given serialization filename, try to deserialize + * the file-information tree associated with it. + * + * @param h master context + * @param filename name of the file (without directory) with + * the infromation + * @return NULL on error + */ +static struct GNUNET_FS_FileInformation * +deserialize_file_information (struct GNUNET_FS_Handle *h, const char *filename) +{ + struct GNUNET_FS_FileInformation *ret; + struct GNUNET_BIO_ReadHandle *rh; + char *emsg; + + rh = get_read_handle (h, GNUNET_FS_SYNC_PATH_FILE_INFO, filename); + if (rh == NULL) + return NULL; + ret = deserialize_fi_node (h, filename, rh); + if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to resume publishing information `%s': %s\n"), + filename, emsg); + GNUNET_free (emsg); + } + if (ret == NULL) + { + if (0 != UNLINK (filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); + } + return ret; +} + + +/** + * Given a serialization name (full absolute path), return the + * basename of the file (without the path), which must only + * consist of the 6 random characters. + * + * @param fullname name to extract the basename from + * @return copy of the basename, NULL on error + */ +static char * +get_serialization_short_name (const char *fullname) +{ + const char *end; + const char *nxt; + + end = NULL; + nxt = fullname; + /* FIXME: we could do this faster since we know + * the length of 'end'... */ + while ('\0' != *nxt) + { + if (DIR_SEPARATOR == *nxt) + end = nxt + 1; + nxt++; + } + if ((end == NULL) || (strlen (end) == 0)) + { + GNUNET_break (0); + return NULL; + } + GNUNET_break (6 == strlen (end)); + return GNUNET_strdup (end); +} + + +/** + * Create a new random name for serialization. Also checks if persistence + * is enabled and returns NULL if not. + * + * @param h master context + * @param ext component of the path + * @return NULL on errror + */ +static char * +make_serialization_file_name (struct GNUNET_FS_Handle *h, const char *ext) +{ + char *fn; + char *dn; + char *ret; + + if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) + return NULL; /* persistence not requested */ + dn = get_serialization_file_name (h, ext, ""); + if (dn == NULL) + return NULL; + if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dn)) + { + GNUNET_free (dn); + return NULL; + } + fn = GNUNET_DISK_mktemp (dn); + GNUNET_free (dn); + if (fn == NULL) + return NULL; /* epic fail */ + ret = get_serialization_short_name (fn); + GNUNET_free (fn); + return ret; +} + + +/** + * Create a new random name for serialization. Also checks if persistence + * is enabled and returns NULL if not. + * + * @param h master context + * @param ext component of the path + * @param uni name of parent + * @return NULL on errror + */ +static char * +make_serialization_file_name_in_dir (struct GNUNET_FS_Handle *h, + const char *ext, const char *uni) +{ + char *fn; + char *dn; + char *ret; + + if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) + return NULL; /* persistence not requested */ + dn = get_serialization_file_name_in_dir (h, ext, uni, ""); + if (dn == NULL) + return NULL; + if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dn)) + { + GNUNET_free (dn); + return NULL; + } + fn = GNUNET_DISK_mktemp (dn); + GNUNET_free (dn); + if (fn == NULL) + return NULL; /* epic fail */ + ret = get_serialization_short_name (fn); + GNUNET_free (fn); + return ret; +} + + +/** + * Copy all of the data from the reader to the write handle. + * + * @param wh write handle + * @param fi file with reader + * @return GNUNET_OK on success + */ +static int +copy_from_reader (struct GNUNET_BIO_WriteHandle *wh, + struct GNUNET_FS_FileInformation *fi) +{ + char buf[32 * 1024]; + uint64_t off; + size_t ret; + size_t left; + char *emsg; + + emsg = NULL; + off = 0; + while (off < fi->data.file.file_size) + { + left = GNUNET_MIN (sizeof (buf), fi->data.file.file_size - off); + ret = + fi->data.file.reader (fi->data.file.reader_cls, off, left, buf, &emsg); + if (ret == 0) + { + GNUNET_free (emsg); + return GNUNET_SYSERR; + } + if (GNUNET_OK != GNUNET_BIO_write (wh, buf, ret)) + return GNUNET_SYSERR; + off += ret; + } + return GNUNET_OK; +} + + +/** + * Create a temporary file on disk to store the current + * state of "fi" in. + * + * @param fi file information to sync with disk + */ +void +GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *fi) +{ + char *fn; + struct GNUNET_BIO_WriteHandle *wh; + char b; + char *ksks; + char *chks; + + if (NULL == fi->serialization) + fi->serialization = + make_serialization_file_name (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO); + if (NULL == fi->serialization) + return; + wh = get_write_handle (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO, + fi->serialization); + if (wh == NULL) + { + GNUNET_free (fi->serialization); + fi->serialization = NULL; + return; + } + if (GNUNET_YES == fi->is_directory) + b = 4; + else if (GNUNET_YES == fi->data.file.index_start_confirmed) + b = 3; + else if (GNUNET_YES == fi->data.file.have_hash) + b = 2; + else if (GNUNET_YES == fi->data.file.do_index) + b = 1; + else + b = 0; + if (fi->keywords != NULL) + ksks = GNUNET_FS_uri_to_string (fi->keywords); + else + ksks = NULL; + if (fi->chk_uri != NULL) + chks = GNUNET_FS_uri_to_string (fi->chk_uri); + else + chks = NULL; + if ((GNUNET_OK != GNUNET_BIO_write (wh, &b, sizeof (b))) || + (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, fi->meta)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, ksks)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, chks)) || + (GNUNET_OK != write_start_time (wh, fi->start_time)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, fi->emsg)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, fi->filename)) || + (GNUNET_OK != + GNUNET_BIO_write_int64 (wh, fi->bo.expiration_time.abs_value)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->bo.anonymity_level)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->bo.content_priority)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->bo.replication_level))) + { + GNUNET_break (0); + goto cleanup; + } + GNUNET_free_non_null (chks); + chks = NULL; + GNUNET_free_non_null (ksks); + ksks = NULL; + + switch (b) + { + case 0: /* file-insert */ + if (GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.file.file_size)) + { + GNUNET_break (0); + goto cleanup; + } + if ((GNUNET_NO == fi->is_published) && (NULL == fi->filename)) + if (GNUNET_OK != copy_from_reader (wh, fi)) + { + GNUNET_break (0); + goto cleanup; + } + break; + case 1: /* file-index, no hash */ + if (NULL == fi->filename) + { + GNUNET_break (0); + goto cleanup; + } + if (GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.file.file_size)) + { + GNUNET_break (0); + goto cleanup; + } + break; + case 2: /* file-index-with-hash */ + case 3: /* file-index-with-hash-confirmed */ + if (NULL == fi->filename) + { + GNUNET_break (0); + goto cleanup; + } + if ((GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.file.file_size)) || + (GNUNET_OK != + GNUNET_BIO_write (wh, &fi->data.file.file_id, + sizeof (GNUNET_HashCode)))) + { + GNUNET_break (0); + goto cleanup; + } + break; + case 4: /* directory */ + if ((GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->data.dir.dir_size)) || + (GNUNET_OK != + GNUNET_BIO_write (wh, fi->data.dir.dir_data, + (uint32_t) fi->data.dir.dir_size)) || + (GNUNET_OK != + GNUNET_BIO_write_string (wh, + (fi->data.dir.entries == + NULL) ? NULL : fi->data.dir. + entries->serialization))) + { + GNUNET_break (0); + goto cleanup; + } + break; + default: + GNUNET_assert (0); + goto cleanup; + } + if (GNUNET_OK != + GNUNET_BIO_write_string (wh, + (fi->next != + NULL) ? fi->next->serialization : NULL)) + { + GNUNET_break (0); + goto cleanup; + } + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + { + wh = NULL; + GNUNET_break (0); + goto cleanup; + } + return; /* done! */ +cleanup: + if (wh != NULL) + (void) GNUNET_BIO_write_close (wh); + GNUNET_free_non_null (chks); + GNUNET_free_non_null (ksks); + fn = get_serialization_file_name (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO, + fi->serialization); + if (NULL != fn) + { + if (0 != UNLINK (fn)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); + GNUNET_free (fn); + } + GNUNET_free (fi->serialization); + fi->serialization = NULL; +} + + + +/** + * Find the entry in the file information struct where the + * serialization filename matches the given name. + * + * @param pos file information to search + * @param srch filename to search for + * @return NULL if srch was not found in this subtree + */ +static struct GNUNET_FS_FileInformation * +find_file_position (struct GNUNET_FS_FileInformation *pos, const char *srch) +{ + struct GNUNET_FS_FileInformation *r; + + while (pos != NULL) + { + if (0 == strcmp (srch, pos->serialization)) + return pos; + if (pos->is_directory == GNUNET_YES) + { + r = find_file_position (pos->data.dir.entries, srch); + if (r != NULL) + return r; + } + pos = pos->next; + } + return NULL; +} + + +/** + * Signal the FS's progress function that we are resuming + * an upload. + * + * @param cls closure (of type "struct GNUNET_FS_PublishContext*") + * @param fi the entry in the publish-structure + * @param length length of the file or directory + * @param meta metadata for the file or directory (can be modified) + * @param uri pointer to the keywords that will be used for this entry (can be modified) + * @param bo block options (can be modified) + * @param do_index should we index? + * @param client_info pointer to client context set upon creation (can be modified) + * @return GNUNET_OK to continue (always) + */ +static int +fip_signal_resume (void *cls, struct GNUNET_FS_FileInformation *fi, + uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, + struct GNUNET_FS_Uri **uri, + struct GNUNET_FS_BlockOptions *bo, int *do_index, + void **client_info) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_ProgressInfo pi; + + if (GNUNET_YES == pc->skip_next_fi_callback) + { + pc->skip_next_fi_callback = GNUNET_NO; + return GNUNET_OK; + } + pi.status = GNUNET_FS_STATUS_PUBLISH_RESUME; + pi.value.publish.specifics.resume.message = pc->fi->emsg; + pi.value.publish.specifics.resume.chk_uri = pc->fi->chk_uri; + *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0); + if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) + { + /* process entries in directory */ + pc->skip_next_fi_callback = GNUNET_YES; + GNUNET_FS_file_information_inspect (fi, &fip_signal_resume, pc); + } + return GNUNET_OK; +} + + +/** + * Function called with a filename of serialized publishing operation + * to deserialize. + * + * @param cls the 'struct GNUNET_FS_Handle*' + * @param filename complete filename (absolute path) + * @return GNUNET_OK (continue to iterate) + */ +static int +deserialize_publish_file (void *cls, const char *filename) +{ + struct GNUNET_FS_Handle *h = cls; + struct GNUNET_BIO_ReadHandle *rh; + struct GNUNET_FS_PublishContext *pc; + int32_t options; + int32_t all_done; + char *fi_root; + char *ns; + char *fi_pos; + char *emsg; + + pc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishContext)); + pc->h = h; + pc->serialization = get_serialization_short_name (filename); + fi_root = NULL; + fi_pos = NULL; + ns = NULL; + rh = GNUNET_BIO_read_open (filename); + if (rh == NULL) + { + GNUNET_break (0); + goto cleanup; + } + if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "publish-nid", &pc->nid, 1024)) + || (GNUNET_OK != + GNUNET_BIO_read_string (rh, "publish-nuid", &pc->nuid, 1024)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &options)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &all_done)) || + (GNUNET_OK != + GNUNET_BIO_read_string (rh, "publish-firoot", &fi_root, 128)) || + (GNUNET_OK != GNUNET_BIO_read_string (rh, "publish-fipos", &fi_pos, 128)) + || (GNUNET_OK != GNUNET_BIO_read_string (rh, "publish-ns", &ns, 1024))) + { + GNUNET_break (0); + goto cleanup; + } + pc->options = options; + pc->all_done = all_done; + if (NULL == fi_root) + { + GNUNET_break (0); + goto cleanup; + } + pc->fi = deserialize_file_information (h, fi_root); + if (pc->fi == NULL) + { + GNUNET_break (0); + goto cleanup; + } + if (ns != NULL) + { + pc->namespace = GNUNET_FS_namespace_create (h, ns); + if (pc->namespace == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Failed to recover namespace `%s', cannot resume publishing operation.\n"), + ns); + goto cleanup; + } + } + if ((0 == (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) && + (GNUNET_YES != pc->all_done)) + { + pc->dsh = GNUNET_DATASTORE_connect (h->cfg); + if (NULL == pc->dsh) + goto cleanup; + } + if (fi_pos != NULL) + { + pc->fi_pos = find_file_position (pc->fi, fi_pos); + GNUNET_free (fi_pos); + fi_pos = NULL; + if (pc->fi_pos == NULL) + { + /* failed to find position for resuming, outch! Will start from root! */ + GNUNET_break (0); + if (pc->all_done != GNUNET_YES) + pc->fi_pos = pc->fi; + } + } + GNUNET_free (fi_root); + fi_root = NULL; + /* generate RESUME event(s) */ + GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_resume, pc); + + /* re-start publishing (if needed)... */ + if (pc->all_done != GNUNET_YES) + { + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); + pc->upload_task = + GNUNET_SCHEDULER_add_with_priority + (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, + &GNUNET_FS_publish_main_, pc); + } + if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failure while resuming publishing operation `%s': %s\n"), + filename, emsg); + GNUNET_free (emsg); + } + GNUNET_free_non_null (ns); + pc->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, pc); + return GNUNET_OK; +cleanup: + GNUNET_free_non_null (pc->nid); + GNUNET_free_non_null (pc->nuid); + GNUNET_free_non_null (fi_root); + GNUNET_free_non_null (fi_pos); + GNUNET_free_non_null (ns); + if ((rh != NULL) && (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to resume publishing operation `%s': %s\n"), filename, + emsg); + GNUNET_free (emsg); + } + if (pc->fi != NULL) + GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL); + if (0 != UNLINK (filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); + GNUNET_free (pc->serialization); + GNUNET_free (pc); + return GNUNET_OK; +} + + +/** + * Synchronize this publishing struct with its mirror + * on disk. Note that all internal FS-operations that change + * publishing structs should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param pc the struct to sync + */ +void +GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc) +{ + struct GNUNET_BIO_WriteHandle *wh; + + if (NULL == pc->serialization) + pc->serialization = + make_serialization_file_name (pc->h, + GNUNET_FS_SYNC_PATH_MASTER_PUBLISH); + if (NULL == pc->serialization) + return; + if (NULL == pc->fi) + return; + if (NULL == pc->fi->serialization) + { + GNUNET_break (0); + return; + } + wh = get_write_handle (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, + pc->serialization); + if (wh == NULL) + { + GNUNET_break (0); + goto cleanup; + } + if ((GNUNET_OK != GNUNET_BIO_write_string (wh, pc->nid)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, pc->nuid)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pc->options)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pc->all_done)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, pc->fi->serialization)) || + (GNUNET_OK != + GNUNET_BIO_write_string (wh, + (pc->fi_pos == + NULL) ? NULL : pc->fi_pos->serialization)) || + (GNUNET_OK != + GNUNET_BIO_write_string (wh, + (pc->namespace == + NULL) ? NULL : pc->namespace->name))) + { + GNUNET_break (0); + goto cleanup; + } + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + { + wh = NULL; + GNUNET_break (0); + goto cleanup; + } + return; +cleanup: + if (wh != NULL) + (void) GNUNET_BIO_write_close (wh); + GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, + pc->serialization); + GNUNET_free (pc->serialization); + pc->serialization = NULL; +} + + +/** + * Synchronize this unindex struct with its mirror + * on disk. Note that all internal FS-operations that change + * publishing structs should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param uc the struct to sync + */ +void +GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc) +{ + struct GNUNET_BIO_WriteHandle *wh; + + if (NULL == uc->serialization) + uc->serialization = + make_serialization_file_name (uc->h, + GNUNET_FS_SYNC_PATH_MASTER_UNINDEX); + if (NULL == uc->serialization) + return; + wh = get_write_handle (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, + uc->serialization); + if (wh == NULL) + { + GNUNET_break (0); + goto cleanup; + } + if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uc->filename)) || + (GNUNET_OK != GNUNET_BIO_write_int64 (wh, uc->file_size)) || + (GNUNET_OK != write_start_time (wh, uc->start_time)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) uc->state)) || + ((uc->state == UNINDEX_STATE_FS_NOTIFY) && + (GNUNET_OK != + GNUNET_BIO_write (wh, &uc->file_id, sizeof (GNUNET_HashCode)))) || + ((uc->state == UNINDEX_STATE_ERROR) && + (GNUNET_OK != GNUNET_BIO_write_string (wh, uc->emsg)))) + { + GNUNET_break (0); + goto cleanup; + } + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + { + wh = NULL; + GNUNET_break (0); + goto cleanup; + } + return; +cleanup: + if (wh != NULL) + (void) GNUNET_BIO_write_close (wh); + GNUNET_FS_remove_sync_file_ (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, + uc->serialization); + GNUNET_free (uc->serialization); + uc->serialization = NULL; +} + + +/** + * Serialize a download request. + * + * @param wh the 'struct GNUNET_BIO_WriteHandle*' + * @param dr the 'struct DownloadRequest' + * @return GNUNET_YES on success, GNUNET_NO on error + */ +static int +write_download_request (struct GNUNET_BIO_WriteHandle *wh, + struct DownloadRequest *dr) +{ + unsigned int i; + + if ((GNUNET_OK != GNUNET_BIO_write_int32 (wh, dr->state)) || + (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dr->offset)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, dr->num_children)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, dr->depth))) + return GNUNET_NO; + if ((dr->state == BRS_CHK_SET) && + (GNUNET_OK != + GNUNET_BIO_write (wh, &dr->chk, sizeof (struct ContentHashKey)))) + return GNUNET_NO; + for (i = 0; i < dr->num_children; i++) + if (GNUNET_NO == write_download_request (wh, dr->children[i])) + return GNUNET_NO; + return GNUNET_YES; +} + + +/** + * Read a download request tree. + * + * @param rh stream to read from + * @return value the 'struct DownloadRequest', NULL on error + */ +static struct DownloadRequest * +read_download_request (struct GNUNET_BIO_ReadHandle *rh) +{ + struct DownloadRequest *dr; + unsigned int i; + + dr = GNUNET_malloc (sizeof (struct DownloadRequest)); + + if ((GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dr->state)) || + (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dr->offset)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dr->num_children)) || + (dr->num_children > CHK_PER_INODE) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dr->depth)) || ((dr->depth == 0) + && + (dr->num_children + > 0)) || + ((dr->depth > 0) && (dr->num_children == 0))) + { + GNUNET_break (0); + dr->num_children = 0; + goto cleanup; + } + if (dr->num_children > 0) + dr->children = + GNUNET_malloc (dr->num_children * sizeof (struct ContentHashKey)); + switch (dr->state) + { + case BRS_INIT: + case BRS_RECONSTRUCT_DOWN: + case BRS_RECONSTRUCT_META_UP: + case BRS_RECONSTRUCT_UP: + break; + case BRS_CHK_SET: + if (GNUNET_OK != + GNUNET_BIO_read (rh, "chk", &dr->chk, sizeof (struct ContentHashKey))) + goto cleanup; + break; + case BRS_DOWNLOAD_DOWN: + case BRS_DOWNLOAD_UP: + case BRS_ERROR: + break; + default: + GNUNET_break (0); + goto cleanup; + } + for (i = 0; i < dr->num_children; i++) + { + if (NULL == (dr->children[i] = read_download_request (rh))) + goto cleanup; + dr->children[i]->parent = dr; + } + return dr; +cleanup: + GNUNET_FS_free_download_request_ (dr); + return NULL; +} + + +/** + * Compute the name of the sync file (or directory) for the given download + * context. + * + * @param dc download context to compute for + * @param uni unique filename to use, use "" for the directory name + * @param ext extension to use, use ".dir" for our own subdirectory + * @return the expanded file name, NULL for none + */ +static char * +get_download_sync_filename (struct GNUNET_FS_DownloadContext *dc, + const char *uni, const char *ext) +{ + char *par; + char *epar; + + if (dc->parent == NULL) + return get_serialization_file_name (dc->h, + (dc->search != + NULL) ? + GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD : + GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, + uni); + if (dc->parent->serialization == NULL) + return NULL; + par = get_download_sync_filename (dc->parent, dc->parent->serialization, ""); + if (par == NULL) + return NULL; + GNUNET_asprintf (&epar, "%s.dir%s%s%s", par, DIR_SEPARATOR_STR, uni, ext); + GNUNET_free (par); + return epar; +} + + +/** + * Synchronize this download struct with its mirror + * on disk. Note that all internal FS-operations that change + * publishing structs should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param dc the struct to sync + */ +void +GNUNET_FS_download_sync_ (struct GNUNET_FS_DownloadContext *dc) +{ + struct GNUNET_BIO_WriteHandle *wh; + char *uris; + char *fn; + char *dir; + + if (NULL == dc->serialization) + { + dir = get_download_sync_filename (dc, "", ""); + if (dir == NULL) + return; + if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dir)) + { + GNUNET_free (dir); + return; + } + fn = GNUNET_DISK_mktemp (dir); + GNUNET_free (dir); + if (fn == NULL) + return; + dc->serialization = get_serialization_short_name (fn); + } + else + { + fn = get_download_sync_filename (dc, dc->serialization, ""); + if (fn == NULL) + { + GNUNET_free (dc->serialization); + dc->serialization = NULL; + GNUNET_free (fn); + return; + } + } + wh = GNUNET_BIO_write_open (fn); + if (wh == NULL) + { + GNUNET_free (dc->serialization); + dc->serialization = NULL; + GNUNET_free (fn); + return; + } + GNUNET_assert ((GNUNET_YES == GNUNET_FS_uri_test_chk (dc->uri)) || + (GNUNET_YES == GNUNET_FS_uri_test_loc (dc->uri))); + uris = GNUNET_FS_uri_to_string (dc->uri); + if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) || + (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, dc->meta)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, dc->emsg)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, dc->filename)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, dc->temp_filename)) || + (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->old_file_size)) || + (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->offset)) || + (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->length)) || + (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->completed)) || + (GNUNET_OK != write_start_time (wh, dc->start_time)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, dc->anonymity)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) dc->options)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) dc->has_finished))) + { + GNUNET_break (0); + goto cleanup; + } + if (NULL == dc->emsg) + { + GNUNET_assert (dc->top_request != NULL); + if (GNUNET_YES != write_download_request (wh, dc->top_request)) + { + GNUNET_break (0); + goto cleanup; + } + } + GNUNET_free_non_null (uris); + uris = NULL; + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + { + wh = NULL; + GNUNET_break (0); + goto cleanup; + } + GNUNET_free (fn); + return; +cleanup: + if (NULL != wh) + (void) GNUNET_BIO_write_close (wh); + GNUNET_free_non_null (uris); + if (0 != UNLINK (fn)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); + GNUNET_free (fn); + GNUNET_free (dc->serialization); + dc->serialization = NULL; +} + + +/** + * Synchronize this search result with its mirror + * on disk. Note that all internal FS-operations that change + * publishing structs should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param sr the struct to sync + */ +void +GNUNET_FS_search_result_sync_ (struct GNUNET_FS_SearchResult *sr) +{ + struct GNUNET_BIO_WriteHandle *wh; + char *uris; + + uris = NULL; + if (NULL == sr->serialization) + sr->serialization = + make_serialization_file_name_in_dir (sr->sc->h, + (sr->sc->psearch_result == + NULL) ? + GNUNET_FS_SYNC_PATH_MASTER_SEARCH : + GNUNET_FS_SYNC_PATH_CHILD_SEARCH, + sr->sc->serialization); + if (NULL == sr->serialization) + return; + wh = get_write_handle_in_dir (sr->sc->h, + (sr->sc->psearch_result == + NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : + GNUNET_FS_SYNC_PATH_CHILD_SEARCH, + sr->sc->serialization, sr->serialization); + if (wh == NULL) + { + GNUNET_break (0); + goto cleanup; + } + uris = GNUNET_FS_uri_to_string (sr->uri); + if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) || + (GNUNET_OK != + GNUNET_BIO_write_string (wh, + sr->download != + NULL ? sr->download->serialization : NULL)) || + (GNUNET_OK != + GNUNET_BIO_write_string (wh, + sr->update_search != + NULL ? sr->update_search->serialization : NULL)) + || (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, sr->meta)) || + (GNUNET_OK != GNUNET_BIO_write (wh, &sr->key, sizeof (GNUNET_HashCode))) + || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->mandatory_missing)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->optional_support)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->availability_success)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->availability_trials)) ) + { + GNUNET_break (0); + goto cleanup; + } + if ( (sr->uri != NULL) && + (sr->sc->uri->type == ksk) && + (GNUNET_OK != GNUNET_BIO_write (wh, sr->keyword_bitmap, + (sr->sc->uri->data.ksk.keywordCount + 7) / 8)) ) + { + GNUNET_break (0); + goto cleanup; + } + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + { + wh = NULL; + GNUNET_break (0); + goto cleanup; + } + GNUNET_free_non_null (uris); + return; +cleanup: + GNUNET_free_non_null (uris); + if (wh != NULL) + (void) GNUNET_BIO_write_close (wh); + remove_sync_file_in_dir (sr->sc->h, + (sr->sc->psearch_result == + NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : + GNUNET_FS_SYNC_PATH_CHILD_SEARCH, + sr->sc->serialization, sr->serialization); + GNUNET_free (sr->serialization); + sr->serialization = NULL; +} + + +/** + * Synchronize this search struct with its mirror + * on disk. Note that all internal FS-operations that change + * publishing structs should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param sc the struct to sync + */ +void +GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc) +{ + struct GNUNET_BIO_WriteHandle *wh; + char *uris; + char in_pause; + const char *category; + + category = + (sc->psearch_result == + NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : + GNUNET_FS_SYNC_PATH_CHILD_SEARCH; + if (NULL == sc->serialization) + sc->serialization = make_serialization_file_name (sc->h, category); + if (NULL == sc->serialization) + return; + uris = NULL; + wh = get_write_handle (sc->h, category, sc->serialization); + if (wh == NULL) + { + GNUNET_break (0); + goto cleanup; + } + GNUNET_assert ((GNUNET_YES == GNUNET_FS_uri_test_ksk (sc->uri)) || + (GNUNET_YES == GNUNET_FS_uri_test_sks (sc->uri))); + uris = GNUNET_FS_uri_to_string (sc->uri); + in_pause = (sc->task != GNUNET_SCHEDULER_NO_TASK) ? 'r' : '\0'; + if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) || + (GNUNET_OK != write_start_time (wh, sc->start_time)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, sc->emsg)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) sc->options)) || + (GNUNET_OK != GNUNET_BIO_write (wh, &in_pause, sizeof (in_pause))) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sc->anonymity))) + { + GNUNET_break (0); + goto cleanup; + } + GNUNET_free (uris); + uris = NULL; + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + { + wh = NULL; + GNUNET_break (0); + goto cleanup; + } + return; +cleanup: + if (wh != NULL) + (void) GNUNET_BIO_write_close (wh); + GNUNET_free_non_null (uris); + GNUNET_FS_remove_sync_file_ (sc->h, category, sc->serialization); + GNUNET_free (sc->serialization); + sc->serialization = NULL; +} + + +/** + * Function called with a filename of serialized unindexing operation + * to deserialize. + * + * @param cls the 'struct GNUNET_FS_Handle*' + * @param filename complete filename (absolute path) + * @return GNUNET_OK (continue to iterate) + */ +static int +deserialize_unindex_file (void *cls, const char *filename) +{ + struct GNUNET_FS_Handle *h = cls; + struct GNUNET_BIO_ReadHandle *rh; + struct GNUNET_FS_UnindexContext *uc; + struct GNUNET_FS_ProgressInfo pi; + char *emsg; + uint32_t state; + + uc = GNUNET_malloc (sizeof (struct GNUNET_FS_UnindexContext)); + uc->h = h; + uc->serialization = get_serialization_short_name (filename); + rh = GNUNET_BIO_read_open (filename); + if (rh == NULL) + { + GNUNET_break (0); + goto cleanup; + } + if ((GNUNET_OK != + GNUNET_BIO_read_string (rh, "unindex-fn", &uc->filename, 10 * 1024)) || + (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &uc->file_size)) || + (GNUNET_OK != read_start_time (rh, &uc->start_time)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &state))) + { + GNUNET_break (0); + goto cleanup; + } + uc->state = (enum UnindexState) state; + switch (state) + { + case UNINDEX_STATE_HASHING: + break; + case UNINDEX_STATE_FS_NOTIFY: + if (GNUNET_OK != + GNUNET_BIO_read (rh, "unindex-hash", &uc->file_id, + sizeof (GNUNET_HashCode))) + { + GNUNET_break (0); + goto cleanup; + } + break; + case UNINDEX_STATE_DS_REMOVE: + break; + case UNINDEX_STATE_COMPLETE: + break; + case UNINDEX_STATE_ERROR: + if (GNUNET_OK != + GNUNET_BIO_read_string (rh, "unindex-emsg", &uc->emsg, 10 * 1024)) + { + GNUNET_break (0); + goto cleanup; + } + break; + default: + GNUNET_break (0); + goto cleanup; + } + uc->top = GNUNET_FS_make_top (h, &GNUNET_FS_unindex_signal_suspend_, uc); + pi.status = GNUNET_FS_STATUS_UNINDEX_RESUME; + pi.value.unindex.specifics.resume.message = uc->emsg; + GNUNET_FS_unindex_make_status_ (&pi, uc, + (uc->state == + UNINDEX_STATE_COMPLETE) ? uc->file_size : 0); + switch (uc->state) + { + case UNINDEX_STATE_HASHING: + uc->fhc = + GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, uc->filename, + HASHING_BLOCKSIZE, + &GNUNET_FS_unindex_process_hash_, uc); + break; + case UNINDEX_STATE_FS_NOTIFY: + uc->state = UNINDEX_STATE_HASHING; + GNUNET_FS_unindex_process_hash_ (uc, &uc->file_id); + break; + case UNINDEX_STATE_DS_REMOVE: + GNUNET_FS_unindex_do_remove_ (uc); + break; + case UNINDEX_STATE_COMPLETE: + case UNINDEX_STATE_ERROR: + /* no need to resume any operation, we were done */ + break; + default: + break; + } + if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failure while resuming unindexing operation `%s': %s\n"), + filename, emsg); + GNUNET_free (emsg); + } + return GNUNET_OK; +cleanup: + GNUNET_free_non_null (uc->filename); + if ((rh != NULL) && (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to resume unindexing operation `%s': %s\n"), filename, + emsg); + GNUNET_free (emsg); + } + if (uc->serialization != NULL) + GNUNET_FS_remove_sync_file_ (h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, + uc->serialization); + GNUNET_free_non_null (uc->serialization); + GNUNET_free (uc); + return GNUNET_OK; +} + + +/** + * Deserialize a download. + * + * @param h overall context + * @param rh file to deserialize from + * @param parent parent download + * @param search associated search + * @param serialization name under which the search was serialized + */ +static void +deserialize_download (struct GNUNET_FS_Handle *h, + struct GNUNET_BIO_ReadHandle *rh, + struct GNUNET_FS_DownloadContext *parent, + struct GNUNET_FS_SearchResult *search, + const char *serialization); + + +/** + * Deserialize a search. + * + * @param h overall context + * @param rh file to deserialize from + * @param psearch_result parent search result + * @param serialization name under which the search was serialized + */ +static struct GNUNET_FS_SearchContext * +deserialize_search (struct GNUNET_FS_Handle *h, + struct GNUNET_BIO_ReadHandle *rh, + struct GNUNET_FS_SearchResult *psearch_result, + const char *serialization); + + +/** + * Function called with a filename of serialized search result + * to deserialize. + * + * @param cls the 'struct GNUNET_FS_SearchContext*' + * @param filename complete filename (absolute path) + * @return GNUNET_OK (continue to iterate) + */ +static int +deserialize_search_result (void *cls, const char *filename) +{ + struct GNUNET_FS_SearchContext *sc = cls; + char *ser; + char *uris; + char *emsg; + char *download; + char *update_srch; + struct GNUNET_BIO_ReadHandle *rh; + struct GNUNET_BIO_ReadHandle *drh; + struct GNUNET_FS_SearchResult *sr; + + ser = get_serialization_short_name (filename); + rh = GNUNET_BIO_read_open (filename); + if (rh == NULL) + { + if (ser != NULL) + { + remove_sync_file_in_dir (sc->h, + (sc->psearch_result == + NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : + GNUNET_FS_SYNC_PATH_CHILD_SEARCH, + sc->serialization, ser); + GNUNET_free (ser); + } + return GNUNET_OK; + } + emsg = NULL; + uris = NULL; + download = NULL; + update_srch = NULL; + sr = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchResult)); + sr->sc = sc; + sr->serialization = ser; + if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "result-uri", &uris, 10 * 1024)) + || (NULL == (sr->uri = GNUNET_FS_uri_parse (uris, &emsg))) || + (GNUNET_OK != GNUNET_BIO_read_string (rh, "download-lnk", &download, 16)) + || (GNUNET_OK != + GNUNET_BIO_read_string (rh, "search-lnk", &update_srch, 16)) || + (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "result-meta", &sr->meta)) || + (GNUNET_OK != + GNUNET_BIO_read (rh, "result-key", &sr->key, sizeof (GNUNET_HashCode))) + || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->mandatory_missing)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->optional_support)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->availability_success)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->availability_trials))) + { + GNUNET_break (0); + goto cleanup; + } + if (sr->sc->uri->type == ksk) + { + sr->keyword_bitmap = GNUNET_malloc ((sr->sc->uri->data.ksk.keywordCount + 7) / 8); /* round up, count bits */ + if (GNUNET_OK != GNUNET_BIO_read (rh, "keyword-bitmap", + sr->keyword_bitmap, + (sr->sc->uri->data.ksk.keywordCount + 7) / 8)) + { + GNUNET_break (0); + goto cleanup; + } + } + GNUNET_free (uris); + if (download != NULL) + { + drh = get_read_handle (sc->h, GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD, download); + if (drh != NULL) + { + deserialize_download (sc->h, drh, NULL, sr, download); + if (GNUNET_OK != GNUNET_BIO_read_close (drh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to resume sub-download `%s': %s\n"), download, + emsg); + GNUNET_free (emsg); + } + } + GNUNET_free (download); + } + if (update_srch != NULL) + { + drh = + get_read_handle (sc->h, GNUNET_FS_SYNC_PATH_CHILD_SEARCH, update_srch); + if (drh != NULL) + { + deserialize_search (sc->h, drh, sr, update_srch); + if (GNUNET_OK != GNUNET_BIO_read_close (drh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to resume sub-search `%s': %s\n"), update_srch, + emsg); + GNUNET_free (emsg); + } + } + GNUNET_free (update_srch); + } + GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &sr->key, sr, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failure while resuming search operation `%s': %s\n"), + filename, emsg); + GNUNET_free (emsg); + } + return GNUNET_OK; +cleanup: + GNUNET_free_non_null (download); + GNUNET_free_non_null (emsg); + GNUNET_free_non_null (uris); + GNUNET_free_non_null (update_srch); + if (sr->uri != NULL) + GNUNET_FS_uri_destroy (sr->uri); + if (sr->meta != NULL) + GNUNET_CONTAINER_meta_data_destroy (sr->meta); + GNUNET_free (sr->serialization); + GNUNET_free (sr); + if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failure while resuming search operation `%s': %s\n"), + filename, emsg); + GNUNET_free (emsg); + } + return GNUNET_OK; +} + + +/** + * Send the 'resume' signal to the callback; also actually + * resume the download (put it in the queue). Does this + * recursively for the top-level download and all child + * downloads. + * + * @param dc download to resume + */ +static void +signal_download_resume (struct GNUNET_FS_DownloadContext *dc) +{ + struct GNUNET_FS_DownloadContext *dcc; + struct GNUNET_FS_ProgressInfo pi; + + pi.status = GNUNET_FS_STATUS_DOWNLOAD_RESUME; + pi.value.download.specifics.resume.meta = dc->meta; + pi.value.download.specifics.resume.message = dc->emsg; + GNUNET_FS_download_make_status_ (&pi, dc); + dcc = dc->child_head; + while (NULL != dcc) + { + signal_download_resume (dcc); + dcc = dcc->next; + } + if (dc->pending_head != NULL) + GNUNET_FS_download_start_downloading_ (dc); +} + + +/** + * Signal resuming of a search to our clients (for the + * top level search and all sub-searches). + * + * @param sc search being resumed + */ +static void +signal_search_resume (struct GNUNET_FS_SearchContext *sc); + + +/** + * Iterator over search results signaling resume to the client for + * each result. + * + * @param cls closure, the 'struct GNUNET_FS_SearchContext' + * @param key current key code + * @param value value in the hash map, the 'struct GNUNET_FS_SearchResult' + * @return GNUNET_YES (we should continue to iterate) + */ +static int +signal_result_resume (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_FS_SearchContext *sc = cls; + struct GNUNET_FS_ProgressInfo pi; + struct GNUNET_FS_SearchResult *sr = value; + + if (0 == sr->mandatory_missing) + { + pi.status = GNUNET_FS_STATUS_SEARCH_RESUME_RESULT; + pi.value.search.specifics.resume_result.meta = sr->meta; + pi.value.search.specifics.resume_result.uri = sr->uri; + pi.value.search.specifics.resume_result.result = sr; + pi.value.search.specifics.resume_result.availability_rank = + 2 * sr->availability_success - sr->availability_trials; + pi.value.search.specifics.resume_result.availability_certainty = + sr->availability_trials; + pi.value.search.specifics.resume_result.applicability_rank = + sr->optional_support; + sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc); + } + if (sr->download != NULL) + { + signal_download_resume (sr->download); + } + else + { + GNUNET_FS_search_start_probe_ (sr); + } + if (sr->update_search != NULL) + signal_search_resume (sr->update_search); + return GNUNET_YES; +} + + +/** + * Free memory allocated by the search context and its children + * + * @param sc search context to free + */ +static void +free_search_context (struct GNUNET_FS_SearchContext *sc); + + +/** + * Iterator over search results freeing each. + * + * @param cls closure, the 'struct GNUNET_FS_SearchContext' + * @param key current key code + * @param value value in the hash map, the 'struct GNUNET_FS_SearchResult' + * @return GNUNET_YES (we should continue to iterate) + */ +static int +free_result (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_FS_SearchResult *sr = value; + + if (sr->update_search != NULL) + { + free_search_context (sr->update_search); + GNUNET_assert (NULL == sr->update_search); + } + GNUNET_CONTAINER_meta_data_destroy (sr->meta); + GNUNET_FS_uri_destroy (sr->uri); + GNUNET_free (sr); + return GNUNET_YES; +} + + +/** + * Free memory allocated by the search context and its children + * + * @param sc search context to free + */ +static void +free_search_context (struct GNUNET_FS_SearchContext *sc) +{ + if (sc->serialization != NULL) + { + GNUNET_FS_remove_sync_file_ (sc->h, + (sc->psearch_result == + NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : + GNUNET_FS_SYNC_PATH_CHILD_SEARCH, + sc->serialization); + GNUNET_FS_remove_sync_dir_ (sc->h, + (sc->psearch_result == + NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : + GNUNET_FS_SYNC_PATH_CHILD_SEARCH, + sc->serialization); + } + GNUNET_free_non_null (sc->serialization); + GNUNET_free_non_null (sc->emsg); + if (sc->uri != NULL) + GNUNET_FS_uri_destroy (sc->uri); + if (sc->master_result_map != NULL) + { + GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &free_result, + sc); + GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); + } + GNUNET_free (sc); +} + + +/** + * Function called with a filename of serialized sub-download + * to deserialize. + * + * @param cls the 'struct GNUNET_FS_DownloadContext*' (parent) + * @param filename complete filename (absolute path) + * @return GNUNET_OK (continue to iterate) + */ +static int +deserialize_subdownload (void *cls, const char *filename) +{ + struct GNUNET_FS_DownloadContext *parent = cls; + char *ser; + char *emsg; + struct GNUNET_BIO_ReadHandle *rh; + + ser = get_serialization_short_name (filename); + rh = GNUNET_BIO_read_open (filename); + if (rh == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Failed to resume sub-download `%s': could not open file `%s'\n"), + ser, filename); + GNUNET_free (ser); + return GNUNET_OK; + } + deserialize_download (parent->h, rh, parent, NULL, ser); + if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to resume sub-download `%s': %s\n"), ser, emsg); + GNUNET_free (emsg); + } + GNUNET_free (ser); + return GNUNET_OK; +} + + +/** + * Free this download context and all of its descendants. + * (only works during deserialization since not all possible + * state it taken care of). + * + * @param dc context to free + */ +static void +free_download_context (struct GNUNET_FS_DownloadContext *dc) +{ + struct GNUNET_FS_DownloadContext *dcc; + + if (dc->meta != NULL) + GNUNET_CONTAINER_meta_data_destroy (dc->meta); + if (dc->uri != NULL) + GNUNET_FS_uri_destroy (dc->uri); + GNUNET_free_non_null (dc->temp_filename); + GNUNET_free_non_null (dc->emsg); + GNUNET_free_non_null (dc->filename); + GNUNET_free_non_null (dc->serialization); + while (NULL != (dcc = dc->child_head)) + { + GNUNET_CONTAINER_DLL_remove (dc->child_head, dc->child_tail, dcc); + free_download_context (dcc); + } + GNUNET_FS_free_download_request_ (dc->top_request); + if (NULL != dc->active) + GNUNET_CONTAINER_multihashmap_destroy (dc->active); + GNUNET_free (dc); +} + + +/** + * Deserialize a download. + * + * @param h overall context + * @param rh file to deserialize from + * @param parent parent download + * @param search associated search + * @param serialization name under which the search was serialized + */ +static void +deserialize_download (struct GNUNET_FS_Handle *h, + struct GNUNET_BIO_ReadHandle *rh, + struct GNUNET_FS_DownloadContext *parent, + struct GNUNET_FS_SearchResult *search, + const char *serialization) +{ + struct GNUNET_FS_DownloadContext *dc; + char *emsg; + char *uris; + char *dn; + uint32_t options; + uint32_t status; + + uris = NULL; + emsg = NULL; + dc = GNUNET_malloc (sizeof (struct GNUNET_FS_DownloadContext)); + dc->parent = parent; + dc->h = h; + dc->serialization = GNUNET_strdup (serialization); + if ((GNUNET_OK != + GNUNET_BIO_read_string (rh, "download-uri", &uris, 10 * 1024)) || + (NULL == (dc->uri = GNUNET_FS_uri_parse (uris, &emsg))) || + ((GNUNET_YES != GNUNET_FS_uri_test_chk (dc->uri)) && + (GNUNET_YES != GNUNET_FS_uri_test_loc (dc->uri))) || + (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "download-meta", &dc->meta)) + || (GNUNET_OK != + GNUNET_BIO_read_string (rh, "download-emsg", &dc->emsg, 10 * 1024)) || + (GNUNET_OK != + GNUNET_BIO_read_string (rh, "download-fn", &dc->filename, 10 * 1024)) || + (GNUNET_OK != + GNUNET_BIO_read_string (rh, "download-tfn", &dc->temp_filename, + 10 * 1024)) || + (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->old_file_size)) || + (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->offset)) || + (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->length)) || + (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->completed)) || + (GNUNET_OK != read_start_time (rh, &dc->start_time)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dc->anonymity)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &options)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &status))) + { + GNUNET_break (0); + goto cleanup; + } + dc->options = (enum GNUNET_FS_DownloadOptions) options; + dc->active = + GNUNET_CONTAINER_multihashmap_create (1 + 2 * (dc->length / DBLOCK_SIZE)); + dc->has_finished = (int) status; + dc->treedepth = + GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri)); + if (GNUNET_FS_uri_test_loc (dc->uri)) + GNUNET_assert (GNUNET_OK == + GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target)); + if (dc->emsg == NULL) + { + dc->top_request = read_download_request (rh); + if (dc->top_request == NULL) + { + GNUNET_break (0); + goto cleanup; + } + } + dn = get_download_sync_filename (dc, dc->serialization, ".dir"); + if (dn != NULL) + { + if (GNUNET_YES == GNUNET_DISK_directory_test (dn)) + GNUNET_DISK_directory_scan (dn, &deserialize_subdownload, dc); + GNUNET_free (dn); + } + if (parent != NULL) + { + GNUNET_abort (); // for debugging for now - FIXME + GNUNET_CONTAINER_DLL_insert (parent->child_head, parent->child_tail, dc); + } + if (search != NULL) + { + dc->search = search; + search->download = dc; + } + if ((parent == NULL) && (search == NULL)) + { + dc->top = + GNUNET_FS_make_top (dc->h, &GNUNET_FS_download_signal_suspend_, dc); + signal_download_resume (dc); + } + GNUNET_free (uris); + dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc); + return; +cleanup: + GNUNET_free_non_null (uris); + GNUNET_free_non_null (emsg); + free_download_context (dc); +} + + +/** + * Signal resuming of a search to our clients (for the + * top level search and all sub-searches). + * + * @param sc search being resumed + */ +static void +signal_search_resume (struct GNUNET_FS_SearchContext *sc) +{ + struct GNUNET_FS_ProgressInfo pi; + + pi.status = GNUNET_FS_STATUS_SEARCH_RESUME; + pi.value.search.specifics.resume.message = sc->emsg; + pi.value.search.specifics.resume.is_paused = + (sc->client == NULL) ? GNUNET_YES : GNUNET_NO; + sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); + GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, + &signal_result_resume, sc); + +} + + +/** + * Deserialize a search. + * + * @param h overall context + * @param rh file to deserialize from + * @param psearch_result parent search result + * @param serialization name under which the search was serialized + */ +static struct GNUNET_FS_SearchContext * +deserialize_search (struct GNUNET_FS_Handle *h, + struct GNUNET_BIO_ReadHandle *rh, + struct GNUNET_FS_SearchResult *psearch_result, + const char *serialization) +{ + struct GNUNET_FS_SearchContext *sc; + char *emsg; + char *uris; + char *dn; + uint32_t options; + char in_pause; + + if ((psearch_result != NULL) && (psearch_result->update_search != NULL)) + { + GNUNET_break (0); + return NULL; + } + uris = NULL; + emsg = NULL; + sc = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchContext)); + if (psearch_result != NULL) + { + sc->psearch_result = psearch_result; + psearch_result->update_search = sc; + } + sc->h = h; + sc->serialization = GNUNET_strdup (serialization); + if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "search-uri", &uris, 10 * 1024)) + || (NULL == (sc->uri = GNUNET_FS_uri_parse (uris, &emsg))) || + ((GNUNET_YES != GNUNET_FS_uri_test_ksk (sc->uri)) && + (GNUNET_YES != GNUNET_FS_uri_test_sks (sc->uri))) || + (GNUNET_OK != read_start_time (rh, &sc->start_time)) || + (GNUNET_OK != + GNUNET_BIO_read_string (rh, "search-emsg", &sc->emsg, 10 * 1024)) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &options)) || + (GNUNET_OK != + GNUNET_BIO_read (rh, "search-pause", &in_pause, sizeof (in_pause))) || + (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sc->anonymity))) + { + GNUNET_break (0); + goto cleanup; + } + sc->options = (enum GNUNET_FS_SearchOptions) options; + sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16); + dn = get_serialization_file_name_in_dir (h, + (sc->psearch_result == + NULL) ? + GNUNET_FS_SYNC_PATH_MASTER_SEARCH : + GNUNET_FS_SYNC_PATH_CHILD_SEARCH, + sc->serialization, ""); + if (dn != NULL) + { + if (GNUNET_YES == GNUNET_DISK_directory_test (dn)) + GNUNET_DISK_directory_scan (dn, &deserialize_search_result, sc); + GNUNET_free (dn); + } + if (('\0' == in_pause) && + (GNUNET_OK != GNUNET_FS_search_start_searching_ (sc))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Could not resume running search, will resume as paused search\n")); + } + signal_search_resume (sc); + GNUNET_free (uris); + return sc; +cleanup: + GNUNET_free_non_null (emsg); + free_search_context (sc); + GNUNET_free_non_null (uris); + return NULL; +} + + +/** + * Function called with a filename of serialized search operation + * to deserialize. + * + * @param cls the 'struct GNUNET_FS_Handle*' + * @param filename complete filename (absolute path) + * @return GNUNET_OK (continue to iterate) + */ +static int +deserialize_search_file (void *cls, const char *filename) +{ + struct GNUNET_FS_Handle *h = cls; + char *ser; + char *emsg; + struct GNUNET_BIO_ReadHandle *rh; + struct GNUNET_FS_SearchContext *sc; + struct stat buf; + + if (0 != STAT (filename, &buf)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename); + return GNUNET_OK; + } + if (S_ISDIR (buf.st_mode)) + return GNUNET_OK; /* skip directories */ + ser = get_serialization_short_name (filename); + rh = GNUNET_BIO_read_open (filename); + if (rh == NULL) + { + if (ser != NULL) + { + GNUNET_FS_remove_sync_file_ (h, GNUNET_FS_SYNC_PATH_MASTER_SEARCH, ser); + GNUNET_free (ser); + } + return GNUNET_OK; + } + sc = deserialize_search (h, rh, NULL, ser); + if (sc != NULL) + sc->top = GNUNET_FS_make_top (h, &GNUNET_FS_search_signal_suspend_, sc); + GNUNET_free (ser); + if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failure while resuming search operation `%s': %s\n"), + filename, emsg); + GNUNET_free (emsg); + } + return GNUNET_OK; +} + + +/** + * Function called with a filename of serialized download operation + * to deserialize. + * + * @param cls the 'struct GNUNET_FS_Handle*' + * @param filename complete filename (absolute path) + * @return GNUNET_OK (continue to iterate) + */ +static int +deserialize_download_file (void *cls, const char *filename) +{ + struct GNUNET_FS_Handle *h = cls; + char *ser; + char *emsg; + struct GNUNET_BIO_ReadHandle *rh; + + ser = get_serialization_short_name (filename); + rh = GNUNET_BIO_read_open (filename); + if (rh == NULL) + { + if (0 != UNLINK (filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); + GNUNET_free (ser); + return GNUNET_OK; + } + deserialize_download (h, rh, NULL, NULL, ser); + GNUNET_free (ser); + if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failure while resuming download operation `%s': %s\n"), + filename, emsg); + GNUNET_free (emsg); + } + return GNUNET_OK; +} + + +/** + * Deserialize informatin about pending operations. + * + * @param master_path which master directory should be scanned + * @param proc function to call for each entry (will get 'h' for 'cls') + * @param h the 'struct GNUNET_FS_Handle*' + */ +static void +deserialization_master (const char *master_path, GNUNET_FileNameCallback proc, + struct GNUNET_FS_Handle *h) +{ + char *dn; + + dn = get_serialization_file_name (h, master_path, ""); + if (dn == NULL) + return; + if (GNUNET_YES == GNUNET_DISK_directory_test (dn)) + GNUNET_DISK_directory_scan (dn, proc, h); + GNUNET_free (dn); +} + + +/** + * Setup a connection to the file-sharing service. + * + * @param cfg configuration to use + * @param client_name unique identifier for this client + * @param upcb function to call to notify about FS actions + * @param upcb_cls closure for upcb + * @param flags specific attributes for fs-operations + * @param ... list of optional options, terminated with GNUNET_FS_OPTIONS_END + * @return NULL on error + */ +struct GNUNET_FS_Handle * +GNUNET_FS_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *client_name, GNUNET_FS_ProgressCallback upcb, + void *upcb_cls, enum GNUNET_FS_Flags flags, ...) +{ + struct GNUNET_FS_Handle *ret; + enum GNUNET_FS_OPTIONS opt; + va_list ap; + + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Handle)); + ret->cfg = cfg; + ret->client_name = GNUNET_strdup (client_name); + ret->upcb = upcb; + ret->upcb_cls = upcb_cls; + ret->flags = flags; + ret->max_parallel_downloads = 1; + ret->max_parallel_requests = 1; + ret->avg_block_latency = GNUNET_TIME_UNIT_MINUTES; /* conservative starting point */ + va_start (ap, flags); + while (GNUNET_FS_OPTIONS_END != (opt = va_arg (ap, enum GNUNET_FS_OPTIONS))) + { + switch (opt) + { + case GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM: + ret->max_parallel_downloads = va_arg (ap, unsigned int); + + break; + case GNUNET_FS_OPTIONS_REQUEST_PARALLELISM: + ret->max_parallel_requests = va_arg (ap, unsigned int); + + break; + default: + GNUNET_break (0); + GNUNET_free (ret->client_name); + GNUNET_free (ret); + va_end (ap); + return NULL; + } + } + va_end (ap); + if (0 != (GNUNET_FS_FLAGS_PERSISTENCE & flags)) + { + deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, + &deserialize_publish_file, ret); + deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_SEARCH, + &deserialize_search_file, ret); + deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, + &deserialize_download_file, ret); + deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, + &deserialize_unindex_file, ret); + } + return ret; +} + + +/** + * Close our connection with the file-sharing service. + * The callback given to GNUNET_FS_start will no longer be + * called after this function returns. + * + * @param h handle that was returned from GNUNET_FS_start + */ +void +GNUNET_FS_stop (struct GNUNET_FS_Handle *h) +{ + while (h->top_head != NULL) + h->top_head->ssf (h->top_head->ssf_cls); + if (h->queue_job != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (h->queue_job); + GNUNET_free (h->client_name); + GNUNET_free (h); +} + + +/* end of fs.c */ diff --git a/src/fs/fs_api.h b/src/fs/fs_api.h new file mode 100644 index 0000000..de66ac6 --- /dev/null +++ b/src/fs/fs_api.h @@ -0,0 +1,1919 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_api.h + * @brief shared definitions for the FS library + * @author Igor Wronsky, Christian Grothoff + */ +#ifndef FS_API_H +#define FS_API_H + +#include "gnunet_constants.h" +#include "gnunet_datastore_service.h" +#include "gnunet_dht_service.h" +#include "gnunet_fs_service.h" +#include "gnunet_block_lib.h" +#include "block_fs.h" +#include "fs.h" + +/** + * Size of the individual blocks used for file-sharing. + */ +#define DBLOCK_SIZE (32*1024) + +/** + * Pick a multiple of 2 here to achive 8-byte alignment! We also + * probably want DBlocks to have (roughly) the same size as IBlocks. + * With SHA-512, the optimal value is 32768 byte / 128 byte = 256 (128 + * byte = 2 * 512 bits). DO NOT CHANGE! + */ +#define CHK_PER_INODE 256 + +/** + * Maximum size for a file to be considered for inlining in a + * directory. + */ +#define MAX_INLINE_SIZE 65536 + +/** + * Name of the directory with top-level searches. + */ +#define GNUNET_FS_SYNC_PATH_MASTER_SEARCH "search" + +/** + * Name of the directory with sub-searches (namespace-updates). + */ +#define GNUNET_FS_SYNC_PATH_CHILD_SEARCH "search-child" + +/** + * Name of the directory with master downloads (not associated + * with search or part of another download). + */ +#define GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD "download" + +/** + * Name of the directory with downloads that are part of another + * download or a search. + */ +#define GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD "download-child" + +/** + * Name of the directory with publishing operations. + */ +#define GNUNET_FS_SYNC_PATH_MASTER_PUBLISH "publish" + +/** + * Name of the directory with files that are being published + */ +#define GNUNET_FS_SYNC_PATH_FILE_INFO "publish-file" + +/** + * Name of the directory with unindex operations. + */ +#define GNUNET_FS_SYNC_PATH_MASTER_UNINDEX "unindex" + + +/** + * @brief complete information needed + * to download a file. + */ +struct FileIdentifier +{ + + /** + * Total size of the file in bytes. (network byte order (!)) + */ + uint64_t file_length; + + /** + * Query and key of the top GNUNET_EC_IBlock. + */ + struct ContentHashKey chk; + +}; + + +/** + * Information about a file and its location + * (peer claiming to share the file). + */ +struct Location +{ + /** + * Information about the shared file. + */ + struct FileIdentifier fi; + + /** + * Identity of the peer sharing the file. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded peer; + + /** + * Time when this location URI expires. + */ + struct GNUNET_TIME_Absolute expirationTime; + + /** + * RSA signature over the GNUNET_EC_FileIdentifier, + * GNUNET_hash of the peer and expiration time. + */ + struct GNUNET_CRYPTO_RsaSignature contentSignature; + +}; + +/** + * Types of URIs. + */ +enum uri_types +{ + /** + * Content-hash-key (simple file). + */ + chk, + + /** + * Signed key space (file in namespace). + */ + sks, + + /** + * Keyword search key (query with keywords). + */ + ksk, + + /** + * Location (chk with identity of hosting peer). + */ + loc +}; + +/** + * A Universal Resource Identifier (URI), opaque. + */ +struct GNUNET_FS_Uri +{ + /** + * Type of the URI. + */ + enum uri_types type; + + union + { + struct + { + /** + * Keywords start with a '+' if they are + * mandatory (in which case the '+' is NOT + * part of the keyword) and with a + * simple space if they are optional + * (in which case the space is ALSO not + * part of the actual keyword). + * + * Double-quotes to protect spaces and + * %-encoding are NOT used internally + * (only in URI-strings). + */ + char **keywords; + + /** + * Size of the keywords array. + */ + unsigned int keywordCount; + } ksk; + + struct + { + /** + * Hash of the public key for the namespace. + */ + GNUNET_HashCode namespace; + + /** + * Human-readable identifier chosen for this + * entry in the namespace. + */ + char *identifier; + } sks; + + /** + * Information needed to retrieve a file (content-hash-key + * plus file size). + */ + struct FileIdentifier chk; + + /** + * Information needed to retrieve a file including signed + * location (identity of a peer) of the content. + */ + struct Location loc; + } data; + +}; + + +/** + * Information for a file or directory that is + * about to be published. + */ +struct GNUNET_FS_FileInformation +{ + + /** + * Files in a directory are kept as a linked list. + */ + struct GNUNET_FS_FileInformation *next; + + /** + * If this is a file in a directory, "dir" refers to + * the directory; otherwise NULL. + */ + struct GNUNET_FS_FileInformation *dir; + + /** + * Handle to the master context. + */ + struct GNUNET_FS_Handle *h; + + /** + * Pointer kept for the client. + */ + void *client_info; + + /** + * Metadata to use for the file. + */ + struct GNUNET_CONTAINER_MetaData *meta; + + /** + * Keywords to use for KBlocks. + */ + struct GNUNET_FS_Uri *keywords; + + /** + * CHK for this file or directory. NULL if + * we have not yet computed it. + */ + struct GNUNET_FS_Uri *chk_uri; + + /** + * Block options for the file. + */ + struct GNUNET_FS_BlockOptions bo; + + /** + * At what time did we start this upload? + */ + struct GNUNET_TIME_Absolute start_time; + + /** + * Under what filename is this struct serialized + * (for operational persistence). Should be determined + * using 'mktemp'. + */ + char *serialization; + + /** + * Encoder being used to publish this file. + */ + struct GNUNET_FS_TreeEncoder *te; + + /** + * Error message (non-NULL if this operation failed). + */ + char *emsg; + + /** + * Name of the file or directory (must be an absolute path). + */ + char *filename; + + /** + * Data describing either the file or the directory. + */ + union + { + + /** + * Data for a file. + */ + struct + { + + /** + * Function that can be used to read the data for the file. + */ + GNUNET_FS_DataReader reader; + + /** + * Closure for reader. + */ + void *reader_cls; + + /** + * If this file is being indexed, this value is set to the hash + * over the entire file (when the indexing process is started). + * Otherwise this field is not used. + */ + GNUNET_HashCode file_id; + + /** + * Size of the file (in bytes). + */ + uint64_t file_size; + + /** + * Should the file be indexed or inserted? + */ + int do_index; + + /** + * Is "file_id" already valid? Set to GNUNET_YES once the hash + * has been calculated. + */ + int have_hash; + + /** + * Has the service confirmed our INDEX_START request? + * GNUNET_YES if this step has been completed. + */ + int index_start_confirmed; + + } file; + + /** + * Data for a directory. + */ + struct + { + + /** + * Linked list of entries in the directory. + */ + struct GNUNET_FS_FileInformation *entries; + + /** + * Size of the directory itself (in bytes); 0 if the + * size has not yet been calculated. + */ + size_t dir_size; + + /** + * Pointer to the data for the directory (or NULL if not + * available). + */ + void *dir_data; + + } dir; + + } data; + + /** + * Is this struct for a file or directory? + */ + int is_directory; + + /** + * Are we done publishing this file? + */ + int is_published; + +}; + + +/** + * The job is now ready to run and should use the given client + * handle to communicate with the FS service. + * + * @param cls closure + * @param client handle to use for FS communication + */ +typedef void (*GNUNET_FS_QueueStart) (void *cls, + struct GNUNET_CLIENT_Connection * client); + + +/** + * The job must now stop to run and should destry the client handle as + * soon as possible (ideally prior to returning). + */ +typedef void (*GNUNET_FS_QueueStop) (void *cls); + + +/** + * Entry in the job queue. + */ +struct GNUNET_FS_QueueEntry +{ + /** + * This is a linked list. + */ + struct GNUNET_FS_QueueEntry *next; + + /** + * This is a linked list. + */ + struct GNUNET_FS_QueueEntry *prev; + + /** + * Function to call when the job is started. + */ + GNUNET_FS_QueueStart start; + + /** + * Function to call when the job needs to stop (or is done / dequeued). + */ + GNUNET_FS_QueueStop stop; + + /** + * Closure for start and stop. + */ + void *cls; + + /** + * Handle to FS primary context. + */ + struct GNUNET_FS_Handle *h; + + /** + * Client handle, or NULL if job is not running. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Time the job was originally queued. + */ + struct GNUNET_TIME_Absolute queue_time; + + /** + * Time the job was started last. + */ + struct GNUNET_TIME_Absolute start_time; + + /** + * Total amount of time the job has been running (except for the + * current run). + */ + struct GNUNET_TIME_Relative run_time; + + /** + * How many blocks do the active downloads have? + */ + unsigned int blocks; + + /** + * How often have we (re)started this download? + */ + unsigned int start_times; + +}; + + + + +/** + * Information we store for each search result. + */ +struct GNUNET_FS_SearchResult +{ + + /** + * Search context this result belongs to. + */ + struct GNUNET_FS_SearchContext *sc; + + /** + * URI to which this search result refers to. + */ + struct GNUNET_FS_Uri *uri; + + /** + * Metadata for the search result. + */ + struct GNUNET_CONTAINER_MetaData *meta; + + /** + * Client info for this search result. + */ + void *client_info; + + /** + * ID of a job that is currently probing this results' availability + * (NULL if we are not currently probing). + */ + struct GNUNET_FS_DownloadContext *probe_ctx; + + /** + * ID of an associated download based on this search result (or + * NULL for none). + */ + struct GNUNET_FS_DownloadContext *download; + + /** + * If this search result triggered an update search, this field + * links to the update search. + */ + struct GNUNET_FS_SearchContext *update_search; + + /** + * Name under which this search result is stored on disk. + */ + char *serialization; + + /** + * Bitmap that specifies precisely which keywords have been matched already. + */ + uint8_t *keyword_bitmap; + + /** + * Key for the search result + */ + GNUNET_HashCode key; + + /** + * ID of the task that will clean up the probe_ctx should it not + * complete on time (and that will need to be cancelled if we clean + * up the search result before then). + */ + GNUNET_SCHEDULER_TaskIdentifier probe_cancel_task; + + /** + * When did the current probe become active? + */ + struct GNUNET_TIME_Absolute probe_active_time; + + /** + * How much longer should we run the current probe before giving up? + */ + struct GNUNET_TIME_Relative remaining_probe_time; + + /** + * Number of mandatory keywords for which we have NOT yet found the + * search result; when this value hits zero, the search result is + * given to the callback. + */ + uint32_t mandatory_missing; + + /** + * Number of optional keywords under which this result was also + * found. + */ + uint32_t optional_support; + + /** + * Number of availability tests that have succeeded for this result. + */ + uint32_t availability_success; + + /** + * Number of availability trials that we have performed for this + * search result. + */ + uint32_t availability_trials; + +}; + + +/** + * Add a job to the queue. + * + * @param h handle to the overall FS state + * @param start function to call to begin the job + * @param stop function to call to pause the job, or on dequeue (if the job was running) + * @param cls closure for start and stop + * @param blocks number of blocks this download has + * @return queue handle + */ +struct GNUNET_FS_QueueEntry * +GNUNET_FS_queue_ (struct GNUNET_FS_Handle *h, GNUNET_FS_QueueStart start, + GNUNET_FS_QueueStop stop, void *cls, unsigned int blocks); + + +/** + * Dequeue a job from the queue. + * @param qh handle for the job + */ +void +GNUNET_FS_dequeue_ (struct GNUNET_FS_QueueEntry *qh); + + +/** + * Function that provides data by reading from a file. + * + * @param cls closure (points to the file information) + * @param offset offset to read from; it is possible + * that the caller might need to go backwards + * a bit at times + * @param max maximum number of bytes that should be + * copied to buf; readers are not allowed + * to provide less data unless there is an error; + * a value of "0" will be used at the end to allow + * the reader to clean up its internal state + * @param buf where the reader should write the data + * @param emsg location for the reader to store an error message + * @return number of bytes written, usually "max", 0 on error + */ +size_t +GNUNET_FS_data_reader_file_ (void *cls, uint64_t offset, size_t max, void *buf, + char **emsg); + + +/** + * Create the closure for the 'GNUNET_FS_data_reader_file_' callback. + * + * @param filename file to read + * @return closure to use + */ +void * +GNUNET_FS_make_file_reader_context_ (const char *filename); + + + +/** + * Function that provides data by copying from a buffer. + * + * @param cls closure (points to the buffer) + * @param offset offset to read from; it is possible + * that the caller might need to go backwards + * a bit at times + * @param max maximum number of bytes that should be + * copied to buf; readers are not allowed + * to provide less data unless there is an error; + * a value of "0" will be used at the end to allow + * the reader to clean up its internal state + * @param buf where the reader should write the data + * @param emsg location for the reader to store an error message + * @return number of bytes written, usually "max", 0 on error + */ +size_t +GNUNET_FS_data_reader_copy_ (void *cls, uint64_t offset, size_t max, void *buf, + char **emsg); + +/** + * Notification of FS that a search probe has made progress. + * This function is used INSTEAD of the client's event handler + * for downloads where the GNUNET_FS_DOWNLOAD_IS_PROBE flag is set. + * + * @param cls closure, always NULL (!), actual closure + * is in the client-context of the info struct + * @param info details about the event, specifying the event type + * and various bits about the event + * @return client-context (for the next progress call + * for this operation; should be set to NULL for + * SUSPEND and STOPPED events). The value returned + * will be passed to future callbacks in the respective + * field in the GNUNET_FS_ProgressInfo struct. + */ +void * +GNUNET_FS_search_probe_progress_ (void *cls, + const struct GNUNET_FS_ProgressInfo *info); + + +/** + * Main function that performs the upload. + * + * @param cls "struct GNUNET_FS_PublishContext" identifies the upload + * @param tc task context + */ +void +GNUNET_FS_publish_main_ (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Function called once the hash of the file + * that is being unindexed has been computed. + * + * @param cls closure, unindex context + * @param file_id computed hash, NULL on error + */ +void +GNUNET_FS_unindex_process_hash_ (void *cls, const GNUNET_HashCode * file_id); + + +/** + * Fill in all of the generic fields for a publish event and call the + * callback. + * + * @param pi structure to fill in + * @param pc overall publishing context + * @param p file information for the file being published + * @param offset where in the file are we so far + * @return value returned from callback + */ +void * +GNUNET_FS_publish_make_status_ (struct GNUNET_FS_ProgressInfo *pi, + struct GNUNET_FS_PublishContext *pc, + const struct GNUNET_FS_FileInformation *p, + uint64_t offset); + + +/** + * Fill in all of the generic fields for a download event and call the + * callback. + * + * @param pi structure to fill in + * @param dc overall download context + */ +void +GNUNET_FS_download_make_status_ (struct GNUNET_FS_ProgressInfo *pi, + struct GNUNET_FS_DownloadContext *dc); + + +/** + * Task that creates the initial (top-level) download + * request for the file. + * + * @param cls the 'struct GNUNET_FS_DownloadContext' + * @param tc scheduler context + */ +void +GNUNET_FS_download_start_task_ (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + + +/** + * Fill in all of the generic fields for + * an unindex event and call the callback. + * + * @param pi structure to fill in + * @param uc overall unindex context + * @param offset where we are in the file (for progress) + */ +void +GNUNET_FS_unindex_make_status_ (struct GNUNET_FS_ProgressInfo *pi, + struct GNUNET_FS_UnindexContext *uc, + uint64_t offset); + +/** + * Fill in all of the generic fields for a search event and + * call the callback. + * + * @param pi structure to fill in + * @param sc overall search context + * @return value returned by the callback + */ +void * +GNUNET_FS_search_make_status_ (struct GNUNET_FS_ProgressInfo *pi, + struct GNUNET_FS_SearchContext *sc); + + +/** + * Connect to the datastore and remove the blocks. + * + * @param uc context for the unindex operation. + */ +void +GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc); + +/** + * Build the request and actually initiate the search using the + * GNUnet FS service. + * + * @param sc search context + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc); + +/** + * Start the downloading process (by entering the queue). + * + * @param dc our download context + */ +void +GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc); + + +/** + * Start download probes for the given search result. + * + * @param sr the search result + */ +void +GNUNET_FS_search_start_probe_ (struct GNUNET_FS_SearchResult *sr); + +/** + * Remove serialization/deserialization file from disk. + * + * @param h master context + * @param ext component of the path + * @param ent entity identifier + */ +void +GNUNET_FS_remove_sync_file_ (struct GNUNET_FS_Handle *h, const char *ext, + const char *ent); + + +/** + * Remove serialization/deserialization directory from disk. + * + * @param h master context + * @param ext component of the path + * @param uni unique name of parent + */ +void +GNUNET_FS_remove_sync_dir_ (struct GNUNET_FS_Handle *h, const char *ext, + const char *uni); + + +/** + * Synchronize this file-information struct with its mirror + * on disk. Note that all internal FS-operations that change + * file information data should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param fi the struct to sync + */ +void +GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *f); + +/** + * Synchronize this publishing struct with its mirror + * on disk. Note that all internal FS-operations that change + * publishing structs should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param pc the struct to sync + */ +void +GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc); + +/** + * Synchronize this unindex struct with its mirror + * on disk. Note that all internal FS-operations that change + * publishing structs should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param uc the struct to sync + */ +void +GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc); + +/** + * Synchronize this search struct with its mirror + * on disk. Note that all internal FS-operations that change + * publishing structs should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param sc the struct to sync + */ +void +GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc); + +/** + * Synchronize this search result with its mirror + * on disk. Note that all internal FS-operations that change + * publishing structs should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param sr the struct to sync + */ +void +GNUNET_FS_search_result_sync_ (struct GNUNET_FS_SearchResult *sr); + +/** + * Synchronize this download struct with its mirror + * on disk. Note that all internal FS-operations that change + * publishing structs should already call "sync" internally, + * so this function is likely not useful for clients. + * + * @param dc the struct to sync + */ +void +GNUNET_FS_download_sync_ (struct GNUNET_FS_DownloadContext *dc); + +/** + * Create SUSPEND event for the given publish operation + * and then clean up our state (without stop signal). + * + * @param cls the 'struct GNUNET_FS_PublishContext' to signal for + */ +void +GNUNET_FS_publish_signal_suspend_ (void *cls); + +/** + * Create SUSPEND event for the given search operation + * and then clean up our state (without stop signal). + * + * @param cls the 'struct GNUNET_FS_SearchContext' to signal for + */ +void +GNUNET_FS_search_signal_suspend_ (void *cls); + +/** + * Create SUSPEND event for the given download operation + * and then clean up our state (without stop signal). + * + * @param cls the 'struct GNUNET_FS_DownloadContext' to signal for + */ +void +GNUNET_FS_download_signal_suspend_ (void *cls); + +/** + * Create SUSPEND event for the given unindex operation + * and then clean up our state (without stop signal). + * + * @param cls the 'struct GNUNET_FS_UnindexContext' to signal for + */ +void +GNUNET_FS_unindex_signal_suspend_ (void *cls); + +/** + * Function signature of the functions that can be called + * to trigger suspend signals and clean-up for top-level + * activities. + * + * @param cls closure + */ +typedef void (*SuspendSignalFunction) (void *cls); + +/** + * We track all of the top-level activities of FS + * so that we can signal 'suspend' on shutdown. + */ +struct TopLevelActivity +{ + /** + * This is a doubly-linked list. + */ + struct TopLevelActivity *next; + + /** + * This is a doubly-linked list. + */ + struct TopLevelActivity *prev; + + /** + * Function to call for suspend-signalling and clean up. + */ + SuspendSignalFunction ssf; + + /** + * Closure for 'ssf' (some struct GNUNET_FS_XXXHandle*) + */ + void *ssf_cls; +}; + + +/** + * Create a top-level activity entry. + * + * @param h global fs handle + * @param ssf suspend signal function to use + * @param ssf_cls closure for ssf + * @return fresh top-level activity handle + */ +struct TopLevelActivity * +GNUNET_FS_make_top (struct GNUNET_FS_Handle *h, SuspendSignalFunction ssf, + void *ssf_cls); + + +/** + * Destroy a top-level activity entry. + * + * @param h global fs handle + * @param top top level activity entry + */ +void +GNUNET_FS_end_top (struct GNUNET_FS_Handle *h, struct TopLevelActivity *top); + + + +/** + * Master context for most FS operations. + */ +struct GNUNET_FS_Handle +{ + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Name of our client. + */ + char *client_name; + + /** + * Function to call with updates on our progress. + */ + GNUNET_FS_ProgressCallback upcb; + + /** + * Closure for upcb. + */ + void *upcb_cls; + + /** + * Head of DLL of top-level activities. + */ + struct TopLevelActivity *top_head; + + /** + * Tail of DLL of top-level activities. + */ + struct TopLevelActivity *top_tail; + + /** + * Head of DLL of running jobs. + */ + struct GNUNET_FS_QueueEntry *running_head; + + /** + * Tail of DLL of running jobs. + */ + struct GNUNET_FS_QueueEntry *running_tail; + + /** + * Head of DLL of pending jobs. + */ + struct GNUNET_FS_QueueEntry *pending_head; + + /** + * Tail of DLL of pending jobs. + */ + struct GNUNET_FS_QueueEntry *pending_tail; + + /** + * Task that processes the jobs in the running and pending queues + * (and moves jobs around as needed). + */ + GNUNET_SCHEDULER_TaskIdentifier queue_job; + + /** + * Average time we take for a single request to be satisfied. + * FIXME: not yet calcualted properly... + */ + struct GNUNET_TIME_Relative avg_block_latency; + + /** + * How many actual downloads do we have running right now? + */ + unsigned int active_downloads; + + /** + * How many blocks do the active downloads have? + */ + unsigned int active_blocks; + + /** + * General flags. + */ + enum GNUNET_FS_Flags flags; + + /** + * Maximum number of parallel downloads. + */ + unsigned int max_parallel_downloads; + + /** + * Maximum number of parallel requests. + */ + unsigned int max_parallel_requests; + +}; + + +/** + * Handle for controlling a publication process. + */ +struct GNUNET_FS_PublishContext +{ + /** + * Handle to the global fs context. + */ + struct GNUNET_FS_Handle *h; + + /** + * Our top-level activity entry (if we are top-level, otherwise NULL). + */ + struct TopLevelActivity *top; + + /** + * File-structure that is being shared. + */ + struct GNUNET_FS_FileInformation *fi; + + /** + * Namespace that we are publishing in, NULL if we have no namespace. + */ + struct GNUNET_FS_Namespace *namespace; + + /** + * ID of the content in the namespace, NULL if we have no namespace. + */ + char *nid; + + /** + * ID for future updates, NULL if we have no namespace or no updates. + */ + char *nuid; + + /** + * Filename used for serializing information about this operation + * (should be determined using 'mktemp'). + */ + char *serialization; + + /** + * Our own client handle for the FS service; only briefly used when + * we start to index a file, otherwise NULL. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Current position in the file-tree for the upload. + */ + struct GNUNET_FS_FileInformation *fi_pos; + + /** + * Non-null if we are currently hashing a file. + */ + struct GNUNET_CRYPTO_FileHashContext *fhc; + + /** + * Connection to the datastore service. + */ + struct GNUNET_DATASTORE_Handle *dsh; + + /** + * Queue entry for reservation/unreservation. + */ + struct GNUNET_DATASTORE_QueueEntry *qre; + + /** + * Context for SKS publishing operation that is part of this publishing operation + * (NULL if not active). + */ + struct GNUNET_FS_PublishSksContext *sks_pc; + + /** + * Context for KSK publishing operation that is part of this publishing operation + * (NULL if not active). + */ + struct GNUNET_FS_PublishKskContext *ksk_pc; + + /** + * ID of the task performing the upload. NO_TASK if the upload has + * completed. + */ + GNUNET_SCHEDULER_TaskIdentifier upload_task; + + /** + * Storage space to reserve for the operation. + */ + uint64_t reserve_space; + + /** + * Overall number of entries to reserve for the + * publish operation. + */ + uint32_t reserve_entries; + + /** + * Options for publishing. + */ + enum GNUNET_FS_PublishOptions options; + + /** + * Space reservation ID with datastore service + * for this upload. + */ + int rid; + + /** + * Set to GNUNET_YES if all processing has completed. + */ + int all_done; + + /** + * Flag set to GNUNET_YES if the next callback from + * GNUNET_FS_file_information_inspect should be skipped because it + * is for the directory which was already processed with the parent. + */ + int skip_next_fi_callback; +}; + + +/** + * Phases of unindex processing (state machine). + */ +enum UnindexState +{ + /** + * We're currently hashing the file. + */ + UNINDEX_STATE_HASHING = 0, + + /** + * We're telling the datastore to delete + * the respective entries. + */ + UNINDEX_STATE_DS_REMOVE = 1, + + /** + * We're notifying the FS service about + * the unindexing. + */ + UNINDEX_STATE_FS_NOTIFY = 2, + + /** + * We're done. + */ + UNINDEX_STATE_COMPLETE = 3, + + /** + * We've encountered a fatal error. + */ + UNINDEX_STATE_ERROR = 4 +}; + + +/** + * Handle for controlling an unindexing operation. + */ +struct GNUNET_FS_UnindexContext +{ + + /** + * Global FS context. + */ + struct GNUNET_FS_Handle *h; + + /** + * Our top-level activity entry. + */ + struct TopLevelActivity *top; + + /** + * Name of the file that we are unindexing. + */ + char *filename; + + /** + * Short name under which we are serializing the state of this operation. + */ + char *serialization; + + /** + * Connection to the FS service, only valid during the + * UNINDEX_STATE_FS_NOTIFY phase. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Connection to the datastore service, only valid during the + * UNINDEX_STATE_DS_NOTIFY phase. + */ + struct GNUNET_DATASTORE_Handle *dsh; + + /** + * Pointer kept for the client. + */ + void *client_info; + + /** + * Merkle-ish tree encoder context. + */ + struct GNUNET_FS_TreeEncoder *tc; + + /** + * Handle used to read the file. + */ + struct GNUNET_DISK_FileHandle *fh; + + /** + * Error message, NULL on success. + */ + char *emsg; + + /** + * Context for hashing of the file. + */ + struct GNUNET_CRYPTO_FileHashContext *fhc; + + /** + * Overall size of the file. + */ + uint64_t file_size; + + /** + * When did we start? + */ + struct GNUNET_TIME_Absolute start_time; + + /** + * Hash of the file's contents (once computed). + */ + GNUNET_HashCode file_id; + + /** + * Current operatinonal phase. + */ + enum UnindexState state; + +}; + + +/** + * Information we keep for each keyword in + * a keyword search. + */ +struct SearchRequestEntry +{ + /** + * Hash of the original keyword, also known as the + * key (for decrypting the KBlock). + */ + GNUNET_HashCode key; + + /** + * Hash of the public key, also known as the query. + */ + GNUNET_HashCode query; + + /** + * Map that contains a "struct GNUNET_FS_SearchResult" for each result that + * was found under this keyword. Note that the entries will point + * to the same locations as those in the master result map (in + * "struct GNUNET_FS_SearchContext"), so they should not be freed. + * The key for each entry is the XOR of the key and query in the CHK + * URI (as a unique identifier for the search result). + */ + struct GNUNET_CONTAINER_MultiHashMap *results; + + /** + * Is this keyword a mandatory keyword + * (started with '+')? + */ + int mandatory; + +}; + + +/** + * Handle for controlling a search. + */ +struct GNUNET_FS_SearchContext +{ + /** + * Handle to the global FS context. + */ + struct GNUNET_FS_Handle *h; + + /** + * Our top-level activity entry (if we are top-level, otherwise NULL). + */ + struct TopLevelActivity *top; + + /** + * List of keywords that we're looking for. + */ + struct GNUNET_FS_Uri *uri; + + /** + * For update-searches, link to the search result that triggered + * the update search; otherwise NULL. + */ + struct GNUNET_FS_SearchResult *psearch_result; + + /** + * Connection to the FS service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Pointer we keep for the client. + */ + void *client_info; + + /** + * Name of the file on disk we use for persistence. + */ + char *serialization; + + /** + * Error message (non-NULL if this operation failed). + */ + char *emsg; + + /** + * Map that contains a "struct GNUNET_FS_SearchResult" for each result that + * was found in the search. The key for each entry is the XOR of + * the key and query in the CHK URI (as a unique identifier for the + * search result). + */ + struct GNUNET_CONTAINER_MultiHashMap *master_result_map; + + /** + * Per-keyword information for a keyword search. This array will + * have exactly as many entries as there were keywords. + */ + struct SearchRequestEntry *requests; + + /** + * When did we start? + */ + struct GNUNET_TIME_Absolute start_time; + + /** + * ID of a task that is using this struct and that must be cancelled + * when the search is being stopped (if not + * GNUNET_SCHEDULER_NO_TASK). Used for the task that adds some + * artificial delay when trying to reconnect to the FS service. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * How many of the entries in the search request + * map have been passed to the service so far? + */ + unsigned int search_request_map_offset; + + /** + * How many of the keywords in the KSK + * map have been passed to the service so far? + */ + unsigned int keyword_offset; + + /** + * Anonymity level for the search. + */ + uint32_t anonymity; + + /** + * Number of mandatory keywords in this query. + */ + uint32_t mandatory_count; + + /** + * Options for the search. + */ + enum GNUNET_FS_SearchOptions options; +}; + + +/** + * FSM for possible states a block can go through. The typical + * order of progression is linear through the states, alternatives + * are documented in the comments. + */ +enum BlockRequestState +{ + /** + * Initial state, block has only been allocated (since it is + * relevant to the overall download request). + */ + BRS_INIT = 0, + + /** + * We've checked the block on the path down the tree, and the + * content on disk did match the desired CHK, but not all + * the way down, so at the bottom some blocks will still + * need to be reconstructed). + */ + BRS_RECONSTRUCT_DOWN = 1, + + /** + * We've calculated the CHK bottom-up based on the meta data. + * This may work, but if it did we have to write the meta data to + * disk at the end (and we still need to check against the + * CHK set on top). + */ + BRS_RECONSTRUCT_META_UP = 2, + + /** + * We've calculated the CHK bottom-up based on what we have on + * disk, which may not be what the desired CHK is. If the + * reconstructed CHKs match whatever comes from above, we're + * done with the respective subtree. + */ + BRS_RECONSTRUCT_UP = 3, + + /** + * We've determined the real, desired CHK for this block + * (full tree reconstruction failed), request is now pending. + * If the CHK that bubbled up through reconstruction did match + * the top-level request, the state machine for the subtree + * would have moved to BRS_DOWNLOAD_UP. + */ + BRS_CHK_SET = 4, + + /** + * We've successfully downloaded this block, but the children + * still need to be either downloaded or verified (download + * request propagates down). If the download fails, the + * state machine for this block may move to + * BRS_DOWNLOAD_ERROR instead. + */ + BRS_DOWNLOAD_DOWN = 5, + + /** + * This block and all of its children have been downloaded + * successfully (full completion propagates up). + */ + BRS_DOWNLOAD_UP = 6, + + /** + * We got a block back that matched the query but did not hash to + * the key (malicious publisher or hash collision); this block + * can never be downloaded (error propagates up). + */ + BRS_ERROR = 7 +}; + + +/** + * Information about an active download request. + */ +struct DownloadRequest +{ + /** + * While pending, we keep all download requests in a doubly-linked list. + */ + struct DownloadRequest *next; + + /** + * While pending, we keep all download requests in a doubly-linked list. + */ + struct DownloadRequest *prev; + + /** + * Parent in the CHK-tree. + */ + struct DownloadRequest *parent; + + /** + * Array (!) of child-requests, or NULL for the bottom of the tree. + */ + struct DownloadRequest **children; + + /** + * CHK for the request for this block (set during reconstruction + * to what we have on disk, later to what we want to have). + */ + struct ContentHashKey chk; + + /** + * Offset of the corresponding block. Specifically, first (!) byte of + * the first DBLOCK in the subtree induced by block represented by + * this request. + */ + uint64_t offset; + + /** + * Number of entries in 'children' array. + */ + unsigned int num_children; + + /** + * Depth of the corresponding block in the tree. 0==DBLOCKs. + */ + unsigned int depth; + + /** + * State in the FSM. + */ + enum BlockRequestState state; + + /** + * GNUNET_YES if this entry is in the pending list. + */ + int is_pending; + +}; + + +/** + * (recursively) free download request structure + * + * @param dr request to free + */ +void +GNUNET_FS_free_download_request_ (struct DownloadRequest *dr); + + +/** + * Context for controlling a download. + */ +struct GNUNET_FS_DownloadContext +{ + + /** + * Global FS context. + */ + struct GNUNET_FS_Handle *h; + + /** + * Our top-level activity entry (if we are top-level, otherwise NULL). + */ + struct TopLevelActivity *top; + + /** + * Connection to the FS service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Parent download (used when downloading files + * in directories). + */ + struct GNUNET_FS_DownloadContext *parent; + + /** + * Associated search (used when downloading files + * based on search results), or NULL for none. + */ + struct GNUNET_FS_SearchResult *search; + + /** + * Head of list of child downloads. + */ + struct GNUNET_FS_DownloadContext *child_head; + + /** + * Tail of list of child downloads. + */ + struct GNUNET_FS_DownloadContext *child_tail; + + /** + * Previous download belonging to the same parent. + */ + struct GNUNET_FS_DownloadContext *prev; + + /** + * Next download belonging to the same parent. + */ + struct GNUNET_FS_DownloadContext *next; + + /** + * Context kept for the client. + */ + void *client_info; + + /** + * URI that identifies the file that we are downloading. + */ + struct GNUNET_FS_Uri *uri; + + /** + * Known meta-data for the file (can be NULL). + */ + struct GNUNET_CONTAINER_MetaData *meta; + + /** + * Error message, NULL if we're doing OK. + */ + char *emsg; + + /** + * Random portion of filename we use for syncing state of this + * download. + */ + char *serialization; + + /** + * Where are we writing the data (name of the + * file, can be NULL!). + */ + char *filename; + + /** + * Where are we writing the data temporarily (name of the + * file, can be NULL!); used if we do not have a permanent + * name and we are a directory and we do a recursive download. + */ + char *temp_filename; + + /** + * Our entry in the job queue. + */ + struct GNUNET_FS_QueueEntry *job_queue; + + /** + * Non-NULL if we are currently having a request for + * transmission pending with the client handle. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Tree encoder used for the reconstruction. + */ + struct GNUNET_FS_TreeEncoder *te; + + /** + * File handle for reading data from an existing file + * (to pass to tree encoder). + */ + struct GNUNET_DISK_FileHandle *rfh; + + /** + * Map of active requests (those waiting for a response). The key + * is the hash of the encryped block (aka query). + */ + struct GNUNET_CONTAINER_MultiHashMap *active; + + /** + * Head of linked list of pending requests. + */ + struct DownloadRequest *pending_head; + + /** + * Head of linked list of pending requests. + */ + struct DownloadRequest *pending_tail; + + /** + * Top-level download request. + */ + struct DownloadRequest *top_request; + + /** + * Identity of the peer having the content, or all-zeros + * if we don't know of such a peer. + */ + struct GNUNET_PeerIdentity target; + + /** + * ID of a task that is using this struct and that must be cancelled + * when the download is being stopped (if not + * GNUNET_SCHEDULER_NO_TASK). Used for the task that adds some + * artificial delay when trying to reconnect to the FS service or + * the task processing incrementally the data on disk, or the + * task requesting blocks, etc. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * What is the first offset that we're interested + * in? + */ + uint64_t offset; + + /** + * How many bytes starting from offset are desired? + * This is NOT the overall length of the file! + */ + uint64_t length; + + /** + * How many bytes have we already received within + * the specified range (DBlocks only). + */ + uint64_t completed; + + /** + * What was the size of the file on disk that we're downloading + * before we started? Used to detect if there is a point in + * checking an existing block on disk for matching the desired + * content. 0 if the file did not exist already. + */ + uint64_t old_file_size; + + /** + * Time download was started. + */ + struct GNUNET_TIME_Absolute start_time; + + /** + * Desired level of anonymity. + */ + uint32_t anonymity; + + /** + * The depth of the file-tree. + */ + unsigned int treedepth; + + /** + * Options for the download. + */ + enum GNUNET_FS_DownloadOptions options; + + /** + * Flag set upon transitive completion (includes child downloads). + * This flag is only set to GNUNET_YES for directories where all + * child-downloads have also completed (and signalled completion). + */ + int has_finished; + + /** + * Have we started the receive continuation yet? + */ + int in_receive; + +}; + + +/** + * Information about an (updateable) node in the + * namespace. + */ +struct NamespaceUpdateNode +{ + /** + * Identifier for this node. + */ + char *id; + + /** + * Identifier of children of this node. + */ + char *update; + + /** + * Metadata for this entry. + */ + struct GNUNET_CONTAINER_MetaData *md; + + /** + * URI of this entry in the namespace. + */ + struct GNUNET_FS_Uri *uri; + + /** + * Namespace update generation ID. Used to ensure + * freshness of the tree_id. + */ + unsigned int nug; + + /** + * TREE this entry belongs to (if nug is current). + */ + unsigned int tree_id; + +}; + + +struct GNUNET_FS_Namespace +{ + + /** + * Handle to the FS service context. + */ + struct GNUNET_FS_Handle *h; + + /** + * Array with information about nodes in the namespace. + */ + struct NamespaceUpdateNode **update_nodes; + + /** + * Private key for the namespace. + */ + struct GNUNET_CRYPTO_RsaPrivateKey *key; + + /** + * Hash map mapping identifiers of update nodes + * to the update nodes (initialized on-demand). + */ + struct GNUNET_CONTAINER_MultiHashMap *update_map; + + /** + * Name of the file with the private key. + */ + char *filename; + + /** + * Name of the namespace. + */ + char *name; + + /** + * Size of the update nodes array. + */ + unsigned int update_node_count; + + /** + * Reference counter. + */ + unsigned int rc; + + /** + * Generator for unique nug numbers. + */ + unsigned int nug_gen; +}; + +#endif + +/* end of fs_api.h */ diff --git a/src/fs/fs_directory.c b/src/fs/fs_directory.c new file mode 100644 index 0000000..b26ec12 --- /dev/null +++ b/src/fs/fs_directory.c @@ -0,0 +1,644 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_directory.c + * @brief Helper functions for building directories. + * @author Christian Grothoff + * + * TODO: + * - modify directory builder API to support incremental + * generation of directories (to allow directories that + * would not fit into memory to be created) + * - modify directory processor API to support incremental + * iteration over FULL directories (without missing entries) + * to allow access to directories that do not fit entirely + * into memory + */ +#include "platform.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" + +/** + * String that is used to indicate that a file + * is a GNUnet directory. + */ +#define GNUNET_DIRECTORY_MAGIC "\211GND\r\n\032\n" + + +/** + * Does the meta-data claim that this is a directory? + * Checks if the mime-type is that of a GNUnet directory. + * + * @return GNUNET_YES if it is, GNUNET_NO if it is not, GNUNET_SYSERR if + * we have no mime-type information (treat as 'GNUNET_NO') + */ +int +GNUNET_FS_meta_data_test_for_directory (const struct GNUNET_CONTAINER_MetaData + *md) +{ + char *mime; + int ret; + + if (NULL == md) + return GNUNET_SYSERR; + mime = + GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE); + if (mime == NULL) + return GNUNET_SYSERR; + ret = (0 == strcmp (mime, GNUNET_FS_DIRECTORY_MIME)) ? GNUNET_YES : GNUNET_NO; + GNUNET_free (mime); + return ret; +} + + +/** + * Set the MIMETYPE information for the given + * metadata to "application/gnunet-directory". + * + * @param md metadata to add mimetype to + */ +void +GNUNET_FS_meta_data_make_directory (struct GNUNET_CONTAINER_MetaData *md) +{ + char *mime; + + mime = + GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE); + if (mime != NULL) + { + GNUNET_break (0 == strcmp (mime, GNUNET_FS_DIRECTORY_MIME)); + GNUNET_free (mime); + return; + } + GNUNET_CONTAINER_meta_data_insert (md, "", + EXTRACTOR_METATYPE_MIMETYPE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + GNUNET_FS_DIRECTORY_MIME, + strlen (GNUNET_FS_DIRECTORY_MIME) + 1); +} + + +/** + * Closure for 'find_full_data'. + */ +struct GetFullDataClosure +{ + + /** + * Extracted binary meta data. + */ + void *data; + + /** + * Number of bytes stored in data. + */ + size_t size; +}; + + +/** + * Type of a function that libextractor calls for each + * meta data item found. + * + * @param cls closure (user-defined) + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_len number of bytes in data + * @return 0 to continue extracting, 1 to abort + */ +static int +find_full_data (void *cls, const char *plugin_name, + enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, + const char *data_mime_type, const char *data, size_t data_len) +{ + struct GetFullDataClosure *gfdc = cls; + + if (type == EXTRACTOR_METATYPE_GNUNET_FULL_DATA) + { + gfdc->size = data_len; + if (data_len > 0) + { + gfdc->data = GNUNET_malloc (data_len); + memcpy (gfdc->data, data, data_len); + } + return 1; + } + return 0; +} + + +/** + * Iterate over all entries in a directory. Note that directories + * are structured such that it is possible to iterate over the + * individual blocks as well as over the entire directory. Thus + * a client can call this function on the buffer in the + * GNUNET_FS_ProgressCallback. Also, directories can optionally + * include the contents of (small) files embedded in the directory + * itself; for those files, the processor may be given the + * contents of the file directly by this function. + *

+ * + * Note that this function maybe called on parts of directories. Thus + * parser errors should not be reported _at all_ (with GNUNET_break). + * Still, if some entries can be recovered despite these parsing + * errors, the function should try to do this. + * + * @param size number of bytes in data + * @param data pointer to the beginning of the directory + * @param offset offset of data in the directory + * @param dep function to call on each entry + * @param dep_cls closure for dep + * @return GNUNET_OK if this could be a block in a directory, + * GNUNET_NO if this could be part of a directory (but not 100% OK) + * GNUNET_SYSERR if 'data' does not represent a directory + */ +int +GNUNET_FS_directory_list_contents (size_t size, const void *data, + uint64_t offset, + GNUNET_FS_DirectoryEntryProcessor dep, + void *dep_cls) +{ + struct GetFullDataClosure full_data; + const char *cdata = data; + char *emsg; + uint64_t pos; + uint64_t align; + uint32_t mdSize; + uint64_t epos; + struct GNUNET_FS_Uri *uri; + struct GNUNET_CONTAINER_MetaData *md; + char *filename; + + if ((offset == 0) && + ((size < 8 + sizeof (uint32_t)) || + (0 != memcmp (cdata, GNUNET_FS_DIRECTORY_MAGIC, 8)))) + return GNUNET_SYSERR; + pos = offset; + if (offset == 0) + { + memcpy (&mdSize, &cdata[8], sizeof (uint32_t)); + mdSize = ntohl (mdSize); + if (mdSize > size - 8 - sizeof (uint32_t)) + { + /* invalid size */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("MAGIC mismatch. This is not a GNUnet directory.\n")); + return GNUNET_SYSERR; + } + md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[8 + sizeof (uint32_t)], + mdSize); + if (md == NULL) + { + GNUNET_break (0); + return GNUNET_SYSERR; /* malformed ! */ + } + dep (dep_cls, NULL, NULL, md, 0, NULL); + GNUNET_CONTAINER_meta_data_destroy (md); + pos = 8 + sizeof (uint32_t) + mdSize; + } + while (pos < size) + { + /* find end of URI */ + if (cdata[pos] == '\0') + { + /* URI is never empty, must be end of block, + * skip to next alignment */ + align = ((pos / DBLOCK_SIZE) + 1) * DBLOCK_SIZE; + if (align == pos) + { + /* if we were already aligned, still skip a block! */ + align += DBLOCK_SIZE; + } + pos = align; + if (pos >= size) + { + /* malformed - or partial download... */ + break; + } + } + epos = pos; + while ((epos < size) && (cdata[epos] != '\0')) + epos++; + if (epos >= size) + return GNUNET_NO; /* malformed - or partial download */ + + uri = GNUNET_FS_uri_parse (&cdata[pos], &emsg); + pos = epos + 1; + if (uri == NULL) + { + GNUNET_free (emsg); + pos--; /* go back to '\0' to force going to next alignment */ + continue; + } + if (GNUNET_FS_uri_test_ksk (uri)) + { + GNUNET_FS_uri_destroy (uri); + GNUNET_break (0); + return GNUNET_NO; /* illegal in directory! */ + } + + memcpy (&mdSize, &cdata[pos], sizeof (uint32_t)); + mdSize = ntohl (mdSize); + pos += sizeof (uint32_t); + if (pos + mdSize > size) + { + GNUNET_FS_uri_destroy (uri); + return GNUNET_NO; /* malformed - or partial download */ + } + + md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos], mdSize); + if (md == NULL) + { + GNUNET_FS_uri_destroy (uri); + GNUNET_break (0); + return GNUNET_NO; /* malformed ! */ + } + pos += mdSize; + filename = + GNUNET_CONTAINER_meta_data_get_by_type (md, + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); + full_data.size = 0; + full_data.data = NULL; + GNUNET_CONTAINER_meta_data_iterate (md, &find_full_data, &full_data); + if (dep != NULL) + { + dep (dep_cls, filename, uri, md, full_data.size, full_data.data); + } + GNUNET_free_non_null (full_data.data); + GNUNET_free_non_null (filename); + GNUNET_CONTAINER_meta_data_destroy (md); + GNUNET_FS_uri_destroy (uri); + } + return GNUNET_OK; +} + +/** + * Entries in the directory (builder). + */ +struct BuilderEntry +{ + /** + * This is a linked list. + */ + struct BuilderEntry *next; + + /** + * Length of this entry. + */ + size_t len; +}; + +/** + * Internal state of a directory builder. + */ +struct GNUNET_FS_DirectoryBuilder +{ + /** + * Meta-data for the directory itself. + */ + struct GNUNET_CONTAINER_MetaData *meta; + + /** + * Head of linked list of entries. + */ + struct BuilderEntry *head; + + /** + * Number of entires in the directory. + */ + unsigned int count; +}; + + +/** + * Create a directory builder. + * + * @param mdir metadata for the directory + */ +struct GNUNET_FS_DirectoryBuilder * +GNUNET_FS_directory_builder_create (const struct GNUNET_CONTAINER_MetaData + *mdir) +{ + struct GNUNET_FS_DirectoryBuilder *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_DirectoryBuilder)); + if (mdir != NULL) + ret->meta = GNUNET_CONTAINER_meta_data_duplicate (mdir); + else + ret->meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_FS_meta_data_make_directory (ret->meta); + return ret; +} + + +/** + * Add an entry to a directory. + * + * @param bld directory to extend + * @param uri uri of the entry (must not be a KSK) + * @param md metadata of the entry + * @param data raw data of the entry, can be NULL, otherwise + * data must point to exactly the number of bytes specified + * by the uri which must be of type LOC or CHK + */ +void +GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_CONTAINER_MetaData *md, + const void *data) +{ + struct GNUNET_FS_Uri *curi; + struct BuilderEntry *e; + uint64_t fsize; + uint32_t big; + ssize_t ret; + size_t mds; + size_t mdxs; + char *uris; + char *ser; + char *sptr; + size_t slen; + struct GNUNET_CONTAINER_MetaData *meta; + const struct GNUNET_CONTAINER_MetaData *meta_use; + + GNUNET_assert (!GNUNET_FS_uri_test_ksk (uri)); + if (NULL != data) + { + GNUNET_assert (!GNUNET_FS_uri_test_sks (uri)); + if (GNUNET_FS_uri_test_chk (uri)) + { + fsize = GNUNET_FS_uri_chk_get_file_size (uri); + } + else + { + curi = GNUNET_FS_uri_loc_get_uri (uri); + GNUNET_assert (NULL != curi); + fsize = GNUNET_FS_uri_chk_get_file_size (curi); + GNUNET_FS_uri_destroy (curi); + } + } + else + { + fsize = 0; /* not given */ + } + if (fsize > MAX_INLINE_SIZE) + fsize = 0; /* too large */ + uris = GNUNET_FS_uri_to_string (uri); + slen = strlen (uris) + 1; + mds = GNUNET_CONTAINER_meta_data_get_serialized_size (md); + meta_use = md; + meta = NULL; + if (fsize > 0) + { + meta = GNUNET_CONTAINER_meta_data_duplicate (md); + GNUNET_CONTAINER_meta_data_insert (meta, "", + EXTRACTOR_METATYPE_GNUNET_FULL_DATA, + EXTRACTOR_METAFORMAT_BINARY, NULL, data, + fsize); + mdxs = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); + if ((slen + sizeof (uint32_t) + mdxs - 1) / DBLOCK_SIZE == + (slen + sizeof (uint32_t) + mds - 1) / DBLOCK_SIZE) + { + /* adding full data would not cause us to cross + * additional blocks, so add it! */ + meta_use = meta; + mds = mdxs; + } + } + + if (mds > GNUNET_MAX_MALLOC_CHECKED / 2) + mds = GNUNET_MAX_MALLOC_CHECKED / 2; + e = GNUNET_malloc (sizeof (struct BuilderEntry) + slen + mds + + sizeof (uint32_t)); + ser = (char *) &e[1]; + memcpy (ser, uris, slen); + GNUNET_free (uris); + sptr = &ser[slen + sizeof (uint32_t)]; + ret = + GNUNET_CONTAINER_meta_data_serialize (meta_use, &sptr, mds, + GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); + if (NULL != meta) + GNUNET_CONTAINER_meta_data_destroy (meta); + if (ret == -1) + mds = 0; + else + mds = ret; + big = htonl (mds); + memcpy (&ser[slen], &big, sizeof (uint32_t)); + e->len = slen + sizeof (uint32_t) + mds; + e->next = bld->head; + bld->head = e; + bld->count++; +} + + +/** + * Given the start and end position of a block of + * data, return the end position of that data + * after alignment to the DBLOCK_SIZE. + */ +static size_t +do_align (size_t start_position, size_t end_position) +{ + size_t align; + + align = (end_position / DBLOCK_SIZE) * DBLOCK_SIZE; + if ((start_position < align) && (end_position > align)) + return align + end_position - start_position; + return end_position; +} + + +/** + * Compute a permuation of the blocks to + * minimize the cost of alignment. Greedy packer. + * + * @param start starting position for the first block + * @param count size of the two arrays + * @param sizes the sizes of the individual blocks + * @param perm the permutation of the blocks (updated) + */ +static void +block_align (size_t start, unsigned int count, const size_t * sizes, + unsigned int *perm) +{ + unsigned int i; + unsigned int j; + unsigned int tmp; + unsigned int best; + ssize_t badness; + size_t cpos; + size_t cend; + ssize_t cbad; + unsigned int cval; + + cpos = start; + for (i = 0; i < count; i++) + { + start = cpos; + badness = 0x7FFFFFFF; + best = -1; + for (j = i; j < count; j++) + { + cval = perm[j]; + cend = cpos + sizes[cval]; + if (cpos % DBLOCK_SIZE == 0) + { + /* prefer placing the largest blocks first */ + cbad = -(cend % DBLOCK_SIZE); + } + else + { + if (cpos / DBLOCK_SIZE == cend / DBLOCK_SIZE) + { + /* Data fits into the same block! Prefer small left-overs! */ + cbad = DBLOCK_SIZE - cend % DBLOCK_SIZE; + } + else + { + /* Would have to waste space to re-align, add big factor, this + * case is a real loss (proportional to space wasted)! */ + cbad = DBLOCK_SIZE * (DBLOCK_SIZE - cpos % DBLOCK_SIZE); + } + } + if (cbad < badness) + { + best = j; + badness = cbad; + } + } + GNUNET_assert (best != -1); + tmp = perm[i]; + perm[i] = perm[best]; + perm[best] = tmp; + cpos += sizes[perm[i]]; + cpos = do_align (start, cpos); + } +} + + +/** + * Finish building the directory. Frees the + * builder context and returns the directory + * in-memory. + * + * @param bld directory to finish + * @param rsize set to the number of bytes needed + * @param rdata set to the encoded directory + * @return GNUNET_OK on success + */ +int +GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld, + size_t * rsize, void **rdata) +{ + char *data; + char *sptr; + size_t *sizes; + unsigned int *perm; + unsigned int i; + unsigned int j; + struct BuilderEntry *pos; + struct BuilderEntry **bes; + size_t size; + size_t psize; + size_t off; + ssize_t ret; + uint32_t big; + + size = strlen (GNUNET_DIRECTORY_MAGIC) + sizeof (uint32_t); + size += GNUNET_CONTAINER_meta_data_get_serialized_size (bld->meta); + sizes = NULL; + perm = NULL; + bes = NULL; + if (0 < bld->count) + { + sizes = GNUNET_malloc (bld->count * sizeof (size_t)); + perm = GNUNET_malloc (bld->count * sizeof (unsigned int)); + bes = GNUNET_malloc (bld->count * sizeof (struct BuilderEntry *)); + pos = bld->head; + for (i = 0; i < bld->count; i++) + { + perm[i] = i; + bes[i] = pos; + sizes[i] = pos->len; + pos = pos->next; + } + block_align (size, bld->count, sizes, perm); + /* compute final size with alignment */ + for (i = 0; i < bld->count; i++) + { + psize = size; + size += sizes[perm[i]]; + size = do_align (psize, size); + } + } + *rsize = size; + data = GNUNET_malloc_large (size); + if (data == NULL) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "malloc"); + *rsize = 0; + *rdata = NULL; + GNUNET_free_non_null (sizes); + GNUNET_free_non_null (perm); + GNUNET_free_non_null (bes); + return GNUNET_SYSERR; + } + *rdata = data; + memcpy (data, GNUNET_DIRECTORY_MAGIC, strlen (GNUNET_DIRECTORY_MAGIC)); + off = strlen (GNUNET_DIRECTORY_MAGIC); + + sptr = &data[off + sizeof (uint32_t)]; + ret = + GNUNET_CONTAINER_meta_data_serialize (bld->meta, &sptr, + size - off - sizeof (uint32_t), + GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL); + GNUNET_assert (ret != -1); + big = htonl (ret); + memcpy (&data[off], &big, sizeof (uint32_t)); + off += sizeof (uint32_t) + ret; + for (j = 0; j < bld->count; j++) + { + i = perm[j]; + psize = off; + off += sizes[i]; + off = do_align (psize, off); + memcpy (&data[off - sizes[i]], &(bes[i])[1], sizes[i]); + GNUNET_free (bes[i]); + } + GNUNET_free_non_null (sizes); + GNUNET_free_non_null (perm); + GNUNET_free_non_null (bes); + GNUNET_assert (off == size); + GNUNET_CONTAINER_meta_data_destroy (bld->meta); + GNUNET_free (bld); + return GNUNET_OK; +} + + +/* end of fs_directory.c */ diff --git a/src/fs/fs_dirmetascan.c b/src/fs/fs_dirmetascan.c new file mode 100644 index 0000000..4e5354e --- /dev/null +++ b/src/fs/fs_dirmetascan.c @@ -0,0 +1,465 @@ +/* + This file is part of GNUnet + (C) 2005-2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_dirmetascan.c + * @brief code to asynchronously build a 'struct GNUNET_FS_ShareTreeItem' + * from an on-disk directory for publishing; use the 'gnunet-helper-fs-publish'. + * @author LRN + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_fs_service.h" +#include "gnunet_scheduler_lib.h" +#include + + +/** + * An opaque structure a pointer to which is returned to the + * caller to be used to control the scanner. + */ +struct GNUNET_FS_DirScanner +{ + + /** + * Helper process. + */ + struct GNUNET_HELPER_Handle *helper; + + /** + * Expanded filename (as given by the scan initiator). + * The scanner thread stores a copy here, and frees it when it finishes. + */ + char *filename_expanded; + + /** + * Second argument to helper process. + */ + char *ex_arg; + + /** + * The function that will be called every time there's a progress + * message. + */ + GNUNET_FS_DirScannerProgressCallback progress_callback; + + /** + * A closure for progress_callback. + */ + void *progress_callback_cls; + + /** + * After the scan is finished, it will contain a pointer to the + * top-level directory entry in the directory tree built by the + * scanner. + */ + struct GNUNET_FS_ShareTreeItem *toplevel; + + /** + * Current position during processing. + */ + struct GNUNET_FS_ShareTreeItem *pos; + + /** + * Task scheduled when we are done. + */ + GNUNET_SCHEDULER_TaskIdentifier stop_task; + + /** + * Arguments for helper. + */ + char *args[4]; + +}; + + + +/** + * Abort the scan. Must not be called from within the progress_callback + * function. + * + * @param ds directory scanner structure + */ +void +GNUNET_FS_directory_scan_abort (struct GNUNET_FS_DirScanner *ds) +{ + /* terminate helper */ + if (NULL != ds->helper) + GNUNET_HELPER_stop (ds->helper); + + /* free resources */ + if (NULL != ds->toplevel) + GNUNET_FS_share_tree_free (ds->toplevel); + if (GNUNET_SCHEDULER_NO_TASK != ds->stop_task) + GNUNET_SCHEDULER_cancel (ds->stop_task); + GNUNET_free_non_null (ds->ex_arg); + GNUNET_free (ds->filename_expanded); + GNUNET_free (ds); +} + + +/** + * Obtain the result of the scan after the scan has signalled + * completion. Must not be called prior to completion. The 'ds' is + * freed as part of this call. + * + * @param ds directory scanner structure + * @return the results of the scan (a directory tree) + */ +struct GNUNET_FS_ShareTreeItem * +GNUNET_FS_directory_scan_get_result (struct GNUNET_FS_DirScanner *ds) +{ + struct GNUNET_FS_ShareTreeItem *result; + + /* check that we're actually done */ + GNUNET_assert (NULL == ds->helper); + /* preserve result */ + result = ds->toplevel; + ds->toplevel = NULL; + GNUNET_FS_directory_scan_abort (ds); + return result; +} + + +/** + * Move in the directory from the given position to the next file + * in DFS traversal. + * + * @param pos current position + * @return next file, NULL for none + */ +static struct GNUNET_FS_ShareTreeItem * +advance (struct GNUNET_FS_ShareTreeItem *pos) +{ + int moved; + + GNUNET_assert (NULL != pos); + moved = 0; /* must not terminate, even on file, otherwise "normal" */ + while ( (pos->is_directory == GNUNET_YES) || + (0 == moved) ) + { + if ( (moved != -1) && + (NULL != pos->children_head) ) + { + pos = pos->children_head; + moved = 1; /* can terminate if file */ + continue; + } + if (NULL != pos->next) + { + pos = pos->next; + moved = 1; /* can terminate if file */ + continue; + } + if (NULL != pos->parent) + { + pos = pos->parent; + moved = -1; /* force move to 'next' or 'parent' */ + continue; + } + /* no more options, end of traversal */ + return NULL; + } + return pos; +} + + +/** + * Add another child node to the tree. + * + * @param parent parent of the child, NULL for top level + * @param filename name of the file or directory + * @param is_directory GNUNET_YES for directories + * @return new entry that was just created + */ +static struct GNUNET_FS_ShareTreeItem * +expand_tree (struct GNUNET_FS_ShareTreeItem *parent, + const char *filename, + int is_directory) +{ + struct GNUNET_FS_ShareTreeItem *chld; + size_t slen; + + chld = GNUNET_malloc (sizeof (struct GNUNET_FS_ShareTreeItem)); + chld->parent = parent; + chld->filename = GNUNET_strdup (filename); + GNUNET_asprintf (&chld->short_filename, + "%s%s", + GNUNET_STRINGS_get_short_name (filename), + is_directory == GNUNET_YES ? "/" : ""); + /* make sure we do not end with '//' */ + slen = strlen (chld->short_filename); + if ( (slen >= 2) && + (chld->short_filename[slen-1] == '/') && + (chld->short_filename[slen-2] == '/') ) + chld->short_filename[slen-1] = '\0'; + chld->is_directory = is_directory; + if (NULL != parent) + GNUNET_CONTAINER_DLL_insert (parent->children_head, + parent->children_tail, + chld); + return chld; +} + + +/** + * Task run last to shut everything down. + * + * @param cls the 'struct GNUNET_FS_DirScanner' + * @param tc unused + */ +static void +finish_scan (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_DirScanner *ds = cls; + + ds->stop_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_HELPER_stop (ds->helper); + ds->helper = NULL; + ds->progress_callback (ds->progress_callback_cls, + NULL, GNUNET_SYSERR, + GNUNET_FS_DIRSCANNER_FINISHED); +} + + +/** + * Called every time there is data to read from the scanner. + * Calls the scanner progress handler. + * + * @param cls the closure (directory scanner object) + * @param client always NULL + * @param msg message from the helper process + */ +static void +process_helper_msgs (void *cls, + void *client, + const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_FS_DirScanner *ds = cls; + const char *filename; + size_t left; + + left = ntohs (msg->size) - sizeof (struct GNUNET_MessageHeader); + filename = (const char*) &msg[1]; + switch (ntohs (msg->type)) + { + case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE: + if (filename[left-1] != '\0') + { + GNUNET_break (0); + break; + } + ds->progress_callback (ds->progress_callback_cls, + filename, GNUNET_NO, + GNUNET_FS_DIRSCANNER_FILE_START); + if (NULL == ds->toplevel) + ds->toplevel = expand_tree (ds->pos, + filename, GNUNET_NO); + else + (void) expand_tree (ds->pos, + filename, GNUNET_NO); + return; + case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY: + if (filename[left-1] != '\0') + { + GNUNET_break (0); + break; + } + if (0 == strcmp ("..", filename)) + { + if (NULL == ds->pos) + { + GNUNET_break (0); + break; + } + ds->pos = ds->pos->parent; + return; + } + ds->progress_callback (ds->progress_callback_cls, + filename, GNUNET_YES, + GNUNET_FS_DIRSCANNER_FILE_START); + ds->pos = expand_tree (ds->pos, + filename, GNUNET_YES); + if (NULL == ds->toplevel) + ds->toplevel = ds->pos; + return; + case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR: + break; + case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE: + if (filename[left-1] != '\0') + break; + ds->progress_callback (ds->progress_callback_cls, + filename, GNUNET_SYSERR, + GNUNET_FS_DIRSCANNER_FILE_IGNORED); + return; + case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE: + if (0 != left) + { + GNUNET_break (0); + break; + } + if (NULL == ds->toplevel) + { + GNUNET_break (0); + break; + } + ds->progress_callback (ds->progress_callback_cls, + NULL, GNUNET_SYSERR, + GNUNET_FS_DIRSCANNER_ALL_COUNTED); + ds->pos = ds->toplevel; + if (ds->pos->is_directory == GNUNET_YES) + ds->pos = advance (ds->pos); + return; + case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA: + { + size_t nlen; + const char *end; + + if (NULL == ds->pos) + { + GNUNET_break (0); + break; + } + end = memchr (filename, 0, left); + if (NULL == end) + { + GNUNET_break (0); + break; + } + end++; + nlen = end - filename; + left -= nlen; + if (0 != strcmp (filename, + ds->pos->filename)) + { + GNUNET_break (0); + break; + } + ds->progress_callback (ds->progress_callback_cls, + filename, GNUNET_YES, + GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED); + if (0 < left) + { + ds->pos->meta = GNUNET_CONTAINER_meta_data_deserialize (end, left); + if (NULL == ds->pos->meta) + { + GNUNET_break (0); + break; + } + /* having full filenames is too dangerous; always make sure we clean them up */ + GNUNET_CONTAINER_meta_data_delete (ds->pos->meta, + EXTRACTOR_METATYPE_FILENAME, + NULL, 0); + /* instead, put in our 'safer' original filename */ + GNUNET_CONTAINER_meta_data_insert (ds->pos->meta, "", + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + ds->pos->short_filename, + strlen (ds->pos->short_filename) + 1); + } + ds->pos->ksk_uri = GNUNET_FS_uri_ksk_create_from_meta_data (ds->pos->meta); + ds->pos = advance (ds->pos); + return; + } + case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED: + if (NULL != ds->pos) + { + GNUNET_break (0); + break; + } + if (0 != left) + { + GNUNET_break (0); + break; + } + if (NULL == ds->toplevel) + { + GNUNET_break (0); + break; + } + ds->stop_task = GNUNET_SCHEDULER_add_now (&finish_scan, + ds); + return; + default: + GNUNET_break (0); + break; + } + ds->progress_callback (ds->progress_callback_cls, + NULL, GNUNET_SYSERR, + GNUNET_FS_DIRSCANNER_INTERNAL_ERROR); +} + + +/** + * Start a directory scanner thread. + * + * @param filename name of the directory to scan + * @param disable_extractor GNUNET_YES to not to run libextractor on files (only build a tree) + * @param ex if not NULL, must be a list of extra plugins for extractor + * @param cb the callback to call when there are scanning progress messages + * @param cb_cls closure for 'cb' + * @return directory scanner object to be used for controlling the scanner + */ +struct GNUNET_FS_DirScanner * +GNUNET_FS_directory_scan_start (const char *filename, + int disable_extractor, const char *ex, + GNUNET_FS_DirScannerProgressCallback cb, + void *cb_cls) +{ + struct stat sbuf; + char *filename_expanded; + struct GNUNET_FS_DirScanner *ds; + + if (0 != STAT (filename, &sbuf)) + return NULL; + filename_expanded = GNUNET_STRINGS_filename_expand (filename); + if (NULL == filename_expanded) + return NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting to scan directory `%s'\n", + filename_expanded); + ds = GNUNET_malloc (sizeof (struct GNUNET_FS_DirScanner)); + ds->progress_callback = cb; + ds->progress_callback_cls = cb_cls; + ds->filename_expanded = filename_expanded; + if (disable_extractor) + ds->ex_arg = GNUNET_strdup ("-"); + else + ds->ex_arg = (NULL != ex) ? GNUNET_strdup (ex) : NULL; + ds->args[0] = "gnunet-helper-fs-publish"; + ds->args[1] = ds->filename_expanded; + ds->args[2] = ds->ex_arg; + ds->args[3] = NULL; + ds->helper = GNUNET_HELPER_start ("gnunet-helper-fs-publish", + ds->args, + &process_helper_msgs, + ds); + if (NULL == ds->helper) + { + GNUNET_free (filename_expanded); + GNUNET_free (ds); + return NULL; + } + return ds; +} + + +/* end of fs_dirmetascan.c */ diff --git a/src/fs/fs_download.c b/src/fs/fs_download.c new file mode 100644 index 0000000..b23d14b --- /dev/null +++ b/src/fs/fs_download.c @@ -0,0 +1,2260 @@ +/* + This file is part of GNUnet. + (C) 2001-2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/fs_download.c + * @brief download methods + * @author Christian Grothoff + * + * TODO: + * - different priority for scheduling probe downloads? + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" +#include "fs_tree.h" + + +/** + * Determine if the given download (options and meta data) should cause + * use to try to do a recursive download. + */ +static int +is_recursive_download (struct GNUNET_FS_DownloadContext *dc) +{ + return (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE)) && + ((GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (dc->meta)) || + ((dc->meta == NULL) && + ((NULL == dc->filename) || + ((strlen (dc->filename) >= strlen (GNUNET_FS_DIRECTORY_EXT)) && + (NULL != + strstr (dc->filename + strlen (dc->filename) - + strlen (GNUNET_FS_DIRECTORY_EXT), + GNUNET_FS_DIRECTORY_EXT)))))); +} + + +/** + * We're storing the IBLOCKS after the DBLOCKS on disk (so that we + * only have to truncate the file once we're done). + * + * Given the offset of a block (with respect to the DBLOCKS) and its + * depth, return the offset where we would store this block in the + * file. + * + * @param fsize overall file size + * @param off offset of the block in the file + * @param depth depth of the block in the tree, 0 for DBLOCK + * @return off for DBLOCKS (depth == treedepth), + * otherwise an offset past the end + * of the file that does not overlap + * with the range for any other block + */ +static uint64_t +compute_disk_offset (uint64_t fsize, uint64_t off, unsigned int depth) +{ + unsigned int i; + uint64_t lsize; /* what is the size of all IBlocks for depth "i"? */ + uint64_t loff; /* where do IBlocks for depth "i" start? */ + unsigned int ioff; /* which IBlock corresponds to "off" at depth "i"? */ + + if (depth == 0) + return off; + /* first IBlocks start at the end of file, rounded up + * to full DBLOCK_SIZE */ + loff = ((fsize + DBLOCK_SIZE - 1) / DBLOCK_SIZE) * DBLOCK_SIZE; + lsize = + ((fsize + DBLOCK_SIZE - + 1) / DBLOCK_SIZE) * sizeof (struct ContentHashKey); + GNUNET_assert (0 == (off % DBLOCK_SIZE)); + ioff = (off / DBLOCK_SIZE); + for (i = 1; i < depth; i++) + { + loff += lsize; + lsize = (lsize + CHK_PER_INODE - 1) / CHK_PER_INODE; + GNUNET_assert (lsize > 0); + GNUNET_assert (0 == (ioff % CHK_PER_INODE)); + ioff /= CHK_PER_INODE; + } + return loff + ioff * sizeof (struct ContentHashKey); +} + + +/** + * Fill in all of the generic fields for a download event and call the + * callback. + * + * @param pi structure to fill in + * @param dc overall download context + */ +void +GNUNET_FS_download_make_status_ (struct GNUNET_FS_ProgressInfo *pi, + struct GNUNET_FS_DownloadContext *dc) +{ + pi->value.download.dc = dc; + pi->value.download.cctx = dc->client_info; + pi->value.download.pctx = + (dc->parent == NULL) ? NULL : dc->parent->client_info; + pi->value.download.sctx = + (dc->search == NULL) ? NULL : dc->search->client_info; + pi->value.download.uri = dc->uri; + pi->value.download.filename = dc->filename; + pi->value.download.size = dc->length; + /* FIXME: Fix duration calculation to account for pauses */ + pi->value.download.duration = + GNUNET_TIME_absolute_get_duration (dc->start_time); + pi->value.download.completed = dc->completed; + pi->value.download.anonymity = dc->anonymity; + pi->value.download.eta = + GNUNET_TIME_calculate_eta (dc->start_time, dc->completed, dc->length); + pi->value.download.is_active = (dc->client == NULL) ? GNUNET_NO : GNUNET_YES; + if (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE)) + dc->client_info = dc->h->upcb (dc->h->upcb_cls, pi); + else + dc->client_info = GNUNET_FS_search_probe_progress_ (NULL, pi); +} + + +/** + * We're ready to transmit a search request to the + * file-sharing service. Do it. If there is + * more than one request pending, try to send + * multiple or request another transmission. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_download_request (void *cls, size_t size, void *buf); + + +/** + * Closure for iterator processing results. + */ +struct ProcessResultClosure +{ + + /** + * Hash of data. + */ + GNUNET_HashCode query; + + /** + * Data found in P2P network. + */ + const void *data; + + /** + * Our download context. + */ + struct GNUNET_FS_DownloadContext *dc; + + /** + * Number of bytes in data. + */ + size_t size; + + /** + * Type of data. + */ + enum GNUNET_BLOCK_Type type; + + /** + * Flag to indicate if this block should be stored on disk. + */ + int do_store; + + struct GNUNET_TIME_Absolute last_transmission; + +}; + + +/** + * Iterator over entries in the pending requests in the 'active' map for the + * reply that we just got. + * + * @param cls closure (our 'struct ProcessResultClosure') + * @param key query for the given value / request + * @param value value in the hash map (a 'struct DownloadRequest') + * @return GNUNET_YES (we should continue to iterate); unless serious error + */ +static int +process_result_with_request (void *cls, const GNUNET_HashCode * key, + void *value); + + +/** + * We've found a matching block without downloading it. + * Encrypt it and pass it to our "receive" function as + * if we had received it from the network. + * + * @param dc download in question + * @param chk request this relates to + * @param dr request details + * @param block plaintext data matching request + * @param len number of bytes in block + * @param do_store should we still store the block on disk? + * @return GNUNET_OK on success + */ +static int +encrypt_existing_match (struct GNUNET_FS_DownloadContext *dc, + const struct ContentHashKey *chk, + struct DownloadRequest *dr, const char *block, + size_t len, int do_store) +{ + struct ProcessResultClosure prc; + char enc[len]; + struct GNUNET_CRYPTO_AesSessionKey sk; + struct GNUNET_CRYPTO_AesInitializationVector iv; + GNUNET_HashCode query; + + GNUNET_CRYPTO_hash_to_aes_key (&chk->key, &sk, &iv); + if (-1 == GNUNET_CRYPTO_aes_encrypt (block, len, &sk, &iv, enc)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_hash (enc, len, &query); + if (0 != memcmp (&query, &chk->query, sizeof (GNUNET_HashCode))) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Matching block for `%s' at offset %llu already present, no need for download!\n", + dc->filename, (unsigned long long) dr->offset); + /* already got it! */ + prc.dc = dc; + prc.data = enc; + prc.size = len; + prc.type = + (0 == + dr->depth) ? GNUNET_BLOCK_TYPE_FS_DBLOCK : GNUNET_BLOCK_TYPE_FS_IBLOCK; + prc.query = chk->query; + prc.do_store = do_store; + prc.last_transmission = GNUNET_TIME_UNIT_FOREVER_ABS; + process_result_with_request (&prc, &chk->key, dr); + return GNUNET_OK; +} + + +/** + * We've lost our connection with the FS service. + * Re-establish it and re-transmit all of our + * pending requests. + * + * @param dc download context that is having trouble + */ +static void +try_reconnect (struct GNUNET_FS_DownloadContext *dc); + + +/** + * We found an entry in a directory. Check if the respective child + * already exists and if not create the respective child download. + * + * @param cls the parent download + * @param filename name of the file in the directory + * @param uri URI of the file (CHK or LOC) + * @param meta meta data of the file + * @param length number of bytes in data + * @param data contents of the file (or NULL if they were not inlined) + */ +static void +trigger_recursive_download (void *cls, const char *filename, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_CONTAINER_MetaData *meta, + size_t length, const void *data); + + +/** + * We're done downloading a directory. Open the file and + * trigger all of the (remaining) child downloads. + * + * @param dc context of download that just completed + */ +static void +full_recursive_download (struct GNUNET_FS_DownloadContext *dc) +{ + size_t size; + uint64_t size64; + void *data; + struct GNUNET_DISK_FileHandle *h; + struct GNUNET_DISK_MapHandle *m; + + size64 = GNUNET_FS_uri_chk_get_file_size (dc->uri); + size = (size_t) size64; + if (size64 != (uint64_t) size) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n")); + return; + } + if (dc->filename != NULL) + { + h = GNUNET_DISK_file_open (dc->filename, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + } + else + { + GNUNET_assert (dc->temp_filename != NULL); + h = GNUNET_DISK_file_open (dc->temp_filename, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + } + if (h == NULL) + return; /* oops */ + data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size); + if (data == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Directory too large for system address space\n")); + } + else + { + GNUNET_FS_directory_list_contents (size, data, 0, + &trigger_recursive_download, dc); + GNUNET_DISK_file_unmap (m); + } + GNUNET_DISK_file_close (h); + if (dc->filename == NULL) + { + if (0 != UNLINK (dc->temp_filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", + dc->temp_filename); + GNUNET_free (dc->temp_filename); + dc->temp_filename = NULL; + } +} + + +/** + * Check if all child-downloads have completed (or trigger them if + * necessary) and once we're completely done, signal completion (and + * possibly recurse to parent). This function MUST be called when the + * download of a file itself is done or when the download of a file is + * done and then later a direct child download has completed (and + * hence this download may complete itself). + * + * @param dc download to check for completion of children + */ +static void +check_completed (struct GNUNET_FS_DownloadContext *dc) +{ + struct GNUNET_FS_ProgressInfo pi; + struct GNUNET_FS_DownloadContext *pos; + + /* first, check if we need to download children */ + if ((dc->child_head == NULL) && (is_recursive_download (dc))) + full_recursive_download (dc); + /* then, check if children are done already */ + pos = dc->child_head; + while (pos != NULL) + { + if ((pos->emsg == NULL) && (pos->completed < pos->length)) + return; /* not done yet */ + if ((pos->child_head != NULL) && (pos->has_finished != GNUNET_YES)) + return; /* not transitively done yet */ + pos = pos->next; + } + /* All of our children are done, so mark this download done */ + dc->has_finished = GNUNET_YES; + if (dc->job_queue != NULL) + { + GNUNET_FS_dequeue_ (dc->job_queue); + dc->job_queue = NULL; + } + GNUNET_FS_download_sync_ (dc); + + /* signal completion */ + pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED; + GNUNET_FS_download_make_status_ (&pi, dc); + + /* let parent know */ + if (dc->parent != NULL) + check_completed (dc->parent); +} + + +/** + * We got a block of plaintext data (from the meta data). + * Try it for upward reconstruction of the data. On success, + * the top-level block will move to state BRS_DOWNLOAD_UP. + * + * @param dc context for the download + * @param dr download request to match against + * @param data plaintext data, starting from the beginning of the file + * @param data_len number of bytes in data + */ +static void +try_match_block (struct GNUNET_FS_DownloadContext *dc, + struct DownloadRequest *dr, const char *data, size_t data_len) +{ + struct GNUNET_FS_ProgressInfo pi; + unsigned int i; + char enc[DBLOCK_SIZE]; + struct ContentHashKey chks[CHK_PER_INODE]; + struct ContentHashKey in_chk; + struct GNUNET_CRYPTO_AesSessionKey sk; + struct GNUNET_CRYPTO_AesInitializationVector iv; + size_t dlen; + struct DownloadRequest *drc; + struct GNUNET_DISK_FileHandle *fh; + int complete; + const char *fn; + const char *odata; + size_t odata_len; + + odata = data; + odata_len = data_len; + if (BRS_DOWNLOAD_UP == dr->state) + return; + if (dr->depth > 0) + { + complete = GNUNET_YES; + for (i = 0; i < dr->num_children; i++) + { + drc = dr->children[i]; + try_match_block (dc, drc, data, data_len); + if (drc->state != BRS_RECONSTRUCT_META_UP) + complete = GNUNET_NO; + else + chks[i] = drc->chk; + } + if (GNUNET_YES != complete) + return; + data = (const char *) chks; + dlen = dr->num_children * sizeof (struct ContentHashKey); + } + else + { + if (dr->offset > data_len) + return; /* oops */ + dlen = GNUNET_MIN (data_len - dr->offset, DBLOCK_SIZE); + } + GNUNET_CRYPTO_hash (&data[dr->offset], dlen, &in_chk.key); + GNUNET_CRYPTO_hash_to_aes_key (&in_chk.key, &sk, &iv); + if (-1 == GNUNET_CRYPTO_aes_encrypt (&data[dr->offset], dlen, &sk, &iv, enc)) + { + GNUNET_break (0); + return; + } + GNUNET_CRYPTO_hash (enc, dlen, &in_chk.query); + switch (dr->state) + { + case BRS_INIT: + dr->chk = in_chk; + dr->state = BRS_RECONSTRUCT_META_UP; + break; + case BRS_CHK_SET: + if (0 != memcmp (&in_chk, &dr->chk, sizeof (struct ContentHashKey))) + { + /* other peer provided bogus meta data */ + GNUNET_break_op (0); + break; + } + /* write block to disk */ + fn = dc->filename != NULL ? dc->filename : dc->temp_filename; + fh = GNUNET_DISK_file_open (fn, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE | + GNUNET_DISK_OPEN_TRUNCATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE | + GNUNET_DISK_PERM_GROUP_READ | + GNUNET_DISK_PERM_OTHER_READ); + if (fh == NULL) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); + GNUNET_asprintf (&dc->emsg, _("Failed to open file `%s' for writing"), + fn); + GNUNET_DISK_file_close (fh); + dr->state = BRS_ERROR; + pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; + pi.value.download.specifics.error.message = dc->emsg; + GNUNET_FS_download_make_status_ (&pi, dc); + return; + } + if (data_len != GNUNET_DISK_file_write (fh, odata, odata_len)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", fn); + GNUNET_asprintf (&dc->emsg, _("Failed to open file `%s' for writing"), + fn); + GNUNET_DISK_file_close (fh); + dr->state = BRS_ERROR; + pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; + pi.value.download.specifics.error.message = dc->emsg; + GNUNET_FS_download_make_status_ (&pi, dc); + return; + } + GNUNET_DISK_file_close (fh); + /* signal success */ + dr->state = BRS_DOWNLOAD_UP; + dc->completed = dc->length; + GNUNET_FS_download_sync_ (dc); + pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS; + pi.value.download.specifics.progress.data = data; + pi.value.download.specifics.progress.offset = 0; + pi.value.download.specifics.progress.data_len = dlen; + pi.value.download.specifics.progress.depth = 0; + pi.value.download.specifics.progress.trust_offered = 0; + GNUNET_FS_download_make_status_ (&pi, dc); + if ((NULL != dc->filename) && + (0 != + truncate (dc->filename, + GNUNET_ntohll (dc->uri->data.chk.file_length)))) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "truncate", + dc->filename); + check_completed (dc); + break; + default: + /* how did we get here? */ + GNUNET_break (0); + break; + } +} + + +/** + * Type of a function that libextractor calls for each + * meta data item found. If we find full data meta data, + * call 'try_match_block' on it. + * + * @param cls our 'struct GNUNET_FS_DownloadContext*' + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_len number of bytes in data + * @return 0 to continue extracting, 1 to abort + */ +static int +match_full_data (void *cls, const char *plugin_name, + enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, + const char *data_mime_type, const char *data, size_t data_len) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + + if (type != EXTRACTOR_METATYPE_GNUNET_FULL_DATA) + return 0; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u bytes of FD!\n", + (unsigned int) data_len); + if (GNUNET_FS_uri_chk_get_file_size (dc->uri) != data_len) + { + GNUNET_break_op (0); + return 1; /* bogus meta data */ + } + try_match_block (dc, dc->top_request, data, data_len); + return 1; +} + + +/** + * Set the state of the given download request to + * BRS_DOWNLOAD_UP and propagate it up the tree. + * + * @param dr download request that is done + */ +static void +propagate_up (struct DownloadRequest *dr) +{ + unsigned int i; + + do + { + dr->state = BRS_DOWNLOAD_UP; + dr = dr->parent; + if (dr == NULL) + break; + for (i = 0; i < dr->num_children; i++) + if (dr->children[i]->state != BRS_DOWNLOAD_UP) + break; + } + while (i == dr->num_children); +} + + +/** + * Try top-down reconstruction. Before, the given request node + * must have the state BRS_CHK_SET. Afterwards, more nodes may + * have that state or advanced to BRS_DOWNLOAD_DOWN or even + * BRS_DOWNLOAD_UP. It is also possible to get BRS_ERROR on the + * top level. + * + * @param dc overall download this block belongs to + * @param dr block to reconstruct + */ +static void +try_top_down_reconstruction (struct GNUNET_FS_DownloadContext *dc, + struct DownloadRequest *dr) +{ + uint64_t off; + char block[DBLOCK_SIZE]; + GNUNET_HashCode key; + uint64_t total; + size_t len; + unsigned int i; + unsigned int chk_off; + struct DownloadRequest *drc; + uint64_t child_block_size; + const struct ContentHashKey *chks; + int up_done; + + GNUNET_assert (dc->rfh != NULL); + GNUNET_assert (dr->state == BRS_CHK_SET); + total = GNUNET_FS_uri_chk_get_file_size (dc->uri); + GNUNET_assert (dr->depth < dc->treedepth); + len = GNUNET_FS_tree_calculate_block_size (total, dr->offset, dr->depth); + GNUNET_assert (len <= DBLOCK_SIZE); + off = compute_disk_offset (total, dr->offset, dr->depth); + if (dc->old_file_size < off + len) + return; /* failure */ + if (off != GNUNET_DISK_file_seek (dc->rfh, off, GNUNET_DISK_SEEK_SET)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "seek", dc->filename); + return; /* failure */ + } + if (len != GNUNET_DISK_file_read (dc->rfh, block, len)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "read", dc->filename); + return; /* failure */ + } + GNUNET_CRYPTO_hash (block, len, &key); + if (0 != memcmp (&key, &dr->chk.key, sizeof (GNUNET_HashCode))) + return; /* mismatch */ + if (GNUNET_OK != + encrypt_existing_match (dc, &dr->chk, dr, block, len, GNUNET_NO)) + { + /* hash matches but encrypted block does not, really bad */ + dr->state = BRS_ERROR; + /* propagate up */ + while (dr->parent != NULL) + { + dr = dr->parent; + dr->state = BRS_ERROR; + } + return; + } + /* block matches */ + dr->state = BRS_DOWNLOAD_DOWN; + + /* set CHKs for children */ + up_done = GNUNET_YES; + chks = (const struct ContentHashKey *) block; + for (i = 0; i < dr->num_children; i++) + { + drc = dr->children[i]; + GNUNET_assert (drc->offset >= dr->offset); + child_block_size = GNUNET_FS_tree_compute_tree_size (drc->depth); + GNUNET_assert (0 == (drc->offset - dr->offset) % child_block_size); + chk_off = (drc->offset - dr->offset) / child_block_size; + if (drc->state == BRS_INIT) + { + drc->state = BRS_CHK_SET; + drc->chk = chks[chk_off]; + try_top_down_reconstruction (dc, drc); + } + if (drc->state != BRS_DOWNLOAD_UP) + up_done = GNUNET_NO; /* children not all done */ + } + if (up_done == GNUNET_YES) + propagate_up (dr); /* children all done (or no children...) */ +} + + +/** + * Schedule the download of the specified block in the tree. + * + * @param dc overall download this block belongs to + * @param dr request to schedule + */ +static void +schedule_block_download (struct GNUNET_FS_DownloadContext *dc, + struct DownloadRequest *dr) +{ + unsigned int i; + + switch (dr->state) + { + case BRS_INIT: + GNUNET_assert (0); + break; + case BRS_RECONSTRUCT_DOWN: + GNUNET_assert (0); + break; + case BRS_RECONSTRUCT_META_UP: + GNUNET_assert (0); + break; + case BRS_RECONSTRUCT_UP: + GNUNET_assert (0); + break; + case BRS_CHK_SET: + /* normal case, start download */ + break; + case BRS_DOWNLOAD_DOWN: + for (i = 0; i < dr->num_children; i++) + schedule_block_download (dc, dr->children[i]); + return; + case BRS_DOWNLOAD_UP: + /* We're done! */ + return; + case BRS_ERROR: + GNUNET_break (0); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling download at offset %llu and depth %u for `%s'\n", + (unsigned long long) dr->offset, dr->depth, + GNUNET_h2s (&dr->chk.query)); + if (GNUNET_NO != + GNUNET_CONTAINER_multihashmap_contains_value (dc->active, &dr->chk.query, + dr)) + return; /* already active */ + GNUNET_CONTAINER_multihashmap_put (dc->active, &dr->chk.query, dr, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + if (dc->client == NULL) + return; /* download not active */ + GNUNET_CONTAINER_DLL_insert (dc->pending_head, dc->pending_tail, dr); + dr->is_pending = GNUNET_YES; + if (NULL == dc->th) + dc->th = + GNUNET_CLIENT_notify_transmit_ready (dc->client, + sizeof (struct SearchMessage), + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + GNUNET_NO, + &transmit_download_request, dc); +} + + +#define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX + +/** + * We found an entry in a directory. Check if the respective child + * already exists and if not create the respective child download. + * + * @param cls the parent download + * @param filename name of the file in the directory + * @param uri URI of the file (CHK or LOC) + * @param meta meta data of the file + * @param length number of bytes in data + * @param data contents of the file (or NULL if they were not inlined) + */ +static void +trigger_recursive_download (void *cls, const char *filename, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_CONTAINER_MetaData *meta, + size_t length, const void *data) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + struct GNUNET_FS_DownloadContext *cpos; + char *temp_name; + char *fn; + char *us; + char *ext; + char *dn; + char *pos; + char *full_name; + char *sfn; + + if (NULL == uri) + return; /* entry for the directory itself */ + cpos = dc->child_head; + while (cpos != NULL) + { + if ((GNUNET_FS_uri_test_equal (uri, cpos->uri)) || + ((filename != NULL) && (0 == strcmp (cpos->filename, filename)))) + break; + cpos = cpos->next; + } + if (cpos != NULL) + return; /* already exists */ + fn = NULL; + if (NULL == filename) + { + fn = GNUNET_FS_meta_data_suggest_filename (meta); + if (fn == NULL) + { + us = GNUNET_FS_uri_to_string (uri); + fn = GNUNET_strdup (&us[strlen (GNUNET_FS_URI_CHK_PREFIX)]); + GNUNET_free (us); + } + else if (fn[0] == '.') + { + ext = fn; + us = GNUNET_FS_uri_to_string (uri); + GNUNET_asprintf (&fn, "%s%s", &us[strlen (GNUNET_FS_URI_CHK_PREFIX)], + ext); + GNUNET_free (ext); + GNUNET_free (us); + } + /* change '\' to '/' (this should have happened + * during insertion, but malicious peers may + * not have done this) */ + while (NULL != (pos = strstr (fn, "\\"))) + *pos = '/'; + /* remove '../' everywhere (again, well-behaved + * peers don't do this, but don't trust that + * we did not get something nasty) */ + while (NULL != (pos = strstr (fn, "../"))) + { + pos[0] = '_'; + pos[1] = '_'; + pos[2] = '_'; + } + filename = fn; + } + if (dc->filename == NULL) + { + full_name = NULL; + } + else + { + dn = GNUNET_strdup (dc->filename); + GNUNET_break ((strlen (dn) >= strlen (GNUNET_FS_DIRECTORY_EXT)) && + (NULL != + strstr (dn + strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT), + GNUNET_FS_DIRECTORY_EXT))); + sfn = GNUNET_strdup (filename); + while ((strlen (sfn) > 0) && (filename[strlen (sfn) - 1] == '/')) + sfn[strlen (sfn) - 1] = '\0'; + if ((strlen (dn) >= strlen (GNUNET_FS_DIRECTORY_EXT)) && + (NULL != + strstr (dn + strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT), + GNUNET_FS_DIRECTORY_EXT))) + dn[strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT)] = '\0'; + if ((GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) && + ((strlen (filename) < strlen (GNUNET_FS_DIRECTORY_EXT)) || + (NULL == + strstr (filename + strlen (filename) - + strlen (GNUNET_FS_DIRECTORY_EXT), GNUNET_FS_DIRECTORY_EXT)))) + { + GNUNET_asprintf (&full_name, "%s%s%s%s", dn, DIR_SEPARATOR_STR, sfn, + GNUNET_FS_DIRECTORY_EXT); + } + else + { + GNUNET_asprintf (&full_name, "%s%s%s", dn, DIR_SEPARATOR_STR, sfn); + } + GNUNET_free (sfn); + GNUNET_free (dn); + } + if ((full_name != NULL) && + (GNUNET_OK != GNUNET_DISK_directory_create_for_file (full_name))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Failed to create directory for recursive download of `%s'\n"), + full_name); + GNUNET_free (full_name); + GNUNET_free_non_null (fn); + return; + } + + temp_name = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Triggering recursive download of size %llu with %u bytes MD\n", + (unsigned long long) GNUNET_FS_uri_chk_get_file_size (uri), + (unsigned int) + GNUNET_CONTAINER_meta_data_get_serialized_size (meta)); + GNUNET_FS_download_start (dc->h, uri, meta, full_name, temp_name, 0, + GNUNET_FS_uri_chk_get_file_size (uri), + dc->anonymity, dc->options, NULL, dc); + GNUNET_free_non_null (full_name); + GNUNET_free_non_null (temp_name); + GNUNET_free_non_null (fn); +} + + +/** + * (recursively) free download request structure + * + * @param dr request to free + */ +void +GNUNET_FS_free_download_request_ (struct DownloadRequest *dr) +{ + unsigned int i; + + if (dr == NULL) + return; + for (i = 0; i < dr->num_children; i++) + GNUNET_FS_free_download_request_ (dr->children[i]); + GNUNET_free_non_null (dr->children); + GNUNET_free (dr); +} + + +/** + * Iterator over entries in the pending requests in the 'active' map for the + * reply that we just got. + * + * @param cls closure (our 'struct ProcessResultClosure') + * @param key query for the given value / request + * @param value value in the hash map (a 'struct DownloadRequest') + * @return GNUNET_YES (we should continue to iterate); unless serious error + */ +static int +process_result_with_request (void *cls, const GNUNET_HashCode * key, + void *value) +{ + struct ProcessResultClosure *prc = cls; + struct DownloadRequest *dr = value; + struct GNUNET_FS_DownloadContext *dc = prc->dc; + struct DownloadRequest *drc; + struct GNUNET_DISK_FileHandle *fh = NULL; + struct GNUNET_CRYPTO_AesSessionKey skey; + struct GNUNET_CRYPTO_AesInitializationVector iv; + char pt[prc->size]; + struct GNUNET_FS_ProgressInfo pi; + uint64_t off; + size_t bs; + size_t app; + int i; + struct ContentHashKey *chkarr; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received block `%s' matching pending request at depth %u and offset %llu/%llu\n", + GNUNET_h2s (key), dr->depth, (unsigned long long) dr->offset, + (unsigned long long) GNUNET_ntohll (dc->uri->data. + chk.file_length)); + bs = GNUNET_FS_tree_calculate_block_size (GNUNET_ntohll + (dc->uri->data.chk.file_length), + dr->offset, dr->depth); + if (prc->size != bs) + { + GNUNET_asprintf (&dc->emsg, + _ + ("Internal error or bogus download URI (expected %u bytes at depth %u and offset %llu/%llu, got %u bytes)\n"), + bs, dr->depth, (unsigned long long) dr->offset, + (unsigned long long) GNUNET_ntohll (dc->uri->data. + chk.file_length), + prc->size); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s", dc->emsg); + while (dr->parent != NULL) + { + dr->state = BRS_ERROR; + dr = dr->parent; + } + dr->state = BRS_ERROR; + goto signal_error; + } + + (void) GNUNET_CONTAINER_multihashmap_remove (dc->active, &prc->query, dr); + if (GNUNET_YES == dr->is_pending) + { + GNUNET_CONTAINER_DLL_remove (dc->pending_head, dc->pending_tail, dr); + dr->is_pending = GNUNET_NO; + } + + GNUNET_CRYPTO_hash_to_aes_key (&dr->chk.key, &skey, &iv); + if (-1 == GNUNET_CRYPTO_aes_decrypt (prc->data, prc->size, &skey, &iv, pt)) + { + GNUNET_break (0); + dc->emsg = GNUNET_strdup (_("internal error decrypting content")); + goto signal_error; + } + off = + compute_disk_offset (GNUNET_ntohll (dc->uri->data.chk.file_length), + dr->offset, dr->depth); + /* save to disk */ + if ((GNUNET_YES == prc->do_store) && + ((dc->filename != NULL) || (is_recursive_download (dc))) && + ((dr->depth == dc->treedepth) || + (0 == (dc->options & GNUNET_FS_DOWNLOAD_NO_TEMPORARIES)))) + { + fh = GNUNET_DISK_file_open (dc->filename != + NULL ? dc->filename : dc->temp_filename, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE | + GNUNET_DISK_PERM_GROUP_READ | + GNUNET_DISK_PERM_OTHER_READ); + if (NULL == fh) + { + GNUNET_asprintf (&dc->emsg, + _("Download failed: could not open file `%s': %s\n"), + dc->filename, STRERROR (errno)); + goto signal_error; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Saving decrypted block to disk at offset %llu\n", + (unsigned long long) off); + if ((off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET))) + { + GNUNET_asprintf (&dc->emsg, + _("Failed to seek to offset %llu in file `%s': %s\n"), + (unsigned long long) off, dc->filename, + STRERROR (errno)); + goto signal_error; + } + if (prc->size != GNUNET_DISK_file_write (fh, pt, prc->size)) + { + GNUNET_asprintf (&dc->emsg, + _ + ("Failed to write block of %u bytes at offset %llu in file `%s': %s\n"), + (unsigned int) prc->size, (unsigned long long) off, + dc->filename, STRERROR (errno)); + goto signal_error; + } + GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh)); + fh = NULL; + } + + if (dr->depth == 0) + { + /* DBLOCK, update progress and try recursion if applicable */ + app = prc->size; + if (dr->offset < dc->offset) + { + /* starting offset begins in the middle of pt, + * do not count first bytes as progress */ + GNUNET_assert (app > (dc->offset - dr->offset)); + app -= (dc->offset - dr->offset); + } + if (dr->offset + prc->size > dc->offset + dc->length) + { + /* end of block is after relevant range, + * do not count last bytes as progress */ + GNUNET_assert (app > + (dr->offset + prc->size) - (dc->offset + dc->length)); + app -= (dr->offset + prc->size) - (dc->offset + dc->length); + } + dc->completed += app; + + /* do recursive download if option is set and either meta data + * says it is a directory or if no meta data is given AND filename + * ends in '.gnd' (top-level case) */ + if (is_recursive_download (dc)) + GNUNET_FS_directory_list_contents (prc->size, pt, off, + &trigger_recursive_download, dc); + + } + GNUNET_assert (dc->completed <= dc->length); + dr->state = BRS_DOWNLOAD_DOWN; + pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS; + pi.value.download.specifics.progress.data = pt; + pi.value.download.specifics.progress.offset = dr->offset; + pi.value.download.specifics.progress.data_len = prc->size; + pi.value.download.specifics.progress.depth = dr->depth; + pi.value.download.specifics.progress.trust_offered = 0; + if (prc->last_transmission.abs_value != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) + pi.value.download.specifics.progress.block_download_duration = + GNUNET_TIME_absolute_get_duration (prc->last_transmission); + else + pi.value.download.specifics.progress.block_download_duration.rel_value = + GNUNET_TIME_UNIT_FOREVER_REL.rel_value; + GNUNET_FS_download_make_status_ (&pi, dc); + if (dr->depth == 0) + propagate_up (dr); + + if (dc->completed == dc->length) + { + /* download completed, signal */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Download completed, truncating file to desired length %llu\n", + (unsigned long long) GNUNET_ntohll (dc->uri->data. + chk.file_length)); + /* truncate file to size (since we store IBlocks at the end) */ + if (dc->filename != NULL) + { + if (0 != + truncate (dc->filename, + GNUNET_ntohll (dc->uri->data.chk.file_length))) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "truncate", + dc->filename); + } + GNUNET_assert (dr->depth == 0); + check_completed (dc); + } + if (dr->depth == 0) + { + /* bottom of the tree, no child downloads possible, just sync */ + GNUNET_FS_download_sync_ (dc); + return GNUNET_YES; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Triggering downloads of children (this block was at depth %u and offset %llu)\n", + dr->depth, (unsigned long long) dr->offset); + GNUNET_assert (0 == (prc->size % sizeof (struct ContentHashKey))); + chkarr = (struct ContentHashKey *) pt; + for (i = (prc->size / sizeof (struct ContentHashKey)) - 1; i >= 0; i--) + { + drc = dr->children[i]; + switch (drc->state) + { + case BRS_INIT: + drc->chk = chkarr[i]; + drc->state = BRS_CHK_SET; + schedule_block_download (dc, drc); + break; + case BRS_RECONSTRUCT_DOWN: + GNUNET_assert (0); + break; + case BRS_RECONSTRUCT_META_UP: + GNUNET_assert (0); + break; + case BRS_RECONSTRUCT_UP: + GNUNET_assert (0); + break; + case BRS_CHK_SET: + GNUNET_assert (0); + break; + case BRS_DOWNLOAD_DOWN: + GNUNET_assert (0); + break; + case BRS_DOWNLOAD_UP: + GNUNET_assert (0); + break; + case BRS_ERROR: + GNUNET_assert (0); + break; + default: + GNUNET_assert (0); + break; + } + } + GNUNET_FS_download_sync_ (dc); + return GNUNET_YES; + +signal_error: + if (fh != NULL) + GNUNET_DISK_file_close (fh); + pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; + pi.value.download.specifics.error.message = dc->emsg; + GNUNET_FS_download_make_status_ (&pi, dc); + /* abort all pending requests */ + if (NULL != dc->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (dc->th); + dc->th = NULL; + } + GNUNET_CLIENT_disconnect (dc->client, GNUNET_NO); + dc->in_receive = GNUNET_NO; + dc->client = NULL; + GNUNET_FS_free_download_request_ (dc->top_request); + dc->top_request = NULL; + GNUNET_CONTAINER_multihashmap_destroy (dc->active); + dc->active = NULL; + dc->pending_head = NULL; + dc->pending_tail = NULL; + GNUNET_FS_download_sync_ (dc); + return GNUNET_NO; +} + + +/** + * Process a download result. + * + * @param dc our download context + * @param type type of the result + * @param last_transmission when was this block requested the last time? (FOREVER if unknown/not applicable) + * @param data the (encrypted) response + * @param size size of data + */ +static void +process_result (struct GNUNET_FS_DownloadContext *dc, + enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute last_transmission, + const void *data, size_t size) +{ + struct ProcessResultClosure prc; + + prc.dc = dc; + prc.data = data; + prc.size = size; + prc.type = type; + prc.do_store = GNUNET_YES; + prc.last_transmission = last_transmission; + GNUNET_CRYPTO_hash (data, size, &prc.query); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received result for query `%s' from `%s'-service\n", + GNUNET_h2s (&prc.query), "FS"); + GNUNET_CONTAINER_multihashmap_get_multiple (dc->active, &prc.query, + &process_result_with_request, + &prc); +} + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +receive_results (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + const struct ClientPutMessage *cm; + uint16_t msize; + + if ((NULL == msg) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_PUT) || + (sizeof (struct ClientPutMessage) > ntohs (msg->size))) + { + GNUNET_break (msg == NULL); + try_reconnect (dc); + return; + } + msize = ntohs (msg->size); + cm = (const struct ClientPutMessage *) msg; + process_result (dc, ntohl (cm->type), + GNUNET_TIME_absolute_ntoh (cm->last_transmission), &cm[1], + msize - sizeof (struct ClientPutMessage)); + if (dc->client == NULL) + return; /* fatal error */ + /* continue receiving */ + GNUNET_CLIENT_receive (dc->client, &receive_results, dc, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + + +/** + * We're ready to transmit a search request to the + * file-sharing service. Do it. If there is + * more than one request pending, try to send + * multiple or request another transmission. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_download_request (void *cls, size_t size, void *buf) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + size_t msize; + struct SearchMessage *sm; + struct DownloadRequest *dr; + + dc->th = NULL; + if (NULL == buf) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting download request failed, trying to reconnect\n"); + try_reconnect (dc); + return 0; + } + GNUNET_assert (size >= sizeof (struct SearchMessage)); + msize = 0; + sm = buf; + while ((NULL != (dr = dc->pending_head)) && + (size >= msize + sizeof (struct SearchMessage))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting download request for `%s' to `%s'-service\n", + GNUNET_h2s (&dr->chk.query), "FS"); + memset (sm, 0, sizeof (struct SearchMessage)); + sm->header.size = htons (sizeof (struct SearchMessage)); + sm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_START_SEARCH); + if (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY)) + sm->options = htonl (GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY); + else + sm->options = htonl (GNUNET_FS_SEARCH_OPTION_NONE); + if (dr->depth == 0) + sm->type = htonl (GNUNET_BLOCK_TYPE_FS_DBLOCK); + else + sm->type = htonl (GNUNET_BLOCK_TYPE_FS_IBLOCK); + sm->anonymity_level = htonl (dc->anonymity); + sm->target = dc->target.hashPubKey; + sm->query = dr->chk.query; + GNUNET_CONTAINER_DLL_remove (dc->pending_head, dc->pending_tail, dr); + dr->is_pending = GNUNET_NO; + msize += sizeof (struct SearchMessage); + sm++; + } + if (dc->pending_head != NULL) + { + dc->th = + GNUNET_CLIENT_notify_transmit_ready (dc->client, + sizeof (struct SearchMessage), + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + GNUNET_NO, + &transmit_download_request, dc); + GNUNET_assert (dc->th != NULL); + } + if (GNUNET_NO == dc->in_receive) + { + dc->in_receive = GNUNET_YES; + GNUNET_CLIENT_receive (dc->client, &receive_results, dc, + GNUNET_TIME_UNIT_FOREVER_REL); + } + return msize; +} + + +/** + * Reconnect to the FS service and transmit our queries NOW. + * + * @param cls our download context + * @param tc unused + */ +static void +do_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + struct GNUNET_CLIENT_Connection *client; + + dc->task = GNUNET_SCHEDULER_NO_TASK; + client = GNUNET_CLIENT_connect ("fs", dc->h->cfg); + if (NULL == client) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Connecting to `%s'-service failed, will try again.\n", "FS"); + try_reconnect (dc); + return; + } + dc->client = client; + if (dc->pending_head != NULL) + { + dc->th = + GNUNET_CLIENT_notify_transmit_ready (client, + sizeof (struct SearchMessage), + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + GNUNET_NO, + &transmit_download_request, dc); + GNUNET_assert (dc->th != NULL); + } +} + + +/** + * Add entries to the pending list. + * + * @param cls our download context + * @param key unused + * @param entry entry of type "struct DownloadRequest" + * @return GNUNET_OK + */ +static int +retry_entry (void *cls, const GNUNET_HashCode * key, void *entry) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + struct DownloadRequest *dr = entry; + + dr->next = NULL; + dr->prev = NULL; + GNUNET_CONTAINER_DLL_insert (dc->pending_head, dc->pending_tail, dr); + dr->is_pending = GNUNET_YES; + return GNUNET_OK; +} + + +/** + * We've lost our connection with the FS service. + * Re-establish it and re-transmit all of our + * pending requests. + * + * @param dc download context that is having trouble + */ +static void +try_reconnect (struct GNUNET_FS_DownloadContext *dc) +{ + + if (NULL != dc->client) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Moving all requests back to pending list\n"); + if (NULL != dc->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (dc->th); + dc->th = NULL; + } + /* full reset of the pending list */ + dc->pending_head = NULL; + dc->pending_tail = NULL; + GNUNET_CONTAINER_multihashmap_iterate (dc->active, &retry_entry, dc); + GNUNET_CLIENT_disconnect (dc->client, GNUNET_NO); + dc->in_receive = GNUNET_NO; + dc->client = NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Will try to reconnect in 1s\n"); + dc->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_reconnect, + dc); +} + + +/** + * We're allowed to ask the FS service for our blocks. Start the download. + * + * @param cls the 'struct GNUNET_FS_DownloadContext' + * @param client handle to use for communcation with FS (we must destroy it!) + */ +static void +activate_fs_download (void *cls, struct GNUNET_CLIENT_Connection *client) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + struct GNUNET_FS_ProgressInfo pi; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download activated\n"); + GNUNET_assert (NULL != client); + GNUNET_assert (dc->client == NULL); + GNUNET_assert (dc->th == NULL); + dc->client = client; + pi.status = GNUNET_FS_STATUS_DOWNLOAD_ACTIVE; + GNUNET_FS_download_make_status_ (&pi, dc); + dc->pending_head = NULL; + dc->pending_tail = NULL; + GNUNET_CONTAINER_multihashmap_iterate (dc->active, &retry_entry, dc); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking for transmission to FS service\n"); + if (dc->pending_head != NULL) + { + dc->th = + GNUNET_CLIENT_notify_transmit_ready (dc->client, + sizeof (struct SearchMessage), + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + GNUNET_NO, + &transmit_download_request, dc); + GNUNET_assert (dc->th != NULL); + } +} + + +/** + * We must stop to ask the FS service for our blocks. Pause the download. + * + * @param cls the 'struct GNUNET_FS_DownloadContext' + */ +static void +deactivate_fs_download (void *cls) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + struct GNUNET_FS_ProgressInfo pi; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download deactivated\n"); + if (NULL != dc->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (dc->th); + dc->th = NULL; + } + if (NULL != dc->client) + { + GNUNET_CLIENT_disconnect (dc->client, GNUNET_NO); + dc->in_receive = GNUNET_NO; + dc->client = NULL; + } + dc->pending_head = NULL; + dc->pending_tail = NULL; + pi.status = GNUNET_FS_STATUS_DOWNLOAD_INACTIVE; + GNUNET_FS_download_make_status_ (&pi, dc); +} + + +/** + * (recursively) Create a download request structure. + * + * @param parent parent of the current entry + * @param depth depth of the current entry, 0 are the DBLOCKs, + * top level block is 'dc->treedepth - 1' + * @param dr_offset offset in the original file this block maps to + * (as in, offset of the first byte of the first DBLOCK + * in the subtree rooted in the returned download request tree) + * @param file_start_offset desired starting offset for the download + * in the original file; requesting tree should not contain + * DBLOCKs prior to the file_start_offset + * @param desired_length desired number of bytes the user wanted to access + * (from file_start_offset). Resulting tree should not contain + * DBLOCKs after file_start_offset + file_length. + * @return download request tree for the given range of DBLOCKs at + * the specified depth + */ +static struct DownloadRequest * +create_download_request (struct DownloadRequest *parent, unsigned int depth, + uint64_t dr_offset, uint64_t file_start_offset, + uint64_t desired_length) +{ + struct DownloadRequest *dr; + unsigned int i; + unsigned int head_skip; + uint64_t child_block_size; + + dr = GNUNET_malloc (sizeof (struct DownloadRequest)); + dr->parent = parent; + dr->depth = depth; + dr->offset = dr_offset; + if (depth > 0) + { + child_block_size = GNUNET_FS_tree_compute_tree_size (depth - 1); + + /* calculate how many blocks at this level are not interesting + * from the start (rounded down), either because of the requested + * file offset or because this IBlock is further along */ + if (dr_offset < file_start_offset) + head_skip = file_start_offset / child_block_size; + else + head_skip = dr_offset / child_block_size; + + /* calculate index of last block at this level that is interesting (rounded up) */ + dr->num_children = file_start_offset + desired_length / child_block_size; + if (dr->num_children * child_block_size < + file_start_offset + desired_length) + dr->num_children++; /* round up */ + + /* now we can get the total number of children for this block */ + dr->num_children -= head_skip; + if (dr->num_children > CHK_PER_INODE) + dr->num_children = CHK_PER_INODE; /* cap at max */ + + /* why else would we have gotten here to begin with? (that'd be a bad logic error) */ + GNUNET_assert (dr->num_children > 0); + + dr->children = + GNUNET_malloc (dr->num_children * sizeof (struct DownloadRequest *)); + for (i = 0; i < dr->num_children; i++) + dr->children[i] = + create_download_request (dr, depth - 1, + dr_offset + i * child_block_size, + file_start_offset, desired_length); + } + return dr; +} + + +/** + * Continuation after a possible attempt to reconstruct + * the current IBlock from the existing file. + * + * @param cls the 'struct ReconstructContext' + * @param tc scheduler context + */ +static void +reconstruct_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + + /* clean up state from tree encoder */ + if (dc->te != NULL) + { + GNUNET_FS_tree_encoder_finish (dc->te, NULL, NULL); + dc->te = NULL; + } + if (dc->task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (dc->task); + dc->task = GNUNET_SCHEDULER_NO_TASK; + } + if (dc->rfh != NULL) + { + GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (dc->rfh)); + dc->rfh = NULL; + } + /* start "normal" download */ + schedule_block_download (dc, dc->top_request); +} + + +/** + * Task requesting the next block from the tree encoder. + * + * @param cls the 'struct GNUJNET_FS_DownloadContext' we're processing + * @param tc task context + */ +static void +get_next_block (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + + dc->task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_FS_tree_encoder_next (dc->te); +} + + + +/** + * Function called asking for the current (encoded) + * block to be processed. After processing the + * client should either call "GNUNET_FS_tree_encode_next" + * or (on error) "GNUNET_FS_tree_encode_finish". + * + * This function checks if the content on disk matches + * the expected content based on the URI. + * + * @param cls closure + * @param chk content hash key for the block + * @param offset offset of the block + * @param depth depth of the block, 0 for DBLOCK + * @param type type of the block (IBLOCK or DBLOCK) + * @param block the (encrypted) block + * @param block_size size of block (in bytes) + */ +static void +reconstruct_cb (void *cls, const struct ContentHashKey *chk, uint64_t offset, + unsigned int depth, enum GNUNET_BLOCK_Type type, + const void *block, uint16_t block_size) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + struct GNUNET_FS_ProgressInfo pi; + struct DownloadRequest *dr; + uint64_t blen; + unsigned int chld; + + /* find corresponding request entry */ + dr = dc->top_request; + while (dr->depth > depth) + { + blen = GNUNET_FS_tree_compute_tree_size (dr->depth); + chld = (offset - dr->offset) / blen; + GNUNET_assert (chld < dr->num_children); + dr = dr->children[chld]; + } + /* FIXME: this code needs more testing and might + need to handle more states... */ + switch (dr->state) + { + case BRS_INIT: + break; + case BRS_RECONSTRUCT_DOWN: + break; + case BRS_RECONSTRUCT_META_UP: + break; + case BRS_RECONSTRUCT_UP: + break; + case BRS_CHK_SET: + if (0 == memcmp (chk, &dr->chk, sizeof (struct ContentHashKey))) + { + /* block matches, hence tree below matches; + * this request is done! */ + dr->state = BRS_DOWNLOAD_UP; + GNUNET_break (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_remove (dc->active, &dr->chk.query, dr)); + if (GNUNET_YES == dr->is_pending) + { + GNUNET_break (0); /* how did we get here? */ + GNUNET_CONTAINER_DLL_remove (dc->pending_head, dc->pending_tail, dr); + dr->is_pending = GNUNET_NO; + } + /* calculate how many bytes of payload this block + * corresponds to */ + blen = GNUNET_FS_tree_compute_tree_size (dr->depth); + /* how many of those bytes are in the requested range? */ + blen = GNUNET_MIN (blen, dc->length + dc->offset - dr->offset); + /* signal progress */ + dc->completed += blen; + pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS; + pi.value.download.specifics.progress.data = NULL; + pi.value.download.specifics.progress.offset = offset; + pi.value.download.specifics.progress.data_len = 0; + pi.value.download.specifics.progress.depth = 0; + pi.value.download.specifics.progress.trust_offered = 0; + GNUNET_FS_download_make_status_ (&pi, dc); + /* FIXME: duplicated code from 'process_result_with_request - refactor */ + if (dc->completed == dc->length) + { + /* download completed, signal */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Download completed, truncating file to desired length %llu\n", + (unsigned long long) GNUNET_ntohll (dc->uri->data. + chk.file_length)); + /* truncate file to size (since we store IBlocks at the end) */ + if (dc->filename != NULL) + { + if (0 != + truncate (dc->filename, + GNUNET_ntohll (dc->uri->data.chk.file_length))) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "truncate", + dc->filename); + } + } + } + break; + case BRS_DOWNLOAD_DOWN: + break; + case BRS_DOWNLOAD_UP: + break; + case BRS_ERROR: + break; + default: + GNUNET_assert (0); + break; + } + if ((dr == dc->top_request) && (dr->state == BRS_DOWNLOAD_UP)) + { + check_completed (dc); + return; + } + dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); +} + + +/** + * Function called by the tree encoder to obtain a block of plaintext + * data (for the lowest level of the tree). + * + * @param cls our 'struct ReconstructContext' + * @param offset identifies which block to get + * @param max (maximum) number of bytes to get; returning + * fewer will also cause errors + * @param buf where to copy the plaintext buffer + * @param emsg location to store an error message (on error) + * @return number of bytes copied to buf, 0 on error + */ +static size_t +fh_reader (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + struct GNUNET_DISK_FileHandle *fh = dc->rfh; + ssize_t ret; + + *emsg = NULL; + if (offset != GNUNET_DISK_file_seek (fh, offset, GNUNET_DISK_SEEK_SET)) + { + *emsg = GNUNET_strdup (strerror (errno)); + return 0; + } + ret = GNUNET_DISK_file_read (fh, buf, max); + if (ret < 0) + { + *emsg = GNUNET_strdup (strerror (errno)); + return 0; + } + return ret; +} + + +/** + * Task that creates the initial (top-level) download + * request for the file. + * + * @param cls the 'struct GNUNET_FS_DownloadContext' + * @param tc scheduler context + */ +void +GNUNET_FS_download_start_task_ (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + struct GNUNET_FS_ProgressInfo pi; + struct GNUNET_DISK_FileHandle *fh; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start task running...\n"); + dc->task = GNUNET_SCHEDULER_NO_TASK; + if (dc->length == 0) + { + /* no bytes required! */ + if (dc->filename != NULL) + { + fh = GNUNET_DISK_file_open (dc->filename, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE | + ((0 == + GNUNET_FS_uri_chk_get_file_size (dc->uri)) ? + GNUNET_DISK_OPEN_TRUNCATE : 0), + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE | + GNUNET_DISK_PERM_GROUP_READ | + GNUNET_DISK_PERM_OTHER_READ); + GNUNET_DISK_file_close (fh); + } + GNUNET_FS_download_sync_ (dc); + pi.status = GNUNET_FS_STATUS_DOWNLOAD_START; + pi.value.download.specifics.start.meta = dc->meta; + GNUNET_FS_download_make_status_ (&pi, dc); + check_completed (dc); + return; + } + if (dc->emsg != NULL) + return; + if (dc->top_request == NULL) + { + dc->top_request = + create_download_request (NULL, dc->treedepth - 1, 0, dc->offset, + dc->length); + dc->top_request->state = BRS_CHK_SET; + dc->top_request->chk = + (dc->uri->type == + chk) ? dc->uri->data.chk.chk : dc->uri->data.loc.fi.chk; + /* signal start */ + GNUNET_FS_download_sync_ (dc); + if (NULL != dc->search) + GNUNET_FS_search_result_sync_ (dc->search); + pi.status = GNUNET_FS_STATUS_DOWNLOAD_START; + pi.value.download.specifics.start.meta = dc->meta; + GNUNET_FS_download_make_status_ (&pi, dc); + } + GNUNET_FS_download_start_downloading_ (dc); + /* attempt reconstruction from disk */ + if (GNUNET_YES == GNUNET_DISK_file_test (dc->filename)) + dc->rfh = + GNUNET_DISK_file_open (dc->filename, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (dc->top_request->state == BRS_CHK_SET) + { + if (dc->rfh != NULL) + { + /* first, try top-down */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying top-down reconstruction for `%s'\n", dc->filename); + try_top_down_reconstruction (dc, dc->top_request); + switch (dc->top_request->state) + { + case BRS_CHK_SET: + break; /* normal */ + case BRS_DOWNLOAD_DOWN: + break; /* normal, some blocks already down */ + case BRS_DOWNLOAD_UP: + /* already done entirely, party! */ + if (dc->rfh != NULL) + { + /* avoid hanging on to file handle longer than + * necessary */ + GNUNET_DISK_file_close (dc->rfh); + dc->rfh = NULL; + } + return; + case BRS_ERROR: + GNUNET_asprintf (&dc->emsg, _("Invalid URI")); + GNUNET_FS_download_sync_ (dc); + pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; + pi.value.download.specifics.error.message = dc->emsg; + GNUNET_FS_download_make_status_ (&pi, dc); + return; + default: + GNUNET_assert (0); + break; + } + } + } + /* attempt reconstruction from meta data */ + if ((GNUNET_FS_uri_chk_get_file_size (dc->uri) <= MAX_INLINE_SIZE) && + (NULL != dc->meta)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying to find embedded meta data for download of size %llu with %u bytes MD\n", + (unsigned long long) GNUNET_FS_uri_chk_get_file_size (dc->uri), + (unsigned int) + GNUNET_CONTAINER_meta_data_get_serialized_size (dc->meta)); + GNUNET_CONTAINER_meta_data_iterate (dc->meta, &match_full_data, dc); + if (dc->top_request->state == BRS_DOWNLOAD_UP) + { + if (dc->rfh != NULL) + { + /* avoid hanging on to file handle longer than + * necessary */ + GNUNET_DISK_file_close (dc->rfh); + dc->rfh = NULL; + } + return; /* finished, status update was already done for us */ + } + } + if (dc->rfh != NULL) + { + /* finally, try bottom-up */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying bottom-up reconstruction of file `%s'\n", dc->filename); + dc->te = + GNUNET_FS_tree_encoder_create (dc->h, dc->old_file_size, dc, &fh_reader, + &reconstruct_cb, NULL, + &reconstruct_cont); + dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); + } + else + { + /* simple, top-level download */ + schedule_block_download (dc, dc->top_request); + } + if (dc->top_request->state == BRS_DOWNLOAD_UP) + check_completed (dc); +} + + +/** + * Create SUSPEND event for the given download operation + * and then clean up our state (without stop signal). + * + * @param cls the 'struct GNUNET_FS_DownloadContext' to signal for + */ +void +GNUNET_FS_download_signal_suspend_ (void *cls) +{ + struct GNUNET_FS_DownloadContext *dc = cls; + struct GNUNET_FS_ProgressInfo pi; + + if (dc->top != NULL) + GNUNET_FS_end_top (dc->h, dc->top); + while (NULL != dc->child_head) + GNUNET_FS_download_signal_suspend_ (dc->child_head); + if (dc->search != NULL) + { + dc->search->download = NULL; + dc->search = NULL; + } + if (dc->job_queue != NULL) + { + GNUNET_FS_dequeue_ (dc->job_queue); + dc->job_queue = NULL; + } + if (dc->parent != NULL) + GNUNET_CONTAINER_DLL_remove (dc->parent->child_head, dc->parent->child_tail, + dc); + if (dc->task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (dc->task); + dc->task = GNUNET_SCHEDULER_NO_TASK; + } + pi.status = GNUNET_FS_STATUS_DOWNLOAD_SUSPEND; + GNUNET_FS_download_make_status_ (&pi, dc); + if (dc->te != NULL) + { + GNUNET_FS_tree_encoder_finish (dc->te, NULL, NULL); + dc->te = NULL; + } + if (dc->rfh != NULL) + { + GNUNET_DISK_file_close (dc->rfh); + dc->rfh = NULL; + } + GNUNET_FS_free_download_request_ (dc->top_request); + if (dc->active != NULL) + { + GNUNET_CONTAINER_multihashmap_destroy (dc->active); + dc->active = NULL; + } + GNUNET_free_non_null (dc->filename); + GNUNET_CONTAINER_meta_data_destroy (dc->meta); + GNUNET_FS_uri_destroy (dc->uri); + GNUNET_free_non_null (dc->temp_filename); + GNUNET_free_non_null (dc->serialization); + GNUNET_free (dc); +} + + +/** + * Download parts of a file. Note that this will store + * the blocks at the respective offset in the given file. Also, the + * download is still using the blocking of the underlying FS + * encoding. As a result, the download may *write* outside of the + * given boundaries (if offset and length do not match the 32k FS + * block boundaries).

+ * + * This function should be used to focus a download towards a + * particular portion of the file (optimization), not to strictly + * limit the download to exactly those bytes. + * + * @param h handle to the file sharing subsystem + * @param uri the URI of the file (determines what to download); CHK or LOC URI + * @param meta known metadata for the file (can be NULL) + * @param filename where to store the file, maybe NULL (then no file is + * created on disk and data must be grabbed from the callbacks) + * @param tempname where to store temporary file data, not used if filename is non-NULL; + * can be NULL (in which case we will pick a name if needed); the temporary file + * may already exist, in which case we will try to use the data that is there and + * if it is not what is desired, will overwrite it + * @param offset at what offset should we start the download (typically 0) + * @param length how many bytes should be downloaded starting at offset + * @param anonymity anonymity level to use for the download + * @param options various options + * @param cctx initial value for the client context for this download + * @param parent parent download to associate this download with (use NULL + * for top-level downloads; useful for manually-triggered recursive downloads) + * @return context that can be used to control this download + */ +struct GNUNET_FS_DownloadContext * +GNUNET_FS_download_start (struct GNUNET_FS_Handle *h, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_CONTAINER_MetaData *meta, + const char *filename, const char *tempname, + uint64_t offset, uint64_t length, uint32_t anonymity, + enum GNUNET_FS_DownloadOptions options, void *cctx, + struct GNUNET_FS_DownloadContext *parent) +{ + struct GNUNET_FS_DownloadContext *dc; + + GNUNET_assert (GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)); + + if ((offset + length < offset) || + (offset + length > GNUNET_FS_uri_chk_get_file_size (uri))) + { + GNUNET_break (0); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting download `%s' of %llu bytes\n", + filename, (unsigned long long) length); + dc = GNUNET_malloc (sizeof (struct GNUNET_FS_DownloadContext)); + dc->h = h; + dc->parent = parent; + if (parent != NULL) + { + GNUNET_CONTAINER_DLL_insert (parent->child_head, parent->child_tail, dc); + } + dc->uri = GNUNET_FS_uri_dup (uri); + dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); + dc->client_info = cctx; + dc->start_time = GNUNET_TIME_absolute_get (); + if (NULL != filename) + { + dc->filename = GNUNET_strdup (filename); + if (GNUNET_YES == GNUNET_DISK_file_test (filename)) + GNUNET_DISK_file_size (filename, &dc->old_file_size, GNUNET_YES); + } + if (GNUNET_FS_uri_test_loc (dc->uri)) + GNUNET_assert (GNUNET_OK == + GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target)); + dc->offset = offset; + dc->length = length; + dc->anonymity = anonymity; + dc->options = options; + dc->active = + GNUNET_CONTAINER_multihashmap_create (1 + 2 * (length / DBLOCK_SIZE)); + dc->treedepth = + GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri)); + if ((filename == NULL) && (is_recursive_download (dc))) + { + if (tempname != NULL) + dc->temp_filename = GNUNET_strdup (tempname); + else + dc->temp_filename = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp"); + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download tree has depth %u\n", + dc->treedepth); + if (parent == NULL) + { + dc->top = + GNUNET_FS_make_top (dc->h, &GNUNET_FS_download_signal_suspend_, dc); + } + dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc); + return dc; +} + + +/** + * Download parts of a file based on a search result. The download + * will be associated with the search result (and the association + * will be preserved when serializing/deserializing the state). + * If the search is stopped, the download will not be aborted but + * be 'promoted' to a stand-alone download. + * + * As with the other download function, this will store + * the blocks at the respective offset in the given file. Also, the + * download is still using the blocking of the underlying FS + * encoding. As a result, the download may *write* outside of the + * given boundaries (if offset and length do not match the 32k FS + * block boundaries).

+ * + * The given range can be used to focus a download towards a + * particular portion of the file (optimization), not to strictly + * limit the download to exactly those bytes. + * + * @param h handle to the file sharing subsystem + * @param sr the search result to use for the download (determines uri and + * meta data and associations) + * @param filename where to store the file, maybe NULL (then no file is + * created on disk and data must be grabbed from the callbacks) + * @param tempname where to store temporary file data, not used if filename is non-NULL; + * can be NULL (in which case we will pick a name if needed); the temporary file + * may already exist, in which case we will try to use the data that is there and + * if it is not what is desired, will overwrite it + * @param offset at what offset should we start the download (typically 0) + * @param length how many bytes should be downloaded starting at offset + * @param anonymity anonymity level to use for the download + * @param options various download options + * @param cctx initial value for the client context for this download + * @return context that can be used to control this download + */ +struct GNUNET_FS_DownloadContext * +GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h, + struct GNUNET_FS_SearchResult *sr, + const char *filename, + const char *tempname, uint64_t offset, + uint64_t length, uint32_t anonymity, + enum GNUNET_FS_DownloadOptions options, + void *cctx) +{ + struct GNUNET_FS_DownloadContext *dc; + + if ((sr == NULL) || (sr->download != NULL)) + { + GNUNET_break (0); + return NULL; + } + GNUNET_assert (GNUNET_FS_uri_test_chk (sr->uri) || + GNUNET_FS_uri_test_loc (sr->uri)); + if ((offset + length < offset) || + (offset + length > sr->uri->data.chk.file_length)) + { + GNUNET_break (0); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting download `%s' of %llu bytes\n", + filename, (unsigned long long) length); + dc = GNUNET_malloc (sizeof (struct GNUNET_FS_DownloadContext)); + dc->h = h; + dc->search = sr; + sr->download = dc; + if (sr->probe_ctx != NULL) + { + GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); + sr->probe_ctx = NULL; + } + dc->uri = GNUNET_FS_uri_dup (sr->uri); + dc->meta = GNUNET_CONTAINER_meta_data_duplicate (sr->meta); + dc->client_info = cctx; + dc->start_time = GNUNET_TIME_absolute_get (); + if (NULL != filename) + { + dc->filename = GNUNET_strdup (filename); + if (GNUNET_YES == GNUNET_DISK_file_test (filename)) + GNUNET_DISK_file_size (filename, &dc->old_file_size, GNUNET_YES); + } + if (GNUNET_FS_uri_test_loc (dc->uri)) + GNUNET_assert (GNUNET_OK == + GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target)); + dc->offset = offset; + dc->length = length; + dc->anonymity = anonymity; + dc->options = options; + dc->active = + GNUNET_CONTAINER_multihashmap_create (1 + 2 * (length / DBLOCK_SIZE)); + dc->treedepth = + GNUNET_FS_compute_depth (GNUNET_ntohll (dc->uri->data.chk.file_length)); + if ((filename == NULL) && (is_recursive_download (dc))) + { + if (tempname != NULL) + dc->temp_filename = GNUNET_strdup (tempname); + else + dc->temp_filename = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp"); + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download tree has depth %u\n", + dc->treedepth); + dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc); + return dc; +} + + +/** + * Start the downloading process (by entering the queue). + * + * @param dc our download context + */ +void +GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc) +{ + if (dc->completed == dc->length) + return; + GNUNET_assert (dc->job_queue == NULL); + dc->job_queue = + GNUNET_FS_queue_ (dc->h, &activate_fs_download, &deactivate_fs_download, + dc, (dc->length + DBLOCK_SIZE - 1) / DBLOCK_SIZE); +} + + +/** + * Stop a download (aborts if download is incomplete). + * + * @param dc handle for the download + * @param do_delete delete files of incomplete downloads + */ +void +GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc, int do_delete) +{ + struct GNUNET_FS_ProgressInfo pi; + int have_children; + + if (dc->top != NULL) + GNUNET_FS_end_top (dc->h, dc->top); + + + if (dc->task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (dc->task); + dc->task = GNUNET_SCHEDULER_NO_TASK; + } + if (dc->search != NULL) + { + dc->search->download = NULL; + GNUNET_FS_search_result_sync_ (dc->search); + dc->search = NULL; + } + if (dc->job_queue != NULL) + { + GNUNET_FS_dequeue_ (dc->job_queue); + dc->job_queue = NULL; + } + if (dc->te != NULL) + { + GNUNET_FS_tree_encoder_finish (dc->te, NULL, NULL); + dc->te = NULL; + } + have_children = (NULL != dc->child_head) ? GNUNET_YES : GNUNET_NO; + while (NULL != dc->child_head) + GNUNET_FS_download_stop (dc->child_head, do_delete); + if (dc->parent != NULL) + GNUNET_CONTAINER_DLL_remove (dc->parent->child_head, dc->parent->child_tail, + dc); + if (dc->serialization != NULL) + GNUNET_FS_remove_sync_file_ (dc->h, + ((dc->parent != NULL) || + (dc->search != + NULL)) ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD : + GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, + dc->serialization); + if ((GNUNET_YES == have_children) && (dc->parent == NULL)) + GNUNET_FS_remove_sync_dir_ (dc->h, + (dc->search != + NULL) ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD : + GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, + dc->serialization); + pi.status = GNUNET_FS_STATUS_DOWNLOAD_STOPPED; + GNUNET_FS_download_make_status_ (&pi, dc); + GNUNET_FS_free_download_request_ (dc->top_request); + dc->top_request = NULL; + if (dc->active != NULL) + { + GNUNET_CONTAINER_multihashmap_destroy (dc->active); + dc->active = NULL; + } + if (dc->filename != NULL) + { + if ((dc->completed != dc->length) && (GNUNET_YES == do_delete)) + { + if (0 != UNLINK (dc->filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", + dc->filename); + } + GNUNET_free (dc->filename); + } + GNUNET_CONTAINER_meta_data_destroy (dc->meta); + GNUNET_FS_uri_destroy (dc->uri); + if (NULL != dc->temp_filename) + { + if (0 != UNLINK (dc->temp_filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", + dc->temp_filename); + GNUNET_free (dc->temp_filename); + } + GNUNET_free_non_null (dc->serialization); + GNUNET_free (dc); +} + +/* end of fs_download.c */ diff --git a/src/fs/fs_file_information.c b/src/fs/fs_file_information.c new file mode 100644 index 0000000..85a076f --- /dev/null +++ b/src/fs/fs_file_information.c @@ -0,0 +1,453 @@ +/* + This file is part of GNUnet. + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_file_information.c + * @brief Manage information for publishing directory hierarchies + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include "gnunet_fs_service.h" +#include "fs_api.h" +#include "fs_tree.h" + + +/** + * Obtain the name under which this file information + * structure is stored on disk. Only works for top-level + * file information structures. + * + * @param s structure to get the filename for + * @return NULL on error, otherwise filename that + * can be passed to "GNUNET_FS_file_information_recover" + * to read this fi-struct from disk. + */ +const char * +GNUNET_FS_file_information_get_id (struct GNUNET_FS_FileInformation *s) +{ + if (NULL != s->dir) + return NULL; + return s->serialization; +} + +/** + * Obtain the filename from the file information structure. + * + * @param s structure to get the filename for + * @return "filename" field of the structure (can be NULL) + */ +const char * +GNUNET_FS_file_information_get_filename (struct GNUNET_FS_FileInformation *s) +{ + return s->filename; +} + + +/** + * Set the filename in the file information structure. + * If filename was already set, frees it before setting the new one. + * Makes a copy of the argument. + * + * @param s structure to get the filename for + * @param filename filename to set + */ +void +GNUNET_FS_file_information_set_filename (struct GNUNET_FS_FileInformation *s, + const char *filename) +{ + GNUNET_free_non_null (s->filename); + if (filename) + s->filename = GNUNET_strdup (filename); + else + s->filename = NULL; +} + +/** + * Create an entry for a file in a publish-structure. + * + * @param h handle to the file sharing subsystem + * @param client_info initial value for the client-info value for this entry + * @param filename name of the file or directory to publish + * @param keywords under which keywords should this file be available + * directly; can be NULL + * @param meta metadata for the file + * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, + * GNUNET_SYSERR for simulation + * @param bo block options + * @return publish structure entry for the file + */ +struct GNUNET_FS_FileInformation * +GNUNET_FS_file_information_create_from_file (struct GNUNET_FS_Handle *h, + void *client_info, + const char *filename, + const struct GNUNET_FS_Uri + *keywords, + const struct + GNUNET_CONTAINER_MetaData *meta, + int do_index, + const struct GNUNET_FS_BlockOptions + *bo) +{ + struct FileInfo *fi; + struct stat sbuf; + struct GNUNET_FS_FileInformation *ret; + const char *fn; + const char *ss; + +#if WINDOWS + char fn_conv[MAX_PATH]; +#endif + + if (0 != STAT (filename, &sbuf)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename); + return NULL; + } + fi = GNUNET_FS_make_file_reader_context_ (filename); + if (fi == NULL) + { + GNUNET_break (0); + return NULL; + } + ret = + GNUNET_FS_file_information_create_from_reader (h, client_info, + sbuf.st_size, + &GNUNET_FS_data_reader_file_, + fi, keywords, meta, + do_index, bo); + if (ret == NULL) + return NULL; + ret->h = h; + ret->filename = GNUNET_strdup (filename); +#if !WINDOWS + fn = filename; +#else + plibc_conv_to_win_path (filename, fn_conv); + fn = fn_conv; +#endif + while (NULL != (ss = strstr (fn, DIR_SEPARATOR_STR))) + fn = ss + 1; +#if !WINDOWS + GNUNET_CONTAINER_meta_data_insert (ret->meta, "", + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, + EXTRACTOR_METAFORMAT_C_STRING, + "text/plain", fn, strlen (fn) + 1); +#else + GNUNET_CONTAINER_meta_data_insert (ret->meta, "", + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", fn, strlen (fn) + 1); +#endif + return ret; +} + + +/** + * Create an entry for a file in a publish-structure. + * + * @param h handle to the file sharing subsystem + * @param client_info initial value for the client-info value for this entry + * @param length length of the file + * @param data data for the file (should not be used afterwards by + * the caller; callee will "free") + * @param keywords under which keywords should this file be available + * directly; can be NULL + * @param meta metadata for the file + * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, + * GNUNET_SYSERR for simulation + * @param bo block options + * @return publish structure entry for the file + */ +struct GNUNET_FS_FileInformation * +GNUNET_FS_file_information_create_from_data (struct GNUNET_FS_Handle *h, + void *client_info, uint64_t length, + void *data, + const struct GNUNET_FS_Uri + *keywords, + const struct + GNUNET_CONTAINER_MetaData *meta, + int do_index, + const struct GNUNET_FS_BlockOptions + *bo) +{ + if (GNUNET_YES == do_index) + { + GNUNET_break (0); + return NULL; + } + return GNUNET_FS_file_information_create_from_reader (h, client_info, length, + &GNUNET_FS_data_reader_copy_, + data, keywords, meta, + do_index, bo); +} + + +/** + * Create an entry for a file in a publish-structure. + * + * @param h handle to the file sharing subsystem + * @param client_info initial value for the client-info value for this entry + * @param length length of the file + * @param reader function that can be used to obtain the data for the file + * @param reader_cls closure for "reader" + * @param keywords under which keywords should this file be available + * directly; can be NULL + * @param meta metadata for the file + * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, + * GNUNET_SYSERR for simulation + * @param bo block options + * @return publish structure entry for the file + */ +struct GNUNET_FS_FileInformation * +GNUNET_FS_file_information_create_from_reader (struct GNUNET_FS_Handle *h, + void *client_info, + uint64_t length, + GNUNET_FS_DataReader reader, + void *reader_cls, + const struct GNUNET_FS_Uri + *keywords, + const struct + GNUNET_CONTAINER_MetaData *meta, + int do_index, + const struct + GNUNET_FS_BlockOptions *bo) +{ + struct GNUNET_FS_FileInformation *ret; + + if ((GNUNET_YES == do_index) && (reader != &GNUNET_FS_data_reader_file_)) + { + GNUNET_break (0); + return NULL; + } + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation)); + ret->h = h; + ret->client_info = client_info; + ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); + if (ret->meta == NULL) + ret->meta = GNUNET_CONTAINER_meta_data_create (); + ret->keywords = (keywords == NULL) ? NULL : GNUNET_FS_uri_dup (keywords); + ret->data.file.reader = reader; + ret->data.file.reader_cls = reader_cls; + ret->data.file.do_index = do_index; + ret->data.file.file_size = length; + ret->bo = *bo; + return ret; +} + + +/** + * Test if a given entry represents a directory. + * + * @param ent check if this FI represents a directory + * @return GNUNET_YES if so, GNUNET_NO if not + */ +int +GNUNET_FS_file_information_is_directory (const struct GNUNET_FS_FileInformation + *ent) +{ + return ent->is_directory; +} + + +/** + * Create an entry for an empty directory in a publish-structure. + * This function should be used by applications for which the + * use of "GNUNET_FS_file_information_create_from_directory" + * is not appropriate. + * + * @param h handle to the file sharing subsystem + * @param client_info initial value for the client-info value for this entry + * @param meta metadata for the directory + * @param keywords under which keywords should this directory be available + * directly; can be NULL + * @param bo block options + * @param filename name of the directory; can be NULL + * @return publish structure entry for the directory , NULL on error + */ +struct GNUNET_FS_FileInformation * +GNUNET_FS_file_information_create_empty_directory (struct GNUNET_FS_Handle *h, + void *client_info, + const struct GNUNET_FS_Uri + *keywords, + const struct + GNUNET_CONTAINER_MetaData + *meta, + const struct + GNUNET_FS_BlockOptions *bo, + const char *filename) +{ + struct GNUNET_FS_FileInformation *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation)); + ret->h = h; + ret->client_info = client_info; + ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); + ret->keywords = GNUNET_FS_uri_dup (keywords); + ret->bo = *bo; + ret->is_directory = GNUNET_YES; + if (filename != NULL) + ret->filename = GNUNET_strdup (filename); + return ret; +} + + +/** + * Add an entry to a directory in a publish-structure. Clients + * should never modify publish structures that were passed to + * "GNUNET_FS_publish_start" already. + * + * @param dir the directory + * @param ent the entry to add; the entry must not have been + * added to any other directory at this point and + * must not include "dir" in its structure + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_FS_file_information_add (struct GNUNET_FS_FileInformation *dir, + struct GNUNET_FS_FileInformation *ent) +{ + if ((ent->dir != NULL) || (ent->next != NULL) || (dir->is_directory != GNUNET_YES)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + ent->dir = dir; + ent->next = dir->data.dir.entries; + dir->data.dir.entries = ent; + dir->data.dir.dir_size = 0; + return GNUNET_OK; +} + + +/** + * Inspect a file or directory in a publish-structure. Clients + * should never modify publish structures that were passed to + * "GNUNET_FS_publish_start" already. When called on a directory, + * this function will FIRST call "proc" with information about + * the directory itself and then for each of the files in the + * directory (but not for files in subdirectories). When called + * on a file, "proc" will be called exactly once (with information + * about the specific file). + * + * @param dir the directory + * @param proc function to call on each entry + * @param proc_cls closure for proc + */ +void +GNUNET_FS_file_information_inspect (struct GNUNET_FS_FileInformation *dir, + GNUNET_FS_FileInformationProcessor proc, + void *proc_cls) +{ + struct GNUNET_FS_FileInformation *pos; + int no; + + no = GNUNET_NO; + if (GNUNET_OK != + proc (proc_cls, dir, + (dir->is_directory == GNUNET_YES) ? dir->data.dir.dir_size : dir->data. + file.file_size, dir->meta, &dir->keywords, &dir->bo, + (dir->is_directory == GNUNET_YES) ? &no : &dir->data.file.do_index, + &dir->client_info)) + return; + if (dir->is_directory != GNUNET_YES) + return; + pos = dir->data.dir.entries; + while (pos != NULL) + { + no = GNUNET_NO; + if (GNUNET_OK != + proc (proc_cls, pos, + (pos->is_directory == GNUNET_YES) ? pos->data.dir.dir_size : pos->data. + file.file_size, pos->meta, &pos->keywords, &pos->bo, + (pos->is_directory == GNUNET_YES) ? &no : &pos->data.file.do_index, + &pos->client_info)) + break; + pos = pos->next; + } +} + + +/** + * Destroy publish-structure. Clients should never destroy publish + * structures that were passed to "GNUNET_FS_publish_start" already. + * + * @param fi structure to destroy + * @param cleaner function to call on each entry in the structure + * (useful to clean up client_info); can be NULL; return + * values are ignored + * @param cleaner_cls closure for cleaner + */ +void +GNUNET_FS_file_information_destroy (struct GNUNET_FS_FileInformation *fi, + GNUNET_FS_FileInformationProcessor cleaner, + void *cleaner_cls) +{ + struct GNUNET_FS_FileInformation *pos; + int no; + + no = GNUNET_NO; + if (fi->is_directory == GNUNET_YES) + { + /* clean up directory */ + while (NULL != (pos = fi->data.dir.entries)) + { + fi->data.dir.entries = pos->next; + GNUNET_FS_file_information_destroy (pos, cleaner, cleaner_cls); + } + /* clean up client-info */ + if (NULL != cleaner) + cleaner (cleaner_cls, fi, fi->data.dir.dir_size, fi->meta, &fi->keywords, + &fi->bo, &no, &fi->client_info); + GNUNET_free_non_null (fi->data.dir.dir_data); + } + else + { + /* call clean-up function of the reader */ + if (fi->data.file.reader != NULL) + fi->data.file.reader (fi->data.file.reader_cls, 0, 0, NULL, NULL); + /* clean up client-info */ + if (NULL != cleaner) + cleaner (cleaner_cls, fi, fi->data.file.file_size, fi->meta, + &fi->keywords, &fi->bo, &fi->data.file.do_index, + &fi->client_info); + } + GNUNET_free_non_null (fi->filename); + GNUNET_free_non_null (fi->emsg); + GNUNET_free_non_null (fi->chk_uri); + /* clean up serialization */ + if ((NULL != fi->serialization) && (0 != UNLINK (fi->serialization))) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", + fi->serialization); + if (NULL != fi->keywords) + GNUNET_FS_uri_destroy (fi->keywords); + if (NULL != fi->meta) + GNUNET_CONTAINER_meta_data_destroy (fi->meta); + GNUNET_free_non_null (fi->serialization); + if (fi->te != NULL) + { + GNUNET_FS_tree_encoder_finish (fi->te, NULL, NULL); + fi->te = NULL; + } + GNUNET_free (fi); +} + + +/* end of fs_file_information.c */ diff --git a/src/fs/fs_getopt.c b/src/fs/fs_getopt.c new file mode 100644 index 0000000..0374774 --- /dev/null +++ b/src/fs/fs_getopt.c @@ -0,0 +1,197 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_getopt.c + * @brief helper functions for command-line argument processing + * @author Igor Wronsky, Christian Grothoff + */ +#include "platform.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" + +/* ******************** command-line option parsing API ******************** */ + +/** + * Command-line option parser function that allows the user + * to specify one or more '-k' options with keywords. Each + * specified keyword will be added to the URI. A pointer to + * the URI must be passed as the "scls" argument. + * + * @param ctx command line processor context + * @param scls must be of type "struct GNUNET_FS_Uri **" + * @param option name of the option (typically 'k') + * @param value command line argument given + * @return GNUNET_OK on success + */ +int +GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext + *ctx, void *scls, const char *option, + const char *value) +{ + struct GNUNET_FS_Uri **uri = scls; + struct GNUNET_FS_Uri *u = *uri; + char *val; + size_t slen; + + if (u == NULL) + { + u = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + *uri = u; + u->type = ksk; + u->data.ksk.keywordCount = 0; + u->data.ksk.keywords = NULL; + } + else + { + GNUNET_assert (u->type == ksk); + } + slen = strlen (value); + if (slen == 0) + return GNUNET_SYSERR; /* cannot be empty */ + if (value[0] == '+') + { + /* simply preserve the "mandatory" flag */ + if (slen < 2) + return GNUNET_SYSERR; /* empty keywords not allowed */ + if ((value[1] == '"') && (slen > 3) && (value[slen - 1] == '"')) + { + /* remove the quotes, keep the '+' */ + val = GNUNET_malloc (slen - 1); + val[0] = '+'; + memcpy (&val[1], &value[2], slen - 3); + val[slen - 2] = '\0'; + } + else + { + /* no quotes, just keep the '+' */ + val = GNUNET_strdup (value); + } + } + else + { + if ((value[0] == '"') && (slen > 2) && (value[slen - 1] == '"')) + { + /* remove the quotes, add a space */ + val = GNUNET_malloc (slen); + val[0] = ' '; + memcpy (&val[1], &value[1], slen - 2); + val[slen - 1] = '\0'; + } + else + { + /* add a space to indicate "not mandatory" */ + val = GNUNET_malloc (slen + 2); + strcpy (val, " "); + strcat (val, value); + } + } + GNUNET_array_append (u->data.ksk.keywords, u->data.ksk.keywordCount, val); + return GNUNET_OK; +} + + +/** + * Command-line option parser function that allows the user to specify + * one or more '-m' options with metadata. Each specified entry of + * the form "type=value" will be added to the metadata. A pointer to + * the metadata must be passed as the "scls" argument. + * + * @param ctx command line processor context + * @param scls must be of type "struct GNUNET_MetaData **" + * @param option name of the option (typically 'k') + * @param value command line argument given + * @return GNUNET_OK on success + */ +int +GNUNET_FS_getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext + *ctx, void *scls, const char *option, + const char *value) +{ + struct GNUNET_CONTAINER_MetaData **mm = scls; + enum EXTRACTOR_MetaType type; + const char *typename; + const char *typename_i18n; + struct GNUNET_CONTAINER_MetaData *meta; + char *tmp; + + meta = *mm; + if (meta == NULL) + { + meta = GNUNET_CONTAINER_meta_data_create (); + *mm = meta; + } + +#if ENABLE_NLS + tmp = GNUNET_STRINGS_to_utf8 (value, strlen (value), nl_langinfo (CODESET)); +#else + tmp = GNUNET_STRINGS_to_utf8 (value, strlen (value), "utf-8"); +#endif + type = EXTRACTOR_metatype_get_max (); + while (type > 0) + { + type--; + typename = EXTRACTOR_metatype_to_string (type); + typename_i18n = dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, typename); + if ((strlen (tmp) >= strlen (typename) + 1) && + (tmp[strlen (typename)] == ':') && + (0 == strncmp (typename, tmp, strlen (typename)))) + { + GNUNET_CONTAINER_meta_data_insert (meta, "", type, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + &tmp[strlen (typename) + 1], + strlen (&tmp[strlen (typename) + 1]) + + 1); + GNUNET_free (tmp); + tmp = NULL; + break; + } + if ((strlen (tmp) >= strlen (typename_i18n) + 1) && + (tmp[strlen (typename_i18n)] == ':') && + (0 == strncmp (typename_i18n, tmp, strlen (typename_i18n)))) + { + GNUNET_CONTAINER_meta_data_insert (meta, "", type, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + &tmp[strlen (typename_i18n) + 1], + strlen (&tmp + [strlen (typename_i18n) + 1]) + + 1); + GNUNET_free (tmp); + tmp = NULL; + break; + } + } + if (tmp != NULL) + { + GNUNET_CONTAINER_meta_data_insert (meta, "", + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + tmp, strlen (tmp) + 1); + GNUNET_free (tmp); + printf (_ + ("Unknown metadata type in metadata option `%s'. Using metadata type `unknown' instead.\n"), + value); + } + return GNUNET_OK; +} + +/* end of fs_getopt.c */ diff --git a/src/fs/fs_list_indexed.c b/src/fs/fs_list_indexed.c new file mode 100644 index 0000000..784c988 --- /dev/null +++ b/src/fs/fs_list_indexed.c @@ -0,0 +1,184 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_list_indexed.c + * @author Christian Grothoff + * @brief provide a list of all indexed files + */ + +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_fs_service.h" +#include "gnunet_protocols.h" +#include "fs_api.h" + + +/** + * Context for "GNUNET_FS_get_indexed_files". + */ +struct GNUNET_FS_GetIndexedContext +{ + /** + * Handle to global FS context. + */ + struct GNUNET_FS_Handle *h; + + /** + * Connection to the FS service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Function to call for each indexed file. + */ + GNUNET_FS_IndexedFileProcessor iterator; + + /** + * Closure for iterator. + */ + void *iterator_cls; + + /** + * Continuation to trigger at the end. + */ + GNUNET_SCHEDULER_Task cont; + + /** + * Closure for cont. + */ + void *cont_cls; +}; + + +/** + * Function called on each response from the FS + * service with information about indexed files. + * + * @param cls closure (of type "struct GNUNET_FS_GetIndexedContext*") + * @param msg message with indexing information + */ +static void +handle_index_info (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_FS_GetIndexedContext *gic = cls; + const struct IndexInfoMessage *iim; + uint16_t msize; + const char *filename; + + if (NULL == msg) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Failed to receive response for `%s' request from `%s' service.\n"), + "GET_INDEXED", "fs"); + (void) gic->iterator (gic->iterator_cls, NULL, NULL); + GNUNET_FS_get_indexed_files_cancel (gic); + return; + } + if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END) + { + /* normal end-of-list */ + (void) gic->iterator (gic->iterator_cls, NULL, NULL); + GNUNET_FS_get_indexed_files_cancel (gic); + return; + } + msize = ntohs (msg->size); + iim = (const struct IndexInfoMessage *) msg; + filename = (const char *) &iim[1]; + if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY) || + (msize <= sizeof (struct IndexInfoMessage)) || + (filename[msize - sizeof (struct IndexInfoMessage) - 1] != '\0')) + { + /* bogus reply */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Failed to receive valid response for `%s' request from `%s' service.\n"), + "GET_INDEXED", "fs"); + (void) gic->iterator (gic->iterator_cls, NULL, NULL); + GNUNET_FS_get_indexed_files_cancel (gic); + return; + } + if (GNUNET_OK != gic->iterator (gic->iterator_cls, filename, &iim->file_id)) + { + GNUNET_FS_get_indexed_files_cancel (gic); + return; + } + /* get more */ + GNUNET_CLIENT_receive (gic->client, &handle_index_info, gic, + GNUNET_CONSTANTS_SERVICE_TIMEOUT); +} + + +/** + * Iterate over all indexed files. + * + * @param h handle to the file sharing subsystem + * @param iterator function to call on each indexed file + * @param iterator_cls closure for iterator + * @return NULL on error ('iter' is not called) + */ +struct GNUNET_FS_GetIndexedContext * +GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h, + GNUNET_FS_IndexedFileProcessor iterator, + void *iterator_cls) +{ + struct GNUNET_CLIENT_Connection *client; + struct GNUNET_FS_GetIndexedContext *gic; + struct GNUNET_MessageHeader msg; + + client = GNUNET_CLIENT_connect ("fs", h->cfg); + if (NULL == client) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to not connect to `%s' service.\n"), "fs"); + return NULL; + } + gic = GNUNET_malloc (sizeof (struct GNUNET_FS_GetIndexedContext)); + gic->h = h; + gic->client = client; + gic->iterator = iterator; + gic->iterator_cls = iterator_cls; + msg.size = htons (sizeof (struct GNUNET_MessageHeader)); + msg.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET); + GNUNET_assert (GNUNET_OK == + GNUNET_CLIENT_transmit_and_get_response (client, &msg, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + GNUNET_YES, + &handle_index_info, + gic)); + return gic; +} + + +/** + * Cancel iteration over all indexed files. + * + * @param gic operation to cancel + */ +void +GNUNET_FS_get_indexed_files_cancel (struct GNUNET_FS_GetIndexedContext *gic) +{ + GNUNET_CLIENT_disconnect (gic->client, GNUNET_NO); + GNUNET_free (gic); +} + + +/* end of fs_list_indexed.c */ diff --git a/src/fs/fs_misc.c b/src/fs/fs_misc.c new file mode 100644 index 0000000..89dc486 --- /dev/null +++ b/src/fs/fs_misc.c @@ -0,0 +1,231 @@ +/* + This file is part of GNUnet. + (C) 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/fs_misc.c + * @brief misc. functions related to file-sharing in general + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" + + +/** + * Suggest a filename based on given metadata. + * + * @param md given meta data + * @return NULL if meta data is useless for suggesting a filename + */ +char * +GNUNET_FS_meta_data_suggest_filename (const struct GNUNET_CONTAINER_MetaData + *md) +{ + static const char *mimeMap[][2] = { + {"application/bz2", ".bz2"}, + {"application/gnunet-directory", ".gnd"}, + {"application/java", ".class"}, + {"application/msword", ".doc"}, + {"application/ogg", ".ogg"}, + {"application/pdf", ".pdf"}, + {"application/pgp-keys", ".key"}, + {"application/pgp-signature", ".pgp"}, + {"application/postscript", ".ps"}, + {"application/rar", ".rar"}, + {"application/rtf", ".rtf"}, + {"application/xml", ".xml"}, + {"application/x-debian-package", ".deb"}, + {"application/x-dvi", ".dvi"}, + {"applixation/x-flac", ".flac"}, + {"applixation/x-gzip", ".gz"}, + {"application/x-java-archive", ".jar"}, + {"application/x-java-vm", ".class"}, + {"application/x-python-code", ".pyc"}, + {"application/x-redhat-package-manager", ".rpm"}, + {"application/x-rpm", ".rpm"}, + {"application/x-tar", ".tar"}, + {"application/x-tex-pk", ".pk"}, + {"application/x-texinfo", ".texinfo"}, + {"application/x-xcf", ".xcf"}, + {"application/x-xfig", ".xfig"}, + {"application/zip", ".zip"}, + + {"audio/midi", ".midi"}, + {"audio/mpeg", ".mp3"}, + {"audio/real", ".rm"}, + {"audio/x-wav", ".wav"}, + + {"image/gif", ".gif"}, + {"image/jpeg", ".jpg"}, + {"image/pcx", ".pcx"}, + {"image/png", ".png"}, + {"image/tiff", ".tiff"}, + {"image/x-ms-bmp", ".bmp"}, + {"image/x-xpixmap", ".xpm"}, + + {"text/css", ".css"}, + {"text/html", ".html"}, + {"text/plain", ".txt"}, + {"text/rtf", ".rtf"}, + {"text/x-c++hdr", ".h++"}, + {"text/x-c++src", ".c++"}, + {"text/x-chdr", ".h"}, + {"text/x-csrc", ".c"}, + {"text/x-java", ".java"}, + {"text/x-moc", ".moc"}, + {"text/x-pascal", ".pas"}, + {"text/x-perl", ".pl"}, + {"text/x-python", ".py"}, + {"text/x-tex", ".tex"}, + + {"video/avi", ".avi"}, + {"video/mpeg", ".mpeg"}, + {"video/quicktime", ".qt"}, + {"video/real", ".rm"}, + {"video/x-msvideo", ".avi"}, + {NULL, NULL}, + }; + char *ret; + unsigned int i; + char *mime; + char *base; + const char *ext; + + ret = + GNUNET_CONTAINER_meta_data_get_by_type (md, + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); + if (ret != NULL) + return ret; + ext = NULL; + mime = + GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE); + if (mime != NULL) + { + i = 0; + while ((mimeMap[i][0] != NULL) && (0 != strcmp (mime, mimeMap[i][0]))) + i++; + if (mimeMap[i][1] == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + _("Did not find mime type `%s' in extension list.\n"), mime); + else + ext = mimeMap[i][1]; + GNUNET_free (mime); + } + base = + GNUNET_CONTAINER_meta_data_get_first_by_types (md, + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METATYPE_BOOK_TITLE, + EXTRACTOR_METATYPE_ORIGINAL_TITLE, + EXTRACTOR_METATYPE_PACKAGE_NAME, + EXTRACTOR_METATYPE_URL, + EXTRACTOR_METATYPE_URI, + EXTRACTOR_METATYPE_DESCRIPTION, + EXTRACTOR_METATYPE_ISRC, + EXTRACTOR_METATYPE_JOURNAL_NAME, + EXTRACTOR_METATYPE_AUTHOR_NAME, + EXTRACTOR_METATYPE_SUBJECT, + EXTRACTOR_METATYPE_ALBUM, + EXTRACTOR_METATYPE_ARTIST, + EXTRACTOR_METATYPE_KEYWORDS, + EXTRACTOR_METATYPE_COMMENT, + EXTRACTOR_METATYPE_UNKNOWN, + -1); + if ((base == NULL) && (ext == NULL)) + return NULL; + if (base == NULL) + return GNUNET_strdup (ext); + if (ext == NULL) + return base; + GNUNET_asprintf (&ret, "%s%s", base, ext); + GNUNET_free (base); + return ret; +} + + +/** + * Return the current year (i.e. '2011'). + */ +unsigned int +GNUNET_FS_get_current_year () +{ + time_t tp; + struct tm *t; + + tp = time (NULL); + t = gmtime (&tp); + if (t == NULL) + return 0; + return t->tm_year + 1900; +} + + +/** + * Convert a year to an expiration time of January 1st of that year. + * + * @param year a year (after 1970, please ;-)). + * @return absolute time for January 1st of that year. + */ +struct GNUNET_TIME_Absolute +GNUNET_FS_year_to_time (unsigned int year) +{ + struct GNUNET_TIME_Absolute ret; + time_t tp; + struct tm t; + + memset (&t, 0, sizeof (t)); + if (year < 1900) + { + GNUNET_break (0); + return GNUNET_TIME_absolute_get (); /* now */ + } + t.tm_year = year - 1900; + t.tm_mday = 1; + t.tm_mon = 1; + t.tm_wday = 1; + t.tm_yday = 1; + tp = mktime (&t); + GNUNET_break (tp != (time_t) - 1); + ret.abs_value = tp * 1000LL; /* seconds to ms */ + return ret; +} + + +/** + * Convert an expiration time to the respective year (rounds) + * + * @param at absolute time + * @return year a year (after 1970), 0 on error + */ +unsigned int +GNUNET_FS_time_to_year (struct GNUNET_TIME_Absolute at) +{ + struct tm *t; + time_t tp; + + tp = at.abs_value / 1000; /* ms to seconds */ + t = gmtime (&tp); + if (t == NULL) + return 0; + return t->tm_year + 1900; + +} + + +/* end of fs_misc.c */ diff --git a/src/fs/fs_namespace.c b/src/fs/fs_namespace.c new file mode 100644 index 0000000..bfd7594 --- /dev/null +++ b/src/fs/fs_namespace.c @@ -0,0 +1,954 @@ +/* + This file is part of GNUnet + (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_namespace.c + * @brief create and destroy namespaces + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_signatures.h" +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" + + +/** + * Maximum legal size for an sblock. + */ +#define MAX_SBLOCK_SIZE (60 * 1024) + + +/** + * Return the name of the directory in which we store + * our local namespaces (or rather, their public keys). + * + * @param h global fs handle + * @return NULL on error, otherwise the name of the directory + */ +static char * +get_namespace_directory (struct GNUNET_FS_Handle *h) +{ + char *dn; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (h->cfg, "FS", "IDENTITY_DIR", + &dn)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Configuration fails to specify `%s' in section `%s'\n"), + "IDENTITY_DIR", "fs"); + return NULL; + } + return dn; +} + + +/** + * Return the name of the directory in which we store + * the update information graph for the given local namespace. + * + * @param ns namespace handle + * @return NULL on error, otherwise the name of the directory + */ +static char * +get_update_information_directory (struct GNUNET_FS_Namespace *ns) +{ + char *dn; + char *ret; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (ns->h->cfg, "FS", "UPDATE_DIR", + &dn)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Configuration fails to specify `%s' in section `%s'\n"), + "UPDATE_DIR", "fs"); + return NULL; + } + GNUNET_asprintf (&ret, "%s%s%s", dn, DIR_SEPARATOR_STR, ns->name); + GNUNET_free (dn); + return ret; +} + + +/** + * Write the namespace update node graph to a file. + * + * @param ns namespace to dump + */ +static void +write_update_information_graph (struct GNUNET_FS_Namespace *ns) +{ + char *fn; + struct GNUNET_BIO_WriteHandle *wh; + unsigned int i; + struct NamespaceUpdateNode *n; + char *uris; + + fn = get_update_information_directory (ns); + wh = GNUNET_BIO_write_open (fn); + if (wh == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to open `%s' for writing: %s\n"), STRERROR (errno)); + GNUNET_free (fn); + return; + } + if (GNUNET_OK != GNUNET_BIO_write_int32 (wh, ns->update_node_count)) + goto END; + for (i = 0; i < ns->update_node_count; i++) + { + n = ns->update_nodes[i]; + uris = GNUNET_FS_uri_to_string (n->uri); + if ((GNUNET_OK != GNUNET_BIO_write_string (wh, n->id)) || + (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, n->md)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, n->update)) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, uris))) + { + GNUNET_free (uris); + break; + } + GNUNET_free (uris); + } +END: + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to write `%s': %s\n"), + STRERROR (errno)); + GNUNET_free (fn); +} + + +/** + * Read the namespace update node graph from a file. + * + * @param ns namespace to read + */ +static void +read_update_information_graph (struct GNUNET_FS_Namespace *ns) +{ + char *fn; + struct GNUNET_BIO_ReadHandle *rh; + unsigned int i; + struct NamespaceUpdateNode *n; + char *uris; + uint32_t count; + char *emsg; + + fn = get_update_information_directory (ns); + if (GNUNET_YES != GNUNET_DISK_file_test (fn)) + { + GNUNET_free (fn); + return; + } + rh = GNUNET_BIO_read_open (fn); + if (rh == NULL) + { + GNUNET_free (fn); + return; + } + if (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &count)) + { + GNUNET_break (0); + goto END; + } + if (count > 1024 * 1024) + { + GNUNET_break (0); + goto END; + } + if (count == 0) + { + GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL)); + GNUNET_free (fn); + return; + } + ns->update_nodes = + GNUNET_malloc (count * sizeof (struct NamespaceUpdateNode *)); + + for (i = 0; i < count; i++) + { + n = GNUNET_malloc (sizeof (struct NamespaceUpdateNode)); + if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "identifier", &n->id, 1024)) + || (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "meta", &n->md)) || + (GNUNET_OK != + GNUNET_BIO_read_string (rh, "update-id", &n->update, 1024)) || + (GNUNET_OK != GNUNET_BIO_read_string (rh, "uri", &uris, 1024 * 2))) + { + GNUNET_break (0); + GNUNET_free_non_null (n->id); + GNUNET_free_non_null (n->update); + if (n->md != NULL) + GNUNET_CONTAINER_meta_data_destroy (n->md); + GNUNET_free (n); + break; + } + n->uri = GNUNET_FS_uri_parse (uris, &emsg); + GNUNET_free (uris); + if (n->uri == NULL) + { + GNUNET_break (0); + GNUNET_free (emsg); + GNUNET_free (n->id); + GNUNET_free_non_null (n->update); + GNUNET_CONTAINER_meta_data_destroy (n->md); + GNUNET_free (n); + break; + } + ns->update_nodes[i] = n; + } + ns->update_node_count = i; +END: + if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to write `%s': %s\n"), emsg); + GNUNET_free (emsg); + } + GNUNET_free (fn); +} + + + + +/** + * Create a namespace with the given name; if one already + * exists, return a handle to the existing namespace. + * + * @param h handle to the file sharing subsystem + * @param name name to use for the namespace + * @return handle to the namespace, NULL on error + */ +struct GNUNET_FS_Namespace * +GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h, const char *name) +{ + char *dn; + char *fn; + struct GNUNET_FS_Namespace *ret; + + dn = get_namespace_directory (h); + GNUNET_asprintf (&fn, "%s%s%s", dn, DIR_SEPARATOR_STR, name); + GNUNET_free (dn); + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace)); + ret->h = h; + ret->rc = 1; + ret->key = GNUNET_CRYPTO_rsa_key_create_from_file (fn); + if (ret->key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to create or read private key for namespace `%s'\n"), + name); + GNUNET_free (ret); + GNUNET_free (fn); + return NULL; + } + ret->name = GNUNET_strdup (name); + ret->filename = fn; + return ret; +} + + +/** + * Duplicate a namespace handle. + * + * @param ns namespace handle + * @return duplicated handle to the namespace + */ +struct GNUNET_FS_Namespace * +GNUNET_FS_namespace_dup (struct GNUNET_FS_Namespace *ns) +{ + ns->rc++; + return ns; +} + + +/** + * Delete a namespace handle. Can be used for a clean shutdown (free + * memory) or also to freeze the namespace to prevent further + * insertions by anyone. + * + * @param namespace handle to the namespace that should be deleted / freed + * @param freeze prevents future insertions; creating a namespace + * with the same name again will create a fresh namespace instead + * + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace, int freeze) +{ + unsigned int i; + struct NamespaceUpdateNode *nsn; + + namespace->rc--; + if (freeze) + { + if (0 != UNLINK (namespace->filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", + namespace->filename); + } + if (0 != namespace->rc) + return GNUNET_OK; + GNUNET_CRYPTO_rsa_key_free (namespace->key); + GNUNET_free (namespace->filename); + GNUNET_free (namespace->name); + for (i = 0; i < namespace->update_node_count; i++) + { + nsn = namespace->update_nodes[i]; + GNUNET_CONTAINER_meta_data_destroy (nsn->md); + GNUNET_FS_uri_destroy (nsn->uri); + GNUNET_free (nsn->id); + GNUNET_free (nsn->update); + GNUNET_free (nsn); + } + GNUNET_array_grow (namespace->update_nodes, namespace->update_node_count, + 0); + if (namespace->update_map != NULL) + GNUNET_CONTAINER_multihashmap_destroy (namespace->update_map); + GNUNET_free (namespace); + return GNUNET_OK; +} + + +/** + * Context for the 'process_namespace' callback. + * Specifies a function to call on each namespace. + */ +struct ProcessNamespaceContext +{ + /** + * Function to call. + */ + GNUNET_FS_NamespaceInfoProcessor cb; + + /** + * Closure for 'cb'. + */ + void *cb_cls; +}; + + +/** + * Function called with a filename of a namespace. Reads the key and + * calls the callback. + * + * @param cls closure (struct ProcessNamespaceContext) + * @param filename complete filename (absolute path) + * @return GNUNET_OK to continue to iterate, + * GNUNET_SYSERR to abort iteration with error! + */ +static int +process_namespace (void *cls, const char *filename) +{ + struct ProcessNamespaceContext *pnc = cls; + struct GNUNET_CRYPTO_RsaPrivateKey *key; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk; + GNUNET_HashCode id; + const char *name; + const char *t; + + key = GNUNET_CRYPTO_rsa_key_create_from_file (filename); + if (key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Failed to read namespace private key file `%s', deleting it!\n"), + filename); + if (0 != UNLINK (filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); + return GNUNET_OK; + } + GNUNET_CRYPTO_rsa_key_get_public (key, &pk); + GNUNET_CRYPTO_rsa_key_free (key); + GNUNET_CRYPTO_hash (&pk, sizeof (pk), &id); + name = filename; + while (NULL != (t = strstr (name, DIR_SEPARATOR_STR))) + name = t + 1; + pnc->cb (pnc->cb_cls, name, &id); + return GNUNET_OK; +} + + +/** + * Build a list of all available local (!) namespaces The returned + * names are only the nicknames since we only iterate over the local + * namespaces. + * + * @param h handle to the file sharing subsystem + * @param cb function to call on each known namespace + * @param cb_cls closure for cb + */ +void +GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h, + GNUNET_FS_NamespaceInfoProcessor cb, void *cb_cls) +{ + char *dn; + struct ProcessNamespaceContext ctx; + + dn = get_namespace_directory (h); + if (dn == NULL) + return; + ctx.cb = cb; + ctx.cb_cls = cb_cls; + GNUNET_DISK_directory_scan (dn, &process_namespace, &ctx); + GNUNET_free (dn); +} + + +/** + * Context for the SKS publication. + */ +struct GNUNET_FS_PublishSksContext +{ + + /** + * URI of the new entry in the namespace. + */ + struct GNUNET_FS_Uri *uri; + + /** + * Namespace update node to add to namespace on success (or to be + * deleted if publishing failed). + */ + struct NamespaceUpdateNode *nsn; + + /** + * Namespace we're publishing to. + */ + struct GNUNET_FS_Namespace *namespace; + + /** + * Handle to the datastore. + */ + struct GNUNET_DATASTORE_Handle *dsh; + + /** + * Function to call once we're done. + */ + GNUNET_FS_PublishContinuation cont; + + /** + * Closure for cont. + */ + void *cont_cls; + + /** + * Handle for our datastore request. + */ + struct GNUNET_DATASTORE_QueueEntry *dqe; +}; + + +/** + * Function called by the datastore API with + * the result from the PUT (SBlock) request. + * + * @param cls closure of type "struct GNUNET_FS_PublishSksContext*" + * @param success GNUNET_OK on success + * @param min_expiration minimum expiration time required for content to be stored + * @param msg error message (or NULL) + */ +static void +sb_put_cont (void *cls, int success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg) +{ + struct GNUNET_FS_PublishSksContext *psc = cls; + GNUNET_HashCode hc; + + psc->dqe = NULL; + if (GNUNET_OK != success) + { + if (NULL != psc->cont) + psc->cont (psc->cont_cls, NULL, msg); + GNUNET_FS_publish_sks_cancel (psc); + return; + } + if (NULL != psc->nsn) + { + /* FIXME: this can be done much more + * efficiently by simply appending to the + * file and overwriting the 4-byte header */ + if (psc->namespace->update_nodes == NULL) + read_update_information_graph (psc->namespace); + GNUNET_array_append (psc->namespace->update_nodes, + psc->namespace->update_node_count, psc->nsn); + if (psc->namespace->update_map != NULL) + { + GNUNET_CRYPTO_hash (psc->nsn->id, strlen (psc->nsn->id), &hc); + GNUNET_CONTAINER_multihashmap_put (psc->namespace->update_map, &hc, + psc->nsn, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + } + psc->nsn = NULL; + write_update_information_graph (psc->namespace); + } + if (NULL != psc->cont) + psc->cont (psc->cont_cls, psc->uri, NULL); + GNUNET_FS_publish_sks_cancel (psc); +} + + +/** + * Publish an SBlock on GNUnet. + * + * @param h handle to the file sharing subsystem + * @param namespace namespace to publish in + * @param identifier identifier to use + * @param update update identifier to use + * @param meta metadata to use + * @param uri URI to refer to in the SBlock + * @param bo block options + * @param options publication options + * @param cont continuation + * @param cont_cls closure for cont + * @return NULL on error ('cont' will still be called) + */ +struct GNUNET_FS_PublishSksContext * +GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, + struct GNUNET_FS_Namespace *namespace, + const char *identifier, const char *update, + const struct GNUNET_CONTAINER_MetaData *meta, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_FS_BlockOptions *bo, + enum GNUNET_FS_PublishOptions options, + GNUNET_FS_PublishContinuation cont, void *cont_cls) +{ + struct GNUNET_FS_PublishSksContext *psc; + struct GNUNET_CRYPTO_AesSessionKey sk; + struct GNUNET_CRYPTO_AesInitializationVector iv; + struct GNUNET_FS_Uri *sks_uri; + char *uris; + size_t size; + size_t slen; + size_t nidlen; + size_t idlen; + ssize_t mdsize; + struct SBlock *sb; + struct SBlock *sb_enc; + char *dest; + struct GNUNET_CONTAINER_MetaData *mmeta; + GNUNET_HashCode key; /* hash of thisId = key */ + GNUNET_HashCode id; /* hash of hc = identifier */ + GNUNET_HashCode query; /* id ^ nsid = DB query */ + + if (NULL == meta) + mmeta = GNUNET_CONTAINER_meta_data_create (); + else + mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta); + uris = GNUNET_FS_uri_to_string (uri); + slen = strlen (uris) + 1; + idlen = strlen (identifier); + if (update != NULL) + nidlen = strlen (update) + 1; + else + nidlen = 1; + mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta); + size = sizeof (struct SBlock) + slen + nidlen + mdsize; + if (size > MAX_SBLOCK_SIZE) + { + size = MAX_SBLOCK_SIZE; + mdsize = size - (sizeof (struct SBlock) + slen + nidlen); + } + sb = GNUNET_malloc (sizeof (struct SBlock) + size); + dest = (char *) &sb[1]; + if (update != NULL) + memcpy (dest, update, nidlen); + else + memset (dest, 0, 1); + dest += nidlen; + memcpy (dest, uris, slen); + GNUNET_free (uris); + dest += slen; + mdsize = + GNUNET_CONTAINER_meta_data_serialize (mmeta, &dest, mdsize, + GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); + GNUNET_CONTAINER_meta_data_destroy (mmeta); + if (mdsize == -1) + { + GNUNET_break (0); + GNUNET_free (sb); + if (NULL != cont) + cont (cont_cls, NULL, _("Internal error.")); + return NULL; + } + size = sizeof (struct SBlock) + mdsize + slen + nidlen; + sb_enc = GNUNET_malloc (size); + GNUNET_CRYPTO_hash (identifier, idlen, &key); + GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id); + sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + sks_uri->type = sks; + GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace); + GNUNET_CRYPTO_hash (&sb_enc->subspace, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &sks_uri->data.sks.namespace); + sks_uri->data.sks.identifier = GNUNET_strdup (identifier); + GNUNET_CRYPTO_hash_xor (&id, &sks_uri->data.sks.namespace, + &sb_enc->identifier); + GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv); + GNUNET_CRYPTO_aes_encrypt (&sb[1], size - sizeof (struct SBlock), &sk, &iv, + &sb_enc[1]); + sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK); + sb_enc->purpose.size = + htonl (slen + mdsize + nidlen + sizeof (struct SBlock) - + sizeof (struct GNUNET_CRYPTO_RsaSignature)); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (namespace->key, &sb_enc->purpose, + &sb_enc->signature)); + psc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishSksContext)); + psc->uri = sks_uri; + psc->cont = cont; + psc->namespace = GNUNET_FS_namespace_dup (namespace); + psc->cont_cls = cont_cls; + if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) + { + GNUNET_free (sb_enc); + GNUNET_free (sb); + sb_put_cont (psc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); + return NULL; + } + psc->dsh = GNUNET_DATASTORE_connect (h->cfg); + if (NULL == psc->dsh) + { + GNUNET_free (sb_enc); + GNUNET_free (sb); + sb_put_cont (psc, GNUNET_NO, GNUNET_TIME_UNIT_ZERO_ABS, _("Failed to connect to datastore.")); + return NULL; + } + GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.namespace, &id, &query); + if (NULL != update) + { + psc->nsn = GNUNET_malloc (sizeof (struct NamespaceUpdateNode)); + psc->nsn->id = GNUNET_strdup (identifier); + psc->nsn->update = GNUNET_strdup (update); + psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta); + psc->nsn->uri = GNUNET_FS_uri_dup (uri); + } + psc->dqe = GNUNET_DATASTORE_put (psc->dsh, 0, &sb_enc->identifier, size, sb_enc, + GNUNET_BLOCK_TYPE_FS_SBLOCK, bo->content_priority, + bo->anonymity_level, bo->replication_level, + bo->expiration_time, -2, 1, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, &sb_put_cont, psc); + GNUNET_free (sb); + GNUNET_free (sb_enc); + return psc; +} + + +/** + * Abort the SKS publishing operation. + * + * @param psc context of the operation to abort. + */ +void +GNUNET_FS_publish_sks_cancel (struct GNUNET_FS_PublishSksContext *psc) +{ + if (NULL != psc->dqe) + { + GNUNET_DATASTORE_cancel (psc->dqe); + psc->dqe = NULL; + } + if (NULL != psc->dsh) + { + GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO); + psc->dsh = NULL; + } + GNUNET_FS_namespace_delete (psc->namespace, GNUNET_NO); + GNUNET_FS_uri_destroy (psc->uri); + if (NULL != psc->nsn) + { + GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md); + GNUNET_FS_uri_destroy (psc->nsn->uri); + GNUNET_free (psc->nsn->id); + GNUNET_free (psc->nsn->update); + GNUNET_free (psc->nsn); + } + GNUNET_free (psc); +} + + +/** + * Closure for 'process_update_node'. + */ +struct ProcessUpdateClosure +{ + /** + * Function to call for each node. + */ + GNUNET_FS_IdentifierProcessor ip; + + /** + * Closure for 'ip'. + */ + void *ip_cls; +}; + + +/** + * Call the iterator in the closure for each node. + * + * @param cls closure (of type 'struct ProcessUpdateClosure *') + * @param key current key code + * @param value value in the hash map (of type 'struct NamespaceUpdateNode *') + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +process_update_node (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ProcessUpdateClosure *pc = cls; + struct NamespaceUpdateNode *nsn = value; + + pc->ip (pc->ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update); + return GNUNET_YES; +} + + +/** + * Closure for 'find_trees'. + */ +struct FindTreeClosure +{ + /** + * Namespace we are operating on. + */ + struct GNUNET_FS_Namespace *namespace; + + /** + * Array with 'head's of TREEs. + */ + struct NamespaceUpdateNode **tree_array; + + /** + * Size of 'tree_array' + */ + unsigned int tree_array_size; + + /** + * Current generational ID used. + */ + unsigned int nug; + + /** + * Identifier for the current TREE, or UINT_MAX for none yet. + */ + unsigned int id; +}; + + +/** + * Find all nodes reachable from the current node (including the + * current node itself). If they are in no tree, add them to the + * current one. If they are the head of another tree, merge the + * trees. If they are in the middle of another tree, let them be. + * We can tell that a node is already in an tree by checking if + * its 'nug' field is set to the current 'nug' value. It is the + * head of an tree if it is in the 'tree_array' under its respective + * 'tree_id'. + * + * In short, we're trying to find the smallest number of tree to + * cover a directed graph. + * + * @param cls closure (of type 'struct FindTreeClosure') + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +find_trees (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct FindTreeClosure *fc = cls; + struct NamespaceUpdateNode *nsn = value; + GNUNET_HashCode hc; + + if (nsn->nug == fc->nug) + { + if (nsn->tree_id == UINT_MAX) + return GNUNET_YES; /* circular */ + GNUNET_assert (nsn->tree_id < fc->tree_array_size); + if (fc->tree_array[nsn->tree_id] != nsn) + return GNUNET_YES; /* part of "another" (directed) TREE, + * and not root of it, end trace */ + if (nsn->tree_id == fc->id) + return GNUNET_YES; /* that's our own root (can this be?) */ + /* merge existing TREE, we have a root for both */ + fc->tree_array[nsn->tree_id] = NULL; + if (fc->id == UINT_MAX) + fc->id = nsn->tree_id; /* take over ID */ + } + else + { + nsn->nug = fc->nug; + nsn->tree_id = UINT_MAX; /* mark as undef */ + /* trace */ + GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc); + GNUNET_CONTAINER_multihashmap_get_multiple (fc->namespace->update_map, &hc, + &find_trees, fc); + } + return GNUNET_YES; +} + + +/** + * List all of the identifiers in the namespace for which we could + * produce an update. Namespace updates form a graph where each node + * has a name. Each node can have any number of URI/meta-data entries + * which can each be linked to other nodes. Cycles are possible. + * + * Calling this function with "next_id" NULL will cause the library to + * call "ip" with a root for each strongly connected component of the + * graph (a root being a node from which all other nodes in the Tree + * are reachable). + * + * Calling this function with "next_id" being the name of a node will + * cause the library to call "ip" with all children of the node. Note + * that cycles within the final tree are possible (including self-loops). + * I know, odd definition of a tree, but the GUI will display an actual + * tree (GtkTreeView), so that's what counts for the term here. + * + * @param namespace namespace to inspect for updateable content + * @param next_id ID to look for; use NULL to look for tree roots + * @param ip function to call on each updateable identifier + * @param ip_cls closure for ip + */ +void +GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace, + const char *next_id, + GNUNET_FS_IdentifierProcessor ip, + void *ip_cls) +{ + unsigned int i; + unsigned int nug; + GNUNET_HashCode hc; + struct NamespaceUpdateNode *nsn; + struct ProcessUpdateClosure pc; + struct FindTreeClosure fc; + + if (namespace->update_nodes == NULL) + read_update_information_graph (namespace); + if (namespace->update_nodes == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No updateable nodes found for ID `%s'\n", next_id); + return; /* no nodes */ + } + if (namespace->update_map == NULL) + { + /* need to construct */ + namespace->update_map = + GNUNET_CONTAINER_multihashmap_create (2 + + 3 * namespace->update_node_count / + 4); + for (i = 0; i < namespace->update_node_count; i++) + { + nsn = namespace->update_nodes[i]; + GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc); + GNUNET_CONTAINER_multihashmap_put (namespace->update_map, &hc, nsn, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + } + } + if (next_id != NULL) + { + GNUNET_CRYPTO_hash (next_id, strlen (next_id), &hc); + pc.ip = ip; + pc.ip_cls = ip_cls; + GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc, + &process_update_node, &pc); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Calculating TREEs to find roots of update trees\n"); + /* Find heads of TREEs in update graph */ + nug = ++namespace->nug_gen; + fc.tree_array = NULL; + fc.tree_array_size = 0; + + for (i = 0; i < namespace->update_node_count; i++) + { + nsn = namespace->update_nodes[i]; + if (nsn->nug == nug) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id, + nsn->nug); + continue; /* already placed in TREE */ + } + GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc); + nsn->nug = nug; + nsn->tree_id = UINT_MAX; + fc.id = UINT_MAX; + fc.nug = nug; + fc.namespace = namespace; + GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc, + &find_trees, &fc); + if (fc.id == UINT_MAX) + { + /* start new TREE */ + for (fc.id = 0; fc.id < fc.tree_array_size; fc.id++) + { + if (fc.tree_array[fc.id] == NULL) + { + fc.tree_array[fc.id] = nsn; + nsn->tree_id = fc.id; + break; + } + } + if (fc.id == fc.tree_array_size) + { + GNUNET_array_append (fc.tree_array, fc.tree_array_size, nsn); + nsn->tree_id = fc.id; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting new TREE %u with node `%s'\n", nsn->tree_id, + nsn->id); + /* put all nodes with same identifier into this TREE */ + GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc); + fc.id = nsn->tree_id; + fc.nug = nug; + fc.namespace = namespace; + GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc, + &find_trees, &fc); + } + else + { + /* make head of TREE "id" */ + fc.tree_array[fc.id] = nsn; + nsn->tree_id = fc.id; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id, + fc.id); + } + for (i = 0; i < fc.tree_array_size; i++) + { + nsn = fc.tree_array[i]; + if (NULL != nsn) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Root of TREE %u is node `%s'\n", i, + nsn->id); + ip (ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update); + } + } + GNUNET_array_grow (fc.tree_array, fc.tree_array_size, 0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done processing TREEs\n"); +} + + +/* end of fs_namespace.c */ diff --git a/src/fs/fs_namespace_advertise.c b/src/fs/fs_namespace_advertise.c new file mode 100644 index 0000000..e0226ca --- /dev/null +++ b/src/fs/fs_namespace_advertise.c @@ -0,0 +1,323 @@ +/* + This file is part of GNUnet + (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_namespace_advertise.c + * @brief advertise namespaces (creating NBlocks) + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_signatures.h" +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" + + +/** + * Maximum legal size for an nblock. + */ +#define MAX_NBLOCK_SIZE (60 * 1024) + + +/** + * Context for advertising a namespace. + */ +struct GNUNET_FS_AdvertisementContext +{ + /** + * Function to call with the result. + */ + GNUNET_FS_PublishContinuation cont; + + /** + * Closure for cont. + */ + void *cont_cls; + + /** + * Datastore handle. + */ + struct GNUNET_DATASTORE_Handle *dsh; + + /** + * Our KSK URI. + */ + struct GNUNET_FS_Uri *ksk_uri; + + /** + * Plaintext. + */ + char *pt; + + /** + * NBlock to sign and store. + */ + struct NBlock *nb; + + /** + * The namespace. + */ + struct GNUNET_FS_Namespace *ns; + + /** + * Current datastore queue entry for advertising. + */ + struct GNUNET_DATASTORE_QueueEntry *dqe; + + /** + * Block options. + */ + struct GNUNET_FS_BlockOptions bo; + + /** + * Number of bytes of plaintext. + */ + size_t pt_size; + + /** + * Current keyword offset. + */ + unsigned int pos; +}; + + +// FIXME: I see no good reason why this should need to be done +// in a new task (anymore). Integrate with 'cancel' function below? +/** + * Disconnect from the datastore. + * + * @param cls datastore handle + * @param tc scheduler context + */ +static void +do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_DATASTORE_Handle *dsh = cls; + + GNUNET_DATASTORE_disconnect (dsh, GNUNET_NO); +} + + +/** + * Continuation called to notify client about result of the + * operation. + * + * @param cls closure (our struct GNUNET_FS_AdvertismentContext) + * @param success GNUNET_SYSERR on failure + * @param min_expiration minimum expiration time required for content to be stored + * @param msg NULL on success, otherwise an error message + */ +static void +advertisement_cont (void *cls, int success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg) +{ + struct GNUNET_FS_AdvertisementContext *ac = cls; + const char *keyword; + GNUNET_HashCode key; + GNUNET_HashCode query; + struct GNUNET_CRYPTO_AesSessionKey skey; + struct GNUNET_CRYPTO_AesInitializationVector iv; + struct GNUNET_CRYPTO_RsaPrivateKey *pk; + + ac->dqe = NULL; + if (GNUNET_SYSERR == success) + { + /* error! */ + (void) GNUNET_SCHEDULER_add_now (&do_disconnect, ac->dsh); + ac->dsh = NULL; + if (msg == NULL) + { + GNUNET_break (0); + msg = _("Unknown error"); + } + if (ac->cont != NULL) + { + ac->cont (ac->cont_cls, NULL, msg); + ac->cont = NULL; + } + GNUNET_FS_namespace_advertise_cancel (ac); + return; + } + if (ac->pos == ac->ksk_uri->data.ksk.keywordCount) + { + /* done! */ + (void) GNUNET_SCHEDULER_add_now (&do_disconnect, ac->dsh); + ac->dsh = NULL; + if (ac->cont != NULL) + { + ac->cont (ac->cont_cls, ac->ksk_uri, NULL); + ac->cont = NULL; + } + GNUNET_FS_namespace_advertise_cancel (ac); + return; + } + keyword = ac->ksk_uri->data.ksk.keywords[ac->pos++]; + /* first character of keyword indicates if it is + * mandatory or not -- ignore for hashing */ + GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key); + GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); + GNUNET_CRYPTO_aes_encrypt (ac->pt, ac->pt_size, &skey, &iv, &ac->nb[1]); + GNUNET_break (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (ac->ns->key, &ac->nb->ns_purpose, + &ac->nb->ns_signature)); + pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key); + GNUNET_assert (pk != NULL); + GNUNET_CRYPTO_rsa_key_get_public (pk, &ac->nb->keyspace); + GNUNET_CRYPTO_hash (&ac->nb->keyspace, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &query); + GNUNET_break (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (pk, &ac->nb->ksk_purpose, + &ac->nb->ksk_signature)); + GNUNET_CRYPTO_rsa_key_free (pk); + ac->dqe = GNUNET_DATASTORE_put (ac->dsh, 0 /* no reservation */ , + &query, ac->pt_size + sizeof (struct NBlock), ac->nb, + GNUNET_BLOCK_TYPE_FS_NBLOCK, ac->bo.content_priority, + ac->bo.anonymity_level, ac->bo.replication_level, + ac->bo.expiration_time, -2, 1, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, &advertisement_cont, + ac); +} + + +/** + * Publish an advertismement for a namespace. + * + * @param h handle to the file sharing subsystem + * @param ksk_uri keywords to use for advertisment + * @param namespace handle for the namespace that should be advertised + * @param meta meta-data for the namespace advertisement + * @param bo block options + * @param rootEntry name of the root of the namespace + * @param cont continuation + * @param cont_cls closure for cont + * @return NULL on error ('cont' is still called) + */ +struct GNUNET_FS_AdvertisementContext * +GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, + struct GNUNET_FS_Uri *ksk_uri, + struct GNUNET_FS_Namespace *namespace, + const struct GNUNET_CONTAINER_MetaData *meta, + const struct GNUNET_FS_BlockOptions *bo, + const char *rootEntry, + GNUNET_FS_PublishContinuation cont, + void *cont_cls) +{ + size_t reslen; + size_t size; + ssize_t mdsize; + struct NBlock *nb; + char *mdst; + struct GNUNET_DATASTORE_Handle *dsh; + struct GNUNET_FS_AdvertisementContext *ctx; + char *pt; + + /* create advertisements */ + mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); + if (-1 == mdsize) + { + cont (cont_cls, NULL, _("Failed to serialize meta data")); + return NULL; + } + reslen = strlen (rootEntry) + 1; + size = mdsize + sizeof (struct NBlock) + reslen; + if (size > MAX_NBLOCK_SIZE) + { + size = MAX_NBLOCK_SIZE; + mdsize = size - sizeof (struct NBlock) - reslen; + } + + pt = GNUNET_malloc (mdsize + reslen); + memcpy (pt, rootEntry, reslen); + mdst = &pt[reslen]; + mdsize = + GNUNET_CONTAINER_meta_data_serialize (meta, &mdst, mdsize, + GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); + if (-1 == mdsize) + { + GNUNET_break (0); + GNUNET_free (pt); + cont (cont_cls, NULL, _("Failed to serialize meta data")); + return NULL; + } + size = mdsize + sizeof (struct NBlock) + reslen; + nb = GNUNET_malloc (size); + GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &nb->subspace); + nb->ns_purpose.size = + htonl (mdsize + reslen + + sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + nb->ns_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK); + nb->ksk_purpose.size = + htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature)); + nb->ksk_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG); + dsh = GNUNET_DATASTORE_connect (h->cfg); + if (NULL == dsh) + { + GNUNET_free (nb); + GNUNET_free (pt); + cont (cont_cls, NULL, _("Failed to connect to datastore service")); + return NULL; + } + ctx = GNUNET_malloc (sizeof (struct GNUNET_FS_AdvertisementContext)); + ctx->cont = cont; + ctx->cont_cls = cont_cls; + ctx->dsh = dsh; + ctx->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); + ctx->nb = nb; + ctx->pt = pt; + ctx->pt_size = mdsize + reslen; + ctx->ns = namespace; + ctx->ns->rc++; + ctx->bo = *bo; + advertisement_cont (ctx, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); + return ctx; +} + + +/** + * Abort the namespace advertisement operation. + * + * @param ac context of the operation to abort. + */ +void +GNUNET_FS_namespace_advertise_cancel (struct GNUNET_FS_AdvertisementContext *ac) +{ + if (NULL != ac->dqe) + { + GNUNET_DATASTORE_cancel (ac->dqe); + ac->dqe = NULL; + } + if (NULL != ac->dsh) + { + GNUNET_DATASTORE_disconnect (ac->dsh, GNUNET_NO); + ac->dsh = NULL; + } + GNUNET_FS_uri_destroy (ac->ksk_uri); + GNUNET_free (ac->pt); + GNUNET_free (ac->nb); + GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO); + GNUNET_free (ac); +} + + +/* end of fs_namespace_advertise.c */ diff --git a/src/fs/fs_publish.c b/src/fs/fs_publish.c new file mode 100644 index 0000000..1657e29 --- /dev/null +++ b/src/fs/fs_publish.c @@ -0,0 +1,1270 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_publish.c + * @brief publish a file or directory in GNUnet + * @see https://gnunet.org/encoding + * @author Krista Bennett + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_signatures.h" +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" +#include "fs_tree.h" + + +/** + * Fill in all of the generic fields for + * a publish event and call the callback. + * + * @param pi structure to fill in + * @param pc overall publishing context + * @param p file information for the file being published + * @param offset where in the file are we so far + * @return value returned from callback + */ +void * +GNUNET_FS_publish_make_status_ (struct GNUNET_FS_ProgressInfo *pi, + struct GNUNET_FS_PublishContext *pc, + const struct GNUNET_FS_FileInformation *p, + uint64_t offset) +{ + pi->value.publish.pc = pc; + pi->value.publish.fi = p; + pi->value.publish.cctx = p->client_info; + pi->value.publish.pctx = (NULL == p->dir) ? NULL : p->dir->client_info; + pi->value.publish.filename = p->filename; + pi->value.publish.size = + (p->is_directory == GNUNET_YES) ? p->data.dir.dir_size : p->data.file.file_size; + pi->value.publish.eta = + GNUNET_TIME_calculate_eta (p->start_time, offset, pi->value.publish.size); + pi->value.publish.completed = offset; + pi->value.publish.duration = + GNUNET_TIME_absolute_get_duration (p->start_time); + pi->value.publish.anonymity = p->bo.anonymity_level; + return pc->h->upcb (pc->h->upcb_cls, pi); +} + + +/** + * Cleanup the publish context, we're done with it. + * + * @param pc struct to clean up + */ +static void +publish_cleanup (struct GNUNET_FS_PublishContext *pc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up publish context (done!)\n"); + if (pc->fhc != NULL) + { + GNUNET_CRYPTO_hash_file_cancel (pc->fhc); + pc->fhc = NULL; + } + GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL); + if (pc->namespace != NULL) + { + GNUNET_FS_namespace_delete (pc->namespace, GNUNET_NO); + pc->namespace = NULL; + } + GNUNET_free_non_null (pc->nid); + GNUNET_free_non_null (pc->nuid); + GNUNET_free_non_null (pc->serialization); + if (pc->dsh != NULL) + { + GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO); + pc->dsh = NULL; + } + if (pc->client != NULL) + { + GNUNET_CLIENT_disconnect (pc->client, GNUNET_NO); + pc->client = NULL; + } + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); + GNUNET_free (pc); +} + + +/** + * Function called by the datastore API with + * the result from the PUT request. + * + * @param cls the 'struct GNUNET_FS_PublishContext' + * @param success GNUNET_OK on success + * @param min_expiration minimum expiration time required for content to be stored + * @param msg error message (or NULL) + */ +static void +ds_put_cont (void *cls, int success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_ProgressInfo pi; + + pc->qre = NULL; + if (GNUNET_SYSERR == success) + { + GNUNET_asprintf (&pc->fi_pos->emsg, _("Publishing failed: %s"), msg); + pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; + pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; + pi.value.publish.specifics.error.message = pc->fi_pos->emsg; + pc->fi_pos->client_info = + GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi_pos, 0); + if ((pc->fi_pos->is_directory != GNUNET_YES) && + (pc->fi_pos->filename != NULL) && + (pc->fi_pos->data.file.do_index == GNUNET_YES)) + { + /* run unindex to clean up */ + GNUNET_FS_unindex_start (pc->h, pc->fi_pos->filename, NULL); + } + } + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); + pc->upload_task = + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, + &GNUNET_FS_publish_main_, pc); +} + + +/** + * Generate the callback that signals clients + * that a file (or directory) has been completely + * published. + * + * @param p the completed upload + * @param pc context of the publication + */ +static void +signal_publish_completion (struct GNUNET_FS_FileInformation *p, + struct GNUNET_FS_PublishContext *pc) +{ + struct GNUNET_FS_ProgressInfo pi; + + pi.status = GNUNET_FS_STATUS_PUBLISH_COMPLETED; + pi.value.publish.eta = GNUNET_TIME_UNIT_ZERO; + pi.value.publish.specifics.completed.chk_uri = p->chk_uri; + p->client_info = + GNUNET_FS_publish_make_status_ (&pi, pc, p, + GNUNET_ntohll (p->chk_uri->data. + chk.file_length)); +} + + +/** + * Generate the callback that signals clients + * that a file (or directory) has encountered + * a problem during publication. + * + * @param p the upload that had trouble + * @param pc context of the publication + * @param emsg error message + */ +static void +signal_publish_error (struct GNUNET_FS_FileInformation *p, + struct GNUNET_FS_PublishContext *pc, const char *emsg) +{ + struct GNUNET_FS_ProgressInfo pi; + + p->emsg = GNUNET_strdup (emsg); + pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; + pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; + pi.value.publish.specifics.error.message = emsg; + p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); + if ((p->is_directory != GNUNET_YES) && (p->filename != NULL) && + (p->data.file.do_index == GNUNET_YES)) + { + /* run unindex to clean up */ + GNUNET_FS_unindex_start (pc->h, p->filename, NULL); + } + +} + + +/** + * Datastore returns from reservation cancel request. + * + * @param cls the 'struct GNUNET_FS_PublishContext' + * @param success success code (not used) + * @param min_expiration minimum expiration time required for content to be stored + * @param msg error message (typically NULL, not used) + */ +static void +finish_release_reserve (void *cls, int success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg) +{ + struct GNUNET_FS_PublishContext *pc = cls; + + pc->qre = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Releasing reserve done!\n"); + signal_publish_completion (pc->fi, pc); + pc->all_done = GNUNET_YES; + GNUNET_FS_publish_sync_ (pc); +} + + +/** + * We've finished publishing the SBlock as part of a larger upload. + * Check the result and complete the larger upload. + * + * @param cls the "struct GNUNET_FS_PublishContext*" of the larger upload + * @param uri URI of the published SBlock + * @param emsg NULL on success, otherwise error message + */ +static void +publish_sblocks_cont (void *cls, const struct GNUNET_FS_Uri *uri, + const char *emsg) +{ + struct GNUNET_FS_PublishContext *pc = cls; + + pc->sks_pc = NULL; + if (NULL != emsg) + { + signal_publish_error (pc->fi, pc, emsg); + GNUNET_FS_publish_sync_ (pc); + return; + } + GNUNET_assert (pc->qre == NULL); + if ((pc->dsh != NULL) && (pc->rid != 0)) + { + pc->qre = + GNUNET_DATASTORE_release_reserve (pc->dsh, pc->rid, UINT_MAX, UINT_MAX, + GNUNET_TIME_UNIT_FOREVER_REL, + &finish_release_reserve, pc); + } + else + { + finish_release_reserve (pc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); + } +} + + +/** + * We are almost done publishing the structure, + * add SBlocks (if needed). + * + * @param pc overall upload data + */ +static void +publish_sblock (struct GNUNET_FS_PublishContext *pc) +{ + if (NULL != pc->namespace) + pc->sks_pc = GNUNET_FS_publish_sks (pc->h, pc->namespace, pc->nid, pc->nuid, + pc->fi->meta, pc->fi->chk_uri, &pc->fi->bo, + pc->options, &publish_sblocks_cont, pc); + else + publish_sblocks_cont (pc, NULL, NULL); +} + + +/** + * We've finished publishing a KBlock as part of a larger upload. + * Check the result and continue the larger upload. + * + * @param cls the "struct GNUNET_FS_PublishContext*" + * of the larger upload + * @param uri URI of the published blocks + * @param emsg NULL on success, otherwise error message + */ +static void +publish_kblocks_cont (void *cls, const struct GNUNET_FS_Uri *uri, + const char *emsg) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_FileInformation *p = pc->fi_pos; + + pc->ksk_pc = NULL; + if (NULL != emsg) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error uploading KSK blocks: %s\n", + emsg); + signal_publish_error (p, pc, emsg); + GNUNET_FS_file_information_sync_ (p); + GNUNET_FS_publish_sync_ (pc); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); + pc->upload_task = + GNUNET_SCHEDULER_add_with_priority + (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "KSK blocks published, moving on to next file\n"); + if (NULL != p->dir) + signal_publish_completion (p, pc); + /* move on to next file */ + if (NULL != p->next) + pc->fi_pos = p->next; + else + pc->fi_pos = p->dir; + GNUNET_FS_publish_sync_ (pc); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); + pc->upload_task = + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, + &GNUNET_FS_publish_main_, pc); +} + + +/** + * Function called by the tree encoder to obtain + * a block of plaintext data (for the lowest level + * of the tree). + * + * @param cls our publishing context + * @param offset identifies which block to get + * @param max (maximum) number of bytes to get; returning + * fewer will also cause errors + * @param buf where to copy the plaintext buffer + * @param emsg location to store an error message (on error) + * @return number of bytes copied to buf, 0 on error + */ +static size_t +block_reader (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_FileInformation *p; + size_t pt_size; + const char *dd; + + p = pc->fi_pos; + if (p->is_directory == GNUNET_YES) + { + pt_size = GNUNET_MIN (max, p->data.dir.dir_size - offset); + dd = p->data.dir.dir_data; + memcpy (buf, &dd[offset], pt_size); + } + else + { + pt_size = GNUNET_MIN (max, p->data.file.file_size - offset); + if (pt_size == 0) + return 0; /* calling reader with pt_size==0 + * might free buf, so don't! */ + if (pt_size != + p->data.file.reader (p->data.file.reader_cls, offset, pt_size, buf, + emsg)) + return 0; + } + return pt_size; +} + + +/** + * The tree encoder has finished processing a + * file. Call it's finish method and deal with + * the final result. + * + * @param cls our publishing context + * @param tc scheduler's task context (not used) + */ +static void +encode_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_FileInformation *p; + struct GNUNET_FS_ProgressInfo pi; + char *emsg; + uint64_t flen; + + p = pc->fi_pos; + GNUNET_FS_tree_encoder_finish (p->te, &p->chk_uri, &emsg); + p->te = NULL; + GNUNET_FS_file_information_sync_ (p); + if (NULL != emsg) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error during tree walk: %s\n", emsg); + GNUNET_asprintf (&p->emsg, _("Publishing failed: %s"), emsg); + GNUNET_free (emsg); + pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; + pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; + pi.value.publish.specifics.error.message = p->emsg; + p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished with tree encoder\n"); + /* final progress event */ + flen = GNUNET_FS_uri_chk_get_file_size (p->chk_uri); + pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; + pi.value.publish.specifics.progress.data = NULL; + pi.value.publish.specifics.progress.offset = flen; + pi.value.publish.specifics.progress.data_len = 0; + pi.value.publish.specifics.progress.depth = GNUNET_FS_compute_depth (flen); + p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, flen); + + /* continue with main */ + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); + pc->upload_task = + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, + &GNUNET_FS_publish_main_, pc); +} + + +/** + * Function called asking for the current (encoded) + * block to be processed. After processing the + * client should either call "GNUNET_FS_tree_encode_next" + * or (on error) "GNUNET_FS_tree_encode_finish". + * + * @param cls closure + * @param chk content hash key for the block + * @param offset offset of the block in the file + * @param depth depth of the block in the file, 0 for DBLOCK + * @param type type of the block (IBLOCK or DBLOCK) + * @param block the (encrypted) block + * @param block_size size of block (in bytes) + */ +static void +block_proc (void *cls, const struct ContentHashKey *chk, uint64_t offset, + unsigned int depth, enum GNUNET_BLOCK_Type type, const void *block, + uint16_t block_size) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_FileInformation *p; + struct OnDemandBlock odb; + + p = pc->fi_pos; + if (NULL == pc->dsh) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Waiting for datastore connection\n"); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); + pc->upload_task = + GNUNET_SCHEDULER_add_with_priority + (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); + return; + } + + if ((p->is_directory != GNUNET_YES) && (GNUNET_YES == p->data.file.do_index) && + (type == GNUNET_BLOCK_TYPE_FS_DBLOCK)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Indexing block `%s' for offset %llu with index size %u\n", + GNUNET_h2s (&chk->query), (unsigned long long) offset, + sizeof (struct OnDemandBlock)); + odb.offset = GNUNET_htonll (offset); + odb.file_id = p->data.file.file_id; + GNUNET_assert (pc->qre == NULL); + pc->qre = + GNUNET_DATASTORE_put (pc->dsh, (p->is_directory == GNUNET_YES) ? 0 : pc->rid, + &chk->query, sizeof (struct OnDemandBlock), &odb, + GNUNET_BLOCK_TYPE_FS_ONDEMAND, + p->bo.content_priority, p->bo.anonymity_level, + p->bo.replication_level, p->bo.expiration_time, + -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, + &ds_put_cont, pc); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Publishing block `%s' for offset %llu with size %u\n", + GNUNET_h2s (&chk->query), (unsigned long long) offset, + (unsigned int) block_size); + GNUNET_assert (pc->qre == NULL); + pc->qre = + GNUNET_DATASTORE_put (pc->dsh, (p->is_directory == GNUNET_YES) ? 0 : pc->rid, + &chk->query, block_size, block, type, + p->bo.content_priority, p->bo.anonymity_level, + p->bo.replication_level, p->bo.expiration_time, -2, + 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &ds_put_cont, + pc); +} + + +/** + * Function called with information about our + * progress in computing the tree encoding. + * + * @param cls closure + * @param offset where are we in the file + * @param pt_block plaintext of the currently processed block + * @param pt_size size of pt_block + * @param depth depth of the block in the tree, 0 for DBLOCK + */ +static void +progress_proc (void *cls, uint64_t offset, const void *pt_block, size_t pt_size, + unsigned int depth) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_FileInformation *p; + struct GNUNET_FS_ProgressInfo pi; + + p = pc->fi_pos; + pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; + pi.value.publish.specifics.progress.data = pt_block; + pi.value.publish.specifics.progress.offset = offset; + pi.value.publish.specifics.progress.data_len = pt_size; + pi.value.publish.specifics.progress.depth = depth; + p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, offset); +} + + +/** + * We are uploading a file or directory; load (if necessary) the next + * block into memory, encrypt it and send it to the FS service. Then + * continue with the main task. + * + * @param pc overall upload data + */ +static void +publish_content (struct GNUNET_FS_PublishContext *pc) +{ + struct GNUNET_FS_FileInformation *p; + char *emsg; + struct GNUNET_FS_DirectoryBuilder *db; + struct GNUNET_FS_FileInformation *dirpos; + void *raw_data; + uint64_t size; + + p = pc->fi_pos; + GNUNET_assert (p != NULL); + if (NULL == p->te) + { + if (p->is_directory == GNUNET_YES) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating directory\n"); + db = GNUNET_FS_directory_builder_create (p->meta); + dirpos = p->data.dir.entries; + while (NULL != dirpos) + { + if (dirpos->is_directory == GNUNET_YES) + { + raw_data = dirpos->data.dir.dir_data; + dirpos->data.dir.dir_data = NULL; + } + else + { + raw_data = NULL; + if ((dirpos->data.file.file_size < MAX_INLINE_SIZE) && + (dirpos->data.file.file_size > 0)) + { + raw_data = GNUNET_malloc (dirpos->data.file.file_size); + emsg = NULL; + if (dirpos->data.file.file_size != + dirpos->data.file.reader (dirpos->data.file.reader_cls, 0, + dirpos->data.file.file_size, raw_data, + &emsg)) + { + GNUNET_free_non_null (emsg); + GNUNET_free (raw_data); + raw_data = NULL; + } + } + } + GNUNET_FS_directory_builder_add (db, dirpos->chk_uri, dirpos->meta, + raw_data); + GNUNET_free_non_null (raw_data); + dirpos = dirpos->next; + } + GNUNET_free_non_null (p->data.dir.dir_data); + p->data.dir.dir_data = NULL; + p->data.dir.dir_size = 0; + GNUNET_FS_directory_builder_finish (db, &p->data.dir.dir_size, + &p->data.dir.dir_data); + GNUNET_FS_file_information_sync_ (p); + } + size = (p->is_directory == GNUNET_YES) ? p->data.dir.dir_size : p->data.file.file_size; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating tree encoder\n"); + p->te = + GNUNET_FS_tree_encoder_create (pc->h, size, pc, &block_reader, + &block_proc, &progress_proc, + &encode_cont); + + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing next block from tree\n"); + GNUNET_FS_tree_encoder_next (p->te); +} + + +/** + * Process the response (or lack thereof) from + * the "fs" service to our 'start index' request. + * + * @param cls closure (of type "struct GNUNET_FS_PublishContext*"_) + * @param msg the response we got + */ +static void +process_index_start_response (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_FileInformation *p; + const char *emsg; + uint16_t msize; + + GNUNET_CLIENT_disconnect (pc->client, GNUNET_NO); + pc->client = NULL; + p = pc->fi_pos; + if (msg == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Can not index file `%s': %s. Will try to insert instead.\n"), + p->filename, + _("timeout on index-start request to `fs' service")); + p->data.file.do_index = GNUNET_NO; + GNUNET_FS_file_information_sync_ (p); + publish_content (pc); + return; + } + if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK) + { + msize = ntohs (msg->size); + emsg = (const char *) &msg[1]; + if ((msize <= sizeof (struct GNUNET_MessageHeader)) || + (emsg[msize - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')) + emsg = gettext_noop ("unknown error"); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Can not index file `%s': %s. Will try to insert instead.\n"), + p->filename, gettext (emsg)); + p->data.file.do_index = GNUNET_NO; + GNUNET_FS_file_information_sync_ (p); + publish_content (pc); + return; + } + p->data.file.index_start_confirmed = GNUNET_YES; + /* success! continue with indexing */ + GNUNET_FS_file_information_sync_ (p); + publish_content (pc); +} + + +/** + * Function called once the hash computation over an + * indexed file has completed. + * + * @param cls closure, our publishing context + * @param res resulting hash, NULL on error + */ +static void +hash_for_index_cb (void *cls, const GNUNET_HashCode * res) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_FileInformation *p; + struct IndexStartMessage *ism; + size_t slen; + struct GNUNET_CLIENT_Connection *client; + uint64_t dev; + uint64_t ino; + char *fn; + + pc->fhc = NULL; + p = pc->fi_pos; + if (NULL == res) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Can not index file `%s': %s. Will try to insert instead.\n"), + p->filename, _("failed to compute hash")); + p->data.file.do_index = GNUNET_NO; + GNUNET_FS_file_information_sync_ (p); + publish_content (pc); + return; + } + if (GNUNET_YES == p->data.file.index_start_confirmed) + { + publish_content (pc); + return; + } + fn = GNUNET_STRINGS_filename_expand (p->filename); + GNUNET_assert (fn != NULL); + slen = strlen (fn) + 1; + if (slen >= + GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct IndexStartMessage)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Can not index file `%s': %s. Will try to insert instead.\n"), + fn, _("filename too long")); + GNUNET_free (fn); + p->data.file.do_index = GNUNET_NO; + GNUNET_FS_file_information_sync_ (p); + publish_content (pc); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hash of indexed file `%s' is `%s'\n", + p->filename, GNUNET_h2s (res)); + if (0 != (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) + { + p->data.file.file_id = *res; + p->data.file.have_hash = GNUNET_YES; + p->data.file.index_start_confirmed = GNUNET_YES; + GNUNET_FS_file_information_sync_ (p); + publish_content (pc); + GNUNET_free (fn); + return; + } + client = GNUNET_CLIENT_connect ("fs", pc->h->cfg); + if (NULL == client) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Can not index file `%s': %s. Will try to insert instead.\n"), + p->filename, _("could not connect to `fs' service")); + p->data.file.do_index = GNUNET_NO; + publish_content (pc); + GNUNET_free (fn); + return; + } + if (p->data.file.have_hash != GNUNET_YES) + { + p->data.file.file_id = *res; + p->data.file.have_hash = GNUNET_YES; + GNUNET_FS_file_information_sync_ (p); + } + ism = GNUNET_malloc (sizeof (struct IndexStartMessage) + slen); + ism->header.size = htons (sizeof (struct IndexStartMessage) + slen); + ism->header.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_START); + if (GNUNET_OK == GNUNET_DISK_file_get_identifiers (p->filename, &dev, &ino)) + { + ism->device = GNUNET_htonll (dev); + ism->inode = GNUNET_htonll (ino); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Failed to get file identifiers for `%s'\n"), p->filename); + } + ism->file_id = *res; + memcpy (&ism[1], fn, slen); + GNUNET_free (fn); + pc->client = client; + GNUNET_break (GNUNET_YES == + GNUNET_CLIENT_transmit_and_get_response (client, &ism->header, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, + &process_index_start_response, + pc)); + GNUNET_free (ism); +} + + +/** + * Main function that performs the upload. + * + * @param cls "struct GNUNET_FS_PublishContext" identifies the upload + * @param tc task context + */ +void +GNUNET_FS_publish_main_ (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_ProgressInfo pi; + struct GNUNET_FS_FileInformation *p; + struct GNUNET_FS_Uri *loc; + char *fn; + + pc->upload_task = GNUNET_SCHEDULER_NO_TASK; + p = pc->fi_pos; + if (NULL == p) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Publishing complete, now publishing SKS and KSK blocks.\n"); + /* upload of entire hierarchy complete, + * publish namespace entries */ + GNUNET_FS_publish_sync_ (pc); + publish_sblock (pc); + return; + } + /* find starting position */ + while ((p->is_directory == GNUNET_YES) && (NULL != p->data.dir.entries) && (NULL == p->emsg) + && (NULL == p->data.dir.entries->chk_uri)) + { + p = p->data.dir.entries; + pc->fi_pos = p; + GNUNET_FS_publish_sync_ (pc); + } + /* abort on error */ + if (NULL != p->emsg) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error uploading: %s\n", p->emsg); + /* error with current file, abort all + * related files as well! */ + while (NULL != p->dir) + { + fn = GNUNET_CONTAINER_meta_data_get_by_type (p->meta, + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); + p = p->dir; + if (fn != NULL) + { + GNUNET_asprintf (&p->emsg, _("Recursive upload failed at `%s': %s"), fn, + p->emsg); + GNUNET_free (fn); + } + else + { + GNUNET_asprintf (&p->emsg, _("Recursive upload failed: %s"), p->emsg); + } + pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; + pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; + pi.value.publish.specifics.error.message = p->emsg; + p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); + } + pc->all_done = GNUNET_YES; + GNUNET_FS_publish_sync_ (pc); + return; + } + /* handle completion */ + if (NULL != p->chk_uri) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "File upload complete, now publishing KSK blocks.\n"); + if (0 == p->bo.anonymity_level) + { + /* zero anonymity, box CHK URI in LOC URI */ + loc = + GNUNET_FS_uri_loc_create (p->chk_uri, pc->h->cfg, + p->bo.expiration_time); + GNUNET_FS_uri_destroy (p->chk_uri); + p->chk_uri = loc; + } + GNUNET_FS_publish_sync_ (pc); + /* upload of "p" complete, publish KBlocks! */ + if (p->keywords != NULL) + { + pc->ksk_pc = GNUNET_FS_publish_ksk (pc->h, p->keywords, p->meta, p->chk_uri, &p->bo, + pc->options, &publish_kblocks_cont, pc); + } + else + { + publish_kblocks_cont (pc, p->chk_uri, NULL); + } + return; + } + if ((p->is_directory != GNUNET_YES) && (p->data.file.do_index)) + { + if (NULL == p->filename) + { + p->data.file.do_index = GNUNET_NO; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Can not index file `%s': %s. Will try to insert instead.\n"), + "", _("needs to be an actual file")); + GNUNET_FS_file_information_sync_ (p); + publish_content (pc); + return; + } + if (p->data.file.have_hash) + { + hash_for_index_cb (pc, &p->data.file.file_id); + } + else + { + p->start_time = GNUNET_TIME_absolute_get (); + pc->fhc = + GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, p->filename, + HASHING_BLOCKSIZE, &hash_for_index_cb, pc); + } + return; + } + publish_content (pc); +} + + +/** + * Signal the FS's progress function that we are starting + * an upload. + * + * @param cls closure (of type "struct GNUNET_FS_PublishContext*") + * @param fi the entry in the publish-structure + * @param length length of the file or directory + * @param meta metadata for the file or directory (can be modified) + * @param uri pointer to the keywords that will be used for this entry (can be modified) + * @param bo block options + * @param do_index should we index? + * @param client_info pointer to client context set upon creation (can be modified) + * @return GNUNET_OK to continue (always) + */ +static int +fip_signal_start (void *cls, struct GNUNET_FS_FileInformation *fi, + uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, + struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, + int *do_index, void **client_info) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_ProgressInfo pi; + unsigned int kc; + uint64_t left; + + if (GNUNET_YES == pc->skip_next_fi_callback) + { + pc->skip_next_fi_callback = GNUNET_NO; + return GNUNET_OK; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting publish operation\n"); + if (*do_index) + { + /* space for on-demand blocks */ + pc->reserve_space += + ((length + DBLOCK_SIZE - + 1) / DBLOCK_SIZE) * sizeof (struct OnDemandBlock); + } + else + { + /* space for DBlocks */ + pc->reserve_space += length; + } + /* entries for IBlocks and DBlocks, space for IBlocks */ + left = length; + while (1) + { + left = (left + DBLOCK_SIZE - 1) / DBLOCK_SIZE; + pc->reserve_entries += left; + if (left <= 1) + break; + left = left * sizeof (struct ContentHashKey); + pc->reserve_space += left; + } + pc->reserve_entries++; + /* entries and space for keywords */ + if (NULL != *uri) + { + kc = GNUNET_FS_uri_ksk_get_keyword_count (*uri); + pc->reserve_entries += kc; + pc->reserve_space += GNUNET_SERVER_MAX_MESSAGE_SIZE * kc; + } + pi.status = GNUNET_FS_STATUS_PUBLISH_START; + *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0); + GNUNET_FS_file_information_sync_ (fi); + if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta) + && (fi->dir != NULL)) + { + /* process entries in directory */ + pc->skip_next_fi_callback = GNUNET_YES; + GNUNET_FS_file_information_inspect (fi, &fip_signal_start, pc); + } + return GNUNET_OK; +} + + +/** + * Signal the FS's progress function that we are suspending + * an upload. + * + * @param cls closure (of type "struct GNUNET_FS_PublishContext*") + * @param fi the entry in the publish-structure + * @param length length of the file or directory + * @param meta metadata for the file or directory (can be modified) + * @param uri pointer to the keywords that will be used for this entry (can be modified) + * @param bo block options + * @param do_index should we index? + * @param client_info pointer to client context set upon creation (can be modified) + * @return GNUNET_OK to continue (always) + */ +static int +fip_signal_suspend (void *cls, struct GNUNET_FS_FileInformation *fi, + uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, + struct GNUNET_FS_Uri **uri, + struct GNUNET_FS_BlockOptions *bo, int *do_index, + void **client_info) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_ProgressInfo pi; + uint64_t off; + + if (GNUNET_YES == pc->skip_next_fi_callback) + { + pc->skip_next_fi_callback = GNUNET_NO; + return GNUNET_OK; + } + if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) + { + /* process entries in directory */ + pc->skip_next_fi_callback = GNUNET_YES; + GNUNET_FS_file_information_inspect (fi, &fip_signal_suspend, pc); + } + if (NULL != pc->ksk_pc) + { + GNUNET_FS_publish_ksk_cancel (pc->ksk_pc); + pc->ksk_pc = NULL; + } + if (NULL != pc->sks_pc) + { + GNUNET_FS_publish_sks_cancel (pc->sks_pc); + pc->sks_pc = NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Suspending publish operation\n"); + GNUNET_free_non_null (fi->serialization); + fi->serialization = NULL; + off = (fi->chk_uri == NULL) ? 0 : length; + pi.status = GNUNET_FS_STATUS_PUBLISH_SUSPEND; + GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, fi, off)); + *client_info = NULL; + if (NULL != pc->qre) + { + GNUNET_DATASTORE_cancel (pc->qre); + pc->qre = NULL; + } + if (NULL != pc->dsh) + { + GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO); + pc->dsh = NULL; + } + pc->rid = 0; + return GNUNET_OK; +} + + +/** + * Create SUSPEND event for the given publish operation + * and then clean up our state (without stop signal). + * + * @param cls the 'struct GNUNET_FS_PublishContext' to signal for + */ +void +GNUNET_FS_publish_signal_suspend_ (void *cls) +{ + struct GNUNET_FS_PublishContext *pc = cls; + + if (GNUNET_SCHEDULER_NO_TASK != pc->upload_task) + { + GNUNET_SCHEDULER_cancel (pc->upload_task); + pc->upload_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_suspend, pc); + GNUNET_FS_end_top (pc->h, pc->top); + pc->top = NULL; + publish_cleanup (pc); +} + + +/** + * We have gotten a reply for our space reservation request. + * Either fail (insufficient space) or start publishing for good. + * + * @param cls the 'struct GNUNET_FS_PublishContext*' + * @param success positive reservation ID on success + * @param min_expiration minimum expiration time required for content to be stored + * @param msg error message on error, otherwise NULL + */ +static void +finish_reserve (void *cls, int success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg) +{ + struct GNUNET_FS_PublishContext *pc = cls; + + pc->qre = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reservation complete (%d)!\n", success); + if ((msg != NULL) || (success <= 0)) + { + GNUNET_asprintf (&pc->fi->emsg, _("Insufficient space for publishing: %s"), + msg); + signal_publish_error (pc->fi, pc, pc->fi->emsg); + return; + } + pc->rid = success; + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); + pc->upload_task = + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, + &GNUNET_FS_publish_main_, pc); +} + + +/** + * Publish a file or directory. + * + * @param h handle to the file sharing subsystem + * @param fi information about the file or directory structure to publish + * @param namespace namespace to publish the file in, NULL for no namespace + * @param nid identifier to use for the publishd content in the namespace + * (can be NULL, must be NULL if namespace is NULL) + * @param nuid update-identifier that will be used for future updates + * (can be NULL, must be NULL if namespace or nid is NULL) + * @param options options for the publication + * @return context that can be used to control the publish operation + */ +struct GNUNET_FS_PublishContext * +GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h, + struct GNUNET_FS_FileInformation *fi, + struct GNUNET_FS_Namespace *namespace, const char *nid, + const char *nuid, + enum GNUNET_FS_PublishOptions options) +{ + struct GNUNET_FS_PublishContext *ret; + struct GNUNET_DATASTORE_Handle *dsh; + + GNUNET_assert (NULL != h); + if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) + { + dsh = GNUNET_DATASTORE_connect (h->cfg); + if (NULL == dsh) + return NULL; + } + else + { + dsh = NULL; + } + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishContext)); + ret->dsh = dsh; + ret->h = h; + ret->fi = fi; + ret->namespace = namespace; + ret->options = options; + if (namespace != NULL) + { + namespace->rc++; + GNUNET_assert (NULL != nid); + ret->nid = GNUNET_strdup (nid); + if (NULL != nuid) + ret->nuid = GNUNET_strdup (nuid); + } + /* signal start */ + GNUNET_FS_file_information_inspect (ret->fi, &fip_signal_start, ret); + ret->fi_pos = ret->fi; + ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, ret); + GNUNET_FS_publish_sync_ (ret); + if (NULL != ret->dsh) + { + GNUNET_assert (NULL == ret->qre); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Reserving space for %u entries and %llu bytes for publication\n"), + (unsigned int) ret->reserve_entries, + (unsigned long long) ret->reserve_space); + ret->qre = + GNUNET_DATASTORE_reserve (ret->dsh, ret->reserve_space, + ret->reserve_entries, UINT_MAX, UINT_MAX, + GNUNET_TIME_UNIT_FOREVER_REL, &finish_reserve, + ret); + } + else + { + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ret->upload_task); + ret->upload_task = + GNUNET_SCHEDULER_add_with_priority + (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, ret); + } + return ret; +} + + +/** + * Signal the FS's progress function that we are stopping + * an upload. + * + * @param cls closure (of type "struct GNUNET_FS_PublishContext*") + * @param fi the entry in the publish-structure + * @param length length of the file or directory + * @param meta metadata for the file or directory (can be modified) + * @param uri pointer to the keywords that will be used for this entry (can be modified) + * @param bo block options (can be modified) + * @param do_index should we index? + * @param client_info pointer to client context set upon creation (can be modified) + * @return GNUNET_OK to continue (always) + */ +static int +fip_signal_stop (void *cls, struct GNUNET_FS_FileInformation *fi, + uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, + struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, + int *do_index, void **client_info) +{ + struct GNUNET_FS_PublishContext *pc = cls; + struct GNUNET_FS_ProgressInfo pi; + uint64_t off; + + if (GNUNET_YES == pc->skip_next_fi_callback) + { + pc->skip_next_fi_callback = GNUNET_NO; + return GNUNET_OK; + } + if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) + { + /* process entries in directory first */ + pc->skip_next_fi_callback = GNUNET_YES; + GNUNET_FS_file_information_inspect (fi, &fip_signal_stop, pc); + } + if (fi->serialization != NULL) + { + GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_FILE_INFO, + fi->serialization); + GNUNET_free (fi->serialization); + fi->serialization = NULL; + } + off = (fi->chk_uri == NULL) ? 0 : length; + pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED; + GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, fi, off)); + *client_info = NULL; + return GNUNET_OK; +} + + +/** + * Stop an upload. Will abort incomplete uploads (but + * not remove blocks that have already been publishd) or + * simply clean up the state for completed uploads. + * Must NOT be called from within the event callback! + * + * @param pc context for the upload to stop + */ +void +GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *pc) +{ + struct GNUNET_FS_ProgressInfo pi; + uint64_t off; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publish stop called\n"); + GNUNET_FS_end_top (pc->h, pc->top); + if (NULL != pc->ksk_pc) + { + GNUNET_FS_publish_ksk_cancel (pc->ksk_pc); + pc->ksk_pc = NULL; + } + if (NULL != pc->sks_pc) + { + GNUNET_FS_publish_sks_cancel (pc->sks_pc); + pc->sks_pc = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != pc->upload_task) + { + GNUNET_SCHEDULER_cancel (pc->upload_task); + pc->upload_task = GNUNET_SCHEDULER_NO_TASK; + } + pc->skip_next_fi_callback = GNUNET_YES; + GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_stop, pc); + + if (pc->fi->serialization != NULL) + { + GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_FILE_INFO, + pc->fi->serialization); + GNUNET_free (pc->fi->serialization); + pc->fi->serialization = NULL; + } + off = (pc->fi->chk_uri == NULL) ? 0 : GNUNET_ntohll (pc->fi->chk_uri->data.chk.file_length); + + if (pc->serialization != NULL) + { + GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, + pc->serialization); + GNUNET_free (pc->serialization); + pc->serialization = NULL; + } + if (NULL != pc->qre) + { + GNUNET_DATASTORE_cancel (pc->qre); + pc->qre = NULL; + } + pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED; + GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi, off)); + publish_cleanup (pc); +} + + + +/* end of fs_publish.c */ diff --git a/src/fs/fs_publish_ksk.c b/src/fs/fs_publish_ksk.c new file mode 100644 index 0000000..5119de4 --- /dev/null +++ b/src/fs/fs_publish_ksk.c @@ -0,0 +1,342 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_publish_ksk.c + * @brief publish a URI under a keyword in GNUnet + * @see https://gnunet.org/encoding + * @author Krista Bennett + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_signatures.h" +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" +#include "fs_tree.h" + + +/** + * Maximum legal size for a kblock. + */ +#define MAX_KBLOCK_SIZE (60 * 1024) + + +/** + * Context for the KSK publication. + */ +struct GNUNET_FS_PublishKskContext +{ + + /** + * Keywords to use. + */ + struct GNUNET_FS_Uri *ksk_uri; + + /** + * Global FS context. + */ + struct GNUNET_FS_Handle *h; + + /** + * The master block that we are sending + * (in plaintext), has "mdsize+slen" more + * bytes than the struct would suggest. + */ + struct KBlock *kb; + + /** + * Buffer of the same size as "kb" for + * the encrypted version. + */ + struct KBlock *cpy; + + /** + * Handle to the datastore, NULL if we are just + * simulating. + */ + struct GNUNET_DATASTORE_Handle *dsh; + + /** + * Handle to datastore PUT request. + */ + struct GNUNET_DATASTORE_QueueEntry *qre; + + /** + * Current task. + */ + GNUNET_SCHEDULER_TaskIdentifier ksk_task; + + /** + * Function to call once we're done. + */ + GNUNET_FS_PublishContinuation cont; + + /** + * Closure for cont. + */ + void *cont_cls; + + /** + * When should the KBlocks expire? + */ + struct GNUNET_FS_BlockOptions bo; + + /** + * Size of the serialized metadata. + */ + ssize_t mdsize; + + /** + * Size of the (CHK) URI as a string. + */ + size_t slen; + + /** + * Keyword that we are currently processing. + */ + unsigned int i; + +}; + + +/** + * Continuation of "GNUNET_FS_publish_ksk" that performs + * the actual publishing operation (iterating over all + * of the keywords). + * + * @param cls closure of type "struct PublishKskContext*" + * @param tc unused + */ +static void +publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Function called by the datastore API with + * the result from the PUT request. + * + * @param cls closure of type "struct GNUNET_FS_PublishKskContext*" + * @param success GNUNET_OK on success + * @param min_expiration minimum expiration time required for content to be stored + * @param msg error message (or NULL) + */ +static void +kb_put_cont (void *cls, int success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg) +{ + struct GNUNET_FS_PublishKskContext *pkc = cls; + + pkc->qre = NULL; + if (GNUNET_OK != success) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "KBlock PUT operation failed: %s\n", msg); + pkc->cont (pkc->cont_cls, NULL, msg); + GNUNET_FS_publish_ksk_cancel (pkc); + return; + } + pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc); +} + + +/** + * Continuation of "GNUNET_FS_publish_ksk" that performs the actual + * publishing operation (iterating over all of the keywords). + * + * @param cls closure of type "struct GNUNET_FS_PublishKskContext*" + * @param tc unused + */ +static void +publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_PublishKskContext *pkc = cls; + const char *keyword; + GNUNET_HashCode key; + GNUNET_HashCode query; + struct GNUNET_CRYPTO_AesSessionKey skey; + struct GNUNET_CRYPTO_AesInitializationVector iv; + struct GNUNET_CRYPTO_RsaPrivateKey *pk; + + pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK; + if ((pkc->i == pkc->ksk_uri->data.ksk.keywordCount) || (NULL == pkc->dsh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KSK PUT operation complete\n"); + pkc->cont (pkc->cont_cls, pkc->ksk_uri, NULL); + GNUNET_FS_publish_ksk_cancel (pkc); + return; + } + keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing under keyword `%s'\n", + keyword); + /* first character of keyword indicates if it is + * mandatory or not -- ignore for hashing */ + GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key); + GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); + GNUNET_CRYPTO_aes_encrypt (&pkc->kb[1], pkc->slen + pkc->mdsize, &skey, &iv, + &pkc->cpy[1]); + pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key); + GNUNET_assert (NULL != pk); + GNUNET_CRYPTO_rsa_key_get_public (pk, &pkc->cpy->keyspace); + GNUNET_CRYPTO_hash (&pkc->cpy->keyspace, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &query); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (pk, &pkc->cpy->purpose, + &pkc->cpy->signature)); + GNUNET_CRYPTO_rsa_key_free (pk); + pkc->qre = + GNUNET_DATASTORE_put (pkc->dsh, 0, &query, + pkc->mdsize + sizeof (struct KBlock) + pkc->slen, + pkc->cpy, GNUNET_BLOCK_TYPE_FS_KBLOCK, + pkc->bo.content_priority, pkc->bo.anonymity_level, + pkc->bo.replication_level, pkc->bo.expiration_time, + -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, + &kb_put_cont, pkc); +} + + +/** + * Publish a CHK under various keywords on GNUnet. + * + * @param h handle to the file sharing subsystem + * @param ksk_uri keywords to use + * @param meta metadata to use + * @param uri URI to refer to in the KBlock + * @param bo per-block options + * @param options publication options + * @param cont continuation + * @param cont_cls closure for cont + * @return NULL on error ('cont' will still be called) + */ +struct GNUNET_FS_PublishKskContext * +GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, + const struct GNUNET_FS_Uri *ksk_uri, + const struct GNUNET_CONTAINER_MetaData *meta, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_FS_BlockOptions *bo, + enum GNUNET_FS_PublishOptions options, + GNUNET_FS_PublishContinuation cont, void *cont_cls) +{ + struct GNUNET_FS_PublishKskContext *pkc; + char *uris; + size_t size; + char *kbe; + char *sptr; + + GNUNET_assert (NULL != uri); + pkc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishKskContext)); + pkc->h = h; + pkc->bo = *bo; + pkc->cont = cont; + pkc->cont_cls = cont_cls; + if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) + { + pkc->dsh = GNUNET_DATASTORE_connect (h->cfg); + if (NULL == pkc->dsh) + { + cont (cont_cls, NULL, _("Could not connect to datastore.")); + GNUNET_free (pkc); + return NULL; + } + } + if (meta == NULL) + pkc->mdsize = 0; + else + pkc->mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); + GNUNET_assert (pkc->mdsize >= 0); + uris = GNUNET_FS_uri_to_string (uri); + pkc->slen = strlen (uris) + 1; + size = pkc->mdsize + sizeof (struct KBlock) + pkc->slen; + if (size > MAX_KBLOCK_SIZE) + { + size = MAX_KBLOCK_SIZE; + pkc->mdsize = size - sizeof (struct KBlock) - pkc->slen; + } + pkc->kb = GNUNET_malloc (size); + kbe = (char *) &pkc->kb[1]; + memcpy (kbe, uris, pkc->slen); + GNUNET_free (uris); + sptr = &kbe[pkc->slen]; + if (meta != NULL) + pkc->mdsize = + GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, pkc->mdsize, + GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); + if (-1 == pkc->mdsize) + { + GNUNET_break (0); + GNUNET_free (pkc->kb); + if (pkc->dsh != NULL) + { + GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); + pkc->dsh = NULL; + } + GNUNET_free (pkc); + cont (cont_cls, NULL, _("Internal error.")); + return NULL; + } + size = sizeof (struct KBlock) + pkc->slen + pkc->mdsize; + + pkc->cpy = GNUNET_malloc (size); + pkc->cpy->purpose.size = + htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + pkc->mdsize + pkc->slen); + pkc->cpy->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK); + pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); + pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc); + return pkc; +} + + +/** + * Abort the KSK publishing operation. + * + * @param pkc context of the operation to abort. + */ +void +GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc) +{ + if (GNUNET_SCHEDULER_NO_TASK != pkc->ksk_task) + { + GNUNET_SCHEDULER_cancel (pkc->ksk_task); + pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != pkc->qre) + { + GNUNET_DATASTORE_cancel (pkc->qre); + pkc->qre = NULL; + } + if (NULL != pkc->dsh) + { + GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); + pkc->dsh = NULL; + } + GNUNET_free (pkc->cpy); + GNUNET_free (pkc->kb); + GNUNET_FS_uri_destroy (pkc->ksk_uri); + GNUNET_free (pkc); +} + + +/* end of fs_publish_ksk.c */ diff --git a/src/fs/fs_search.c b/src/fs/fs_search.c new file mode 100644 index 0000000..a163d97 --- /dev/null +++ b/src/fs/fs_search.c @@ -0,0 +1,1548 @@ +/* + This file is part of GNUnet. + (C) 2001-2006, 2008-2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_search.c + * @brief Helper functions for searching. + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_fs_service.h" +#include "gnunet_protocols.h" +#include "fs_api.h" + +#define DEBUG_SEARCH GNUNET_EXTRA_LOGGING + +/** + * Number of availability trials we perform per search result. + */ +#define AVAILABILITY_TRIALS_MAX 8 + +/** + * Fill in all of the generic fields for a search event and + * call the callback. + * + * @param pi structure to fill in + * @param sc overall search context + * @return value returned by the callback + */ +void * +GNUNET_FS_search_make_status_ (struct GNUNET_FS_ProgressInfo *pi, + struct GNUNET_FS_SearchContext *sc) +{ + void *ret; + + pi->value.search.sc = sc; + pi->value.search.cctx = sc->client_info; + pi->value.search.pctx = + (sc->psearch_result == NULL) ? NULL : sc->psearch_result->client_info; + pi->value.search.query = sc->uri; + pi->value.search.duration = + GNUNET_TIME_absolute_get_duration (sc->start_time); + pi->value.search.anonymity = sc->anonymity; + ret = sc->h->upcb (sc->h->upcb_cls, pi); + return ret; +} + + +/** + * Check if the given result is identical + * to the given URI. + * + * @param cls points to the URI we check against + * @param key not used + * @param value a "struct GNUNET_FS_SearchResult" who's URI we + * should compare with + * @return GNUNET_SYSERR if the result is present, + * GNUNET_OK otherwise + */ +static int +test_result_present (void *cls, const GNUNET_HashCode * key, void *value) +{ + const struct GNUNET_FS_Uri *uri = cls; + struct GNUNET_FS_SearchResult *sr = value; + + if (GNUNET_FS_uri_test_equal (uri, sr->uri)) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * We've found a new CHK result. Let the client + * know about it. + * + * @param sc the search context + * @param sr the specific result + */ +static void +notify_client_chk_result (struct GNUNET_FS_SearchContext *sc, + struct GNUNET_FS_SearchResult *sr) +{ + struct GNUNET_FS_ProgressInfo pi; + + pi.status = GNUNET_FS_STATUS_SEARCH_RESULT; + pi.value.search.specifics.result.meta = sr->meta; + pi.value.search.specifics.result.uri = sr->uri; + pi.value.search.specifics.result.result = sr; + pi.value.search.specifics.result.applicability_rank = sr->optional_support; + sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc); +} + + +/** + * We've found new information about an existing CHK result. Let the + * client know about it. + * + * @param sc the search context + * @param sr the specific result + */ +static void +notify_client_chk_update (struct GNUNET_FS_SearchContext *sc, + struct GNUNET_FS_SearchResult *sr) +{ + struct GNUNET_FS_ProgressInfo pi; + + pi.status = GNUNET_FS_STATUS_SEARCH_UPDATE; + pi.value.search.specifics.update.cctx = sr->client_info; + pi.value.search.specifics.update.meta = sr->meta; + pi.value.search.specifics.update.uri = sr->uri; + pi.value.search.specifics.update.availability_rank = + 2 * sr->availability_success - sr->availability_trials; + pi.value.search.specifics.update.availability_certainty = + sr->availability_trials; + pi.value.search.specifics.update.applicability_rank = sr->optional_support; + sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc); +} + + +/** + * Context for "get_result_present". + */ +struct GetResultContext +{ + /** + * The URI we're looking for. + */ + const struct GNUNET_FS_Uri *uri; + + /** + * Where to store a pointer to the search + * result struct if we found a match. + */ + struct GNUNET_FS_SearchResult *sr; +}; + + +/** + * Check if the given result is identical to the given URI and if so + * return it. + * + * @param cls a "struct GetResultContext" + * @param key not used + * @param value a "struct GNUNET_FS_SearchResult" who's URI we + * should compare with + * @return GNUNET_OK + */ +static int +get_result_present (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GetResultContext *grc = cls; + struct GNUNET_FS_SearchResult *sr = value; + + if (GNUNET_FS_uri_test_equal (grc->uri, sr->uri)) + grc->sr = sr; + return GNUNET_OK; +} + + +/** + * Signal result of last probe to client and then schedule next + * probe. + */ +static void +signal_probe_result (struct GNUNET_FS_SearchResult *sr) +{ + struct GNUNET_FS_ProgressInfo pi; + + pi.status = GNUNET_FS_STATUS_SEARCH_START; + pi.value.search.specifics.update.cctx = sr->client_info; + pi.value.search.specifics.update.meta = sr->meta; + pi.value.search.specifics.update.uri = sr->uri; + pi.value.search.specifics.update.availability_rank = sr->availability_success; + pi.value.search.specifics.update.availability_certainty = + sr->availability_trials; + pi.value.search.specifics.update.applicability_rank = sr->optional_support; + sr->sc->client_info = GNUNET_FS_search_make_status_ (&pi, sr->sc); + GNUNET_FS_search_start_probe_ (sr); +} + + +/** + * Handle the case where we have failed to receive a response for our probe. + * + * @param cls our 'struct GNUNET_FS_SearchResult*' + * @param tc scheduler context + */ +static void +probe_failure_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_SearchResult *sr = cls; + + sr->availability_trials++; + GNUNET_FS_search_result_sync_ (sr); + signal_probe_result (sr); +} + + +/** + * Handle the case where we have gotten a response for our probe. + * + * @param cls our 'struct GNUNET_FS_SearchResult*' + * @param tc scheduler context + */ +static void +probe_success_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_SearchResult *sr = cls; + + sr->availability_trials++; + sr->availability_success++; + GNUNET_FS_search_result_sync_ (sr); + signal_probe_result (sr); +} + + +/** + * Notification of FS that a search probe has made progress. + * This function is used INSTEAD of the client's event handler + * for downloads where the GNUNET_FS_DOWNLOAD_IS_PROBE flag is set. + * + * @param cls closure, always NULL (!), actual closure + * is in the client-context of the info struct + * @param info details about the event, specifying the event type + * and various bits about the event + * @return client-context (for the next progress call + * for this operation; should be set to NULL for + * SUSPEND and STOPPED events). The value returned + * will be passed to future callbacks in the respective + * field in the GNUNET_FS_ProgressInfo struct. + */ +void * +GNUNET_FS_search_probe_progress_ (void *cls, + const struct GNUNET_FS_ProgressInfo *info) +{ + struct GNUNET_FS_SearchResult *sr = info->value.download.cctx; + struct GNUNET_TIME_Relative dur; + + switch (info->status) + { + case GNUNET_FS_STATUS_DOWNLOAD_START: + /* ignore */ + break; + case GNUNET_FS_STATUS_DOWNLOAD_RESUME: + /* probes should never be resumed */ + GNUNET_assert (0); + break; + case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND: + /* probes should never be suspended */ + GNUNET_break (0); + break; + case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: + /* ignore */ + break; + case GNUNET_FS_STATUS_DOWNLOAD_ERROR: + if (sr->probe_cancel_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); + sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; + } + sr->probe_cancel_task = + GNUNET_SCHEDULER_add_delayed (sr->remaining_probe_time, + &probe_failure_handler, sr); + break; + case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: + if (sr->probe_cancel_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); + sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; + } + sr->probe_cancel_task = + GNUNET_SCHEDULER_add_delayed (sr->remaining_probe_time, + &probe_success_handler, sr); + break; + case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: + if (sr->probe_cancel_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); + sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; + } + sr = NULL; + break; + case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: + GNUNET_assert (sr->probe_cancel_task == GNUNET_SCHEDULER_NO_TASK); + sr->probe_active_time = GNUNET_TIME_absolute_get (); + sr->probe_cancel_task = + GNUNET_SCHEDULER_add_delayed (sr->remaining_probe_time, + &probe_failure_handler, sr); + break; + case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: + if (sr->probe_cancel_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); + sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; + } + dur = GNUNET_TIME_absolute_get_duration (sr->probe_active_time); + sr->remaining_probe_time = + GNUNET_TIME_relative_subtract (sr->remaining_probe_time, dur); + GNUNET_FS_search_result_sync_ (sr); + break; + default: + GNUNET_break (0); + return NULL; + } + return sr; +} + + +/** + * Start download probes for the given search result. + * + * @param sr the search result + */ +void +GNUNET_FS_search_start_probe_ (struct GNUNET_FS_SearchResult *sr) +{ + uint64_t off; + uint64_t len; + + if (sr->probe_ctx != NULL) + return; + if (sr->download != NULL) + return; + if (0 == (sr->sc->h->flags & GNUNET_FS_FLAGS_DO_PROBES)) + return; + if (sr->availability_trials > AVAILABILITY_TRIALS_MAX) + return; + len = GNUNET_FS_uri_chk_get_file_size (sr->uri); + if (len == 0) + return; + if ((len <= DBLOCK_SIZE) && (sr->availability_success > 0)) + return; + off = len / DBLOCK_SIZE; + if (off > 0) + off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, off); + off *= DBLOCK_SIZE; + if (len - off < DBLOCK_SIZE) + len = len - off; + else + len = DBLOCK_SIZE; + sr->remaining_probe_time = + GNUNET_TIME_relative_multiply (sr->sc->h->avg_block_latency, + 2 * (1 + sr->availability_trials)); + sr->probe_ctx = + GNUNET_FS_download_start (sr->sc->h, sr->uri, sr->meta, NULL, NULL, off, + len, sr->sc->anonymity, + GNUNET_FS_DOWNLOAD_NO_TEMPORARIES | + GNUNET_FS_DOWNLOAD_IS_PROBE, sr, NULL); +} + + +/** + * We have received a KSK result. Check how it fits in with the + * overall query and notify the client accordingly. + * + * @param sc context for the overall query + * @param ent entry for the specific keyword + * @param uri the URI that was found + * @param meta metadata associated with the URI + * under the "ent" keyword + */ +static void +process_ksk_result (struct GNUNET_FS_SearchContext *sc, + struct SearchRequestEntry *ent, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_CONTAINER_MetaData *meta) +{ + GNUNET_HashCode key; + struct GNUNET_FS_SearchResult *sr; + struct GetResultContext grc; + int is_new; + unsigned int koff; + + /* check if new */ + GNUNET_assert (NULL != sc); + GNUNET_FS_uri_to_key (uri, &key); + if (GNUNET_SYSERR == + GNUNET_CONTAINER_multihashmap_get_multiple (ent->results, &key, + &test_result_present, + (void *) uri)) + return; /* duplicate result */ + /* try to find search result in master map */ + grc.sr = NULL; + grc.uri = uri; + GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map, &key, + &get_result_present, &grc); + sr = grc.sr; + is_new = (NULL == sr) || (sr->mandatory_missing > 0); + if (NULL == sr) + { + sr = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchResult)); + sr->sc = sc; + sr->uri = GNUNET_FS_uri_dup (uri); + sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); + sr->mandatory_missing = sc->mandatory_count; + sr->key = key; + sr->keyword_bitmap = GNUNET_malloc ((sc->uri->data.ksk.keywordCount + 7) / 8); /* round up, count bits */ + GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &key, sr, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + } + else + { + GNUNET_CONTAINER_meta_data_merge (sr->meta, meta); + } + koff = ent - sc->requests; + GNUNET_assert ( (ent >= sc->requests) && (koff < sc->uri->data.ksk.keywordCount)); + sr->keyword_bitmap[koff / 8] |= (1 << (koff % 8)); + /* check if mandatory satisfied */ + if (ent->mandatory) + sr->mandatory_missing--; + else + sr->optional_support++; + if (0 != sr->mandatory_missing) + return; + if (is_new) + notify_client_chk_result (sc, sr); + else + notify_client_chk_update (sc, sr); + GNUNET_FS_search_result_sync_ (sr); + GNUNET_FS_search_start_probe_ (sr); +} + + +/** + * Start search for content, internal API. + * + * @param h handle to the file sharing subsystem + * @param uri specifies the search parameters; can be + * a KSK URI or an SKS URI. + * @param anonymity desired level of anonymity + * @param options options for the search + * @param cctx client context + * @param psearch parent search result (for namespace update searches) + * @return context that can be used to control the search + */ +static struct GNUNET_FS_SearchContext * +search_start (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri, + uint32_t anonymity, enum GNUNET_FS_SearchOptions options, + void *cctx, struct GNUNET_FS_SearchResult *psearch); + + +/** + * We have received an SKS result. Start searching for updates and + * notify the client if it is a new result. + * + * @param sc context for the overall query + * @param id_update identifier for updates, NULL for none + * @param uri the URI that was found + * @param meta metadata associated with the URI + */ +static void +process_sks_result (struct GNUNET_FS_SearchContext *sc, const char *id_update, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_CONTAINER_MetaData *meta) +{ + struct GNUNET_FS_Uri uu; + GNUNET_HashCode key; + struct GNUNET_FS_SearchResult *sr; + + /* check if new */ + GNUNET_assert (NULL != sc); + GNUNET_FS_uri_to_key (uri, &key); + GNUNET_CRYPTO_hash_xor (&uri->data.chk.chk.key, &uri->data.chk.chk.query, + &key); + if (GNUNET_SYSERR == + GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map, &key, + &test_result_present, + (void *) uri)) + return; /* duplicate result */ + sr = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchResult)); + sr->sc = sc; + sr->uri = GNUNET_FS_uri_dup (uri); + sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); + sr->key = key; + GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &key, sr, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + GNUNET_FS_search_result_sync_ (sr); + GNUNET_FS_search_start_probe_ (sr); + /* notify client */ + notify_client_chk_result (sc, sr); + /* search for updates */ + if (strlen (id_update) == 0) + return; /* no updates */ + uu.type = sks; + uu.data.sks.namespace = sc->uri->data.sks.namespace; + uu.data.sks.identifier = GNUNET_strdup (id_update); + (void) search_start (sc->h, &uu, sc->anonymity, sc->options, NULL, sr); + GNUNET_free (uu.data.sks.identifier); +} + + +/** + * Process a keyword-search result. + * + * @param sc our search context + * @param kb the kblock + * @param size size of kb + */ +static void +process_kblock (struct GNUNET_FS_SearchContext *sc, const struct KBlock *kb, + size_t size) +{ + unsigned int i; + size_t j; + GNUNET_HashCode q; + char pt[size - sizeof (struct KBlock)]; + struct GNUNET_CRYPTO_AesSessionKey skey; + struct GNUNET_CRYPTO_AesInitializationVector iv; + const char *eos; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *uri; + char *emsg; + + GNUNET_CRYPTO_hash (&kb->keyspace, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &q); + /* find key */ + for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) + if (0 == memcmp (&q, &sc->requests[i].query, sizeof (GNUNET_HashCode))) + break; + if (i == sc->uri->data.ksk.keywordCount) + { + /* oops, does not match any of our keywords!? */ + GNUNET_break (0); + return; + } + /* decrypt */ + GNUNET_CRYPTO_hash_to_aes_key (&sc->requests[i].key, &skey, &iv); + if (-1 == + GNUNET_CRYPTO_aes_decrypt (&kb[1], size - sizeof (struct KBlock), &skey, + &iv, pt)) + { + GNUNET_break (0); + return; + } + /* parse */ + eos = memchr (pt, 0, sizeof (pt)); + if (NULL == eos) + { + GNUNET_break_op (0); + return; + } + j = eos - pt + 1; + if (sizeof (pt) == j) + meta = GNUNET_CONTAINER_meta_data_create (); + else + meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j], sizeof (pt) - j); + if (meta == NULL) + { + GNUNET_break_op (0); /* kblock malformed */ + return; + } + uri = GNUNET_FS_uri_parse (pt, &emsg); + if (uri == NULL) + { + GNUNET_break_op (0); /* kblock malformed */ + GNUNET_free_non_null (emsg); + GNUNET_CONTAINER_meta_data_destroy (meta); + return; + } + /* process */ + process_ksk_result (sc, &sc->requests[i], uri, meta); + + /* clean up */ + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_FS_uri_destroy (uri); +} + + +/** + * Process a keyword-search result with a namespace advertisment. + * + * @param sc our search context + * @param nb the nblock + * @param size size of nb + */ +static void +process_nblock (struct GNUNET_FS_SearchContext *sc, const struct NBlock *nb, + size_t size) +{ + unsigned int i; + size_t j; + GNUNET_HashCode q; + char pt[size - sizeof (struct NBlock)]; + struct GNUNET_CRYPTO_AesSessionKey skey; + struct GNUNET_CRYPTO_AesInitializationVector iv; + const char *eos; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *uri; + char *uris; + + GNUNET_CRYPTO_hash (&nb->keyspace, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &q); + /* find key */ + for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) + if (0 == memcmp (&q, &sc->requests[i].query, sizeof (GNUNET_HashCode))) + break; + if (i == sc->uri->data.ksk.keywordCount) + { + /* oops, does not match any of our keywords!? */ + GNUNET_break (0); + return; + } + /* decrypt */ + GNUNET_CRYPTO_hash_to_aes_key (&sc->requests[i].key, &skey, &iv); + if (-1 == + GNUNET_CRYPTO_aes_decrypt (&nb[1], size - sizeof (struct NBlock), &skey, + &iv, pt)) + { + GNUNET_break (0); + return; + } + /* parse */ + eos = memchr (pt, 0, sizeof (pt)); + if (NULL == eos) + { + GNUNET_break_op (0); + return; + } + j = eos - pt + 1; + if (sizeof (pt) == j) + meta = GNUNET_CONTAINER_meta_data_create (); + else + meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j], sizeof (pt) - j); + if (meta == NULL) + { + GNUNET_break_op (0); /* nblock malformed */ + return; + } + + uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + uri->type = sks; + uri->data.sks.identifier = GNUNET_strdup (pt); + GNUNET_CRYPTO_hash (&nb->subspace, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &uri->data.sks.namespace); + uris = GNUNET_FS_uri_to_string (uri); + GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_URI, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + uris, strlen (uris) + 1); + GNUNET_free (uris); + GNUNET_PSEUDONYM_add (sc->h->cfg, &uri->data.sks.namespace, meta); + /* process */ + process_ksk_result (sc, &sc->requests[i], uri, meta); + + /* clean up */ + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_FS_uri_destroy (uri); +} + + +/** + * Process a namespace-search result. + * + * @param sc our search context + * @param sb the sblock + * @param size size of sb + */ +static void +process_sblock (struct GNUNET_FS_SearchContext *sc, const struct SBlock *sb, + size_t size) +{ + size_t len = size - sizeof (struct SBlock); + char pt[len]; + struct GNUNET_CRYPTO_AesSessionKey skey; + struct GNUNET_CRYPTO_AesInitializationVector iv; + struct GNUNET_FS_Uri *uri; + struct GNUNET_CONTAINER_MetaData *meta; + const char *id; + const char *uris; + size_t off; + char *emsg; + GNUNET_HashCode key; + char *identifier; + + /* decrypt */ + identifier = sc->uri->data.sks.identifier; + GNUNET_CRYPTO_hash (identifier, strlen (identifier), &key); + GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); + if (-1 == GNUNET_CRYPTO_aes_decrypt (&sb[1], len, &skey, &iv, pt)) + { + GNUNET_break (0); + return; + } + /* parse */ + off = GNUNET_STRINGS_buffer_tokenize (pt, len, 2, &id, &uris); + if (off == 0) + { + GNUNET_break_op (0); /* sblock malformed */ + return; + } + meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[off], len - off); + if (meta == NULL) + { + GNUNET_break_op (0); /* sblock malformed */ + return; + } + uri = GNUNET_FS_uri_parse (uris, &emsg); + if (uri == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse URI `%s': %s\n", uris, + emsg); + GNUNET_break_op (0); /* sblock malformed */ + GNUNET_free_non_null (emsg); + GNUNET_CONTAINER_meta_data_destroy (meta); + return; + } + /* process */ + process_sks_result (sc, id, uri, meta); + /* clean up */ + GNUNET_FS_uri_destroy (uri); + GNUNET_CONTAINER_meta_data_destroy (meta); +} + + +/** + * Process a search result. + * + * @param sc our search context + * @param type type of the result + * @param expiration when it will expire + * @param data the (encrypted) response + * @param size size of data + */ +static void +process_result (struct GNUNET_FS_SearchContext *sc, enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute expiration, const void *data, + size_t size) +{ + if (GNUNET_TIME_absolute_get_duration (expiration).rel_value > 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Result received has already expired.\n"); + return; /* result expired */ + } + switch (type) + { + case GNUNET_BLOCK_TYPE_FS_KBLOCK: + if (!GNUNET_FS_uri_test_ksk (sc->uri)) + { + GNUNET_break (0); + return; + } + if (sizeof (struct KBlock) > size) + { + GNUNET_break_op (0); + return; + } + process_kblock (sc, data, size); + break; + case GNUNET_BLOCK_TYPE_FS_SBLOCK: + if (!GNUNET_FS_uri_test_sks (sc->uri)) + { + GNUNET_break (0); + return; + } + if (sizeof (struct SBlock) > size) + { + GNUNET_break_op (0); + return; + } + process_sblock (sc, data, size); + break; + case GNUNET_BLOCK_TYPE_FS_NBLOCK: + if (!GNUNET_FS_uri_test_ksk (sc->uri)) + { + GNUNET_break (0); + return; + } + if (sizeof (struct NBlock) > size) + { + GNUNET_break_op (0); + return; + } + process_nblock (sc, data, size); + break; + case GNUNET_BLOCK_TYPE_ANY: + GNUNET_break (0); + break; + case GNUNET_BLOCK_TYPE_FS_DBLOCK: + GNUNET_break (0); + break; + case GNUNET_BLOCK_TYPE_FS_ONDEMAND: + GNUNET_break (0); + break; + case GNUNET_BLOCK_TYPE_FS_IBLOCK: + GNUNET_break (0); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Got result with unknown block type `%d', ignoring"), type); + break; + } +} + + +/** + * Shutdown any existing connection to the FS + * service and try to establish a fresh one + * (and then re-transmit our search request). + * + * @param sc the search to reconnec + */ +static void +try_reconnect (struct GNUNET_FS_SearchContext *sc); + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +receive_results (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_FS_SearchContext *sc = cls; + const struct ClientPutMessage *cm; + uint16_t msize; + + if ((NULL == msg) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_PUT) || + (ntohs (msg->size) <= sizeof (struct ClientPutMessage))) + { + try_reconnect (sc); + return; + } + msize = ntohs (msg->size); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Receiving %u bytes of result from fs service\n", msize); + cm = (const struct ClientPutMessage *) msg; + process_result (sc, ntohl (cm->type), + GNUNET_TIME_absolute_ntoh (cm->expiration), &cm[1], + msize - sizeof (struct ClientPutMessage)); + /* continue receiving */ + GNUNET_CLIENT_receive (sc->client, &receive_results, sc, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Schedule the transmission of the (next) search request + * to the service. + * + * @param sc context for the search + */ +static void +schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc); + + +/** + * Closure for 'build_result_set'. + */ +struct MessageBuilderContext +{ + /** + * How many entries can we store to xoff. + */ + unsigned int put_cnt; + + /** + * How many entries should we skip. + */ + unsigned int skip_cnt; + + /** + * Where to store the keys. + */ + GNUNET_HashCode *xoff; + + /** + * Search context we are iterating for. + */ + struct GNUNET_FS_SearchContext *sc; + + /** + * Keyword offset the search result must match (0 for SKS) + */ + unsigned int keyword_offset; +}; + + +/** + * Iterating over the known results, pick those matching the given + * result range and store their keys at 'xoff'. + * + * @param cls the 'struct MessageBuilderContext' + * @param key key for a result + * @param value the search result + * @return GNUNET_OK to continue iterating + */ +static int +build_result_set (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct MessageBuilderContext *mbc = cls; + struct GNUNET_FS_SearchResult *sr = value; + + if ( (sr->keyword_bitmap != NULL) && + (0 == (sr->keyword_bitmap[mbc->keyword_offset / 8] & (1 << (mbc->keyword_offset % 8)))) ) + return GNUNET_OK; /* have no match for this keyword yet */ + if (mbc->skip_cnt > 0) + { + mbc->skip_cnt--; + return GNUNET_OK; + } + if (mbc->put_cnt == 0) + return GNUNET_SYSERR; + mbc->sc->search_request_map_offset++; + mbc->xoff[--mbc->put_cnt] = *key; + return GNUNET_OK; +} + + +/** + * Iterating over the known results, count those + * matching the given result range and increment + * put count for each. + * + * @param cls the 'struct MessageBuilderContext' + * @param key key for a result + * @param value the search result + * @return GNUNET_OK to continue iterating + */ +static int +find_result_set (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct MessageBuilderContext *mbc = cls; + struct GNUNET_FS_SearchResult *sr = value; + + if ( (sr->keyword_bitmap != NULL) && + (0 == (sr->keyword_bitmap[mbc->keyword_offset / 8] & (1 << (mbc->keyword_offset % 8)))) ) + return GNUNET_OK; /* have no match for this keyword yet */ + mbc->put_cnt++; + return GNUNET_OK; +} + + +/** + * We're ready to transmit the search request to the + * file-sharing service. Do it. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_search_request (void *cls, size_t size, void *buf) +{ + struct GNUNET_FS_SearchContext *sc = cls; + struct MessageBuilderContext mbc; + size_t msize; + struct SearchMessage *sm; + const char *identifier; + GNUNET_HashCode key; + GNUNET_HashCode idh; + unsigned int sqms; + uint32_t options; + + if (NULL == buf) + { + try_reconnect (sc); + return 0; + } + mbc.sc = sc; + mbc.skip_cnt = sc->search_request_map_offset; + sm = buf; + sm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_START_SEARCH); + mbc.xoff = (GNUNET_HashCode *) & sm[1]; + options = SEARCH_MESSAGE_OPTION_NONE; + if (0 != (sc->options & GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY)) + options |= SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY; + if (GNUNET_FS_uri_test_ksk (sc->uri)) + { + msize = sizeof (struct SearchMessage); + GNUNET_assert (size >= msize); + mbc.keyword_offset = sc->keyword_offset; + mbc.put_cnt = 0; + GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, + &find_result_set, &mbc); + sqms = mbc.put_cnt; + mbc.put_cnt = (size - msize) / sizeof (GNUNET_HashCode); + mbc.put_cnt = GNUNET_MIN (mbc.put_cnt, sqms - mbc.skip_cnt); + if (sc->search_request_map_offset < sqms) + GNUNET_assert (mbc.put_cnt > 0); + + sm->header.size = htons (msize); + sm->type = htonl (GNUNET_BLOCK_TYPE_ANY); + sm->anonymity_level = htonl (sc->anonymity); + memset (&sm->target, 0, sizeof (GNUNET_HashCode)); + sm->query = sc->requests[sc->keyword_offset].query; + msize += sizeof (GNUNET_HashCode) * mbc.put_cnt; + GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, + &build_result_set, &mbc); + sm->header.size = htons (msize); + GNUNET_assert (sqms >= sc->search_request_map_offset); + if (sqms != sc->search_request_map_offset) + { + /* more requesting to be done... */ + sm->options = htonl (options | SEARCH_MESSAGE_OPTION_CONTINUED); + schedule_transmit_search_request (sc); + return msize; + } + sm->options = htonl (options); + sc->keyword_offset++; + if (sc->uri->data.ksk.keywordCount != sc->keyword_offset) + { + /* more requesting to be done... */ + schedule_transmit_search_request (sc); + return msize; + } + } + else + { + GNUNET_assert (GNUNET_FS_uri_test_sks (sc->uri)); + msize = sizeof (struct SearchMessage); + GNUNET_assert (size >= msize); + sm->type = htonl (GNUNET_BLOCK_TYPE_FS_SBLOCK); + sm->anonymity_level = htonl (sc->anonymity); + sm->target = sc->uri->data.sks.namespace; + identifier = sc->uri->data.sks.identifier; + GNUNET_CRYPTO_hash (identifier, strlen (identifier), &key); + GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &idh); + GNUNET_CRYPTO_hash_xor (&idh, &sm->target, &sm->query); + mbc.put_cnt = (size - msize) / sizeof (GNUNET_HashCode); + sqms = GNUNET_CONTAINER_multihashmap_size (sc->master_result_map); + mbc.put_cnt = GNUNET_MIN (mbc.put_cnt, sqms - mbc.skip_cnt); + mbc.keyword_offset = 0; + if (sc->search_request_map_offset < sqms) + GNUNET_assert (mbc.put_cnt > 0); + msize += sizeof (GNUNET_HashCode) * mbc.put_cnt; + GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, + &build_result_set, &mbc); + sm->header.size = htons (msize); + GNUNET_assert (sqms >= sc->search_request_map_offset); + if (sqms != sc->search_request_map_offset) + { + /* more requesting to be done... */ + sm->options = htonl (options | SEARCH_MESSAGE_OPTION_CONTINUED); + schedule_transmit_search_request (sc); + return msize; + } + sm->options = htonl (options); + } + GNUNET_CLIENT_receive (sc->client, &receive_results, sc, + GNUNET_TIME_UNIT_FOREVER_REL); + return msize; +} + + +/** + * Schedule the transmission of the (next) search request + * to the service. + * + * @param sc context for the search + */ +static void +schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc) +{ + size_t size; + unsigned int sqms; + unsigned int fit; + + size = sizeof (struct SearchMessage); + sqms = + GNUNET_CONTAINER_multihashmap_size (sc->master_result_map) - + sc->search_request_map_offset; + fit = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - size) / sizeof (GNUNET_HashCode); + fit = GNUNET_MIN (fit, sqms); + size += sizeof (GNUNET_HashCode) * fit; + GNUNET_CLIENT_notify_transmit_ready (sc->client, size, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + GNUNET_NO, &transmit_search_request, sc); + +} + + +/** + * Reconnect to the FS service and transmit + * our queries NOW. + * + * @param cls our search context + * @param tc unused + */ +static void +do_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_SearchContext *sc = cls; + struct GNUNET_CLIENT_Connection *client; + + sc->task = GNUNET_SCHEDULER_NO_TASK; + client = GNUNET_CLIENT_connect ("fs", sc->h->cfg); + if (NULL == client) + { + try_reconnect (sc); + return; + } + sc->client = client; + sc->search_request_map_offset = 0; + sc->keyword_offset = 0; + schedule_transmit_search_request (sc); +} + + +/** + * Shutdown any existing connection to the FS + * service and try to establish a fresh one + * (and then re-transmit our search request). + * + * @param sc the search to reconnec + */ +static void +try_reconnect (struct GNUNET_FS_SearchContext *sc) +{ + if (NULL != sc->client) + { + GNUNET_CLIENT_disconnect (sc->client, GNUNET_NO); + sc->client = NULL; + } + sc->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_reconnect, + sc); +} + + +/** + * Start search for content, internal API. + * + * @param h handle to the file sharing subsystem + * @param uri specifies the search parameters; can be + * a KSK URI or an SKS URI. + * @param anonymity desired level of anonymity + * @param options options for the search + * @param cctx initial value for the client context + * @param psearch parent search result (for namespace update searches) + * @return context that can be used to control the search + */ +static struct GNUNET_FS_SearchContext * +search_start (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri, + uint32_t anonymity, enum GNUNET_FS_SearchOptions options, + void *cctx, struct GNUNET_FS_SearchResult *psearch) +{ + struct GNUNET_FS_SearchContext *sc; + struct GNUNET_FS_ProgressInfo pi; + + sc = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchContext)); + sc->h = h; + sc->options = options; + sc->uri = GNUNET_FS_uri_dup (uri); + sc->anonymity = anonymity; + sc->start_time = GNUNET_TIME_absolute_get (); + if (psearch != NULL) + { + sc->psearch_result = psearch; + psearch->update_search = sc; + } + sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16); + sc->client_info = cctx; + if (GNUNET_OK != GNUNET_FS_search_start_searching_ (sc)) + { + GNUNET_FS_uri_destroy (sc->uri); + GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); + GNUNET_free (sc); + return NULL; + } + GNUNET_FS_search_sync_ (sc); + pi.status = GNUNET_FS_STATUS_SEARCH_START; + sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); + return sc; +} + + +/** + * Build the request and actually initiate the search using the + * GNUnet FS service. + * + * @param sc search context + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc) +{ + unsigned int i; + const char *keyword; + GNUNET_HashCode hc; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; + struct GNUNET_CRYPTO_RsaPrivateKey *pk; + + GNUNET_assert (NULL == sc->client); + if (GNUNET_FS_uri_test_ksk (sc->uri)) + { + GNUNET_assert (0 != sc->uri->data.ksk.keywordCount); + sc->requests = + GNUNET_malloc (sizeof (struct SearchRequestEntry) * + sc->uri->data.ksk.keywordCount); + for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) + { + keyword = &sc->uri->data.ksk.keywords[i][1]; + GNUNET_CRYPTO_hash (keyword, strlen (keyword), &hc); + pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&hc); + GNUNET_assert (pk != NULL); + GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); + GNUNET_CRYPTO_rsa_key_free (pk); + GNUNET_CRYPTO_hash (&pub, + sizeof (struct + GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &sc->requests[i].query); + sc->requests[i].mandatory = (sc->uri->data.ksk.keywords[i][0] == '+'); + if (sc->requests[i].mandatory) + sc->mandatory_count++; + sc->requests[i].results = GNUNET_CONTAINER_multihashmap_create (4); + GNUNET_CRYPTO_hash (keyword, strlen (keyword), &sc->requests[i].key); + } + } + sc->client = GNUNET_CLIENT_connect ("fs", sc->h->cfg); + if (NULL == sc->client) + return GNUNET_SYSERR; + schedule_transmit_search_request (sc); + return GNUNET_OK; +} + + +/** + * Freeze probes for the given search result. + * + * @param cls the global FS handle + * @param key the key for the search result (unused) + * @param value the search result to free + * @return GNUNET_OK + */ +static int +search_result_freeze_probes (void *cls, const GNUNET_HashCode * key, + void *value) +{ + struct GNUNET_FS_SearchResult *sr = value; + + if (sr->probe_ctx != NULL) + { + GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); + sr->probe_ctx = NULL; + } + if (sr->probe_cancel_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); + sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; + } + if (sr->update_search != NULL) + GNUNET_FS_search_pause (sr->update_search); + return GNUNET_OK; +} + + +/** + * Resume probes for the given search result. + * + * @param cls the global FS handle + * @param key the key for the search result (unused) + * @param value the search result to free + * @return GNUNET_OK + */ +static int +search_result_resume_probes (void *cls, const GNUNET_HashCode * key, + void *value) +{ + struct GNUNET_FS_SearchResult *sr = value; + + GNUNET_FS_search_start_probe_ (sr); + if (sr->update_search != NULL) + GNUNET_FS_search_continue (sr->update_search); + return GNUNET_OK; +} + + +/** + * Signal suspend and free the given search result. + * + * @param cls the global FS handle + * @param key the key for the search result (unused) + * @param value the search result to free + * @return GNUNET_OK + */ +static int +search_result_suspend (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_FS_SearchContext *sc = cls; + struct GNUNET_FS_SearchResult *sr = value; + struct GNUNET_FS_ProgressInfo pi; + + if (sr->download != NULL) + GNUNET_FS_download_signal_suspend_ (sr->download); + if (sr->update_search != NULL) + GNUNET_FS_search_signal_suspend_ (sr->update_search); + pi.status = GNUNET_FS_STATUS_SEARCH_RESULT_SUSPEND; + pi.value.search.specifics.result_suspend.cctx = sr->client_info; + pi.value.search.specifics.result_suspend.meta = sr->meta; + pi.value.search.specifics.result_suspend.uri = sr->uri; + sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc); + GNUNET_break (NULL == sr->client_info); + GNUNET_free_non_null (sr->serialization); + GNUNET_FS_uri_destroy (sr->uri); + GNUNET_CONTAINER_meta_data_destroy (sr->meta); + if (sr->probe_ctx != NULL) + GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); + if (sr->probe_cancel_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); + GNUNET_free_non_null (sr->keyword_bitmap); + GNUNET_free (sr); + return GNUNET_OK; +} + + +/** + * Create SUSPEND event for the given search operation + * and then clean up our state (without stop signal). + * + * @param cls the 'struct GNUNET_FS_SearchContext' to signal for + */ +void +GNUNET_FS_search_signal_suspend_ (void *cls) +{ + struct GNUNET_FS_SearchContext *sc = cls; + struct GNUNET_FS_ProgressInfo pi; + unsigned int i; + + GNUNET_FS_end_top (sc->h, sc->top); + GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, + &search_result_suspend, sc); + pi.status = GNUNET_FS_STATUS_SEARCH_SUSPEND; + sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); + GNUNET_break (NULL == sc->client_info); + if (sc->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (sc->task); + if (NULL != sc->client) + GNUNET_CLIENT_disconnect (sc->client, GNUNET_NO); + GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); + if (sc->requests != NULL) + { + GNUNET_assert (GNUNET_FS_uri_test_ksk (sc->uri)); + for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) + GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results); + } + GNUNET_free_non_null (sc->requests); + GNUNET_free_non_null (sc->emsg); + GNUNET_FS_uri_destroy (sc->uri); + GNUNET_free_non_null (sc->serialization); + GNUNET_free (sc); +} + + +/** + * Start search for content. + * + * @param h handle to the file sharing subsystem + * @param uri specifies the search parameters; can be + * a KSK URI or an SKS URI. + * @param anonymity desired level of anonymity + * @param options options for the search + * @param cctx initial value for the client context + * @return context that can be used to control the search + */ +struct GNUNET_FS_SearchContext * +GNUNET_FS_search_start (struct GNUNET_FS_Handle *h, + const struct GNUNET_FS_Uri *uri, uint32_t anonymity, + enum GNUNET_FS_SearchOptions options, void *cctx) +{ + struct GNUNET_FS_SearchContext *ret; + + ret = search_start (h, uri, anonymity, options, cctx, NULL); + if (ret == NULL) + return NULL; + ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_search_signal_suspend_, ret); + return ret; +} + + +/** + * Pause search. + * + * @param sc context for the search that should be paused + */ +void +GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc) +{ + struct GNUNET_FS_ProgressInfo pi; + + if (sc->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (sc->task); + sc->task = GNUNET_SCHEDULER_NO_TASK; + if (NULL != sc->client) + GNUNET_CLIENT_disconnect (sc->client, GNUNET_NO); + sc->client = NULL; + GNUNET_FS_search_sync_ (sc); + GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, + &search_result_freeze_probes, sc); + pi.status = GNUNET_FS_STATUS_SEARCH_PAUSED; + sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); +} + + +/** + * Continue paused search. + * + * @param sc context for the search that should be resumed + */ +void +GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc) +{ + struct GNUNET_FS_ProgressInfo pi; + + GNUNET_assert (sc->client == NULL); + GNUNET_assert (sc->task == GNUNET_SCHEDULER_NO_TASK); + do_reconnect (sc, NULL); + GNUNET_FS_search_sync_ (sc); + pi.status = GNUNET_FS_STATUS_SEARCH_CONTINUED; + sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); + GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, + &search_result_resume_probes, sc); +} + + +/** + * Free the given search result. + * + * @param cls the global FS handle + * @param key the key for the search result (unused) + * @param value the search result to free + * @return GNUNET_OK + */ +static int +search_result_free (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_FS_SearchContext *sc = cls; + struct GNUNET_FS_SearchResult *sr = value; + struct GNUNET_FS_ProgressInfo pi; + + if (NULL != sr->download) + { + sr->download->search = NULL; + sr->download->top = + GNUNET_FS_make_top (sr->download->h, + &GNUNET_FS_download_signal_suspend_, sr->download); + if (NULL != sr->download->serialization) + { + GNUNET_FS_remove_sync_file_ (sc->h, GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD, + sr->download->serialization); + GNUNET_free (sr->download->serialization); + sr->download->serialization = NULL; + } + pi.status = GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT; + GNUNET_FS_download_make_status_ (&pi, sr->download); + GNUNET_FS_download_sync_ (sr->download); + sr->download = NULL; + } + if (NULL != sr->update_search) + { + GNUNET_FS_search_stop (sr->update_search); + GNUNET_assert (sr->update_search == NULL); + } + pi.status = GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED; + pi.value.search.specifics.result_stopped.cctx = sr->client_info; + pi.value.search.specifics.result_stopped.meta = sr->meta; + pi.value.search.specifics.result_stopped.uri = sr->uri; + sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc); + GNUNET_break (NULL == sr->client_info); + GNUNET_free_non_null (sr->serialization); + GNUNET_FS_uri_destroy (sr->uri); + GNUNET_CONTAINER_meta_data_destroy (sr->meta); + if (sr->probe_ctx != NULL) + GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); + if (sr->probe_cancel_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); + GNUNET_free_non_null (sr->keyword_bitmap); + GNUNET_free (sr); + return GNUNET_OK; +} + + +/** + * Stop search for content. + * + * @param sc context for the search that should be stopped + */ +void +GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc) +{ + struct GNUNET_FS_ProgressInfo pi; + unsigned int i; + + if (sc->top != NULL) + GNUNET_FS_end_top (sc->h, sc->top); + if (sc->psearch_result != NULL) + sc->psearch_result->update_search = NULL; + GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, + &search_result_free, sc); + if (sc->serialization != NULL) + { + GNUNET_FS_remove_sync_file_ (sc->h, + (sc->psearch_result != + NULL) ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH : + GNUNET_FS_SYNC_PATH_MASTER_SEARCH, + sc->serialization); + GNUNET_FS_remove_sync_dir_ (sc->h, + (sc->psearch_result != + NULL) ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH : + GNUNET_FS_SYNC_PATH_MASTER_SEARCH, + sc->serialization); + GNUNET_free (sc->serialization); + } + pi.status = GNUNET_FS_STATUS_SEARCH_STOPPED; + sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); + GNUNET_break (NULL == sc->client_info); + if (sc->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (sc->task); + if (NULL != sc->client) + GNUNET_CLIENT_disconnect (sc->client, GNUNET_NO); + GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); + if (sc->requests != NULL) + { + GNUNET_assert (GNUNET_FS_uri_test_ksk (sc->uri)); + for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) + GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results); + } + GNUNET_free_non_null (sc->requests); + GNUNET_free_non_null (sc->emsg); + GNUNET_FS_uri_destroy (sc->uri); + GNUNET_free (sc); +} + +/* end of fs_search.c */ diff --git a/src/fs/fs_sharetree.c b/src/fs/fs_sharetree.c new file mode 100644 index 0000000..c929428 --- /dev/null +++ b/src/fs/fs_sharetree.c @@ -0,0 +1,452 @@ +/* + This file is part of GNUnet + (C) 2005-2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_sharetree.c + * @brief code to manipulate the 'struct GNUNET_FS_ShareTreeItem' tree + * @author LRN + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_fs_service.h" +#include "gnunet_scheduler_lib.h" +#include + + +/** + * Entry for each unique keyword to track how often + * it occured. Contains the keyword and the counter. + */ +struct KeywordCounter +{ + + /** + * This is a doubly-linked list + */ + struct KeywordCounter *prev; + + /** + * This is a doubly-linked list + */ + struct KeywordCounter *next; + + /** + * Keyword that was found. + */ + const char *value; + + /** + * How many files have this keyword? + */ + unsigned int count; + +}; + + +/** + * Aggregate information we keep for meta data in each directory. + */ +struct MetaCounter +{ + + /** + * This is a doubly-linked list + */ + struct MetaCounter *prev; + + /** + * This is a doubly-linked list + */ + struct MetaCounter *next; + + /** + * Name of the plugin that provided that piece of metadata + */ + const char *plugin_name; + + /** + * MIME-type of the metadata itself + */ + const char *data_mime_type; + + /** + * The actual meta data. + */ + const char *data; + + /** + * Number of bytes in 'data'. + */ + size_t data_size; + + /** + * Type of the data + */ + enum EXTRACTOR_MetaType type; + + /** + * Format of the data + */ + enum EXTRACTOR_MetaFormat format; + + /** + * How many files have meta entries matching this value? + * (type and format do not have to match). + */ + unsigned int count; + +}; + + +/** + * A structure that forms a singly-linked list that serves as a stack + * for metadata-processing function. + */ +struct TrimContext +{ + + /** + * Map from the hash over the keyword to an 'struct KeywordCounter *' + * counter that says how often this keyword was + * encountered in the current directory. + */ + struct GNUNET_CONTAINER_MultiHashMap *keywordcounter; + + /** + * Map from the hash over the metadata to an 'struct MetaCounter *' + * counter that says how often this metadata was + * encountered in the current directory. + */ + struct GNUNET_CONTAINER_MultiHashMap *metacounter; + + /** + * Position we are currently manipulating. + */ + struct GNUNET_FS_ShareTreeItem *pos; + + /** + * Number of times an item has to be found to be moved to the parent. + */ + unsigned int move_threshold; + +}; + + +/** + * Add the given keyword to the keyword statistics tracker. + * + * @param cls the multihashmap we store the keyword counters in + * @param keyword the keyword to count + * @param is_mandatory ignored + * @return always GNUNET_OK + */ +static int +add_to_keyword_counter (void *cls, const char *keyword, int is_mandatory) +{ + struct GNUNET_CONTAINER_MultiHashMap *mcm = cls; + struct KeywordCounter *cnt; + GNUNET_HashCode hc; + size_t klen; + + klen = strlen (keyword) + 1; + GNUNET_CRYPTO_hash (keyword, klen - 1, &hc); + cnt = GNUNET_CONTAINER_multihashmap_get (mcm, &hc); + if (cnt == NULL) + { + cnt = GNUNET_malloc (sizeof (struct KeywordCounter) + klen); + cnt->value = (const char *) &cnt[1]; + memcpy (&cnt[1], keyword, klen); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (mcm, + &hc, cnt, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + } + cnt->count++; + return GNUNET_OK; +} + + +/** + * Function called on each meta data item. Increments the + * respective counter. + * + * @param cls the container multihashmap to update + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_len number of bytes in data + * @return GNUNET_OK to continue extracting / iterating + */ +static int +add_to_meta_counter (void *cls, const char *plugin_name, + enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, + const char *data_mime_type, const char *data, size_t data_len) +{ + struct GNUNET_CONTAINER_MultiHashMap *map = cls; + GNUNET_HashCode key; + struct MetaCounter *cnt; + + GNUNET_CRYPTO_hash (data, data_len, &key); + cnt = GNUNET_CONTAINER_multihashmap_get (map, &key); + if (cnt == NULL) + { + cnt = GNUNET_malloc (sizeof (struct MetaCounter)); + cnt->data = data; + cnt->data_size = data_len; + cnt->plugin_name = plugin_name; + cnt->type = type; + cnt->format = format; + cnt->data_mime_type = data_mime_type; + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (map, + &key, cnt, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + } + cnt->count++; + return 0; +} + + +/** + * Remove keywords above the threshold. + * + * @param cls the 'struct TrimContext' with the pos to remove the keywords from + * @param keyword the keyword to check + * @param is_mandatory ignored + * @return always GNUNET_OK + */ +static int +remove_high_frequency_keywords (void *cls, const char *keyword, int is_mandatory) +{ + struct TrimContext *tc = cls; + struct KeywordCounter *counter; + GNUNET_HashCode hc; + size_t klen; + + klen = strlen (keyword) + 1; + GNUNET_CRYPTO_hash (keyword, klen - 1, &hc); + counter = GNUNET_CONTAINER_multihashmap_get (tc->keywordcounter, &hc); + GNUNET_assert (NULL != counter); + if (counter->count < tc->move_threshold) + return GNUNET_OK; + GNUNET_FS_uri_ksk_remove_keyword (tc->pos->ksk_uri, + counter->value); + return GNUNET_OK; +} + + +/** + * Move "frequent" keywords over to the target ksk uri, free the + * counters. + * + * @param cls the 'struct TrimContext' + * @param key key of the entry + * @param value the 'struct KeywordCounter' + * @return GNUNET_YES (always) + */ +static int +migrate_and_drop_keywords (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct TrimContext *tc = cls; + struct KeywordCounter *counter = value; + + if (counter->count >= tc->move_threshold) + { + if (NULL == tc->pos->ksk_uri) + tc->pos->ksk_uri = GNUNET_FS_uri_ksk_create_from_args (1, &counter->value); + else + GNUNET_FS_uri_ksk_add_keyword (tc->pos->ksk_uri, counter->value, GNUNET_NO); + } + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (tc->keywordcounter, + key, + counter)); + GNUNET_free (counter); + return GNUNET_YES; +} + + +/** + * Copy "frequent" metadata items over to the + * target metadata container, free the counters. + * + * @param cls the 'struct TrimContext' + * @param key key of the entry + * @param value the 'struct KeywordCounter' + * @return GNUNET_YES (always) + */ +static int +migrate_and_drop_metadata (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct TrimContext *tc = cls; + struct MetaCounter *counter = value; + + if (counter->count >= tc->move_threshold) + { + if (NULL == tc->pos->meta) + tc->pos->meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (tc->pos->meta, + counter->plugin_name, + counter->type, + counter->format, + counter->data_mime_type, counter->data, + counter->data_size); + } + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (tc->metacounter, + key, + counter)); + GNUNET_free (counter); + return GNUNET_YES; +} + + +/** + * Process a share item tree, moving frequent keywords up and + * copying frequent metadata up. + * + * @param tc trim context with hash maps to use + * @param tree tree to trim + */ +static void +share_tree_trim (struct TrimContext *tc, + struct GNUNET_FS_ShareTreeItem *tree) +{ + struct GNUNET_FS_ShareTreeItem *pos; + unsigned int num_children; + + /* first, trim all children */ + num_children = 0; + for (pos = tree->children_head; NULL != pos; pos = pos->next) + { + share_tree_trim (tc, pos); + num_children++; + } + + /* consider adding filename to directory meta data */ + if (tree->is_directory == GNUNET_YES) + { + const char *user = getenv ("USER"); + if ( (user == NULL) || + (0 != strncasecmp (user, tree->short_filename, strlen(user)))) + { + /* only use filename if it doesn't match $USER */ + if (NULL == tree->meta) + tree->meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (tree->meta, "", + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", tree->short_filename, + strlen (tree->short_filename) + 1); + } + } + + if (1 >= num_children) + return; /* nothing to trim */ + + /* now, count keywords and meta data in children */ + for (pos = tree->children_head; NULL != pos; pos = pos->next) + { + if (NULL != pos->meta) + GNUNET_CONTAINER_meta_data_iterate (pos->meta, &add_to_meta_counter, tc->metacounter); + if (NULL != pos->ksk_uri) + GNUNET_FS_uri_ksk_get_keywords (pos->ksk_uri, &add_to_keyword_counter, tc->keywordcounter); + } + + /* calculate threshold for moving keywords / meta data */ + tc->move_threshold = 1 + (num_children / 2); + + /* remove high-frequency keywords from children */ + for (pos = tree->children_head; NULL != pos; pos = pos->next) + { + tc->pos = pos; + if (NULL != pos->ksk_uri) + { + struct GNUNET_FS_Uri *ksk_uri_copy = GNUNET_FS_uri_dup (pos->ksk_uri); + GNUNET_FS_uri_ksk_get_keywords (ksk_uri_copy, &remove_high_frequency_keywords, tc); + GNUNET_FS_uri_destroy (ksk_uri_copy); + } + } + + /* add high-frequency meta data and keywords to parent */ + tc->pos = tree; + GNUNET_CONTAINER_multihashmap_iterate (tc->keywordcounter, + &migrate_and_drop_keywords, + tc); + GNUNET_CONTAINER_multihashmap_iterate (tc->metacounter, + &migrate_and_drop_metadata, + tc); +} + + +/** + * Process a share item tree, moving frequent keywords up and + * copying frequent metadata up. + * + * @param toplevel toplevel directory in the tree, returned by the scanner + */ +void +GNUNET_FS_share_tree_trim (struct GNUNET_FS_ShareTreeItem *toplevel) +{ + struct TrimContext tc; + + if (toplevel == NULL) + return; + tc.keywordcounter = GNUNET_CONTAINER_multihashmap_create (1024); + tc.metacounter = GNUNET_CONTAINER_multihashmap_create (1024); + share_tree_trim (&tc, toplevel); + GNUNET_CONTAINER_multihashmap_destroy (tc.keywordcounter); + GNUNET_CONTAINER_multihashmap_destroy (tc.metacounter); +} + + +/** + * Release memory of a share item tree. + * + * @param toplevel toplevel of the tree to be freed + */ +void +GNUNET_FS_share_tree_free (struct GNUNET_FS_ShareTreeItem *toplevel) +{ + struct GNUNET_FS_ShareTreeItem *pos; + + while (NULL != (pos = toplevel->children_head)) + GNUNET_FS_share_tree_free (pos); + if (NULL != toplevel->parent) + GNUNET_CONTAINER_DLL_remove (toplevel->parent->children_head, + toplevel->parent->children_tail, + toplevel); + if (NULL != toplevel->meta) + GNUNET_CONTAINER_meta_data_destroy (toplevel->meta); + if (NULL != toplevel->ksk_uri) + GNUNET_FS_uri_destroy (toplevel->ksk_uri); + GNUNET_free_non_null (toplevel->filename); + GNUNET_free_non_null (toplevel->short_filename); + GNUNET_free (toplevel); +} + +/* end fs_sharetree.c */ + diff --git a/src/fs/fs_test_lib.c b/src/fs/fs_test_lib.c new file mode 100644 index 0000000..06ab01f --- /dev/null +++ b/src/fs/fs_test_lib.c @@ -0,0 +1,731 @@ +/* + This file is part of GNUnet. + (C) 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_test_lib.c + * @brief library routines for testing FS publishing and downloading + * with multiple peers; this code is limited to flat files + * and no keywords (those functions can be tested with + * single-peer setups; this is for testing routing). + * @author Christian Grothoff + */ +#include "platform.h" +#include "fs_api.h" +#include "fs_test_lib.h" +#include "gnunet_testing_lib.h" + +#define CONNECT_ATTEMPTS 4 + +#define CONTENT_LIFETIME GNUNET_TIME_UNIT_HOURS + +/** + * Handle for a daemon started for testing FS. + */ +struct GNUNET_FS_TestDaemon +{ + + /** + * Global configuration, only stored in first test daemon, + * otherwise NULL. + */ + struct GNUNET_CONFIGURATION_Handle *gcfg; + + /** + * Handle to the file sharing context using this daemon. + */ + struct GNUNET_FS_Handle *fs; + + /** + * Handle to the daemon via testing. + */ + struct GNUNET_TESTING_Daemon *daemon; + + /** + * Note that 'group' will be the same value for all of the + * daemons started jointly. + */ + struct GNUNET_TESTING_PeerGroup *group; + + /** + * Configuration for accessing this peer. + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * ID of this peer. + */ + struct GNUNET_PeerIdentity id; + + /** + * Function to call when upload is done. + */ + GNUNET_FS_TEST_UriContinuation publish_cont; + + /** + * Closure for publish_cont. + */ + void *publish_cont_cls; + + /** + * Task to abort publishing (timeout). + */ + GNUNET_SCHEDULER_TaskIdentifier publish_timeout_task; + + /** + * Seed for file generation. + */ + uint32_t publish_seed; + + /** + * Context for current publishing operation. + */ + struct GNUNET_FS_PublishContext *publish_context; + + /** + * Result URI. + */ + struct GNUNET_FS_Uri *publish_uri; + + /** + * Name of the temporary file used, or NULL for none. + */ + char *publish_tmp_file; + + /** + * Function to call when download is done. + */ + GNUNET_SCHEDULER_Task download_cont; + + /** + * Closure for download_cont. + */ + void *download_cont_cls; + + /** + * Seed for download verification. + */ + uint32_t download_seed; + + /** + * Task to abort downloading (timeout). + */ + GNUNET_SCHEDULER_TaskIdentifier download_timeout_task; + + /** + * Context for current download operation. + */ + struct GNUNET_FS_DownloadContext *download_context; + + /** + * Verbosity level of the current operation. + */ + int verbose; + + +}; + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + struct GNUNET_CONFIGURATION_Handle *gcfg = cls; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Shutdown of peers failed: %s\n", + emsg); + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } + if (gcfg != NULL) + GNUNET_CONFIGURATION_destroy (gcfg); +} + + +static void +report_uri (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_TestDaemon *daemon = cls; + GNUNET_FS_TEST_UriContinuation cont; + struct GNUNET_FS_Uri *uri; + + GNUNET_FS_publish_stop (daemon->publish_context); + daemon->publish_context = NULL; + cont = daemon->publish_cont; + daemon->publish_cont = NULL; + uri = daemon->publish_uri; + cont (daemon->publish_cont_cls, uri); + GNUNET_FS_uri_destroy (uri); +} + + +static void +report_success (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_TestDaemon *daemon = cls; + + GNUNET_FS_download_stop (daemon->download_context, GNUNET_YES); + daemon->download_context = NULL; + GNUNET_SCHEDULER_add_continuation (daemon->download_cont, + daemon->download_cont_cls, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + daemon->download_cont = NULL; +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) +{ + struct GNUNET_FS_TestDaemon *daemon = cls; + + switch (info->status) + { + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + GNUNET_SCHEDULER_cancel (daemon->publish_timeout_task); + daemon->publish_timeout_task = GNUNET_SCHEDULER_NO_TASK; + daemon->publish_uri = + GNUNET_FS_uri_dup (info->value.publish.specifics.completed.chk_uri); + GNUNET_SCHEDULER_add_continuation (&report_uri, daemon, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: + if (daemon->verbose) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Publishing at %llu/%llu bytes\n", + (unsigned long long) info->value.publish.completed, + (unsigned long long) info->value.publish.size); + break; + case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: + if (daemon->verbose) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Download at %llu/%llu bytes\n", + (unsigned long long) info->value.download.completed, + (unsigned long long) info->value.download.size); + break; + case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: + GNUNET_SCHEDULER_cancel (daemon->download_timeout_task); + daemon->download_timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_continuation (&report_success, daemon, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: + case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: + break; + /* FIXME: monitor data correctness during download progress */ + /* FIXME: do performance reports given sufficient verbosity */ + /* FIXME: advance timeout task to "immediate" on error */ + default: + break; + } + return NULL; +} + + +struct StartContext +{ + struct GNUNET_TIME_Relative timeout; + unsigned int total; + unsigned int have; + struct GNUNET_FS_TestDaemon **daemons; + GNUNET_SCHEDULER_Task cont; + void *cont_cls; + struct GNUNET_TESTING_PeerGroup *group; + struct GNUNET_CONFIGURATION_Handle *cfg; + GNUNET_SCHEDULER_TaskIdentifier timeout_task; +}; + + +static void +notify_running (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct StartContext *sctx = cls; + unsigned int i; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start daemon: %s\n"), + emsg); + return; + } + i = 0; + while (i < sctx->total) + { + if (GNUNET_TESTING_daemon_get (sctx->group, i) == d) + break; + i++; + } + GNUNET_assert (i < sctx->total); + GNUNET_assert (sctx->have < sctx->total); + GNUNET_assert (sctx->daemons[i]->cfg == NULL); + sctx->daemons[i]->cfg = GNUNET_CONFIGURATION_dup (cfg); + sctx->daemons[i]->group = sctx->group; + sctx->daemons[i]->daemon = d; + sctx->daemons[i]->id = *id; + sctx->have++; + if (sctx->have == sctx->total) + { + GNUNET_SCHEDULER_add_continuation (sctx->cont, sctx->cont_cls, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + sctx->daemons[0]->gcfg = sctx->cfg; + GNUNET_SCHEDULER_cancel (sctx->timeout_task); + for (i = 0; i < sctx->total; i++) + { + sctx->daemons[i]->fs = + GNUNET_FS_start (sctx->daemons[i]->cfg, "", &progress_cb, + sctx->daemons[i], GNUNET_FS_FLAGS_NONE, + GNUNET_FS_OPTIONS_END); + } + GNUNET_free (sctx); + } +} + + +static void +start_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct StartContext *sctx = cls; + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout while trying to start daemons\n"); + GNUNET_TESTING_daemons_stop (sctx->group, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 30), + &shutdown_callback, NULL); + for (i = 0; i < sctx->total; i++) + { + if (i < sctx->have) + GNUNET_CONFIGURATION_destroy (sctx->daemons[i]->cfg); + GNUNET_free (sctx->daemons[i]); + sctx->daemons[i] = NULL; + } + GNUNET_CONFIGURATION_destroy (sctx->cfg); + GNUNET_SCHEDULER_add_continuation (sctx->cont, sctx->cont_cls, + GNUNET_SCHEDULER_REASON_TIMEOUT); + GNUNET_free (sctx); +} + + +/** + * Start daemons for testing. + * + * @param template_cfg_file configuration template to use + * @param timeout if this operation cannot be completed within the + * given period, call the continuation with an error code + * @param total number of daemons to start + * @param daemons array of 'total' entries to be initialized + * (array must already be allocated, will be filled) + * @param cont function to call when done + * @param cont_cls closure for cont + */ +void +GNUNET_FS_TEST_daemons_start (const char *template_cfg_file, + struct GNUNET_TIME_Relative timeout, + unsigned int total, + struct GNUNET_FS_TestDaemon **daemons, + GNUNET_SCHEDULER_Task cont, void *cont_cls) +{ + struct StartContext *sctx; + unsigned int i; + + GNUNET_assert (total > 0); + sctx = GNUNET_malloc (sizeof (struct StartContext)); + sctx->daemons = daemons; + sctx->total = total; + sctx->cont = cont; + sctx->cont_cls = cont_cls; + sctx->cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != GNUNET_CONFIGURATION_load (sctx->cfg, template_cfg_file)) + { + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (sctx->cfg); + GNUNET_free (sctx); + GNUNET_SCHEDULER_add_continuation (cont, cont_cls, + GNUNET_SCHEDULER_REASON_TIMEOUT); + return; + } + for (i = 0; i < total; i++) + daemons[i] = GNUNET_malloc (sizeof (struct GNUNET_FS_TestDaemon)); + sctx->group = GNUNET_TESTING_daemons_start (sctx->cfg, total, total, /* Outstanding connections */ + total, /* Outstanding ssh connections */ + timeout, NULL, NULL, + ¬ify_running, sctx, NULL, NULL, + NULL); + sctx->timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, &start_timeout, sctx); +} + + +struct GNUNET_FS_TEST_ConnectContext +{ + GNUNET_SCHEDULER_Task cont; + void *cont_cls; + struct GNUNET_TESTING_ConnectContext *cc; +}; + + +/** + * Prototype of a function that will be called whenever + * two daemons are connected by the testing library. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param first_cfg config for the first daemon + * @param second_cfg config for the second daemon + * @param first_daemon handle for the first daemon + * @param second_daemon handle for the second daemon + * @param emsg error message (NULL on success) + */ +static void +notify_connection (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + struct GNUNET_FS_TEST_ConnectContext *cc = cls; + + cc->cc = NULL; + if (emsg != NULL) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to connect peers: %s\n", + emsg); + GNUNET_SCHEDULER_add_continuation (cc->cont, cc->cont_cls, + (emsg != + NULL) ? GNUNET_SCHEDULER_REASON_TIMEOUT : + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + GNUNET_free (cc); +} + + +/** + * Connect two daemons for testing. + * + * @param daemon1 first daemon to connect + * @param daemon2 second first daemon to connect + * @param timeout if this operation cannot be completed within the + * given period, call the continuation with an error code + * @param cont function to call when done + * @param cont_cls closure for cont + */ +struct GNUNET_FS_TEST_ConnectContext * +GNUNET_FS_TEST_daemons_connect (struct GNUNET_FS_TestDaemon *daemon1, + struct GNUNET_FS_TestDaemon *daemon2, + struct GNUNET_TIME_Relative timeout, + GNUNET_SCHEDULER_Task cont, void *cont_cls) +{ + struct GNUNET_FS_TEST_ConnectContext *ncc; + + ncc = GNUNET_malloc (sizeof (struct GNUNET_FS_TEST_ConnectContext)); + ncc->cont = cont; + ncc->cont_cls = cont_cls; + ncc->cc = + GNUNET_TESTING_daemons_connect (daemon1->daemon, daemon2->daemon, timeout, + CONNECT_ATTEMPTS, GNUNET_YES, + ¬ify_connection, ncc); + return ncc; +} + + +/** + * Cancel connect operation. + * + * @param cc operation to cancel + */ +void +GNUNET_FS_TEST_daemons_connect_cancel (struct GNUNET_FS_TEST_ConnectContext *cc) +{ + GNUNET_TESTING_daemons_connect_cancel (cc->cc); + GNUNET_free (cc); +} + + +/** + * Obtain peer configuration used for testing. + * + * @param daemons array with the daemons + * @param off which configuration to get + * @return peer configuration + */ +const struct GNUNET_CONFIGURATION_Handle * +GNUNET_FS_TEST_get_configuration (struct GNUNET_FS_TestDaemon **daemons, + unsigned int off) +{ + return daemons[off]->cfg; +} + +/** + * Obtain peer group used for testing. + * + * @param daemons array with the daemons (must contain at least one) + * @return peer group + */ +struct GNUNET_TESTING_PeerGroup * +GNUNET_FS_TEST_get_group (struct GNUNET_FS_TestDaemon **daemons) +{ + return daemons[0]->group; +} + + +/** + * Stop daemons used for testing. + * + * @param total number of daemons to stop + * @param daemons array with the daemons (values will be clobbered) + */ +void +GNUNET_FS_TEST_daemons_stop (unsigned int total, + struct GNUNET_FS_TestDaemon **daemons) +{ + unsigned int i; + struct GNUNET_TESTING_PeerGroup *pg; + struct GNUNET_CONFIGURATION_Handle *gcfg; + struct GNUNET_FS_TestDaemon *daemon; + + GNUNET_assert (total > 0); + GNUNET_assert (daemons[0] != NULL); + pg = daemons[0]->group; + gcfg = daemons[0]->gcfg; + for (i = 0; i < total; i++) + { + daemon = daemons[i]; + if (daemon->download_timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (daemon->download_timeout_task); + daemon->download_timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (daemon->publish_timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (daemon->publish_timeout_task); + daemon->publish_timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != daemon->download_context) + { + GNUNET_FS_download_stop (daemon->download_context, GNUNET_YES); + daemon->download_context = NULL; + } + if (daemon->fs != NULL) + GNUNET_FS_stop (daemon->fs); + if (daemon->cfg != NULL) + GNUNET_CONFIGURATION_destroy (daemon->cfg); + if (NULL != daemon->publish_tmp_file) + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_directory_remove (daemon->publish_tmp_file)); + GNUNET_free (daemon->publish_tmp_file); + daemon->publish_tmp_file = NULL; + } + GNUNET_free (daemon); + daemons[i] = NULL; + } + GNUNET_TESTING_daemons_stop (pg, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 30), + &shutdown_callback, gcfg); +} + + +static void +publish_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_TestDaemon *daemon = cls; + GNUNET_FS_TEST_UriContinuation cont; + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout while trying to publish data\n"); + cont = daemon->publish_cont; + daemon->publish_timeout_task = GNUNET_SCHEDULER_NO_TASK; + daemon->publish_cont = NULL; + GNUNET_FS_publish_stop (daemon->publish_context); + daemon->publish_context = NULL; + cont (daemon->publish_cont_cls, NULL); +} + + +static size_t +file_generator (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) +{ + struct GNUNET_FS_TestDaemon *daemon = cls; + uint64_t pos; + uint8_t *cbuf = buf; + int mod; + + if (emsg != NULL) + *emsg = NULL; + if (buf == NULL) + return 0; + for (pos = 0; pos < 8; pos++) + cbuf[pos] = (uint8_t) (offset >> pos * 8); + for (pos = 8; pos < max; pos++) + { + mod = (255 - (offset / 1024 / 32)); + if (mod == 0) + mod = 1; + cbuf[pos] = (uint8_t) ((offset * daemon->publish_seed) % mod); + } + return max; +} + + + +/** + * Publish a file at the given daemon. + * + * @param daemon where to publish + * @param timeout if this operation cannot be completed within the + * given period, call the continuation with an error code + * @param anonymity option for publication + * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, + * GNUNET_SYSERR for simulation + * @param size size of the file to publish + * @param seed seed to use for file generation + * @param verbose how verbose to be in reporting + * @param cont function to call when done + * @param cont_cls closure for cont + */ +void +GNUNET_FS_TEST_publish (struct GNUNET_FS_TestDaemon *daemon, + struct GNUNET_TIME_Relative timeout, uint32_t anonymity, + int do_index, uint64_t size, uint32_t seed, + unsigned int verbose, + GNUNET_FS_TEST_UriContinuation cont, void *cont_cls) +{ + struct GNUNET_FS_FileInformation *fi; + struct GNUNET_DISK_FileHandle *fh; + char *emsg; + uint64_t off; + char buf[DBLOCK_SIZE]; + size_t bsize; + struct GNUNET_FS_BlockOptions bo; + + GNUNET_assert (daemon->publish_cont == NULL); + daemon->publish_cont = cont; + daemon->publish_cont_cls = cont_cls; + daemon->publish_seed = seed; + daemon->verbose = verbose; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (CONTENT_LIFETIME); + bo.anonymity_level = anonymity; + bo.content_priority = 42; + bo.replication_level = 1; + if (GNUNET_YES == do_index) + { + GNUNET_assert (daemon->publish_tmp_file == NULL); + daemon->publish_tmp_file = GNUNET_DISK_mktemp ("fs-test-publish-index"); + GNUNET_assert (daemon->publish_tmp_file != NULL); + fh = GNUNET_DISK_file_open (daemon->publish_tmp_file, + GNUNET_DISK_OPEN_WRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + GNUNET_assert (NULL != fh); + off = 0; + while (off < size) + { + bsize = GNUNET_MIN (sizeof (buf), size - off); + emsg = NULL; + GNUNET_assert (bsize == file_generator (daemon, off, bsize, buf, &emsg)); + GNUNET_assert (emsg == NULL); + GNUNET_assert (bsize == GNUNET_DISK_file_write (fh, buf, bsize)); + off += bsize; + } + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); + fi = GNUNET_FS_file_information_create_from_file (daemon->fs, daemon, + daemon->publish_tmp_file, + NULL, NULL, do_index, + &bo); + } + else + { + fi = GNUNET_FS_file_information_create_from_reader (daemon->fs, daemon, + size, &file_generator, + daemon, NULL, NULL, + do_index, &bo); + } + daemon->publish_context = + GNUNET_FS_publish_start (daemon->fs, fi, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + daemon->publish_timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, &publish_timeout, daemon); +} + + +static void +download_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_TestDaemon *daemon = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout while trying to download file\n"); + daemon->download_timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_FS_download_stop (daemon->download_context, GNUNET_YES); + daemon->download_context = NULL; + GNUNET_SCHEDULER_add_continuation (daemon->download_cont, + daemon->download_cont_cls, + GNUNET_SCHEDULER_REASON_TIMEOUT); + daemon->download_cont = NULL; +} + + +/** + * Perform test download. + * + * @param daemon which peer to download from + * @param timeout if this operation cannot be completed within the + * given period, call the continuation with an error code + * @param anonymity option for download + * @param seed used for file validation + * @param uri URI of file to download (CHK/LOC only) + * @param verbose how verbose to be in reporting + * @param cont function to call when done + * @param cont_cls closure for cont + */ +void +GNUNET_FS_TEST_download (struct GNUNET_FS_TestDaemon *daemon, + struct GNUNET_TIME_Relative timeout, + uint32_t anonymity, uint32_t seed, + const struct GNUNET_FS_Uri *uri, unsigned int verbose, + GNUNET_SCHEDULER_Task cont, void *cont_cls) +{ + uint64_t size; + + GNUNET_assert (daemon->download_cont == NULL); + size = GNUNET_FS_uri_chk_get_file_size (uri); + daemon->verbose = verbose; + daemon->download_cont = cont; + daemon->download_cont_cls = cont_cls; + daemon->download_seed = seed; + daemon->download_context = + GNUNET_FS_download_start (daemon->fs, uri, NULL, NULL, NULL, 0, size, + anonymity, GNUNET_FS_DOWNLOAD_OPTION_NONE, NULL, + NULL); + daemon->download_timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, &download_timeout, daemon); +} + +/* end of test_fs_lib.c */ diff --git a/src/fs/fs_test_lib.h b/src/fs/fs_test_lib.h new file mode 100644 index 0000000..81125ca --- /dev/null +++ b/src/fs/fs_test_lib.h @@ -0,0 +1,183 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_test_lib.h + * @brief library routines for testing FS publishing and downloading + * with multiple peers; this code is limited to flat files + * and no keywords (those functions can be tested with + * single-peer setups; this is for testing routing). + * @author Christian Grothoff + */ +#ifndef FS_TEST_LIB_H +#define FS_TEST_LIB_H + +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" + +/** + * Handle for a daemon started for testing FS. + */ +struct GNUNET_FS_TestDaemon; + + +/** + * Start daemons for testing. + * + * @param template_cfg_file configuration template to use + * @param timeout if this operation cannot be completed within the + * given period, call the continuation with an error code + * @param total number of daemons to start + * @param daemons array of 'total' entries to be initialized + * (array must already be allocated, will be filled) + * @param cont function to call when done; note that if 'cont' + * is called with reason "TIMEOUT", then starting the + * daemons has failed and the client MUST NOT call + * 'GNUNET_FS_TEST_daemons_stop'! + * @param cont_cls closure for cont + */ +void +GNUNET_FS_TEST_daemons_start (const char *template_cfg_file, + struct GNUNET_TIME_Relative timeout, + unsigned int total, + struct GNUNET_FS_TestDaemon **daemons, + GNUNET_SCHEDULER_Task cont, void *cont_cls); + + +struct GNUNET_FS_TEST_ConnectContext; + + +/** + * Connect two daemons for testing. + * + * @param daemon1 first daemon to connect + * @param daemon2 second first daemon to connect + * @param timeout if this operation cannot be completed within the + * given period, call the continuation with an error code + * @param cont function to call when done + * @param cont_cls closure for cont + */ +struct GNUNET_FS_TEST_ConnectContext * +GNUNET_FS_TEST_daemons_connect (struct GNUNET_FS_TestDaemon *daemon1, + struct GNUNET_FS_TestDaemon *daemon2, + struct GNUNET_TIME_Relative timeout, + GNUNET_SCHEDULER_Task cont, void *cont_cls); + + +/** + * Cancel connect operation. + * + * @param cc operation to cancel + */ +void +GNUNET_FS_TEST_daemons_connect_cancel (struct GNUNET_FS_TEST_ConnectContext + *cc); + + +/** + * Obtain peer group used for testing. + * + * @param daemons array with the daemons (must contain at least one) + * @return peer group + */ +struct GNUNET_TESTING_PeerGroup * +GNUNET_FS_TEST_get_group (struct GNUNET_FS_TestDaemon **daemons); + + + +/** + * Obtain peer configuration used for testing. + * + * @param daemons array with the daemons + * @param off which configuration to get + * @return peer configuration + */ +const struct GNUNET_CONFIGURATION_Handle * +GNUNET_FS_TEST_get_configuration (struct GNUNET_FS_TestDaemon **daemons, + unsigned int off); + +/** + * Stop daemons used for testing. + * + * @param total number of daemons to stop + * @param daemons array with the daemons (values will be clobbered) + */ +void +GNUNET_FS_TEST_daemons_stop (unsigned int total, + struct GNUNET_FS_TestDaemon **daemons); + + +/** + * Function signature. + * + * @param cls closure (user defined) + * @param uri a URI, NULL for errors + */ +typedef void (*GNUNET_FS_TEST_UriContinuation) (void *cls, + const struct GNUNET_FS_Uri * + uri); + + +/** + * Publish a file at the given daemon. + * + * @param daemon where to publish + * @param timeout if this operation cannot be completed within the + * given period, call the continuation with an error code + * @param anonymity option for publication + * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, + * GNUNET_SYSERR for simulation + * @param size size of the file to publish + * @param seed seed to use for file generation + * @param verbose how verbose to be in reporting + * @param cont function to call when done + * @param cont_cls closure for cont + */ +void +GNUNET_FS_TEST_publish (struct GNUNET_FS_TestDaemon *daemon, + struct GNUNET_TIME_Relative timeout, uint32_t anonymity, + int do_index, uint64_t size, uint32_t seed, + unsigned int verbose, + GNUNET_FS_TEST_UriContinuation cont, void *cont_cls); + + +/** + * Perform test download. + * + * @param daemon which peer to download from + * @param timeout if this operation cannot be completed within the + * given period, call the continuation with an error code + * @param anonymity option for download + * @param seed used for file validation + * @param uri URI of file to download (CHK/LOC only) + * @param verbose how verbose to be in reporting + * @param cont function to call when done + * @param cont_cls closure for cont + */ +void +GNUNET_FS_TEST_download (struct GNUNET_FS_TestDaemon *daemon, + struct GNUNET_TIME_Relative timeout, + uint32_t anonymity, uint32_t seed, + const struct GNUNET_FS_Uri *uri, unsigned int verbose, + GNUNET_SCHEDULER_Task cont, void *cont_cls); + + + +#endif diff --git a/src/fs/fs_test_lib_data.conf b/src/fs/fs_test_lib_data.conf new file mode 100644 index 0000000..e6c2abd --- /dev/null +++ b/src/fs/fs_test_lib_data.conf @@ -0,0 +1,11 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-fs-test-lib/ + +[ats] +WAN_QUOTA_IN = 3932160 +WAN_QUOTA_OUT = 3932160 + +[datastore] +QUOTA = 2 GB + diff --git a/src/fs/fs_tree.c b/src/fs/fs_tree.c new file mode 100644 index 0000000..b3bbdc7 --- /dev/null +++ b/src/fs/fs_tree.c @@ -0,0 +1,441 @@ +/* + This file is part of GNUnet. + (C) 2009-2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/fs_tree.c + * @brief Merkle-tree-ish-CHK file encoding for GNUnet + * @see http://gnunet.org/encoding.php3 + * @author Krista Bennett + * @author Christian Grothoff + */ +#include "platform.h" +#include "fs_tree.h" + + +/** + * Context for an ECRS-based file encoder that computes + * the Merkle-ish-CHK tree. + */ +struct GNUNET_FS_TreeEncoder +{ + + /** + * Global FS context. + */ + struct GNUNET_FS_Handle *h; + + /** + * Closure for all callbacks. + */ + void *cls; + + /** + * Function to call on encrypted blocks. + */ + GNUNET_FS_TreeBlockProcessor proc; + + /** + * Function to call with progress information. + */ + GNUNET_FS_TreeProgressCallback progress; + + /** + * Function to call to receive input data. + */ + GNUNET_FS_DataReader reader; + + /** + * Function to call once we're done with processing. + */ + GNUNET_SCHEDULER_Task cont; + + /** + * Set to an error message (if we had an error). + */ + char *emsg; + + /** + * Set to the URI (upon successful completion) + */ + struct GNUNET_FS_Uri *uri; + + /** + * Overall file size. + */ + uint64_t size; + + /** + * How far are we? + */ + uint64_t publish_offset; + + /** + * How deep are we? Depth 0 is for the DBLOCKs. + */ + unsigned int current_depth; + + /** + * How deep is the tree? Always > 0. + */ + unsigned int chk_tree_depth; + + /** + * In-memory cache of the current CHK tree. + * This struct will contain the CHK values + * from the root to the currently processed + * node in the tree as identified by + * "current_depth" and "publish_offset". + * The "chktree" will be initially NULL, + * then allocated to a sufficient number of + * entries for the size of the file and + * finally freed once the upload is complete. + */ + struct ContentHashKey *chk_tree; + + /** + * Are we currently in 'GNUNET_FS_tree_encoder_next'? + * Flag used to prevent recursion. + */ + int in_next; +}; + + +/** + * Compute the depth of the CHK tree. + * + * @param flen file length for which to compute the depth + * @return depth of the tree, always > 0. A depth of 1 means only a DBLOCK. + */ +unsigned int +GNUNET_FS_compute_depth (uint64_t flen) +{ + unsigned int treeDepth; + uint64_t fl; + + treeDepth = 1; + fl = DBLOCK_SIZE; + while (fl < flen) + { + treeDepth++; + if (fl * CHK_PER_INODE < fl) + { + /* integer overflow, this is a HUGE file... */ + return treeDepth; + } + fl = fl * CHK_PER_INODE; + } + return treeDepth; +} + + +/** + * Calculate how many bytes of payload a block tree of the given + * depth MAY correspond to at most (this function ignores the fact that + * some blocks will only be present partially due to the total file + * size cutting some blocks off at the end). + * + * @param depth depth of the block. depth==0 is a DBLOCK. + * @return number of bytes of payload a subtree of this depth may correspond to + */ +uint64_t +GNUNET_FS_tree_compute_tree_size (unsigned int depth) +{ + uint64_t rsize; + unsigned int i; + + rsize = DBLOCK_SIZE; + for (i = 0; i < depth; i++) + rsize *= CHK_PER_INODE; + return rsize; +} + + +/** + * Compute the size of the current IBLOCK. The encoder is + * triggering the calculation of the size of an IBLOCK at the + * *end* (hence end_offset) of its construction. The IBLOCK + * maybe a full or a partial IBLOCK, and this function is to + * calculate how long it should be. + * + * @param depth depth of the IBlock in the tree, 0 would be a DBLOCK, + * must be > 0 (this function is for IBLOCKs only!) + * @param end_offset current offset in the payload (!) of the overall file, + * must be > 0 (since this function is called at the + * end of a block). + * @return size of the corresponding IBlock + */ +static uint16_t +GNUNET_FS_tree_compute_iblock_size (unsigned int depth, uint64_t end_offset) +{ + unsigned int ret; + uint64_t mod; + uint64_t bds; + + GNUNET_assert (depth > 0); + GNUNET_assert (end_offset > 0); + bds = GNUNET_FS_tree_compute_tree_size (depth); + mod = end_offset % bds; + if (0 == mod) + { + /* we were triggered at the end of a full block */ + ret = CHK_PER_INODE; + } + else + { + /* we were triggered at the end of the file */ + bds /= CHK_PER_INODE; + ret = mod / bds; + if (0 != mod % bds) + ret++; + } + return (uint16_t) (ret * sizeof (struct ContentHashKey)); +} + + +/** + * Compute how many bytes of data should be stored in + * the specified block. + * + * @param fsize overall file size, must be > 0. + * @param offset offset in the original data corresponding + * to the beginning of the tree induced by the block; + * must be <= fsize + * @param depth depth of the node in the tree, 0 for DBLOCK + * @return number of bytes stored in this node + */ +size_t +GNUNET_FS_tree_calculate_block_size (uint64_t fsize, uint64_t offset, + unsigned int depth) +{ + size_t ret; + uint64_t rsize; + uint64_t epos; + unsigned int chks; + + GNUNET_assert (fsize > 0); + GNUNET_assert (offset <= fsize); + if (depth == 0) + { + ret = DBLOCK_SIZE; + if ((offset + ret > fsize) || (offset + ret < offset)) + ret = (size_t) (fsize - offset); + return ret; + } + + rsize = GNUNET_FS_tree_compute_tree_size (depth - 1); + epos = offset + rsize * CHK_PER_INODE; + if ((epos < offset) || (epos > fsize)) + epos = fsize; + /* round up when computing #CHKs in our IBlock */ + chks = (epos - offset + rsize - 1) / rsize; + GNUNET_assert (chks <= CHK_PER_INODE); + return chks * sizeof (struct ContentHashKey); +} + + +/** + * Initialize a tree encoder. This function will call "proc" and + * "progress" on each block in the tree. Once all blocks have been + * processed, "cont" will be scheduled. The "reader" will be called + * to obtain the (plaintext) blocks for the file. Note that this + * function will not actually call "proc". The client must + * call "GNUNET_FS_tree_encoder_next" to trigger encryption (and + * calling of "proc") for the each block. + * + * @param h the global FS context + * @param size overall size of the file to encode + * @param cls closure for reader, proc, progress and cont + * @param reader function to call to read plaintext data + * @param proc function to call on each encrypted block + * @param progress function to call with progress information + * @param cont function to call when done + */ +struct GNUNET_FS_TreeEncoder * +GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, uint64_t size, + void *cls, GNUNET_FS_DataReader reader, + GNUNET_FS_TreeBlockProcessor proc, + GNUNET_FS_TreeProgressCallback progress, + GNUNET_SCHEDULER_Task cont) +{ + struct GNUNET_FS_TreeEncoder *te; + + te = GNUNET_malloc (sizeof (struct GNUNET_FS_TreeEncoder)); + te->h = h; + te->size = size; + te->cls = cls; + te->reader = reader; + te->proc = proc; + te->progress = progress; + te->cont = cont; + te->chk_tree_depth = GNUNET_FS_compute_depth (size); + te->chk_tree = + GNUNET_malloc (te->chk_tree_depth * CHK_PER_INODE * + sizeof (struct ContentHashKey)); + return te; +} + + +/** + * Compute the offset of the CHK for the + * current block in the IBlock above. + * + * @param depth depth of the IBlock in the tree (aka overall + * number of tree levels minus depth); 0 == DBlock + * @param end_offset current offset in the overall file, + * at the *beginning* of the block for DBLOCKs (depth==0), + * otherwise at the *end* of the block (exclusive) + * @return (array of CHKs') offset in the above IBlock + */ +static unsigned int +compute_chk_offset (unsigned int depth, uint64_t end_offset) +{ + uint64_t bds; + unsigned int ret; + + bds = GNUNET_FS_tree_compute_tree_size (depth); + if (depth > 0) + end_offset--; /* round down since for depth > 0 offset is at the END of the block */ + ret = end_offset / bds; + return ret % CHK_PER_INODE; +} + + +/** + * Encrypt the next block of the file (and call proc and progress + * accordingly; or of course "cont" if we have already completed + * encoding of the entire file). + * + * @param te tree encoder to use + */ +void +GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder *te) +{ + struct ContentHashKey *mychk; + const void *pt_block; + uint16_t pt_size; + char iob[DBLOCK_SIZE]; + char enc[DBLOCK_SIZE]; + struct GNUNET_CRYPTO_AesSessionKey sk; + struct GNUNET_CRYPTO_AesInitializationVector iv; + unsigned int off; + + GNUNET_assert (GNUNET_NO == te->in_next); + te->in_next = GNUNET_YES; + if (te->chk_tree_depth == te->current_depth) + { + off = CHK_PER_INODE * (te->chk_tree_depth - 1); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TE done, reading CHK `%s' from %u\n", + GNUNET_h2s (&te->chk_tree[off].query), off); + te->uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + te->uri->type = chk; + te->uri->data.chk.chk = te->chk_tree[off]; + te->uri->data.chk.file_length = GNUNET_htonll (te->size); + te->in_next = GNUNET_NO; + te->cont (te->cls, NULL); + return; + } + if (0 == te->current_depth) + { + /* read DBLOCK */ + pt_size = GNUNET_MIN (DBLOCK_SIZE, te->size - te->publish_offset); + if (pt_size != + te->reader (te->cls, te->publish_offset, pt_size, iob, &te->emsg)) + { + te->cont (te->cls, NULL); + te->in_next = GNUNET_NO; + return; + } + pt_block = iob; + } + else + { + pt_size = + GNUNET_FS_tree_compute_iblock_size (te->current_depth, + te->publish_offset); + pt_block = &te->chk_tree[(te->current_depth - 1) * CHK_PER_INODE]; + } + off = compute_chk_offset (te->current_depth, te->publish_offset); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "TE is at offset %llu and depth %u with block size %u and target-CHK-offset %u\n", + (unsigned long long) te->publish_offset, te->current_depth, + (unsigned int) pt_size, (unsigned int) off); + mychk = &te->chk_tree[te->current_depth * CHK_PER_INODE + off]; + GNUNET_CRYPTO_hash (pt_block, pt_size, &mychk->key); + GNUNET_CRYPTO_hash_to_aes_key (&mychk->key, &sk, &iv); + GNUNET_CRYPTO_aes_encrypt (pt_block, pt_size, &sk, &iv, enc); + GNUNET_CRYPTO_hash (enc, pt_size, &mychk->query); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "TE calculates query to be `%s', stored at %u\n", + GNUNET_h2s (&mychk->query), + te->current_depth * CHK_PER_INODE + off); + if (NULL != te->proc) + te->proc (te->cls, mychk, te->publish_offset, te->current_depth, + (0 == + te->current_depth) ? GNUNET_BLOCK_TYPE_FS_DBLOCK : + GNUNET_BLOCK_TYPE_FS_IBLOCK, enc, pt_size); + if (NULL != te->progress) + te->progress (te->cls, te->publish_offset, pt_block, pt_size, + te->current_depth); + if (0 == te->current_depth) + { + te->publish_offset += pt_size; + if ((te->publish_offset == te->size) || + (0 == te->publish_offset % (CHK_PER_INODE * DBLOCK_SIZE))) + te->current_depth++; + } + else + { + if ((off == CHK_PER_INODE) || (te->publish_offset == te->size)) + te->current_depth++; + else + te->current_depth = 0; + } + te->in_next = GNUNET_NO; +} + + +/** + * Clean up a tree encoder and return information + * about the resulting URI or an error message. + * + * @param te the tree encoder to clean up + * @param uri set to the resulting URI (if encoding finished) + * @param emsg set to an error message (if an error occured + * within the tree encoder; if this function is called + * prior to completion and prior to an internal error, + * both "*uri" and "*emsg" will be set to NULL). + */ +void +GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder *te, + struct GNUNET_FS_Uri **uri, char **emsg) +{ + GNUNET_assert (GNUNET_NO == te->in_next); + if (uri != NULL) + *uri = te->uri; + else if (NULL != te->uri) + GNUNET_FS_uri_destroy (te->uri); + if (emsg != NULL) + *emsg = te->emsg; + else + GNUNET_free_non_null (te->emsg); + GNUNET_free (te->chk_tree); + GNUNET_free (te); +} + +/* end of fs_tree.c */ diff --git a/src/fs/fs_tree.h b/src/fs/fs_tree.h new file mode 100644 index 0000000..5b1c202 --- /dev/null +++ b/src/fs/fs_tree.h @@ -0,0 +1,207 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_tree.h + * @brief Merkle-tree-ish-CHK file encoding for GNUnet + * @see https://gnunet.org/encoding + * @author Krista Bennett + * @author Christian Grothoff + * + * TODO: + * - decide if this API should be made public (gnunet_fs_service.h) + * or remain "internal" (but with exported symbols?) + */ +#ifndef GNUNET_FS_TREE_H +#define GNUNET_FS_TREE_H + +#include "fs_api.h" + +/** + * Compute the depth of the CHK tree. + * + * @param flen file length for which to compute the depth + * @return depth of the tree, always > 0. A depth of 1 means only a DBLOCK. + */ +unsigned int +GNUNET_FS_compute_depth (uint64_t flen); + + +/** + * Calculate how many bytes of payload a block tree of the given + * depth MAY correspond to at most (this function ignores the fact that + * some blocks will only be present partially due to the total file + * size cutting some blocks off at the end). + * + * @param depth depth of the block. depth==0 is a DBLOCK. + * @return number of bytes of payload a subtree of this depth may correspond to + */ +uint64_t +GNUNET_FS_tree_compute_tree_size (unsigned int depth); + + +/** + * Compute how many bytes of data should be stored in + * the specified block. + * + * @param fsize overall file size, must be > 0. + * @param offset offset in the original data corresponding + * to the beginning of the tree induced by the block; + * must be < fsize + * @param depth depth of the node in the tree, 0 for DBLOCK + * @return number of bytes stored in this node + */ +size_t +GNUNET_FS_tree_calculate_block_size (uint64_t fsize, uint64_t offset, + unsigned int depth); + + +/** + * Context for an ECRS-based file encoder that computes + * the Merkle-ish-CHK tree. + */ +struct GNUNET_FS_TreeEncoder; + + +/** + * Function called asking for the current (encoded) + * block to be processed. After processing the + * client should either call "GNUNET_FS_tree_encode_next" + * or (on error) "GNUNET_FS_tree_encode_finish". + * + * @param cls closure + * @param chk content hash key for the block + * @param offset offset of the block + * @param depth depth of the block, 0 for DBLOCKs + * @param type type of the block (IBLOCK or DBLOCK) + * @param block the (encrypted) block + * @param block_size size of block (in bytes) + */ +typedef void (*GNUNET_FS_TreeBlockProcessor) (void *cls, + const struct ContentHashKey * chk, + uint64_t offset, + unsigned int depth, + enum GNUNET_BLOCK_Type type, + const void *block, + uint16_t block_size); + + +/** + * Function called with information about our + * progress in computing the tree encoding. + * + * @param cls closure + * @param offset where are we in the file + * @param pt_block plaintext of the currently processed block + * @param pt_size size of pt_block + * @param depth depth of the block in the tree, 0 for DBLOCKS + */ +typedef void (*GNUNET_FS_TreeProgressCallback) (void *cls, uint64_t offset, + const void *pt_block, + size_t pt_size, + unsigned int depth); + + +/** + * Initialize a tree encoder. This function will call "proc" and + * "progress" on each block in the tree. Once all blocks have been + * processed, "cont" will be scheduled. The "reader" will be called + * to obtain the (plaintext) blocks for the file. Note that this + * function will actually never call "proc"; the "proc" function must + * be triggered by calling "GNUNET_FS_tree_encoder_next" to trigger + * encryption (and calling of "proc") for each block. + * + * @param h the global FS context + * @param size overall size of the file to encode + * @param cls closure for reader, proc, progress and cont + * @param reader function to call to read plaintext data + * @param proc function to call on each encrypted block + * @param progress function to call with progress information + * @param cont function to call when done + * @return tree encoder context + */ +struct GNUNET_FS_TreeEncoder * +GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, uint64_t size, + void *cls, GNUNET_FS_DataReader reader, + GNUNET_FS_TreeBlockProcessor proc, + GNUNET_FS_TreeProgressCallback progress, + GNUNET_SCHEDULER_Task cont); + + +/** + * Encrypt the next block of the file (and + * call proc and progress accordingly; or + * of course "cont" if we have already completed + * encoding of the entire file). + * + * @param te tree encoder to use + */ +void +GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder *te); + + +/** + * Clean up a tree encoder and return information + * about the resulting URI or an error message. + * + * @param te the tree encoder to clean up + * @param uri set to the resulting URI (if encoding finished) + * @param emsg set to an error message (if an error occured + * within the tree encoder; if this function is called + * prior to completion and prior to an internal error, + * both "*uri" and "*emsg" will be set to NULL). + */ +void +GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder *te, + struct GNUNET_FS_Uri **uri, char **emsg); + + +#if 0 +/* the functions below will be needed for persistence + but are not yet implemented -- FIXME... */ +/** + * Get data that would be needed to resume + * the encoding later. + * + * @param te encoding to resume + * @param data set to the resume data + * @param size set to the size of the resume data + */ +void +GNUNET_FS_tree_encoder_resume_get_data (const struct GNUNET_FS_TreeEncoder *te, + void **data, size_t * size); + + +/** + * Reset tree encoder to point previously + * obtained for resuming. + * + * @param te encoding to resume + * @param data the resume data + * @param size the size of the resume data + */ +void +GNUNET_FS_tree_encoder_resume (struct GNUNET_FS_TreeEncoder *te, + const void *data, size_t size); +#endif + +#endif + +/* end of fs_tree.h */ diff --git a/src/fs/fs_unindex.c b/src/fs/fs_unindex.c new file mode 100644 index 0000000..ff1996a --- /dev/null +++ b/src/fs/fs_unindex.c @@ -0,0 +1,524 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_unindex.c + * @author Krista Grothoff + * @author Christian Grothoff + * @brief Unindex file. + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_fs_service.h" +#include "gnunet_protocols.h" +#include "fs_api.h" +#include "fs_tree.h" + + +/** + * Function called by the tree encoder to obtain + * a block of plaintext data (for the lowest level + * of the tree). + * + * @param cls our publishing context + * @param offset identifies which block to get + * @param max (maximum) number of bytes to get; returning + * fewer will also cause errors + * @param buf where to copy the plaintext buffer + * @param emsg location to store an error message (on error) + * @return number of bytes copied to buf, 0 on error + */ +static size_t +unindex_reader (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) +{ + struct GNUNET_FS_UnindexContext *uc = cls; + size_t pt_size; + + pt_size = GNUNET_MIN (max, uc->file_size - offset); + if (offset != GNUNET_DISK_file_seek (uc->fh, offset, GNUNET_DISK_SEEK_SET)) + { + *emsg = GNUNET_strdup (_("Failed to find given position in file")); + return 0; + } + if (pt_size != GNUNET_DISK_file_read (uc->fh, buf, pt_size)) + { + *emsg = GNUNET_strdup (_("Failed to read file")); + return 0; + } + return pt_size; +} + + +/** + * Fill in all of the generic fields for + * an unindex event and call the callback. + * + * @param pi structure to fill in + * @param uc overall unindex context + * @param offset where we are in the file (for progress) + */ +void +GNUNET_FS_unindex_make_status_ (struct GNUNET_FS_ProgressInfo *pi, + struct GNUNET_FS_UnindexContext *uc, + uint64_t offset) +{ + pi->value.unindex.uc = uc; + pi->value.unindex.cctx = uc->client_info; + pi->value.unindex.filename = uc->filename; + pi->value.unindex.size = uc->file_size; + pi->value.unindex.eta = + GNUNET_TIME_calculate_eta (uc->start_time, offset, uc->file_size); + pi->value.unindex.duration = + GNUNET_TIME_absolute_get_duration (uc->start_time); + pi->value.unindex.completed = offset; + uc->client_info = uc->h->upcb (uc->h->upcb_cls, pi); + +} + + +/** + * Function called with information about our + * progress in computing the tree encoding. + * + * @param cls closure + * @param offset where are we in the file + * @param pt_block plaintext of the currently processed block + * @param pt_size size of pt_block + * @param depth depth of the block in the tree, 0 for DBLOCK + */ +static void +unindex_progress (void *cls, uint64_t offset, const void *pt_block, + size_t pt_size, unsigned int depth) +{ + struct GNUNET_FS_UnindexContext *uc = cls; + struct GNUNET_FS_ProgressInfo pi; + + pi.status = GNUNET_FS_STATUS_UNINDEX_PROGRESS; + pi.value.unindex.specifics.progress.data = pt_block; + pi.value.unindex.specifics.progress.offset = offset; + pi.value.unindex.specifics.progress.data_len = pt_size; + pi.value.unindex.specifics.progress.depth = depth; + GNUNET_FS_unindex_make_status_ (&pi, uc, offset); +} + + +/** + * We've encountered an error during + * unindexing. Signal the client. + * + * @param uc context for the failed unindexing operation + */ +static void +signal_unindex_error (struct GNUNET_FS_UnindexContext *uc) +{ + struct GNUNET_FS_ProgressInfo pi; + + pi.status = GNUNET_FS_STATUS_UNINDEX_ERROR; + pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL; + pi.value.unindex.specifics.error.message = uc->emsg; + GNUNET_FS_unindex_make_status_ (&pi, uc, 0); +} + + +/** + * Continuation called to notify client about result of the + * datastore removal operation. + * + * @param cls closure + * @param success GNUNET_SYSERR on failure + * @param min_expiration minimum expiration time required for content to be stored + * @param msg NULL on success, otherwise an error message + */ +static void +process_cont (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) +{ + struct GNUNET_FS_UnindexContext *uc = cls; + + if (success == GNUNET_SYSERR) + { + uc->emsg = GNUNET_strdup (msg); + signal_unindex_error (uc); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Datastore REMOVE operation succeeded\n"); + GNUNET_FS_tree_encoder_next (uc->tc); +} + + +/** + * Function called asking for the current (encoded) + * block to be processed. After processing the + * client should either call "GNUNET_FS_tree_encode_next" + * or (on error) "GNUNET_FS_tree_encode_finish". + * + * @param cls closure + * @param chk content hash key for the block (key for lookup in the datastore) + * @param offset offset of the block + * @param depth depth of the block, 0 for DBLOCK + * @param type type of the block (IBLOCK or DBLOCK) + * @param block the (encrypted) block + * @param block_size size of block (in bytes) + */ +static void +unindex_process (void *cls, const struct ContentHashKey *chk, uint64_t offset, + unsigned int depth, enum GNUNET_BLOCK_Type type, + const void *block, uint16_t block_size) +{ + struct GNUNET_FS_UnindexContext *uc = cls; + uint32_t size; + const void *data; + struct OnDemandBlock odb; + + if (type != GNUNET_BLOCK_TYPE_FS_DBLOCK) + { + size = block_size; + data = block; + } + else /* on-demand encoded DBLOCK */ + { + size = sizeof (struct OnDemandBlock); + odb.offset = GNUNET_htonll (offset); + odb.file_id = uc->file_id; + data = &odb; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending REMOVE request to DATASTORE service\n"); + GNUNET_DATASTORE_remove (uc->dsh, &chk->query, size, data, -2, 1, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, &process_cont, uc); +} + + +/** + * Function called with the response from the + * FS service to our unindexing request. + * + * @param cls closure, unindex context + * @param msg NULL on timeout, otherwise the response + */ +static void +process_fs_response (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_FS_UnindexContext *uc = cls; + struct GNUNET_FS_ProgressInfo pi; + + if (uc->client != NULL) + { + GNUNET_CLIENT_disconnect (uc->client, GNUNET_NO); + uc->client = NULL; + } + if (uc->state != UNINDEX_STATE_FS_NOTIFY) + { + uc->state = UNINDEX_STATE_ERROR; + uc->emsg = + GNUNET_strdup (_("Unexpected time for a response from `fs' service.")); + GNUNET_FS_unindex_sync_ (uc); + signal_unindex_error (uc); + return; + } + if (NULL == msg) + { + uc->state = UNINDEX_STATE_ERROR; + uc->emsg = GNUNET_strdup (_("Timeout waiting for `fs' service.")); + GNUNET_FS_unindex_sync_ (uc); + signal_unindex_error (uc); + return; + } + if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK) + { + uc->state = UNINDEX_STATE_ERROR; + uc->emsg = GNUNET_strdup (_("Invalid response from `fs' service.")); + GNUNET_FS_unindex_sync_ (uc); + signal_unindex_error (uc); + return; + } + uc->state = UNINDEX_STATE_COMPLETE; + pi.status = GNUNET_FS_STATUS_UNINDEX_COMPLETED; + pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO; + GNUNET_FS_unindex_sync_ (uc); + GNUNET_FS_unindex_make_status_ (&pi, uc, uc->file_size); +} + + +/** + * Function called when the tree encoder has + * processed all blocks. Clean up. + * + * @param cls our unindexing context + * @param tc not used + */ +static void +unindex_finish (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_UnindexContext *uc = cls; + char *emsg; + struct GNUNET_FS_Uri *uri; + struct UnindexMessage req; + + /* generate final progress message */ + unindex_progress (uc, uc->file_size, NULL, 0, 0); + GNUNET_FS_tree_encoder_finish (uc->tc, &uri, &emsg); + uc->tc = NULL; + if (uri != NULL) + GNUNET_FS_uri_destroy (uri); + GNUNET_DISK_file_close (uc->fh); + uc->fh = NULL; + GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); + uc->dsh = NULL; + uc->state = UNINDEX_STATE_FS_NOTIFY; + GNUNET_FS_unindex_sync_ (uc); + uc->client = GNUNET_CLIENT_connect ("fs", uc->h->cfg); + if (uc->client == NULL) + { + uc->state = UNINDEX_STATE_ERROR; + uc->emsg = + GNUNET_strdup (_("Failed to connect to FS service for unindexing.")); + GNUNET_FS_unindex_sync_ (uc); + signal_unindex_error (uc); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending UNINDEX message to FS service\n"); + req.header.size = htons (sizeof (struct UnindexMessage)); + req.header.type = htons (GNUNET_MESSAGE_TYPE_FS_UNINDEX); + req.reserved = 0; + req.file_id = uc->file_id; + GNUNET_break (GNUNET_OK == + GNUNET_CLIENT_transmit_and_get_response (uc->client, + &req.header, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + GNUNET_YES, + &process_fs_response, + uc)); +} + + +/** + * Connect to the datastore and remove the blocks. + * + * @param uc context for the unindex operation. + */ +void +GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc) +{ + uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg); + if (NULL == uc->dsh) + { + uc->state = UNINDEX_STATE_ERROR; + uc->emsg = GNUNET_strdup (_("Failed to connect to `datastore' service.")); + GNUNET_FS_unindex_sync_ (uc); + signal_unindex_error (uc); + return; + } + uc->fh = + GNUNET_DISK_file_open (uc->filename, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == uc->fh) + { + GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); + uc->dsh = NULL; + uc->state = UNINDEX_STATE_ERROR; + uc->emsg = GNUNET_strdup (_("Failed to open file for unindexing.")); + GNUNET_FS_unindex_sync_ (uc); + signal_unindex_error (uc); + return; + } + uc->tc = + GNUNET_FS_tree_encoder_create (uc->h, uc->file_size, uc, &unindex_reader, + &unindex_process, &unindex_progress, + &unindex_finish); + GNUNET_FS_tree_encoder_next (uc->tc); +} + + +/** + * Function called once the hash of the file + * that is being unindexed has been computed. + * + * @param cls closure, unindex context + * @param file_id computed hash, NULL on error + */ +void +GNUNET_FS_unindex_process_hash_ (void *cls, const GNUNET_HashCode * file_id) +{ + struct GNUNET_FS_UnindexContext *uc = cls; + + uc->fhc = NULL; + if (uc->state != UNINDEX_STATE_HASHING) + { + GNUNET_FS_unindex_stop (uc); + return; + } + if (file_id == NULL) + { + uc->state = UNINDEX_STATE_ERROR; + uc->emsg = GNUNET_strdup (_("Failed to compute hash of file.")); + GNUNET_FS_unindex_sync_ (uc); + signal_unindex_error (uc); + return; + } + uc->file_id = *file_id; + uc->state = UNINDEX_STATE_DS_REMOVE; + GNUNET_FS_unindex_sync_ (uc); + GNUNET_FS_unindex_do_remove_ (uc); +} + + +/** + * Create SUSPEND event for the given unindex operation + * and then clean up our state (without stop signal). + * + * @param cls the 'struct GNUNET_FS_UnindexContext' to signal for + */ +void +GNUNET_FS_unindex_signal_suspend_ (void *cls) +{ + struct GNUNET_FS_UnindexContext *uc = cls; + struct GNUNET_FS_ProgressInfo pi; + + if (uc->fhc != NULL) + { + GNUNET_CRYPTO_hash_file_cancel (uc->fhc); + uc->fhc = NULL; + } + if (uc->client != NULL) + { + GNUNET_CLIENT_disconnect (uc->client, GNUNET_NO); + uc->client = NULL; + } + if (NULL != uc->dsh) + { + GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); + uc->dsh = NULL; + } + if (NULL != uc->tc) + { + GNUNET_FS_tree_encoder_finish (uc->tc, NULL, NULL); + uc->tc = NULL; + } + if (uc->fh != NULL) + { + GNUNET_DISK_file_close (uc->fh); + uc->fh = NULL; + } + GNUNET_FS_end_top (uc->h, uc->top); + pi.status = GNUNET_FS_STATUS_UNINDEX_SUSPEND; + GNUNET_FS_unindex_make_status_ (&pi, uc, + (uc->state == + UNINDEX_STATE_COMPLETE) ? uc->file_size : 0); + GNUNET_break (NULL == uc->client_info); + GNUNET_free (uc->filename); + GNUNET_free_non_null (uc->serialization); + GNUNET_free_non_null (uc->emsg); + GNUNET_free (uc); +} + + +/** + * Unindex a file. + * + * @param h handle to the file sharing subsystem + * @param filename file to unindex + * @param cctx initial value for the client context + * @return NULL on error, otherwise handle + */ +struct GNUNET_FS_UnindexContext * +GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h, const char *filename, + void *cctx) +{ + struct GNUNET_FS_UnindexContext *ret; + struct GNUNET_FS_ProgressInfo pi; + uint64_t size; + + if (GNUNET_OK != GNUNET_DISK_file_size (filename, &size, GNUNET_YES)) + return NULL; + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_UnindexContext)); + ret->h = h; + ret->filename = GNUNET_strdup (filename); + ret->start_time = GNUNET_TIME_absolute_get (); + ret->file_size = size; + ret->client_info = cctx; + GNUNET_FS_unindex_sync_ (ret); + pi.status = GNUNET_FS_STATUS_UNINDEX_START; + pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_FS_unindex_make_status_ (&pi, ret, 0); + ret->fhc = + GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, filename, + HASHING_BLOCKSIZE, + &GNUNET_FS_unindex_process_hash_, ret); + ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_unindex_signal_suspend_, ret); + return ret; +} + + +/** + * Clean up after completion of an unindex operation. + * + * @param uc handle + */ +void +GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc) +{ + struct GNUNET_FS_ProgressInfo pi; + + if (uc->fhc != NULL) + { + GNUNET_CRYPTO_hash_file_cancel (uc->fhc); + uc->fhc = NULL; + } + if (uc->client != NULL) + { + GNUNET_CLIENT_disconnect (uc->client, GNUNET_NO); + uc->client = NULL; + } + if (NULL != uc->dsh) + { + GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); + uc->dsh = NULL; + } + if (NULL != uc->tc) + { + GNUNET_FS_tree_encoder_finish (uc->tc, NULL, NULL); + uc->tc = NULL; + } + if (uc->fh != NULL) + { + GNUNET_DISK_file_close (uc->fh); + uc->fh = NULL; + } + GNUNET_FS_end_top (uc->h, uc->top); + if (uc->serialization != NULL) + { + GNUNET_FS_remove_sync_file_ (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, + uc->serialization); + GNUNET_free (uc->serialization); + uc->serialization = NULL; + } + pi.status = GNUNET_FS_STATUS_UNINDEX_STOPPED; + pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO; + GNUNET_FS_unindex_make_status_ (&pi, uc, + (uc->state == + UNINDEX_STATE_COMPLETE) ? uc->file_size : 0); + GNUNET_break (NULL == uc->client_info); + GNUNET_free (uc->filename); + GNUNET_free (uc); +} + +/* end of fs_unindex.c */ diff --git a/src/fs/fs_uri.c b/src/fs/fs_uri.c new file mode 100644 index 0000000..5dfdcb5 --- /dev/null +++ b/src/fs/fs_uri.c @@ -0,0 +1,2084 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_uri.c + * @brief Parses and produces uri strings. + * @author Igor Wronsky, Christian Grothoff + * + * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER". + * The specific structure of "IDENTIFIER" depends on the module and + * maybe differenciated into additional subcategories if applicable. + * This module only deals with fs identifiers (MODULE = "fs"). + *

+ * + * This module only parses URIs for the AFS module. The FS URIs fall + * into four categories, "chk", "sks", "ksk" and "loc". The first three + * categories were named in analogy (!) to Freenet, but they do NOT + * work in exactly the same way. They are very similar from the user's + * point of view (unique file identifier, subspace, keyword), but the + * implementation is rather different in pretty much every detail. + * The concrete URI formats are: + * + *

  • + * + * First, there are URIs that identify a file. They have the format + * "gnunet://fs/chk/HEX1.HEX2.SIZE". These URIs can be used to + * download the file. The description, filename, mime-type and other + * meta-data is NOT part of the file-URI since a URI uniquely + * identifies a resource (and the contents of the file would be the + * same even if it had a different description). + * + *
  • + * + * The second category identifies entries in a namespace. The format + * is "gnunet://fs/sks/NAMESPACE/IDENTIFIER" where the namespace + * should be given in HEX. Applications may allow using a nickname + * for the namespace if the nickname is not ambiguous. The identifier + * can be either an ASCII sequence or a HEX-encoding. If the + * identifier is in ASCII but the format is ambiguous and could denote + * a HEX-string a "/" is appended to indicate ASCII encoding. + * + *
  • + * + * The third category identifies ordinary searches. The format is + * "gnunet://fs/ksk/KEYWORD[+KEYWORD]*". Using the "+" syntax + * it is possible to encode searches with the boolean "AND" operator. + * "+" is used since it indicates a commutative 'and' operation and + * is unlikely to be used in a keyword by itself. + * + *
  • + * + * The last category identifies a datum on a specific machine. The + * format is "gnunet://fs/loc/HEX1.HEX2.SIZE.PEER.SIG.EXPTIME". PEER is + * the BinName of the public key of the peer storing the datum. The + * signature (SIG) certifies that this peer has this content. + * HEX1, HEX2 and SIZE correspond to a 'chk' URI. + * + *
+ * + * The encoding for hexadecimal values is defined in the hashing.c + * module in the gnunetutil library and discussed there. + *

+ */ +#include "platform.h" +#include "gnunet_fs_service.h" +#include "gnunet_signatures.h" +#include "fs_api.h" +#include +#include +#include +#include +#include + + + +/** + * Get a unique key from a URI. This is for putting URIs + * into HashMaps. The key may change between FS implementations. + * + * @param uri uri to convert to a unique key + * @param key wherer to store the unique key + */ +void +GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri, GNUNET_HashCode * key) +{ + switch (uri->type) + { + case chk: + *key = uri->data.chk.chk.query; + return; + case sks: + GNUNET_CRYPTO_hash (uri->data.sks.identifier, + strlen (uri->data.sks.identifier), key); + break; + case ksk: + if (uri->data.ksk.keywordCount > 0) + GNUNET_CRYPTO_hash (uri->data.ksk.keywords[0], + strlen (uri->data.ksk.keywords[0]), key); + break; + case loc: + GNUNET_CRYPTO_hash (&uri->data.loc.fi, + sizeof (struct FileIdentifier) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + key); + break; + default: + memset (key, 0, sizeof (GNUNET_HashCode)); + break; + } +} + + +/** + * Convert keyword URI to a human readable format + * (i.e. the search query that was used in the first place) + * + * @param uri ksk uri to convert to a string + * @return string with the keywords + */ +char * +GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri) +{ + size_t n; + char *ret; + unsigned int i; + const char *keyword; + char **keywords; + unsigned int keywordCount; + + if ((uri == NULL) || (uri->type != ksk)) + { + GNUNET_break (0); + return NULL; + } + keywords = uri->data.ksk.keywords; + keywordCount = uri->data.ksk.keywordCount; + n = keywordCount + 1; + for (i = 0; i < keywordCount; i++) + { + keyword = keywords[i]; + n += strlen (keyword) - 1; + if (NULL != strstr (&keyword[1], " ")) + n += 2; + if (keyword[0] == '+') + n++; + } + ret = GNUNET_malloc (n); + strcpy (ret, ""); + for (i = 0; i < keywordCount; i++) + { + keyword = keywords[i]; + if (NULL != strstr (&keyword[1], " ")) + { + strcat (ret, "\""); + if (keyword[0] == '+') + strcat (ret, keyword); + else + strcat (ret, &keyword[1]); + strcat (ret, "\""); + } + else + { + if (keyword[0] == '+') + strcat (ret, keyword); + else + strcat (ret, &keyword[1]); + } + strcat (ret, " "); + } + return ret; +} + + +/** + * Given a keyword with %-encoding (and possibly quotes to protect + * spaces), return a copy of the keyword without %-encoding and + * without double-quotes (%22). Also, add a space at the beginning + * if there is not a '+'. + * + * @param in string with %-encoding + * @param emsg where to store the parser error message (if any) + * @return decodded string with leading space (or preserved plus) + */ +static char * +percent_decode_keyword (const char *in, char **emsg) +{ + char *out; + char *ret; + unsigned int rpos; + unsigned int wpos; + unsigned int hx; + + out = GNUNET_strdup (in); + rpos = 0; + wpos = 0; + while (out[rpos] != '\0') + { + if (out[rpos] == '%') + { + if (1 != sscanf (&out[rpos + 1], "%2X", &hx)) + { + GNUNET_free (out); + *emsg = GNUNET_strdup (_("`%' must be followed by HEX number")); + return NULL; + } + rpos += 3; + if (hx == '"') + continue; /* skip double quote */ + out[wpos++] = (char) hx; + } + else + { + out[wpos++] = out[rpos++]; + } + } + out[wpos] = '\0'; + if (out[0] == '+') + { + ret = GNUNET_strdup (out); + } + else + { + /* need to prefix with space */ + ret = GNUNET_malloc (strlen (out) + 2); + strcpy (ret, " "); + strcat (ret, out); + } + GNUNET_free (out); + return ret; +} + +#define GNUNET_FS_URI_KSK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_KSK_INFIX + +/** + * Parse a KSK URI. + * + * @param s an uri string + * @param emsg where to store the parser error message (if any) + * @return NULL on error, otherwise the KSK URI + */ +static struct GNUNET_FS_Uri * +uri_ksk_parse (const char *s, char **emsg) +{ + struct GNUNET_FS_Uri *ret; + char **keywords; + unsigned int pos; + int max; + int iret; + int i; + size_t slen; + char *dup; + int saw_quote; + + GNUNET_assert (s != NULL); + slen = strlen (s); + pos = strlen (GNUNET_FS_URI_KSK_PREFIX); + if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_KSK_PREFIX, pos))) + return NULL; /* not KSK URI */ + if ((s[slen - 1] == '+') || (s[pos] == '+')) + { + *emsg = + GNUNET_strdup (_("Malformed KSK URI (must not begin or end with `+')")); + return NULL; + } + max = 1; + saw_quote = 0; + for (i = pos; i < slen; i++) + { + if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22"))) + { + saw_quote = (saw_quote + 1) % 2; + i += 3; + continue; + } + if ((s[i] == '+') && (saw_quote == 0)) + { + max++; + if (s[i - 1] == '+') + { + *emsg = GNUNET_strdup (_("`++' not allowed in KSK URI")); + return NULL; + } + } + } + if (saw_quote == 1) + { + *emsg = GNUNET_strdup (_("Quotes not balanced in KSK URI")); + return NULL; + } + iret = max; + dup = GNUNET_strdup (s); + keywords = GNUNET_malloc (max * sizeof (char *)); + for (i = slen - 1; i >= pos; i--) + { + if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22"))) + { + saw_quote = (saw_quote + 1) % 2; + i += 3; + continue; + } + if ((dup[i] == '+') && (saw_quote == 0)) + { + keywords[--max] = percent_decode_keyword (&dup[i + 1], emsg); + if (NULL == keywords[max]) + goto CLEANUP; + dup[i] = '\0'; + } + } + keywords[--max] = percent_decode_keyword (&dup[pos], emsg); + if (NULL == keywords[max]) + goto CLEANUP; + GNUNET_assert (max == 0); + GNUNET_free (dup); + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = ksk; + ret->data.ksk.keywordCount = iret; + ret->data.ksk.keywords = keywords; + return ret; +CLEANUP: + for (i = 0; i < max; i++) + GNUNET_free_non_null (keywords[i]); + GNUNET_free (keywords); + GNUNET_free (dup); + return NULL; +} + + +#define GNUNET_FS_URI_SKS_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_SKS_INFIX + +/** + * Parse an SKS URI. + * + * @param s an uri string + * @param emsg where to store the parser error message (if any) + * @return NULL on error, SKS URI otherwise + */ +static struct GNUNET_FS_Uri * +uri_sks_parse (const char *s, char **emsg) +{ + struct GNUNET_FS_Uri *ret; + GNUNET_HashCode namespace; + char *identifier; + unsigned int pos; + size_t slen; + char enc[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + + GNUNET_assert (s != NULL); + slen = strlen (s); + pos = strlen (GNUNET_FS_URI_SKS_PREFIX); + if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_SKS_PREFIX, pos))) + return NULL; /* not an SKS URI */ + if ((slen < pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) || + (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '/')) + { + *emsg = GNUNET_strdup (_("Malformed SKS URI")); + return NULL; + } + memcpy (enc, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + enc[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (enc, &namespace)) + { + *emsg = GNUNET_strdup (_("Malformed SKS URI")); + return NULL; + } + identifier = + GNUNET_strdup (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]); + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = sks; + ret->data.sks.namespace = namespace; + ret->data.sks.identifier = identifier; + return ret; +} + +#define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX + + +/** + * Parse a CHK URI. + * + * @param s an uri string + * @param emsg where to store the parser error message (if any) + * @return NULL on error, CHK URI otherwise + */ +static struct GNUNET_FS_Uri * +uri_chk_parse (const char *s, char **emsg) +{ + struct GNUNET_FS_Uri *ret; + struct FileIdentifier fi; + unsigned int pos; + unsigned long long flen; + size_t slen; + char h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + char h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + + if (NULL == s) + return NULL; + GNUNET_assert (s != NULL); + slen = strlen (s); + pos = strlen (GNUNET_FS_URI_CHK_PREFIX); + if ((slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) || + (0 != strncmp (s, GNUNET_FS_URI_CHK_PREFIX, pos))) + return NULL; /* not a CHK URI */ + if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') || + (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.')) + { + *emsg = GNUNET_strdup (_("Malformed CHK URI")); + return NULL; + } + memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + memcpy (h2, &s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)], + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + + if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &fi.chk.key)) || + (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h2, &fi.chk.query)) || + (1 != + SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2], + "%llu", &flen))) + { + *emsg = GNUNET_strdup (_("Malformed CHK URI")); + return NULL; + } + fi.file_length = GNUNET_htonll (flen); + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = chk; + ret->data.chk = fi; + return ret; +} + + +/** + * Convert a character back to the binary value + * that it represents (given base64-encoding). + * + * @param a character to convert + * @return offset in the "tbl" array + */ +static unsigned int +c2v (unsigned char a) +{ + if ((a >= '0') && (a <= '9')) + return a - '0'; + if ((a >= 'A') && (a <= 'Z')) + return (a - 'A' + 10); + if ((a >= 'a') && (a <= 'z')) + return (a - 'a' + 36); + if (a == '_') + return 62; + if (a == '=') + return 63; + return -1; +} + + +/** + * Convert string back to binary data. + * + * @param input '\\0'-terminated string + * @param data where to write binary data + * @param size how much data should be converted + * @return number of characters processed from input, + * -1 on error + */ +static int +enc2bin (const char *input, void *data, size_t size) +{ + size_t len; + size_t pos; + unsigned int bits; + unsigned int hbits; + + len = size * 8 / 6; + if (((size * 8) % 6) != 0) + len++; + if (strlen (input) < len) + return -1; /* error! */ + bits = 0; + hbits = 0; + len = 0; + for (pos = 0; pos < size; pos++) + { + while (hbits < 8) + { + bits |= (c2v (input[len++]) << hbits); + hbits += 6; + } + (((unsigned char *) data)[pos]) = (unsigned char) bits; + bits >>= 8; + hbits -= 8; + } + return len; +} + + +/** + * Structure that defines how the + * contents of a location URI must be + * assembled in memory to create or + * verify the signature of a location + * URI. + */ +struct LocUriAssembly +{ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + struct GNUNET_TIME_AbsoluteNBO exptime; + + struct FileIdentifier fi; + + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded peer; + +}; + + +#define GNUNET_FS_URI_LOC_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_LOC_INFIX + +/** + * Parse a LOC URI. + * Also verifies validity of the location URI. + * + * @param s an uri string + * @param emsg where to store the parser error message (if any) + * @return NULL on error, valid LOC URI otherwise + */ +static struct GNUNET_FS_Uri * +uri_loc_parse (const char *s, char **emsg) +{ + struct GNUNET_FS_Uri *uri; + char h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + char h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + unsigned int pos; + unsigned int npos; + unsigned long long exptime; + unsigned long long flen; + struct GNUNET_TIME_Absolute et; + struct GNUNET_CRYPTO_RsaSignature sig; + struct LocUriAssembly ass; + int ret; + size_t slen; + + GNUNET_assert (s != NULL); + slen = strlen (s); + pos = strlen (GNUNET_FS_URI_LOC_PREFIX); + if ((slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) || + (0 != strncmp (s, GNUNET_FS_URI_LOC_PREFIX, pos))) + return NULL; /* not an SKS URI */ + if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') || + (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.')) + { + *emsg = GNUNET_strdup (_("SKS URI malformed")); + return NULL; + } + memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + memcpy (h2, &s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)], + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + + if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &ass.fi.chk.key)) || + (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h2, &ass.fi.chk.query)) || + (1 != + SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2], + "%llu", &flen))) + { + *emsg = GNUNET_strdup (_("SKS URI malformed")); + return NULL; + } + ass.fi.file_length = GNUNET_htonll (flen); + + npos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2; + while ((s[npos] != '\0') && (s[npos] != '.')) + npos++; + if (s[npos] == '\0') + { + *emsg = GNUNET_strdup (_("SKS URI malformed")); + goto ERR; + } + npos++; + ret = + enc2bin (&s[npos], &ass.peer, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + if (ret == -1) + { + *emsg = + GNUNET_strdup (_("SKS URI malformed (could not decode public key)")); + goto ERR; + } + npos += ret; + if (s[npos++] != '.') + { + *emsg = GNUNET_strdup (_("SKS URI malformed (could not find signature)")); + goto ERR; + } + ret = enc2bin (&s[npos], &sig, sizeof (struct GNUNET_CRYPTO_RsaSignature)); + if (ret == -1) + { + *emsg = GNUNET_strdup (_("SKS URI malformed (could not decode signature)")); + goto ERR; + } + npos += ret; + if (s[npos++] != '.') + { + *emsg = GNUNET_strdup (_("SKS URI malformed")); + goto ERR; + } + if (1 != SSCANF (&s[npos], "%llu", &exptime)) + { + *emsg = + GNUNET_strdup (_ + ("SKS URI malformed (could not parse expiration time)")); + goto ERR; + } + ass.purpose.size = htonl (sizeof (struct LocUriAssembly)); + ass.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); + et.abs_value = exptime; + ass.exptime = GNUNET_TIME_absolute_hton (et); + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT, + &ass.purpose, &sig, &ass.peer)) + { + *emsg = + GNUNET_strdup (_("SKS URI malformed (signature failed validation)")); + goto ERR; + } + uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + uri->type = loc; + uri->data.loc.fi = ass.fi; + uri->data.loc.peer = ass.peer; + uri->data.loc.expirationTime = et; + uri->data.loc.contentSignature = sig; + + return uri; +ERR: + return NULL; +} + + +/** + * Convert a UTF-8 String to a URI. + * + * @param uri string to parse + * @param emsg where to store the parser error message (if any) + * @return NULL on error + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_parse (const char *uri, char **emsg) +{ + struct GNUNET_FS_Uri *ret; + char *msg; + + if (NULL == emsg) + emsg = &msg; + *emsg = NULL; + if ((NULL != (ret = uri_chk_parse (uri, emsg))) || + (NULL != (ret = uri_ksk_parse (uri, emsg))) || + (NULL != (ret = uri_sks_parse (uri, emsg))) || + (NULL != (ret = uri_loc_parse (uri, emsg)))) + return ret; + if (NULL == *emsg) + *emsg = GNUNET_strdup (_("Unrecognized URI type")); + if (emsg == &msg) + GNUNET_free (msg); + return NULL; +} + + +/** + * Free URI. + * + * @param uri uri to free + */ +void +GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri) +{ + unsigned int i; + + GNUNET_assert (uri != NULL); + switch (uri->type) + { + case ksk: + for (i = 0; i < uri->data.ksk.keywordCount; i++) + GNUNET_free (uri->data.ksk.keywords[i]); + GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount, 0); + break; + case sks: + GNUNET_free (uri->data.sks.identifier); + break; + case loc: + break; + default: + /* do nothing */ + break; + } + GNUNET_free (uri); +} + +/** + * How many keywords are ANDed in this keyword URI? + * + * @param uri ksk uri to get the number of keywords from + * @return 0 if this is not a keyword URI + */ +unsigned int +GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri) +{ + if (uri->type != ksk) + return 0; + return uri->data.ksk.keywordCount; +} + + +/** + * Iterate over all keywords in this keyword URI. + * + * @param uri ksk uri to get the keywords from + * @param iterator function to call on each keyword + * @param iterator_cls closure for iterator + * @return -1 if this is not a keyword URI, otherwise number of + * keywords iterated over until iterator aborted + */ +int +GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri, + GNUNET_FS_KeywordIterator iterator, + void *iterator_cls) +{ + unsigned int i; + char *keyword; + + if (uri->type != ksk) + return -1; + if (iterator == NULL) + return uri->data.ksk.keywordCount; + for (i = 0; i < uri->data.ksk.keywordCount; i++) + { + keyword = uri->data.ksk.keywords[i]; + /* first character of keyword indicates + * if it is mandatory or not */ + if (GNUNET_OK != iterator (iterator_cls, &keyword[1], keyword[0] == '+')) + return i; + } + return i; +} + + +/** + * Add the given keyword to the set of keywords represented by the URI. + * Does nothing if the keyword is already present. + * + * @param uri ksk uri to modify + * @param keyword keyword to add + * @param is_mandatory is this keyword mandatory? + */ +void +GNUNET_FS_uri_ksk_add_keyword (struct GNUNET_FS_Uri *uri, const char *keyword, + int is_mandatory) +{ + unsigned int i; + const char *old; + char *n; + + GNUNET_assert (uri->type == ksk); + for (i = 0; i < uri->data.ksk.keywordCount; i++) + { + old = uri->data.ksk.keywords[i]; + if (0 == strcmp (&old[1], keyword)) + return; + } + GNUNET_asprintf (&n, is_mandatory ? "+%s" : " %s", keyword); + GNUNET_array_append (uri->data.ksk.keywords, uri->data.ksk.keywordCount, n); +} + + +/** + * Remove the given keyword from the set of keywords represented by the URI. + * Does nothing if the keyword is not present. + * + * @param uri ksk uri to modify + * @param keyword keyword to add + */ +void +GNUNET_FS_uri_ksk_remove_keyword (struct GNUNET_FS_Uri *uri, + const char *keyword) +{ + unsigned int i; + char *old; + + GNUNET_assert (uri->type == ksk); + for (i = 0; i < uri->data.ksk.keywordCount; i++) + { + old = uri->data.ksk.keywords[i]; + if (0 == strcmp (&old[1], keyword)) + { + uri->data.ksk.keywords[i] = + uri->data.ksk.keywords[uri->data.ksk.keywordCount - 1]; + GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount, + uri->data.ksk.keywordCount - 1); + GNUNET_free (old); + return; + } + } +} + + +/** + * Obtain the identity of the peer offering the data + * + * @param uri the location URI to inspect + * @param peer where to store the identify of the peer (presumably) offering the content + * @return GNUNET_SYSERR if this is not a location URI, otherwise GNUNET_OK + */ +int +GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri, + struct GNUNET_PeerIdentity *peer) +{ + if (uri->type != loc) + return GNUNET_SYSERR; + GNUNET_CRYPTO_hash (&uri->data.loc.peer, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &peer->hashPubKey); + return GNUNET_OK; +} + + +/** + * Obtain the expiration of the LOC URI. + * + * @param uri location URI to get the expiration from + * @return expiration time of the URI + */ +struct GNUNET_TIME_Absolute +GNUNET_FS_uri_loc_get_expiration (const struct GNUNET_FS_Uri *uri) +{ + GNUNET_assert (uri->type == loc); + return uri->data.loc.expirationTime; +} + + + +/** + * Obtain the URI of the content itself. + * + * @param uri location URI to get the content URI from + * @return NULL if argument is not a location URI + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri) +{ + struct GNUNET_FS_Uri *ret; + + if (uri->type != loc) + return NULL; + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = chk; + ret->data.chk = uri->data.loc.fi; + return ret; +} + + +/** + * Construct a location URI (this peer will be used for the location). + * + * @param baseUri content offered by the sender + * @param cfg configuration information (used to find our hostkey) + * @param expiration_time how long will the content be offered? + * @return the location URI, NULL on error + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *baseUri, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TIME_Absolute expiration_time) +{ + struct GNUNET_FS_Uri *uri; + struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; + char *keyfile; + struct LocUriAssembly ass; + + if (baseUri->type != chk) + return NULL; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", + &keyfile)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Lacking key configuration settings.\n")); + return NULL; + } + my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + if (my_private_key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access hostkey file `%s'.\n"), keyfile); + GNUNET_free (keyfile); + return NULL; + } + GNUNET_free (keyfile); + GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); + ass.purpose.size = htonl (sizeof (struct LocUriAssembly)); + ass.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); + ass.exptime = GNUNET_TIME_absolute_hton (expiration_time); + ass.fi = baseUri->data.chk; + ass.peer = my_public_key; + uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + uri->type = loc; + uri->data.loc.fi = baseUri->data.chk; + uri->data.loc.expirationTime = expiration_time; + uri->data.loc.peer = my_public_key; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (my_private_key, &ass.purpose, + &uri->data.loc.contentSignature)); + GNUNET_CRYPTO_rsa_key_free (my_private_key); + return uri; +} + + +/** + * Create an SKS URI from a namespace and an identifier. + * + * @param ns namespace + * @param id identifier + * @param emsg where to store an error message + * @return an FS URI for the given namespace and identifier + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_sks_create (struct GNUNET_FS_Namespace *ns, const char *id, + char **emsg) +{ + struct GNUNET_FS_Uri *ns_uri; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk; + + ns_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ns_uri->type = sks; + GNUNET_CRYPTO_rsa_key_get_public (ns->key, &pk); + GNUNET_CRYPTO_hash (&pk, sizeof (pk), &ns_uri->data.sks.namespace); + ns_uri->data.sks.identifier = GNUNET_strdup (id); + return ns_uri; +} + + +/** + * Create an SKS URI from a namespace ID and an identifier. + * + * @param nsid namespace ID + * @param id identifier + * @return an FS URI for the given namespace and identifier + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_sks_create_from_nsid (GNUNET_HashCode * nsid, const char *id) +{ + struct GNUNET_FS_Uri *ns_uri; + + ns_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ns_uri->type = sks; + ns_uri->data.sks.namespace = *nsid; + ns_uri->data.sks.identifier = GNUNET_strdup (id); + return ns_uri; +} + + +/** + * Merge the sets of keywords from two KSK URIs. + * (useful for merging the canonicalized keywords with + * the original keywords for sharing). + * + * @param u1 first uri + * @param u2 second uri + * @return merged URI, NULL on error + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1, + const struct GNUNET_FS_Uri *u2) +{ + struct GNUNET_FS_Uri *ret; + unsigned int kc; + unsigned int i; + unsigned int j; + int found; + const char *kp; + char **kl; + + if ((u1 == NULL) && (u2 == NULL)) + return NULL; + if (u1 == NULL) + return GNUNET_FS_uri_dup (u2); + if (u2 == NULL) + return GNUNET_FS_uri_dup (u1); + if ((u1->type != ksk) || (u2->type != ksk)) + { + GNUNET_break (0); + return NULL; + } + kc = u1->data.ksk.keywordCount; + kl = GNUNET_malloc ((kc + u2->data.ksk.keywordCount) * sizeof (char *)); + for (i = 0; i < u1->data.ksk.keywordCount; i++) + kl[i] = GNUNET_strdup (u1->data.ksk.keywords[i]); + for (i = 0; i < u2->data.ksk.keywordCount; i++) + { + kp = u2->data.ksk.keywords[i]; + found = 0; + for (j = 0; j < u1->data.ksk.keywordCount; j++) + if (0 == strcmp (kp + 1, kl[j] + 1)) + { + found = 1; + if (kp[0] == '+') + kl[j][0] = '+'; + break; + } + if (0 == found) + kl[kc++] = GNUNET_strdup (kp); + } + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = ksk; + ret->data.ksk.keywordCount = kc; + ret->data.ksk.keywords = kl; + return ret; +} + + +/** + * Duplicate URI. + * + * @param uri the URI to duplicate + * @return copy of the URI + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri) +{ + struct GNUNET_FS_Uri *ret; + unsigned int i; + + if (uri == NULL) + return NULL; + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + memcpy (ret, uri, sizeof (struct GNUNET_FS_Uri)); + switch (ret->type) + { + case ksk: + if (ret->data.ksk.keywordCount >= + GNUNET_MAX_MALLOC_CHECKED / sizeof (char *)) + { + GNUNET_break (0); + GNUNET_free (ret); + return NULL; + } + if (ret->data.ksk.keywordCount > 0) + { + ret->data.ksk.keywords = + GNUNET_malloc (ret->data.ksk.keywordCount * sizeof (char *)); + for (i = 0; i < ret->data.ksk.keywordCount; i++) + ret->data.ksk.keywords[i] = GNUNET_strdup (uri->data.ksk.keywords[i]); + } + else + ret->data.ksk.keywords = NULL; /* just to be sure */ + break; + case sks: + ret->data.sks.identifier = GNUNET_strdup (uri->data.sks.identifier); + break; + case loc: + break; + default: + break; + } + return ret; +} + + +/** + * Create an FS URI from a single user-supplied string of keywords. + * The string is broken up at spaces into individual keywords. + * Keywords that start with "+" are mandatory. Double-quotes can + * be used to prevent breaking up strings at spaces (and also + * to specify non-mandatory keywords starting with "+"). + * + * Keywords must contain a balanced number of double quotes and + * double quotes can not be used in the actual keywords (for + * example, the string '""foo bar""' will be turned into two + * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'. + * + * @param keywords the keyword string + * @param emsg where to store an error message + * @return an FS URI for the given keywords, NULL + * if keywords is not legal (i.e. empty). + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_ksk_create (const char *keywords, char **emsg) +{ + char **keywordarr; + unsigned int num_Words; + int inWord; + char *pos; + struct GNUNET_FS_Uri *uri; + char *searchString; + int saw_quote; + + if (keywords == NULL) + { + *emsg = GNUNET_strdup (_("No keywords specified!\n")); + GNUNET_break (0); + return NULL; + } + searchString = GNUNET_strdup (keywords); + num_Words = 0; + inWord = 0; + saw_quote = 0; + pos = searchString; + while ('\0' != *pos) + { + if ((saw_quote == 0) && (isspace ((unsigned char) *pos))) + { + inWord = 0; + } + else if (0 == inWord) + { + inWord = 1; + ++num_Words; + } + if ('"' == *pos) + saw_quote = (saw_quote + 1) % 2; + pos++; + } + if (num_Words == 0) + { + GNUNET_free (searchString); + *emsg = GNUNET_strdup (_("No keywords specified!\n")); + return NULL; + } + if (saw_quote != 0) + { + GNUNET_free (searchString); + *emsg = GNUNET_strdup (_("Number of double-quotes not balanced!\n")); + return NULL; + } + keywordarr = GNUNET_malloc (num_Words * sizeof (char *)); + num_Words = 0; + inWord = 0; + pos = searchString; + while ('\0' != *pos) + { + if ((saw_quote == 0) && (isspace ((unsigned char) *pos))) + { + inWord = 0; + *pos = '\0'; + } + else if (0 == inWord) + { + keywordarr[num_Words] = pos; + inWord = 1; + ++num_Words; + } + if ('"' == *pos) + saw_quote = (saw_quote + 1) % 2; + pos++; + } + uri = + GNUNET_FS_uri_ksk_create_from_args (num_Words, + (const char **) keywordarr); + GNUNET_free (keywordarr); + GNUNET_free (searchString); + return uri; +} + + +/** + * Create an FS URI from a user-supplied command line of keywords. + * Arguments should start with "+" to indicate mandatory + * keywords. + * + * @param argc number of keywords + * @param argv keywords (double quotes are not required for + * keywords containing spaces; however, double + * quotes are required for keywords starting with + * "+"); there is no mechanism for having double + * quotes in the actual keywords (if the user + * did specifically specify double quotes, the + * caller should convert each double quote + * into two single quotes). + * @return an FS URI for the given keywords, NULL + * if keywords is not legal (i.e. empty). + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, const char **argv) +{ + unsigned int i; + struct GNUNET_FS_Uri *uri; + const char *keyword; + char *val; + const char *r; + char *w; + char *emsg; + + if (argc == 0) + return NULL; + /* allow URI to be given as one and only keyword and + * handle accordingly */ + emsg = NULL; + if ((argc == 1) && (strlen (argv[0]) > strlen (GNUNET_FS_URI_PREFIX)) && + (0 == + strncmp (argv[0], GNUNET_FS_URI_PREFIX, strlen (GNUNET_FS_URI_PREFIX))) + && (NULL != (uri = GNUNET_FS_uri_parse (argv[0], &emsg)))) + return uri; + GNUNET_free_non_null (emsg); + uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + uri->type = ksk; + uri->data.ksk.keywordCount = argc; + uri->data.ksk.keywords = GNUNET_malloc (argc * sizeof (char *)); + for (i = 0; i < argc; i++) + { + keyword = argv[i]; + if (keyword[0] == '+') + val = GNUNET_strdup (keyword); + else + GNUNET_asprintf (&val, " %s", keyword); + r = val; + w = val; + while ('\0' != *r) + { + if ('"' == *r) + r++; + else + *(w++) = *(r++); + } + *w = '\0'; + uri->data.ksk.keywords[i] = val; + } + return uri; +} + + +/** + * Test if two URIs are equal. + * + * @param u1 one of the URIs + * @param u2 the other URI + * @return GNUNET_YES if the URIs are equal + */ +int +GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1, + const struct GNUNET_FS_Uri *u2) +{ + int ret; + unsigned int i; + unsigned int j; + + GNUNET_assert (u1 != NULL); + GNUNET_assert (u2 != NULL); + if (u1->type != u2->type) + return GNUNET_NO; + switch (u1->type) + { + case chk: + if (0 == + memcmp (&u1->data.chk, &u2->data.chk, sizeof (struct FileIdentifier))) + return GNUNET_YES; + return GNUNET_NO; + case sks: + if ((0 == + memcmp (&u1->data.sks.namespace, &u2->data.sks.namespace, + sizeof (GNUNET_HashCode))) && + (0 == strcmp (u1->data.sks.identifier, u2->data.sks.identifier))) + + return GNUNET_YES; + return GNUNET_NO; + case ksk: + if (u1->data.ksk.keywordCount != u2->data.ksk.keywordCount) + return GNUNET_NO; + for (i = 0; i < u1->data.ksk.keywordCount; i++) + { + ret = GNUNET_NO; + for (j = 0; j < u2->data.ksk.keywordCount; j++) + { + if (0 == strcmp (u1->data.ksk.keywords[i], u2->data.ksk.keywords[j])) + { + ret = GNUNET_YES; + break; + } + } + if (ret == GNUNET_NO) + return GNUNET_NO; + } + return GNUNET_YES; + case loc: + if (memcmp + (&u1->data.loc, &u2->data.loc, + sizeof (struct FileIdentifier) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + sizeof (struct GNUNET_TIME_Absolute) + sizeof (unsigned short) + + sizeof (unsigned short)) != 0) + return GNUNET_NO; + return GNUNET_YES; + default: + return GNUNET_NO; + } +} + + +/** + * Is this a namespace URI? + * + * @param uri the uri to check + * @return GNUNET_YES if this is an SKS uri + */ +int +GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri) +{ + return uri->type == sks; +} + + +/** + * Get the ID of a namespace from the given + * namespace URI. + * + * @param uri the uri to get the namespace ID from + * @param nsid where to store the ID of the namespace + * @return GNUNET_OK on success + */ +int +GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri, + GNUNET_HashCode * nsid) +{ + if (!GNUNET_FS_uri_test_sks (uri)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + *nsid = uri->data.sks.namespace; + return GNUNET_OK; +} + + +/** + * Get the content identifier of an SKS URI. + * + * @param uri the sks uri + * @return NULL on error (not a valid SKS URI) + */ +char * +GNUNET_FS_uri_sks_get_content_id (const struct GNUNET_FS_Uri *uri) +{ + if (!GNUNET_FS_uri_test_sks (uri)) + { + GNUNET_break (0); + return NULL; + } + return GNUNET_strdup (uri->data.sks.identifier); +} + + +/** + * Convert namespace URI to a human readable format + * (using the namespace description, if available). + * + * @param cfg configuration to use + * @param uri SKS uri to convert + * @return NULL on error (not an SKS URI) + */ +char * +GNUNET_FS_uri_sks_to_string_fancy (struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_FS_Uri *uri) +{ + char *ret; + char *name; + + if (uri->type != sks) + return NULL; + name = GNUNET_PSEUDONYM_id_to_name (cfg, &uri->data.sks.namespace); + if (name == NULL) + return GNUNET_FS_uri_to_string (uri); + GNUNET_asprintf (&ret, "%s: %s", name, uri->data.sks.identifier); + GNUNET_free (name); + return ret; +} + + +/** + * Is this a keyword URI? + * + * @param uri the uri + * @return GNUNET_YES if this is a KSK uri + */ +int +GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri) +{ +#if EXTRA_CHECKS + unsigned int i; + + if (uri->type == ksk) + { + for (i=0;i < uri->data.ksk.keywordCount; i++) + GNUNET_assert (uri->data.ksk.keywords[i] != NULL); + } +#endif + return uri->type == ksk; +} + + +/** + * Is this a file (or directory) URI? + * + * @param uri the uri to check + * @return GNUNET_YES if this is a CHK uri + */ +int +GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri) +{ + return uri->type == chk; +} + + +/** + * What is the size of the file that this URI + * refers to? + * + * @param uri the CHK URI to inspect + * @return size of the file as specified in the CHK URI + */ +uint64_t +GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri * uri) +{ + switch (uri->type) + { + case chk: + return GNUNET_ntohll (uri->data.chk.file_length); + case loc: + return GNUNET_ntohll (uri->data.loc.fi.file_length); + default: + GNUNET_assert (0); + } + return 0; /* unreachable */ +} + + +/** + * Is this a location URI? + * + * @param uri the uri to check + * @return GNUNET_YES if this is a LOC uri + */ +int +GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri) +{ + return uri->type == loc; +} + + +/** + * Add a keyword as non-mandatory (with ' '-prefix) to the + * given keyword list at offset 'index'. The array is + * guaranteed to be long enough. + * + * @param s keyword to add + * @param array array to add the keyword to + * @param index offset where to add the keyword + */ +static void +insert_non_mandatory_keyword (const char *s, char **array, int index) +{ + char *nkword; + GNUNET_asprintf (&nkword, " %s", /* space to mark as 'non mandatory' */ s); + array[index] = nkword; +} + + +/** + * Test if the given keyword 's' is already present in the + * given array, ignoring the '+'-mandatory prefix in the array. + * + * @param s keyword to test + * @param array keywords to test against, with ' ' or '+' prefix to ignore + * @param array_length length of the array + * @return GNUNET_YES if the keyword exists, GNUNET_NO if not + */ +static int +find_duplicate (const char *s, const char **array, int array_length) +{ + int j; + + for (j = array_length - 1; j >= 0; j--) + if (0 == strcmp (&array[j][1], s)) + return GNUNET_YES; + return GNUNET_NO; +} + +static char * +normalize_metadata (enum EXTRACTOR_MetaFormat format, const char *data, + size_t data_len) +{ + uint8_t *free_str = NULL; + uint8_t *str_to_normalize = (uint8_t *) data; + uint8_t *normalized; + size_t r_len; + if (str_to_normalize == NULL) + return NULL; + /* Don't trust libextractor */ + if (format == EXTRACTOR_METAFORMAT_UTF8) + { + free_str = (uint8_t *) u8_check ((const uint8_t *) data, data_len); + if (free_str == NULL) + free_str = NULL; + else + format = EXTRACTOR_METAFORMAT_C_STRING; + } + if (format == EXTRACTOR_METAFORMAT_C_STRING) + { + free_str = u8_strconv_from_encoding (data, locale_charset (), iconveh_escape_sequence); + if (free_str == NULL) + return NULL; + } + + normalized = u8_tolower (str_to_normalize, strlen ((char *) str_to_normalize), NULL, UNINORM_NFD, NULL, &r_len); + /* free_str is allocated by libunistring internally, use free() */ + if (free_str != NULL) + free (free_str); + if (normalized != NULL) + { + /* u8_tolower allocates a non-NULL-terminated string! */ + free_str = GNUNET_malloc (r_len + 1); + memcpy (free_str, normalized, r_len); + free_str[r_len] = '\0'; + free (normalized); + normalized = free_str; + } + return (char *) normalized; +} + +/** + * Counts the number of UTF-8 characters (not bytes) in the string, + * returns that count. + */ +static size_t +u8_strcount (const uint8_t *s) +{ + size_t count; + ucs4_t c; + GNUNET_assert (s != NULL); + if (s[0] == 0) + return 0; + for (count = 0; s != NULL; count++) + s = u8_next (&c, s); + return count - 1; +} + + +/** + * Break the filename up by matching [], () and {} pairs to make + * keywords. In case of nesting parentheses only the inner pair counts. + * You can't escape parentheses to scan something like "[blah\{foo]" to + * make a "blah{foo" keyword, this function is only a heuristic! + * + * @param s string to break down. + * @param array array to fill with enclosed tokens. If NULL, then tokens + * are only counted. + * @param index index at which to start filling the array (entries prior + * to it are used to check for duplicates). ignored if array == NULL. + * @return number of tokens counted (including duplicates), or number of + * tokens extracted (excluding duplicates). 0 if there are no + * matching parens in the string (when counting), or when all tokens + * were duplicates (when extracting). + */ +static int +get_keywords_from_parens (const char *s, char **array, int index) +{ + int count = 0; + char *open_paren; + char *close_paren; + char *ss; + char tmp; + + if (NULL == s) + return 0; + ss = GNUNET_strdup (s); + open_paren = ss - 1; + while (NULL != (open_paren = strpbrk (open_paren + 1, "[{("))) + { + int match = 0; + + close_paren = strpbrk (open_paren + 1, "]})"); + if (NULL == close_paren) + continue; + switch (open_paren[0]) + { + case '[': + if (']' == close_paren[0]) + match = 1; + break; + case '{': + if ('}' == close_paren[0]) + match = 1; + break; + case '(': + if (')' == close_paren[0]) + match = 1; + break; + default: + break; + } + if (match && (close_paren - open_paren > 1)) + { + tmp = close_paren[0]; + close_paren[0] = '\0'; + /* Keywords must be at least 3 characters long */ + if (u8_strcount ((const uint8_t *) &open_paren[1]) <= 2) + { + close_paren[0] = tmp; + continue; + } + if (NULL != array) + { + char *normalized; + if (GNUNET_NO == find_duplicate ((const char *) &open_paren[1], + (const char **) array, index + count)) + { + insert_non_mandatory_keyword ((const char *) &open_paren[1], array, + index + count); + count++; + } + normalized = normalize_metadata (EXTRACTOR_METAFORMAT_UTF8, + &open_paren[1], close_paren - &open_paren[1]); + if (normalized != NULL) + { + if (GNUNET_NO == find_duplicate ((const char *) normalized, + (const char **) array, index + count)) + { + insert_non_mandatory_keyword ((const char *) normalized, array, + index + count); + count++; + } + GNUNET_free (normalized); + } + } + else + count++; + close_paren[0] = tmp; + } + } + GNUNET_free (ss); + return count; +} + + +/** + * Where to break up keywords + */ +#define TOKENS "_. /-!?#&+@\"\'\\;:," + +/** + * Break the filename up by TOKENS to make + * keywords. + * + * @param s string to break down. + * @param array array to fill with tokens. If NULL, then tokens are only + * counted. + * @param index index at which to start filling the array (entries prior + * to it are used to check for duplicates). ignored if array == NULL. + * @return number of tokens (>1) counted (including duplicates), or number of + * tokens extracted (excluding duplicates). 0 if there are no + * separators in the string (when counting), or when all tokens were + * duplicates (when extracting). + */ +static int +get_keywords_from_tokens (const char *s, char **array, int index) +{ + char *p; + char *ss; + int seps = 0; + + ss = GNUNET_strdup (s); + for (p = strtok (ss, TOKENS); p != NULL; p = strtok (NULL, TOKENS)) + { + /* Keywords must be at least 3 characters long */ + if (u8_strcount ((const uint8_t *) p) <= 2) + continue; + if (NULL != array) + { + char *normalized; + if (GNUNET_NO == find_duplicate (p, (const char **) array, index + seps)) + { + insert_non_mandatory_keyword (p, array, + index + seps); + seps++; + } + normalized = normalize_metadata (EXTRACTOR_METAFORMAT_UTF8, + p, strlen (p)); + if (normalized != NULL) + { + if (GNUNET_NO == find_duplicate ((const char *) normalized, + (const char **) array, index + seps)) + { + insert_non_mandatory_keyword ((const char *) normalized, array, + index + seps); + seps++; + } + GNUNET_free (normalized); + } + } + else + seps++; + } + GNUNET_free (ss); + return seps; +} +#undef TOKENS + +/** + * Function called on each value in the meta data. + * Adds it to the URI. + * + * @param cls URI to update + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_len number of bytes in data + * @return 0 (always) + */ +static int +gather_uri_data (void *cls, const char *plugin_name, + enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, + const char *data_mime_type, const char *data, size_t data_len) +{ + struct GNUNET_FS_Uri *uri = cls; + char *normalized_data; + + if ((format != EXTRACTOR_METAFORMAT_UTF8) && + (format != EXTRACTOR_METAFORMAT_C_STRING)) + return 0; + /* Keywords must be at least 3 characters long + * If given non-utf8 string it will, most likely, find it to be invalid, + * and will return the length of its valid part, skipping the keyword. + * If it does - fix the extractor, not this check! + */ + if (u8_strcount ((const uint8_t *) data) <= 2) + { + return 0; + } + normalized_data = normalize_metadata (format, data, data_len); + if (!find_duplicate (data, (const char **) uri->data.ksk.keywords, uri->data.ksk.keywordCount)) + { + insert_non_mandatory_keyword (data, + uri->data.ksk.keywords, uri->data.ksk.keywordCount); + uri->data.ksk.keywordCount++; + } + if (normalized_data != NULL) + { + if (!find_duplicate (normalized_data, (const char **) uri->data.ksk.keywords, uri->data.ksk.keywordCount)) + { + insert_non_mandatory_keyword (normalized_data, + uri->data.ksk.keywords, uri->data.ksk.keywordCount); + uri->data.ksk.keywordCount++; + } + GNUNET_free (normalized_data); + } + return 0; +} + + +/** + * Construct a keyword-URI from meta-data (take all entries + * in the meta-data and construct one large keyword URI + * that lists all keywords that can be found in the meta-data). + * + * @param md metadata to use + * @return NULL on error, otherwise a KSK URI + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData + *md) +{ + struct GNUNET_FS_Uri *ret; + char *filename; + char *full_name = NULL; + char *ss; + int ent; + int tok_keywords = 0; + int paren_keywords = 0; + + if (md == NULL) + return NULL; + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = ksk; + ent = GNUNET_CONTAINER_meta_data_iterate (md, NULL, NULL); + if (ent > 0) + { + full_name = GNUNET_CONTAINER_meta_data_get_first_by_types (md, + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, -1); + if (NULL != full_name) + { + filename = full_name; + while (NULL != (ss = strstr (filename, DIR_SEPARATOR_STR))) + filename = ss + 1; + tok_keywords = get_keywords_from_tokens (filename, NULL, 0); + paren_keywords = get_keywords_from_parens (filename, NULL, 0); + } + /* x2 because there might be a normalized variant of every keyword */ + ret->data.ksk.keywords = GNUNET_malloc (sizeof (char *) * (ent + + tok_keywords + paren_keywords) * 2); + GNUNET_CONTAINER_meta_data_iterate (md, &gather_uri_data, ret); + } + if (tok_keywords > 0) + ret->data.ksk.keywordCount += get_keywords_from_tokens (filename, + ret->data.ksk.keywords, + ret->data.ksk.keywordCount); + if (paren_keywords > 0) + ret->data.ksk.keywordCount += get_keywords_from_parens (filename, + ret->data.ksk.keywords, + ret->data.ksk.keywordCount); + if (ent > 0) + GNUNET_free_non_null (full_name); + return ret; +} + + +/** + * In URI-encoding, does the given character + * need to be encoded using %-encoding? + */ +static int +needs_percent (char c) +{ + return (! + ((isalnum ((unsigned char) c)) || (c == '-') || (c == '_') || + (c == '.') || (c == '~'))); +} + + +/** + * Convert a KSK URI to a string. + * + * @param uri the URI to convert + * @return NULL on error (i.e. keywordCount == 0) + */ +static char * +uri_ksk_to_string (const struct GNUNET_FS_Uri *uri) +{ + char **keywords; + unsigned int keywordCount; + size_t n; + char *ret; + unsigned int i; + unsigned int j; + unsigned int wpos; + size_t slen; + const char *keyword; + + if (uri->type != ksk) + return NULL; + keywords = uri->data.ksk.keywords; + keywordCount = uri->data.ksk.keywordCount; + n = keywordCount + strlen (GNUNET_FS_URI_PREFIX) + + strlen (GNUNET_FS_URI_KSK_INFIX) + 1; + for (i = 0; i < keywordCount; i++) + { + keyword = keywords[i]; + slen = strlen (keyword); + n += slen; + for (j = 0; j < slen; j++) + { + if ((j == 0) && (keyword[j] == ' ')) + { + n--; + continue; /* skip leading space */ + } + if (needs_percent (keyword[j])) + n += 2; /* will use %-encoding */ + } + } + ret = GNUNET_malloc (n); + strcpy (ret, GNUNET_FS_URI_PREFIX); + strcat (ret, GNUNET_FS_URI_KSK_INFIX); + wpos = strlen (ret); + for (i = 0; i < keywordCount; i++) + { + keyword = keywords[i]; + slen = strlen (keyword); + for (j = 0; j < slen; j++) + { + if ((j == 0) && (keyword[j] == ' ')) + continue; /* skip leading space */ + if (needs_percent (keyword[j])) + { + sprintf (&ret[wpos], "%%%02X", keyword[j]); + wpos += 3; + } + else + { + ret[wpos++] = keyword[j]; + } + } + if (i != keywordCount - 1) + ret[wpos++] = '+'; + } + return ret; +} + + +/** + * Convert SKS URI to a string. + * + * @param uri sks uri to convert + * @return NULL on error + */ +static char * +uri_sks_to_string (const struct GNUNET_FS_Uri *uri) +{ + const GNUNET_HashCode *namespace; + const char *identifier; + char *ret; + struct GNUNET_CRYPTO_HashAsciiEncoded ns; + + if (uri->type != sks) + return NULL; + namespace = &uri->data.sks.namespace; + identifier = uri->data.sks.identifier; + GNUNET_CRYPTO_hash_to_enc (namespace, &ns); + GNUNET_asprintf (&ret, "%s%s%s/%s", GNUNET_FS_URI_PREFIX, + GNUNET_FS_URI_SKS_INFIX, (const char *) &ns, identifier); + return ret; +} + + +/** + * Convert a CHK URI to a string. + * + * @param uri chk uri to convert + * @return NULL on error + */ +static char * +uri_chk_to_string (const struct GNUNET_FS_Uri *uri) +{ + const struct FileIdentifier *fi; + char *ret; + struct GNUNET_CRYPTO_HashAsciiEncoded keyhash; + struct GNUNET_CRYPTO_HashAsciiEncoded queryhash; + + if (uri->type != chk) + return NULL; + fi = &uri->data.chk; + GNUNET_CRYPTO_hash_to_enc (&fi->chk.key, &keyhash); + GNUNET_CRYPTO_hash_to_enc (&fi->chk.query, &queryhash); + + GNUNET_asprintf (&ret, "%s%s%s.%s.%llu", GNUNET_FS_URI_PREFIX, + GNUNET_FS_URI_CHK_INFIX, (const char *) &keyhash, + (const char *) &queryhash, GNUNET_ntohll (fi->file_length)); + return ret; +} + +/** + * Convert binary data to a string. + * + * @param data binary data to convert + * @param size number of bytes in data + * @return converted data + */ +static char * +bin2enc (const void *data, size_t size) +{ + /** + * 64 characters for encoding, 6 bits per character + */ + static char *tbl = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_="; + + size_t len; + size_t pos; + unsigned int bits; + unsigned int hbits; + char *ret; + + GNUNET_assert (strlen (tbl) == 64); + len = size * 8 / 6; + if (((size * 8) % 6) != 0) + len++; + ret = GNUNET_malloc (len + 1); + ret[len] = '\0'; + len = 0; + bits = 0; + hbits = 0; + for (pos = 0; pos < size; pos++) + { + bits |= ((((const unsigned char *) data)[pos]) << hbits); + hbits += 8; + while (hbits >= 6) + { + ret[len++] = tbl[bits & 63]; + bits >>= 6; + hbits -= 6; + } + } + if (hbits > 0) + ret[len] = tbl[bits & 63]; + return ret; +} + + +/** + * Convert a LOC URI to a string. + * + * @param uri loc uri to convert + * @return NULL on error + */ +static char * +uri_loc_to_string (const struct GNUNET_FS_Uri *uri) +{ + char *ret; + struct GNUNET_CRYPTO_HashAsciiEncoded keyhash; + struct GNUNET_CRYPTO_HashAsciiEncoded queryhash; + char *peerId; + char *peerSig; + + GNUNET_CRYPTO_hash_to_enc (&uri->data.loc.fi.chk.key, &keyhash); + GNUNET_CRYPTO_hash_to_enc (&uri->data.loc.fi.chk.query, &queryhash); + peerId = + bin2enc (&uri->data.loc.peer, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + peerSig = + bin2enc (&uri->data.loc.contentSignature, + sizeof (struct GNUNET_CRYPTO_RsaSignature)); + GNUNET_asprintf (&ret, "%s%s%s.%s.%llu.%s.%s.%llu", GNUNET_FS_URI_PREFIX, + GNUNET_FS_URI_LOC_INFIX, (const char *) &keyhash, + (const char *) &queryhash, + (unsigned long long) GNUNET_ntohll (uri->data.loc. + fi.file_length), peerId, + peerSig, + (unsigned long long) uri->data.loc.expirationTime.abs_value); + GNUNET_free (peerSig); + GNUNET_free (peerId); + return ret; +} + + +/** + * Convert a URI to a UTF-8 String. + * + * @param uri uri to convert to a string + * @return the UTF-8 string + */ +char * +GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri) +{ + if (uri == NULL) + { + GNUNET_break (0); + return NULL; + } + switch (uri->type) + { + case ksk: + return uri_ksk_to_string (uri); + case sks: + return uri_sks_to_string (uri); + case chk: + return uri_chk_to_string (uri); + case loc: + return uri_loc_to_string (uri); + default: + GNUNET_break (0); + return NULL; + } +} + +/* end of fs_uri.c */ diff --git a/src/fs/gnunet-directory.c b/src/fs/gnunet-directory.c new file mode 100644 index 0000000..0721ea9 --- /dev/null +++ b/src/fs/gnunet-directory.c @@ -0,0 +1,183 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/gnunet-directory.c + * @brief display content of GNUnet directories + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_fs_service.h" + +static int ret; + +/** + * Print a meta data entry. + * + * @param cls closure (unused) + * @param plugin_name name of the plugin that generated the meta data + * @param type type of the keyword + * @param format format of data + * @param data_mime_type mime type of data + * @param data value of the meta data + * @param data_size number of bytes in data + * @return always 0 (to continue iterating) + */ +static int +item_printer (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, + enum EXTRACTOR_MetaFormat format, const char *data_mime_type, + const char *data, size_t data_size) +{ + if (type == EXTRACTOR_METATYPE_GNUNET_FULL_DATA) + { + printf (_("\t\n"), + (unsigned int) data_size); + return 0; + } + if ((format != EXTRACTOR_METAFORMAT_UTF8) && + (format != EXTRACTOR_METAFORMAT_C_STRING)) + return 0; + if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) + return 0; + printf ("\t%20s: %s\n", + dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, + EXTRACTOR_metatype_to_string (type)), data); + return 0; +} + + + +/** + * Print an entry in a directory. + * + * @param cls closure (not used) + * @param filename name of the file in the directory + * @param uri URI of the file + * @param meta metadata for the file; metadata for + * the directory if everything else is NULL/zero + * @param length length of the available data for the file + * (of type size_t since data must certainly fit + * into memory; if files are larger than size_t + * permits, then they will certainly not be + * embedded with the directory itself). + * @param data data available for the file (length bytes) + */ +static void +print_entry (void *cls, const char *filename, const struct GNUNET_FS_Uri *uri, + const struct GNUNET_CONTAINER_MetaData *meta, size_t length, + const void *data) +{ + char *string; + char *name; + + name = + GNUNET_CONTAINER_meta_data_get_by_type (meta, + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); + if (uri == NULL) + { + printf (_("Directory `%s' meta data:\n"), name); + GNUNET_CONTAINER_meta_data_iterate (meta, &item_printer, NULL); + printf ("\n"); + printf (_("Directory `%s' contents:\n"), name); + GNUNET_free (name); + return; + } + string = GNUNET_FS_uri_to_string (uri); + printf ("%s (%s):\n", name, string); + GNUNET_free (string); + GNUNET_CONTAINER_meta_data_iterate (meta, &item_printer, NULL); + printf ("\n"); + GNUNET_free (name); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_DISK_MapHandle *map; + struct GNUNET_DISK_FileHandle *h; + void *data; + size_t len; + uint64_t size; + const char *filename; + int i; + + if (NULL == args[0]) + { + FPRINTF (stderr, "%s", _("You must specify a filename to inspect.\n")); + ret = 1; + return; + } + i = 0; + while (NULL != (filename = args[i++])) + { + if ((GNUNET_OK != GNUNET_DISK_file_size (filename, &size, GNUNET_YES)) || + (NULL == + (h = + GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to read directory `%s'\n"), + filename); + ret = 1; + continue; + } + len = (size_t) size; + data = GNUNET_DISK_file_map (h, &map, GNUNET_DISK_MAP_TYPE_READ, len); + GNUNET_assert (NULL != data); + if (GNUNET_OK != GNUNET_FS_directory_list_contents (len, data, 0, &print_entry, NULL)) + fprintf (stdout, _("`%s' is not a GNUnet directory\n"), + filename); + else + printf ("\n"); + GNUNET_DISK_file_unmap (map); + GNUNET_DISK_file_close (h); + } +} + +/** + * The main function to inspect GNUnet directories. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-directory [OPTIONS] FILENAME", + gettext_noop + ("Display contents of a GNUnet directory"), + options, &run, NULL)) ? ret : 1; +} + +/* end of gnunet-directory.c */ diff --git a/src/fs/gnunet-download-manager.scm b/src/fs/gnunet-download-manager.scm new file mode 100755 index 0000000..80d04fa --- /dev/null +++ b/src/fs/gnunet-download-manager.scm @@ -0,0 +1,407 @@ +#!/bin/sh +exec guile -e main -s "$0" "$@" +!# + +;;; gnunet-download-manager -- Manage GNUnet downloads. +;;; Copyright (C) 2004 Ludovic Courtès +;;; +;;; This program is free software; you can redistribute it and/or +;;; modify it under the terms of the GNU General Public License +;;; as published by the Free Software Foundation; either version 2 +;;; of the License, or (at your option) any later version. +;;; +;;; This program is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program; if not, write to the Free Software +;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Remember ongoing GNUnet downloads so as to be able to resume them +;;; later. Typical usage is to define the following alias in your +;;; favorite shell: +;;; +;;; alias gnunet-download='gnunet-download-manager.scm download' +;;; +;;; You may have a ~/.gnunet-download-manager.scm Scheme configuration +;;; file. In particular, if you would like to be notified of +;;; completed downloads, you may want to add the following line to +;;; your configuration file: +;;; +;;; (add-hook! *completed-download-hook* +;;; completed-download-notification-hook) +;;; +;;; This script works fine with GNU Guile 1.6.4, and doesn't run with +;;; Guile 1.4.x. +;;; +;;; Enjoy! +;;; Ludovic Courtès + +(use-modules (ice-9 format) + (ice-9 optargs) + (ice-9 regex) + (ice-9 and-let-star) + (ice-9 pretty-print) + (ice-9 documentation)) + +;; Overall user settings +(define *debug?* #f) +(define *rc-file* (string-append (getenv "HOME") + "/.gnunet-download-manager.scm")) +(define *status-directory* (string-append (getenv "HOME") "/" + ".gnunet-download-manager")) +(define *gnunet-download* "gnunet-download") + +;; Helper macros +(define-macro (gnunet-info fmt . args) + `(format #t (string-append *program-name* ": " ,fmt "~%") + ,@args)) + +(define-macro (gnunet-debug fmt . args) + (if *debug?* + (cons 'gnunet-info (cons fmt args)) + #t)) + +(define-macro (gnunet-error fmt . args) + `(and ,(cons 'gnunet-info (cons fmt args)) + (exit 1))) + +(define (exception-string key args) + "Describe an error, using the format from @var{args}, if available." + (if (< (length args) 4) + (format #f "Scheme exception: ~S" key) + (string-append + (if (string? (car args)) + (string-append "In " (car args)) + "Scheme exception") + ": " + (apply format `(#f ,(cadr args) ,@(caddr args)))))) + + +;; Regexps matching GNUnet URIs +(define *uri-base* + "([[:alnum:]]+)\.([[:alnum:]]+)\.([[:alnum:]]+)\.([0-9]+)") +(define *uri-re* + (make-regexp (string-append "^gnunet://afs/" *uri-base* "$") + regexp/extended)) +(define *uri-status-file-re* + (make-regexp (string-append "^" *uri-base* "$") + regexp/extended)) + + +(define (uri-status-file-name directory uri) + "Return the name of the status file for URI @var{uri}." + (let ((match (regexp-exec *uri-re* uri))) + (if (not match) + (and (gnunet-info "~a: Invalid URI" uri) #f) + (let ((start (match:start match 1)) + (end (match:end match 4))) + (string-append directory "/" + (substring uri start end)))))) + +(define (uri-status directory uri) + "Load the current status alist for URI @var{uri} from @var{directory}." + (gnunet-debug "uri-status") + (let ((filename (uri-status-file-name directory uri))) + (catch 'system-error + (lambda () + (let* ((file (open-input-file filename)) + (status (read file))) + (begin + (close-port file) + status))) + (lambda (key . args) + (and (gnunet-debug (exception-string key args)) + '()))))) + +(define (process-exists? pid) + (false-if-exception (begin (kill pid 0) #t))) + +(define (fork-and-exec directory program . args) + "Launch @var{program} and return its PID." + (gnunet-debug "fork-and-exec: ~a ~a" program args) + (let ((pid (primitive-fork))) + (if (= 0 pid) + (begin + (if directory (chdir directory)) + (apply execlp (cons program (cons program args)))) + pid))) + +(define* (start-downloader downloader uri options + #:key (directory #f)) + "Start the GNUnet downloader for URI @var{uri} with options +@var{options}. Return an alist describing the download status." + (catch 'system-error + (lambda () + (let* ((pid (apply fork-and-exec + `(,(if directory directory (getcwd)) + ,downloader + ,@options)))) + (gnunet-info "Launched process ~a" pid) + `((uri . ,uri) + (working-directory . ,(if directory directory (getcwd))) + (options . ,options) + (pid . ,(getpid)) + (downloader-pid . ,pid)))) + (lambda (key . args) + (gnunet-error (exception-string key args))))) + +(define (download-process-alive? uri-status) + "Return true if the download whose status is that described by +@var{uri-status} is still alive." + (let ((pid (assoc-ref uri-status 'pid)) + (downloader-pid (assoc-ref uri-status 'downloader-pid))) + (and (process-exists? pid) + (process-exists? downloader-pid)))) + +(define (start-file-download downloader status-dir uri options) + "Dowload the file located at @var{uri}, with options @var{options} +and return an updated status alist." + (gnunet-debug "start-file-download") + (let ((uri-status (uri-status status-dir uri))) + (if (null? uri-status) + (acons 'start-date (current-time) + (start-downloader downloader uri options)) + (if (download-process-alive? uri-status) + (and (gnunet-info "~a already being downloaded by process ~a" + uri (assoc-ref uri-status 'pid)) + #f) + (and (gnunet-info "Resuming download") + (let ((start-date (assoc-ref uri-status 'start-date)) + (dir (assoc-ref uri-status 'working-directory)) + (options (assoc-ref uri-status 'options))) + (acons 'start-date start-date + (start-downloader downloader uri options + #:directory dir)))))))) + +(define *completed-download-hook* (make-hook 1)) + +(define (download-file downloader status-dir uri options) + "Start downloading file located at URI @var{uri}, with options +@var{options}, resuming it if it's already started." + (catch 'system-error + (lambda () + (and-let* ((status (start-file-download downloader + status-dir + uri options)) + (pid (assoc-ref status 'downloader-pid)) + (filename (uri-status-file-name status-dir + uri)) + (file (open-file filename "w"))) + + ;; Write down the status + (pretty-print status file) + (close-port file) + + ;; Wait for `gnunet-download' + (gnunet-info "Waiting for process ~a" pid) + (let* ((process-status (waitpid pid)) + (exit-val (status:exit-val (cdr process-status))) + (term-sig (status:term-sig (cdr process-status)))) + + ;; Terminate + (delete-file filename) + (gnunet-info + "Download completed (PID ~a, exit code ~a)" + pid exit-val) + (let ((ret `((end-date . ,(current-time)) + (exit-code . ,exit-val) + (terminating-signal . ,term-sig) + ,@status))) + (run-hook *completed-download-hook* ret) + ret)))) + (lambda (key . args) + (gnunet-error (exception-string key args))))) + +(define (uri-status-files directory) + "Return the list of URI status files in @var{directory}." + (catch 'system-error + (lambda () + (let ((dir (opendir directory))) + (let loop ((filename (readdir dir)) + (file-list '())) + (if (eof-object? filename) + file-list + (if (regexp-exec *uri-status-file-re* filename) + (loop (readdir dir) + (cons filename file-list)) + (loop (readdir dir) file-list)))))) + (lambda (key . args) + (gnunet-error (exception-string key args))))) + +(define (output-file-option option-list) + "Return the output file specified in @var{option-list}, false if +anavailable." + (if (null? option-list) + #f + (let ((rest (cdr option-list)) + (opt (car option-list))) + (if (null? rest) + #f + (if (or (string=? opt "-o") + (string=? opt "--output")) + (car rest) + (output-file-option rest)))))) + +(define (download-command . args) + "Start downloading a file using the given `gnunet-download' +arguments." + (gnunet-debug "download-command") + (let* ((argc (length args)) + ;; FIXME: We're assuming the URI is the last argument + (uri (car (list-tail args (- argc 1)))) + (options args)) + (download-file *gnunet-download* *status-directory* uri options))) + +(define (status-command . args) + "Print status info about files being downloaded." + (for-each (lambda (status) + (format #t "~a: ~a~% ~a~% ~a~% ~a~%" + (assoc-ref status 'uri) + (if (download-process-alive? status) + (string-append "running (PID " + (number->string (assoc-ref status + 'pid)) + ")") + "not running") + (string-append "Started on " + (strftime "%c" + (localtime (assoc-ref + status + 'start-date)))) + (string-append "Directory: " + (assoc-ref status + 'working-directory)) + (string-append "Output file: " + (or (output-file-option (assoc-ref + status + 'options)) + "")))) + (map (lambda (file) + (uri-status *status-directory* + (string-append "gnunet://afs/" file))) + (uri-status-files *status-directory*)))) + +(define (resume-command . args) + "Resume stopped downloads." + (for-each (lambda (status) + (if (not (download-process-alive? status)) + (if (= 0 (primitive-fork)) + (let* ((ret (download-file *gnunet-download* + *status-directory* + (assoc-ref status 'uri) + (assoc-ref status 'options))) + (code (assoc-ref ret 'exit-code))) + (exit code))))) + (map (lambda (file) + (uri-status *status-directory* + (string-append "gnunet://afs/" file))) + (uri-status-files *status-directory*)))) + +(define (killall-command . args) + "Stop all running downloads." + (for-each (lambda (status) + (if (download-process-alive? status) + (let ((pid (assoc-ref status 'pid)) + (dl-pid (assoc-ref status 'downloader-pid))) + (and (gnunet-info "Stopping processes ~a and ~a" + pid dl-pid) + (kill pid 15) + (kill dl-pid 15))))) + (map (lambda (file) + (uri-status *status-directory* + (string-append "gnunet://afs/" file))) + (uri-status-files *status-directory*)))) + + +(define (help-command . args) + "Show this help message." + (format #t "Usage: ~a [options]~%" *program-name*) + (format #t "Where may be one of the following:~%~%") + (for-each (lambda (command) + (if (not (eq? (cdr command) help-command)) + (format #t (string-append " " (car command) ": " + (object-documentation + (cdr command)) + "~%")))) + *commands*) + (format #t "~%")) + +(define (settings-command . args) + "Dump the current settings." + (format #t "Current settings:~%~%") + (module-for-each (lambda (symbol variable) + (if (string-match "^\\*.*\\*$" (symbol->string symbol)) + (format #t " ~a: ~a~%" + symbol (variable-ref variable)))) + (current-module)) + (format #t "~%")) + +(define (version-command . args) + "Show version information." + (format #t "~a ~a.~a (~a)~%" + *program-name* *version-major* *version-minor* *version-date*)) + +;; This hook may be added to *completed-download-hook*. +(define (completed-download-notification-hook status) + "Notifies of the completion of a file download." + (let ((msg (string-append "GNUnet download of " + (output-file-option + (assoc-ref status 'options)) + " in " + (assoc-ref status + 'working-directory) + " complete!"))) + (if (getenv "DISPLAY") + (waitpid (fork-and-exec #f "xmessage" msg)) + (waitpid (fork-and-exec #f "write" + (cuserid) msg))))) + +;; Available user commands +(define *commands* + `(("download" . ,download-command) + ("status" . ,status-command) + ("resume" . ,resume-command) + ("killall" . ,killall-command) + ("settings" . ,settings-command) + ("version" . ,version-command) + ("help" . ,help-command) + ("--help" . ,help-command) + ("-h" . ,help-command))) + +(define *program-name* "gnunet-download-manager") +(define *version-major* 0) +(define *version-minor* 1) +(define *version-date* "april 2004") + +(define (main args) + (set! *program-name* (basename (car args))) + + ;; Load the user's configuration file + (if (file-exists? *rc-file*) + (load *rc-file*)) + + ;; Check whether the status directory already exists + (if (not (file-exists? *status-directory*)) + (begin + (gnunet-info "Creating status directory ~a..." *status-directory*) + (catch 'system-error + (lambda () + (mkdir *status-directory*)) + (lambda (key . args) + (and (gnunet-error (exception-string key args)) + (exit 1)))))) + + ;; Go ahead + (if (< (length args) 2) + (and (format #t "Usage: ~a [options]~%" + *program-name*) + (exit 1)) + (let* ((command-name (cadr args)) + (command (assoc-ref *commands* command-name))) + (if command + (apply command (cddr args)) + (and (gnunet-info "~a command not found" command-name) + (exit 1)))))) \ No newline at end of file diff --git a/src/fs/gnunet-download.c b/src/fs/gnunet-download.c new file mode 100644 index 0000000..ff10c39 --- /dev/null +++ b/src/fs/gnunet-download.c @@ -0,0 +1,281 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/gnunet-download.c + * @brief downloading for files on GNUnet + * @author Christian Grothoff + * @author Krista Bennett + * @author James Blackwell + * @author Igor Wronsky + */ +#include "platform.h" +#include "gnunet_fs_service.h" + +static int ret; + +static int verbose; + +static int delete_incomplete; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_FS_Handle *ctx; + +static struct GNUNET_FS_DownloadContext *dc; + +static unsigned int anonymity = 1; + +static unsigned int parallelism = 16; + +static unsigned int request_parallelism = 4092; + +static int do_recursive; + +static char *filename; + +static int local_only; + +static void +cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_stop (ctx); + ctx = NULL; +} + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_DownloadContext *d; + + if (dc != NULL) + { + d = dc; + dc = NULL; + GNUNET_FS_download_stop (d, delete_incomplete); + } +} + + +/** + * Called by FS client to give information about the progress of an + * operation. + * + * @param cls closure + * @param info details about the event, specifying the event type + * and various bits about the event + * @return client-context (for the next progress call + * for this operation; should be set to NULL for + * SUSPEND and STOPPED events). The value returned + * will be passed to future callbacks in the respective + * field in the GNUNET_FS_ProgressInfo struct. + */ +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) +{ + char *s, *s2; + char *t; + + switch (info->status) + { + case GNUNET_FS_STATUS_DOWNLOAD_START: + if (verbose > 1) + FPRINTF (stderr, _("Starting download `%s'.\n"), + info->value.download.filename); + break; + case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: + if (verbose) + { + s = GNUNET_STRINGS_relative_time_to_string (info->value.download.eta); + if (info->value.download.specifics.progress.block_download_duration.rel_value + == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) + s2 = GNUNET_strdup (_("")); + else + s2 = GNUNET_STRINGS_relative_time_to_string ( + info->value.download.specifics.progress.block_download_duration); + t = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * + 1000LL / + (info->value.download. + duration.rel_value + 1)); + FPRINTF (stdout, + _("Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to download\n"), + info->value.download.filename, + (unsigned long long) info->value.download.completed, + (unsigned long long) info->value.download.size, s, t, s2); + GNUNET_free (s); + GNUNET_free (s2); + GNUNET_free (t); + } + break; + case GNUNET_FS_STATUS_DOWNLOAD_ERROR: + FPRINTF (stderr, _("Error downloading: %s.\n"), + info->value.download.specifics.error.message); + GNUNET_SCHEDULER_shutdown (); + break; + case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: + s = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * 1000 / + (info->value.download. + duration.rel_value + 1)); + FPRINTF (stdout, _("Downloading `%s' done (%s/s).\n"), + info->value.download.filename, s); + GNUNET_free (s); + if (info->value.download.dc == dc) + GNUNET_SCHEDULER_shutdown (); + break; + case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: + if (info->value.download.dc == dc) + GNUNET_SCHEDULER_add_continuation (&cleanup_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: + case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: + break; + default: + FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); + break; + } + return NULL; +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + struct GNUNET_FS_Uri *uri; + char *emsg; + enum GNUNET_FS_DownloadOptions options; + + if (NULL == args[0]) + { + FPRINTF (stderr, "%s", _("You need to specify a URI argument.\n")); + return; + } + uri = GNUNET_FS_uri_parse (args[0], &emsg); + if (NULL == uri) + { + FPRINTF (stderr, _("Failed to parse URI: %s\n"), emsg); + GNUNET_free (emsg); + ret = 1; + return; + } + if ((!GNUNET_FS_uri_test_chk (uri)) && (!GNUNET_FS_uri_test_loc (uri))) + { + FPRINTF (stderr, "%s", _("Only CHK or LOC URIs supported.\n")); + ret = 1; + GNUNET_FS_uri_destroy (uri); + return; + } + if (NULL == filename) + { + FPRINTF (stderr, "%s", _("Target filename must be specified.\n")); + ret = 1; + GNUNET_FS_uri_destroy (uri); + return; + } + cfg = c; + ctx = + GNUNET_FS_start (cfg, "gnunet-download", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, + GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM, parallelism, + GNUNET_FS_OPTIONS_REQUEST_PARALLELISM, + request_parallelism, GNUNET_FS_OPTIONS_END); + if (NULL == ctx) + { + FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS"); + GNUNET_FS_uri_destroy (uri); + ret = 1; + return; + } + options = GNUNET_FS_DOWNLOAD_OPTION_NONE; + if (do_recursive) + options |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE; + if (local_only) + options |= GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY; + dc = GNUNET_FS_download_start (ctx, uri, NULL, filename, NULL, 0, + GNUNET_FS_uri_chk_get_file_size (uri), + anonymity, options, NULL, NULL); + GNUNET_FS_uri_destroy (uri); + if (dc == NULL) + { + GNUNET_FS_stop (ctx); + ctx = NULL; + return; + } + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); +} + + +/** + * The main function to download GNUnet. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'a', "anonymity", "LEVEL", + gettext_noop ("set the desired LEVEL of receiver-anonymity"), + 1, &GNUNET_GETOPT_set_uint, &anonymity}, + {'D', "delete-incomplete", NULL, + gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"), + 0, &GNUNET_GETOPT_set_one, &delete_incomplete}, + {'n', "no-network", NULL, + gettext_noop ("only search the local peer (no P2P network search)"), + 0, &GNUNET_GETOPT_set_uint, &local_only}, + {'o', "output", "FILENAME", + gettext_noop ("write the file to FILENAME"), + 1, &GNUNET_GETOPT_set_string, &filename}, + {'p', "parallelism", "DOWNLOADS", + gettext_noop + ("set the maximum number of parallel downloads that is allowed"), + 1, &GNUNET_GETOPT_set_uint, ¶llelism}, + {'r', "request-parallelism", "REQUESTS", + gettext_noop + ("set the maximum number of parallel requests for blocks that is allowed"), + 1, &GNUNET_GETOPT_set_uint, &request_parallelism}, + {'R', "recursive", NULL, + gettext_noop ("download a GNUnet directory recursively"), + 0, &GNUNET_GETOPT_set_one, &do_recursive}, + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_increment_value, &verbose}, + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-download [OPTIONS] URI", + gettext_noop + ("Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/chk/...)"), + options, &run, NULL)) ? ret : 1; +} + +/* end of gnunet-download.c */ diff --git a/src/fs/gnunet-fs.c b/src/fs/gnunet-fs.c new file mode 100644 index 0000000..0b28923 --- /dev/null +++ b/src/fs/gnunet-fs.c @@ -0,0 +1,128 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/gnunet-fs.c + * @brief special file-sharing functions + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_fs_service.h" + +/** + * Return value. + */ +static int ret; + +/** + * Handle to FS service. + */ +static struct GNUNET_FS_Handle *fs; + +/** + * Option -i given? + */ +static int list_indexed_files; + +/** + * Option -v given? + */ +static int verbose; + + +/** + * Print indexed filenames to stdout. + * + * @param cls closure + * @param filename the name of the file + * @param file_id hash of the contents of the indexed file + * @return GNUNET_OK to continue iteration + */ +static int +print_indexed (void *cls, const char *filename, const GNUNET_HashCode * file_id) +{ + if (NULL == filename) + { + GNUNET_FS_stop (fs); + fs = NULL; + return GNUNET_OK; + } + if (verbose) + FPRINTF (stdout, "%s: %s\n", GNUNET_h2s (file_id), filename); + else + FPRINTF (stdout, "%s\n", filename); + return GNUNET_OK; +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + if (list_indexed_files) + { + fs = GNUNET_FS_start (cfg, "gnunet-fs", NULL, NULL, GNUNET_FS_FLAGS_NONE, + GNUNET_FS_OPTIONS_END); + if (NULL == fs) + { + ret = 1; + return; + } + if (NULL == GNUNET_FS_get_indexed_files (fs, &print_indexed, NULL)) + { + ret = 2; + GNUNET_FS_stop (fs); + fs = NULL; + return; + } + } +} + +/** + * The main function to access special file-sharing functions. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static struct GNUNET_GETOPT_CommandLineOption options[] = { + {'i', "list-indexed", NULL, + gettext_noop ("print a list of all indexed files"), 0, + &GNUNET_GETOPT_set_one, &list_indexed_files}, + GNUNET_GETOPT_OPTION_VERBOSE (&verbose), + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-fs [OPTIONS]", + gettext_noop ("Special file-sharing operations"), + options, &run, NULL)) ? ret : 1; +} + +/* end of gnunet-fs.c */ diff --git a/src/fs/gnunet-helper-fs-publish.c b/src/fs/gnunet-helper-fs-publish.c new file mode 100644 index 0000000..4f70464 --- /dev/null +++ b/src/fs/gnunet-helper-fs-publish.c @@ -0,0 +1,457 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/fs/gnunet-helper-fs-publish.c + * @brief Tool to help extract meta data asynchronously + * @author Christian Grothoff + * + * This program will scan a directory for files with meta data + * and report the results to stdout. + */ +#include "platform.h" +#include "gnunet_fs_service.h" + + +/** + * A node of a directory tree. + */ +struct ScanTreeNode +{ + + /** + * This is a doubly-linked list + */ + struct ScanTreeNode *next; + + /** + * This is a doubly-linked list + */ + struct ScanTreeNode *prev; + + /** + * Parent of this node, NULL for top-level entries. + */ + struct ScanTreeNode *parent; + + /** + * This is a doubly-linked tree + * NULL for files and empty directories + */ + struct ScanTreeNode *children_head; + + /** + * This is a doubly-linked tree + * NULL for files and empty directories + */ + struct ScanTreeNode *children_tail; + + /** + * Name of the file/directory + */ + char *filename; + + /** + * Size of the file (if it is a file), in bytes + */ + uint64_t file_size; + + /** + * GNUNET_YES if this is a directory + */ + int is_directory; + +}; + + +/** + * List of libextractor plugins to use for extracting. + */ +static struct EXTRACTOR_PluginList *plugins; + + +/** + * Add meta data that libextractor finds to our meta data + * container. + * + * @param cls closure, our meta data container + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_len number of bytes in data + * @return always 0 to continue extracting + */ +static int +add_to_md (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, + enum EXTRACTOR_MetaFormat format, const char *data_mime_type, + const char *data, size_t data_len) +{ + struct GNUNET_CONTAINER_MetaData *md = cls; + + (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format, + data_mime_type, data, data_len); + return 0; +} + + +/** + * Free memory of the 'tree' structure + * + * @param tree tree to free + */ +static void +free_tree (struct ScanTreeNode *tree) +{ + struct ScanTreeNode *pos; + + while (NULL != (pos = tree->children_head)) + free_tree (pos); + if (NULL != tree->parent) + GNUNET_CONTAINER_DLL_remove (tree->parent->children_head, + tree->parent->children_tail, + tree); + GNUNET_free (tree->filename); + GNUNET_free (tree); +} + + +/** + * Write 'size' bytes from 'buf' into 'out'. + * + * @param buf buffer with data to write + * @param size number of bytes to write + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +write_all (const void *buf, + size_t size) +{ + const char *cbuf = buf; + size_t total; + ssize_t wr; + + total = 0; + do + { + wr = write (1, + &cbuf[total], + size - total); + if (wr > 0) + total += wr; + } while ( (wr > 0) && (total < size) ); + if (wr <= 0) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to write to stdout: %s\n", + strerror (errno)); + return (total == size) ? GNUNET_OK : GNUNET_SYSERR; +} + + +/** + * Write message to the master process. + * + * @param message_type message type to use + * @param data data to append, NULL for none + * @param data_length number of bytes in data + * @return GNUNET_SYSERR to stop scanning (the pipe was broken somehow) + */ +static int +write_message (uint16_t message_type, + const char *data, + size_t data_length) +{ + struct GNUNET_MessageHeader hdr; + + hdr.type = htons (message_type); + hdr.size = htons (sizeof (struct GNUNET_MessageHeader) + data_length); + if ( (GNUNET_OK != + write_all (&hdr, + sizeof (hdr))) || + (GNUNET_OK != + write_all (data, + data_length)) ) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Function called to (recursively) add all of the files in the + * directory to the tree. Called by the directory scanner to initiate + * the scan. Does NOT yet add any metadata. + * + * @param filename file or directory to scan + * @param dst where to store the resulting share tree item + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +preprocess_file (const char *filename, + struct ScanTreeNode **dst); + + +/** + * Closure for the 'scan_callback' + */ +struct RecursionContext +{ + /** + * Parent to add the files to. + */ + struct ScanTreeNode *parent; + + /** + * Flag to set to GNUNET_YES on serious errors. + */ + int stop; +}; + + +/** + * Function called by the directory iterator to (recursively) add all + * of the files in the directory to the tree. Called by the directory + * scanner to initiate the scan. Does NOT yet add any metadata. + * + * @param cls the 'struct RecursionContext' + * @param filename file or directory to scan + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +scan_callback (void *cls, + const char *filename) +{ + struct RecursionContext *rc = cls; + struct ScanTreeNode *chld; + + if (GNUNET_OK != + preprocess_file (filename, + &chld)) + { + rc->stop = GNUNET_YES; + return GNUNET_SYSERR; + } + chld->parent = rc->parent; + GNUNET_CONTAINER_DLL_insert (rc->parent->children_head, + rc->parent->children_tail, + chld); + return GNUNET_OK; +} + + +/** + * Function called to (recursively) add all of the files in the + * directory to the tree. Called by the directory scanner to initiate + * the scan. Does NOT yet add any metadata. + * + * @param filename file or directory to scan + * @param dst where to store the resulting share tree item + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +preprocess_file (const char *filename, + struct ScanTreeNode **dst) +{ + struct ScanTreeNode *item; + struct stat sbuf; + + if (0 != STAT (filename, &sbuf)) + { + /* If the file doesn't exist (or is not stat-able for any other reason) + skip it (but report it), but do continue. */ + if (GNUNET_OK != + write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE, + filename, strlen (filename) + 1)) + return GNUNET_SYSERR; + return GNUNET_OK; + } + + /* Report the progress */ + if (GNUNET_OK != + write_message (S_ISDIR (sbuf.st_mode) + ? GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY + : GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE, + filename, strlen (filename) + 1)) + return GNUNET_SYSERR; + item = GNUNET_malloc (sizeof (struct ScanTreeNode)); + item->filename = GNUNET_strdup (filename); + item->is_directory = (S_ISDIR (sbuf.st_mode)) ? GNUNET_YES : GNUNET_NO; + item->file_size = (uint64_t) sbuf.st_size; + if (item->is_directory == GNUNET_YES) + { + struct RecursionContext rc; + + rc.parent = item; + rc.stop = GNUNET_NO; + GNUNET_DISK_directory_scan (filename, + &scan_callback, + &rc); + if ( (rc.stop == GNUNET_YES) || + (GNUNET_OK != + write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY, + "..", 3)) ) + { + free_tree (item); + return GNUNET_SYSERR; + } + } + *dst = item; + return GNUNET_OK; +} + + +/** + * Extract metadata from files. + * + * @param item entry we are processing + * @return GNUNET_OK on success, GNUNET_SYSERR on fatal errors + */ +static int +extract_files (struct ScanTreeNode *item) +{ + struct GNUNET_CONTAINER_MetaData *meta; + ssize_t size; + size_t slen; + + if (item->is_directory == GNUNET_YES) + { + /* for directories, we simply only descent, no extraction, no + progress reporting */ + struct ScanTreeNode *pos; + + for (pos = item->children_head; NULL != pos; pos = pos->next) + if (GNUNET_OK != + extract_files (pos)) + return GNUNET_SYSERR; + return GNUNET_OK; + } + + /* this is the expensive operation, *afterwards* we'll check for aborts */ + meta = GNUNET_CONTAINER_meta_data_create (); + if (NULL != plugins) + EXTRACTOR_extract (plugins, item->filename, NULL, 0, &add_to_md, meta); + slen = strlen (item->filename) + 1; + size = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); + if (-1 == size) + { + /* no meta data */ + GNUNET_CONTAINER_meta_data_destroy (meta); + if (GNUNET_OK != + write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA, + item->filename, slen)) + return GNUNET_SYSERR; + return GNUNET_OK; + } + { + char buf[size + slen]; + char *dst = &buf[slen]; + + memcpy (buf, item->filename, slen); + size = GNUNET_CONTAINER_meta_data_serialize (meta, + &dst, size - slen, + GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); + GNUNET_CONTAINER_meta_data_destroy (meta); + if (GNUNET_OK != + write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA, + buf, + slen + size)) + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Main function of the helper process to extract meta data. + * + * @param argc should be 3 + * @param argv [0] our binary name + * [1] name of the file or directory to process + * [2] "-" to disable extraction, NULL for defaults, + * otherwise custom plugins to load from LE + * @return 0 on success + */ +int main(int argc, + char **argv) +{ + const char *filename_expanded; + const char *ex; + struct ScanTreeNode *root; + +#if WINDOWS + /* We're using stdout to communicate binary data back to the parent; use + * binary mode. + */ + _setmode (1, _O_BINARY); +#endif + + /* parse command line */ + if ( (argc != 3) && (argc != 2) ) + { + FPRINTF (stderr, + "%s", + "gnunet-helper-fs-publish needs exactly one or two arguments\n"); + return 1; + } + filename_expanded = argv[1]; + ex = argv[2]; + if ( (ex == NULL) || + (0 != strcmp (ex, "-")) ) + { + plugins = EXTRACTOR_plugin_add_defaults (EXTRACTOR_OPTION_DEFAULT_POLICY); + if (NULL != ex) + plugins = EXTRACTOR_plugin_add_config (plugins, ex, + EXTRACTOR_OPTION_DEFAULT_POLICY); + } + + /* scan tree to find out how much work there is to be done */ + if (GNUNET_OK != preprocess_file (filename_expanded, + &root)) + { + (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR, NULL, 0); + return 2; + } + /* signal that we're done counting files, so that a percentage of + progress can now be calculated */ + if (GNUNET_OK != + write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE, NULL, 0)) + return 3; + if (GNUNET_OK != + extract_files (root)) + { + (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR, NULL, 0); + free_tree (root); + return 4; + } + free_tree (root); + /* enable "clean" shutdown by telling parent that we are done */ + (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED, NULL, 0); + if (NULL != plugins) + EXTRACTOR_plugin_remove_all (plugins); + + return 0; +} + +/* end of gnunet-helper-fs-publish.c */ + diff --git a/src/fs/gnunet-pseudonym.c b/src/fs/gnunet-pseudonym.c new file mode 100644 index 0000000..412ddd2 --- /dev/null +++ b/src/fs/gnunet-pseudonym.c @@ -0,0 +1,312 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/gnunet-pseudonym.c + * @brief manage GNUnet namespaces / pseudonyms + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_fs_service.h" + +/** + * -C option + */ +static char *create_ns; + +/** + * -D option + */ +static char *delete_ns; + +/** + * -k option + */ +static struct GNUNET_FS_Uri *ksk_uri; + +/** + * -l option. + */ +static int print_local_only; + +/** + * -m option. + */ +static struct GNUNET_CONTAINER_MetaData *adv_metadata; + +/** + * Our block options (-p, -r, -a). + */ +static struct GNUNET_FS_BlockOptions bo = { {0LL}, 1, 365, 1 }; + +/** + * -q option given. + */ +static int no_remote_printing; + +/** + * -r option. + */ +static char *root_identifier; + +/** + * -s option. + */ +static char *rating_change; + +/** + * Handle to fs service. + */ +static struct GNUNET_FS_Handle *h; + +/** + * Namespace we are looking at. + */ +static struct GNUNET_FS_Namespace *ns; + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static int ret; + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) +{ + return NULL; +} + + +static void +ns_printer (void *cls, const char *name, const GNUNET_HashCode * id) +{ + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + + GNUNET_CRYPTO_hash_to_enc (id, &enc); + FPRINTF (stdout, "%s (%s)\n", name, (const char *) &enc); +} + + +static int +pseudo_printer (void *cls, const GNUNET_HashCode * pseudonym, + const struct GNUNET_CONTAINER_MetaData *md, int rating) +{ + char *id; + + id = GNUNET_PSEUDONYM_id_to_name (cfg, pseudonym); + if (id == NULL) + { + GNUNET_break (0); + return GNUNET_OK; + } + FPRINTF (stdout, "%s (%d):\n", id, rating); + GNUNET_CONTAINER_meta_data_iterate (md, &EXTRACTOR_meta_data_print, stdout); + FPRINTF (stdout, "%s", "\n"); + GNUNET_free (id); + return GNUNET_OK; +} + + +static void +post_advertising (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) +{ + GNUNET_HashCode nsid; + char *set; + int delta; + + if (emsg != NULL) + { + FPRINTF (stderr, "%s", emsg); + ret = 1; + } + if (ns != NULL) + { + if (GNUNET_OK != GNUNET_FS_namespace_delete (ns, GNUNET_NO)) + ret = 1; + } + if (NULL != rating_change) + { + set = rating_change; + while ((*set != '\0') && (*set != ':')) + set++; + if (*set != ':') + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Invalid argument `%s'\n"), + rating_change); + } + else + { + *set = '\0'; + delta = strtol (&set[1], NULL, /* no error handling yet */ + 10); + if (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, rating_change, &nsid)) + { + (void) GNUNET_PSEUDONYM_rank (cfg, &nsid, delta); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Namespace `%s' unknown.\n"), + rating_change); + } + } + GNUNET_free (rating_change); + rating_change = NULL; + } + if (0 != print_local_only) + { + GNUNET_FS_namespace_list (h, &ns_printer, NULL); + } + else if (0 == no_remote_printing) + { + GNUNET_PSEUDONYM_list_all (cfg, &pseudo_printer, NULL); + } + GNUNET_FS_stop (h); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + char *emsg; + + cfg = c; + h = GNUNET_FS_start (cfg, "gnunet-pseudonym", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + if (NULL != delete_ns) + { + ns = GNUNET_FS_namespace_create (h, delete_ns); + if (ns == NULL) + { + ret = 1; + } + else + { + if (GNUNET_OK != GNUNET_FS_namespace_delete (ns, GNUNET_YES)) + ret = 1; + ns = NULL; + } + } + if (NULL != create_ns) + { + ns = GNUNET_FS_namespace_create (h, create_ns); + if (ns == NULL) + { + ret = 1; + } + else + { + if (NULL != root_identifier) + { + if (ksk_uri == NULL) + { + emsg = NULL; + ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/namespace", &emsg); + GNUNET_assert (NULL == emsg); + } + GNUNET_FS_namespace_advertise (h, ksk_uri, ns, adv_metadata, &bo, + root_identifier, &post_advertising, + NULL); + return; + } + else + { + if (ksk_uri != NULL) + FPRINTF (stderr, _("Option `%s' ignored\n"), "-k"); + } + } + } + else + { + if (root_identifier != NULL) + FPRINTF (stderr, _("Option `%s' ignored\n"), "-r"); + if (ksk_uri != NULL) + FPRINTF (stderr, _("Option `%s' ignored\n"), "-k"); + } + + post_advertising (NULL, NULL, NULL); +} + + +/** + * The main function to manipulate GNUnet pseudonyms (and publish + * to namespaces). + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'a', "anonymity", "LEVEL", + gettext_noop ("set the desired LEVEL of sender-anonymity"), + 1, &GNUNET_GETOPT_set_uint, &bo.anonymity_level}, + {'C', "create", "NAME", + gettext_noop ("create or advertise namespace NAME"), + 1, &GNUNET_GETOPT_set_string, &create_ns}, + {'D', "delete", "NAME", + gettext_noop ("delete namespace NAME "), + 1, &GNUNET_GETOPT_set_string, &delete_ns}, + {'k', "keyword", "VALUE", + gettext_noop ("add an additional keyword for the advertisment" + " (this option can be specified multiple times)"), + 1, &GNUNET_FS_getopt_set_keywords, &ksk_uri}, + {'m', "meta", "TYPE:VALUE", + gettext_noop ("set the meta-data for the given TYPE to the given VALUE"), + 1, &GNUNET_FS_getopt_set_metadata, &adv_metadata}, + {'o', "only-local", NULL, + gettext_noop ("print names of local namespaces"), + 0, &GNUNET_GETOPT_set_one, &print_local_only}, + {'p', "priority", "PRIORITY", + gettext_noop ("use the given PRIORITY for the advertisments"), + 1, &GNUNET_GETOPT_set_uint, &bo.content_priority}, + {'q', "quiet", NULL, + gettext_noop ("do not print names of remote namespaces"), + 0, &GNUNET_GETOPT_set_one, &no_remote_printing}, + {'r', "replication", "LEVEL", + gettext_noop ("set the desired replication LEVEL"), + 1, &GNUNET_GETOPT_set_uint, &bo.replication_level}, + {'R', "root", "ID", + gettext_noop ("specify ID of the root of the namespace"), + 1, &GNUNET_GETOPT_set_string, &root_identifier}, + {'s', "set-rating", "ID:VALUE", + gettext_noop ("change rating of namespace ID by VALUE"), + 1, &GNUNET_GETOPT_set_string, &rating_change}, + GNUNET_GETOPT_OPTION_END + }; + bo.expiration_time = + GNUNET_FS_year_to_time (GNUNET_FS_get_current_year () + 2); + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-pseudonym [OPTIONS]", + gettext_noop ("Manage GNUnet pseudonyms."), + options, &run, NULL)) ? ret : 1; +} + +/* end of gnunet-pseudonym.c */ diff --git a/src/fs/gnunet-publish.c b/src/fs/gnunet-publish.c new file mode 100644 index 0000000..50f507d --- /dev/null +++ b/src/fs/gnunet-publish.c @@ -0,0 +1,740 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/gnunet-publish.c + * @brief publishing files on GNUnet + * @author Christian Grothoff + * @author Krista Bennett + * @author James Blackwell + * @author Igor Wronsky + */ +#include "platform.h" +#include "gnunet_fs_service.h" + +static int ret; + +static int verbose; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_FS_Handle *ctx; + +static struct GNUNET_FS_PublishContext *pc; + +static struct GNUNET_CONTAINER_MetaData *meta; + +static struct GNUNET_FS_Uri *topKeywords; + +static struct GNUNET_FS_Uri *uri; + +static struct GNUNET_FS_BlockOptions bo = { {0LL}, 1, 365, 1 }; + +static char *uri_string; + +static char *next_id; + +static char *this_id; + +static char *pseudonym; + +static int do_insert; + +static int disable_extractor; + +static int do_simulate; + +static int extract_only; + +static int do_disable_creation_time; + +static GNUNET_SCHEDULER_TaskIdentifier kill_task; + +static struct GNUNET_FS_DirScanner *ds; + +static struct GNUNET_FS_ShareTreeItem * directory_scan_result; + +static struct GNUNET_FS_Namespace *namespace; + +/** + * FIXME: docu + */ +static void +do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_PublishContext *p; + + kill_task = GNUNET_SCHEDULER_NO_TASK; + if (pc != NULL) + { + p = pc; + pc = NULL; + GNUNET_FS_publish_stop (p); + } + if (NULL != meta) + { + GNUNET_CONTAINER_meta_data_destroy (meta); + meta = NULL; + } +} + + +/** + * Stop the directory scanner (we had an error). + * + * @param cls closure + * @param tc scheduler context + */ +static void +stop_scanner_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + kill_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_FS_directory_scan_abort (ds); + ds = NULL; + if (namespace != NULL) + { + GNUNET_FS_namespace_delete (namespace, GNUNET_NO); + namespace = NULL; + } + GNUNET_FS_stop (ctx); + ctx = NULL; + ret = 1; +} + + +/** + * Called by FS client to give information about the progress of an + * operation. + * + * @param cls closure + * @param info details about the event, specifying the event type + * and various bits about the event + * @return client-context (for the next progress call + * for this operation; should be set to NULL for + * SUSPEND and STOPPED events). The value returned + * will be passed to future callbacks in the respective + * field in the GNUNET_FS_ProgressInfo struct. + */ +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) +{ + char *s; + + switch (info->status) + { + case GNUNET_FS_STATUS_PUBLISH_START: + break; + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: + if (verbose) + { + s = GNUNET_STRINGS_relative_time_to_string (info->value.publish.eta); + FPRINTF (stdout, _("Publishing `%s' at %llu/%llu (%s remaining)\n"), + info->value.publish.filename, + (unsigned long long) info->value.publish.completed, + (unsigned long long) info->value.publish.size, s); + GNUNET_free (s); + } + break; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + FPRINTF (stderr, _("Error publishing: %s.\n"), + info->value.publish.specifics.error.message); + if (kill_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + } + kill_task = GNUNET_SCHEDULER_add_now (&do_stop_task, NULL); + break; + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + FPRINTF (stdout, _("Publishing `%s' done.\n"), + info->value.publish.filename); + s = GNUNET_FS_uri_to_string (info->value.publish.specifics. + completed.chk_uri); + FPRINTF (stdout, _("URI is `%s'.\n"), s); + GNUNET_free (s); + if (info->value.publish.pctx == NULL) + { + if (kill_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + } + kill_task = GNUNET_SCHEDULER_add_now (&do_stop_task, NULL); + } + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + GNUNET_break (NULL == pc); + return NULL; + case GNUNET_FS_STATUS_UNINDEX_PROGRESS: + return NULL; + case GNUNET_FS_STATUS_UNINDEX_COMPLETED: + FPRINTF (stderr, "%s", _("Cleanup after abort complete.\n")); + return NULL; + default: + FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); + return NULL; + } + return ""; /* non-null */ +} + + +/** + * Print metadata entries (except binary + * metadata and the filename). + * + * @param cls closure + * @param plugin_name name of the plugin that generated the meta data + * @param type type of the meta data + * @param format format of data + * @param data_mime_type mime type of data + * @param data value of the meta data + * @param data_size number of bytes in data + * @return always 0 + */ +static int +meta_printer (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, + enum EXTRACTOR_MetaFormat format, const char *data_mime_type, + const char *data, size_t data_size) +{ + if ((format != EXTRACTOR_METAFORMAT_UTF8) && + (format != EXTRACTOR_METAFORMAT_C_STRING)) + return 0; + if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) + return 0; + FPRINTF (stdout, "\t%s - %s\n", EXTRACTOR_metatype_to_string (type), data); + return 0; +} + + +/** + * Iterator printing keywords + * + * @param cls closure + * @param keyword the keyword + * @param is_mandatory is the keyword mandatory (in a search) + * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort + */ +static int +keyword_printer (void *cls, const char *keyword, int is_mandatory) +{ + FPRINTF (stdout, "\t%s\n", keyword); + return GNUNET_OK; +} + + +/** + * Function called on all entries before the publication. This is + * where we perform modifications to the default based on command-line + * options. + * + * @param cls closure + * @param fi the entry in the publish-structure + * @param length length of the file or directory + * @param m metadata for the file or directory (can be modified) + * @param uri pointer to the keywords that will be used for this entry (can be modified) + * @param bo block options + * @param do_index should we index? + * @param client_info pointer to client context set upon creation (can be modified) + * @return GNUNET_OK to continue, GNUNET_NO to remove + * this entry from the directory, GNUNET_SYSERR + * to abort the iteration + */ +static int +publish_inspector (void *cls, struct GNUNET_FS_FileInformation *fi, + uint64_t length, struct GNUNET_CONTAINER_MetaData *m, + struct GNUNET_FS_Uri **uri, + struct GNUNET_FS_BlockOptions *bo, int *do_index, + void **client_info) +{ + char *fn; + char *fs; + struct GNUNET_FS_Uri *new_uri; + + if (cls == fi) + return GNUNET_OK; + if (NULL != topKeywords) + { + if (*uri != NULL) + { + new_uri = GNUNET_FS_uri_ksk_merge (topKeywords, *uri); + GNUNET_FS_uri_destroy (*uri); + *uri = new_uri; + GNUNET_FS_uri_destroy (topKeywords); + } + else + { + *uri = topKeywords; + } + topKeywords = NULL; + } + if (NULL != meta) + { + GNUNET_CONTAINER_meta_data_merge (m, meta); + GNUNET_CONTAINER_meta_data_destroy (meta); + meta = NULL; + } + if (!do_disable_creation_time) + GNUNET_CONTAINER_meta_data_add_publication_date (m); + if (extract_only) + { + fn = GNUNET_CONTAINER_meta_data_get_by_type (m, + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); + fs = GNUNET_STRINGS_byte_size_fancy (length); + FPRINTF (stdout, _("Meta data for file `%s' (%s)\n"), fn, fs); + GNUNET_CONTAINER_meta_data_iterate (m, &meta_printer, NULL); + FPRINTF (stdout, _("Keywords for file `%s' (%s)\n"), fn, fs); + GNUNET_free (fn); + GNUNET_free (fs); + if (NULL != *uri) + GNUNET_FS_uri_ksk_get_keywords (*uri, &keyword_printer, NULL); + FPRINTF (stdout, "%s", "\n"); + } + if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (m)) + GNUNET_FS_file_information_inspect (fi, &publish_inspector, fi); + return GNUNET_OK; +} + + +/** + * FIXME: docu + */ +static void +uri_sks_continuation (void *cls, const struct GNUNET_FS_Uri *ksk_uri, + const char *emsg) +{ + if (emsg != NULL) + { + FPRINTF (stderr, "%s\n", emsg); + ret = 1; + } + GNUNET_FS_uri_destroy (uri); + uri = NULL; + GNUNET_FS_stop (ctx); + ctx = NULL; +} + + +/** + * FIXME: docu + */ +static void +uri_ksk_continuation (void *cls, const struct GNUNET_FS_Uri *ksk_uri, + const char *emsg) +{ + struct GNUNET_FS_Namespace *ns; + + if (emsg != NULL) + { + FPRINTF (stderr, "%s\n", emsg); + ret = 1; + } + if (pseudonym != NULL) + { + ns = GNUNET_FS_namespace_create (ctx, pseudonym); + if (ns == NULL) + { + FPRINTF (stderr, _("Failed to create namespace `%s'\n"), pseudonym); + ret = 1; + } + else + { + GNUNET_FS_publish_sks (ctx, ns, this_id, next_id, meta, uri, &bo, + GNUNET_FS_PUBLISH_OPTION_NONE, + &uri_sks_continuation, NULL); + GNUNET_assert (GNUNET_OK == GNUNET_FS_namespace_delete (ns, GNUNET_NO)); + return; + } + } + GNUNET_FS_uri_destroy (uri); + uri = NULL; + GNUNET_FS_stop (ctx); + ctx = NULL; +} + + +/** + * FIXME: docu + */ +static struct GNUNET_FS_FileInformation * +get_file_information (struct GNUNET_FS_ShareTreeItem *item) +{ + struct GNUNET_FS_FileInformation *fi; + struct GNUNET_FS_FileInformation *fic; + struct GNUNET_FS_ShareTreeItem *child; + + if (item->is_directory == GNUNET_YES) + { + GNUNET_CONTAINER_meta_data_delete (item->meta, + EXTRACTOR_METATYPE_MIMETYPE, NULL, 0); + GNUNET_FS_meta_data_make_directory (item->meta); + if (NULL == item->ksk_uri) + { + const char *mime = GNUNET_FS_DIRECTORY_MIME; + item->ksk_uri = GNUNET_FS_uri_ksk_create_from_args (1, &mime); + } + else + GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri, GNUNET_FS_DIRECTORY_MIME, + GNUNET_NO); + fi = GNUNET_FS_file_information_create_empty_directory ( + ctx, NULL, item->ksk_uri, + item->meta, &bo, item->filename); + for (child = item->children_head; child; child = child->next) + { + fic = get_file_information (child); + GNUNET_break (GNUNET_OK == GNUNET_FS_file_information_add (fi, fic)); + } + } + else + { + fi = GNUNET_FS_file_information_create_from_file ( + ctx, NULL, item->filename, + item->ksk_uri, item->meta, !do_insert, + &bo); + } + return fi; +} + + +/** + * FIXME: docu + */ +static void +directory_trim_complete () +{ + struct GNUNET_FS_FileInformation *fi; + + fi = get_file_information (directory_scan_result); + GNUNET_FS_share_tree_free (directory_scan_result); + directory_scan_result = NULL; + if (fi == NULL) + { + FPRINTF (stderr, "%s", _("Could not publish\n")); + if (namespace != NULL) + GNUNET_FS_namespace_delete (namespace, GNUNET_NO); + GNUNET_FS_stop (ctx); + ret = 1; + return; + } + GNUNET_FS_file_information_inspect (fi, &publish_inspector, NULL); + if (extract_only) + { + if (namespace != NULL) + GNUNET_FS_namespace_delete (namespace, GNUNET_NO); + GNUNET_FS_file_information_destroy (fi, NULL, NULL); + GNUNET_FS_stop (ctx); + if (kill_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + } + return; + } + pc = GNUNET_FS_publish_start (ctx, fi, namespace, this_id, next_id, + (do_simulate) ? + GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY : + GNUNET_FS_PUBLISH_OPTION_NONE); + if (NULL == pc) + { + FPRINTF (stderr, "%s", _("Could not start publishing.\n")); + GNUNET_FS_stop (ctx); + ret = 1; + return; + } +} + + +/** + * Function called by the directory scanner as we build the tree + * that we will need to publish later. + * + * @param cls closure + * @param filename which file we are making progress on + * @param is_directory GNUNET_YES if this is a directory, + * GNUNET_NO if this is a file + * GNUNET_SYSERR if it is neither (or unknown) + * @param reason kind of progress we are making + */ +static void +directory_scan_cb (void *cls, + const char *filename, + int is_directory, + enum GNUNET_FS_DirScannerProgressUpdateReason reason) +{ + switch (reason) + { + case GNUNET_FS_DIRSCANNER_FILE_START: + if (verbose > 1) + { + if (is_directory == GNUNET_YES) + FPRINTF (stdout, _("Scanning directory `%s'.\n"), filename); + else + FPRINTF (stdout, _("Scanning file `%s'.\n"), filename); + } + break; + case GNUNET_FS_DIRSCANNER_FILE_IGNORED: + FPRINTF (stderr, + _("There was trouble processing file `%s', skipping it.\n"), + filename); + break; + case GNUNET_FS_DIRSCANNER_ALL_COUNTED: + if (verbose) + FPRINTF (stdout, "%s", _("Preprocessing complete.\n")); + break; + case GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED: + if (verbose > 2) + FPRINTF (stdout, _("Extracting meta data from file `%s' complete.\n"), filename); + break; + case GNUNET_FS_DIRSCANNER_FINISHED: + if (verbose > 1) + FPRINTF (stdout, "%s", _("Meta data extraction has finished.\n")); + directory_scan_result = GNUNET_FS_directory_scan_get_result (ds); + ds = NULL; + GNUNET_FS_share_tree_trim (directory_scan_result); + directory_trim_complete (); + break; + case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR: + FPRINTF (stdout, "%s", _("Internal error scanning directory.\n")); + if (kill_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (kill_task); + kill_task = GNUNET_SCHEDULER_NO_TASK; + } + kill_task = GNUNET_SCHEDULER_add_now (&stop_scanner_task, NULL); + break; + default: + GNUNET_assert (0); + break; + } + fflush (stdout); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + char *ex; + char *emsg; + + /* check arguments */ + if ((uri_string != NULL) && (extract_only)) + { + printf (_("Cannot extract metadata from a URI!\n")); + ret = -1; + return; + } + if (((uri_string == NULL) || (extract_only)) && + ((args[0] == NULL) || (args[1] != NULL))) + { + printf (_("You must specify one and only one filename for insertion.\n")); + ret = -1; + return; + } + if ((uri_string != NULL) && (args[0] != NULL)) + { + printf (_("You must NOT specify an URI and a filename.\n")); + ret = -1; + return; + } + if (pseudonym != NULL) + { + if (NULL == this_id) + { + FPRINTF (stderr, _("Option `%s' is required when using option `%s'.\n"), + "-t", "-P"); + ret = -1; + return; + } + } + else + { /* ordinary insertion checks */ + if (NULL != next_id) + { + FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"), + "-N", "-P"); + ret = -1; + return; + } + if (NULL != this_id) + { + FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"), + "-t", "-P"); + ret = -1; + return; + } + } + cfg = c; + ctx = + GNUNET_FS_start (cfg, "gnunet-publish", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + if (NULL == ctx) + { + FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS"); + ret = 1; + return; + } + namespace = NULL; + if (NULL != pseudonym) + { + namespace = GNUNET_FS_namespace_create (ctx, pseudonym); + if (NULL == namespace) + { + FPRINTF (stderr, _("Could not create namespace `%s'\n"), pseudonym); + GNUNET_FS_stop (ctx); + ret = 1; + return; + } + } + if (NULL != uri_string) + { + emsg = NULL; + uri = GNUNET_FS_uri_parse (uri_string, &emsg); + if (uri == NULL) + { + FPRINTF (stderr, _("Failed to parse URI: %s\n"), emsg); + GNUNET_free (emsg); + if (namespace != NULL) + GNUNET_FS_namespace_delete (namespace, GNUNET_NO); + GNUNET_FS_stop (ctx); + ret = 1; + return; + } + GNUNET_FS_publish_ksk (ctx, topKeywords, meta, uri, &bo, + GNUNET_FS_PUBLISH_OPTION_NONE, &uri_ksk_continuation, + NULL); + if (namespace != NULL) + GNUNET_FS_namespace_delete (namespace, GNUNET_NO); + return; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "FS", "EXTRACTORS", &ex)) + ex = NULL; + if (0 != ACCESS (args[0], R_OK)) + { + FPRINTF (stderr, + _("Failed to access `%s': %s\n"), + args[0], + STRERROR (errno)); + return; + } + ds = GNUNET_FS_directory_scan_start (args[0], + disable_extractor, + ex, + &directory_scan_cb, NULL); + if (NULL == ds) + { + FPRINTF (stderr, + "%s", _("Failed to start meta directory scanner. Is gnunet-helper-publish-fs installed?\n")); + return; + } + kill_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_stop_task, + NULL); +} + + +/** + * The main function to publish content to GNUnet. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'a', "anonymity", "LEVEL", + gettext_noop ("set the desired LEVEL of sender-anonymity"), + 1, &GNUNET_GETOPT_set_uint, &bo.anonymity_level}, + {'d', "disable-creation-time", NULL, + gettext_noop + ("disable adding the creation time to the metadata of the uploaded file"), + 0, &GNUNET_GETOPT_set_one, &do_disable_creation_time}, + {'D', "disable-extractor", NULL, + gettext_noop ("do not use libextractor to add keywords or metadata"), + 0, &GNUNET_GETOPT_set_one, &disable_extractor}, + {'e', "extract", NULL, + gettext_noop + ("print list of extracted keywords that would be used, but do not perform upload"), + 0, &GNUNET_GETOPT_set_one, &extract_only}, + {'k', "key", "KEYWORD", + gettext_noop + ("add an additional keyword for the top-level file or directory" + " (this option can be specified multiple times)"), + 1, &GNUNET_FS_getopt_set_keywords, &topKeywords}, + {'m', "meta", "TYPE:VALUE", + gettext_noop ("set the meta-data for the given TYPE to the given VALUE"), + 1, &GNUNET_FS_getopt_set_metadata, &meta}, + {'n', "noindex", NULL, + gettext_noop ("do not index, perform full insertion (stores entire " + "file in encrypted form in GNUnet database)"), + 0, &GNUNET_GETOPT_set_one, &do_insert}, + {'N', "next", "ID", + gettext_noop + ("specify ID of an updated version to be published in the future" + " (for namespace insertions only)"), + 1, &GNUNET_GETOPT_set_string, &next_id}, + {'p', "priority", "PRIORITY", + gettext_noop ("specify the priority of the content"), + 1, &GNUNET_GETOPT_set_uint, &bo.content_priority}, + {'P', "pseudonym", "NAME", + gettext_noop + ("publish the files under the pseudonym NAME (place file into namespace)"), + 1, &GNUNET_GETOPT_set_string, &pseudonym}, + {'r', "replication", "LEVEL", + gettext_noop ("set the desired replication LEVEL"), + 1, &GNUNET_GETOPT_set_uint, &bo.replication_level}, + {'s', "simulate-only", NULL, + gettext_noop ("only simulate the process but do not do any " + "actual publishing (useful to compute URIs)"), + 0, &GNUNET_GETOPT_set_one, &do_simulate}, + {'t', "this", "ID", + gettext_noop ("set the ID of this version of the publication" + " (for namespace insertions only)"), + 1, &GNUNET_GETOPT_set_string, &this_id}, + {'u', "uri", "URI", + gettext_noop ("URI to be published (can be used instead of passing a " + "file to add keywords to the file with the respective URI)"), + 1, &GNUNET_GETOPT_set_string, &uri_string}, + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END + }; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "GNUnet publish starts\n"); + bo.expiration_time = + GNUNET_FS_year_to_time (GNUNET_FS_get_current_year () + 2); + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-publish [OPTIONS] FILENAME", + gettext_noop + ("Publish a file or directory on GNUnet"), + options, &run, NULL)) ? ret : 1; +} + +/* end of gnunet-publish.c */ diff --git a/src/fs/gnunet-search.c b/src/fs/gnunet-search.c new file mode 100644 index 0000000..60620a4 --- /dev/null +++ b/src/fs/gnunet-search.c @@ -0,0 +1,312 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/gnunet-search.c + * @brief searching for files on GNUnet + * @author Christian Grothoff + * @author Krista Bennett + * @author James Blackwell + * @author Igor Wronsky + */ +#include "platform.h" +#include "gnunet_fs_service.h" + +static int ret; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_FS_Handle *ctx; + +static struct GNUNET_FS_SearchContext *sc; + +static char *output_filename; + +static struct GNUNET_FS_DirectoryBuilder *db; + +static unsigned int anonymity = 1; + +static unsigned long long timeout; + +static unsigned int results_limit; + +static unsigned int results = 0; + +static int verbose; + +static int local_only; + +/** + * Type of a function that libextractor calls for each + * meta data item found. + * + * @param cls closure (user-defined, unused) + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_size number of bytes in data + * @return 0 to continue extracting, 1 to abort + */ +static int +item_printer (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, + enum EXTRACTOR_MetaFormat format, const char *data_mime_type, + const char *data, size_t data_size) +{ + if ((format != EXTRACTOR_METAFORMAT_UTF8) && + (format != EXTRACTOR_METAFORMAT_C_STRING)) + return 0; + if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) + return 0; + printf ("\t%20s: %s\n", + dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, + EXTRACTOR_metatype_to_string (type)), data); + return 0; +} + + +static void +clean_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + size_t dsize; + void *ddata; + + GNUNET_FS_stop (ctx); + ctx = NULL; + if (output_filename == NULL) + return; + if (GNUNET_OK != GNUNET_FS_directory_builder_finish (db, &dsize, &ddata)) + { + GNUNET_break (0); + GNUNET_free (output_filename); + return; + } + if (dsize != + GNUNET_DISK_fn_write (output_filename, ddata, dsize, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)) + { + FPRINTF (stderr, + _("Failed to write directory with search results to `%s'\n"), + output_filename); + } + GNUNET_free_non_null (ddata); + GNUNET_free (output_filename); +} + + +/** + * Called by FS client to give information about the progress of an + * operation. + * + * @param cls closure + * @param info details about the event, specifying the event type + * and various bits about the event + * @return client-context (for the next progress call + * for this operation; should be set to NULL for + * SUSPEND and STOPPED events). The value returned + * will be passed to future callbacks in the respective + * field in the GNUNET_FS_ProgressInfo struct. + */ +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) +{ + static unsigned int cnt; + char *uri; + char *dotdot; + char *filename; + + switch (info->status) + { + case GNUNET_FS_STATUS_SEARCH_START: + break; + case GNUNET_FS_STATUS_SEARCH_RESULT: + if (db != NULL) + GNUNET_FS_directory_builder_add (db, + info->value.search.specifics.result.uri, + info->value.search.specifics.result.meta, + NULL); + uri = GNUNET_FS_uri_to_string (info->value.search.specifics.result.uri); + printf ("#%u:\n", cnt++); + filename = + GNUNET_CONTAINER_meta_data_get_by_type (info->value.search. + specifics.result.meta, + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); + if (filename != NULL) + { + while (NULL != (dotdot = strstr (filename, ".."))) + dotdot[0] = dotdot[1] = '_'; + printf ("gnunet-download -o \"%s\" %s\n", filename, uri); + } + else + printf ("gnunet-download %s\n", uri); + if (verbose) + GNUNET_CONTAINER_meta_data_iterate (info->value.search.specifics. + result.meta, &item_printer, NULL); + printf ("\n"); + fflush (stdout); + GNUNET_free_non_null (filename); + GNUNET_free (uri); + results++; + if ((results_limit > 0) && (results >= results_limit)) + GNUNET_SCHEDULER_shutdown (); + break; + case GNUNET_FS_STATUS_SEARCH_UPDATE: + break; + case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: + /* ignore */ + break; + case GNUNET_FS_STATUS_SEARCH_ERROR: + FPRINTF (stderr, _("Error searching: %s.\n"), + info->value.search.specifics.error.message); + GNUNET_SCHEDULER_shutdown (); + break; + case GNUNET_FS_STATUS_SEARCH_STOPPED: + GNUNET_SCHEDULER_add_continuation (&clean_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + default: + FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); + break; + } + return NULL; +} + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (sc != NULL) + { + GNUNET_FS_search_stop (sc); + sc = NULL; + } +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + struct GNUNET_FS_Uri *uri; + unsigned int argc; + enum GNUNET_FS_SearchOptions options; + struct GNUNET_TIME_Relative delay; + + argc = 0; + while (NULL != args[argc]) + argc++; + uri = GNUNET_FS_uri_ksk_create_from_args (argc, (const char **) args); + if (NULL == uri) + { + FPRINTF (stderr, "%s", _("Could not create keyword URI from arguments.\n")); + ret = 1; + return; + } + cfg = c; + ctx = + GNUNET_FS_start (cfg, "gnunet-search", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + if (NULL == ctx) + { + FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS"); + GNUNET_FS_uri_destroy (uri); + ret = 1; + return; + } + if (output_filename != NULL) + db = GNUNET_FS_directory_builder_create (NULL); + options = GNUNET_FS_SEARCH_OPTION_NONE; + if (local_only) + options |= GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY; + sc = GNUNET_FS_search_start (ctx, uri, anonymity, options, NULL); + GNUNET_FS_uri_destroy (uri); + if (NULL == sc) + { + FPRINTF (stderr, "%s", _("Could not start searching.\n")); + GNUNET_FS_stop (ctx); + ret = 1; + return; + } + if (timeout != 0) + { + delay.rel_value = timeout; + GNUNET_SCHEDULER_add_delayed (delay, &shutdown_task, NULL); + } + else + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + } +} + + +/** + * The main function to search GNUnet. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'a', "anonymity", "LEVEL", + gettext_noop ("set the desired LEVEL of receiver-anonymity"), + 1, &GNUNET_GETOPT_set_uint, &anonymity}, + {'n', "no-network", NULL, + gettext_noop ("only search the local peer (no P2P network search)"), + 0, &GNUNET_GETOPT_set_one, &local_only}, + {'o', "output", "PREFIX", + gettext_noop ("write search results to file starting with PREFIX"), + 1, &GNUNET_GETOPT_set_string, &output_filename}, + {'t', "timeout", "VALUE", + gettext_noop ("automatically terminate search after VALUE ms"), + 1, &GNUNET_GETOPT_set_ulong, &timeout}, + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + {'N', "results", "VALUE", + gettext_noop + ("automatically terminate search after VALUE results are found"), + 1, &GNUNET_GETOPT_set_uint, &results_limit}, + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-search [OPTIONS] KEYWORD", + gettext_noop + ("Search GNUnet for files that were published on GNUnet"), + options, &run, NULL)) ? ret : 1; +} + +/* end of gnunet-search.c */ diff --git a/src/fs/gnunet-service-fs.c b/src/fs/gnunet-service-fs.c new file mode 100644 index 0000000..06ac91c --- /dev/null +++ b/src/fs/gnunet-service-fs.c @@ -0,0 +1,654 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs.c + * @brief gnunet anonymity protocol implementation + * @author Christian Grothoff + * + * To use: + * - consider re-issue GSF_dht_lookup_ after non-DHT reply received + */ +#include "platform.h" +#include +#include "gnunet_constants.h" +#include "gnunet_core_service.h" +#include "gnunet_dht_service.h" +#include "gnunet_datastore_service.h" +#include "gnunet_load_lib.h" +#include "gnunet_peer_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_signatures.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_util_lib.h" +#include "gnunet-service-fs_cp.h" +#include "gnunet-service-fs_indexing.h" +#include "gnunet-service-fs_lc.h" +#include "gnunet-service-fs_pe.h" +#include "gnunet-service-fs_pr.h" +#include "gnunet-service-fs_push.h" +#include "gnunet-service-fs_put.h" +#include "fs.h" + +/** + * Size for the hash map for DHT requests from the FS + * service. Should be about the number of concurrent + * DHT requests we plan to make. + */ +#define FS_DHT_HT_SIZE 1024 + + +/** + * How quickly do we age cover traffic? At the given + * time interval, remaining cover traffic counters are + * decremented by 1/16th. + */ +#define COVER_AGE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + + +/* ****************************** globals ****************************** */ + +/** + * Our connection to the datastore. + */ +struct GNUNET_DATASTORE_Handle *GSF_dsh; + +/** + * Our configuration. + */ +const struct GNUNET_CONFIGURATION_Handle *GSF_cfg; + +/** + * Handle for reporting statistics. + */ +struct GNUNET_STATISTICS_Handle *GSF_stats; + +/** + * Handle for DHT operations. + */ +struct GNUNET_DHT_Handle *GSF_dht; + +/** + * How long do requests typically stay in the routing table? + */ +struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime; + +/** + * Running average of the observed latency to other peers (round trip). + * Initialized to 5s as the initial default. + */ +struct GNUNET_TIME_Relative GSF_avg_latency = { 500 }; + +/** + * Typical priorities we're seeing from other peers right now. Since + * most priorities will be zero, this value is the weighted average of + * non-zero priorities seen "recently". In order to ensure that new + * values do not dramatically change the ratio, values are first + * "capped" to a reasonable range (+N of the current value) and then + * averaged into the existing value by a ratio of 1:N. Hence + * receiving the largest possible priority can still only raise our + * "current_priorities" by at most 1. + */ +double GSF_current_priorities; + +/** + * How many query messages have we received 'recently' that + * have not yet been claimed as cover traffic? + */ +unsigned int GSF_cover_query_count; + +/** + * How many content messages have we received 'recently' that + * have not yet been claimed as cover traffic? + */ +unsigned int GSF_cover_content_count; + +/** + * Our block context. + */ +struct GNUNET_BLOCK_Context *GSF_block_ctx; + +/** + * Pointer to handle to the core service (points to NULL until we've + * connected to it). + */ +struct GNUNET_CORE_Handle *GSF_core; + +/** + * Are we introducing randomized delays for better anonymity? + */ +int GSF_enable_randomized_delays; + +/* ***************************** locals ******************************* */ + +/** + * Configuration for block library. + */ +static struct GNUNET_CONFIGURATION_Handle *block_cfg; + +/** + * ID of our task that we use to age the cover counters. + */ +static GNUNET_SCHEDULER_TaskIdentifier cover_age_task; + +/** + * Datastore 'GET' load tracking. + */ +static struct GNUNET_LOAD_Value *datastore_get_load; + +/** + * Identity of this peer. + */ +static struct GNUNET_PeerIdentity my_id; + +/** + * Task that periodically ages our cover traffic statistics. + * + * @param cls unused closure + * @param tc task context + */ +static void +age_cover_counters (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GSF_cover_content_count = (GSF_cover_content_count * 15) / 16; + GSF_cover_query_count = (GSF_cover_query_count * 15) / 16; + cover_age_task = + GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY, &age_cover_counters, + NULL); +} + + +/** + * We've just now completed a datastore request. Update our + * datastore load calculations. + * + * @param start time when the datastore request was issued + */ +void +GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start) +{ + struct GNUNET_TIME_Relative delay; + + delay = GNUNET_TIME_absolute_get_duration (start); + GNUNET_LOAD_update (datastore_get_load, delay.rel_value); +} + + +/** + * Test if the DATABASE (GET) load on this peer is too high + * to even consider processing the query at + * all. + * + * @return GNUNET_YES if the load is too high to do anything (load high) + * GNUNET_NO to process normally (load normal) + * GNUNET_SYSERR to process for free (load low) + */ +int +GSF_test_get_load_too_high_ (uint32_t priority) +{ + double ld; + + ld = GNUNET_LOAD_get_load (datastore_get_load); + if (ld < 1) + return GNUNET_SYSERR; + if (ld <= priority) + return GNUNET_NO; + return GNUNET_YES; +} + + +/** + * We've received peer performance information. Update + * our running average for the P2P latency. + * + * @param atsi performance information + * @param atsi_count number of 'atsi' records + */ +static void +update_latencies (const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + unsigned int i; + + for (i = 0; i < atsi_count; i++) + { + if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DELAY) + { + GSF_avg_latency.rel_value = + (GSF_avg_latency.rel_value * 31 + + GNUNET_MIN (5000, ntohl (atsi[i].value))) / 32; + GNUNET_STATISTICS_set (GSF_stats, + gettext_noop + ("# running average P2P latency (ms)"), + GSF_avg_latency.rel_value, GNUNET_NO); + break; + } + } +} + + +/** + * Handle P2P "PUT" message. + * + * @param cls closure, always NULL + * @param other the other peer involved (sender or receiver, NULL + * for loopback messages where we are both sender and receiver) + * @param message the actual message + * @param atsi performance information + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_p2p_put (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GSF_ConnectedPeer *cp; + + cp = GSF_peer_get_ (other); + if (NULL == cp) + { + GNUNET_break (0); + return GNUNET_OK; + } + GSF_cover_content_count++; + update_latencies (atsi, atsi_count); + return GSF_handle_p2p_content_ (cp, message); +} + + +/** + * We have a new request, consider forwarding it to the given + * peer. + * + * @param cls the 'struct GSF_PendingRequest' + * @param peer identity of the peer + * @param cp handle to the connected peer record + * @param ppd peer performance data + */ +static void +consider_request_for_forwarding (void *cls, + const struct GNUNET_PeerIdentity *peer, + struct GSF_ConnectedPeer *cp, + const struct GSF_PeerPerformanceData *ppd) +{ + struct GSF_PendingRequest *pr = cls; + + if (GNUNET_YES != GSF_pending_request_test_target_ (pr, peer)) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# Loopback routes suppressed"), 1, + GNUNET_NO); + return; + } + GSF_plan_add_ (cp, pr); +} + + +/** + * Function to be called after we're done processing + * replies from the local lookup. If the result status + * code indicates that there may be more replies, plan + * forwarding the request. + * + * @param cls closure (NULL) + * @param pr the pending request we were processing + * @param result final datastore lookup result + */ +static void +consider_forwarding (void *cls, struct GSF_PendingRequest *pr, + enum GNUNET_BLOCK_EvaluationResult result) +{ + if (GNUNET_BLOCK_EVALUATION_OK_LAST == result) + return; /* we're done... */ + GSF_iterate_connected_peers_ (&consider_request_for_forwarding, pr); +} + + +/** + * Handle P2P "GET" request. + * + * @param cls closure, always NULL + * @param other the other peer involved (sender or receiver, NULL + * for loopback messages where we are both sender and receiver) + * @param message the actual message + * @param atsi performance information + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_p2p_get (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GSF_PendingRequest *pr; + + pr = GSF_handle_p2p_query_ (other, message); + if (NULL == pr) + return GNUNET_SYSERR; + GSF_pending_request_get_data_ (pr)->has_started = GNUNET_YES; + GSF_local_lookup_ (pr, &consider_forwarding, NULL); + update_latencies (atsi, atsi_count); + return GNUNET_OK; +} + + +/** + * We're done with the local lookup, now consider + * P2P processing (depending on request options and + * result status). Also signal that we can now + * receive more request information from the client. + * + * @param cls the client doing the request ('struct GNUNET_SERVER_Client') + * @param pr the pending request we were processing + * @param result final datastore lookup result + */ +static void +start_p2p_processing (void *cls, struct GSF_PendingRequest *pr, + enum GNUNET_BLOCK_EvaluationResult result) +{ + struct GNUNET_SERVER_Client *client = cls; + struct GSF_PendingRequestData *prd; + + prd = GSF_pending_request_get_data_ (pr); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finished database lookup for local request `%s' with result %d\n", + GNUNET_h2s (&prd->query), result); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + if (GNUNET_BLOCK_EVALUATION_OK_LAST == result) + return; /* we're done, 'pr' was already destroyed... */ + if (0 != (GSF_PRO_LOCAL_ONLY & prd->options)) + { + GSF_pending_request_cancel_ (pr, GNUNET_YES); + return; + } + GSF_dht_lookup_ (pr); + consider_forwarding (NULL, pr, result); +} + + +/** + * Handle START_SEARCH-message (search request from client). + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_start_search (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GSF_PendingRequest *pr; + int ret; + + pr = NULL; + ret = GSF_local_client_start_search_handler_ (client, message, &pr); + switch (ret) + { + case GNUNET_SYSERR: + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + break; + case GNUNET_NO: + GNUNET_SERVER_receive_done (client, GNUNET_OK); + break; + case GNUNET_YES: + GSF_pending_request_get_data_ (pr)->has_started = GNUNET_YES; + GSF_local_lookup_ (pr, &start_p2p_processing, client); + break; + default: + GNUNET_assert (0); + } +} + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != GSF_core) + { + GNUNET_CORE_disconnect (GSF_core); + GSF_core = NULL; + } + GSF_put_done_ (); + GSF_push_done_ (); + GSF_pending_request_done_ (); + GSF_plan_done (); + GSF_connected_peer_done_ (); + GNUNET_DATASTORE_disconnect (GSF_dsh, GNUNET_NO); + GSF_dsh = NULL; + GNUNET_DHT_disconnect (GSF_dht); + GSF_dht = NULL; + GNUNET_BLOCK_context_destroy (GSF_block_ctx); + GSF_block_ctx = NULL; + GNUNET_CONFIGURATION_destroy (block_cfg); + block_cfg = NULL; + GNUNET_STATISTICS_destroy (GSF_stats, GNUNET_NO); + GSF_stats = NULL; + if (GNUNET_SCHEDULER_NO_TASK != cover_age_task) + { + GNUNET_SCHEDULER_cancel (cover_age_task); + cover_age_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_FS_indexing_done (); + GNUNET_LOAD_value_free (datastore_get_load); + datastore_get_load = NULL; + GNUNET_LOAD_value_free (GSF_rt_entry_lifetime); + GSF_rt_entry_lifetime = NULL; +} + + +/** + * Function called for each pending request whenever a new + * peer connects, giving us a chance to decide about submitting + * the existing request to the new peer. + * + * @param cls the 'struct GSF_ConnectedPeer' of the new peer + * @param key query for the request + * @param pr handle to the pending request + * @return GNUNET_YES to continue to iterate + */ +static int +consider_peer_for_forwarding (void *cls, const GNUNET_HashCode * key, + struct GSF_PendingRequest *pr) +{ + struct GSF_ConnectedPeer *cp = cls; + struct GNUNET_PeerIdentity pid; + + GSF_connected_peer_get_identity_ (cp, &pid); + if (GNUNET_YES != GSF_pending_request_test_target_ (pr, &pid)) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# Loopback routes suppressed"), 1, + GNUNET_NO); + return GNUNET_YES; + } + GSF_plan_add_ (cp, pr); + return GNUNET_YES; +} + + +/** + * Method called whenever a given peer connects. + * + * @param cls closure, not used + * @param peer peer identity this notification is about + * @param atsi performance information + * @param atsi_count number of records in 'atsi' + */ +static void +peer_connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GSF_ConnectedPeer *cp; + + if (0 == memcmp (&my_id, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + cp = GSF_peer_connect_handler_ (peer, atsi, atsi_count); + if (NULL == cp) + return; + GSF_iterate_pending_requests_ (&consider_peer_for_forwarding, cp); +} + + +/** + * Function called after GNUNET_CORE_connect has succeeded + * (or failed for good). Note that the private key of the + * peer is intentionally not exposed here; if you need it, + * your process should try to read the private key file + * directly (which should work if you are authorized...). + * + * @param cls closure + * @param server handle to the server, NULL if we failed + * @param my_identity ID of this peer, NULL if we failed + */ +static void +peer_init_handler (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + my_id = *my_identity; +} + + +/** + * Process fs requests. + * + * @param server the initialized server + * @param c configuration to use + */ +static int +main_init (struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + static const struct GNUNET_CORE_MessageHandler p2p_handlers[] = { + {&handle_p2p_get, + GNUNET_MESSAGE_TYPE_FS_GET, 0}, + {&handle_p2p_put, + GNUNET_MESSAGE_TYPE_FS_PUT, 0}, + {&GSF_handle_p2p_migration_stop_, + GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP, + sizeof (struct MigrationStopMessage)}, + {NULL, 0, 0} + }; + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&GNUNET_FS_handle_index_start, NULL, + GNUNET_MESSAGE_TYPE_FS_INDEX_START, 0}, + {&GNUNET_FS_handle_index_list_get, NULL, + GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET, + sizeof (struct GNUNET_MessageHeader)}, + {&GNUNET_FS_handle_unindex, NULL, GNUNET_MESSAGE_TYPE_FS_UNINDEX, + sizeof (struct UnindexMessage)}, + {&handle_start_search, NULL, GNUNET_MESSAGE_TYPE_FS_START_SEARCH, + 0}, + {NULL, NULL, 0, 0} + }; + + GSF_core = + GNUNET_CORE_connect (GSF_cfg, 1, NULL, &peer_init_handler, + &peer_connect_handler, &GSF_peer_disconnect_handler_, + NULL, GNUNET_NO, NULL, GNUNET_NO, p2p_handlers); + if (NULL == GSF_core) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to `%s' service.\n"), "core"); + return GNUNET_SYSERR; + } + GNUNET_SERVER_disconnect_notify (server, &GSF_client_disconnect_handler_, + NULL); + GNUNET_SERVER_add_handlers (server, handlers); + cover_age_task = + GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY, &age_cover_counters, + NULL); + datastore_get_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + return GNUNET_OK; +} + + +/** + * Process fs requests. + * + * @param cls closure + * @param server the initialized server + * @param cfg configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GSF_cfg = cfg; + GSF_enable_randomized_delays = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "fs", "DELAY"); + GSF_dsh = GNUNET_DATASTORE_connect (cfg); + if (NULL == GSF_dsh) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + GSF_rt_entry_lifetime = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_FOREVER_REL); + GSF_stats = GNUNET_STATISTICS_create ("fs", cfg); + block_cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_string (block_cfg, "block", "PLUGINS", "fs"); + GSF_block_ctx = GNUNET_BLOCK_context_create (block_cfg); + GNUNET_assert (NULL != GSF_block_ctx); + GSF_dht = GNUNET_DHT_connect (cfg, FS_DHT_HT_SIZE); + GSF_plan_init (); + GSF_pending_request_init_ (); + GSF_connected_peer_init_ (); + GSF_push_init_ (); + GSF_put_init_ (); + if ((GNUNET_OK != GNUNET_FS_indexing_init (cfg, GSF_dsh)) || + (GNUNET_OK != main_init (server, cfg))) + { + GNUNET_SCHEDULER_shutdown (); + shutdown_task (NULL, NULL); + return; + } +} + + +/** + * The main function for the fs service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "fs", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-service-fs.c */ diff --git a/src/fs/gnunet-service-fs.h b/src/fs/gnunet-service-fs.h new file mode 100644 index 0000000..5ea73ee --- /dev/null +++ b/src/fs/gnunet-service-fs.h @@ -0,0 +1,286 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs.h + * @brief shared data structures of gnunet-service-fs.c + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_FS_H +#define GNUNET_SERVICE_FS_H + +#include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_core_service.h" +#include "gnunet_block_lib.h" +#include "fs.h" + + +/** + * By which amount do we decrement the TTL for simple forwarding / + * indirection of the query; in milli-seconds. Set somewhat in + * accordance to your network latency (above the time it'll take you + * to send a packet and get a reply). + */ +#define TTL_DECREMENT 5000 + +/** + * At what frequency should our datastore load decrease + * automatically (since if we don't use it, clearly the + * load must be going down). + */ +#define DATASTORE_LOAD_AUTODECLINE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250) + +/** + * Only the (mandatory) query is included. + */ +#define GET_MESSAGE_BIT_QUERY_ONLY 0 + +/** + * The peer identity of a peer waiting for the + * reply is included (used if the response + * should be transmitted to someone other than + * the sender of the GET). + */ +#define GET_MESSAGE_BIT_RETURN_TO 1 + +/** + * The hash of the public key of the target + * namespace is included (for SKS queries). + */ +#define GET_MESSAGE_BIT_SKS_NAMESPACE 2 + +/** + * The peer identity of a peer that had claimed to have the content + * previously is included (can be used if responder-anonymity is not + * desired; note that the precursor presumably lacked a direct + * connection to the specified peer; still, the receiver is in no way + * required to limit forwarding only to the specified peer, it should + * only prefer it somewhat if possible). + */ +#define GET_MESSAGE_BIT_TRANSMIT_TO 4 + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message sent between peers asking for FS-content. + */ +struct GetMessage +{ + + /** + * Message type will be GNUNET_MESSAGE_TYPE_FS_GET. + */ + struct GNUNET_MessageHeader header; + + /** + * Type of the query (block type). + */ + uint32_t type GNUNET_PACKED; + + /** + * How important is this request (network byte order) + */ + uint32_t priority GNUNET_PACKED; + + /** + * Relative time to live in MILLISECONDS (network byte order) + */ + int32_t ttl GNUNET_PACKED; + + /** + * The content hash should be mutated using this value + * before checking against the bloomfilter (used to + * get many different filters for the same hash codes). + * The number should be in big-endian format when used + * for mingling. + */ + uint32_t filter_mutator GNUNET_PACKED; + + /** + * Which of the optional hash codes are present at the end of the + * message? See GET_MESSAGE_BIT_xx constants. For each bit that is + * set, an additional GNUNET_HashCode with the respective content + * (in order of the bits) will be appended to the end of the GET + * message. + */ + uint32_t hash_bitmap GNUNET_PACKED; + + /** + * Hashcodes of the file(s) we're looking for. + * Details depend on the query type. + */ + GNUNET_HashCode query GNUNET_PACKED; + + /* this is followed by hash codes as specified in the "hash_bitmap"; + * after that, an optional bloomfilter (with bits set for replies + * that should be suppressed) can be present */ +}; + + +/** + * Message send by a peer that wants to be excluded + * from migration for a while. + */ +struct MigrationStopMessage +{ + /** + * Message type will be + * GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP. + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * How long should the block last? + */ + struct GNUNET_TIME_RelativeNBO duration; + +}; +GNUNET_NETWORK_STRUCT_END + +/** + * A connected peer. + */ +struct GSF_ConnectedPeer; + +/** + * An active request. + */ +struct GSF_PendingRequest; + +/** + * A local client. + */ +struct GSF_LocalClient; + +/** + * Information kept per plan per request ('pe' module). + */ +struct GSF_RequestPlan; + +/** + * DLL of request plans a particular pending request is + * involved with. + */ +struct GSF_RequestPlanReference; + +/** + * Our connection to the datastore. + */ +extern struct GNUNET_DATASTORE_Handle *GSF_dsh; + +/** + * Our configuration. + */ +extern const struct GNUNET_CONFIGURATION_Handle *GSF_cfg; + +/** + * Handle for reporting statistics. + */ +extern struct GNUNET_STATISTICS_Handle *GSF_stats; + +/** + * Pointer to handle to the core service (points to NULL until we've + * connected to it). + */ +extern struct GNUNET_CORE_Handle *GSF_core; + +/** + * Handle for DHT operations. + */ +extern struct GNUNET_DHT_Handle *GSF_dht; + +/** + * How long do requests typically stay in the routing table? + */ +extern struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime; + +/** + * Running average of the observed latency to other peers (round trip). + */ +extern struct GNUNET_TIME_Relative GSF_avg_latency; + +/** + * Typical priorities we're seeing from other peers right now. Since + * most priorities will be zero, this value is the weighted average of + * non-zero priorities seen "recently". In order to ensure that new + * values do not dramatically change the ratio, values are first + * "capped" to a reasonable range (+N of the current value) and then + * averaged into the existing value by a ratio of 1:N. Hence + * receiving the largest possible priority can still only raise our + * "current_priorities" by at most 1. + */ +extern double GSF_current_priorities; + +/** + * How many query messages have we received 'recently' that + * have not yet been claimed as cover traffic? + */ +extern unsigned int GSF_cover_query_count; + +/** + * How many content messages have we received 'recently' that + * have not yet been claimed as cover traffic? + */ +extern unsigned int GSF_cover_content_count; + +/** + * Our block context. + */ +extern struct GNUNET_BLOCK_Context *GSF_block_ctx; + +/** + * Are we introducing randomized delays for better anonymity? + */ +extern int GSF_enable_randomized_delays; + +/** + * Test if the DATABASE (GET) load on this peer is too high + * to even consider processing the query at + * all. + * + * @return GNUNET_YES if the load is too high to do anything (load high) + * GNUNET_NO to process normally (load normal) + * GNUNET_SYSERR to process for free (load low) + */ +int +GSF_test_get_load_too_high_ (uint32_t priority); + + +/** + * We've just now completed a datastore request. Update our + * datastore load calculations. + * + * @param start time when the datastore request was issued + */ +void +GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start); + + + +#endif +/* end of gnunet-service-fs.h */ diff --git a/src/fs/gnunet-service-fs_cp.c b/src/fs/gnunet-service-fs_cp.c new file mode 100644 index 0000000..e84993b --- /dev/null +++ b/src/fs/gnunet-service-fs_cp.c @@ -0,0 +1,1898 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_cp.c + * @brief API to handle 'connected peers' + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_load_lib.h" +#include "gnunet_ats_service.h" +#include "gnunet-service-fs.h" +#include "gnunet-service-fs_cp.h" +#include "gnunet-service-fs_pe.h" +#include "gnunet-service-fs_pr.h" +#include "gnunet-service-fs_push.h" + + +/** + * Ratio for moving average delay calculation. The previous + * average goes in with a factor of (n-1) into the calculation. + * Must be > 0. + */ +#define RUNAVG_DELAY_N 16 + +/** + * How often do we flush trust values to disk? + */ +#define TRUST_FLUSH_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) + +/** + * After how long do we discard a reply? + */ +#define REPLY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) + + +/** + * Handle to cancel a transmission request. + */ +struct GSF_PeerTransmitHandle +{ + + /** + * Kept in a doubly-linked list. + */ + struct GSF_PeerTransmitHandle *next; + + /** + * Kept in a doubly-linked list. + */ + struct GSF_PeerTransmitHandle *prev; + + /** + * Handle for an active request for transmission to this + * peer, or NULL (if core queue was full). + */ + struct GNUNET_CORE_TransmitHandle *cth; + + /** + * Time when this transmission request was issued. + */ + struct GNUNET_TIME_Absolute transmission_request_start_time; + + /** + * Timeout for this request. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Task called on timeout, or 0 for none. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * Function to call to get the actual message. + */ + GSF_GetMessageCallback gmc; + + /** + * Peer this request targets. + */ + struct GSF_ConnectedPeer *cp; + + /** + * Closure for 'gmc'. + */ + void *gmc_cls; + + /** + * Size of the message to be transmitted. + */ + size_t size; + + /** + * Set to 1 if we're currently in the process of calling + * 'GNUNET_CORE_notify_transmit_ready' (so while cth is + * NULL, we should not call notify_transmit_ready for this + * handle right now). + */ + unsigned int cth_in_progress; + + /** + * GNUNET_YES if this is a query, GNUNET_NO for content. + */ + int is_query; + + /** + * Did we get a reservation already? + */ + int was_reserved; + + /** + * Priority of this request. + */ + uint32_t priority; + +}; + + +/** + * Handle for an entry in our delay list. + */ +struct GSF_DelayedHandle +{ + + /** + * Kept in a doubly-linked list. + */ + struct GSF_DelayedHandle *next; + + /** + * Kept in a doubly-linked list. + */ + struct GSF_DelayedHandle *prev; + + /** + * Peer this transmission belongs to. + */ + struct GSF_ConnectedPeer *cp; + + /** + * The PUT that was delayed. + */ + struct PutMessage *pm; + + /** + * Task for the delay. + */ + GNUNET_SCHEDULER_TaskIdentifier delay_task; + + /** + * Size of the message. + */ + size_t msize; + +}; + + +/** + * Information per peer and request. + */ +struct PeerRequest +{ + + /** + * Handle to generic request. + */ + struct GSF_PendingRequest *pr; + + /** + * Handle to specific peer. + */ + struct GSF_ConnectedPeer *cp; + + /** + * Task for asynchronous stopping of this request. + */ + GNUNET_SCHEDULER_TaskIdentifier kill_task; + +}; + + +/** + * A connected peer. + */ +struct GSF_ConnectedPeer +{ + + /** + * Performance data for this peer. + */ + struct GSF_PeerPerformanceData ppd; + + /** + * Time until when we blocked this peer from migrating + * data to us. + */ + struct GNUNET_TIME_Absolute last_migration_block; + + /** + * Task scheduled to revive migration to this peer. + */ + GNUNET_SCHEDULER_TaskIdentifier mig_revive_task; + + /** + * Messages (replies, queries, content migration) we would like to + * send to this peer in the near future. Sorted by priority, head. + */ + struct GSF_PeerTransmitHandle *pth_head; + + /** + * Messages (replies, queries, content migration) we would like to + * send to this peer in the near future. Sorted by priority, tail. + */ + struct GSF_PeerTransmitHandle *pth_tail; + + /** + * Messages (replies, queries, content migration) we would like to + * send to this peer in the near future. Sorted by priority, head. + */ + struct GSF_DelayedHandle *delayed_head; + + /** + * Messages (replies, queries, content migration) we would like to + * send to this peer in the near future. Sorted by priority, tail. + */ + struct GSF_DelayedHandle *delayed_tail; + + /** + * Migration stop message in our queue, or NULL if we have none pending. + */ + struct GSF_PeerTransmitHandle *migration_pth; + + /** + * Context of our GNUNET_ATS_reserve_bandwidth call (or NULL). + */ + struct GNUNET_ATS_ReservationContext *rc; + + /** + * Task scheduled if we need to retry bandwidth reservation later. + */ + GNUNET_SCHEDULER_TaskIdentifier rc_delay_task; + + /** + * Active requests from this neighbour, map of query to 'struct PeerRequest'. + */ + struct GNUNET_CONTAINER_MultiHashMap *request_map; + + /** + * Increase in traffic preference still to be submitted + * to the core service for this peer. + */ + uint64_t inc_preference; + + /** + * Trust rating for this peer on disk. + */ + uint32_t disk_trust; + + /** + * Which offset in "last_p2p_replies" will be updated next? + * (we go round-robin). + */ + unsigned int last_p2p_replies_woff; + + /** + * Which offset in "last_client_replies" will be updated next? + * (we go round-robin). + */ + unsigned int last_client_replies_woff; + + /** + * Current offset into 'last_request_times' ring buffer. + */ + unsigned int last_request_times_off; + + /** + * GNUNET_YES if we did successfully reserve 32k bandwidth, + * GNUNET_NO if not. + */ + int did_reserve; + +}; + + +/** + * Map from peer identities to 'struct GSF_ConnectPeer' entries. + */ +static struct GNUNET_CONTAINER_MultiHashMap *cp_map; + +/** + * Where do we store trust information? + */ +static char *trustDirectory; + +/** + * Handle to ATS service. + */ +static struct GNUNET_ATS_PerformanceHandle *ats; + +/** + * Get the filename under which we would store the GNUNET_HELLO_Message + * for the given host and protocol. + * @return filename of the form DIRECTORY/HOSTID + */ +static char * +get_trust_filename (const struct GNUNET_PeerIdentity *id) +{ + struct GNUNET_CRYPTO_HashAsciiEncoded fil; + char *fn; + + GNUNET_CRYPTO_hash_to_enc (&id->hashPubKey, &fil); + GNUNET_asprintf (&fn, "%s%s%s", trustDirectory, DIR_SEPARATOR_STR, &fil); + return fn; +} + + +/** + * Find latency information in 'atsi'. + * + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * @return connection latency + */ +static struct GNUNET_TIME_Relative +get_latency (const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) +{ + unsigned int i; + + for (i = 0; i < atsi_count; i++) + if (ntohl (atsi->type) == GNUNET_ATS_QUALITY_NET_DELAY) + return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + ntohl (atsi->value)); + return GNUNET_TIME_UNIT_SECONDS; +} + + +/** + * Update the performance information kept for the given peer. + * + * @param cp peer record to update + * @param atsi transport performance data + * @param atsi_count number of records in 'atsi' + */ +static void +update_atsi (struct GSF_ConnectedPeer *cp, + const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) +{ + struct GNUNET_TIME_Relative latency; + + latency = get_latency (atsi, atsi_count); + GNUNET_LOAD_value_set_decline (cp->ppd.transmission_delay, latency); + /* LATER: merge atsi into cp's performance data (if we ever care...) */ +} + + +/** + * Return the performance data record for the given peer + * + * @param cp peer to query + * @return performance data record for the peer + */ +struct GSF_PeerPerformanceData * +GSF_get_peer_performance_data_ (struct GSF_ConnectedPeer *cp) +{ + return &cp->ppd; +} + + +/** + * Core is ready to transmit to a peer, get the message. + * + * @param cls the 'struct GSF_PeerTransmitHandle' of the message + * @param size number of bytes core is willing to take + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +peer_transmit_ready_cb (void *cls, size_t size, void *buf); + + +/** + * Function called by core upon success or failure of our bandwidth reservation request. + * + * @param cls the 'struct GSF_ConnectedPeer' of the peer for which we made the request + * @param peer identifies the peer + * @param amount set to the amount that was actually reserved or unreserved; + * either the full requested amount or zero (no partial reservations) + * @param res_delay if the reservation could not be satisfied (amount was 0), how + * long should the client wait until re-trying? + */ +static void +ats_reserve_callback (void *cls, const struct GNUNET_PeerIdentity *peer, + int32_t amount, struct GNUNET_TIME_Relative res_delay); + + +/** + * If ready (bandwidth reserved), try to schedule transmission via + * core for the given handle. + * + * @param pth transmission handle to schedule + */ +static void +schedule_transmission (struct GSF_PeerTransmitHandle *pth) +{ + struct GSF_ConnectedPeer *cp; + struct GNUNET_PeerIdentity target; + + if ((NULL != pth->cth) || (0 != pth->cth_in_progress)) + return; /* already done */ + cp = pth->cp; + GNUNET_assert (0 != cp->ppd.pid); + GNUNET_PEER_resolve (cp->ppd.pid, &target); + + if (0 != cp->inc_preference) + { + GNUNET_ATS_change_preference (ats, &target, GNUNET_ATS_PREFERENCE_BANDWIDTH, + (double) cp->inc_preference, + GNUNET_ATS_PREFERENCE_END); + cp->inc_preference = 0; + } + + if ((GNUNET_YES == pth->is_query) && (GNUNET_YES != pth->was_reserved)) + { + /* query, need reservation */ + if (GNUNET_YES != cp->did_reserve) + return; /* not ready */ + cp->did_reserve = GNUNET_NO; + /* reservation already done! */ + pth->was_reserved = GNUNET_YES; + cp->rc = + GNUNET_ATS_reserve_bandwidth (ats, &target, DBLOCK_SIZE, + &ats_reserve_callback, cp); + } + GNUNET_assert (pth->cth == NULL); + pth->cth_in_progress++; + pth->cth = + GNUNET_CORE_notify_transmit_ready (GSF_core, GNUNET_YES, pth->priority, + GNUNET_TIME_absolute_get_remaining + (pth->timeout), &target, pth->size, + &peer_transmit_ready_cb, pth); + GNUNET_assert (0 < pth->cth_in_progress--); +} + + +/** + * Core is ready to transmit to a peer, get the message. + * + * @param cls the 'struct GSF_PeerTransmitHandle' of the message + * @param size number of bytes core is willing to take + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +peer_transmit_ready_cb (void *cls, size_t size, void *buf) +{ + struct GSF_PeerTransmitHandle *pth = cls; + struct GSF_PeerTransmitHandle *pos; + struct GSF_ConnectedPeer *cp; + size_t ret; + + GNUNET_assert ((NULL == buf) || (pth->size <= size)); + pth->cth = NULL; + if (pth->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (pth->timeout_task); + pth->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + cp = pth->cp; + GNUNET_CONTAINER_DLL_remove (cp->pth_head, cp->pth_tail, pth); + if (GNUNET_YES == pth->is_query) + { + cp->ppd.last_request_times[(cp->last_request_times_off++) % + MAX_QUEUE_PER_PEER] = + GNUNET_TIME_absolute_get (); + GNUNET_assert (0 < cp->ppd.pending_queries--); + } + else if (GNUNET_NO == pth->is_query) + { + GNUNET_assert (0 < cp->ppd.pending_replies--); + } + GNUNET_LOAD_update (cp->ppd.transmission_delay, + GNUNET_TIME_absolute_get_duration + (pth->transmission_request_start_time).rel_value); + ret = pth->gmc (pth->gmc_cls, size, buf); + GNUNET_assert (NULL == pth->cth); + for (pos = cp->pth_head; pos != NULL; pos = pos->next) + { + GNUNET_assert (pos != pth); + schedule_transmission (pos); + } + GNUNET_assert (pth->cth == NULL); + GNUNET_assert (pth->cth_in_progress == 0); + GNUNET_free (pth); + return ret; +} + + +/** + * (re)try to reserve bandwidth from the given peer. + * + * @param cls the 'struct GSF_ConnectedPeer' to reserve from + * @param tc scheduler context + */ +static void +retry_reservation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GSF_ConnectedPeer *cp = cls; + struct GNUNET_PeerIdentity target; + + GNUNET_PEER_resolve (cp->ppd.pid, &target); + cp->rc_delay_task = GNUNET_SCHEDULER_NO_TASK; + cp->rc = + GNUNET_ATS_reserve_bandwidth (ats, &target, DBLOCK_SIZE, + &ats_reserve_callback, cp); +} + + +/** + * Function called by core upon success or failure of our bandwidth reservation request. + * + * @param cls the 'struct GSF_ConnectedPeer' of the peer for which we made the request + * @param peer identifies the peer + * @param amount set to the amount that was actually reserved or unreserved; + * either the full requested amount or zero (no partial reservations) + * @param res_delay if the reservation could not be satisfied (amount was 0), how + * long should the client wait until re-trying? + */ +static void +ats_reserve_callback (void *cls, const struct GNUNET_PeerIdentity *peer, + int32_t amount, struct GNUNET_TIME_Relative res_delay) +{ + struct GSF_ConnectedPeer *cp = cls; + struct GSF_PeerTransmitHandle *pth; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Reserved %d bytes / need to wait %llu ms for reservation\n", + (int) amount, (unsigned long long) res_delay.rel_value); + cp->rc = NULL; + if (0 == amount) + { + cp->rc_delay_task = + GNUNET_SCHEDULER_add_delayed (res_delay, &retry_reservation, cp); + return; + } + cp->did_reserve = GNUNET_YES; + pth = cp->pth_head; + if ((NULL != pth) && (NULL == pth->cth)) + { + /* reservation success, try transmission now! */ + pth->cth_in_progress++; + pth->cth = + GNUNET_CORE_notify_transmit_ready (GSF_core, GNUNET_YES, pth->priority, + GNUNET_TIME_absolute_get_remaining + (pth->timeout), peer, pth->size, + &peer_transmit_ready_cb, pth); + GNUNET_assert (0 < pth->cth_in_progress--); + } +} + + +/** + * A peer connected to us. Setup the connected peer + * records. + * + * @param peer identity of peer that connected + * @param atsi performance data for the connection + * @param atsi_count number of records in 'atsi' + * @return handle to connected peer entry + */ +struct GSF_ConnectedPeer * +GSF_peer_connect_handler_ (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GSF_ConnectedPeer *cp; + char *fn; + uint32_t trust; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected to peer %s\n", + GNUNET_i2s (peer)); + cp = GNUNET_malloc (sizeof (struct GSF_ConnectedPeer)); + cp->ppd.pid = GNUNET_PEER_intern (peer); + cp->ppd.transmission_delay = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_ZERO); + cp->rc = + GNUNET_ATS_reserve_bandwidth (ats, peer, DBLOCK_SIZE, + &ats_reserve_callback, cp); + fn = get_trust_filename (peer); + if ((GNUNET_DISK_file_test (fn) == GNUNET_YES) && + (sizeof (trust) == GNUNET_DISK_fn_read (fn, &trust, sizeof (trust)))) + cp->disk_trust = cp->ppd.trust = ntohl (trust); + GNUNET_free (fn); + cp->request_map = GNUNET_CONTAINER_multihashmap_create (128); + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (cp_map, &peer->hashPubKey, + cp, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# peers connected"), + GNUNET_CONTAINER_multihashmap_size (cp_map), + GNUNET_NO); + update_atsi (cp, atsi, atsi_count); + GSF_push_start_ (cp); + return cp; +} + + +/** + * It may be time to re-start migrating content to this + * peer. Check, and if so, restart migration. + * + * @param cls the 'struct GSF_ConnectedPeer' + * @param tc scheduler context + */ +static void +revive_migration (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GSF_ConnectedPeer *cp = cls; + struct GNUNET_TIME_Relative bt; + + cp->mig_revive_task = GNUNET_SCHEDULER_NO_TASK; + bt = GNUNET_TIME_absolute_get_remaining (cp->ppd.migration_blocked_until); + if (0 != bt.rel_value) + { + /* still time left... */ + cp->mig_revive_task = + GNUNET_SCHEDULER_add_delayed (bt, &revive_migration, cp); + return; + } + GSF_push_start_ (cp); +} + + +/** + * Get a handle for a connected peer. + * + * @param peer peer's identity + * @return NULL if the peer is not currently connected + */ +struct GSF_ConnectedPeer * +GSF_peer_get_ (const struct GNUNET_PeerIdentity *peer) +{ + if (NULL == cp_map) + return NULL; + return GNUNET_CONTAINER_multihashmap_get (cp_map, &peer->hashPubKey); +} + + +/** + * Handle P2P "MIGRATION_STOP" message. + * + * @param cls closure, always NULL + * @param other the other peer involved (sender or receiver, NULL + * for loopback messages where we are both sender and receiver) + * @param message the actual message + * @param atsi performance information + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GSF_handle_p2p_migration_stop_ (void *cls, + const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GSF_ConnectedPeer *cp; + const struct MigrationStopMessage *msm; + struct GNUNET_TIME_Relative bt; + + msm = (const struct MigrationStopMessage *) message; + cp = GSF_peer_get_ (other); + if (cp == NULL) + { + GNUNET_break (0); + return GNUNET_OK; + } + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# migration stop messages received"), + 1, GNUNET_NO); + bt = GNUNET_TIME_relative_ntoh (msm->duration); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Migration of content to peer `%s' blocked for %llu ms\n"), + GNUNET_i2s (other), (unsigned long long) bt.rel_value); + cp->ppd.migration_blocked_until = GNUNET_TIME_relative_to_absolute (bt); + if (cp->mig_revive_task == GNUNET_SCHEDULER_NO_TASK) + { + GSF_push_stop_ (cp); + cp->mig_revive_task = + GNUNET_SCHEDULER_add_delayed (bt, &revive_migration, cp); + } + update_atsi (cp, atsi, atsi_count); + return GNUNET_OK; +} + + +/** + * Copy reply and free put message. + * + * @param cls the 'struct PutMessage' + * @param buf_size number of bytes available in buf + * @param buf where to copy the message, NULL on error (peer disconnect) + * @return number of bytes copied to 'buf', can be 0 (without indicating an error) + */ +static size_t +copy_reply (void *cls, size_t buf_size, void *buf) +{ + struct PutMessage *pm = cls; + size_t size; + + if (buf != NULL) + { + GNUNET_assert (buf_size >= ntohs (pm->header.size)); + size = ntohs (pm->header.size); + memcpy (buf, pm, size); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# replies transmitted to other peers"), 1, + GNUNET_NO); + } + else + { + size = 0; + GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# replies dropped"), 1, + GNUNET_NO); + } + GNUNET_free (pm); + return size; +} + + +/** + * Free resources associated with the given peer request. + * + * @param peerreq request to free + * @param query associated key for the request + */ +static void +free_pending_request (struct PeerRequest *peerreq, + const GNUNET_HashCode *query) +{ + struct GSF_ConnectedPeer *cp = peerreq->cp; + + if (peerreq->kill_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (peerreq->kill_task); + peerreq->kill_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# P2P searches active"), + -1, GNUNET_NO); + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (cp->request_map, + query, peerreq)); + GNUNET_free (peerreq); +} + + +/** + * Cancel all requests associated with the peer. + * + * @param cls unused + * @param query hash code of the request + * @param value the 'struct GSF_PendingRequest' + * @return GNUNET_YES (continue to iterate) + */ +static int +cancel_pending_request (void *cls, const GNUNET_HashCode * query, void *value) +{ + struct PeerRequest *peerreq = value; + struct GSF_PendingRequest *pr = peerreq->pr; + struct GSF_PendingRequestData *prd; + + prd = GSF_pending_request_get_data_ (pr); + GSF_pending_request_cancel_ (pr, GNUNET_NO); + free_pending_request (peerreq, &prd->query); + return GNUNET_OK; +} + + +/** + * Free the given request. + * + * @param cls the request to free + * @param tc task context + */ +static void +peer_request_destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerRequest *peerreq = cls; + struct GSF_PendingRequest *pr = peerreq->pr; + struct GSF_PendingRequestData *prd; + + peerreq->kill_task = GNUNET_SCHEDULER_NO_TASK; + prd = GSF_pending_request_get_data_ (pr); + cancel_pending_request (NULL, &prd->query, peerreq); +} + + +/** + * The artificial delay is over, transmit the message now. + * + * @param cls the 'struct GSF_DelayedHandle' with the message + * @param tc scheduler context + */ +static void +transmit_delayed_now (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GSF_DelayedHandle *dh = cls; + struct GSF_ConnectedPeer *cp = dh->cp; + + GNUNET_CONTAINER_DLL_remove (cp->delayed_head, cp->delayed_tail, dh); + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + { + GNUNET_free (dh->pm); + GNUNET_free (dh); + return; + } + (void) GSF_peer_transmit_ (cp, GNUNET_NO, UINT32_MAX, REPLY_TIMEOUT, + dh->msize, ©_reply, dh->pm); + GNUNET_free (dh); +} + + +/** + * Get the randomized delay a response should be subjected to. + * + * @return desired delay + */ +static struct GNUNET_TIME_Relative +get_randomized_delay () +{ + struct GNUNET_TIME_Relative ret; + + ret = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + GNUNET_CRYPTO_random_u32 + (GNUNET_CRYPTO_QUALITY_WEAK, + 2 * GSF_avg_latency.rel_value + 1)); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# artificial delays introduced (ms)"), + ret.rel_value, GNUNET_NO); + + return ret; +} + + +/** + * Handle a reply to a pending request. Also called if a request + * expires (then with data == NULL). The handler may be called + * many times (depending on the request type), but will not be + * called during or after a call to GSF_pending_request_cancel + * and will also not be called anymore after a call signalling + * expiration. + * + * @param cls 'struct PeerRequest' this is an answer for + * @param eval evaluation of the result + * @param pr handle to the original pending request + * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" + * @param expiration when does 'data' expire? + * @param last_transmission when did we last transmit a request for this block + * @param type type of the block + * @param data response data, NULL on request expiration + * @param data_len number of bytes in data + */ +static void +handle_p2p_reply (void *cls, enum GNUNET_BLOCK_EvaluationResult eval, + struct GSF_PendingRequest *pr, uint32_t reply_anonymity_level, + struct GNUNET_TIME_Absolute expiration, + struct GNUNET_TIME_Absolute last_transmission, + enum GNUNET_BLOCK_Type type, const void *data, + size_t data_len) +{ + struct PeerRequest *peerreq = cls; + struct GSF_ConnectedPeer *cp = peerreq->cp; + struct GSF_PendingRequestData *prd; + struct PutMessage *pm; + size_t msize; + + GNUNET_assert (data_len + sizeof (struct PutMessage) < + GNUNET_SERVER_MAX_MESSAGE_SIZE); + GNUNET_assert (peerreq->pr == pr); + prd = GSF_pending_request_get_data_ (pr); + if (NULL == data) + { + free_pending_request (peerreq, &prd->query); + return; + } + GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY); + if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY)) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# replies dropped due to type mismatch"), + 1, GNUNET_NO); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting result for query `%s' to peer\n", + GNUNET_h2s (&prd->query)); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# replies received for other peers"), + 1, GNUNET_NO); + msize = sizeof (struct PutMessage) + data_len; + if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + if ((reply_anonymity_level != UINT32_MAX) && (reply_anonymity_level > 1)) + { + if (reply_anonymity_level - 1 > GSF_cover_content_count) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# replies dropped due to insufficient cover traffic"), + 1, GNUNET_NO); + return; + } + GSF_cover_content_count -= (reply_anonymity_level - 1); + } + + pm = GNUNET_malloc (msize); + pm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT); + pm->header.size = htons (msize); + pm->type = htonl (type); + pm->expiration = GNUNET_TIME_absolute_hton (expiration); + memcpy (&pm[1], data, data_len); + if ((reply_anonymity_level != UINT32_MAX) && (reply_anonymity_level != 0) && + (GSF_enable_randomized_delays == GNUNET_YES)) + { + struct GSF_DelayedHandle *dh; + + dh = GNUNET_malloc (sizeof (struct GSF_DelayedHandle)); + dh->cp = cp; + dh->pm = pm; + dh->msize = msize; + GNUNET_CONTAINER_DLL_insert (cp->delayed_head, cp->delayed_tail, dh); + dh->delay_task = + GNUNET_SCHEDULER_add_delayed (get_randomized_delay (), + &transmit_delayed_now, dh); + } + else + { + (void) GSF_peer_transmit_ (cp, GNUNET_NO, UINT32_MAX, REPLY_TIMEOUT, msize, + ©_reply, pm); + } + if (eval != GNUNET_BLOCK_EVALUATION_OK_LAST) + return; + if (GNUNET_SCHEDULER_NO_TASK == peerreq->kill_task) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# P2P searches destroyed due to ultimate reply"), + 1, GNUNET_NO); + peerreq->kill_task = + GNUNET_SCHEDULER_add_now (&peer_request_destroy, peerreq); + } +} + + +/** + * Increase the host credit by a value. + * + * @param cp which peer to change the trust value on + * @param value is the int value by which the + * host credit is to be increased or decreased + * @returns the actual change in trust (positive or negative) + */ +static int +change_host_trust (struct GSF_ConnectedPeer *cp, int value) +{ + if (value == 0) + return 0; + GNUNET_assert (cp != NULL); + if (value > 0) + { + if (cp->ppd.trust + value < cp->ppd.trust) + { + value = UINT32_MAX - cp->ppd.trust; + cp->ppd.trust = UINT32_MAX; + } + else + cp->ppd.trust += value; + } + else + { + if (cp->ppd.trust < -value) + { + value = -cp->ppd.trust; + cp->ppd.trust = 0; + } + else + cp->ppd.trust += value; + } + return value; +} + + +/** + * We've received a request with the specified priority. Bound it + * according to how much we trust the given peer. + * + * @param prio_in requested priority + * @param cp the peer making the request + * @return effective priority + */ +static int32_t +bound_priority (uint32_t prio_in, struct GSF_ConnectedPeer *cp) +{ +#define N ((double)128.0) + uint32_t ret; + double rret; + int ld; + + ld = GSF_test_get_load_too_high_ (0); + if (ld == GNUNET_SYSERR) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# requests done for free (low load)"), 1, + GNUNET_NO); + return 0; /* excess resources */ + } + if (prio_in > INT32_MAX) + prio_in = INT32_MAX; + ret = -change_host_trust (cp, -(int) prio_in); + if (ret > 0) + { + if (ret > GSF_current_priorities + N) + rret = GSF_current_priorities + N; + else + rret = ret; + GSF_current_priorities = (GSF_current_priorities * (N - 1) + rret) / N; + } + if ((ld == GNUNET_YES) && (ret > 0)) + { + /* try with charging */ + ld = GSF_test_get_load_too_high_ (ret); + } + if (ld == GNUNET_YES) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# request dropped, priority insufficient"), 1, + GNUNET_NO); + /* undo charge */ + change_host_trust (cp, (int) ret); + return -1; /* not enough resources */ + } + else + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# requests done for a price (normal load)"), 1, + GNUNET_NO); + } +#undef N + return ret; +} + + +/** + * The priority level imposes a bound on the maximum + * value for the ttl that can be requested. + * + * @param ttl_in requested ttl + * @param prio given priority + * @return ttl_in if ttl_in is below the limit, + * otherwise the ttl-limit for the given priority + */ +static int32_t +bound_ttl (int32_t ttl_in, uint32_t prio) +{ + unsigned long long allowed; + + if (ttl_in <= 0) + return ttl_in; + allowed = ((unsigned long long) prio) * TTL_DECREMENT / 1000; + if (ttl_in > allowed) + { + if (allowed >= (1 << 30)) + return 1 << 30; + return allowed; + } + return ttl_in; +} + + +/** + * Handle P2P "QUERY" message. Creates the pending request entry + * and sets up all of the data structures to that we will + * process replies properly. Does not initiate forwarding or + * local database lookups. + * + * @param other the other peer involved (sender or receiver, NULL + * for loopback messages where we are both sender and receiver) + * @param message the actual message + * @return pending request handle, NULL on error + */ +struct GSF_PendingRequest * +GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message) +{ + struct PeerRequest *peerreq; + struct GSF_PendingRequest *pr; + struct GSF_PendingRequestData *prd; + struct GSF_ConnectedPeer *cp; + struct GSF_ConnectedPeer *cps; + const GNUNET_HashCode *namespace; + const struct GNUNET_PeerIdentity *target; + enum GSF_PendingRequestOptions options; + uint16_t msize; + const struct GetMessage *gm; + unsigned int bits; + const GNUNET_HashCode *opt; + uint32_t bm; + size_t bfsize; + uint32_t ttl_decrement; + int32_t priority; + int32_t ttl; + enum GNUNET_BLOCK_Type type; + GNUNET_PEER_Id spid; + + GNUNET_assert (other != NULL); + msize = ntohs (message->size); + if (msize < sizeof (struct GetMessage)) + { + GNUNET_break_op (0); + return NULL; + } + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# GET requests received (from other peers)"), 1, + GNUNET_NO); + gm = (const struct GetMessage *) message; + type = ntohl (gm->type); + bm = ntohl (gm->hash_bitmap); + bits = 0; + while (bm > 0) + { + if (1 == (bm & 1)) + bits++; + bm >>= 1; + } + if (msize < sizeof (struct GetMessage) + bits * sizeof (GNUNET_HashCode)) + { + GNUNET_break_op (0); + return NULL; + } + opt = (const GNUNET_HashCode *) &gm[1]; + bfsize = msize - sizeof (struct GetMessage) - bits * sizeof (GNUNET_HashCode); + /* bfsize must be power of 2, check! */ + if (0 != ((bfsize - 1) & bfsize)) + { + GNUNET_break_op (0); + return NULL; + } + GSF_cover_query_count++; + bm = ntohl (gm->hash_bitmap); + bits = 0; + cps = GSF_peer_get_ (other); + if (NULL == cps) + { + /* peer must have just disconnected */ + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# requests dropped due to initiator not being connected"), + 1, GNUNET_NO); + return NULL; + } + if (0 != (bm & GET_MESSAGE_BIT_RETURN_TO)) + cp = GSF_peer_get_ ((const struct GNUNET_PeerIdentity *) &opt[bits++]); + else + cp = cps; + if (cp == NULL) + { + if (0 != (bm & GET_MESSAGE_BIT_RETURN_TO)) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to find RETURN-TO peer `%4s' in connection set. Dropping query.\n", + GNUNET_i2s ((const struct GNUNET_PeerIdentity *) + &opt[bits - 1])); + + else + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to find peer `%4s' in connection set. Dropping query.\n", + GNUNET_i2s (other)); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# requests dropped due to missing reverse route"), + 1, GNUNET_NO); + return NULL; + } + /* note that we can really only check load here since otherwise + * peers could find out that we are overloaded by not being + * disconnected after sending us a malformed query... */ + priority = bound_priority (ntohl (gm->priority), cps); + if (priority < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Dropping query from `%s', this peer is too busy.\n", + GNUNET_i2s (other)); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received request for `%s' of type %u from peer `%4s' with flags %u\n", + GNUNET_h2s (&gm->query), (unsigned int) type, GNUNET_i2s (other), + (unsigned int) bm); + namespace = (0 != (bm & GET_MESSAGE_BIT_SKS_NAMESPACE)) ? &opt[bits++] : NULL; + if ((type == GNUNET_BLOCK_TYPE_FS_SBLOCK) && (namespace == NULL)) + { + GNUNET_break_op (0); + return NULL; + } + if ((type != GNUNET_BLOCK_TYPE_FS_SBLOCK) && (namespace != NULL)) + { + GNUNET_break_op (0); + return NULL; + } + target = + (0 != + (bm & GET_MESSAGE_BIT_TRANSMIT_TO)) ? ((const struct GNUNET_PeerIdentity + *) &opt[bits++]) : NULL; + options = GSF_PRO_DEFAULTS; + spid = 0; + if ((GNUNET_LOAD_get_load (cp->ppd.transmission_delay) > 3 * (1 + priority)) + || (GNUNET_LOAD_get_average (cp->ppd.transmission_delay) > + GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value * 2 + + GNUNET_LOAD_get_average (GSF_rt_entry_lifetime))) + { + /* don't have BW to send to peer, or would likely take longer than we have for it, + * so at best indirect the query */ + priority = 0; + options |= GSF_PRO_FORWARD_ONLY; + spid = GNUNET_PEER_intern (other); + GNUNET_assert (0 != spid); + } + ttl = bound_ttl (ntohl (gm->ttl), priority); + /* decrement ttl (always) */ + ttl_decrement = + 2 * TTL_DECREMENT + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + TTL_DECREMENT); + if ((ttl < 0) && (((int32_t) (ttl - ttl_decrement)) > 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Dropping query from `%s' due to TTL underflow (%d - %u).\n", + GNUNET_i2s (other), ttl, ttl_decrement); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# requests dropped due TTL underflow"), 1, + GNUNET_NO); + /* integer underflow => drop (should be very rare)! */ + return NULL; + } + ttl -= ttl_decrement; + + /* test if the request already exists */ + peerreq = GNUNET_CONTAINER_multihashmap_get (cp->request_map, &gm->query); + if (peerreq != NULL) + { + pr = peerreq->pr; + prd = GSF_pending_request_get_data_ (pr); + if ((prd->type == type) && + ((type != GNUNET_BLOCK_TYPE_FS_SBLOCK) || + (0 == memcmp (&prd->namespace, namespace, sizeof (GNUNET_HashCode))))) + { + if (prd->ttl.abs_value >= GNUNET_TIME_absolute_get ().abs_value + ttl) + { + /* existing request has higher TTL, drop new one! */ + prd->priority += priority; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Have existing request with higher TTL, dropping new request.\n", + GNUNET_i2s (other)); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# requests dropped due to higher-TTL request"), + 1, GNUNET_NO); + return NULL; + } + /* existing request has lower TTL, drop old one! */ + priority += prd->priority; + GSF_pending_request_cancel_ (pr, GNUNET_YES); + free_pending_request (peerreq, &gm->query); + } + } + + peerreq = GNUNET_malloc (sizeof (struct PeerRequest)); + peerreq->cp = cp; + pr = GSF_pending_request_create_ (options, type, &gm->query, namespace, + target, + (bfsize > + 0) ? (const char *) &opt[bits] : NULL, + bfsize, ntohl (gm->filter_mutator), + 1 /* anonymity */ , + (uint32_t) priority, ttl, spid, GNUNET_PEER_intern (other), NULL, 0, /* replies_seen */ + &handle_p2p_reply, peerreq); + GNUNET_assert (NULL != pr); + peerreq->pr = pr; + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (cp->request_map, &gm->query, + peerreq, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# P2P query messages received and processed"), 1, + GNUNET_NO); + GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# P2P searches active"), + 1, GNUNET_NO); + return pr; +} + + +/** + * Function called if there has been a timeout trying to satisfy + * a transmission request. + * + * @param cls the 'struct GSF_PeerTransmitHandle' of the request + * @param tc scheduler context + */ +static void +peer_transmit_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GSF_PeerTransmitHandle *pth = cls; + struct GSF_ConnectedPeer *cp; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout trying to transmit to other peer\n"); + pth->timeout_task = GNUNET_SCHEDULER_NO_TASK; + cp = pth->cp; + GNUNET_CONTAINER_DLL_remove (cp->pth_head, cp->pth_tail, pth); + if (GNUNET_YES == pth->is_query) + GNUNET_assert (0 < cp->ppd.pending_queries--); + else if (GNUNET_NO == pth->is_query) + GNUNET_assert (0 < cp->ppd.pending_replies--); + GNUNET_LOAD_update (cp->ppd.transmission_delay, UINT64_MAX); + if (NULL != pth->cth) + { + GNUNET_CORE_notify_transmit_ready_cancel (pth->cth); + pth->cth = NULL; + } + pth->gmc (pth->gmc_cls, 0, NULL); + GNUNET_assert (0 == pth->cth_in_progress); + GNUNET_free (pth); +} + + +/** + * Transmit a message to the given peer as soon as possible. + * If the peer disconnects before the transmission can happen, + * the callback is invoked with a 'NULL' buffer. + * + * @param cp target peer + * @param is_query is this a query (GNUNET_YES) or content (GNUNET_NO) or neither (GNUNET_SYSERR) + * @param priority how important is this request? + * @param timeout when does this request timeout (call gmc with error) + * @param size number of bytes we would like to send to the peer + * @param gmc function to call to get the message + * @param gmc_cls closure for gmc + * @return handle to cancel request + */ +struct GSF_PeerTransmitHandle * +GSF_peer_transmit_ (struct GSF_ConnectedPeer *cp, int is_query, + uint32_t priority, struct GNUNET_TIME_Relative timeout, + size_t size, GSF_GetMessageCallback gmc, void *gmc_cls) +{ + struct GSF_PeerTransmitHandle *pth; + struct GSF_PeerTransmitHandle *pos; + struct GSF_PeerTransmitHandle *prev; + + pth = GNUNET_malloc (sizeof (struct GSF_PeerTransmitHandle)); + pth->transmission_request_start_time = GNUNET_TIME_absolute_get (); + pth->timeout = GNUNET_TIME_relative_to_absolute (timeout); + pth->gmc = gmc; + pth->gmc_cls = gmc_cls; + pth->size = size; + pth->is_query = is_query; + pth->priority = priority; + pth->cp = cp; + /* insertion sort (by priority, descending) */ + prev = NULL; + pos = cp->pth_head; + while ((pos != NULL) && (pos->priority > priority)) + { + prev = pos; + pos = pos->next; + } + if (prev == NULL) + GNUNET_CONTAINER_DLL_insert (cp->pth_head, cp->pth_tail, pth); + else + GNUNET_CONTAINER_DLL_insert_after (cp->pth_head, cp->pth_tail, prev, pth); + if (GNUNET_YES == is_query) + cp->ppd.pending_queries++; + else if (GNUNET_NO == is_query) + cp->ppd.pending_replies++; + pth->timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, &peer_transmit_timeout, pth); + schedule_transmission (pth); + return pth; +} + + +/** + * Cancel an earlier request for transmission. + * + * @param pth request to cancel + */ +void +GSF_peer_transmit_cancel_ (struct GSF_PeerTransmitHandle *pth) +{ + struct GSF_ConnectedPeer *cp; + + if (pth->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (pth->timeout_task); + pth->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != pth->cth) + { + GNUNET_CORE_notify_transmit_ready_cancel (pth->cth); + pth->cth = NULL; + } + cp = pth->cp; + GNUNET_CONTAINER_DLL_remove (cp->pth_head, cp->pth_tail, pth); + if (GNUNET_YES == pth->is_query) + GNUNET_assert (0 < cp->ppd.pending_queries--); + else if (GNUNET_NO == pth->is_query) + GNUNET_assert (0 < cp->ppd.pending_replies--); + GNUNET_assert (0 == pth->cth_in_progress); + GNUNET_free (pth); +} + + +/** + * Report on receiving a reply; update the performance record of the given peer. + * + * @param cp responding peer (will be updated) + * @param request_time time at which the original query was transmitted + * @param request_priority priority of the original request + */ +void +GSF_peer_update_performance_ (struct GSF_ConnectedPeer *cp, + struct GNUNET_TIME_Absolute request_time, + uint32_t request_priority) +{ + struct GNUNET_TIME_Relative delay; + + delay = GNUNET_TIME_absolute_get_duration (request_time); + cp->ppd.avg_reply_delay.rel_value = + (cp->ppd.avg_reply_delay.rel_value * (RUNAVG_DELAY_N - 1) + + delay.rel_value) / RUNAVG_DELAY_N; + cp->ppd.avg_priority = + (cp->ppd.avg_priority * (RUNAVG_DELAY_N - 1) + + request_priority) / RUNAVG_DELAY_N; +} + + +/** + * Report on receiving a reply in response to an initiating client. + * Remember that this peer is good for this client. + * + * @param cp responding peer (will be updated) + * @param initiator_client local client on responsible for query + */ +void +GSF_peer_update_responder_client_ (struct GSF_ConnectedPeer *cp, + struct GSF_LocalClient *initiator_client) +{ + cp->ppd.last_client_replies[cp->last_client_replies_woff++ % + CS2P_SUCCESS_LIST_SIZE] = initiator_client; +} + + +/** + * Report on receiving a reply in response to an initiating peer. + * Remember that this peer is good for this initiating peer. + * + * @param cp responding peer (will be updated) + * @param initiator_peer other peer responsible for query + */ +void +GSF_peer_update_responder_peer_ (struct GSF_ConnectedPeer *cp, + const struct GSF_ConnectedPeer *initiator_peer) +{ + unsigned int woff; + + woff = cp->last_p2p_replies_woff % P2P_SUCCESS_LIST_SIZE; + GNUNET_PEER_change_rc (cp->ppd.last_p2p_replies[woff], -1); + cp->ppd.last_p2p_replies[woff] = initiator_peer->ppd.pid; + GNUNET_PEER_change_rc (initiator_peer->ppd.pid, 1); + cp->last_p2p_replies_woff = (woff + 1) % P2P_SUCCESS_LIST_SIZE; +} + + +/** + * A peer disconnected from us. Tear down the connected peer + * record. + * + * @param cls unused + * @param peer identity of peer that connected + */ +void +GSF_peer_disconnect_handler_ (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct GSF_ConnectedPeer *cp; + struct GSF_PeerTransmitHandle *pth; + struct GSF_DelayedHandle *dh; + + cp = GSF_peer_get_ (peer); + if (NULL == cp) + return; /* must have been disconnect from core with + * 'peer' == my_id, ignore */ + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (cp_map, + &peer->hashPubKey, cp)); + GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# peers connected"), + GNUNET_CONTAINER_multihashmap_size (cp_map), + GNUNET_NO); + if (NULL != cp->migration_pth) + { + GSF_peer_transmit_cancel_ (cp->migration_pth); + cp->migration_pth = NULL; + } + if (NULL != cp->rc) + { + GNUNET_ATS_reserve_bandwidth_cancel (cp->rc); + cp->rc = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != cp->rc_delay_task) + { + GNUNET_SCHEDULER_cancel (cp->rc_delay_task); + cp->rc_delay_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_CONTAINER_multihashmap_iterate (cp->request_map, + &cancel_pending_request, cp); + GNUNET_CONTAINER_multihashmap_destroy (cp->request_map); + cp->request_map = NULL; + GSF_plan_notify_peer_disconnect_ (cp); + GNUNET_LOAD_value_free (cp->ppd.transmission_delay); + GNUNET_PEER_decrement_rcs (cp->ppd.last_p2p_replies, P2P_SUCCESS_LIST_SIZE); + memset (cp->ppd.last_p2p_replies, 0, sizeof (cp->ppd.last_p2p_replies)); + GSF_push_stop_ (cp); + while (NULL != (pth = cp->pth_head)) + { + if (NULL != pth->cth) + { + GNUNET_CORE_notify_transmit_ready_cancel (pth->cth); + pth->cth = NULL; + } + if (pth->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (pth->timeout_task); + pth->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_CONTAINER_DLL_remove (cp->pth_head, cp->pth_tail, pth); + GNUNET_assert (0 == pth->cth_in_progress); + pth->gmc (pth->gmc_cls, 0, NULL); + GNUNET_free (pth); + } + while (NULL != (dh = cp->delayed_head)) + { + GNUNET_CONTAINER_DLL_remove (cp->delayed_head, cp->delayed_tail, dh); + GNUNET_SCHEDULER_cancel (dh->delay_task); + GNUNET_free (dh->pm); + GNUNET_free (dh); + } + GNUNET_PEER_change_rc (cp->ppd.pid, -1); + if (GNUNET_SCHEDULER_NO_TASK != cp->mig_revive_task) + { + GNUNET_SCHEDULER_cancel (cp->mig_revive_task); + cp->mig_revive_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (cp); +} + + +/** + * Closure for 'call_iterator'. + */ +struct IterationContext +{ + /** + * Function to call on each entry. + */ + GSF_ConnectedPeerIterator it; + + /** + * Closure for 'it'. + */ + void *it_cls; +}; + + +/** + * Function that calls the callback for each peer. + * + * @param cls the 'struct IterationContext*' + * @param key identity of the peer + * @param value the 'struct GSF_ConnectedPeer*' + * @return GNUNET_YES to continue iteration + */ +static int +call_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct IterationContext *ic = cls; + struct GSF_ConnectedPeer *cp = value; + + ic->it (ic->it_cls, (const struct GNUNET_PeerIdentity *) key, cp, &cp->ppd); + return GNUNET_YES; +} + + +/** + * Iterate over all connected peers. + * + * @param it function to call for each peer + * @param it_cls closure for it + */ +void +GSF_iterate_connected_peers_ (GSF_ConnectedPeerIterator it, void *it_cls) +{ + struct IterationContext ic; + + ic.it = it; + ic.it_cls = it_cls; + GNUNET_CONTAINER_multihashmap_iterate (cp_map, &call_iterator, &ic); +} + + +/** + * Obtain the identity of a connected peer. + * + * @param cp peer to reserve bandwidth from + * @param id identity to set (written to) + */ +void +GSF_connected_peer_get_identity_ (const struct GSF_ConnectedPeer *cp, + struct GNUNET_PeerIdentity *id) +{ + GNUNET_assert (0 != cp->ppd.pid); + GNUNET_PEER_resolve (cp->ppd.pid, id); +} + + +/** + * Assemble a migration stop message for transmission. + * + * @param cls the 'struct GSF_ConnectedPeer' to use + * @param size number of bytes we're allowed to write to buf + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +create_migration_stop_message (void *cls, size_t size, void *buf) +{ + struct GSF_ConnectedPeer *cp = cls; + struct MigrationStopMessage msm; + + cp->migration_pth = NULL; + if (NULL == buf) + return 0; + GNUNET_assert (size >= sizeof (struct MigrationStopMessage)); + msm.header.size = htons (sizeof (struct MigrationStopMessage)); + msm.header.type = htons (GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP); + msm.reserved = htonl (0); + msm.duration = + GNUNET_TIME_relative_hton (GNUNET_TIME_absolute_get_remaining + (cp->last_migration_block)); + memcpy (buf, &msm, sizeof (struct MigrationStopMessage)); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# migration stop messages sent"), + 1, GNUNET_NO); + return sizeof (struct MigrationStopMessage); +} + + +/** + * Ask a peer to stop migrating data to us until the given point + * in time. + * + * @param cp peer to ask + * @param block_time until when to block + */ +void +GSF_block_peer_migration_ (struct GSF_ConnectedPeer *cp, + struct GNUNET_TIME_Absolute block_time) +{ + if (cp->last_migration_block.abs_value > block_time.abs_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Migration already blocked for another %llu ms\n", + (unsigned long long) + GNUNET_TIME_absolute_get_remaining + (cp->last_migration_block).rel_value); + return; /* already blocked */ + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to stop migration for %llu ms\n", + (unsigned long long) GNUNET_TIME_absolute_get_remaining (block_time).rel_value); + cp->last_migration_block = block_time; + if (cp->migration_pth != NULL) + GSF_peer_transmit_cancel_ (cp->migration_pth); + cp->migration_pth = + GSF_peer_transmit_ (cp, GNUNET_SYSERR, UINT32_MAX, + GNUNET_TIME_UNIT_FOREVER_REL, + sizeof (struct MigrationStopMessage), + &create_migration_stop_message, cp); +} + + +/** + * Write host-trust information to a file - flush the buffer entry! + * + * @param cls closure, not used + * @param key host identity + * @param value the 'struct GSF_ConnectedPeer' to flush + * @return GNUNET_OK to continue iteration + */ +static int +flush_trust (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GSF_ConnectedPeer *cp = value; + char *fn; + uint32_t trust; + struct GNUNET_PeerIdentity pid; + + if (cp->ppd.trust == cp->disk_trust) + return GNUNET_OK; /* unchanged */ + GNUNET_assert (0 != cp->ppd.pid); + GNUNET_PEER_resolve (cp->ppd.pid, &pid); + fn = get_trust_filename (&pid); + if (cp->ppd.trust == 0) + { + if ((0 != UNLINK (fn)) && (errno != ENOENT)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING | + GNUNET_ERROR_TYPE_BULK, "unlink", fn); + } + else + { + trust = htonl (cp->ppd.trust); + if (sizeof (uint32_t) == + GNUNET_DISK_fn_write (fn, &trust, sizeof (uint32_t), + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE | + GNUNET_DISK_PERM_GROUP_READ | + GNUNET_DISK_PERM_OTHER_READ)) + cp->disk_trust = cp->ppd.trust; + } + GNUNET_free (fn); + return GNUNET_OK; +} + + +/** + * Notify core about a preference we have for the given peer + * (to allocate more resources towards it). The change will + * be communicated the next time we reserve bandwidth with + * core (not instantly). + * + * @param cp peer to reserve bandwidth from + * @param pref preference change + */ +void +GSF_connected_peer_change_preference_ (struct GSF_ConnectedPeer *cp, + uint64_t pref) +{ + cp->inc_preference += pref; +} + + +/** + * Call this method periodically to flush trust information to disk. + * + * @param cls closure, not used + * @param tc task context, not used + */ +static void +cron_flush_trust (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + if (NULL == cp_map) + return; + GNUNET_CONTAINER_multihashmap_iterate (cp_map, &flush_trust, NULL); + if (NULL == tc) + return; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + GNUNET_SCHEDULER_add_delayed_with_priority (TRUST_FLUSH_FREQ, + GNUNET_SCHEDULER_PRIORITY_HIGH, + &cron_flush_trust, NULL); +} + + +/** + * Initialize peer management subsystem. + */ +void +GSF_connected_peer_init_ () +{ + cp_map = GNUNET_CONTAINER_multihashmap_create (128); + ats = GNUNET_ATS_performance_init (GSF_cfg, NULL, NULL); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_filename (GSF_cfg, "fs", + "TRUST", + &trustDirectory)); + GNUNET_DISK_directory_create (trustDirectory); + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_HIGH, + &cron_flush_trust, NULL); +} + + +/** + * Iterator to free peer entries. + * + * @param cls closure, unused + * @param key current key code + * @param value value in the hash map (peer entry) + * @return GNUNET_YES (we should continue to iterate) + */ +static int +clean_peer (void *cls, const GNUNET_HashCode * key, void *value) +{ + GSF_peer_disconnect_handler_ (NULL, (const struct GNUNET_PeerIdentity *) key); + return GNUNET_YES; +} + + +/** + * Shutdown peer management subsystem. + */ +void +GSF_connected_peer_done_ () +{ + cron_flush_trust (NULL, NULL); + GNUNET_CONTAINER_multihashmap_iterate (cp_map, &clean_peer, NULL); + GNUNET_CONTAINER_multihashmap_destroy (cp_map); + cp_map = NULL; + GNUNET_free (trustDirectory); + trustDirectory = NULL; + GNUNET_ATS_performance_done (ats); + ats = NULL; +} + + +/** + * Iterator to remove references to LC entry. + * + * @param cls the 'struct GSF_LocalClient*' to look for + * @param key current key code + * @param value value in the hash map (peer entry) + * @return GNUNET_YES (we should continue to iterate) + */ +static int +clean_local_client (void *cls, const GNUNET_HashCode * key, void *value) +{ + const struct GSF_LocalClient *lc = cls; + struct GSF_ConnectedPeer *cp = value; + unsigned int i; + + for (i = 0; i < CS2P_SUCCESS_LIST_SIZE; i++) + if (cp->ppd.last_client_replies[i] == lc) + cp->ppd.last_client_replies[i] = NULL; + return GNUNET_YES; +} + + +/** + * Notification that a local client disconnected. Clean up all of our + * references to the given handle. + * + * @param lc handle to the local client (henceforth invalid) + */ +void +GSF_handle_local_client_disconnect_ (const struct GSF_LocalClient *lc) +{ + if (NULL == cp_map) + return; /* already cleaned up */ + GNUNET_CONTAINER_multihashmap_iterate (cp_map, &clean_local_client, + (void *) lc); +} + + +/* 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 new file mode 100644 index 0000000..e3c7cd2 --- /dev/null +++ b/src/fs/gnunet-service-fs_cp.h @@ -0,0 +1,420 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_cp.h + * @brief API to handle 'connected peers' + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_FS_CP_H +#define GNUNET_SERVICE_FS_CP_H + +#include "fs.h" +#include "gnunet-service-fs.h" + + +/** + * Maximum number of outgoing messages we queue per peer. + * + * Performance measurements for 2 peer setup for 50 MB file + * (with MAX_DATASTORE_QUEUE = 1 and RETRY_PROBABILITY_INV = 1): + * + * 2: 1700 kb/s, 1372 kb/s + * 8: 2117 kb/s, 1284 kb/s, 1112 kb/s + * 16: 3500 kb/s, 3200 kb/s, 3388 kb/s + * 32: 3441 kb/s, 3163 kb/s, 3277 kb/s + * 128: 1700 kb/s; 2010 kb/s, 3383 kb/s, 1156 kb/s + * + * Conclusion: 16 seems to be a pretty good value (stable + * and high performance, no excessive memory use). + */ +#define MAX_QUEUE_PER_PEER 16 + +/** + * Length of the P2P success tracker. Note that having a very long + * list can also hurt performance. + */ +#define P2P_SUCCESS_LIST_SIZE 8 + +/** + * Length of the CS-2-P success tracker. Note that + * having a very long list can also hurt performance. + */ +#define CS2P_SUCCESS_LIST_SIZE 8 + + +/** + * Performance data kept for a peer. + */ +struct GSF_PeerPerformanceData +{ + + /** + * Transport performance data. + */ + struct GNUNET_ATS_Information *atsi; + + /** + * List of the last clients for which this peer successfully + * answered a query. + */ + struct GSF_LocalClient *last_client_replies[CS2P_SUCCESS_LIST_SIZE]; + + /** + * List of the last PIDs for which + * this peer successfully answered a query; + * We use 0 to indicate no successful reply. + */ + GNUNET_PEER_Id last_p2p_replies[P2P_SUCCESS_LIST_SIZE]; + + /** + * Average delay between sending the peer a request and + * getting a reply (only calculated over the requests for + * which we actually got a reply). Calculated + * as a moving average: new_delay = ((n-1)*last_delay+curr_delay) / n + */ + struct GNUNET_TIME_Relative avg_reply_delay; + + /** + * If we get content we already have from this peer, for how + * long do we block him? Adjusted based on the fraction of + * redundant data we receive, between 1s and 1h. + */ + struct GNUNET_TIME_Relative migration_delay; + + /** + * Point in time until which this peer does not want us to migrate content + * to it. + */ + struct GNUNET_TIME_Absolute migration_blocked_until; + + /** + * Transmission times for the last MAX_QUEUE_PER_PEER + * requests for this peer. Used as a ring buffer, current + * offset is stored in 'last_request_times_off'. If the + * oldest entry is more recent than the 'avg_delay', we should + * not send any more requests right now. + */ + struct GNUNET_TIME_Absolute last_request_times[MAX_QUEUE_PER_PEER]; + + /** + * How long does it typically take for us to transmit a message + * to this peer? (delay between the request being issued and + * the callback being invoked). + */ + struct GNUNET_LOAD_Value *transmission_delay; + + /** + * Average priority of successful replies. Calculated + * as a moving average: new_avg = ((n-1)*last_avg+curr_prio) / n + */ + double avg_priority; + + /** + * The peer's identity. + */ + GNUNET_PEER_Id pid; + + /** + * Trust rating for this peer + */ + uint32_t trust; + + /** + * Number of pending queries (replies are not counted) + */ + unsigned int pending_queries; + + /** + * Number of pending replies (queries are not counted) + */ + unsigned int pending_replies; + +}; + + +/** + * Signature of function called on a connected peer. + * + * @param cls closure + * @param peer identity of the peer + * @param cp handle to the connected peer record + * @param perf peer performance data + */ +typedef void (*GSF_ConnectedPeerIterator) (void *cls, + const struct GNUNET_PeerIdentity * + peer, struct GSF_ConnectedPeer * cp, + const struct GSF_PeerPerformanceData + * ppd); + + +/** + * Function called to get a message for transmission. + * + * @param cls closure + * @param buf_size number of bytes available in buf + * @param buf where to copy the message, NULL on error (peer disconnect) + * @return number of bytes copied to 'buf', can be 0 (without indicating an error) + */ +typedef size_t (*GSF_GetMessageCallback) (void *cls, size_t buf_size, + void *buf); + + +/** + * Signature of function called on a reservation success or failure. + * + * @param cls closure + * @param cp handle to the connected peer record + * @param success GNUNET_YES on success, GNUNET_NO on failure + */ +typedef void (*GSF_PeerReserveCallback) (void *cls, + struct GSF_ConnectedPeer * cp, + int success); + + +/** + * Handle to cancel a transmission request. + */ +struct GSF_PeerTransmitHandle; + + +/** + * A peer connected to us. Setup the connected peer + * records. + * + * @param peer identity of peer that connected + * @param atsi performance data for the connection + * @param atsi_count number of records in 'atsi' + * @return handle to connected peer entry + */ +struct GSF_ConnectedPeer * +GSF_peer_connect_handler_ (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count); + + +/** + * Get a handle for a connected peer. + * + * @param peer peer's identity + * @return NULL if this peer is not currently connected + */ +struct GSF_ConnectedPeer * +GSF_peer_get_ (const struct GNUNET_PeerIdentity *peer); + + +/** + * Transmit a message to the given peer as soon as possible. + * If the peer disconnects before the transmission can happen, + * the callback is invoked with a 'NULL' buffer. + * + * @param cp target peer + * @param is_query is this a query (GNUNET_YES) or content (GNUNET_NO) + * @param priority how important is this request? + * @param timeout when does this request timeout (call gmc with error) + * @param size number of bytes we would like to send to the peer + * @param gmc function to call to get the message + * @param gmc_cls closure for gmc + * @return handle to cancel request + */ +struct GSF_PeerTransmitHandle * +GSF_peer_transmit_ (struct GSF_ConnectedPeer *cp, int is_query, + uint32_t priority, struct GNUNET_TIME_Relative timeout, + size_t size, GSF_GetMessageCallback gmc, void *gmc_cls); + + +/** + * Cancel an earlier request for transmission. + * + * @param pth request to cancel + */ +void +GSF_peer_transmit_cancel_ (struct GSF_PeerTransmitHandle *pth); + + +/** + * Report on receiving a reply; update the performance record of the given peer. + * + * @param cp responding peer (will be updated) + * @param request_time time at which the original query was transmitted + * @param request_priority priority of the original request + */ +void +GSF_peer_update_performance_ (struct GSF_ConnectedPeer *cp, + struct GNUNET_TIME_Absolute request_time, + uint32_t request_priority); + + +/** + * Report on receiving a reply in response to an initiating client. + * Remember that this peer is good for this client. + * + * @param cp responding peer (will be updated) + * @param initiator_client local client on responsible for query + */ +void +GSF_peer_update_responder_client_ (struct GSF_ConnectedPeer *cp, + struct GSF_LocalClient *initiator_client); + + +/** + * Report on receiving a reply in response to an initiating peer. + * Remember that this peer is good for this initiating peer. + * + * @param cp responding peer (will be updated) + * @param initiator_peer other peer responsible for query + */ +void +GSF_peer_update_responder_peer_ (struct GSF_ConnectedPeer *cp, + const struct GSF_ConnectedPeer + *initiator_peer); + + +/** + * Handle P2P "MIGRATION_STOP" message. + * + * @param cls closure, always NULL + * @param other the other peer involved (sender or receiver, NULL + * for loopback messages where we are both sender and receiver) + * @param message the actual message + * @param atsi performance information + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GSF_handle_p2p_migration_stop_ (void *cls, + const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count); + + +/** + * Handle P2P "QUERY" message. Only responsible for creating the + * request entry itself and setting up reply callback and cancellation + * on peer disconnect. Does NOT execute the actual request strategy + * (planning) or local database operations. + * + * @param other the other peer involved (sender or receiver, NULL + * for loopback messages where we are both sender and receiver) + * @param message the actual message + * @return pending request handle, NULL on error + */ +struct GSF_PendingRequest * +GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message); + + +/** + * Return the performance data record for the given peer + * + * @param cp peer to query + * @return performance data record for the peer + */ +struct GSF_PeerPerformanceData * +GSF_get_peer_performance_data_ (struct GSF_ConnectedPeer *cp); + + +/** + * Ask a peer to stop migrating data to us until the given point + * in time. + * + * @param cp peer to ask + * @param block_time until when to block + */ +void +GSF_block_peer_migration_ (struct GSF_ConnectedPeer *cp, + struct GNUNET_TIME_Absolute block_time); + + +/** + * A peer disconnected from us. Tear down the connected peer + * record. + * + * @param cls unused + * @param peer identity of peer that connected + */ +void +GSF_peer_disconnect_handler_ (void *cls, + const struct GNUNET_PeerIdentity *peer); + + +/** + * Notification that a local client disconnected. Clean up all of our + * references to the given handle. + * + * @param lc handle to the local client (henceforth invalid) + */ +void +GSF_handle_local_client_disconnect_ (const struct GSF_LocalClient *lc); + + +/** + * Notify core about a preference we have for the given peer + * (to allocate more resources towards it). The change will + * be communicated the next time we reserve bandwidth with + * core (not instantly). + * + * @param cp peer to reserve bandwidth from + * @param pref preference change + */ +void +GSF_connected_peer_change_preference_ (struct GSF_ConnectedPeer *cp, + uint64_t pref); + + +/** + * Obtain the identity of a connected peer. + * + * @param cp peer to reserve bandwidth from + * @param id identity to set (written to) + */ +void +GSF_connected_peer_get_identity_ (const struct GSF_ConnectedPeer *cp, + struct GNUNET_PeerIdentity *id); + + +/** + * Iterate over all connected peers. + * + * @param it function to call for each peer + * @param it_cls closure for it + */ +void +GSF_iterate_connected_peers_ (GSF_ConnectedPeerIterator it, void *it_cls); + + +/** + * Initialize peer management subsystem. + */ +void +GSF_connected_peer_init_ (void); + + +/** + * Shutdown peer management subsystem. + */ +void +GSF_connected_peer_done_ (void); + + +#endif +/* 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 new file mode 100644 index 0000000..b563019 --- /dev/null +++ b/src/fs/gnunet-service-fs_indexing.c @@ -0,0 +1,623 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_indexing.c + * @brief program that provides indexing functions of the file-sharing service + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include "gnunet_core_service.h" +#include "gnunet_datastore_service.h" +#include "gnunet_peer_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_signatures.h" +#include "gnunet_util_lib.h" +#include "gnunet-service-fs.h" +#include "gnunet-service-fs_indexing.h" +#include "fs.h" + +/** + * In-memory information about indexed files (also available + * on-disk). + */ +struct IndexInfo +{ + + /** + * This is a linked list. + */ + struct IndexInfo *next; + + /** + * Name of the indexed file. Memory allocated + * at the end of this struct (do not free). + */ + const char *filename; + + /** + * Context for transmitting confirmation to client, + * NULL if we've done this already. + */ + struct GNUNET_SERVER_TransmitContext *tc; + + /** + * Context for hashing of the file. + */ + struct GNUNET_CRYPTO_FileHashContext *fhc; + + /** + * Hash of the contents of the file. + */ + GNUNET_HashCode file_id; + +}; + + +/** + * Linked list of indexed files. + */ +static struct IndexInfo *indexed_files; + +/** + * Maps hash over content of indexed files to the respective filename. + * The filenames are pointers into the indexed_files linked list and + * do not need to be freed. + */ +static struct GNUNET_CONTAINER_MultiHashMap *ifm; + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Datastore handle. Created and destroyed by code in + * gnunet-service-fs (this is an alias). + */ +static struct GNUNET_DATASTORE_Handle *dsh; + + +/** + * Write the current index information list to disk. + */ +static void +write_index_list () +{ + struct GNUNET_BIO_WriteHandle *wh; + char *fn; + struct IndexInfo *pos; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + _("Configuration option `%s' in section `%s' missing.\n"), + "INDEXDB", "FS"); + return; + } + wh = GNUNET_BIO_write_open (fn); + if (NULL == wh) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + _("Could not open `%s'.\n"), fn); + GNUNET_free (fn); + return; + } + pos = indexed_files; + while (pos != NULL) + { + if ((GNUNET_OK != + GNUNET_BIO_write (wh, &pos->file_id, sizeof (GNUNET_HashCode))) || + (GNUNET_OK != GNUNET_BIO_write_string (wh, pos->filename))) + break; + pos = pos->next; + } + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + _("Error writing `%s'.\n"), fn); + GNUNET_free (fn); + return; + } + GNUNET_free (fn); +} + + +/** + * Read index information from disk. + */ +static void +read_index_list () +{ + struct GNUNET_BIO_ReadHandle *rh; + char *fn; + struct IndexInfo *pos; + char *fname; + GNUNET_HashCode hc; + size_t slen; + char *emsg; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + _("Configuration option `%s' in section `%s' missing.\n"), + "INDEXDB", "FS"); + return; + } + if (GNUNET_NO == GNUNET_DISK_file_test (fn)) + { + /* no index info yet */ + GNUNET_free (fn); + return; + } + rh = GNUNET_BIO_read_open (fn); + if (NULL == rh) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + _("Could not open `%s'.\n"), fn); + GNUNET_free (fn); + return; + } + while ((GNUNET_OK == + GNUNET_BIO_read (rh, "Hash of indexed file", &hc, + sizeof (GNUNET_HashCode))) && + (GNUNET_OK == + GNUNET_BIO_read_string (rh, "Name of indexed file", &fname, + 1024 * 16)) && (fname != NULL)) + { + slen = strlen (fname) + 1; + pos = GNUNET_malloc (sizeof (struct IndexInfo) + slen); + pos->file_id = hc; + pos->filename = (const char *) &pos[1]; + memcpy (&pos[1], fname, slen); + if (GNUNET_SYSERR == + GNUNET_CONTAINER_multihashmap_put (ifm, &hc, (void *) pos->filename, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) + { + GNUNET_free (pos); + } + else + { + pos->next = indexed_files; + indexed_files = pos; + } + GNUNET_free (fname); + } + if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) + GNUNET_free (emsg); + GNUNET_free (fn); +} + + +/** + * We've validated the hash of the file we're about to index. Signal + * success to the client and update our internal data structures. + * + * @param ii the index info entry for the request + */ +static void +signal_index_ok (struct IndexInfo *ii) +{ + if (GNUNET_SYSERR == + GNUNET_CONTAINER_multihashmap_put (ifm, &ii->file_id, + (void *) ii->filename, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Index request received for file `%s' is already indexed as `%s'. Permitting anyway.\n"), + ii->filename, + (const char *) GNUNET_CONTAINER_multihashmap_get (ifm, + &ii->file_id)); + GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, + GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK); + GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); + GNUNET_free (ii); + return; + } + ii->next = indexed_files; + indexed_files = ii; + write_index_list (); + GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, + GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK); + GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); + ii->tc = NULL; +} + + +/** + * Function called once the hash computation over an + * indexed file has completed. + * + * @param cls closure, our publishing context + * @param res resulting hash, NULL on error + */ +static void +hash_for_index_val (void *cls, const GNUNET_HashCode * res) +{ + struct IndexInfo *ii = cls; + + ii->fhc = NULL; + if ((res == NULL) || + (0 != memcmp (res, &ii->file_id, sizeof (GNUNET_HashCode)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Hash mismatch trying to index file `%s' which has hash `%s'\n"), + ii->filename, GNUNET_h2s (res)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wanted `%s'\n", + GNUNET_h2s (&ii->file_id)); + GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, + GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED); + GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); + GNUNET_free (ii); + return; + } + signal_index_ok (ii); +} + + +/** + * Handle INDEX_START-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +void +GNUNET_FS_handle_index_start (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct IndexStartMessage *ism; + char *fn; + uint16_t msize; + struct IndexInfo *ii; + size_t slen; + uint64_t dev; + uint64_t ino; + uint64_t mydev; + uint64_t myino; + + msize = ntohs (message->size); + if ((msize <= sizeof (struct IndexStartMessage)) || + (((const char *) message)[msize - 1] != '\0')) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + ism = (const struct IndexStartMessage *) message; + if (0 != ism->reserved) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]); + if (fn == NULL) + { + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + dev = GNUNET_ntohll (ism->device); + ino = GNUNET_ntohll (ism->inode); + ism = (const struct IndexStartMessage *) message; + slen = strlen (fn) + 1; + ii = GNUNET_malloc (sizeof (struct IndexInfo) + slen); + ii->filename = (const char *) &ii[1]; + memcpy (&ii[1], fn, slen); + ii->file_id = ism->file_id; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for file `%s'\n", + "START_INDEX", ii->filename); + ii->tc = GNUNET_SERVER_transmit_context_create (client); + mydev = 0; + myino = 0; + if (((dev != 0) || (ino != 0)) && + (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn, &mydev, &myino)) && + ((dev == mydev) && (ino == myino))) + { + /* fast validation OK! */ + signal_index_ok (ii); + GNUNET_free (fn); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n", + (unsigned long long) ino, (unsigned long long) myino, + (unsigned int) dev, (unsigned int) mydev); + /* slow validation, need to hash full file (again) */ + ii->fhc = + GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, fn, + HASHING_BLOCKSIZE, &hash_for_index_val, ii); + if (ii->fhc == NULL) + hash_for_index_val (ii, NULL); + GNUNET_free (fn); +} + + +/** + * Handle INDEX_LIST_GET-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +void +GNUNET_FS_handle_index_list_get (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_SERVER_TransmitContext *tc; + struct IndexInfoMessage *iim; + char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + size_t slen; + const char *fn; + struct IndexInfo *pos; + + tc = GNUNET_SERVER_transmit_context_create (client); + iim = (struct IndexInfoMessage *) buf; + pos = indexed_files; + while (NULL != pos) + { + fn = pos->filename; + slen = strlen (fn) + 1; + if (slen + sizeof (struct IndexInfoMessage) >= + GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + break; + } + iim->header.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY); + iim->header.size = htons (slen + sizeof (struct IndexInfoMessage)); + iim->reserved = 0; + iim->file_id = pos->file_id; + memcpy (&iim[1], fn, slen); + GNUNET_SERVER_transmit_context_append_message (tc, &iim->header); + pos = pos->next; + } + GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END); + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_MINUTES); +} + + +/** + * Handle UNINDEX-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +void +GNUNET_FS_handle_unindex (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct UnindexMessage *um; + struct IndexInfo *pos; + struct IndexInfo *prev; + struct IndexInfo *next; + struct GNUNET_SERVER_TransmitContext *tc; + int found; + + um = (const struct UnindexMessage *) message; + if (0 != um->reserved) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + found = GNUNET_NO; + prev = NULL; + pos = indexed_files; + while (NULL != pos) + { + next = pos->next; + if (0 == memcmp (&pos->file_id, &um->file_id, sizeof (GNUNET_HashCode))) + { + if (prev == NULL) + indexed_files = next; + else + prev->next = next; + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (ifm, &pos->file_id, + (void *) + pos->filename)); + GNUNET_free (pos); + found = GNUNET_YES; + } + else + { + prev = pos; + } + pos = next; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client requested unindexing of file `%s': %s\n", + GNUNET_h2s (&um->file_id), found ? "found" : "not found"); + if (GNUNET_YES == found) + write_index_list (); + tc = GNUNET_SERVER_transmit_context_create (client); + GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK); + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_MINUTES); +} + + +/** + * Continuation called from datastore's remove + * function. + * + * @param cls unused + * @param success did the deletion work? + * @param min_expiration minimum expiration time required for content to be stored + * @param msg error message + */ +static void +remove_cont (void *cls, int success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg) +{ + if (GNUNET_OK != success) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to delete bogus block: %s\n"), msg); +} + + +/** + * We've received an on-demand encoded block from the datastore. + * Attempt to do on-demand encoding and (if successful), call the + * continuation with the resulting block. On error, clean up and ask + * the datastore for more results. + * + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + * @param cont function to call with the actual block (at most once, on success) + * @param cont_cls closure for cont + * @return GNUNET_OK on success + */ +int +GNUNET_FS_handle_on_demand_block (const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, + uint64_t uid, + GNUNET_DATASTORE_DatumProcessor cont, + void *cont_cls) +{ + const struct OnDemandBlock *odb; + GNUNET_HashCode nkey; + struct GNUNET_CRYPTO_AesSessionKey skey; + struct GNUNET_CRYPTO_AesInitializationVector iv; + GNUNET_HashCode query; + ssize_t nsize; + char ndata[DBLOCK_SIZE]; + char edata[DBLOCK_SIZE]; + const char *fn; + struct GNUNET_DISK_FileHandle *fh; + uint64_t off; + + if (size != sizeof (struct OnDemandBlock)) + { + GNUNET_break (0); + GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, + GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); + return GNUNET_SYSERR; + } + odb = (const struct OnDemandBlock *) data; + off = GNUNET_ntohll (odb->offset); + fn = (const char *) GNUNET_CONTAINER_multihashmap_get (ifm, &odb->file_id); + if ((NULL == fn) || (0 != ACCESS (fn, R_OK))) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# index blocks removed: original file inaccessible"), + 1, GNUNET_YES); + GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, + GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); + return GNUNET_SYSERR; + } + if ((NULL == + (fh = + GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE))) || + (off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET)) || + (-1 == (nsize = GNUNET_DISK_file_read (fh, ndata, sizeof (ndata))))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Could not access indexed file `%s' (%s) at offset %llu: %s\n"), + GNUNET_h2s (&odb->file_id), fn, (unsigned long long) off, + (fn == NULL) ? _("not indexed") : STRERROR (errno)); + if (fh != NULL) + GNUNET_DISK_file_close (fh); + GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, + GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); + return GNUNET_SYSERR; + } + GNUNET_DISK_file_close (fh); + GNUNET_CRYPTO_hash (ndata, nsize, &nkey); + GNUNET_CRYPTO_hash_to_aes_key (&nkey, &skey, &iv); + GNUNET_CRYPTO_aes_encrypt (ndata, nsize, &skey, &iv, edata); + GNUNET_CRYPTO_hash (edata, nsize, &query); + if (0 != memcmp (&query, key, sizeof (GNUNET_HashCode))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Indexed file `%s' changed at offset %llu\n"), fn, + (unsigned long long) off); + GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, + GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "On-demand encoded block for query `%s'\n", GNUNET_h2s (key)); + cont (cont_cls, key, nsize, edata, GNUNET_BLOCK_TYPE_FS_DBLOCK, priority, + anonymity, expiration, uid); + return GNUNET_OK; +} + + +/** + * Shutdown the module. + */ +void +GNUNET_FS_indexing_done () +{ + struct IndexInfo *pos; + + GNUNET_CONTAINER_multihashmap_destroy (ifm); + ifm = NULL; + while (NULL != (pos = indexed_files)) + { + indexed_files = pos->next; + if (pos->fhc != NULL) + GNUNET_CRYPTO_hash_file_cancel (pos->fhc); + GNUNET_free (pos); + } + cfg = NULL; +} + + +/** + * Initialize the indexing submodule. + * + * @param c configuration to use + * @param d datastore to use + */ +int +GNUNET_FS_indexing_init (const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_DATASTORE_Handle *d) +{ + cfg = c; + dsh = d; + ifm = GNUNET_CONTAINER_multihashmap_create (128); + read_index_list (); + return GNUNET_OK; +} + +/* 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 new file mode 100644 index 0000000..4295b20 --- /dev/null +++ b/src/fs/gnunet-service-fs_indexing.h @@ -0,0 +1,121 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_indexing.h + * @brief indexing for the file-sharing service + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_FS_INDEXING_H +#define GNUNET_SERVICE_FS_INDEXING_H + +#include "gnunet_block_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_datastore_service.h" +#include "gnunet_peer_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_signatures.h" +#include "gnunet_util_lib.h" + + +/** + * We've received an on-demand encoded block from the datastore. + * Attempt to do on-demand encoding and (if successful), call the + * continuation with the resulting block. On error, clean up and ask + * the datastore for more results. + * + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + * @param cont function to call with the actual block (at most once, on success) + * @param cont_cls closure for cont + * @return GNUNET_OK on success + */ +int +GNUNET_FS_handle_on_demand_block (const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, + uint64_t uid, + GNUNET_DATASTORE_DatumProcessor cont, + void *cont_cls); + +/** + * Handle INDEX_START-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +void +GNUNET_FS_handle_index_start (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + + +/** + * Handle INDEX_LIST_GET-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +void +GNUNET_FS_handle_index_list_get (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + + +/** + * Handle UNINDEX-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +void +GNUNET_FS_handle_unindex (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + + +/** + * Initialize the indexing submodule. + * + * @param c configuration to use + * @param d datastore to use + * @return GNUNET_OK on success + */ +int +GNUNET_FS_indexing_init (const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_DATASTORE_Handle *d); + + +/** + * Shutdown the module. + */ +void +GNUNET_FS_indexing_done (void); + + +#endif diff --git a/src/fs/gnunet-service-fs_lc.c b/src/fs/gnunet-service-fs_lc.c new file mode 100644 index 0000000..36aafdd --- /dev/null +++ b/src/fs/gnunet-service-fs_lc.c @@ -0,0 +1,510 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_lc.c + * @brief API to handle 'local clients' + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet-service-fs.h" +#include "gnunet-service-fs_lc.h" +#include "gnunet-service-fs_cp.h" +#include "gnunet-service-fs_pr.h" + + +/** + * Doubly-linked list of requests we are performing + * on behalf of the same client. + */ +struct ClientRequest +{ + + /** + * This is a doubly-linked list. + */ + struct ClientRequest *next; + + /** + * This is a doubly-linked list. + */ + struct ClientRequest *prev; + + /** + * Request this entry represents. + */ + struct GSF_PendingRequest *pr; + + /** + * Client list this request belongs to. + */ + struct GSF_LocalClient *lc; + + /** + * Task scheduled to destroy the request. + */ + GNUNET_SCHEDULER_TaskIdentifier kill_task; + +}; + + +/** + * Replies to be transmitted to the client. The actual + * response message is allocated after this struct. + */ +struct ClientResponse +{ + /** + * This is a doubly-linked list. + */ + struct ClientResponse *next; + + /** + * This is a doubly-linked list. + */ + struct ClientResponse *prev; + + /** + * Client list entry this response belongs to. + */ + struct GSF_LocalClient *lc; + + /** + * Number of bytes in the response. + */ + size_t msize; +}; + + +/** + * A local client. + */ +struct GSF_LocalClient +{ + + /** + * We keep clients in a DLL. + */ + struct GSF_LocalClient *next; + + /** + * We keep clients in a DLL. + */ + struct GSF_LocalClient *prev; + + /** + * ID of the client. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Head of list of requests performed on behalf + * of this client right now. + */ + struct ClientRequest *cr_head; + + /** + * Tail of list of requests performed on behalf + * of this client right now. + */ + struct ClientRequest *cr_tail; + + /** + * Head of linked list of responses. + */ + struct ClientResponse *res_head; + + /** + * Tail of linked list of responses. + */ + struct ClientResponse *res_tail; + + /** + * Context for sending replies. + */ + struct GNUNET_CONNECTION_TransmitHandle *th; + +}; + + +/** + * Head of linked list of our local clients. + */ +static struct GSF_LocalClient *client_head; + + +/** + * Head of linked list of our local clients. + */ +static struct GSF_LocalClient *client_tail; + + +/** + * Look up a local client record or create one if it + * doesn't exist yet. + * + * @param client handle of the client + * @return handle to local client entry + */ +struct GSF_LocalClient * +GSF_local_client_lookup_ (struct GNUNET_SERVER_Client *client) +{ + struct GSF_LocalClient *pos; + + pos = client_head; + while ((pos != NULL) && (pos->client != client)) + pos = pos->next; + if (pos != NULL) + return pos; + pos = GNUNET_malloc (sizeof (struct GSF_LocalClient)); + pos->client = client; + GNUNET_CONTAINER_DLL_insert (client_head, client_tail, pos); + return pos; +} + + +/** + * Free the given client request. + * + * @param cls the client request to free + * @param tc task context + */ +static void +client_request_destroy (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ClientRequest *cr = cls; + struct GSF_LocalClient *lc; + + cr->kill_task = GNUNET_SCHEDULER_NO_TASK; + lc = cr->lc; + GNUNET_CONTAINER_DLL_remove (lc->cr_head, lc->cr_tail, cr); + GSF_pending_request_cancel_ (cr->pr, GNUNET_NO); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# client searches active"), -1, + GNUNET_NO); + GNUNET_free (cr); +} + + +/** + * Handle a reply to a pending request. Also called if a request + * expires (then with data == NULL). The handler may be called + * many times (depending on the request type), but will not be + * called during or after a call to GSF_pending_request_cancel + * and will also not be called anymore after a call signalling + * expiration. + * + * @param cls user-specified closure + * @param eval evaluation of the result + * @param pr handle to the original pending request + * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" + * @param expiration when does 'data' expire? + * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown) + * @param type type of the block + * @param data response data, NULL on request expiration + * @param data_len number of bytes in data + */ +static void +client_response_handler (void *cls, enum GNUNET_BLOCK_EvaluationResult eval, + struct GSF_PendingRequest *pr, + uint32_t reply_anonymity_level, + struct GNUNET_TIME_Absolute expiration, + struct GNUNET_TIME_Absolute last_transmission, + enum GNUNET_BLOCK_Type type, const void *data, + size_t data_len) +{ + struct ClientRequest *cr = cls; + struct GSF_LocalClient *lc; + struct ClientPutMessage *pm; + const struct GSF_PendingRequestData *prd; + size_t msize; + + if (NULL == data) + { + /* ugh, request 'timed out' -- how can this be? */ + GNUNET_break (0); + return; + } + prd = GSF_pending_request_get_data_ (pr); + GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY); + if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY)) + { + GNUNET_break (0); + return; + } + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# replies received for local clients"), 1, + GNUNET_NO); + GNUNET_assert (pr == cr->pr); + lc = cr->lc; + msize = sizeof (struct ClientPutMessage) + data_len; + { + char buf[msize]; + + pm = (struct ClientPutMessage *) buf; + pm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT); + pm->header.size = htons (msize); + pm->type = htonl (type); + pm->expiration = GNUNET_TIME_absolute_hton (expiration); + pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission); + memcpy (&pm[1], data, data_len); + GSF_local_client_transmit_ (lc, &pm->header); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Queued reply to query `%s' for local client\n", + GNUNET_h2s (&prd->query), (unsigned int) prd->type); + if (eval != GNUNET_BLOCK_EVALUATION_OK_LAST) + return; + if (GNUNET_SCHEDULER_NO_TASK != cr->kill_task) + cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy, cr); +} + + +/** + * Handle START_SEARCH-message (search request from local client). + * Only responsible for creating the request entry itself and setting + * up reply callback and cancellation on client disconnect. Does NOT + * execute the actual request strategy (planning). + * + * @param client identification of the client + * @param message the actual message + * @param prptr where to store the pending request handle for the request + * @return GNUNET_YES to start local processing, + * GNUNET_NO to not (yet) start local processing, + * GNUNET_SYSERR on error + */ +int +GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader + *message, + struct GSF_PendingRequest **prptr) +{ + static GNUNET_HashCode all_zeros; + const struct SearchMessage *sm; + struct GSF_LocalClient *lc; + struct ClientRequest *cr; + struct GSF_PendingRequestData *prd; + uint16_t msize; + unsigned int sc; + enum GNUNET_BLOCK_Type type; + enum GSF_PendingRequestOptions options; + + msize = ntohs (message->size); + if ((msize < sizeof (struct SearchMessage)) || + (0 != (msize - sizeof (struct SearchMessage)) % sizeof (GNUNET_HashCode))) + { + GNUNET_break (0); + *prptr = NULL; + return GNUNET_SYSERR; + } + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# client searches received"), 1, + GNUNET_NO); + sc = (msize - sizeof (struct SearchMessage)) / sizeof (GNUNET_HashCode); + sm = (const struct SearchMessage *) message; + type = ntohl (sm->type); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received request for `%s' of type %u from local client\n", + GNUNET_h2s (&sm->query), (unsigned int) type); + lc = GSF_local_client_lookup_ (client); + cr = NULL; + /* detect duplicate KBLOCK requests */ + if ((type == GNUNET_BLOCK_TYPE_FS_KBLOCK) || + (type == GNUNET_BLOCK_TYPE_FS_NBLOCK) || (type == GNUNET_BLOCK_TYPE_ANY)) + { + cr = lc->cr_head; + while (cr != NULL) + { + prd = GSF_pending_request_get_data_ (cr->pr); + /* only unify with queries that hae not yet started local processing + (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a + matching query and type */ + if ((GNUNET_YES != prd->has_started) && + (0 != memcmp (&prd->query, &sm->query, sizeof (GNUNET_HashCode))) && + (prd->type == type)) + break; + cr = cr->next; + } + } + if (cr != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Have existing request, merging content-seen lists.\n"); + GSF_pending_request_update_ (cr->pr, (const GNUNET_HashCode *) &sm[1], sc); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# client searches updated (merged content seen list)"), + 1, GNUNET_NO); + } + else + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# client searches active"), 1, + GNUNET_NO); + cr = GNUNET_malloc (sizeof (struct ClientRequest)); + cr->lc = lc; + GNUNET_CONTAINER_DLL_insert (lc->cr_head, lc->cr_tail, cr); + options = GSF_PRO_LOCAL_REQUEST; + if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options))) + options |= GSF_PRO_LOCAL_ONLY; + cr->pr = GSF_pending_request_create_ (options, type, &sm->query, (type == GNUNET_BLOCK_TYPE_FS_SBLOCK) ? &sm->target /* namespace */ + : NULL, + (0 != + memcmp (&sm->target, &all_zeros, + sizeof (GNUNET_HashCode))) + ? (const struct GNUNET_PeerIdentity *) + &sm->target : NULL, NULL, 0, + 0 /* bf */ , + ntohl (sm->anonymity_level), + 0 /* priority */ , + 0 /* ttl */ , + 0 /* sender PID */ , + 0 /* origin PID */ , + (const GNUNET_HashCode *) &sm[1], sc, + &client_response_handler, cr); + } + *prptr = cr->pr; + return (0 != + (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options))) ? GNUNET_NO : + GNUNET_YES; +} + + +/** + * Transmit the given message by copying it to the target buffer + * "buf". "buf" will be NULL and "size" zero if the socket was closed + * for writing in the meantime. In that case, do nothing + * (the disconnect or shutdown handler will take care of the rest). + * If we were able to transmit messages and there are still more + * pending, ask core again for further calls to this function. + * + * @param cls closure, pointer to the 'struct GSF_LocalClient' + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_to_client (void *cls, size_t size, void *buf) +{ + struct GSF_LocalClient *lc = cls; + char *cbuf = buf; + struct ClientResponse *res; + size_t msize; + + lc->th = NULL; + if (NULL == buf) + return 0; + msize = 0; + while ((NULL != (res = lc->res_head)) && (res->msize <= size)) + { + memcpy (&cbuf[msize], &res[1], res->msize); + msize += res->msize; + size -= res->msize; + GNUNET_CONTAINER_DLL_remove (lc->res_head, lc->res_tail, res); + GNUNET_free (res); + } + if (NULL != res) + lc->th = + GNUNET_SERVER_notify_transmit_ready (lc->client, res->msize, + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_to_client, lc); + return msize; +} + + +/** + * Transmit a message to the given local client as soon as possible. + * If the client disconnects before transmission, the message is + * simply discarded. + * + * @param lc recipient + * @param msg message to transmit to client + */ +void +GSF_local_client_transmit_ (struct GSF_LocalClient *lc, + const struct GNUNET_MessageHeader *msg) +{ + struct ClientResponse *res; + size_t msize; + + msize = ntohs (msg->size); + res = GNUNET_malloc (sizeof (struct ClientResponse) + msize); + res->lc = lc; + res->msize = msize; + memcpy (&res[1], msg, msize); + GNUNET_CONTAINER_DLL_insert_tail (lc->res_head, lc->res_tail, res); + if (NULL == lc->th) + lc->th = + GNUNET_SERVER_notify_transmit_ready (lc->client, msize, + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_to_client, lc); +} + + +/** + * A client disconnected from us. Tear down the local client + * record. + * + * @param cls unused + * @param client handle of the client + */ +void +GSF_client_disconnect_handler_ (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct GSF_LocalClient *pos; + struct ClientRequest *cr; + struct ClientResponse *res; + + pos = client_head; + while ((pos != NULL) && (pos->client != client)) + pos = pos->next; + if (pos == NULL) + return; + while (NULL != (cr = pos->cr_head)) + { + GNUNET_CONTAINER_DLL_remove (pos->cr_head, pos->cr_tail, cr); + GSF_pending_request_cancel_ (cr->pr, GNUNET_NO); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# client searches active"), -1, + GNUNET_NO); + if (GNUNET_SCHEDULER_NO_TASK != cr->kill_task) + GNUNET_SCHEDULER_cancel (cr->kill_task); + GNUNET_free (cr); + } + while (NULL != (res = pos->res_head)) + { + GNUNET_CONTAINER_DLL_remove (pos->res_head, pos->res_tail, res); + GNUNET_free (res); + } + if (pos->th != NULL) + { + GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th); + pos->th = NULL; + } + GSF_handle_local_client_disconnect_ (pos); + GNUNET_CONTAINER_DLL_remove (client_head, client_tail, pos); + GNUNET_free (pos); +} + + +/* end of gnunet-service-fs_lc.c */ diff --git a/src/fs/gnunet-service-fs_lc.h b/src/fs/gnunet-service-fs_lc.h new file mode 100644 index 0000000..3bddb89 --- /dev/null +++ b/src/fs/gnunet-service-fs_lc.h @@ -0,0 +1,87 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_lc.h + * @brief API to handle 'local clients' + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_FS_LC_H +#define GNUNET_SERVICE_FS_LC_H + +#include "gnunet-service-fs.h" + + +/** + * Look up a local client record or create one if it + * doesn't exist yet. + * + * @param client handle of the client + * @return handle to local client entry + */ +struct GSF_LocalClient * +GSF_local_client_lookup_ (struct GNUNET_SERVER_Client *client); + + +/** + * Handle START_SEARCH-message (search request from local client). + * Only responsible for creating the request entry itself and setting + * up reply callback and cancellation on client disconnect. Does NOT + * execute the actual request strategy (planning). + * + * @param client identification of the client + * @param message the actual message + * @param prptr where to store the pending request handle for the request + * @return GNUNET_YES to start local processing, + * GNUNET_NO to not (yet) start local processing, + * GNUNET_SYSERR on error + */ +int +GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader + *message, + struct GSF_PendingRequest **prptr); + + +/** + * Transmit a message to the given local client as soon as possible. + * If the client disconnects before transmission, the message is + * simply discarded. + * + * @param lc recipient + * @param msg message to transmit to client + */ +void +GSF_local_client_transmit_ (struct GSF_LocalClient *lc, + const struct GNUNET_MessageHeader *msg); + + +/** + * A client disconnected from us. Tear down the local client record. + * + * @param cls unused + * @param client handle of the client + */ +void +GSF_client_disconnect_handler_ (void *cls, struct GNUNET_SERVER_Client *client); + + +#endif +/* end of gnunet-service-fs_lc.h */ diff --git a/src/fs/gnunet-service-fs_pe.c b/src/fs/gnunet-service-fs_pe.c new file mode 100644 index 0000000..71b0fc0 --- /dev/null +++ b/src/fs/gnunet-service-fs_pe.c @@ -0,0 +1,775 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_pe.c + * @brief API to manage query plan + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-fs.h" +#include "gnunet-service-fs_cp.h" +#include "gnunet-service-fs_pe.h" +#include "gnunet-service-fs_pr.h" + + +/** + * List of GSF_PendingRequests this request plan + * participates with. + */ +struct PendingRequestList; + +/** + * Transmission plan for a peer. + */ +struct PeerPlan; + + +/** + * DLL of request plans a particular pending request is + * involved with. + */ +struct GSF_RequestPlanReference +{ + + /** + * This is a doubly-linked list. + */ + struct GSF_RequestPlanReference *next; + + /** + * This is a doubly-linked list. + */ + struct GSF_RequestPlanReference *prev; + + /** + * Associated request plan. + */ + struct GSF_RequestPlan *rp; + + /** + * Corresponding PendingRequestList. + */ + struct PendingRequestList *prl; +}; + + +/** + * List of GSF_PendingRequests this request plan + * participates with. + */ +struct PendingRequestList +{ + + /** + * This is a doubly-linked list. + */ + struct PendingRequestList *next; + + /** + * This is a doubly-linked list. + */ + struct PendingRequestList *prev; + + /** + * Associated pending request. + */ + struct GSF_PendingRequest *pr; + + /** + * Corresponding GSF_RequestPlanReference. + */ + struct GSF_RequestPlanReference *rpr; + +}; + + +/** + * Information we keep per request per peer. This is a doubly-linked + * list (with head and tail in the 'struct GSF_PendingRequestData') + * with one entry in each heap of each 'struct PeerPlan'. Each + * entry tracks information relevant for this request and this peer. + */ +struct GSF_RequestPlan +{ + + /** + * This is a doubly-linked list. + */ + struct GSF_RequestPlan *next; + + /** + * This is a doubly-linked list. + */ + struct GSF_RequestPlan *prev; + + /** + * Heap node associated with this request and this peer. + */ + struct GNUNET_CONTAINER_HeapNode *hn; + + /** + * The transmission plan for a peer that this request is associated with. + */ + struct PeerPlan *pp; + + /** + * Head of list of associated pending requests. + */ + struct PendingRequestList *prl_head; + + /** + * Tail of list of associated pending requests. + */ + struct PendingRequestList *prl_tail; + + /** + * Earliest time we'd be happy to (re)transmit this request. + */ + struct GNUNET_TIME_Absolute earliest_transmission; + + /** + * When was the last time we transmitted this request to this peer? 0 for never. + */ + struct GNUNET_TIME_Absolute last_transmission; + + /** + * Current priority for this request for this target. + */ + uint64_t priority; + + /** + * How often did we transmit this request to this peer? + */ + unsigned int transmission_counter; + +}; + + +/** + * Transmission plan for a peer. + */ +struct PeerPlan +{ + /** + * Heap with pending queries (struct GSF_RequestPlan), higher weights mean higher priority. + */ + struct GNUNET_CONTAINER_Heap *priority_heap; + + /** + * Heap with pending queries (struct GSF_RequestPlan), by transmission time, lowest first. + */ + struct GNUNET_CONTAINER_Heap *delay_heap; + + /** + * Map of queries to plan entries. All entries in the priority_heap or delay_heap + * should be in the plan map. Note that it IS possible for the plan map to have + * multiple entries for the same query. + */ + struct GNUNET_CONTAINER_MultiHashMap *plan_map; + + /** + * Current transmission request handle. + */ + struct GSF_PeerTransmitHandle *pth; + + /** + * Peer for which this is the plan. + */ + struct GSF_ConnectedPeer *cp; + + /** + * Current task for executing the plan. + */ + GNUNET_SCHEDULER_TaskIdentifier task; +}; + + +/** + * Hash map from peer identities to PeerPlans. + */ +static struct GNUNET_CONTAINER_MultiHashMap *plans; + +/** + * Sum of all transmission counters (equals total delay for all plan entries). + */ +static unsigned long long total_delay; + +/** + * Number of plan entries. + */ +static unsigned long long plan_count; + + +/** + * Return the query (key in the plan_map) for the given request plan. + * + * @param rp a request plan + * @return the associated query + */ +static const GNUNET_HashCode * +get_rp_key (struct GSF_RequestPlan *rp) +{ + return &GSF_pending_request_get_data_ (rp->prl_head->pr)->query; +} + + +/** + * Figure out when and how to transmit to the given peer. + * + * @param cls the 'struct GSF_ConnectedPeer' for transmission + * @param tc scheduler context + */ +static void +schedule_peer_transmission (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Insert the given request plan into the heap with the appropriate weight. + * + * @param pp associated peer's plan + * @param rp request to plan + */ +static void +plan (struct PeerPlan *pp, struct GSF_RequestPlan *rp) +{ +#define N ((double)128.0) + /** + * Running average delay we currently impose. + */ + static double avg_delay; + + struct GSF_PendingRequestData *prd; + struct GNUNET_TIME_Relative delay; + + GNUNET_assert (rp->pp == pp); + GNUNET_STATISTICS_set (GSF_stats, + gettext_noop ("# average retransmission delay (ms)"), + total_delay * 1000LL / plan_count, GNUNET_NO); + prd = GSF_pending_request_get_data_ (rp->prl_head->pr); + + if (rp->transmission_counter < 8) + delay = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, + rp->transmission_counter); + else if (rp->transmission_counter < 32) + delay = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, + 8 + + (1LL << (rp->transmission_counter - 8))); + else + delay = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, + 8 + (1LL << 24)); + delay.rel_value = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + delay.rel_value + 1); + /* Add 0.01 to avg_delay to avoid division-by-zero later */ + avg_delay = (((avg_delay * (N - 1.0)) + delay.rel_value) / N) + 0.01; + + /* + * For the priority, we need to consider a few basic rules: + * 1) if we just started requesting (delay is small), we should + * virtually always have a priority of zero. + * 2) for requests with average latency, our priority should match + * the average priority observed on the network + * 3) even the longest-running requests should not be WAY out of + * the observed average (thus we bound by a factor of 2) + * 4) we add +1 to the observed average priority to avoid everyone + * staying put at zero (2 * 0 = 0...). + * + * Using the specific calculation below, we get: + * + * delay = 0 => priority = 0; + * delay = avg delay => priority = running-average-observed-priority; + * delay >> avg_delay => priority = 2 * running-average-observed-priority; + * + * which satisfies all of the rules above. + * + * Note: M_PI_4 = PI/4 = arctan(1) + */ + rp->priority = + round ((GSF_current_priorities + + 1.0) * atan (delay.rel_value / avg_delay)) / M_PI_4; + /* Note: usage of 'round' and 'atan' requires -lm */ + + if (rp->transmission_counter != 0) + delay.rel_value += TTL_DECREMENT; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Considering (re)transmission number %u in %llu ms\n", + (unsigned int) rp->transmission_counter, + (unsigned long long) delay.rel_value); + rp->earliest_transmission = GNUNET_TIME_relative_to_absolute (delay); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Earliest (re)transmission for `%s' in %us\n", + GNUNET_h2s (&prd->query), rp->transmission_counter); + GNUNET_assert (rp->hn == NULL); + if (GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value + == 0) + rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority); + else + rp->hn = + GNUNET_CONTAINER_heap_insert (pp->delay_heap, rp, + rp->earliest_transmission.abs_value); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains_value (pp->plan_map, + get_rp_key (rp), + rp)); + if (GNUNET_SCHEDULER_NO_TASK != pp->task) + GNUNET_SCHEDULER_cancel (pp->task); + pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp); +#undef N +} + + +/** + * Get the pending request with the highest TTL from the given plan. + * + * @param rp plan to investigate + * @return pending request with highest TTL + */ +struct GSF_PendingRequest * +get_latest (const struct GSF_RequestPlan *rp) +{ + struct GSF_PendingRequest *ret; + struct PendingRequestList *prl; + + prl = rp->prl_head; + ret = prl->pr; + prl = prl->next; + while (NULL != prl) + { + if (GSF_pending_request_get_data_ (prl->pr)->ttl.abs_value > + GSF_pending_request_get_data_ (ret)->ttl.abs_value) + ret = prl->pr; + prl = prl->next; + } + return ret; +} + + +/** + * Function called to get a message for transmission. + * + * @param cls closure + * @param buf_size number of bytes available in buf + * @param buf where to copy the message, NULL on error (peer disconnect) + * @return number of bytes copied to 'buf', can be 0 (without indicating an error) + */ +static size_t +transmit_message_callback (void *cls, size_t buf_size, void *buf) +{ + struct PeerPlan *pp = cls; + struct GSF_RequestPlan *rp; + size_t msize; + + pp->pth = NULL; + if (NULL == buf) + { + /* failed, try again... */ + pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# transmission failed (core has no bandwidth)"), + 1, GNUNET_NO); + return 0; + } + rp = GNUNET_CONTAINER_heap_peek (pp->priority_heap); + if (NULL == rp) + { + pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp); + return 0; + } + msize = GSF_pending_request_get_message_ (get_latest (rp), buf_size, buf); + if (msize > buf_size) + { + /* buffer to small (message changed), try again */ + pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp); + return 0; + } + /* remove from root, add again elsewhere... */ + GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->priority_heap)); + rp->hn = NULL; + rp->last_transmission = GNUNET_TIME_absolute_get (); + rp->transmission_counter++; + total_delay++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Executing plan %p executed %u times, planning retransmission\n", + rp, rp->transmission_counter); + plan (pp, rp); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# query messages sent to other peers"), 1, + GNUNET_NO); + return msize; +} + + +/** + * Figure out when and how to transmit to the given peer. + * + * @param cls the 'struct PeerPlan' + * @param tc scheduler context + */ +static void +schedule_peer_transmission (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerPlan *pp = cls; + struct GSF_RequestPlan *rp; + size_t msize; + struct GNUNET_TIME_Relative delay; + + pp->task = GNUNET_SCHEDULER_NO_TASK; + if (pp->pth != NULL) + { + GSF_peer_transmit_cancel_ (pp->pth); + pp->pth = NULL; + } + /* move ready requests to priority queue */ + while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) && + (GNUNET_TIME_absolute_get_remaining + (rp->earliest_transmission).rel_value == 0)) + { + GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->delay_heap)); + rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority); + } + if (0 == GNUNET_CONTAINER_heap_get_size (pp->priority_heap)) + { + /* priority heap (still) empty, check for delay... */ + rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap); + if (NULL == rp) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No active requests for plan %p.\n", + pp); + return; /* both queues empty */ + } + delay = GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sleeping for %llu ms before retrying requests on plan %p.\n", + (unsigned long long) delay.rel_value, pp); + GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# delay heap timeout"), + delay.rel_value, GNUNET_NO); + + pp->task = + GNUNET_SCHEDULER_add_delayed (delay, &schedule_peer_transmission, pp); + return; + } + GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plans executed"), + 1, GNUNET_NO); + /* process from priority heap */ + rp = GNUNET_CONTAINER_heap_peek (pp->priority_heap); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing query plan %p\n", rp); + GNUNET_assert (NULL != rp); + msize = GSF_pending_request_get_message_ (get_latest (rp), 0, NULL); + pp->pth = + GSF_peer_transmit_ (pp->cp, GNUNET_YES, rp->priority, + GNUNET_TIME_UNIT_FOREVER_REL, msize, + &transmit_message_callback, pp); + GNUNET_assert (NULL != pp->pth); +} + + +/** + * Closure for 'merge_pr'. + */ +struct MergeContext +{ + + struct GSF_PendingRequest *pr; + + int merged; + +}; + + +/** + * Iterator that checks if an equivalent request is already + * present for this peer. + * + * @param cls closure + * @param query the query + * @param element request plan stored at the node + * @return GNUNET_YES if we should continue to iterate, + * GNUNET_NO if not (merge success) + */ +static int +merge_pr (void *cls, const GNUNET_HashCode * query, void *element) +{ + struct MergeContext *mpr = cls; + struct GSF_RequestPlan *rp = element; + struct GSF_PendingRequestData *prd; + struct GSF_RequestPlanReference *rpr; + struct PendingRequestList *prl; + struct GSF_PendingRequest *latest; + + if (GNUNET_OK != + GSF_pending_request_is_compatible_ (mpr->pr, rp->prl_head->pr)) + return GNUNET_YES; + /* merge new request with existing request plan */ + rpr = GNUNET_malloc (sizeof (struct GSF_RequestPlanReference)); + prl = GNUNET_malloc (sizeof (struct PendingRequestList)); + rpr->rp = rp; + rpr->prl = prl; + prl->rpr = rpr; + prl->pr = mpr->pr; + prd = GSF_pending_request_get_data_ (mpr->pr); + GNUNET_CONTAINER_DLL_insert (prd->rpr_head, prd->rpr_tail, rpr); + GNUNET_CONTAINER_DLL_insert (rp->prl_head, rp->prl_tail, prl); + mpr->merged = GNUNET_YES; + GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests merged"), 1, + GNUNET_NO); + latest = get_latest (rp); + if (GSF_pending_request_get_data_ (latest)->ttl.abs_value < + prd->ttl.abs_value) + { + GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests refreshed"), + 1, GNUNET_NO); + rp->transmission_counter = 0; /* reset */ + } + return GNUNET_NO; +} + + +/** + * Create a new query plan entry. + * + * @param cp peer with the entry + * @param pr request with the entry + */ +void +GSF_plan_add_ (struct GSF_ConnectedPeer *cp, struct GSF_PendingRequest *pr) +{ + struct GNUNET_PeerIdentity id; + struct PeerPlan *pp; + struct GSF_PendingRequestData *prd; + struct GSF_RequestPlan *rp; + struct GSF_RequestPlanReference *rpr; + struct PendingRequestList *prl; + struct MergeContext mpc; + + GNUNET_assert (NULL != cp); + GSF_connected_peer_get_identity_ (cp, &id); + pp = GNUNET_CONTAINER_multihashmap_get (plans, &id.hashPubKey); + if (NULL == pp) + { + pp = GNUNET_malloc (sizeof (struct PeerPlan)); + pp->plan_map = GNUNET_CONTAINER_multihashmap_create (128); + pp->priority_heap = + GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); + pp->delay_heap = + GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + pp->cp = cp; + GNUNET_CONTAINER_multihashmap_put (plans, &id.hashPubKey, pp, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + } + mpc.merged = GNUNET_NO; + mpc.pr = pr; + GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map, + &GSF_pending_request_get_data_ + (pr)->query, &merge_pr, &mpc); + if (mpc.merged != GNUNET_NO) + return; + GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map, + &GSF_pending_request_get_data_ + (pr)->query, &merge_pr, &mpc); + if (mpc.merged != GNUNET_NO) + return; + plan_count++; + GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plan entries"), 1, + GNUNET_NO); + prd = GSF_pending_request_get_data_ (pr); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Planning transmission of query `%s' to peer `%s'\n", + GNUNET_h2s (&prd->query), GNUNET_i2s (&id)); + rp = GNUNET_malloc (sizeof (struct GSF_RequestPlan)); + rpr = GNUNET_malloc (sizeof (struct GSF_RequestPlanReference)); + prl = GNUNET_malloc (sizeof (struct PendingRequestList)); + rpr->rp = rp; + rpr->prl = prl; + prl->rpr = rpr; + prl->pr = pr; + GNUNET_CONTAINER_DLL_insert (prd->rpr_head, prd->rpr_tail, rpr); + GNUNET_CONTAINER_DLL_insert (rp->prl_head, rp->prl_tail, prl); + rp->pp = pp; + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_put (pp->plan_map, + get_rp_key (rp), rp, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + plan (pp, rp); +} + + +/** + * Notify the plan about a peer being no longer available; + * destroy all entries associated with this peer. + * + * @param cp connected peer + */ +void +GSF_plan_notify_peer_disconnect_ (const struct GSF_ConnectedPeer *cp) +{ + struct GNUNET_PeerIdentity id; + struct PeerPlan *pp; + struct GSF_RequestPlan *rp; + struct GSF_PendingRequestData *prd; + struct PendingRequestList *prl; + + GSF_connected_peer_get_identity_ (cp, &id); + pp = GNUNET_CONTAINER_multihashmap_get (plans, &id.hashPubKey); + if (NULL == pp) + return; /* nothing was ever planned for this peer */ + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (plans, &id.hashPubKey, + pp)); + if (NULL != pp->pth) + GSF_peer_transmit_cancel_ (pp->pth); + if (GNUNET_SCHEDULER_NO_TASK != pp->task) + { + GNUNET_SCHEDULER_cancel (pp->task); + pp->task = GNUNET_SCHEDULER_NO_TASK; + } + while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap))) + { + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (pp->plan_map, + get_rp_key (rp), rp)); + while (NULL != (prl = rp->prl_head)) + { + GNUNET_CONTAINER_DLL_remove (rp->prl_head, rp->prl_tail, prl); + prd = GSF_pending_request_get_data_ (prl->pr); + GNUNET_CONTAINER_DLL_remove (prd->rpr_head, prd->rpr_tail, prl->rpr); + GNUNET_free (prl->rpr); + GNUNET_free (prl); + } + GNUNET_free (rp); + } + GNUNET_CONTAINER_heap_destroy (pp->priority_heap); + while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->delay_heap))) + { + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (pp->plan_map, + get_rp_key (rp), rp)); + while (NULL != (prl = rp->prl_head)) + { + GNUNET_CONTAINER_DLL_remove (rp->prl_head, rp->prl_tail, prl); + prd = GSF_pending_request_get_data_ (prl->pr); + GNUNET_CONTAINER_DLL_remove (prd->rpr_head, prd->rpr_tail, prl->rpr); + GNUNET_free (prl->rpr); + GNUNET_free (prl); + } + GNUNET_free (rp); + } + GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# query plan entries"), + plan_count, GNUNET_NO); + + GNUNET_CONTAINER_heap_destroy (pp->delay_heap); + GNUNET_CONTAINER_multihashmap_destroy (pp->plan_map); + GNUNET_free (pp); +} + +/** + * Get the last transmission attempt time for the request plan list + * referenced by 'rpr_head', that was sent to 'sender' + * + * @param rpr_head request plan reference list to check. + * @param sender the peer that we've sent the request to. + * @param result the timestamp to fill. + * @return GNUNET_YES if 'result' was changed, GNUNET_NO otherwise. + */ +int +GSF_request_plan_reference_get_last_transmission_ ( + struct GSF_RequestPlanReference *rpr_head, struct GSF_ConnectedPeer *sender, + struct GNUNET_TIME_Absolute *result) +{ + struct GSF_RequestPlanReference *rpr; + for (rpr = rpr_head; rpr; rpr = rpr->next) + { + if (rpr->rp->pp->cp == sender) + { + *result = rpr->rp->last_transmission; + return GNUNET_YES; + } + } + return GNUNET_NO; +} + +/** + * Notify the plan about a request being done; destroy all entries + * associated with this request. + * + * @param pr request that is done + */ +void +GSF_plan_notify_request_done_ (struct GSF_PendingRequest *pr) +{ + struct GSF_RequestPlan *rp; + struct GSF_PendingRequestData *prd; + struct GSF_RequestPlanReference *rpr; + + prd = GSF_pending_request_get_data_ (pr); + while (NULL != (rpr = prd->rpr_head)) + { + GNUNET_CONTAINER_DLL_remove (prd->rpr_head, prd->rpr_tail, rpr); + rp = rpr->rp; + GNUNET_CONTAINER_DLL_remove (rp->prl_head, rp->prl_tail, rpr->prl); + if (NULL == rp->prl_head) + { + GNUNET_CONTAINER_heap_remove_node (rp->hn); + plan_count--; + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (rp->pp->plan_map, + &GSF_pending_request_get_data_ + (rpr->prl->pr)->query, + rp)); + GNUNET_free (rp); + } + GNUNET_free (rpr->prl); + GNUNET_free (rpr); + } + GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# query plan entries"), + plan_count, GNUNET_NO); +} + + +/** + * Initialize plan subsystem. + */ +void +GSF_plan_init () +{ + plans = GNUNET_CONTAINER_multihashmap_create (256); +} + + +/** + * Shutdown plan subsystem. + */ +void +GSF_plan_done () +{ + GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (plans)); + GNUNET_CONTAINER_multihashmap_destroy (plans); +} + + + +/* 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 new file mode 100644 index 0000000..3a18715 --- /dev/null +++ b/src/fs/gnunet-service-fs_pe.h @@ -0,0 +1,90 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_pe.h + * @brief API to manage query plan + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_FS_PE_H +#define GNUNET_SERVICE_FS_PE_H + +#include "gnunet-service-fs.h" + + +/** + * Create a new query plan entry. + * + * @param cp peer with the entry + * @param pr request with the entry + */ +void +GSF_plan_add_ (struct GSF_ConnectedPeer *cp, struct GSF_PendingRequest *pr); + + +/** + * Notify the plan about a peer being no longer available; + * destroy all entries associated with this peer. + * + * @param cp connected peer + */ +void +GSF_plan_notify_peer_disconnect_ (const struct GSF_ConnectedPeer *cp); + + +/** + * Notify the plan about a request being done; + * destroy all entries associated with this request. + * + * @param pr request that is done + */ +void +GSF_plan_notify_request_done_ (struct GSF_PendingRequest *pr); + +/** + * Get the last transmission attempt time for the request plan list + * referenced by 'rpr_head', that was sent to 'sender' + * + * @param rpr_head request plan reference list to check. + * @param sender the peer that we've sent the request to. + * @param result the timestamp to fill. + * @return GNUNET_YES if 'result' was changed, GNUNET_NO otherwise. + */ +int +GSF_request_plan_reference_get_last_transmission_ ( + struct GSF_RequestPlanReference *rpr_head, struct GSF_ConnectedPeer *sender, + struct GNUNET_TIME_Absolute *result); + +/** + * Initialize plan subsystem. + */ +void +GSF_plan_init (void); + + +/** + * Shutdown plan subsystem. + */ +void +GSF_plan_done (void); + + +#endif +/* 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 new file mode 100644 index 0000000..d4b4481 --- /dev/null +++ b/src/fs/gnunet-service-fs_pr.c @@ -0,0 +1,1644 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_pr.c + * @brief API to handle pending requests + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_load_lib.h" +#include "gnunet-service-fs.h" +#include "gnunet-service-fs_cp.h" +#include "gnunet-service-fs_indexing.h" +#include "gnunet-service-fs_pe.h" +#include "gnunet-service-fs_pr.h" + +/** + * Maximum size of the datastore queue for P2P operations. Needs to + * be large enough to queue MAX_QUEUE_PER_PEER operations for roughly + * the number of active (connected) peers. + */ +#define MAX_DATASTORE_QUEUE (16 * MAX_QUEUE_PER_PEER) + +/** + * Bandwidth value of a 0-priority content (must be fairly high + * compared to query since content is typically significantly larger + * -- and more valueable since it can take many queries to get one + * piece of content). + */ +#define CONTENT_BANDWIDTH_VALUE 800 + +/** + * Hard limit on the number of results we may get from the datastore per query. + */ +#define MAX_RESULTS (100 * 1024) + +/** + * An active request. + */ +struct GSF_PendingRequest +{ + /** + * Public data for the request. + */ + struct GSF_PendingRequestData public_data; + + /** + * Function to call if we encounter a reply. + */ + GSF_PendingRequestReplyHandler rh; + + /** + * Closure for 'rh' + */ + void *rh_cls; + + /** + * Array of hash codes of replies we've already seen. + */ + GNUNET_HashCode *replies_seen; + + /** + * Bloomfilter masking replies we've already seen. + */ + struct GNUNET_CONTAINER_BloomFilter *bf; + + /** + * Entry for this pending request in the expiration heap, or NULL. + */ + struct GNUNET_CONTAINER_HeapNode *hnode; + + /** + * Datastore queue entry for this request (or NULL for none). + */ + struct GNUNET_DATASTORE_QueueEntry *qe; + + /** + * DHT request handle for this request (or NULL for none). + */ + struct GNUNET_DHT_GetHandle *gh; + + /** + * Function to call upon completion of the local get + * request, or NULL for none. + */ + GSF_LocalLookupContinuation llc_cont; + + /** + * Closure for llc_cont. + */ + void *llc_cont_cls; + + /** + * Last result from the local datastore lookup evaluation. + */ + enum GNUNET_BLOCK_EvaluationResult local_result; + + /** + * Identity of the peer that we should use for the 'sender' + * (recipient of the response) when forwarding (0 for none). + */ + GNUNET_PEER_Id sender_pid; + + /** + * Identity of the peer that we should never forward this query + * to since it originated this query (0 for none). + */ + GNUNET_PEER_Id origin_pid; + + /** + * Time we started the last datastore lookup. + */ + struct GNUNET_TIME_Absolute qe_start; + + /** + * Task that warns us if the local datastore lookup takes too long. + */ + GNUNET_SCHEDULER_TaskIdentifier warn_task; + + /** + * Current offset for querying our local datastore for results. + * Starts at a random value, incremented until we get the same + * UID again (detected using 'first_uid'), which is then used + * to termiante the iteration. + */ + uint64_t local_result_offset; + + /** + * Unique ID of the first result from the local datastore; + * used to detect wrap-around of the offset. + */ + uint64_t first_uid; + + /** + * Number of valid entries in the 'replies_seen' array. + */ + unsigned int replies_seen_count; + + /** + * Length of the 'replies_seen' array. + */ + unsigned int replies_seen_size; + + /** + * Mingle value we currently use for the bf. + */ + uint32_t mingle; + + /** + * Do we have a first UID yet? + */ + unsigned int have_first_uid; + +}; + + +/** + * All pending requests, ordered by the query. Entries + * are of type 'struct GSF_PendingRequest*'. + */ +static struct GNUNET_CONTAINER_MultiHashMap *pr_map; + + +/** + * Datastore 'PUT' load tracking. + */ +static struct GNUNET_LOAD_Value *datastore_put_load; + + +/** + * Are we allowed to migrate content to this peer. + */ +static int active_to_migration; + + +/** + * Size of the datastore queue we assume for common requests. + * Determined based on the network quota. + */ +static unsigned int datastore_queue_size; + +/** + * Heap with the request that will expire next at the top. Contains + * pointers of type "struct PendingRequest*"; these will *also* be + * aliased from the "requests_by_peer" data structures and the + * "requests_by_query" table. Note that requests from our clients + * don't expire and are thus NOT in the "requests_by_expiration" + * (or the "requests_by_peer" tables). + */ +static struct GNUNET_CONTAINER_Heap *requests_by_expiration_heap; + + +/** + * Maximum number of requests (from other peers, overall) that we're + * willing to have pending at any given point in time. Can be changed + * via the configuration file (32k is just the default). + */ +static unsigned long long max_pending_requests = (32 * 1024); + + + +/** + * Recalculate our bloom filter for filtering replies. This function + * will create a new bloom filter from scratch, so it should only be + * called if we have no bloomfilter at all (and hence can create a + * fresh one of minimal size without problems) OR if our peer is the + * initiator (in which case we may resize to larger than mimimum size). + * + * @param pr request for which the BF is to be recomputed + */ +static void +refresh_bloomfilter (struct GSF_PendingRequest *pr) +{ + if (pr->bf != NULL) + GNUNET_CONTAINER_bloomfilter_free (pr->bf); + pr->mingle = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); + pr->bf = + GNUNET_BLOCK_construct_bloomfilter (pr->mingle, pr->replies_seen, + pr->replies_seen_count); +} + + +/** + * Create a new pending request. + * + * @param options request options + * @param type type of the block that is being requested + * @param query key for the lookup + * @param namespace namespace to lookup, NULL for no namespace + * @param target preferred target for the request, NULL for none + * @param bf_data raw data for bloom filter for known replies, can be NULL + * @param bf_size number of bytes in bf_data + * @param mingle mingle value for bf + * @param anonymity_level desired anonymity level + * @param priority maximum outgoing cummulative request priority to use + * @param ttl current time-to-live for the request + * @param sender_pid peer ID to use for the sender when forwarding, 0 for none + * @param origin_pid peer ID of origin of query (do not loop back) + * @param replies_seen hash codes of known local replies + * @param replies_seen_count size of the 'replies_seen' array + * @param rh handle to call when we get a reply + * @param rh_cls closure for rh + * @return handle for the new pending request + */ +struct GSF_PendingRequest * +GSF_pending_request_create_ (enum GSF_PendingRequestOptions options, + enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode * query, + const GNUNET_HashCode * namespace, + const struct GNUNET_PeerIdentity *target, + const char *bf_data, size_t bf_size, + uint32_t mingle, uint32_t anonymity_level, + uint32_t priority, int32_t ttl, + GNUNET_PEER_Id sender_pid, + GNUNET_PEER_Id origin_pid, + const GNUNET_HashCode * replies_seen, + unsigned int replies_seen_count, + GSF_PendingRequestReplyHandler rh, void *rh_cls) +{ + struct GSF_PendingRequest *pr; + struct GSF_PendingRequest *dpr; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating request handle for `%s' of type %d\n", + GNUNET_h2s (query), type); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# Pending requests created"), 1, + GNUNET_NO); + pr = GNUNET_malloc (sizeof (struct GSF_PendingRequest)); + pr->local_result_offset = + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); + pr->public_data.query = *query; + if (GNUNET_BLOCK_TYPE_FS_SBLOCK == type) + { + GNUNET_assert (NULL != namespace); + pr->public_data.namespace = *namespace; + } + if (NULL != target) + { + pr->public_data.target = *target; + pr->public_data.has_target = GNUNET_YES; + } + pr->public_data.anonymity_level = anonymity_level; + pr->public_data.priority = priority; + pr->public_data.original_priority = priority; + pr->public_data.options = options; + pr->public_data.type = type; + pr->public_data.start_time = GNUNET_TIME_absolute_get (); + pr->sender_pid = sender_pid; + pr->origin_pid = origin_pid; + pr->rh = rh; + pr->rh_cls = rh_cls; + GNUNET_assert ((sender_pid != 0) || (0 == (options & GSF_PRO_FORWARD_ONLY))); + if (ttl >= 0) + pr->public_data.ttl = + GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + (uint32_t) ttl)); + else + pr->public_data.ttl = + GNUNET_TIME_absolute_subtract (pr->public_data.start_time, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + (uint32_t) (-ttl))); + if (replies_seen_count > 0) + { + pr->replies_seen_size = replies_seen_count; + pr->replies_seen = + GNUNET_malloc (sizeof (GNUNET_HashCode) * pr->replies_seen_size); + memcpy (pr->replies_seen, replies_seen, + replies_seen_count * sizeof (GNUNET_HashCode)); + pr->replies_seen_count = replies_seen_count; + } + if (NULL != bf_data) + { + pr->bf = + GNUNET_CONTAINER_bloomfilter_init (bf_data, bf_size, + GNUNET_CONSTANTS_BLOOMFILTER_K); + pr->mingle = mingle; + } + else if ((replies_seen_count > 0) && + (0 != (options & GSF_PRO_BLOOMFILTER_FULL_REFRESH))) + { + refresh_bloomfilter (pr); + } + GNUNET_CONTAINER_multihashmap_put (pr_map, query, pr, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + if (0 == (options & GSF_PRO_REQUEST_NEVER_EXPIRES)) + { + pr->hnode = + GNUNET_CONTAINER_heap_insert (requests_by_expiration_heap, pr, + pr->public_data.ttl.abs_value); + /* make sure we don't track too many requests */ + while (GNUNET_CONTAINER_heap_get_size (requests_by_expiration_heap) > + max_pending_requests) + { + dpr = GNUNET_CONTAINER_heap_peek (requests_by_expiration_heap); + GNUNET_assert (dpr != NULL); + if (pr == dpr) + break; /* let the request live briefly... */ + if (NULL != dpr->rh) + dpr->rh (dpr->rh_cls, GNUNET_BLOCK_EVALUATION_REQUEST_VALID, dpr, + UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_ABS, + GNUNET_BLOCK_TYPE_ANY, NULL, 0); + GSF_pending_request_cancel_ (dpr, GNUNET_YES); + } + } + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# Pending requests active"), 1, + GNUNET_NO); + return pr; +} + +/** + * Obtain the public data associated with a pending request + * + * @param pr pending request + * @return associated public data + */ +struct GSF_PendingRequestData * +GSF_pending_request_get_data_ (struct GSF_PendingRequest *pr) +{ + return &pr->public_data; +} + + +/** + * Test if two pending requests are compatible (would generate + * the same query modulo filters and should thus be processed + * jointly). + * + * @param pra a pending request + * @param prb another pending request + * @return GNUNET_OK if the requests are compatible + */ +int +GSF_pending_request_is_compatible_ (struct GSF_PendingRequest *pra, + struct GSF_PendingRequest *prb) +{ + if ((pra->public_data.type != prb->public_data.type) || + (0 != + memcmp (&pra->public_data.query, &prb->public_data.query, + sizeof (GNUNET_HashCode))) || + ((pra->public_data.type == GNUNET_BLOCK_TYPE_FS_SBLOCK) && + (0 != + memcmp (&pra->public_data.namespace, &prb->public_data.namespace, + sizeof (GNUNET_HashCode))))) + return GNUNET_NO; + return GNUNET_OK; +} + + + +/** + * Update a given pending request with additional replies + * that have been seen. + * + * @param pr request to update + * @param replies_seen hash codes of replies that we've seen + * @param replies_seen_count size of the replies_seen array + */ +void +GSF_pending_request_update_ (struct GSF_PendingRequest *pr, + const GNUNET_HashCode * replies_seen, + unsigned int replies_seen_count) +{ + unsigned int i; + GNUNET_HashCode mhash; + + if (replies_seen_count + pr->replies_seen_count < pr->replies_seen_count) + return; /* integer overflow */ + if (0 != (pr->public_data.options & GSF_PRO_BLOOMFILTER_FULL_REFRESH)) + { + /* we're responsible for the BF, full refresh */ + if (replies_seen_count + pr->replies_seen_count > pr->replies_seen_size) + GNUNET_array_grow (pr->replies_seen, pr->replies_seen_size, + replies_seen_count + pr->replies_seen_count); + memcpy (&pr->replies_seen[pr->replies_seen_count], replies_seen, + sizeof (GNUNET_HashCode) * replies_seen_count); + pr->replies_seen_count += replies_seen_count; + refresh_bloomfilter (pr); + } + else + { + if (NULL == pr->bf) + { + /* we're not the initiator, but the initiator did not give us + * any bloom-filter, so we need to create one on-the-fly */ + pr->mingle = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); + pr->bf = + GNUNET_BLOCK_construct_bloomfilter (pr->mingle, replies_seen, + replies_seen_count); + } + else + { + for (i = 0; i < pr->replies_seen_count; i++) + { + GNUNET_BLOCK_mingle_hash (&replies_seen[i], pr->mingle, &mhash); + GNUNET_CONTAINER_bloomfilter_add (pr->bf, &mhash); + } + } + } +} + + +/** + * Generate the message corresponding to the given pending request for + * transmission to other peers (or at least determine its size). + * + * @param pr request to generate the message for + * @param buf_size number of bytes available in buf + * @param buf where to copy the message (can be NULL) + * @return number of bytes needed (if > buf_size) or used + */ +size_t +GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr, + size_t buf_size, void *buf) +{ + char lbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE]; + struct GetMessage *gm; + GNUNET_HashCode *ext; + size_t msize; + unsigned int k; + uint32_t bm; + uint32_t prio; + size_t bf_size; + struct GNUNET_TIME_Absolute now; + int64_t ttl; + int do_route; + + if (buf_size > 0) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Building request message for `%s' of type %d\n", + GNUNET_h2s (&pr->public_data.query), pr->public_data.type); + k = 0; + bm = 0; + do_route = (0 == (pr->public_data.options & GSF_PRO_FORWARD_ONLY)); + if ((!do_route) && (pr->sender_pid == 0)) + { + GNUNET_break (0); + do_route = GNUNET_YES; + } + if (!do_route) + { + bm |= GET_MESSAGE_BIT_RETURN_TO; + k++; + } + if (GNUNET_BLOCK_TYPE_FS_SBLOCK == pr->public_data.type) + { + bm |= GET_MESSAGE_BIT_SKS_NAMESPACE; + k++; + } + if (GNUNET_YES == pr->public_data.has_target) + { + bm |= GET_MESSAGE_BIT_TRANSMIT_TO; + k++; + } + bf_size = GNUNET_CONTAINER_bloomfilter_get_size (pr->bf); + msize = sizeof (struct GetMessage) + bf_size + k * sizeof (GNUNET_HashCode); + GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); + if (buf_size < msize) + return msize; + gm = (struct GetMessage *) lbuf; + gm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_GET); + gm->header.size = htons (msize); + gm->type = htonl (pr->public_data.type); + if (do_route) + prio = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + pr->public_data.priority + 1); + else + prio = 0; + pr->public_data.priority -= prio; + gm->priority = htonl (prio); + now = GNUNET_TIME_absolute_get (); + ttl = (int64_t) (pr->public_data.ttl.abs_value - now.abs_value); + gm->ttl = htonl (ttl / 1000); + gm->filter_mutator = htonl (pr->mingle); + gm->hash_bitmap = htonl (bm); + gm->query = pr->public_data.query; + ext = (GNUNET_HashCode *) & gm[1]; + k = 0; + if (!do_route) + GNUNET_PEER_resolve (pr->sender_pid, + (struct GNUNET_PeerIdentity *) &ext[k++]); + if (GNUNET_BLOCK_TYPE_FS_SBLOCK == pr->public_data.type) + memcpy (&ext[k++], &pr->public_data.namespace, sizeof (GNUNET_HashCode)); + if (GNUNET_YES == pr->public_data.has_target) + ext[k++] = pr->public_data.target.hashPubKey; + if (pr->bf != NULL) + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONTAINER_bloomfilter_get_raw_data (pr->bf, + (char *) &ext[k], + bf_size)); + memcpy (buf, gm, msize); + return msize; +} + + +/** + * Iterator to free pending requests. + * + * @param cls closure, unused + * @param key current key code + * @param value value in the hash map (pending request) + * @return GNUNET_YES (we should continue to iterate) + */ +static int +clean_request (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GSF_PendingRequest *pr = value; + GSF_LocalLookupContinuation cont; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up pending request for `%s'.\n", GNUNET_h2s (key)); + if (NULL != (cont = pr->llc_cont)) + { + pr->llc_cont = NULL; + cont (pr->llc_cont_cls, pr, pr->local_result); + } + GSF_plan_notify_request_done_ (pr); + GNUNET_free_non_null (pr->replies_seen); + if (NULL != pr->bf) + { + GNUNET_CONTAINER_bloomfilter_free (pr->bf); + pr->bf = NULL; + } + GNUNET_PEER_change_rc (pr->sender_pid, -1); + pr->sender_pid = 0; + GNUNET_PEER_change_rc (pr->origin_pid, -1); + pr->origin_pid = 0; + if (NULL != pr->hnode) + { + GNUNET_CONTAINER_heap_remove_node (pr->hnode); + pr->hnode = NULL; + } + if (NULL != pr->qe) + { + GNUNET_DATASTORE_cancel (pr->qe); + pr->qe = NULL; + } + if (NULL != pr->gh) + { + GNUNET_DHT_get_stop (pr->gh); + pr->gh = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != pr->warn_task) + { + GNUNET_SCHEDULER_cancel (pr->warn_task); + pr->warn_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (pr_map, + &pr->public_data.query, + pr)); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# Pending requests active"), -1, + GNUNET_NO); + GNUNET_free (pr); + return GNUNET_YES; +} + + +/** + * Explicitly cancel a pending request. + * + * @param pr request to cancel + * @param full_cleanup fully purge the request + */ +void +GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr, int full_cleanup) +{ + GSF_LocalLookupContinuation cont; + + if (NULL == pr_map) + return; /* already cleaned up! */ + if (GNUNET_YES != full_cleanup) + { + /* make request inactive (we're no longer interested in more results), + * but do NOT remove from our data-structures, we still need it there + * to prevent the request from looping */ + pr->rh = NULL; + if (NULL != (cont = pr->llc_cont)) + { + pr->llc_cont = NULL; + cont (pr->llc_cont_cls, pr, pr->local_result); + } + GSF_plan_notify_request_done_ (pr); + if (NULL != pr->qe) + { + GNUNET_DATASTORE_cancel (pr->qe); + pr->qe = NULL; + } + if (NULL != pr->gh) + { + GNUNET_DHT_get_stop (pr->gh); + pr->gh = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != pr->warn_task) + { + GNUNET_SCHEDULER_cancel (pr->warn_task); + pr->warn_task = GNUNET_SCHEDULER_NO_TASK; + } + return; + } + GNUNET_assert (GNUNET_YES == + clean_request (NULL, &pr->public_data.query, pr)); +} + + +/** + * Iterate over all pending requests. + * + * @param it function to call for each request + * @param cls closure for it + */ +void +GSF_iterate_pending_requests_ (GSF_PendingRequestIterator it, void *cls) +{ + GNUNET_CONTAINER_multihashmap_iterate (pr_map, + (GNUNET_CONTAINER_HashMapIterator) it, + cls); +} + + + + +/** + * Closure for "process_reply" function. + */ +struct ProcessReplyClosure +{ + /** + * The data for the reply. + */ + const void *data; + + /** + * Who gave us this reply? NULL for local host (or DHT) + */ + struct GSF_ConnectedPeer *sender; + + /** + * When the reply expires. + */ + struct GNUNET_TIME_Absolute expiration; + + /** + * Size of data. + */ + size_t size; + + /** + * Type of the block. + */ + enum GNUNET_BLOCK_Type type; + + /** + * How much was this reply worth to us? + */ + uint32_t priority; + + /** + * Anonymity requirements for this reply. + */ + uint32_t anonymity_level; + + /** + * Evaluation result (returned). + */ + enum GNUNET_BLOCK_EvaluationResult eval; + + /** + * Did we find a matching request? + */ + int request_found; +}; + + +/** + * Update the performance data for the sender (if any) since + * the sender successfully answered one of our queries. + * + * @param prq information about the sender + * @param pr request that was satisfied + */ +static void +update_request_performance_data (struct ProcessReplyClosure *prq, + struct GSF_PendingRequest *pr) +{ + if (prq->sender == NULL) + return; + GSF_peer_update_performance_ (prq->sender, pr->public_data.start_time, + prq->priority); +} + + +/** + * We have received a reply; handle it! + * + * @param cls response (struct ProcessReplyClosure) + * @param key our query + * @param value value in the hash map (info about the query) + * @return GNUNET_YES (we should continue to iterate) + */ +static int +process_reply (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ProcessReplyClosure *prq = cls; + struct GSF_PendingRequest *pr = value; + GNUNET_HashCode chash; + struct GNUNET_TIME_Absolute last_transmission; + + if (NULL == pr->rh) + return GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Matched result (type %u) for query `%s' with pending request\n", + (unsigned int) prq->type, GNUNET_h2s (key)); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# replies received and matched"), 1, + GNUNET_NO); + prq->eval = + GNUNET_BLOCK_evaluate (GSF_block_ctx, prq->type, key, &pr->bf, pr->mingle, + &pr->public_data.namespace, + (prq->type == + GNUNET_BLOCK_TYPE_FS_SBLOCK) ? + sizeof (GNUNET_HashCode) : 0, prq->data, + prq->size); + switch (prq->eval) + { + case GNUNET_BLOCK_EVALUATION_OK_MORE: + update_request_performance_data (prq, pr); + break; + case GNUNET_BLOCK_EVALUATION_OK_LAST: + /* short cut: stop processing early, no BF-update, etc. */ + update_request_performance_data (prq, pr); + GNUNET_LOAD_update (GSF_rt_entry_lifetime, + GNUNET_TIME_absolute_get_duration (pr-> + public_data.start_time).rel_value); + if (!GSF_request_plan_reference_get_last_transmission_ (pr->public_data.rpr_head, prq->sender, &last_transmission)) + last_transmission.abs_value = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value; + /* pass on to other peers / local clients */ + pr->rh (pr->rh_cls, prq->eval, pr, prq->anonymity_level, prq->expiration, + last_transmission, prq->type, prq->data, prq->size); + return GNUNET_YES; + case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# duplicate replies discarded (bloomfilter)"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Duplicate response, discarding.\n"); + return GNUNET_YES; /* duplicate */ + case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: + return GNUNET_YES; /* wrong namespace */ + case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: + GNUNET_break (0); + return GNUNET_YES; + case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: + GNUNET_break (0); + return GNUNET_YES; + case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported block type %u\n"), + prq->type); + return GNUNET_NO; + } + /* update bloomfilter */ + GNUNET_CRYPTO_hash (prq->data, prq->size, &chash); + GSF_pending_request_update_ (pr, &chash, 1); + if (NULL == prq->sender) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found result for query `%s' in local datastore\n", + GNUNET_h2s (key)); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# results found locally"), 1, + GNUNET_NO); + } + else + { + GSF_dht_lookup_ (pr); + } + prq->priority += pr->public_data.original_priority; + pr->public_data.priority = 0; + pr->public_data.original_priority = 0; + pr->public_data.results_found++; + prq->request_found = GNUNET_YES; + /* finally, pass on to other peer / local client */ + if (!GSF_request_plan_reference_get_last_transmission_ (pr->public_data.rpr_head, prq->sender, &last_transmission)) + last_transmission.abs_value = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value; + pr->rh (pr->rh_cls, prq->eval, pr, prq->anonymity_level, prq->expiration, + last_transmission, prq->type, prq->data, prq->size); + return GNUNET_YES; +} + + +/** + * Context for the 'put_migration_continuation'. + */ +struct PutMigrationContext +{ + + /** + * Start time for the operation. + */ + struct GNUNET_TIME_Absolute start; + + /** + * Request origin. + */ + struct GNUNET_PeerIdentity origin; + + /** + * GNUNET_YES if we had a matching request for this block, + * GNUNET_NO if not. + */ + int requested; +}; + + +/** + * Continuation called to notify client about result of the + * operation. + * + * @param cls closure + * @param success GNUNET_SYSERR on failure + * @param min_expiration minimum expiration time required for content to be stored + * @param msg NULL on success, otherwise an error message + */ +static void +put_migration_continuation (void *cls, int success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg) +{ + struct PutMigrationContext *pmc = cls; + struct GSF_ConnectedPeer *cp; + struct GNUNET_TIME_Relative mig_pause; + struct GSF_PeerPerformanceData *ppd; + + if (NULL != datastore_put_load) + { + if (GNUNET_SYSERR != success) + { + GNUNET_LOAD_update (datastore_put_load, + GNUNET_TIME_absolute_get_duration (pmc->start).rel_value); + } + else + { + /* on queue failure / timeout, increase the put load dramatically */ + GNUNET_LOAD_update (datastore_put_load, + GNUNET_TIME_UNIT_MINUTES.rel_value); + } + } + cp = GSF_peer_get_ (&pmc->origin); + if (GNUNET_OK == success) + { + if (NULL != cp) + { + ppd = GSF_get_peer_performance_data_ (cp); + ppd->migration_delay.rel_value /= 2; + } + GNUNET_free (pmc); + return; + } + if ( (GNUNET_NO == success) && + (GNUNET_NO == pmc->requested) && + (NULL != cp) ) + { + ppd = GSF_get_peer_performance_data_ (cp); + if (min_expiration.abs_value > 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking to stop migration for %llu ms because datastore is full\n", + (unsigned long long) GNUNET_TIME_absolute_get_remaining (min_expiration).rel_value); + GSF_block_peer_migration_ (cp, min_expiration); + } + else + { + ppd->migration_delay = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_SECONDS, + ppd->migration_delay); + ppd->migration_delay = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_HOURS, + ppd->migration_delay); + mig_pause.rel_value = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + ppd->migration_delay.rel_value); + ppd->migration_delay = GNUNET_TIME_relative_multiply (ppd->migration_delay, 2); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Replicated content already exists locally, asking to stop migration for %llu ms\n", + (unsigned long long) mig_pause.rel_value); + GSF_block_peer_migration_ (cp, GNUNET_TIME_relative_to_absolute (mig_pause)); + } + } + GNUNET_free (pmc); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# Datastore `PUT' failures"), 1, + GNUNET_NO); +} + + +/** + * Test if the DATABASE (PUT) load on this peer is too high + * to even consider processing the query at + * all. + * + * @return GNUNET_YES if the load is too high to do anything (load high) + * GNUNET_NO to process normally (load normal or low) + */ +static int +test_put_load_too_high (uint32_t priority) +{ + double ld; + + if (NULL == datastore_put_load) + return GNUNET_NO; + if (GNUNET_LOAD_get_average (datastore_put_load) < 50) + return GNUNET_NO; /* very fast */ + ld = GNUNET_LOAD_get_load (datastore_put_load); + if (ld < 2.0 * (1 + priority)) + return GNUNET_NO; + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# storage requests dropped due to high load"), 1, + GNUNET_NO); + return GNUNET_YES; +} + + +/** + * Iterator called on each result obtained for a DHT + * operation that expects a reply + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param get_path peers on reply path (or NULL if not recorded) + * @param get_path_length number of entries in get_path + * @param put_path peers on the PUT path (or NULL if not recorded) + * @param put_path_length number of entries in get_path + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +static void +handle_dht_reply (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + struct GSF_PendingRequest *pr = cls; + struct ProcessReplyClosure prq; + struct PutMigrationContext *pmc; + + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# Replies received from DHT"), 1, + GNUNET_NO); + memset (&prq, 0, sizeof (prq)); + prq.data = data; + prq.expiration = exp; + /* do not allow migrated content to live longer than 1 year */ + prq.expiration = GNUNET_TIME_absolute_min (GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS), + prq.expiration); + prq.size = size; + prq.type = type; + process_reply (&prq, key, pr); + if ((GNUNET_YES == active_to_migration) && + (GNUNET_NO == test_put_load_too_high (prq.priority))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Replicating result for query `%s' with priority %u\n", + GNUNET_h2s (key), prq.priority); + pmc = GNUNET_malloc (sizeof (struct PutMigrationContext)); + pmc->start = GNUNET_TIME_absolute_get (); + pmc->requested = GNUNET_YES; + if (NULL == + GNUNET_DATASTORE_put (GSF_dsh, 0, key, size, data, type, prq.priority, + 1 /* anonymity */ , + 0 /* replication */ , + exp, 1 + prq.priority, MAX_DATASTORE_QUEUE, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + &put_migration_continuation, pmc)) + { + put_migration_continuation (pmc, GNUNET_SYSERR, GNUNET_TIME_UNIT_ZERO_ABS, NULL); + } + } +} + + +/** + * Consider looking up the data in the DHT (anonymity-level permitting). + * + * @param pr the pending request to process + */ +void +GSF_dht_lookup_ (struct GSF_PendingRequest *pr) +{ + const void *xquery; + size_t xquery_size; + struct GNUNET_PeerIdentity pi; + char buf[sizeof (GNUNET_HashCode) * 2]; + + if (0 != pr->public_data.anonymity_level) + return; + if (NULL != pr->gh) + { + GNUNET_DHT_get_stop (pr->gh); + pr->gh = NULL; + } + xquery = NULL; + xquery_size = 0; + if (GNUNET_BLOCK_TYPE_FS_SBLOCK == pr->public_data.type) + { + xquery = buf; + memcpy (buf, &pr->public_data.namespace, sizeof (GNUNET_HashCode)); + xquery_size = sizeof (GNUNET_HashCode); + } + if (0 != (pr->public_data.options & GSF_PRO_FORWARD_ONLY)) + { + GNUNET_assert (0 != pr->sender_pid); + GNUNET_PEER_resolve (pr->sender_pid, &pi); + memcpy (&buf[xquery_size], &pi, sizeof (struct GNUNET_PeerIdentity)); + xquery_size += sizeof (struct GNUNET_PeerIdentity); + } + pr->gh = + GNUNET_DHT_get_start (GSF_dht, GNUNET_TIME_UNIT_FOREVER_REL, + pr->public_data.type, &pr->public_data.query, + 5 /* DEFAULT_GET_REPLICATION */ , + GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, + /* FIXME: can no longer pass pr->bf/pr->mingle... */ + xquery, xquery_size, &handle_dht_reply, pr); +} + + +/** + * Task that issues a warning if the datastore lookup takes too long. + * + * @param cls the 'struct GSF_PendingRequest' + * @param tc task context + */ +static void +warn_delay_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GSF_PendingRequest *pr = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Datastore lookup already took %llu ms!\n"), + (unsigned long long) + GNUNET_TIME_absolute_get_duration (pr->qe_start).rel_value); + pr->warn_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_delay_task, + pr); +} + + +/** + * Task that issues a warning if the datastore lookup takes too long. + * + * @param cls the 'struct GSF_PendingRequest' + * @param tc task context + */ +static void +odc_warn_delay_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GSF_PendingRequest *pr = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("On-demand lookup already took %llu ms!\n"), + (unsigned long long) + GNUNET_TIME_absolute_get_duration (pr->qe_start).rel_value); + pr->warn_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &odc_warn_delay_task, pr); +} + + +/** + * We're processing (local) results for a search request + * from another peer. Pass applicable results to the + * peer and if we are done either clean up (operation + * complete) or forward to other peers (more results possible). + * + * @param cls our closure (struct PendingRequest) + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + */ +static void +process_local_reply (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, uint64_t uid) +{ + struct GSF_PendingRequest *pr = cls; + GSF_LocalLookupContinuation cont; + struct ProcessReplyClosure prq; + GNUNET_HashCode query; + unsigned int old_rf; + + GNUNET_SCHEDULER_cancel (pr->warn_task); + pr->warn_task = GNUNET_SCHEDULER_NO_TASK; + if (NULL != pr->qe) + { + pr->qe = NULL; + if (NULL == key) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# Datastore lookups concluded (no results)"), + 1, GNUNET_NO); + } + if (GNUNET_NO == pr->have_first_uid) + { + pr->first_uid = uid; + pr->have_first_uid = 1; + } + else + { + if ((uid == pr->first_uid) && (key != NULL)) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# Datastore lookups concluded (seen all)"), + 1, GNUNET_NO); + key = NULL; /* all replies seen! */ + } + pr->have_first_uid++; + if ((pr->have_first_uid > MAX_RESULTS) && (key != NULL)) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# Datastore lookups aborted (more than MAX_RESULTS)"), + 1, GNUNET_NO); + key = NULL; /* all replies seen! */ + } + } + } + if (NULL == key) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "No further local responses available.\n"); + if ((pr->public_data.type == GNUNET_BLOCK_TYPE_FS_DBLOCK) || + (pr->public_data.type == GNUNET_BLOCK_TYPE_FS_IBLOCK)) + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# requested DBLOCK or IBLOCK not found"), 1, + GNUNET_NO); + goto check_error_and_continue; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received reply for `%s' of type %d with UID %llu from datastore.\n", + GNUNET_h2s (key), type, (unsigned long long) uid); + if (type == GNUNET_BLOCK_TYPE_FS_ONDEMAND) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found ONDEMAND block, performing on-demand encoding\n"); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# on-demand blocks matched requests"), 1, + GNUNET_NO); + pr->qe_start = GNUNET_TIME_absolute_get (); + pr->warn_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &odc_warn_delay_task, pr); + if (GNUNET_OK == + GNUNET_FS_handle_on_demand_block (key, size, data, type, priority, + anonymity, expiration, uid, + &process_local_reply, pr)) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# on-demand lookups performed successfully"), + 1, GNUNET_NO); + return; /* we're done */ + } + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# on-demand lookups failed"), 1, + GNUNET_NO); + GNUNET_SCHEDULER_cancel (pr->warn_task); + pr->warn_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &warn_delay_task, pr); + pr->qe = + GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset - 1, + &pr->public_data.query, + pr->public_data.type == + GNUNET_BLOCK_TYPE_FS_DBLOCK ? + GNUNET_BLOCK_TYPE_ANY : pr->public_data.type, + (0 != + (GSF_PRO_PRIORITY_UNLIMITED & + pr->public_data.options)) ? UINT_MAX : 1 + /* queue priority */ , + (0 != + (GSF_PRO_PRIORITY_UNLIMITED & + pr->public_data.options)) ? UINT_MAX : + datastore_queue_size + /* max queue size */ , + GNUNET_TIME_UNIT_FOREVER_REL, + &process_local_reply, pr); + if (NULL != pr->qe) + return; /* we're done */ + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# Datastore lookups concluded (error queueing)"), + 1, GNUNET_NO); + goto check_error_and_continue; + } + old_rf = pr->public_data.results_found; + memset (&prq, 0, sizeof (prq)); + prq.data = data; + prq.expiration = expiration; + prq.size = size; + if (GNUNET_OK != + GNUNET_BLOCK_get_key (GSF_block_ctx, type, data, size, &query)) + { + GNUNET_break (0); + GNUNET_DATASTORE_remove (GSF_dsh, key, size, data, -1, -1, + GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); + pr->qe_start = GNUNET_TIME_absolute_get (); + pr->warn_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &warn_delay_task, pr); + pr->qe = + GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset - 1, + &pr->public_data.query, + pr->public_data.type == + GNUNET_BLOCK_TYPE_FS_DBLOCK ? + GNUNET_BLOCK_TYPE_ANY : pr->public_data.type, + (0 != + (GSF_PRO_PRIORITY_UNLIMITED & + pr->public_data.options)) ? UINT_MAX : 1 + /* queue priority */ , + (0 != + (GSF_PRO_PRIORITY_UNLIMITED & + pr->public_data.options)) ? UINT_MAX : + datastore_queue_size + /* max queue size */ , + GNUNET_TIME_UNIT_FOREVER_REL, + &process_local_reply, pr); + if (pr->qe == NULL) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# Datastore lookups concluded (error queueing)"), + 1, GNUNET_NO); + goto check_error_and_continue; + } + return; + } + prq.type = type; + prq.priority = priority; + prq.request_found = GNUNET_NO; + prq.anonymity_level = anonymity; + if ((old_rf == 0) && (pr->public_data.results_found == 0)) + GSF_update_datastore_delay_ (pr->public_data.start_time); + process_reply (&prq, key, pr); + pr->local_result = prq.eval; + if (prq.eval == GNUNET_BLOCK_EVALUATION_OK_LAST) + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# Datastore lookups concluded (found last result)"), + 1, GNUNET_NO); + goto check_error_and_continue; + } + if ((0 == (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) && + ((GNUNET_YES == GSF_test_get_load_too_high_ (0)) || + (pr->public_data.results_found > 5 + 2 * pr->public_data.priority))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Load too high, done with request\n"); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# Datastore lookups concluded (load too high)"), + 1, GNUNET_NO); + goto check_error_and_continue; + } + pr->qe_start = GNUNET_TIME_absolute_get (); + pr->warn_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_delay_task, + pr); + pr->qe = + GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset++, + &pr->public_data.query, + pr->public_data.type == + GNUNET_BLOCK_TYPE_FS_DBLOCK ? + GNUNET_BLOCK_TYPE_ANY : pr->public_data.type, + (0 != + (GSF_PRO_PRIORITY_UNLIMITED & pr-> + public_data.options)) ? UINT_MAX : 1 + /* queue priority */ , + (0 != + (GSF_PRO_PRIORITY_UNLIMITED & pr-> + public_data.options)) ? UINT_MAX : + datastore_queue_size + /* max queue size */ , + GNUNET_TIME_UNIT_FOREVER_REL, + &process_local_reply, pr); + /* check if we successfully queued another datastore request; + * if so, return, otherwise call our continuation (if we have + * any) */ +check_error_and_continue: + if (NULL != pr->qe) + return; + if (GNUNET_SCHEDULER_NO_TASK != pr->warn_task) + { + GNUNET_SCHEDULER_cancel (pr->warn_task); + pr->warn_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL == (cont = pr->llc_cont)) + return; /* no continuation */ + pr->llc_cont = NULL; + cont (pr->llc_cont_cls, pr, pr->local_result); +} + + +/** + * Is the given target a legitimate peer for forwarding the given request? + * + * @param pr request + * @param target + * @return GNUNET_YES if this request could be forwarded to the given peer + */ +int +GSF_pending_request_test_target_ (struct GSF_PendingRequest *pr, + const struct GNUNET_PeerIdentity *target) +{ + struct GNUNET_PeerIdentity pi; + + if (0 == pr->origin_pid) + return GNUNET_YES; + GNUNET_PEER_resolve (pr->origin_pid, &pi); + return (0 == + memcmp (&pi, target, + sizeof (struct GNUNET_PeerIdentity))) ? GNUNET_NO : + GNUNET_YES; +} + + +/** + * Look up the request in the local datastore. + * + * @param pr the pending request to process + * @param cont function to call at the end + * @param cont_cls closure for cont + */ +void +GSF_local_lookup_ (struct GSF_PendingRequest *pr, + GSF_LocalLookupContinuation cont, void *cont_cls) +{ + GNUNET_assert (NULL == pr->gh); + GNUNET_assert (NULL == pr->llc_cont); + pr->llc_cont = cont; + pr->llc_cont_cls = cont_cls; + pr->qe_start = GNUNET_TIME_absolute_get (); + pr->warn_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_delay_task, + pr); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# Datastore lookups initiated"), 1, + GNUNET_NO); + pr->qe = + GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset++, + &pr->public_data.query, + pr->public_data.type == + GNUNET_BLOCK_TYPE_FS_DBLOCK ? + GNUNET_BLOCK_TYPE_ANY : pr->public_data.type, + (0 != + (GSF_PRO_PRIORITY_UNLIMITED & pr-> + public_data.options)) ? UINT_MAX : 1 + /* queue priority */ , + (0 != + (GSF_PRO_PRIORITY_UNLIMITED & pr-> + public_data.options)) ? UINT_MAX : + datastore_queue_size + /* max queue size */ , + GNUNET_TIME_UNIT_FOREVER_REL, + &process_local_reply, pr); + if (NULL != pr->qe) + return; + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# Datastore lookups concluded (error queueing)"), + 1, GNUNET_NO); + GNUNET_SCHEDULER_cancel (pr->warn_task); + pr->warn_task = GNUNET_SCHEDULER_NO_TASK; + pr->llc_cont = NULL; + if (NULL != cont) + cont (cont_cls, pr, pr->local_result); +} + + + +/** + * Handle P2P "CONTENT" message. Checks that the message is + * well-formed and then checks if there are any pending requests for + * this content and possibly passes it on (to local clients or other + * peers). Does NOT perform migration (content caching at this peer). + * + * @param cp the other peer involved (sender or receiver, NULL + * for loopback messages where we are both sender and receiver) + * @param message the actual message + * @return GNUNET_OK if the message was well-formed, + * GNUNET_SYSERR if the message was malformed (close connection, + * do not cache under any circumstances) + */ +int +GSF_handle_p2p_content_ (struct GSF_ConnectedPeer *cp, + const struct GNUNET_MessageHeader *message) +{ + const struct PutMessage *put; + uint16_t msize; + size_t dsize; + enum GNUNET_BLOCK_Type type; + struct GNUNET_TIME_Absolute expiration; + GNUNET_HashCode query; + struct ProcessReplyClosure prq; + struct GNUNET_TIME_Relative block_time; + double putl; + struct PutMigrationContext *pmc; + + msize = ntohs (message->size); + if (msize < sizeof (struct PutMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + put = (const struct PutMessage *) message; + dsize = msize - sizeof (struct PutMessage); + type = ntohl (put->type); + expiration = GNUNET_TIME_absolute_ntoh (put->expiration); + /* do not allow migrated content to live longer than 1 year */ + expiration = GNUNET_TIME_absolute_min (GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS), + expiration); + if (type == GNUNET_BLOCK_TYPE_FS_ONDEMAND) + return GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_BLOCK_get_key (GSF_block_ctx, type, &put[1], dsize, &query)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# GAP PUT messages received"), 1, + GNUNET_NO); + /* now, lookup 'query' */ + prq.data = (const void *) &put[1]; + if (NULL != cp) + prq.sender = cp; + else + prq.sender = NULL; + prq.size = dsize; + prq.type = type; + prq.expiration = expiration; + prq.priority = 0; + prq.anonymity_level = UINT32_MAX; + prq.request_found = GNUNET_NO; + GNUNET_CONTAINER_multihashmap_get_multiple (pr_map, &query, &process_reply, + &prq); + if (NULL != cp) + { + GSF_connected_peer_change_preference_ (cp, + CONTENT_BANDWIDTH_VALUE + + 1000 * prq.priority); + GSF_get_peer_performance_data_ (cp)->trust += prq.priority; + } + if ((GNUNET_YES == active_to_migration) && + (GNUNET_NO == test_put_load_too_high (prq.priority))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Replicating result for query `%s' with priority %u\n", + GNUNET_h2s (&query), prq.priority); + pmc = GNUNET_malloc (sizeof (struct PutMigrationContext)); + pmc->start = GNUNET_TIME_absolute_get (); + pmc->requested = prq.request_found; + GNUNET_assert (0 != GSF_get_peer_performance_data_ (cp)->pid); + GNUNET_PEER_resolve (GSF_get_peer_performance_data_ (cp)->pid, + &pmc->origin); + if (NULL == + GNUNET_DATASTORE_put (GSF_dsh, 0, &query, dsize, &put[1], type, + prq.priority, 1 /* anonymity */ , + 0 /* replication */ , + expiration, 1 + prq.priority, MAX_DATASTORE_QUEUE, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + &put_migration_continuation, pmc)) + { + put_migration_continuation (pmc, GNUNET_SYSERR, GNUNET_TIME_UNIT_ZERO_ABS, NULL); + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Choosing not to keep content `%s' (%d/%d)\n", + GNUNET_h2s (&query), active_to_migration, + test_put_load_too_high (prq.priority)); + } + putl = GNUNET_LOAD_get_load (datastore_put_load); + if ((NULL != (cp = prq.sender)) && (GNUNET_NO == prq.request_found) && + ((GNUNET_YES != active_to_migration) || + (putl > 2.5 * (1 + prq.priority)))) + { + if (GNUNET_YES != active_to_migration) + putl = 1.0 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 5); + block_time = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + 5000 + + GNUNET_CRYPTO_random_u32 + (GNUNET_CRYPTO_QUALITY_WEAK, + (unsigned int) (60000 * putl * putl))); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking to stop migration for %llu ms because of load %f and events %d/%d\n", + (unsigned long long) block_time.rel_value, + putl, + active_to_migration, + (GNUNET_NO == prq.request_found)); + GSF_block_peer_migration_ (cp, GNUNET_TIME_relative_to_absolute (block_time)); + } + return GNUNET_OK; +} + + +/** + * Setup the subsystem. + */ +void +GSF_pending_request_init_ () +{ + unsigned long long bps; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (GSF_cfg, "fs", + "MAX_PENDING_REQUESTS", + &max_pending_requests)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Configuration fails to specify `%s', assuming default value."), + "MAX_PENDING_REQUESTS"); + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_size (GSF_cfg, "ats", "WAN_QUOTA_OUT", + &bps)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Configuration fails to specify `%s', assuming default value."), + "WAN_QUOTA_OUT"); + bps = 65536; + } + /* queue size should be #queries we can have pending and satisfy within + * a carry interval: */ + datastore_queue_size = + bps * GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S / DBLOCK_SIZE; + + active_to_migration = + GNUNET_CONFIGURATION_get_value_yesno (GSF_cfg, "FS", "CONTENT_CACHING"); + datastore_put_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE); + pr_map = GNUNET_CONTAINER_multihashmap_create (32 * 1024); + requests_by_expiration_heap = + GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); +} + + +/** + * Shutdown the subsystem. + */ +void +GSF_pending_request_done_ () +{ + GNUNET_CONTAINER_multihashmap_iterate (pr_map, &clean_request, NULL); + GNUNET_CONTAINER_multihashmap_destroy (pr_map); + pr_map = NULL; + GNUNET_CONTAINER_heap_destroy (requests_by_expiration_heap); + requests_by_expiration_heap = NULL; + GNUNET_LOAD_value_free (datastore_put_load); + datastore_put_load = NULL; +} + + +/* 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 new file mode 100644 index 0000000..92827f7 --- /dev/null +++ b/src/fs/gnunet-service-fs_pr.h @@ -0,0 +1,403 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_pr.h + * @brief API to handle pending requests + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_FS_PR_H +#define GNUNET_SERVICE_FS_PR_H + +#include "gnunet-service-fs.h" + + +/** + * Options for pending requests (bits to be ORed). + */ +enum GSF_PendingRequestOptions +{ + + /** + * No special options (P2P-default). + */ + GSF_PRO_DEFAULTS = 0, + + /** + * Request must only be processed locally. + */ + GSF_PRO_LOCAL_ONLY = 1, + + /** + * Request must only be forwarded (no routing) + */ + GSF_PRO_FORWARD_ONLY = 2, + + /** + * Request persists indefinitely (no expiration). + */ + GSF_PRO_REQUEST_NEVER_EXPIRES = 4, + + /** + * Request is allowed to refresh bloomfilter and change mingle value. + */ + GSF_PRO_BLOOMFILTER_FULL_REFRESH = 8, + + /** + * Request priority is allowed to be exceeded. + */ + GSF_PRO_PRIORITY_UNLIMITED = 16, + + /** + * Option mask for typical local requests. + */ + GSF_PRO_LOCAL_REQUEST = + (GSF_PRO_BLOOMFILTER_FULL_REFRESH | GSF_PRO_PRIORITY_UNLIMITED | GSF_PRO_REQUEST_NEVER_EXPIRES) +}; + + +/** + * Public data (in the sense of not encapsulated within + * 'gnunet-service-fs_pr', not in the sense of network-wide + * known) associated with each pending request. + */ +struct GSF_PendingRequestData +{ + + /** + * Primary query hash for this request. + */ + GNUNET_HashCode query; + + /** + * Namespace to query, only set if the type is SBLOCK. + */ + GNUNET_HashCode namespace; + + /** + * Identity of a peer hosting the content, only set if + * 'has_target' is GNUNET_YES. + */ + struct GNUNET_PeerIdentity target; + + /** + * Fields for the plan module to track a DLL with the request. + */ + struct GSF_RequestPlanReference *rpr_head; + + /** + * Fields for the plan module to track a DLL with the request. + */ + struct GSF_RequestPlanReference *rpr_tail; + + /** + * Current TTL for the request. + */ + struct GNUNET_TIME_Absolute ttl; + + /** + * When did we start with the request. + */ + struct GNUNET_TIME_Absolute start_time; + + /** + * Desired anonymity level. + */ + uint32_t anonymity_level; + + /** + * Priority that this request (still) has for us. + */ + uint32_t priority; + + /** + * Priority that this request (originally) had for us. + */ + uint32_t original_priority; + + /** + * Options for the request. + */ + enum GSF_PendingRequestOptions options; + + /** + * Type of the requested block. + */ + enum GNUNET_BLOCK_Type type; + + /** + * Number of results we have found for this request so far. + */ + unsigned int results_found; + + /** + * Is the 'target' value set to a valid peer identity? + */ + int has_target; + + /** + * Has this request been started yet (local/p2p operations)? Or are + * we still constructing it? + */ + int has_started; + +}; + + +/** + * Handle a reply to a pending request. Also called if a request + * expires (then with data == NULL). The handler may be called + * many times (depending on the request type), but will not be + * called during or after a call to GSF_pending_request_cancel + * and will also not be called anymore after a call signalling + * expiration. + * + * @param cls user-specified closure + * @param eval evaluation of the result + * @param pr handle to the original pending request + * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" + * @param expiration when does 'data' expire? + * @param last_transmission the last time we've tried to get this block (FOREVER if unknown) + * @param type type of the block + * @param data response data, NULL on request expiration + * @param data_len number of bytes in data + */ +typedef void (*GSF_PendingRequestReplyHandler) (void *cls, + enum + GNUNET_BLOCK_EvaluationResult + eval, + struct GSF_PendingRequest * pr, + uint32_t reply_anonymity_level, + struct GNUNET_TIME_Absolute + expiration, + struct GNUNET_TIME_Absolute + last_transmission, + enum GNUNET_BLOCK_Type type, + const void *data, + size_t data_len); + + +/** + * Create a new pending request. + * + * @param options request options + * @param type type of the block that is being requested + * @param query key for the lookup + * @param namespace namespace to lookup, NULL for no namespace + * @param target preferred target for the request, NULL for none + * @param bf_data raw data for bloom filter for known replies, can be NULL + * @param bf_size number of bytes in bf_data + * @param mingle mingle value for bf + * @param anonymity_level desired anonymity level + * @param priority maximum outgoing cummulative request priority to use + * @param ttl current time-to-live for the request + * @param sender_pid peer ID to use for the sender when forwarding, 0 for none; + * reference counter is taken over by this function + * @param origin_pid peer ID of origin of query (do not loop back) + * @param replies_seen hash codes of known local replies + * @param replies_seen_count size of the 'replies_seen' array + * @param rh handle to call when we get a reply + * @param rh_cls closure for rh + * @return handle for the new pending request + */ +struct GSF_PendingRequest * +GSF_pending_request_create_ (enum GSF_PendingRequestOptions options, + enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode * query, + const GNUNET_HashCode * namespace, + const struct GNUNET_PeerIdentity *target, + const char *bf_data, size_t bf_size, + uint32_t mingle, uint32_t anonymity_level, + uint32_t priority, int32_t ttl, + GNUNET_PEER_Id sender_pid, + GNUNET_PEER_Id origin_pid, + const GNUNET_HashCode * replies_seen, + unsigned int replies_seen_count, + GSF_PendingRequestReplyHandler rh, void *rh_cls); + + +/** + * Update a given pending request with additional replies + * that have been seen. + * + * @param pr request to update + * @param replies_seen hash codes of replies that we've seen + * @param replies_seen_count size of the replies_seen array + */ +void +GSF_pending_request_update_ (struct GSF_PendingRequest *pr, + const GNUNET_HashCode * replies_seen, + unsigned int replies_seen_count); + + +/** + * Obtain the public data associated with a pending request + * + * @param pr pending request + * @return associated public data + */ +struct GSF_PendingRequestData * +GSF_pending_request_get_data_ (struct GSF_PendingRequest *pr); + + +/** + * Test if two pending requests are compatible (would generate + * the same query modulo filters and should thus be processed + * jointly). + * + * @param pra a pending request + * @param prb another pending request + * @return GNUNET_OK if the requests are compatible + */ +int +GSF_pending_request_is_compatible_ (struct GSF_PendingRequest *pra, + struct GSF_PendingRequest *prb); + + +/** + * Generate the message corresponding to the given pending request for + * transmission to other peers (or at least determine its size). + * + * @param pr request to generate the message for + * @param buf_size number of bytes available in buf + * @param buf where to copy the message (can be NULL) + * @return number of bytes needed (if buf_size too small) or used + */ +size_t +GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr, + size_t buf_size, void *buf); + + +/** + * Explicitly cancel a pending request. + * + * @param pr request to cancel + * @param full_cleanup fully purge the request + */ +void +GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr, int full_cleanup); + + +/** + * Signature of function called on each request. + * (Note: 'subtype' of GNUNET_CONTAINER_HashMapIterator). + * + * @param cls closure + * @param key query for the request + * @param pr handle to the pending request + * @return GNUNET_YES to continue to iterate + */ +typedef int (*GSF_PendingRequestIterator) (void *cls, + const GNUNET_HashCode * key, + struct GSF_PendingRequest * pr); + + +/** + * Iterate over all pending requests. + * + * @param it function to call for each request + * @param cls closure for it + */ +void +GSF_iterate_pending_requests_ (GSF_PendingRequestIterator it, void *cls); + + +/** + * Handle P2P "CONTENT" message. Checks that the message is + * well-formed and then checks if there are any pending requests for + * this content and possibly passes it on (to local clients or other + * peers). Does NOT perform migration (content caching at this peer). + * + * @param cp the other peer involved (sender or receiver, NULL + * for loopback messages where we are both sender and receiver) + * @param message the actual message + * @return GNUNET_OK if the message was well-formed, + * GNUNET_SYSERR if the message was malformed (close connection, + * do not cache under any circumstances) + */ +int +GSF_handle_p2p_content_ (struct GSF_ConnectedPeer *cp, + const struct GNUNET_MessageHeader *message); + + +/** + * Consider looking up the data in the DHT (anonymity-level permitting). + * + * @param pr the pending request to process + */ +void +GSF_dht_lookup_ (struct GSF_PendingRequest *pr); + + +/** + * Function to be called after we're done processing + * replies from the local lookup. + * + * @param cls closure + * @param pr the pending request we were processing + * @param result final datastore lookup result + */ +typedef void (*GSF_LocalLookupContinuation) (void *cls, + struct GSF_PendingRequest * pr, + enum GNUNET_BLOCK_EvaluationResult + result); + + +/** + * Look up the request in the local datastore. + * + * @param pr the pending request to process + * @param cont function to call at the end + * @param cont_cls closure for cont + */ +void +GSF_local_lookup_ (struct GSF_PendingRequest *pr, + GSF_LocalLookupContinuation cont, void *cont_cls); + + +/** + * Is the given target a legitimate peer for forwarding the given request? + * + * @param pr request + * @param target + * @return GNUNET_YES if this request could be forwarded to the given peer + */ +int +GSF_pending_request_test_target_ (struct GSF_PendingRequest *pr, + const struct GNUNET_PeerIdentity *target); + + + +/** + * Setup the subsystem. + */ +void +GSF_pending_request_init_ (void); + + +/** + * Shutdown the subsystem. + */ +void +GSF_pending_request_done_ (void); + + +#endif +/* 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 new file mode 100644 index 0000000..22a76f3 --- /dev/null +++ b/src/fs/gnunet-service-fs_push.c @@ -0,0 +1,658 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_push.c + * @brief API to push content from our datastore to other peers + * ('anonymous'-content P2P migration) + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-fs.h" +#include "gnunet-service-fs_cp.h" +#include "gnunet-service-fs_indexing.h" +#include "gnunet-service-fs_push.h" + + +/** + * Maximum number of blocks we keep in memory for migration. + */ +#define MAX_MIGRATION_QUEUE 8 + +/** + * Blocks are at most migrated to this number of peers + * plus one, each time they are fetched from the database. + */ +#define MIGRATION_LIST_SIZE 2 + +/** + * How long must content remain valid for us to consider it for migration? + * If content will expire too soon, there is clearly no point in pushing + * it to other peers. This value gives the threshold for migration. Note + * that if this value is increased, the migration testcase may need to be + * adjusted as well (especially the CONTENT_LIFETIME in fs_test_lib.c). + */ +#define MIN_MIGRATION_CONTENT_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) + + +/** + * Block that is ready for migration to other peers. Actual data is at the end of the block. + */ +struct MigrationReadyBlock +{ + + /** + * This is a doubly-linked list. + */ + struct MigrationReadyBlock *next; + + /** + * This is a doubly-linked list. + */ + struct MigrationReadyBlock *prev; + + /** + * Query for the block. + */ + GNUNET_HashCode query; + + /** + * When does this block expire? + */ + struct GNUNET_TIME_Absolute expiration; + + /** + * Peers we already forwarded this + * block to. Zero for empty entries. + */ + GNUNET_PEER_Id target_list[MIGRATION_LIST_SIZE]; + + /** + * Size of the block. + */ + size_t size; + + /** + * Number of targets already used. + */ + unsigned int used_targets; + + /** + * Type of the block. + */ + enum GNUNET_BLOCK_Type type; +}; + + +/** + * Information about a peer waiting for + * migratable data. + */ +struct MigrationReadyPeer +{ + /** + * This is a doubly-linked list. + */ + struct MigrationReadyPeer *next; + + /** + * This is a doubly-linked list. + */ + struct MigrationReadyPeer *prev; + + /** + * Handle to peer. + */ + struct GSF_ConnectedPeer *peer; + + /** + * Handle for current transmission request, + * or NULL for none. + */ + struct GSF_PeerTransmitHandle *th; + + /** + * Message we are trying to push right now (or NULL) + */ + struct PutMessage *msg; +}; + + +/** + * Head of linked list of blocks that can be migrated. + */ +static struct MigrationReadyBlock *mig_head; + +/** + * Tail of linked list of blocks that can be migrated. + */ +static struct MigrationReadyBlock *mig_tail; + +/** + * Head of linked list of peers. + */ +static struct MigrationReadyPeer *peer_head; + +/** + * Tail of linked list of peers. + */ +static struct MigrationReadyPeer *peer_tail; + +/** + * Request to datastore for migration (or NULL). + */ +static struct GNUNET_DATASTORE_QueueEntry *mig_qe; + +/** + * ID of task that collects blocks for migration. + */ +static GNUNET_SCHEDULER_TaskIdentifier mig_task; + +/** + * What is the maximum frequency at which we are allowed to + * poll the datastore for migration content? + */ +static struct GNUNET_TIME_Relative min_migration_delay; + +/** + * Size of the doubly-linked list of migration blocks. + */ +static unsigned int mig_size; + +/** + * Is this module enabled? + */ +static int enabled; + + +/** + * Delete the given migration block. + * + * @param mb block to delete + */ +static void +delete_migration_block (struct MigrationReadyBlock *mb) +{ + GNUNET_CONTAINER_DLL_remove (mig_head, mig_tail, mb); + GNUNET_PEER_decrement_rcs (mb->target_list, MIGRATION_LIST_SIZE); + mig_size--; + GNUNET_free (mb); +} + + +/** + * Find content for migration to this peer. + */ +static void +find_content (struct MigrationReadyPeer *mrp); + + +/** + * Transmit the message currently scheduled for + * transmission. + * + * @param cls the 'struct MigrationReadyPeer' + * @param buf_size number of bytes available in buf + * @param buf where to copy the message, NULL on error (peer disconnect) + * @return number of bytes copied to 'buf', can be 0 (without indicating an error) + */ +static size_t +transmit_message (void *cls, size_t buf_size, void *buf) +{ + struct MigrationReadyPeer *peer = cls; + struct PutMessage *msg; + uint16_t msize; + + peer->th = NULL; + msg = peer->msg; + peer->msg = NULL; + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to migrate content to another peer (disconnect)\n"); + GNUNET_free (msg); + return 0; + } + msize = ntohs (msg->header.size); + GNUNET_assert (msize <= buf_size); + memcpy (buf, msg, msize); + GNUNET_free (msg); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Pushing %u bytes to another peer\n", + msize); + find_content (peer); + return msize; +} + + +/** + * Send the given block to the given peer. + * + * @param peer target peer + * @param block the block + * @return GNUNET_YES if the block was deleted (!) + */ +static int +transmit_content (struct MigrationReadyPeer *peer, + struct MigrationReadyBlock *block) +{ + size_t msize; + struct PutMessage *msg; + unsigned int i; + struct GSF_PeerPerformanceData *ppd; + int ret; + + ppd = GSF_get_peer_performance_data_ (peer->peer); + GNUNET_assert (NULL == peer->th); + msize = sizeof (struct PutMessage) + block->size; + msg = GNUNET_malloc (msize); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT); + msg->header.size = htons (msize); + msg->type = htonl (block->type); + msg->expiration = GNUNET_TIME_absolute_hton (block->expiration); + memcpy (&msg[1], &block[1], block->size); + peer->msg = msg; + for (i = 0; i < MIGRATION_LIST_SIZE; i++) + { + if (block->target_list[i] == 0) + { + block->target_list[i] = ppd->pid; + GNUNET_PEER_change_rc (block->target_list[i], 1); + break; + } + } + if (MIGRATION_LIST_SIZE == i) + { + delete_migration_block (block); + ret = GNUNET_YES; + } + else + { + ret = GNUNET_NO; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking for transmission of %u bytes for migration\n", msize); + peer->th = GSF_peer_transmit_ (peer->peer, GNUNET_NO, 0 /* priority */ , + GNUNET_TIME_UNIT_FOREVER_REL, msize, + &transmit_message, peer); + return ret; +} + + +/** + * Count the number of peers this block has + * already been forwarded to. + * + * @param block the block + * @return number of times block was forwarded + */ +static unsigned int +count_targets (struct MigrationReadyBlock *block) +{ + unsigned int i; + + for (i = 0; i < MIGRATION_LIST_SIZE; i++) + if (block->target_list[i] == 0) + return i; + return i; +} + + +/** + * Check if sending this block to this peer would + * be a good idea. + * + * @param peer target peer + * @param block the block + * @return score (>= 0: feasible, negative: infeasible) + */ +static long +score_content (struct MigrationReadyPeer *peer, + struct MigrationReadyBlock *block) +{ + unsigned int i; + struct GSF_PeerPerformanceData *ppd; + struct GNUNET_PeerIdentity id; + uint32_t dist; + + ppd = GSF_get_peer_performance_data_ (peer->peer); + for (i = 0; i < MIGRATION_LIST_SIZE; i++) + if (block->target_list[i] == ppd->pid) + return -1; + GNUNET_assert (0 != ppd->pid); + GNUNET_PEER_resolve (ppd->pid, &id); + dist = GNUNET_CRYPTO_hash_distance_u32 (&block->query, &id.hashPubKey); + /* closer distance, higher score: */ + return UINT32_MAX - dist; +} + + +/** + * If the migration task is not currently running, consider + * (re)scheduling it with the appropriate delay. + */ +static void +consider_gathering (void); + + +/** + * Find content for migration to this peer. + * + * @param mrp peer to find content for + */ +static void +find_content (struct MigrationReadyPeer *mrp) +{ + struct MigrationReadyBlock *pos; + long score; + long best_score; + struct MigrationReadyBlock *best; + + GNUNET_assert (NULL == mrp->th); + best = NULL; + best_score = -1; + pos = mig_head; + while (NULL != pos) + { + score = score_content (mrp, pos); + if (score > best_score) + { + best_score = score; + best = pos; + } + pos = pos->next; + } + if (NULL == best) + { + if (mig_size < MAX_MIGRATION_QUEUE) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No content found for pushing, waiting for queue to fill\n"); + return; /* will fill up eventually... */ + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No suitable content found, purging content from full queue\n"); + /* failed to find migration target AND + * queue is full, purge most-forwarded + * block from queue to make room for more */ + pos = mig_head; + while (NULL != pos) + { + score = count_targets (pos); + if (score >= best_score) + { + best_score = score; + best = pos; + } + pos = pos->next; + } + GNUNET_assert (NULL != best); + delete_migration_block (best); + consider_gathering (); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Preparing to push best content to peer\n"); + transmit_content (mrp, best); +} + + +/** + * Task that is run periodically to obtain blocks for content + * migration + * + * @param cls unused + * @param tc scheduler context (also unused) + */ +static void +gather_migration_blocks (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * If the migration task is not currently running, consider + * (re)scheduling it with the appropriate delay. + */ +static void +consider_gathering () +{ + struct GNUNET_TIME_Relative delay; + + if (GSF_dsh == NULL) + return; + if (mig_qe != NULL) + return; + if (mig_task != GNUNET_SCHEDULER_NO_TASK) + return; + if (mig_size >= MAX_MIGRATION_QUEUE) + return; + delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, mig_size); + delay = GNUNET_TIME_relative_divide (delay, MAX_MIGRATION_QUEUE); + delay = GNUNET_TIME_relative_max (delay, min_migration_delay); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling gathering task (queue size: %u)\n", mig_size); + mig_task = + GNUNET_SCHEDULER_add_delayed (delay, &gather_migration_blocks, NULL); +} + + +/** + * Process content offered for migration. + * + * @param cls closure + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + */ +static void +process_migration_content (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, uint64_t uid) +{ + struct MigrationReadyBlock *mb; + struct MigrationReadyPeer *pos; + + mig_qe = NULL; + if (key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No content found for migration...\n"); + consider_gathering (); + return; + } + if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value < + MIN_MIGRATION_CONTENT_LIFETIME.rel_value) + { + /* content will expire soon, don't bother */ + consider_gathering (); + return; + } + if (type == GNUNET_BLOCK_TYPE_FS_ONDEMAND) + { + if (GNUNET_OK != + GNUNET_FS_handle_on_demand_block (key, size, data, type, priority, + anonymity, expiration, uid, + &process_migration_content, NULL)) + consider_gathering (); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Retrieved block `%s' of type %u for migration (queue size: %u/%u)\n", + GNUNET_h2s (key), type, mig_size + 1, MAX_MIGRATION_QUEUE); + mb = GNUNET_malloc (sizeof (struct MigrationReadyBlock) + size); + mb->query = *key; + mb->expiration = expiration; + mb->size = size; + mb->type = type; + memcpy (&mb[1], data, size); + GNUNET_CONTAINER_DLL_insert_after (mig_head, mig_tail, mig_tail, mb); + mig_size++; + pos = peer_head; + while (pos != NULL) + { + if (NULL == pos->th) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Preparing to push best content to peer\n"); + if (GNUNET_YES == transmit_content (pos, mb)) + break; /* 'mb' was freed! */ + } + pos = pos->next; + } + consider_gathering (); +} + + +/** + * Task that is run periodically to obtain blocks for content + * migration + * + * @param cls unused + * @param tc scheduler context (also unused) + */ +static void +gather_migration_blocks (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + mig_task = GNUNET_SCHEDULER_NO_TASK; + if (mig_size >= MAX_MIGRATION_QUEUE) + return; + if (GSF_dsh != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking datastore for content for replication (queue size: %u)\n", + mig_size); + mig_qe = + GNUNET_DATASTORE_get_for_replication (GSF_dsh, 0, UINT_MAX, + GNUNET_TIME_UNIT_FOREVER_REL, + &process_migration_content, NULL); + if (NULL == mig_qe) + consider_gathering (); + } +} + + +/** + * A peer connected to us. Start pushing content + * to this peer. + * + * @param peer handle for the peer that connected + */ +void +GSF_push_start_ (struct GSF_ConnectedPeer *peer) +{ + struct MigrationReadyPeer *mrp; + + if (GNUNET_YES != enabled) + return; + mrp = GNUNET_malloc (sizeof (struct MigrationReadyPeer)); + mrp->peer = peer; + find_content (mrp); + GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, mrp); +} + + +/** + * A peer disconnected from us. Stop pushing content + * to this peer. + * + * @param peer handle for the peer that disconnected + */ +void +GSF_push_stop_ (struct GSF_ConnectedPeer *peer) +{ + struct MigrationReadyPeer *pos; + + pos = peer_head; + while (pos != NULL) + { + if (pos->peer == peer) + { + GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos); + if (NULL != pos->th) + { + GSF_peer_transmit_cancel_ (pos->th); + pos->th = NULL; + } + if (NULL != pos->msg) + { + GNUNET_free (pos->msg); + pos->msg = NULL; + } + GNUNET_free (pos); + return; + } + pos = pos->next; + } +} + + +/** + * Setup the module. + */ +void +GSF_push_init_ () +{ + enabled = + GNUNET_CONFIGURATION_get_value_yesno (GSF_cfg, "FS", "CONTENT_PUSHING"); + if (GNUNET_YES != enabled) + return; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (GSF_cfg, "fs", "MIN_MIGRATION_DELAY", + &min_migration_delay)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value specified for option `%s' in section `%s', content pushing disabled\n"), + "MIN_MIGRATION_DELAY", "fs"); + return; + } + consider_gathering (); +} + + +/** + * Shutdown the module. + */ +void +GSF_push_done_ () +{ + if (GNUNET_SCHEDULER_NO_TASK != mig_task) + { + GNUNET_SCHEDULER_cancel (mig_task); + mig_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != mig_qe) + { + GNUNET_DATASTORE_cancel (mig_qe); + mig_qe = NULL; + } + while (NULL != mig_head) + delete_migration_block (mig_head); + GNUNET_assert (0 == mig_size); +} + +/* 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 new file mode 100644 index 0000000..7967b04 --- /dev/null +++ b/src/fs/gnunet-service-fs_push.h @@ -0,0 +1,66 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_push.h + * @brief support for pushing out content + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_FS_PUSH_H +#define GNUNET_SERVICE_FS_PUSH_H + +#include "gnunet-service-fs.h" + + +/** + * Setup the module. + */ +void +GSF_push_init_ (void); + + +/** + * Shutdown the module. + */ +void +GSF_push_done_ (void); + + +/** + * A peer connected to us or we are now again allowed to push content. + * Start pushing content to this peer. + * + * @param peer handle for the peer that connected + */ +void +GSF_push_start_ (struct GSF_ConnectedPeer *peer); + + +/** + * A peer disconnected from us or asked us to stop pushing content for + * a while. Stop pushing content to this peer. + * + * @param peer handle for the peer that disconnected + */ +void +GSF_push_stop_ (struct GSF_ConnectedPeer *peer); + + +#endif diff --git a/src/fs/gnunet-service-fs_put.c b/src/fs/gnunet-service-fs_put.c new file mode 100644 index 0000000..3ac6713 --- /dev/null +++ b/src/fs/gnunet-service-fs_put.c @@ -0,0 +1,238 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_put.c + * @brief API to PUT zero-anonymity index data from our datastore into the DHT + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-fs.h" +#include "gnunet-service-fs_put.h" + + +/** + * How often do we at most PUT content into the DHT? + */ +#define MAX_DHT_PUT_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + + +/** + * Context for each zero-anonymity iterator. + */ +struct PutOperator +{ + + /** + * Request to datastore for DHT PUTs (or NULL). + */ + struct GNUNET_DATASTORE_QueueEntry *dht_qe; + + /** + * Type we request from the datastore. + */ + enum GNUNET_BLOCK_Type dht_put_type; + + /** + * ID of task that collects blocks for DHT PUTs. + */ + GNUNET_SCHEDULER_TaskIdentifier dht_task; + + /** + * How many entires with zero anonymity of our type do we currently + * estimate to have in the database? + */ + uint64_t zero_anonymity_count_estimate; + + /** + * Current offset when iterating the database. + */ + uint64_t current_offset; +}; + + +/** + * ANY-terminated list of our operators (one per type + * of block that we're putting into the DHT). + */ +static struct PutOperator operators[] = { + {NULL, GNUNET_BLOCK_TYPE_FS_KBLOCK, 0, 0, 0}, + {NULL, GNUNET_BLOCK_TYPE_FS_SBLOCK, 0, 0, 0}, + {NULL, GNUNET_BLOCK_TYPE_FS_NBLOCK, 0, 0, 0}, + {NULL, GNUNET_BLOCK_TYPE_ANY, 0, 0, 0} +}; + + +/** + * Task that is run periodically to obtain blocks for DHT PUTs. + * + * @param cls type of blocks to gather + * @param tc scheduler context (unused) + */ +static void +gather_dht_put_blocks (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Task that is run periodically to obtain blocks for DHT PUTs. + * + * @param cls type of blocks to gather + * @param tc scheduler context (unused) + */ +static void +delay_dht_put_blocks (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PutOperator *po = cls; + struct GNUNET_TIME_Relative delay; + + po->dht_task = GNUNET_SCHEDULER_NO_TASK; + if (tc != NULL && 0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + if (po->zero_anonymity_count_estimate > 0) + { + delay = + GNUNET_TIME_relative_divide (GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY, + po->zero_anonymity_count_estimate); + delay = GNUNET_TIME_relative_min (delay, MAX_DHT_PUT_FREQ); + } + else + { + /* if we have NO zero-anonymity content yet, wait 5 minutes for some to + * (hopefully) appear */ + delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5); + } + po->dht_task = + GNUNET_SCHEDULER_add_delayed (delay, &gather_dht_put_blocks, po); +} + + +/** + * Store content in DHT. + * + * @param cls closure + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + */ +static void +process_dht_put_content (void *cls, const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, uint64_t uid) +{ + struct PutOperator *po = cls; + + po->dht_qe = NULL; + if (key == NULL) + { + po->zero_anonymity_count_estimate = po->current_offset - 1; + po->current_offset = 0; + po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_blocks, po); + return; + } + po->zero_anonymity_count_estimate = + GNUNET_MAX (po->current_offset, po->zero_anonymity_count_estimate); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Retrieved block `%s' of type %u for DHT PUT\n", GNUNET_h2s (key), + type); + GNUNET_DHT_put (GSF_dht, key, 5 /* DEFAULT_PUT_REPLICATION */ , + GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, type, size, data, + expiration, GNUNET_TIME_UNIT_FOREVER_REL, + &delay_dht_put_blocks, po); +} + + +/** + * Task that is run periodically to obtain blocks for DHT PUTs. + * + * @param cls type of blocks to gather + * @param tc scheduler context (unused) + */ +static void +gather_dht_put_blocks (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PutOperator *po = cls; + + po->dht_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + po->dht_qe = + GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh, po->current_offset++, 0, + UINT_MAX, + GNUNET_TIME_UNIT_FOREVER_REL, + po->dht_put_type, + &process_dht_put_content, po); + if (NULL == po->dht_qe) + po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_blocks, po); +} + + +/** + * Setup the module. + */ +void +GSF_put_init_ () +{ + unsigned int i; + + i = 0; + while (operators[i].dht_put_type != GNUNET_BLOCK_TYPE_ANY) + { + operators[i].dht_task = + GNUNET_SCHEDULER_add_now (&gather_dht_put_blocks, &operators[i]); + i++; + } +} + + +/** + * Shutdown the module. + */ +void +GSF_put_done_ () +{ + struct PutOperator *po; + unsigned int i; + + i = 0; + while ((po = &operators[i])->dht_put_type != GNUNET_BLOCK_TYPE_ANY) + { + if (GNUNET_SCHEDULER_NO_TASK != po->dht_task) + { + GNUNET_SCHEDULER_cancel (po->dht_task); + po->dht_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != po->dht_qe) + { + GNUNET_DATASTORE_cancel (po->dht_qe); + po->dht_qe = NULL; + } + i++; + } +} + +/* 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 new file mode 100644 index 0000000..59b1f83 --- /dev/null +++ b/src/fs/gnunet-service-fs_put.h @@ -0,0 +1,46 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/gnunet-service-fs_put.h + * @brief support for putting content into the DHT + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_FS_PUT_H +#define GNUNET_SERVICE_FS_PUT_H + +#include "gnunet-service-fs.h" + + +/** + * Setup the module. + */ +void +GSF_put_init_ (void); + + +/** + * Shutdown the module. + */ +void +GSF_put_done_ (void); + + +#endif diff --git a/src/fs/gnunet-unindex.c b/src/fs/gnunet-unindex.c new file mode 100644 index 0000000..3e8308d --- /dev/null +++ b/src/fs/gnunet-unindex.c @@ -0,0 +1,180 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/gnunet-unindex.c + * @brief unindex files published on GNUnet + * @author Christian Grothoff + * @author Krista Bennett + * @author James Blackwell + * @author Igor Wronsky + */ +#include "platform.h" +#include "gnunet_fs_service.h" + +static int ret; + +static int verbose; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_FS_Handle *ctx; + +static struct GNUNET_FS_UnindexContext *uc; + + +static void +cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_stop (ctx); + ctx = NULL; +} + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_UnindexContext *u; + + if (uc != NULL) + { + u = uc; + uc = NULL; + GNUNET_FS_unindex_stop (u); + } +} + +/** + * Called by FS client to give information about the progress of an + * operation. + * + * @param cls closure + * @param info details about the event, specifying the event type + * and various bits about the event + * @return client-context (for the next progress call + * for this operation; should be set to NULL for + * SUSPEND and STOPPED events). The value returned + * will be passed to future callbacks in the respective + * field in the GNUNET_FS_ProgressInfo struct. + */ +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) +{ + char *s; + + switch (info->status) + { + case GNUNET_FS_STATUS_UNINDEX_START: + break; + case GNUNET_FS_STATUS_UNINDEX_PROGRESS: + if (verbose) + { + s = GNUNET_STRINGS_relative_time_to_string (info->value.unindex.eta); + FPRINTF (stdout, _("Unindexing at %llu/%llu (%s remaining)\n"), + (unsigned long long) info->value.unindex.completed, + (unsigned long long) info->value.unindex.size, s); + GNUNET_free (s); + } + break; + case GNUNET_FS_STATUS_UNINDEX_ERROR: + FPRINTF (stderr, _("Error unindexing: %s.\n"), + info->value.unindex.specifics.error.message); + GNUNET_SCHEDULER_shutdown (); + break; + case GNUNET_FS_STATUS_UNINDEX_COMPLETED: + FPRINTF (stdout, "%s", _("Unindexing done.\n")); + GNUNET_SCHEDULER_shutdown (); + break; + case GNUNET_FS_STATUS_UNINDEX_STOPPED: + GNUNET_SCHEDULER_add_continuation (&cleanup_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + default: + FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); + break; + } + return NULL; +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + /* check arguments */ + if ((args[0] == NULL) || (args[1] != NULL)) + { + printf (_("You must specify one and only one filename for unindexing.\n")); + ret = -1; + return; + } + cfg = c; + ctx = + GNUNET_FS_start (cfg, "gnunet-unindex", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + if (NULL == ctx) + { + FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS"); + ret = 1; + return; + } + uc = GNUNET_FS_unindex_start (ctx, args[0], NULL); + if (NULL == uc) + { + FPRINTF (stderr, "%s", _("Could not start unindex operation.\n")); + GNUNET_FS_stop (ctx); + return; + } + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); +} + + +/** + * The main function to unindex content. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-unindex [OPTIONS] FILENAME", + gettext_noop + ("Unindex a file that was previously indexed with gnunet-publish."), + options, &run, NULL)) ? ret : 1; +} + +/* 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 new file mode 100644 index 0000000..32dcffa --- /dev/null +++ b/src/fs/perf_gnunet_service_fs_p2p.c @@ -0,0 +1,337 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/perf_gnunet_service_fs_p2p.c + * @brief profile P2P routing using simple publish + download operation + * @author Christian Grothoff + */ +#include "platform.h" +#include "fs_test_lib.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_NO + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 10) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) + +#define NUM_DAEMONS 2 + +#define SEED 42 + +static struct GNUNET_FS_TestDaemon *daemons[NUM_DAEMONS]; + +static int ok; + +static struct GNUNET_TIME_Absolute start_time; + +static const char *progname; + +static void +do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); +} + + +/** + * Master context for 'stat_run'. + */ +struct StatMaster +{ + struct GNUNET_STATISTICS_Handle *stat; + unsigned int daemon; + unsigned int value; +}; + +struct StatValues +{ + const char *subsystem; + const char *name; +}; + +/** + * Statistics we print out. + */ +static struct StatValues stats[] = { + {"fs", "# artificial delays introduced (ms)"}, + {"fs", "# queries forwarded"}, + {"fs", "# replies received and matched"}, + {"fs", "# results found locally"}, + {"fs", "# requests forwarded due to high load"}, + {"fs", "# requests done for free (low load)"}, + {"fs", "# requests dropped, priority insufficient"}, + {"fs", "# requests done for a price (normal load)"}, + {"fs", "# requests dropped by datastore (queue length limit)"}, + {"fs", "# P2P searches received"}, + {"fs", "# P2P searches discarded (queue length bound)"}, + {"fs", "# replies received for local clients"}, + {"fs", "# queries retransmitted to same target"}, + {"core", "# bytes decrypted"}, + {"core", "# bytes encrypted"}, + {"core", "# discarded CORE_SEND requests"}, + {"core", "# discarded CORE_SEND request bytes"}, + {"core", "# discarded lower priority CORE_SEND requests"}, + {"core", "# discarded lower priority CORE_SEND request bytes"}, + {"transport", "# bytes received via TCP"}, + {"transport", "# bytes transmitted via TCP"}, + {"datacache", "# bytes stored"}, + {NULL, NULL} +}; + + +/** + * Callback function to process statistic values. + * + * @param cls closure + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +print_stat (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + struct StatMaster *sm = cls; + + FPRINTF (stderr, "Peer %2u: %12s/%50s = %12llu\n", sm->daemon, subsystem, + name, (unsigned long long) value); + return GNUNET_OK; +} + + +/** + * Function that gathers stats from all daemons. + */ +static void +stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Function called when GET operation on stats is done. + */ +static void +get_done (void *cls, int success) +{ + struct StatMaster *sm = cls; + + GNUNET_break (GNUNET_OK == success); + sm->value++; + GNUNET_SCHEDULER_add_now (&stat_run, sm); +} + + +/** + * Function that gathers stats from all daemons. + */ +static void +stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct StatMaster *sm = cls; + + if (stats[sm->value].name != NULL) + { + GNUNET_STATISTICS_get (sm->stat, +#if 0 + NULL, NULL, +#else + stats[sm->value].subsystem, stats[sm->value].name, +#endif + GNUNET_TIME_UNIT_FOREVER_REL, &get_done, &print_stat, + sm); + return; + } + GNUNET_STATISTICS_destroy (sm->stat, GNUNET_NO); + sm->value = 0; + sm->daemon++; + if (sm->daemon == NUM_DAEMONS) + { + GNUNET_free (sm); + GNUNET_SCHEDULER_add_now (&do_stop, NULL); + return; + } + sm->stat = + GNUNET_STATISTICS_create ("", + GNUNET_FS_TEST_get_configuration (daemons, + sm->daemon)); + GNUNET_SCHEDULER_add_now (&stat_run, sm); +} + + +static void +do_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TIME_Relative del; + char *fancy; + struct StatMaster *sm; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + del = GNUNET_TIME_absolute_get_duration (start_time); + if (del.rel_value == 0) + del.rel_value = 1; + fancy = + GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) * + 1000LL / del.rel_value); + FPRINTF (stdout, "Download speed was %s/s\n", fancy); + GNUNET_free (fancy); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished download, shutting down\n", + (unsigned long long) FILESIZE); + sm = GNUNET_malloc (sizeof (struct StatMaster)); + sm->stat = + GNUNET_STATISTICS_create ("", + GNUNET_FS_TEST_get_configuration (daemons, + sm->daemon)); + GNUNET_SCHEDULER_add_now (&stat_run, sm); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout during download, shutting down with error\n"); + ok = 1; + GNUNET_SCHEDULER_add_now (&do_stop, NULL); + } +} + + +static void +do_download (void *cls, const struct GNUNET_FS_Uri *uri) +{ + int anonymity; + + if (NULL == uri) + { + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout during upload attempt, shutting down with error\n"); + ok = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", + (unsigned long long) FILESIZE); + start_time = GNUNET_TIME_absolute_get (); + if (NULL != strstr (progname, "dht")) + anonymity = 0; + else + anonymity = 1; + GNUNET_FS_TEST_download (daemons[0], TIMEOUT, anonymity, SEED, uri, VERBOSE, + &do_report, NULL); +} + + +static void +do_publish (void *cls, const char *emsg) +{ + int do_index; + int anonymity; + + if (NULL != emsg) + { + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error trying to connect: %s\n", emsg); + ok = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", + (unsigned long long) FILESIZE); + if (NULL != strstr (progname, "index")) + do_index = GNUNET_YES; + else + do_index = GNUNET_NO; + if (NULL != strstr (progname, "dht")) + anonymity = 0; + else + anonymity = 1; + + GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity, + do_index, FILESIZE, SEED, VERBOSE, &do_download, + NULL); +} + + +static void +do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_PeerGroup *pg; + + GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Daemons started, will now try to connect them\n"); + pg = GNUNET_FS_TEST_get_group (daemons); + GNUNET_break ((NUM_DAEMONS - 1) * 2 == + (GNUNET_TESTING_create_topology + (pg, GNUNET_TESTING_TOPOLOGY_LINE, + GNUNET_TESTING_TOPOLOGY_NONE, NULL))); + GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, + GNUNET_TESTING_TOPOLOGY_OPTION_NONE, 0.0, + TIMEOUT, NUM_DAEMONS, &do_publish, NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_FS_TEST_daemons_start ("fs_test_lib_data.conf", TIMEOUT, NUM_DAEMONS, + daemons, &do_connect, NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "perf-gnunet-service-fs-p2p", + "-c", + "fs_test_lib_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + progname = argv[0]; + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); + GNUNET_log_setup ("perf_gnunet_service_fs_p2p_index", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "perf-gnunet-service-fs-p2p-index", "nohelp", options, + &run, NULL); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); + return ok; +} + +/* end of perf_gnunet_service_fs_p2p.c */ diff --git a/src/fs/perf_gnunet_service_fs_p2p_trust.c b/src/fs/perf_gnunet_service_fs_p2p_trust.c new file mode 100644 index 0000000..c412e84 --- /dev/null +++ b/src/fs/perf_gnunet_service_fs_p2p_trust.c @@ -0,0 +1,418 @@ +/* + This file is part of GNUnet. + (C) 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/perf_gnunet_service_fs_p2p_trust.c + * @brief profile P2P routing trust mechanism. Creates + * a clique of NUM_DAEMONS (i.e. 3) where two + * peers share (seed) different files and download + * them from each other while all the other peers + * just "leach" those files. Ideally, the seeders + * "learn" that they contribute (to each other), + * and give the other seeder higher priority; + * naturally, this only happens nicely for larger + * files; finally, once the seeders are done, the + * leachers should see fast download rates as well. + * @author Christian Grothoff + * + * Sample output: + * - 10 MB, 3 peers, with delays: + * Download speed of type `seeder 1' was 757 KiB/s + * Download speed of type `seeder 2' was 613 KiB/s + * Download speed of type `leach` was 539 KiB/s + * + * - 10 MB, 3 peers, without delays: + * Download speed of type `seeder 1' was 1784 KiB/s + * Download speed of type `seeder 2' was 1604 KiB/s + * Download speed of type `leach` was 1384 KiB/s + */ +#include "platform.h" +#include "fs_test_lib.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_NO + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 1) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) + +/** + * Number of daemons in clique, must be at least 3 (!). + */ +#define NUM_DAEMONS 3 + +/** + * Seed for first file on offer. + */ +#define SEED1 42 + +/** + * Seed for second file on offer. + */ +#define SEED2 43 + +static struct GNUNET_FS_TestDaemon *daemons[NUM_DAEMONS]; + +static int ok; + +static struct GNUNET_TIME_Absolute start_time; + +static const char *progname; + +static struct GNUNET_FS_Uri *uri1; + +static struct GNUNET_FS_Uri *uri2; + +static void +do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); +} + + +/** + * Master context for 'stat_run'. + */ +struct StatMaster +{ + struct GNUNET_STATISTICS_Handle *stat; + unsigned int daemon; + unsigned int value; +}; + +struct StatValues +{ + const char *subsystem; + const char *name; +}; + +/** + * Statistics we print out. + */ +static struct StatValues stats[] = { + {"fs", "# artificial delays introduced (ms)"}, + {"fs", "# queries forwarded"}, + {"fs", "# replies received and matched"}, + {"fs", "# results found locally"}, + {"fs", "# requests forwarded due to high load"}, + {"fs", "# requests done for free (low load)"}, + {"fs", "# requests dropped, priority insufficient"}, + {"fs", "# requests done for a price (normal load)"}, + {"fs", "# requests dropped by datastore (queue length limit)"}, + {"fs", "# P2P searches received"}, + {"fs", "# P2P searches discarded (queue length bound)"}, + {"fs", "# replies received for local clients"}, + {"fs", "# queries retransmitted to same target"}, + {"core", "# bytes decrypted"}, + {"core", "# bytes encrypted"}, + {"core", "# discarded CORE_SEND requests"}, + {"core", "# discarded lower priority CORE_SEND requests"}, + {"transport", "# bytes received via TCP"}, + {"transport", "# bytes transmitted via TCP"}, + {"datacache", "# bytes stored"}, + {NULL, NULL} +}; + + +/** + * Callback function to process statistic values. + * + * @param cls closure + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +print_stat (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + struct StatMaster *sm = cls; + + FPRINTF (stderr, "Peer %2u: %12s/%50s = %12llu\n", sm->daemon, subsystem, + name, (unsigned long long) value); + return GNUNET_OK; +} + + +/** + * Function that gathers stats from all daemons. + */ +static void +stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Function called when GET operation on stats is done. + */ +static void +get_done (void *cls, int success) +{ + struct StatMaster *sm = cls; + + GNUNET_break (GNUNET_OK == success); + sm->value++; + GNUNET_SCHEDULER_add_now (&stat_run, sm); +} + + +/** + * Function that gathers stats from all daemons. + */ +static void +stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct StatMaster *sm = cls; + + if (stats[sm->value].name != NULL) + { + GNUNET_STATISTICS_get (sm->stat, +#if 0 + NULL, NULL, +#else + stats[sm->value].subsystem, stats[sm->value].name, +#endif + GNUNET_TIME_UNIT_FOREVER_REL, &get_done, &print_stat, + sm); + return; + } + GNUNET_STATISTICS_destroy (sm->stat, GNUNET_NO); + sm->value = 0; + sm->daemon++; + if (sm->daemon == NUM_DAEMONS) + { + GNUNET_free (sm); + GNUNET_SCHEDULER_add_now (&do_stop, NULL); + return; + } + sm->stat = + GNUNET_STATISTICS_create ("", + GNUNET_FS_TEST_get_configuration (daemons, + sm->daemon)); + GNUNET_SCHEDULER_add_now (&stat_run, sm); +} + + +static void +do_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static int download_counter; + const char *type = cls; + struct GNUNET_TIME_Relative del; + char *fancy; + struct StatMaster *sm; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + del = GNUNET_TIME_absolute_get_duration (start_time); + if (del.rel_value == 0) + del.rel_value = 1; + fancy = + GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) * + 1000LL / del.rel_value); + FPRINTF (stderr, "Download speed of type `%s' was %s/s\n", type, fancy); + GNUNET_free (fancy); + if (NUM_DAEMONS != ++download_counter) + return; /* more downloads to come */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finished all downloads, shutting down\n", + (unsigned long long) FILESIZE); + sm = GNUNET_malloc (sizeof (struct StatMaster)); + sm->stat = + GNUNET_STATISTICS_create ("", + GNUNET_FS_TEST_get_configuration (daemons, + sm->daemon)); + GNUNET_SCHEDULER_add_now (&stat_run, sm); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout during download for type `%s', shutting down with error\n", + type); + ok = 1; + GNUNET_SCHEDULER_add_now (&do_stop, NULL); + } +} + + +static void +do_downloads (void *cls, const struct GNUNET_FS_Uri *u2) +{ + int anonymity; + unsigned int i; + + if (NULL == u2) + { + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout during upload attempt, shutting down with error\n"); + ok = 1; + return; + } + uri2 = GNUNET_FS_uri_dup (u2); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", + (unsigned long long) FILESIZE); + start_time = GNUNET_TIME_absolute_get (); + if (NULL != strstr (progname, "dht")) + anonymity = 0; + else + anonymity = 1; + /* (semi) leach-download(s); not true leaches since + * these peers do participate in sharing, they just + * don't have to offer anything *initially*. */ + for (i = 0; i < NUM_DAEMONS - 2; i++) + GNUNET_FS_TEST_download (daemons[i], TIMEOUT, anonymity, + 0 == (i % 2) ? SEED1 : SEED2, + 0 == (i % 2) ? uri1 : uri2, VERBOSE, &do_report, + "leach"); + /* mutual downloads of (primary) sharing peers */ + GNUNET_FS_TEST_download (daemons[NUM_DAEMONS - 2], TIMEOUT, anonymity, SEED1, + uri1, VERBOSE, &do_report, "seeder 2"); + GNUNET_FS_TEST_download (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity, SEED2, + uri2, VERBOSE, &do_report, "seeder 1"); +} + + +static void +do_publish2 (void *cls, const struct GNUNET_FS_Uri *u1) +{ + int do_index; + int anonymity; + + if (NULL == u1) + { + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout during upload attempt, shutting down with error\n"); + ok = 1; + return; + } + uri1 = GNUNET_FS_uri_dup (u1); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", + (unsigned long long) FILESIZE); + if (NULL != strstr (progname, "index")) + do_index = GNUNET_YES; + else + do_index = GNUNET_NO; + if (NULL != strstr (progname, "dht")) + anonymity = 0; + else + anonymity = 1; + + GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 2], TIMEOUT, anonymity, + do_index, FILESIZE, SEED2, VERBOSE, &do_downloads, + NULL); +} + +static void +do_publish1 (void *cls, const char *emsg) +{ + int do_index; + int anonymity; + + if (NULL != emsg) + { + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error trying to connect: %s\n", emsg); + ok = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", + (unsigned long long) FILESIZE); + if (NULL != strstr (progname, "index")) + do_index = GNUNET_YES; + else + do_index = GNUNET_NO; + if (NULL != strstr (progname, "dht")) + anonymity = 0; + else + anonymity = 1; + + GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity, + do_index, FILESIZE, SEED1, VERBOSE, &do_publish2, + NULL); +} + + +static void +do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_PeerGroup *pg; + + GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Daemons started, will now try to connect them\n"); + pg = GNUNET_FS_TEST_get_group (daemons); + GNUNET_TESTING_create_topology (pg, GNUNET_TESTING_TOPOLOGY_CLIQUE, + GNUNET_TESTING_TOPOLOGY_NONE, NULL); + GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_CLIQUE, + GNUNET_TESTING_TOPOLOGY_OPTION_NONE, 0.0, + TIMEOUT, NUM_DAEMONS, &do_publish1, NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_FS_TEST_daemons_start ("fs_test_lib_data.conf", TIMEOUT, NUM_DAEMONS, + daemons, &do_connect, NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "perf-gnunet-service-fs-p2p", + "-c", + "fs_test_lib_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + progname = argv[0]; + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); + GNUNET_log_setup ("perf_gnunet_service_fs_p2p_trust", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "perf-gnunet-service-fs-p2p-trust", "nohelp", options, + &run, NULL); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); + return ok; +} + +/* end of perf_gnunet_service_fs_p2p_trust.c */ diff --git a/src/fs/plugin_block_fs.c b/src/fs/plugin_block_fs.c new file mode 100644 index 0000000..9b73f24 --- /dev/null +++ b/src/fs/plugin_block_fs.c @@ -0,0 +1,322 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/plugin_block_fs.c + * @brief blocks used for file-sharing + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_block_plugin.h" +#include "block_fs.h" +#include "gnunet_signatures.h" + +#define DEBUG_FS_BLOCK GNUNET_EXTRA_LOGGING + +/** + * Number of bits we set per entry in the bloomfilter. + * Do not change! + */ +#define BLOOMFILTER_K 16 + +/** + * Function called to validate a reply or a request. For + * request evaluation, simply pass "NULL" for the reply_block. + * Note that it is assumed that the reply has already been + * matched to the key (and signatures checked) as it would + * be done with the "get_key" function. + * + * @param cls closure + * @param type block type + * @param query original query (hash) + * @param bf pointer to bloom filter associated with query; possibly updated (!) + * @param bf_mutator mutation value for bf + * @param xquery extrended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in reply block + * @return characterization of result + */ +static enum GNUNET_BLOCK_EvaluationResult +block_plugin_fs_evaluate (void *cls, enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode * query, + struct GNUNET_CONTAINER_BloomFilter **bf, + int32_t bf_mutator, const void *xquery, + size_t xquery_size, const void *reply_block, + size_t reply_block_size) +{ + const struct SBlock *sb; + GNUNET_HashCode chash; + GNUNET_HashCode mhash; + const GNUNET_HashCode *nsid; + GNUNET_HashCode sh; + + switch (type) + { + case GNUNET_BLOCK_TYPE_FS_DBLOCK: + case GNUNET_BLOCK_TYPE_FS_IBLOCK: + if (xquery_size != 0) + { + GNUNET_break_op (0); + return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; + } + if (reply_block == NULL) + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + return GNUNET_BLOCK_EVALUATION_OK_LAST; + case GNUNET_BLOCK_TYPE_FS_KBLOCK: + case GNUNET_BLOCK_TYPE_FS_NBLOCK: + if (xquery_size != 0) + { + GNUNET_break_op (0); + return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; + } + if (reply_block == NULL) + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + if (NULL != bf) + { + GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); + GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); + if (NULL != *bf) + { + if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) + return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; + } + else + { + *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K); + } + GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash); + } + return GNUNET_BLOCK_EVALUATION_OK_MORE; + case GNUNET_BLOCK_TYPE_FS_SBLOCK: + if (xquery_size != sizeof (GNUNET_HashCode)) + { + GNUNET_break_op (0); + return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; + } + if (reply_block == NULL) + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + nsid = xquery; + if (reply_block_size < sizeof (struct SBlock)) + { + GNUNET_break_op (0); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + sb = reply_block; + GNUNET_CRYPTO_hash (&sb->subspace, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &sh); + if (0 != memcmp (nsid, &sh, sizeof (GNUNET_HashCode))) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "block-fs", + _ + ("Reply mismatched in terms of namespace. Discarded.\n")); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + if (NULL != bf) + { + GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); + GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); + if (NULL != *bf) + { + if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) + return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; + } + else + { + *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K); + } + GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash); + } + return GNUNET_BLOCK_EVALUATION_OK_MORE; + default: + return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; + } +} + + +/** + * Function called to obtain the key for a block. + * + * @param cls closure + * @param type block type + * @param block block to get the key for + * @param block_size number of bytes in block + * @param key set to the key (query) for the given block + * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported + * (or if extracting a key from a block of this type does not work) + */ +static int +block_plugin_fs_get_key (void *cls, enum GNUNET_BLOCK_Type type, + const void *block, size_t block_size, + GNUNET_HashCode * key) +{ + const struct KBlock *kb; + const struct SBlock *sb; + const struct NBlock *nb; + + switch (type) + { + case GNUNET_BLOCK_TYPE_FS_DBLOCK: + case GNUNET_BLOCK_TYPE_FS_IBLOCK: + GNUNET_CRYPTO_hash (block, block_size, key); + return GNUNET_OK; + case GNUNET_BLOCK_TYPE_FS_KBLOCK: + if (block_size < sizeof (struct KBlock)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + kb = block; + if (block_size - sizeof (struct KBlock) != + ntohl (kb->purpose.size) - + sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) - + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK, + &kb->purpose, &kb->signature, &kb->keyspace)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + if (key != NULL) + GNUNET_CRYPTO_hash (&kb->keyspace, + sizeof (struct + GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + key); + return GNUNET_OK; + case GNUNET_BLOCK_TYPE_FS_SBLOCK: + if (block_size < sizeof (struct SBlock)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + sb = block; + if (block_size != + ntohl (sb->purpose.size) + sizeof (struct GNUNET_CRYPTO_RsaSignature)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK, + &sb->purpose, &sb->signature, &sb->subspace)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + if (key != NULL) + *key = sb->identifier; + return GNUNET_OK; + case GNUNET_BLOCK_TYPE_FS_NBLOCK: + if (block_size < sizeof (struct NBlock)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + nb = block; + if (block_size - sizeof (struct NBlock) != + ntohl (nb->ns_purpose.size) - + sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) - + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + if (block_size != + ntohl (nb->ksk_purpose.size) + + sizeof (struct GNUNET_CRYPTO_RsaSignature)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG, + &nb->ksk_purpose, &nb->ksk_signature, + &nb->keyspace)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK, + &nb->ns_purpose, &nb->ns_signature, + &nb->subspace)) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + /* FIXME: we used to xor ID with NSID, + * why not here? */ + if (key != NULL) + GNUNET_CRYPTO_hash (&nb->keyspace, + sizeof (struct + GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + key); + return GNUNET_OK; + default: + return GNUNET_SYSERR; + } +} + + +/** + * Entry point for the plugin. + */ +void * +libgnunet_plugin_block_fs_init (void *cls) +{ + static enum GNUNET_BLOCK_Type types[] = + { + GNUNET_BLOCK_TYPE_FS_DBLOCK, + GNUNET_BLOCK_TYPE_FS_IBLOCK, + GNUNET_BLOCK_TYPE_FS_KBLOCK, + GNUNET_BLOCK_TYPE_FS_SBLOCK, + GNUNET_BLOCK_TYPE_FS_NBLOCK, + GNUNET_BLOCK_TYPE_ANY /* end of list */ + }; + struct GNUNET_BLOCK_PluginFunctions *api; + + api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); + api->evaluate = &block_plugin_fs_evaluate; + api->get_key = &block_plugin_fs_get_key; + api->types = types; + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +libgnunet_plugin_block_fs_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + +/* end of plugin_block_fs.c */ diff --git a/src/fs/test_fs_data.conf b/src/fs/test_fs_data.conf new file mode 100644 index 0000000..f2b4e1e --- /dev/null +++ b/src/fs/test_fs_data.conf @@ -0,0 +1,8 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-data/ +DEFAULTCONFIG = test_fs_data.conf + +[fs] +ACTIVEMIGRATION = NO + diff --git a/src/fs/test_fs_defaults.conf b/src/fs/test_fs_defaults.conf new file mode 100644 index 0000000..2bc3d26 --- /dev/null +++ b/src/fs/test_fs_defaults.conf @@ -0,0 +1,87 @@ +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-lib/ +DEFAULTCONFIG = fs_test_lib_data.conf + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[resolver] +PORT = 43464 +HOSTNAME = localhost + +[transport] +PORT = 43465 +PLUGINS = tcp + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[arm] +PORT = 43466 +HOSTNAME = localhost +DEFAULTSERVICES = fs + +[datastore] +QUOTA = 100 MB + +[statistics] +PORT = 43467 +HOSTNAME = localhost + +[transport-tcp] +BINDTO = 127.0.0.1 +PORT = 43468 + +[peerinfo] +PORT = 43469 +HOSTNAME = localhost + +[ats] +WAN_QUOTA_IN = 65536 +WAN_QUOTA_OUT = 65536 + +[core] +PORT = 43470 +HOSTNAME = localhost + +[fs] +PORT = 43471 +HOSTNAME = localhost +CONTENT_CACHING = YES +CONTENT_PUSHING = YES +DELAY = YES + +[testing] +WEAKRANDOM = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat + +[dhtcache] +QUOTA=65536 +DATABASE=sqlite + +[mesh] +AUTOSTART = NO + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[dv] +AUTOSTART = NO + +[chat] +AUTOSTART = NO + +[gns] +AUTOSTART = NO + +[vpn] +AUTOSTART = NO diff --git a/src/fs/test_fs_directory.c b/src/fs/test_fs_directory.c new file mode 100644 index 0000000..96ad29c --- /dev/null +++ b/src/fs/test_fs_directory.c @@ -0,0 +1,179 @@ +/* + This file is part of GNUnet. + (C) 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_directory.c + * @brief Test for fs_directory.c + * @author Christian Grothoff + */ + +#include "platform.h" +#include +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" + +#define ABORT() { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); return 1; } + +struct PCLS +{ + struct GNUNET_FS_Uri **uri; + struct GNUNET_CONTAINER_MetaData **md; + unsigned int pos; + unsigned int max; +}; + +static void +processor (void *cls, const char *filename, const struct GNUNET_FS_Uri *uri, + const struct GNUNET_CONTAINER_MetaData *md, size_t length, + const void *data) +{ + struct PCLS *p = cls; + int i; + + if (NULL == uri) + return; /* ignore directory's meta data */ + for (i = 0; i < p->max; i++) + { + if (GNUNET_CONTAINER_meta_data_test_equal (p->md[i], md) && + GNUNET_FS_uri_test_equal (p->uri[i], uri)) + { + p->pos++; + return; + } + } + FPRINTF (stderr, "Error at %s:%d\n", __FILE__, __LINE__); +} + +static int +testDirectory (unsigned int i) +{ + struct GNUNET_FS_DirectoryBuilder *db; + char *data; + size_t dlen; + struct GNUNET_FS_Uri **uris; + struct GNUNET_CONTAINER_MetaData **mds; + struct GNUNET_CONTAINER_MetaData *meta; + struct PCLS cls; + char *emsg; + int p; + int q; + char uri[512]; + char txt[128]; + int ret = 0; + struct GNUNET_TIME_Absolute start; + char *s; + + cls.max = i; + uris = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri *) * i); + mds = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_MetaData *) * i); + meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "A title", strlen ("A title") + 1); + GNUNET_CONTAINER_meta_data_insert (meta, "", + EXTRACTOR_METATYPE_AUTHOR_NAME, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "An author", strlen ("An author") + 1); + for (p = 0; p < i; p++) + { + mds[p] = GNUNET_CONTAINER_meta_data_create (); + for (q = 0; q <= p; q++) + { + GNUNET_snprintf (txt, sizeof (txt), "%u -- %u\n", p, q); + GNUNET_CONTAINER_meta_data_insert (mds[p], "", + q % EXTRACTOR_metatype_get_max (), + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", txt, strlen (txt) + 1); + } + GNUNET_snprintf (uri, sizeof (uri), + "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.%u", + p); + emsg = NULL; + uris[p] = GNUNET_FS_uri_parse (uri, &emsg); + if (uris[p] == NULL) + { + GNUNET_CONTAINER_meta_data_destroy (mds[p]); + while (--p > 0) + { + GNUNET_CONTAINER_meta_data_destroy (mds[p]); + GNUNET_FS_uri_destroy (uris[p]); + } + GNUNET_free (mds); + GNUNET_free (uris); + GNUNET_free (emsg); + GNUNET_CONTAINER_meta_data_destroy (meta); + ABORT (); /* error in testcase */ + } + GNUNET_assert (emsg == NULL); + } + start = GNUNET_TIME_absolute_get (); + db = GNUNET_FS_directory_builder_create (meta); + for (p = 0; p < i; p++) + GNUNET_FS_directory_builder_add (db, uris[p], mds[p], NULL); + GNUNET_FS_directory_builder_finish (db, &dlen, (void **) &data); + s = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration + (start)); + FPRINTF (stdout, + "Creating directory with %u entires and total size %llu took %s\n", + i, (unsigned long long) dlen, s); + GNUNET_free (s); + if (i < 100) + { + cls.pos = 0; + cls.uri = uris; + cls.md = mds; + GNUNET_FS_directory_list_contents (dlen, data, 0, &processor, &cls); + GNUNET_assert (cls.pos == i); + } + GNUNET_free (data); + GNUNET_CONTAINER_meta_data_destroy (meta); + for (p = 0; p < i; p++) + { + GNUNET_CONTAINER_meta_data_destroy (mds[p]); + GNUNET_FS_uri_destroy (uris[p]); + } + GNUNET_free (uris); + GNUNET_free (mds); + return ret; +} + + +int +main (int argc, char *argv[]) +{ + int failureCount = 0; + int i; + + GNUNET_log_setup ("test_fs_directory", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + for (i = 17; i < 1000; i *= 2) + failureCount += testDirectory (i); + if (failureCount != 0) + return 1; + return 0; +} + +/* end of test_fs_directory.c */ diff --git a/src/fs/test_fs_download.c b/src/fs/test_fs_download.c new file mode 100644 index 0000000..570eab9 --- /dev/null +++ b/src/fs/test_fs_download.c @@ -0,0 +1,353 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_download.c + * @brief simple testcase for simple publish + download operation + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" +#include + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 2) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct GNUNET_TIME_Absolute start; + +static struct GNUNET_FS_Handle *fs; + +static struct GNUNET_FS_DownloadContext *download; + +static struct GNUNET_FS_PublishContext *publish; + +static GNUNET_SCHEDULER_TaskIdentifier timeout_kill; + +static char *fn; + +static int err; + +static void +timeout_kill_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (download != NULL) + { + GNUNET_FS_download_stop (download, GNUNET_YES); + download = NULL; + } + else if (publish != NULL) + { + GNUNET_FS_publish_stop (publish); + publish = NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout downloading file\n"); + timeout_kill = GNUNET_SCHEDULER_NO_TASK; + err = 1; +} + +static void +abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (publish != NULL) + { + GNUNET_FS_publish_stop (publish); + publish = NULL; + } +} + +static void +stop_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_stop (fs); + fs = NULL; +} + +static void +abort_download_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + uint64_t size; + + if (download != NULL) + { + GNUNET_FS_download_stop (download, GNUNET_YES); + download = NULL; + } + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_size (fn, &size, GNUNET_YES)); + GNUNET_assert (size == FILESIZE); + GNUNET_DISK_directory_remove (fn); + GNUNET_free (fn); + fn = NULL; + GNUNET_SCHEDULER_cancel (timeout_kill); + timeout_kill = GNUNET_SCHEDULER_NO_TASK; +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + + switch (event->status) + { + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: +#if VERBOSE + printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.publish.completed, + (unsigned long long) event->value.publish.size, + event->value.publish.specifics.progress.depth, + (unsigned long long) event->value.publish.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + printf ("Publishing complete, %llu kb/s.\n", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024LL)); + GAUGER ("FS", "Publishing speed (insertion)", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024LL), "kb/s"); + fn = GNUNET_DISK_mktemp ("gnunet-download-test-dst"); + start = GNUNET_TIME_absolute_get (); + download = + GNUNET_FS_download_start (fs, + event->value.publish.specifics. + completed.chk_uri, NULL, fn, NULL, 0, + FILESIZE, 1, GNUNET_FS_DOWNLOAD_OPTION_NONE, + "download", NULL); + GNUNET_assert (download != NULL); + break; + case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: + printf ("Download complete, %llu kb/s.\n", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024LL)); + GAUGER ("FS", "Local download speed (inserted)", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024LL), "kb/s"); + GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); + break; + case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: + GNUNET_assert (download == event->value.download.dc); +#if VERBOSE + printf ("Download is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.download.completed, + (unsigned long long) event->value.download.size, + event->value.download.specifics.progress.depth, + (unsigned long long) event->value.download.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + FPRINTF (stderr, "Error publishing file: %s\n", + event->value.publish.specifics.error.message); + GNUNET_break (0); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_DOWNLOAD_ERROR: + FPRINTF (stderr, "Error downloading file: %s\n", + event->value.download.specifics.error.message); + GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); + break; + case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: + case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: + break; + case GNUNET_FS_STATUS_PUBLISH_START: + GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); + GNUNET_assert (NULL == event->value.publish.pctx); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (1 == event->value.publish.anonymity); + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + GNUNET_assert (publish == event->value.publish.pc); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (1 == event->value.publish.anonymity); + GNUNET_SCHEDULER_add_now (&stop_fs_task, NULL); + break; + case GNUNET_FS_STATUS_DOWNLOAD_START: + GNUNET_assert (0 == strcmp ("download", event->value.download.cctx)); + GNUNET_assert (NULL == event->value.download.pctx); + GNUNET_assert (NULL != event->value.download.uri); + GNUNET_assert (0 == strcmp (fn, event->value.download.filename)); + GNUNET_assert (FILESIZE == event->value.download.size); + GNUNET_assert (0 == event->value.download.completed); + GNUNET_assert (1 == event->value.download.anonymity); + break; + case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: + GNUNET_assert (download == event->value.download.dc); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + default: + printf ("Unexpected event: %d\n", event->status); + break; + } + return NULL; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const char *keywords[] = { + "down_foo", + "down_bar", + }; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_FileInformation *fi; + size_t i; + struct GNUNET_FS_BlockOptions bo; + + setup_peer (&p1, "test_fs_download_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-download", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", + FILESIZE, buf, kuri, meta, + GNUNET_NO, &bo); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fi); + timeout_kill = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill_task, NULL); + start = GNUNET_TIME_absolute_get (); + publish = + GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + GNUNET_assert (publish != NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-download", + "-c", + "test_fs_download_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_download", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-download", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-download/"); + return err; +} + +/* end of test_fs_download.c */ diff --git a/src/fs/test_fs_download_data.conf b/src/fs/test_fs_download_data.conf new file mode 100644 index 0000000..25aad51 --- /dev/null +++ b/src/fs/test_fs_download_data.conf @@ -0,0 +1,5 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-download/ +DEFAULTCONFIG = test_fs_download_data.conf + diff --git a/src/fs/test_fs_download_indexed.c b/src/fs/test_fs_download_indexed.c new file mode 100644 index 0000000..e8504f1 --- /dev/null +++ b/src/fs/test_fs_download_indexed.c @@ -0,0 +1,372 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_download_indexed.c + * @brief simple testcase for downloading of indexed file + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" +#include + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 2) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct GNUNET_TIME_Absolute start; + +static struct GNUNET_FS_Handle *fs; + +static struct GNUNET_FS_DownloadContext *download; + +static struct GNUNET_FS_PublishContext *publish; + +static GNUNET_SCHEDULER_TaskIdentifier timeout_kill; + +static char *fn; + +static char *fn1; + +static int err; + +static void +timeout_kill_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (download != NULL) + { + GNUNET_FS_download_stop (download, GNUNET_YES); + download = NULL; + } + else if (publish != NULL) + { + GNUNET_FS_publish_stop (publish); + publish = NULL; + } + timeout_kill = GNUNET_SCHEDULER_NO_TASK; + err = 1; +} + +static void +abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (publish != NULL) + { + GNUNET_FS_publish_stop (publish); + publish = NULL; + } +} + +static void +stop_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_stop (fs); + fs = NULL; +} + +static void +abort_download_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + uint64_t size; + + if (download != NULL) + { + GNUNET_FS_download_stop (download, GNUNET_YES); + download = NULL; + } + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_size (fn, &size, GNUNET_YES)); + GNUNET_assert (size == FILESIZE); + GNUNET_DISK_directory_remove (fn); + GNUNET_free (fn); + fn = NULL; + GNUNET_SCHEDULER_cancel (timeout_kill); + timeout_kill = GNUNET_SCHEDULER_NO_TASK; +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + + switch (event->status) + { + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: +#if VERBOSE + printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.publish.completed, + (unsigned long long) event->value.publish.size, + event->value.publish.specifics.progress.depth, + (unsigned long long) event->value.publish.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + printf ("Publishing complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024LL)); + GAUGER ("FS", "Publishing speed (indexing)", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024LL), "kb/s"); + fn = GNUNET_DISK_mktemp ("gnunet-download-test-dst"); + start = GNUNET_TIME_absolute_get (); + download = + GNUNET_FS_download_start (fs, + event->value.publish.specifics. + completed.chk_uri, NULL, fn, NULL, 0, + FILESIZE, 1, GNUNET_FS_DOWNLOAD_OPTION_NONE, + "download", NULL); + GNUNET_assert (download != NULL); + break; + case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: + printf ("Download complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024LL)); + GAUGER ("FS", "Local download speed (indexed)", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024LL), "kb/s"); + GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); + break; + case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: + GNUNET_assert (download == event->value.download.dc); +#if VERBOSE + printf ("Download is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.download.completed, + (unsigned long long) event->value.download.size, + event->value.download.specifics.progress.depth, + (unsigned long long) event->value.download.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + FPRINTF (stderr, "Error publishing file: %s\n", + event->value.publish.specifics.error.message); + GNUNET_break (0); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_DOWNLOAD_ERROR: + FPRINTF (stderr, "Error downloading file: %s\n", + event->value.download.specifics.error.message); + GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); + break; + case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: + case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: + break; + case GNUNET_FS_STATUS_PUBLISH_START: + GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); + GNUNET_assert (NULL == event->value.publish.pctx); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (1 == event->value.publish.anonymity); + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + GNUNET_assert (publish == event->value.publish.pc); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (1 == event->value.publish.anonymity); + GNUNET_SCHEDULER_add_now (&stop_fs_task, NULL); + break; + case GNUNET_FS_STATUS_DOWNLOAD_START: + GNUNET_assert (0 == strcmp ("download", event->value.download.cctx)); + GNUNET_assert (NULL == event->value.download.pctx); + GNUNET_assert (NULL != event->value.download.uri); + GNUNET_assert (0 == strcmp (fn, event->value.download.filename)); + GNUNET_assert (FILESIZE == event->value.download.size); + GNUNET_assert (0 == event->value.download.completed); + GNUNET_assert (1 == event->value.download.anonymity); + break; + case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: + GNUNET_assert (download == event->value.download.dc); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + default: + printf ("Unexpected event: %d\n", event->status); + break; + } + return NULL; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const char *keywords[] = { + "down_foo", + "down_bar", + }; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_FileInformation *fi; + struct GNUNET_FS_BlockOptions bo; + size_t i; + + setup_peer (&p1, "test_fs_download_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-download-indexed", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + + fn1 = GNUNET_DISK_mktemp ("gnunet-download-indexed-test"); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn1, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + fi = GNUNET_FS_file_information_create_from_file (fs, "publish-context", fn1, + kuri, meta, GNUNET_YES, + &bo); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fi); + timeout_kill = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill_task, NULL); + start = GNUNET_TIME_absolute_get (); + publish = + GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + GNUNET_assert (publish != NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-download-indexed", + "-c", + "test_fs_download_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_download_indexed", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-download-indexed", "nohelp", options, &run, + NULL); + stop_arm (&p1); + if (fn1 != NULL) + { + GNUNET_DISK_directory_remove (fn1); + GNUNET_free (fn1); + } + if (fn != NULL) + { + GNUNET_DISK_directory_remove (fn); + GNUNET_free (fn); + } + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-download/"); + return err; +} + +/* end of test_fs_download_indexed.c */ diff --git a/src/fs/test_fs_download_persistence.c b/src/fs/test_fs_download_persistence.c new file mode 100644 index 0000000..bcb1c54 --- /dev/null +++ b/src/fs/test_fs_download_persistence.c @@ -0,0 +1,405 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_download_persistence.c + * @brief simple testcase for persistence of simple download operation + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 2) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct GNUNET_TIME_Absolute start; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_FS_Handle *fs; + +static struct GNUNET_FS_DownloadContext *download; + +static struct GNUNET_FS_PublishContext *publish; + +static GNUNET_SCHEDULER_TaskIdentifier timeout_kill; + +static char *fn; + +static int err; + +static void +timeout_kill_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout downloading file\n"); + if (download != NULL) + { + GNUNET_FS_download_stop (download, GNUNET_YES); + download = NULL; + } + else if (publish != NULL) + { + GNUNET_FS_publish_stop (publish); + publish = NULL; + } + timeout_kill = GNUNET_SCHEDULER_NO_TASK; + err = 1; +} + +static void +abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (publish != NULL) + { + GNUNET_FS_publish_stop (publish); + publish = NULL; + } +} + + +static void +abort_download_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + uint64_t size; + + if (download != NULL) + { + GNUNET_FS_download_stop (download, GNUNET_YES); + download = NULL; + } + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_size (fn, &size, GNUNET_YES)); + GNUNET_assert (size == FILESIZE); + GNUNET_DISK_directory_remove (fn); + GNUNET_free (fn); + fn = NULL; + GNUNET_SCHEDULER_cancel (timeout_kill); + timeout_kill = GNUNET_SCHEDULER_NO_TASK; +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); + + +static void +restart_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting FS.\n"); + GNUNET_FS_stop (fs); + fs = GNUNET_FS_start (cfg, "test-fs-download-persistence", &progress_cb, NULL, + GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); +} + + +/** + * Consider scheduling the restart-task. + * Only runs the restart task once per event + * category. + * + * @param ev type of the event to consider + */ +static void +consider_restart (int ev) +{ + static int prev[32]; + static int off; + int i; + + for (i = 0; i < off; i++) + if (prev[i] == ev) + return; + prev[off++] = ev; + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, + &restart_fs_task, NULL); +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + switch (event->status) + { + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: +#if VERBOSE + printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.publish.completed, + (unsigned long long) event->value.publish.size, + event->value.publish.specifics.progress.depth, + (unsigned long long) event->value.publish.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + printf ("Publishing complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024LL)); + fn = GNUNET_DISK_mktemp ("gnunet-download-test-dst"); + start = GNUNET_TIME_absolute_get (); + GNUNET_assert (download == NULL); + GNUNET_FS_download_start (fs, + event->value.publish.specifics.completed.chk_uri, + NULL, fn, NULL, 0, FILESIZE, 1, + GNUNET_FS_DOWNLOAD_OPTION_NONE, "download", NULL); + break; + case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: + consider_restart (event->status); + printf ("Download complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024LL)); + GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); + break; + case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: + consider_restart (event->status); + GNUNET_assert (download == event->value.download.dc); +#if VERBOSE + printf ("Download is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.download.completed, + (unsigned long long) event->value.download.size, + event->value.download.specifics.progress.depth, + (unsigned long long) event->value.download.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + FPRINTF (stderr, "Error publishing file: %s\n", + event->value.publish.specifics.error.message); + GNUNET_break (0); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_DOWNLOAD_ERROR: + FPRINTF (stderr, "Error downloading file: %s\n", + event->value.download.specifics.error.message); + GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); + break; + case GNUNET_FS_STATUS_PUBLISH_SUSPEND: + GNUNET_assert (event->value.publish.pc == publish); + publish = NULL; + break; + case GNUNET_FS_STATUS_PUBLISH_RESUME: + GNUNET_assert (NULL == publish); + publish = event->value.publish.pc; + break; + case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download suspended.\n"); + GNUNET_assert (event->value.download.dc == download); + download = NULL; + break; + case GNUNET_FS_STATUS_DOWNLOAD_RESUME: + GNUNET_assert (NULL == download); + download = event->value.download.dc; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download resumed.\n"); + break; + case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: + consider_restart (event->status); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download active.\n"); + break; + case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: + consider_restart (event->status); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download inactive.\n"); + break; + case GNUNET_FS_STATUS_PUBLISH_START: + GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); + GNUNET_assert (NULL == event->value.publish.pctx); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (1 == event->value.publish.anonymity); + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + GNUNET_assert (publish == event->value.publish.pc); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (1 == event->value.publish.anonymity); + GNUNET_FS_stop (fs); + fs = NULL; + break; + case GNUNET_FS_STATUS_DOWNLOAD_START: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download started.\n"); + consider_restart (event->status); + GNUNET_assert (download == NULL); + download = event->value.download.dc; + GNUNET_assert (0 == strcmp ("download", event->value.download.cctx)); + GNUNET_assert (NULL == event->value.download.pctx); + GNUNET_assert (NULL != event->value.download.uri); + GNUNET_assert (0 == strcmp (fn, event->value.download.filename)); + GNUNET_assert (FILESIZE == event->value.download.size); + GNUNET_assert (0 == event->value.download.completed); + GNUNET_assert (1 == event->value.download.anonymity); + break; + case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: + GNUNET_assert (download == event->value.download.dc); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + download = NULL; + break; + default: + printf ("Unexpected event: %d\n", event->status); + break; + } + return NULL; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + const char *keywords[] = { + "down_foo", + "down_bar", + }; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_FileInformation *fi; + size_t i; + struct GNUNET_FS_BlockOptions bo; + + cfg = c; + setup_peer (&p1, "test_fs_download_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-download-persistence", &progress_cb, NULL, + GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", + FILESIZE, buf, kuri, meta, + GNUNET_NO, &bo); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fi); + timeout_kill = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill_task, NULL); + start = GNUNET_TIME_absolute_get (); + publish = + GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + GNUNET_assert (publish != NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-download-persistence", + "-c", + "test_fs_download_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_log_setup ("test_fs_download_persistence", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-download/"); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-download-persistence", "nohelp", options, &run, + NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-download/"); + return err; +} + +/* 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 new file mode 100644 index 0000000..fb7de7d --- /dev/null +++ b/src/fs/test_fs_file_information.c @@ -0,0 +1,172 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_file_information.c + * @brief simple testcase for file_information operations + * @author Christian Grothoff + * + * TODO: + * - test that metatdata, etc. are all correct (for example, + * there is a known bug with dirname never being set that is + * not detected!) + * - need to iterate over file-information structure + * - other API functions may not yet be tested (such as + * filedata-from-callback) + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 2) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + + +static int +mycleaner (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, + struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, + struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) +{ + return GNUNET_OK; +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const char *keywords[] = { + "down_foo", + "down_bar", + }; + char *fn1; + char *fn2; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_FileInformation *fi1; + struct GNUNET_FS_FileInformation *fi2; + struct GNUNET_FS_FileInformation *fidir; + struct GNUNET_FS_Handle *fs; + size_t i; + struct GNUNET_FS_BlockOptions bo; + + fs = GNUNET_FS_start (cfg, "test-fs-file-information", NULL, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + fn1 = GNUNET_DISK_mktemp ("gnunet-file_information-test-dst"); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn1, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + + fn2 = GNUNET_DISK_mktemp ("gnunet-file_information-test-dst"); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn2, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + fi1 = + GNUNET_FS_file_information_create_from_file (fs, + "file_information-context1", + fn1, kuri, meta, GNUNET_YES, + &bo); + GNUNET_assert (fi1 != NULL); + fi2 = + GNUNET_FS_file_information_create_from_file (fs, + "file_information-context2", + fn2, kuri, meta, GNUNET_YES, + &bo); + GNUNET_assert (fi2 != NULL); + fidir = + GNUNET_FS_file_information_create_empty_directory (fs, + "file_information-context-dir", + kuri, meta, &bo, NULL); + GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); + GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fidir); + /* FIXME: test more of API! */ + GNUNET_FS_file_information_destroy (fidir, &mycleaner, NULL); + GNUNET_DISK_directory_remove (fn1); + GNUNET_DISK_directory_remove (fn2); + GNUNET_free_non_null (fn1); + GNUNET_free_non_null (fn2); + GNUNET_FS_stop (fs); +} + + + + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-file_information", + "-c", + "test_fs_file_information_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_file_information", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-file_information", "nohelp", options, &run, + NULL); + return 0; +} + +/* 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 new file mode 100644 index 0000000..09cedf8 --- /dev/null +++ b/src/fs/test_fs_file_information_data.conf @@ -0,0 +1,8 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-file-information/ +DEFAULTCONFIG = test_fs_file_information_data.conf + +[transport] +PLUGINS = + diff --git a/src/fs/test_fs_getopt.c b/src/fs/test_fs_getopt.c new file mode 100644 index 0000000..571346f --- /dev/null +++ b/src/fs/test_fs_getopt.c @@ -0,0 +1,40 @@ +/* + This file is part of GNUnet + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file fs/test_fs_getopt.c + * @brief test for fs_getopt.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_fs_service.h" + +int +main (int argc, char *argv[]) +{ + GNUNET_log_setup ("test_fs_directory", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + FPRINTF (stderr, "%s", "WARNING: testcase not yet written.\n"); + return 0; /* testcase passed */ +} diff --git a/src/fs/test_fs_list_indexed.c b/src/fs/test_fs_list_indexed.c new file mode 100644 index 0000000..535f8ef --- /dev/null +++ b/src/fs/test_fs_list_indexed.c @@ -0,0 +1,338 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_list_indexed.c + * @brief simple testcase for list_indexed operation (indexing, listing + * indexed) + * @author Christian Grothoff + * + * TODO: + * - actually call list_indexed API! + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 2) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct GNUNET_TIME_Absolute start; + +static struct GNUNET_FS_Handle *fs; + +static struct GNUNET_FS_PublishContext *publish; + +static char *fn1; + +static char *fn2; + +static int err; + +static void +abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_publish_stop (publish); + publish = NULL; + GNUNET_DISK_directory_remove (fn1); + GNUNET_free (fn1); + fn1 = NULL; + GNUNET_DISK_directory_remove (fn2); + GNUNET_free (fn2); + fn2 = NULL; +} + + +static void +list_indexed_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + void *ret; + + ret = NULL; + switch (event->status) + { + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + ret = event->value.publish.cctx; + printf ("Publish complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000 / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024)); + if (0 == strcmp ("list_indexed-context-dir", event->value.publish.cctx)) + GNUNET_SCHEDULER_add_continuation (&list_indexed_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + + break; + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: + ret = event->value.publish.cctx; + GNUNET_assert (publish == event->value.publish.pc); +#if VERBOSE + printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.publish.completed, + (unsigned long long) event->value.publish.size, + event->value.publish.specifics.progress.depth, + (unsigned long long) event->value.publish.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + ret = event->value.publish.cctx; + FPRINTF (stderr, "Error publishing file: %s\n", + event->value.publish.specifics.error.message); + err = 1; + if (0 == strcmp ("list_indexed-context-dir", event->value.publish.cctx)) + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_PUBLISH_START: + ret = event->value.publish.cctx; + if (0 == strcmp ("list_indexed-context1", event->value.publish.cctx)) + { + GNUNET_assert (0 == + strcmp ("list_indexed-context-dir", + event->value.publish.pctx)); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (1 == event->value.publish.anonymity); + } + else if (0 == strcmp ("list_indexed-context2", event->value.publish.cctx)) + { + GNUNET_assert (0 == + strcmp ("list_indexed-context-dir", + event->value.publish.pctx)); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (2 == event->value.publish.anonymity); + } + else if (0 == + strcmp ("list_indexed-context-dir", event->value.publish.cctx)) + { + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (3 == event->value.publish.anonymity); + } + else + GNUNET_assert (0); + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + if (0 == strcmp ("list_indexed-context-dir", event->value.publish.cctx)) + { + GNUNET_assert (publish == event->value.publish.pc); + publish = NULL; + } + break; + default: + printf ("Unexpected event: %d\n", event->status); + break; + } + return ret; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const char *keywords[] = { + "down_foo", + "down_bar", + }; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_FileInformation *fi1; + struct GNUNET_FS_FileInformation *fi2; + struct GNUNET_FS_FileInformation *fidir; + size_t i; + struct GNUNET_FS_BlockOptions bo; + + setup_peer (&p1, "test_fs_list_indexed_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-list_indexed", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + fn1 = GNUNET_DISK_mktemp ("gnunet-list_indexed-test-dst"); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn1, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + + fn2 = GNUNET_DISK_mktemp ("gnunet-list_indexed-test-dst"); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn2, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + fi1 = + GNUNET_FS_file_information_create_from_file (fs, "list_indexed-context1", + fn1, kuri, meta, GNUNET_YES, + &bo); + GNUNET_assert (NULL != fi1); + bo.anonymity_level = 2; + fi2 = + GNUNET_FS_file_information_create_from_file (fs, "list_indexed-context2", + fn2, kuri, meta, GNUNET_YES, + &bo); + GNUNET_assert (NULL != fi2); + bo.anonymity_level = 3; + fidir = + GNUNET_FS_file_information_create_empty_directory (fs, + "list_indexed-context-dir", + kuri, meta, &bo, NULL); + GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); + GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fidir); + start = GNUNET_TIME_absolute_get (); + publish = + GNUNET_FS_publish_start (fs, fidir, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + GNUNET_assert (publish != NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-list_indexed", + "-c", + "test_fs_list_indexed_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_list_indexed", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-list_indexed", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-list-indexed/"); + if (fn1 != NULL) + { + GNUNET_DISK_directory_remove (fn1); + GNUNET_free (fn1); + } + if (fn2 != NULL) + { + GNUNET_DISK_directory_remove (fn2); + GNUNET_free (fn2); + } + return err; +} + +/* 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 new file mode 100644 index 0000000..704ba4d --- /dev/null +++ b/src/fs/test_fs_list_indexed_data.conf @@ -0,0 +1,11 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-list-indexed/ +DEFAULTCONFIG = test_fs_list_indexed_data.conf + +[transport] +PLUGINS = + +[fs] +ACTIVEMIGRATION = NO + diff --git a/src/fs/test_fs_namespace.c b/src/fs/test_fs_namespace.c new file mode 100644 index 0000000..d25fd6f --- /dev/null +++ b/src/fs/test_fs_namespace.c @@ -0,0 +1,410 @@ +/* + This file is part of GNUnet. + (C) 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_namespace.c + * @brief Test for fs_namespace.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +static struct PeerContext p1; + +static GNUNET_HashCode nsid; + +static struct GNUNET_FS_Uri *sks_expect_uri; + +static struct GNUNET_FS_Uri *ksk_expect_uri; + +static struct GNUNET_FS_Handle *fs; + +static struct GNUNET_FS_SearchContext *sks_search; + +static struct GNUNET_FS_SearchContext *ksk_search; + +static GNUNET_SCHEDULER_TaskIdentifier kill_task; + +static int update_started; + +static int err; + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +abort_ksk_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (ksk_search != NULL) + { + GNUNET_FS_search_stop (ksk_search); + ksk_search = NULL; + if (sks_search == NULL) + { + GNUNET_FS_stop (fs); + if (GNUNET_SCHEDULER_NO_TASK != kill_task) + GNUNET_SCHEDULER_cancel (kill_task); + } + } +} + + +static void +abort_sks_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_Namespace *ns; + + if (sks_search == NULL) + return; + GNUNET_FS_search_stop (sks_search); + sks_search = NULL; + ns = GNUNET_FS_namespace_create (fs, "testNamespace"); + GNUNET_assert (NULL != ns); + GNUNET_assert (GNUNET_OK == GNUNET_FS_namespace_delete (ns, GNUNET_YES)); + if (ksk_search == NULL) + { + GNUNET_FS_stop (fs); + if (GNUNET_SCHEDULER_NO_TASK != kill_task) + GNUNET_SCHEDULER_cancel (kill_task); + } +} + + +static void +do_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + FPRINTF (stderr, "%s", "Operation timed out\n"); + kill_task = GNUNET_SCHEDULER_NO_TASK; + abort_sks_search_task (NULL, tc); + abort_ksk_search_task (NULL, tc); +} + + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + switch (event->status) + { + case GNUNET_FS_STATUS_SEARCH_RESULT: + if (sks_search == event->value.search.sc) + { + if (!GNUNET_FS_uri_test_equal + (sks_expect_uri, event->value.search.specifics.result.uri)) + { + FPRINTF (stderr, "%s", "Wrong result for sks search!\n"); + err = 1; + } + /* give system 1ms to initiate update search! */ + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, + &abort_sks_search_task, NULL); + } + else if (ksk_search == event->value.search.sc) + { + if (!GNUNET_FS_uri_test_equal + (ksk_expect_uri, event->value.search.specifics.result.uri)) + { + FPRINTF (stderr, "%s", "Wrong result for ksk search!\n"); + err = 1; + } + GNUNET_SCHEDULER_add_continuation (&abort_ksk_search_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + } + else + { + FPRINTF (stderr, "%s", "Unexpected search result received!\n"); + GNUNET_break (0); + } + break; + case GNUNET_FS_STATUS_SEARCH_ERROR: + FPRINTF (stderr, "Error searching file: %s\n", + event->value.search.specifics.error.message); + if (sks_search == event->value.search.sc) + GNUNET_SCHEDULER_add_continuation (&abort_sks_search_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + else if (ksk_search == event->value.search.sc) + GNUNET_SCHEDULER_add_continuation (&abort_ksk_search_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + else + GNUNET_break (0); + break; + case GNUNET_FS_STATUS_SEARCH_START: + GNUNET_assert ((NULL == event->value.search.cctx) || + (0 == strcmp ("sks_search", event->value.search.cctx)) || + (0 == strcmp ("ksk_search", event->value.search.cctx))); + if (NULL == event->value.search.cctx) + { + GNUNET_assert (0 == strcmp ("sks_search", event->value.search.pctx)); + update_started = GNUNET_YES; + } + GNUNET_assert (1 == event->value.search.anonymity); + break; + case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: + return NULL; + case GNUNET_FS_STATUS_SEARCH_STOPPED: + return NULL; + default: + FPRINTF (stderr, "Unexpected event: %d\n", event->status); + break; + } + return event->value.search.cctx; +} + + +static void +publish_cont (void *cls, const struct GNUNET_FS_Uri *ksk_uri, const char *emsg) +{ + char *msg; + struct GNUNET_FS_Uri *sks_uri; + char sbuf[1024]; + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + + if (NULL != emsg) + { + FPRINTF (stderr, "Error publishing: %s\n", emsg); + err = 1; + GNUNET_FS_stop (fs); + return; + } + GNUNET_CRYPTO_hash_to_enc (&nsid, &enc); + GNUNET_snprintf (sbuf, sizeof (sbuf), "gnunet://fs/sks/%s/this", &enc); + sks_uri = GNUNET_FS_uri_parse (sbuf, &msg); + if (NULL == sks_uri) + { + FPRINTF (stderr, "failed to parse URI `%s': %s\n", sbuf, msg); + err = 1; + GNUNET_FS_stop (fs); + GNUNET_free_non_null (msg); + return; + } + ksk_search = + GNUNET_FS_search_start (fs, ksk_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, + "ksk_search"); + sks_search = + GNUNET_FS_search_start (fs, sks_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, + "sks_search"); + GNUNET_FS_uri_destroy (sks_uri); +} + + +static void +sks_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) +{ + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *ksk_uri; + char *msg; + struct GNUNET_FS_BlockOptions bo; + + meta = GNUNET_CONTAINER_meta_data_create (); + msg = NULL; + ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/ns-search", &msg); + GNUNET_assert (NULL == msg); + ksk_expect_uri = GNUNET_FS_uri_dup (uri); + bo.content_priority = 1; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = + GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); + GNUNET_FS_publish_ksk (fs, ksk_uri, meta, uri, &bo, + GNUNET_FS_PUBLISH_OPTION_NONE, &publish_cont, NULL); + GNUNET_FS_uri_destroy (ksk_uri); + GNUNET_CONTAINER_meta_data_destroy (meta); +} + + +static void +adv_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) +{ + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Namespace *ns; + struct GNUNET_FS_BlockOptions bo; + + if (NULL != emsg) + { + FPRINTF (stderr, "Error publishing: %s\n", emsg); + err = 1; + GNUNET_FS_stop (fs); + return; + } + ns = GNUNET_FS_namespace_create (fs, "testNamespace"); + GNUNET_assert (NULL != ns); + meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_assert (NULL == emsg); + sks_expect_uri = GNUNET_FS_uri_dup (uri); + bo.content_priority = 1; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = + GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); + GNUNET_FS_publish_sks (fs, ns, "this", "next", meta, uri, /* FIXME: this is non-sense (use CHK URI!?) */ + &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont, NULL); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_FS_namespace_delete (ns, GNUNET_NO); +} + + +static void +ns_iterator (void *cls, const char *name, const GNUNET_HashCode * id) +{ + int *ok = cls; + + if (0 != strcmp (name, "testNamespace")) + return; + *ok = GNUNET_YES; + nsid = *id; +} + + +static void +testNamespace () +{ + struct GNUNET_FS_Namespace *ns; + struct GNUNET_FS_BlockOptions bo; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *ksk_uri; + int ok; + + ns = GNUNET_FS_namespace_create (fs, "testNamespace"); + GNUNET_assert (NULL != ns); + ok = GNUNET_NO; + GNUNET_FS_namespace_list (fs, &ns_iterator, &ok); + if (GNUNET_NO == ok) + { + FPRINTF (stderr, "%s", "namespace_list failed to find namespace!\n"); + GNUNET_FS_namespace_delete (ns, GNUNET_YES); + GNUNET_FS_stop (fs); + err = 1; + return; + } + meta = GNUNET_CONTAINER_meta_data_create (); + ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/testnsa", NULL); + bo.content_priority = 1; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = + GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); + GNUNET_FS_namespace_advertise (fs, ksk_uri, ns, meta, &bo, "root", &adv_cont, + NULL); + kill_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &do_timeout, + NULL); + GNUNET_FS_uri_destroy (ksk_uri); + GNUNET_FS_namespace_delete (ns, GNUNET_NO); + GNUNET_CONTAINER_meta_data_destroy (meta); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + setup_peer (&p1, "test_fs_namespace_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-namespace", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + testNamespace (); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-namespace", + "-c", + "test_fs_namespace_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_namespace", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-namespace", "nohelp", options, &run, NULL); + stop_arm (&p1); + if (GNUNET_YES != update_started) + { + FPRINTF (stderr, "%s", "Update search never started!\n"); + err = 1; + } + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-namespace/"); + return err; +} + + +/* end of test_fs_namespace.c */ diff --git a/src/fs/test_fs_namespace_data.conf b/src/fs/test_fs_namespace_data.conf new file mode 100644 index 0000000..3cdd241 --- /dev/null +++ b/src/fs/test_fs_namespace_data.conf @@ -0,0 +1,8 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-namespace/ +DEFAULTCONFIG = test_fs_namespace_data.conf + +[transport] +PLUGINS = + diff --git a/src/fs/test_fs_namespace_list_updateable.c b/src/fs/test_fs_namespace_list_updateable.c new file mode 100644 index 0000000..44775ac --- /dev/null +++ b/src/fs/test_fs_namespace_list_updateable.c @@ -0,0 +1,244 @@ +/* + This file is part of GNUnet. + (C) 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_namespace_list_updateable.c + * @brief Test for fs_namespace_list_updateable.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +static struct PeerContext p1; + +static struct GNUNET_FS_Handle *fs; + +static int err; + +static struct GNUNET_FS_Namespace *ns; + +static struct GNUNET_CONTAINER_MetaData *meta; + +static struct GNUNET_FS_Uri *uri_this; + +static struct GNUNET_FS_Uri *uri_next; + +static struct GNUNET_FS_BlockOptions bo; + + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + return NULL; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + if (uri_this != NULL) + GNUNET_FS_uri_destroy (uri_this); + if (uri_next != NULL) + GNUNET_FS_uri_destroy (uri_next); + if (ns != NULL) + GNUNET_FS_namespace_delete (ns, GNUNET_NO); + if (meta != NULL) + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + + +static void +check_next (void *cls, const char *last_id, + const struct GNUNET_FS_Uri *last_uri, + const struct GNUNET_CONTAINER_MetaData *last_meta, + const char *next_id) +{ + GNUNET_break (0 == strcmp (last_id, "next")); + GNUNET_break (0 == strcmp (next_id, "future")); + err -= 4; +} + + +static void +check_this_next (void *cls, const char *last_id, + const struct GNUNET_FS_Uri *last_uri, + const struct GNUNET_CONTAINER_MetaData *last_meta, + const char *next_id) +{ + GNUNET_break (0 == strcmp (last_id, "this")); + GNUNET_break (0 == strcmp (next_id, "next")); + err -= 2; + err += 4; + GNUNET_FS_namespace_list_updateable (ns, next_id, &check_next, NULL); +} + + +static void +sks_cont_next (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) +{ + GNUNET_assert (NULL == emsg); + err += 2; + GNUNET_FS_namespace_list_updateable (ns, NULL, &check_this_next, NULL); + +} + + +static void +check_this (void *cls, const char *last_id, + const struct GNUNET_FS_Uri *last_uri, + const struct GNUNET_CONTAINER_MetaData *last_meta, + const char *next_id) +{ + GNUNET_break (0 == strcmp (last_id, "this")); + GNUNET_break (0 == strcmp (next_id, "next")); + err -= 1; +} + + +static void +sks_cont_this (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) +{ + + GNUNET_assert (NULL == emsg); + err = 1; + GNUNET_FS_namespace_list_updateable (ns, NULL, &check_this, NULL); + GNUNET_FS_publish_sks (fs, ns, "next", "future", meta, uri_next, &bo, + GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont_next, NULL); + +} + + + +static void +testNamespace () +{ + + ns = GNUNET_FS_namespace_create (fs, "testNamespace"); + GNUNET_assert (NULL != ns); + bo.content_priority = 1; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = + GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); + meta = GNUNET_CONTAINER_meta_data_create (); + + uri_this = + GNUNET_FS_uri_parse + ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42", + NULL); + uri_next = + GNUNET_FS_uri_parse + ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.43", + NULL); + GNUNET_FS_publish_sks (fs, ns, "this", "next", meta, uri_this, &bo, + GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont_this, NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + setup_peer (&p1, "test_fs_namespace_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-namespace", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + testNamespace (); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-namespace", + "-c", + "test_fs_namespace_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_namespace_list_updateable", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-namespace", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-namespace/"); + return err; +} + + +/* end of test_fs_namespace_list_updateable.c */ diff --git a/src/fs/test_fs_publish.c b/src/fs/test_fs_publish.c new file mode 100644 index 0000000..e527438 --- /dev/null +++ b/src/fs/test_fs_publish.c @@ -0,0 +1,323 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_publish.c + * @brief simple testcase for publish operation (indexing, listing + * indexed, directory structure) + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 2) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct GNUNET_TIME_Absolute start; + +static struct GNUNET_FS_Handle *fs; + +static struct GNUNET_FS_PublishContext *publish; + +static char *fn1; + +static char *fn2; + +static int err; + +static void +abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_publish_stop (publish); + publish = NULL; + GNUNET_DISK_directory_remove (fn1); + GNUNET_free (fn1); + fn1 = NULL; + GNUNET_DISK_directory_remove (fn2); + GNUNET_free (fn2); + fn2 = NULL; +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + void *ret; + + ret = NULL; + switch (event->status) + { + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + ret = event->value.publish.cctx; + printf ("Publish complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000 / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024)); + if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: + ret = event->value.publish.cctx; + GNUNET_assert (publish == event->value.publish.pc); +#if VERBOSE + printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.publish.completed, + (unsigned long long) event->value.publish.size, + event->value.publish.specifics.progress.depth, + (unsigned long long) event->value.publish.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + ret = event->value.publish.cctx; + FPRINTF (stderr, "Error publishing file: %s\n", + event->value.publish.specifics.error.message); + err = 1; + if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) + { + FPRINTF (stderr, "Scheduling abort task for error on `%s'\n", + (const char *) event->value.publish.cctx); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + } + break; + case GNUNET_FS_STATUS_PUBLISH_START: + ret = event->value.publish.cctx; + if (0 == strcmp ("publish-context1", event->value.publish.cctx)) + { + GNUNET_assert (0 == + strcmp ("publish-context-dir", event->value.publish.pctx)); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (1 == event->value.publish.anonymity); + } + else if (0 == strcmp ("publish-context2", event->value.publish.cctx)) + { + GNUNET_assert (0 == + strcmp ("publish-context-dir", event->value.publish.pctx)); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (2 == event->value.publish.anonymity); + } + else if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) + { + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (3 == event->value.publish.anonymity); + } + else + GNUNET_assert (0); + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) + GNUNET_assert (publish == event->value.publish.pc); + break; + default: + printf ("Unexpected event: %d\n", event->status); + break; + } + return ret; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const char *keywords[] = { + "down_foo", + "down_bar", + }; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_FileInformation *fi1; + struct GNUNET_FS_FileInformation *fi2; + struct GNUNET_FS_FileInformation *fidir; + size_t i; + struct GNUNET_FS_BlockOptions bo; + + setup_peer (&p1, "test_fs_publish_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-publish", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + fn1 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn1, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + + fn2 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn2, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + + fi1 = + GNUNET_FS_file_information_create_from_file (fs, "publish-context1", fn1, + kuri, meta, GNUNET_YES, &bo); + + GNUNET_assert (NULL != fi1); + bo.anonymity_level = 2; + fi2 = + GNUNET_FS_file_information_create_from_file (fs, "publish-context2", fn2, + kuri, meta, GNUNET_YES, &bo); + GNUNET_assert (NULL != fi2); + bo.anonymity_level = 3; + fidir = + GNUNET_FS_file_information_create_empty_directory (fs, + "publish-context-dir", + kuri, meta, &bo, NULL); + GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); + GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fidir); + start = GNUNET_TIME_absolute_get (); + publish = + GNUNET_FS_publish_start (fs, fidir, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + GNUNET_assert (publish != NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-publish", + "-c", + "test_fs_publish_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_publish", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-publish", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-publish/"); + if (fn1 != NULL) + { + GNUNET_DISK_directory_remove (fn1); + GNUNET_free (fn1); + } + if (fn2 != NULL) + { + GNUNET_DISK_directory_remove (fn2); + GNUNET_free (fn2); + } + return err; +} + +/* end of test_fs_publish.c */ diff --git a/src/fs/test_fs_publish_data.conf b/src/fs/test_fs_publish_data.conf new file mode 100644 index 0000000..234f2b0 --- /dev/null +++ b/src/fs/test_fs_publish_data.conf @@ -0,0 +1,11 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-publish/ +DEFAULTCONFIG = test_fs_publish_data.conf + +[transport] +PLUGINS = + +[fs] +ACTIVEMIGRATION = NO + diff --git a/src/fs/test_fs_publish_persistence.c b/src/fs/test_fs_publish_persistence.c new file mode 100644 index 0000000..7707eac --- /dev/null +++ b/src/fs/test_fs_publish_persistence.c @@ -0,0 +1,384 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_publish_persistence.c + * @brief simple testcase for persistence of simple publish operation + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 2) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct GNUNET_TIME_Absolute start; + +static struct GNUNET_FS_Handle *fs; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_FS_PublishContext *publish; + +static struct GNUNET_FS_PublishContext *publish; + +static char *fn1; + +static char *fn2; + +static int err; + +static GNUNET_SCHEDULER_TaskIdentifier rtask; + +static void +abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_publish_stop (publish); + publish = NULL; + GNUNET_DISK_directory_remove (fn1); + GNUNET_free (fn1); + fn1 = NULL; + GNUNET_DISK_directory_remove (fn2); + GNUNET_free (fn2); + fn2 = NULL; + GNUNET_FS_stop (fs); + fs = NULL; + if (GNUNET_SCHEDULER_NO_TASK != rtask) + { + GNUNET_SCHEDULER_cancel (rtask); + rtask = GNUNET_SCHEDULER_NO_TASK; + } +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); + + +static void +restart_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + rtask = GNUNET_SCHEDULER_NO_TASK; + GNUNET_FS_stop (fs); + fs = GNUNET_FS_start (cfg, "test-fs-publish-persistence", &progress_cb, NULL, + GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); +} + + +/** + * Consider scheduling the restart-task. + * Only runs the restart task once per event + * category. + * + * @param ev type of the event to consider + */ +static void +consider_restart (int ev) +{ + static int prev[32]; + static int off; + int i; + + for (i = 0; i < off; i++) + if (prev[i] == ev) + return; + prev[off++] = ev; + rtask = + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, + &restart_fs_task, NULL); +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + void *ret; + + ret = NULL; + switch (event->status) + { + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + consider_restart (event->status); + ret = event->value.publish.cctx; + printf ("Publish complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000LL / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024)); + if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) + GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); + break; + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: + consider_restart (event->status); + ret = event->value.publish.cctx; + GNUNET_assert (publish == event->value.publish.pc); +#if VERBOSE + printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.publish.completed, + (unsigned long long) event->value.publish.size, + event->value.publish.specifics.progress.depth, + (unsigned long long) event->value.publish.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_SUSPEND: + if (event->value.publish.pc == publish) + publish = NULL; + break; + case GNUNET_FS_STATUS_PUBLISH_RESUME: + if (NULL == publish) + { + GNUNET_assert (GNUNET_YES == + GNUNET_FS_file_information_is_directory (event-> + value.publish. + fi)); + publish = event->value.publish.pc; + return "publish-context-dir"; + } + break; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + ret = event->value.publish.cctx; + FPRINTF (stderr, "Error publishing file: %s\n", + event->value.publish.specifics.error.message); + err = 1; + GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); + break; + case GNUNET_FS_STATUS_PUBLISH_START: + consider_restart (event->status); + publish = event->value.publish.pc; + ret = event->value.publish.cctx; + if (0 == strcmp ("publish-context1", event->value.publish.cctx)) + { + GNUNET_assert (0 == + strcmp ("publish-context-dir", event->value.publish.pctx)); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (1 == event->value.publish.anonymity); + } + else if (0 == strcmp ("publish-context2", event->value.publish.cctx)) + { + GNUNET_assert (0 == + strcmp ("publish-context-dir", event->value.publish.pctx)); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (2 == event->value.publish.anonymity); + } + else if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) + { + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (3 == event->value.publish.anonymity); + } + else + GNUNET_assert (0); + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + consider_restart (event->status); + if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) + GNUNET_assert (publish == event->value.publish.pc); + break; + default: + printf ("Unexpected event: %d\n", event->status); + break; + } + return ret; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + const char *keywords[] = { + "down_foo", + "down_bar", + }; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_FileInformation *fi1; + struct GNUNET_FS_FileInformation *fi2; + struct GNUNET_FS_FileInformation *fidir; + size_t i; + struct GNUNET_FS_BlockOptions bo; + + cfg = c; + setup_peer (&p1, "test_fs_publish_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-publish-persistence", &progress_cb, NULL, + GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + fn1 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn1, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + + fn2 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn2, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + fi1 = + GNUNET_FS_file_information_create_from_file (fs, "publish-context1", fn1, + kuri, meta, GNUNET_YES, &bo); + GNUNET_assert (NULL != fi1); + bo.anonymity_level = 2; + fi2 = + GNUNET_FS_file_information_create_from_file (fs, "publish-context2", fn2, + kuri, meta, GNUNET_YES, &bo); + GNUNET_assert (NULL != fi2); + bo.anonymity_level = 3; + fidir = + GNUNET_FS_file_information_create_empty_directory (fs, + "publish-context-dir", + kuri, meta, &bo, NULL); + GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); + GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fidir); + start = GNUNET_TIME_absolute_get (); + GNUNET_FS_publish_start (fs, fidir, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + GNUNET_assert (publish != NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-publish-persistence", + "-c", + "test_fs_publish_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_publish_persistence", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-publish", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-publish/"); + if (fn1 != NULL) + { + GNUNET_DISK_directory_remove (fn1); + GNUNET_free (fn1); + } + if (fn2 != NULL) + { + GNUNET_DISK_directory_remove (fn2); + GNUNET_free (fn2); + } + return err; +} + +/* end of test_fs_publish_persistence.c */ diff --git a/src/fs/test_fs_search.c b/src/fs/test_fs_search.c new file mode 100644 index 0000000..f6c8f00 --- /dev/null +++ b/src/fs/test_fs_search.c @@ -0,0 +1,280 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_search.c + * @brief simple testcase for simple publish + search operation + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * File-size we use for testing. + */ +#define FILESIZE 1024 + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_PeerIdentity id; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct GNUNET_TIME_Absolute start; + +static struct GNUNET_FS_Handle *fs; + +static struct GNUNET_FS_SearchContext *search; + +static struct GNUNET_FS_PublishContext *publish; + + +static void +abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_publish_stop (publish); + publish = NULL; +} + + +static void +abort_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (search != NULL) + GNUNET_FS_search_stop (search); + search = NULL; +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + const char *keywords[] = { + "down_foo" + }; + struct GNUNET_FS_Uri *kuri; + + switch (event->status) + { + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: +#if VERBOSE + printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.publish.completed, + (unsigned long long) event->value.publish.size, + event->value.publish.specifics.progress.depth, + (unsigned long long) event->value.publish.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + kuri = GNUNET_FS_uri_ksk_create_from_args (1, keywords); + start = GNUNET_TIME_absolute_get (); + search = + GNUNET_FS_search_start (fs, kuri, 1, GNUNET_FS_SEARCH_OPTION_NONE, + "search"); + GNUNET_FS_uri_destroy (kuri); + GNUNET_assert (search != NULL); + break; + case GNUNET_FS_STATUS_SEARCH_RESULT: +#if VERBOSE + printf ("Search complete.\n"); +#endif + GNUNET_SCHEDULER_add_continuation (&abort_search_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + FPRINTF (stderr, "Error publishing file: %s\n", + event->value.publish.specifics.error.message); + GNUNET_break (0); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_SEARCH_ERROR: + FPRINTF (stderr, "Error searching file: %s\n", + event->value.search.specifics.error.message); + GNUNET_SCHEDULER_add_continuation (&abort_search_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_PUBLISH_START: + GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); + GNUNET_assert (NULL == event->value.publish.pctx); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (1 == event->value.publish.anonymity); + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + GNUNET_assert (publish == event->value.publish.pc); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (1 == event->value.publish.anonymity); + GNUNET_FS_stop (fs); + fs = NULL; + break; + case GNUNET_FS_STATUS_SEARCH_START: + GNUNET_assert (search == NULL); + GNUNET_assert (0 == strcmp ("search", event->value.search.cctx)); + GNUNET_assert (1 == event->value.search.anonymity); + break; + case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: + break; + case GNUNET_FS_STATUS_SEARCH_STOPPED: + GNUNET_assert (search == event->value.search.sc); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + default: + FPRINTF (stderr, "Unexpected event: %d\n", event->status); + break; + } + return NULL; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const char *keywords[] = { + "down_foo", + "down_bar" + }; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_BlockOptions bo; + struct GNUNET_FS_FileInformation *fi; + size_t i; + + setup_peer (&p1, "test_fs_search_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-search", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", + FILESIZE, buf, kuri, meta, + GNUNET_NO, &bo); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fi); + start = GNUNET_TIME_absolute_get (); + publish = + GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + GNUNET_assert (publish != NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-search", + "-c", + "test_fs_search_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_search", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-search", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-search/"); + return 0; +} + +/* end of test_fs_search.c */ diff --git a/src/fs/test_fs_search_data.conf b/src/fs/test_fs_search_data.conf new file mode 100644 index 0000000..ea5e4c5 --- /dev/null +++ b/src/fs/test_fs_search_data.conf @@ -0,0 +1,8 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-search/ +DEFAULTCONFIG = test_fs_search_data.conf + +[transport] +PLUGINS = + diff --git a/src/fs/test_fs_search_persistence.c b/src/fs/test_fs_search_persistence.c new file mode 100644 index 0000000..38f88a8 --- /dev/null +++ b/src/fs/test_fs_search_persistence.c @@ -0,0 +1,345 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_search_persistence.c + * @brief simple testcase for persistence of search operation + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * File-size we use for testing. + */ +#define FILESIZE 1024 + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_PeerIdentity id; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct GNUNET_TIME_Absolute start; + +static struct GNUNET_FS_Handle *fs; + +static struct GNUNET_FS_SearchContext *search; + +static struct GNUNET_FS_PublishContext *publish; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static void +abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_publish_stop (publish); + publish = NULL; +} + + +static void +abort_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (search != NULL) + GNUNET_FS_search_stop (search); + search = NULL; +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); + + +static void +restart_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_stop (fs); + fs = GNUNET_FS_start (cfg, "test-fs-search-persistence", &progress_cb, NULL, + GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); +} + + + + +/** + * Consider scheduling the restart-task. + * Only runs the restart task once per event + * category. + * + * @param ev type of the event to consider + */ +static void +consider_restart (int ev) +{ + static int prev[32]; + static int off; + int i; + + for (i = 0; i < off; i++) + if (prev[i] == ev) + return; + prev[off++] = ev; + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, + &restart_fs_task, NULL); +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + const char *keywords[] = { + "down_foo" + }; + struct GNUNET_FS_Uri *kuri; + + switch (event->status) + { + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: +#if VERBOSE + printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.publish.completed, + (unsigned long long) event->value.publish.size, + event->value.publish.specifics.progress.depth, + (unsigned long long) event->value.publish.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + kuri = GNUNET_FS_uri_ksk_create_from_args (1, keywords); + start = GNUNET_TIME_absolute_get (); + GNUNET_FS_search_start (fs, kuri, 1, GNUNET_FS_SEARCH_OPTION_NONE, + "search"); + GNUNET_FS_uri_destroy (kuri); + GNUNET_assert (search != NULL); + break; + case GNUNET_FS_STATUS_PUBLISH_SUSPEND: + if (event->value.publish.pc == publish) + publish = NULL; + break; + case GNUNET_FS_STATUS_PUBLISH_RESUME: + if (NULL == publish) + publish = event->value.publish.pc; + break; + case GNUNET_FS_STATUS_SEARCH_RESULT: + /* FIXME: consider_restart (event->status); cannot be tested with + * search result since we exit here after the first one... */ +#if VERBOSE + printf ("Search complete.\n"); +#endif + GNUNET_SCHEDULER_add_continuation (&abort_search_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + FPRINTF (stderr, "Error publishing file: %s\n", + event->value.publish.specifics.error.message); + GNUNET_break (0); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_SEARCH_ERROR: + FPRINTF (stderr, "Error searching file: %s\n", + event->value.search.specifics.error.message); + GNUNET_SCHEDULER_add_continuation (&abort_search_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_SEARCH_SUSPEND: + if (event->value.search.sc == search) + search = NULL; + break; + case GNUNET_FS_STATUS_SEARCH_RESUME: + if (NULL == search) + { + search = event->value.search.sc; + return "search"; + } + break; + case GNUNET_FS_STATUS_PUBLISH_START: + GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); + GNUNET_assert (NULL == event->value.publish.pctx); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (1 == event->value.publish.anonymity); + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + GNUNET_assert (publish == event->value.publish.pc); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (1 == event->value.publish.anonymity); + GNUNET_FS_stop (fs); + fs = NULL; + break; + case GNUNET_FS_STATUS_SEARCH_START: + consider_restart (event->status); + GNUNET_assert (search == NULL); + search = event->value.search.sc; + GNUNET_assert (0 == strcmp ("search", event->value.search.cctx)); + GNUNET_assert (1 == event->value.search.anonymity); + break; + case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: + break; + case GNUNET_FS_STATUS_SEARCH_STOPPED: + GNUNET_assert (search == event->value.search.sc); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + search = NULL; + break; + default: + FPRINTF (stderr, "Unexpected event: %d\n", event->status); + break; + } + return NULL; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + const char *keywords[] = { + "down_foo", + "down_bar" + }; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_FileInformation *fi; + size_t i; + struct GNUNET_FS_BlockOptions bo; + + cfg = c; + setup_peer (&p1, "test_fs_search_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-search-persistence", &progress_cb, NULL, + GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", + FILESIZE, buf, kuri, meta, + GNUNET_NO, &bo); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fi); + start = GNUNET_TIME_absolute_get (); + publish = + GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + GNUNET_assert (publish != NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-search-persistence", + "-c", + "test_fs_search_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-search/"); + GNUNET_log_setup ("test_fs_search_persistence", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-search-persistence", "nohelp", options, &run, + NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-search/"); + return 0; +} + +/* end of test_fs_search_persistence.c */ diff --git a/src/fs/test_fs_start_stop.c b/src/fs/test_fs_start_stop.c new file mode 100644 index 0000000..0ef0723 --- /dev/null +++ b/src/fs/test_fs_start_stop.c @@ -0,0 +1,135 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_start_stop.c + * @brief testcase for fs.c (start-stop only) + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +static struct PeerContext p1; + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + return NULL; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_FS_Handle *fs; + + setup_peer (&p1, "test_fs_data.conf"); + fs = GNUNET_FS_start (cfg, "test-fs-start-stop", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + GNUNET_FS_stop (fs); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-start-stop", + "-c", + "test_fs_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_start_stop", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-start-stop", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs/"); + return 0; +} + +/* 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 new file mode 100644 index 0000000..589abb3 --- /dev/null +++ b/src/fs/test_fs_test_lib.c @@ -0,0 +1,164 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_test_lib.c + * @brief test fs test library + * @author Christian Grothoff + */ +#include "platform.h" +#include "fs_test_lib.h" + +#define VERBOSE GNUNET_NO + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 2) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define NUM_DAEMONS 2 + +#define SEED 42 + +static struct GNUNET_FS_TestDaemon *daemons[NUM_DAEMONS]; + +static struct GNUNET_FS_TEST_ConnectContext *cc; + +static int ret; + +static void +do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != cc) + { + GNUNET_FS_TEST_daemons_connect_cancel (cc); + cc = NULL; + } + if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + GNUNET_break (0); + ret = 1; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished download, shutting down\n", + (unsigned long long) FILESIZE); + } + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); +} + + +static void +do_download (void *cls, const struct GNUNET_FS_Uri *uri) +{ + if (NULL == uri) + { + GNUNET_break (0); + GNUNET_SCHEDULER_add_now (&do_stop, NULL); + ret = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", + (unsigned long long) FILESIZE); + GNUNET_FS_TEST_download (daemons[0], TIMEOUT, 1, SEED, uri, VERBOSE, &do_stop, + NULL); +} + + +static void +do_publish (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + cc = NULL; + if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + GNUNET_break (0); + ret = 1; + GNUNET_SCHEDULER_add_now (&do_stop, NULL); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", + (unsigned long long) FILESIZE); + GNUNET_FS_TEST_publish (daemons[0], TIMEOUT, 1, GNUNET_NO, FILESIZE, SEED, + VERBOSE, &do_download, NULL); +} + + +static void +do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + GNUNET_break (0); + ret = 1; + GNUNET_SCHEDULER_add_now (&do_stop, NULL); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Daemons started, will now try to connect them\n"); + cc = GNUNET_FS_TEST_daemons_connect (daemons[0], daemons[1], TIMEOUT, + &do_publish, NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_FS_TEST_daemons_start ("fs_test_lib_data.conf", TIMEOUT, NUM_DAEMONS, + daemons, &do_connect, NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-test-lib", + "-c", + "fs_test_lib_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); + GNUNET_log_setup ("test_fs_test_lib", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-test-lib", "nohelp", options, &run, NULL); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); + return ret; +} + +/* end of test_fs_test_lib.c */ diff --git a/src/fs/test_fs_unindex.c b/src/fs/test_fs_unindex.c new file mode 100644 index 0000000..a8b68a3 --- /dev/null +++ b/src/fs/test_fs_unindex.c @@ -0,0 +1,304 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_unindex.c + * @brief simple testcase for simple publish + unindex operation + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 2) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct GNUNET_TIME_Absolute start; + +static struct GNUNET_FS_Handle *fs; + +static struct GNUNET_FS_UnindexContext *unindex; + +static struct GNUNET_FS_PublishContext *publish; + +static char *fn; + + +static void +abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_publish_stop (publish); + publish = NULL; +} + + +static void +abort_unindex_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_unindex_stop (unindex); + unindex = NULL; + GNUNET_DISK_directory_remove (fn); + GNUNET_free (fn); + fn = NULL; +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + + switch (event->status) + { + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: +#if VERBOSE + printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.publish.completed, + (unsigned long long) event->value.publish.size, + event->value.publish.specifics.progress.depth, + (unsigned long long) event->value.publish.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + printf ("Publishing complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000 / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024)); + start = GNUNET_TIME_absolute_get (); + unindex = GNUNET_FS_unindex_start (fs, fn, "unindex"); + GNUNET_assert (unindex != NULL); + break; + case GNUNET_FS_STATUS_UNINDEX_COMPLETED: + printf ("Unindex complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000 / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024)); + GNUNET_SCHEDULER_add_continuation (&abort_unindex_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_UNINDEX_PROGRESS: + GNUNET_assert (unindex == event->value.unindex.uc); +#if VERBOSE + printf ("Unindex is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.unindex.completed, + (unsigned long long) event->value.unindex.size, + event->value.unindex.specifics.progress.depth, + (unsigned long long) event->value.unindex.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + FPRINTF (stderr, "Error publishing file: %s\n", + event->value.publish.specifics.error.message); + GNUNET_break (0); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_UNINDEX_ERROR: + FPRINTF (stderr, "Error unindexing file: %s\n", + event->value.unindex.specifics.error.message); + GNUNET_SCHEDULER_add_continuation (&abort_unindex_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_PUBLISH_START: + GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); + GNUNET_assert (NULL == event->value.publish.pctx); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (1 == event->value.publish.anonymity); + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + GNUNET_assert (publish == event->value.publish.pc); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (1 == event->value.publish.anonymity); + GNUNET_FS_stop (fs); + fs = NULL; + break; + case GNUNET_FS_STATUS_UNINDEX_START: + GNUNET_assert (unindex == NULL); + GNUNET_assert (0 == strcmp ("unindex", event->value.unindex.cctx)); + GNUNET_assert (0 == strcmp (fn, event->value.unindex.filename)); + GNUNET_assert (FILESIZE == event->value.unindex.size); + GNUNET_assert (0 == event->value.unindex.completed); + break; + case GNUNET_FS_STATUS_UNINDEX_STOPPED: + GNUNET_assert (unindex == event->value.unindex.uc); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + default: + printf ("Unexpected event: %d\n", event->status); + break; + } + return NULL; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const char *keywords[] = { + "down_foo", + "down_bar", + }; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_FileInformation *fi; + size_t i; + struct GNUNET_FS_BlockOptions bo; + + setup_peer (&p1, "test_fs_unindex_data.conf"); + fn = GNUNET_DISK_mktemp ("gnunet-unindex-test-dst"); + fs = GNUNET_FS_start (cfg, "test-fs-unindex", &progress_cb, NULL, + GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + fi = GNUNET_FS_file_information_create_from_file (fs, "publish-context", fn, + kuri, meta, GNUNET_YES, + &bo); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fi); + start = GNUNET_TIME_absolute_get (); + publish = + GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + GNUNET_assert (publish != NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-unindex", + "-c", + "test_fs_unindex_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_unindex", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-unindex", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-unindex/"); + if (NULL != fn) + { + GNUNET_DISK_directory_remove (fn); + GNUNET_free (fn); + } + return 0; +} + +/* end of test_fs_unindex.c */ diff --git a/src/fs/test_fs_unindex_data.conf b/src/fs/test_fs_unindex_data.conf new file mode 100644 index 0000000..977d6e7 --- /dev/null +++ b/src/fs/test_fs_unindex_data.conf @@ -0,0 +1,8 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-unindex/ +DEFAULTCONFIG = test_fs_unindex_data.conf + +[transport] +PLUGINS = + diff --git a/src/fs/test_fs_unindex_persistence.c b/src/fs/test_fs_unindex_persistence.c new file mode 100644 index 0000000..575e171 --- /dev/null +++ b/src/fs/test_fs_unindex_persistence.c @@ -0,0 +1,367 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_unindex_persistence.c + * @brief simple testcase for simple publish + unindex operation + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_fs_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 2) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long should our test-content live? + */ +#define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct GNUNET_TIME_Absolute start; + +static struct GNUNET_FS_Handle *fs; + +static struct GNUNET_FS_UnindexContext *unindex; + +static struct GNUNET_FS_PublishContext *publish; + +static char *fn; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static void +abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_publish_stop (publish); + publish = NULL; +} + + +static void +abort_unindex_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (unindex != NULL) + { + GNUNET_FS_unindex_stop (unindex); + unindex = NULL; + } + if (fn != NULL) + { + GNUNET_DISK_directory_remove (fn); + GNUNET_free (fn); + fn = NULL; + } +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); + + +static void +restart_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_FS_stop (fs); + fs = GNUNET_FS_start (cfg, "test-fs-unindex-persistence", &progress_cb, NULL, + GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); +} + + +/** + * Consider scheduling the restart-task. + * Only runs the restart task once per event + * category. + * + * @param ev type of the event to consider + */ +static void +consider_restart (int ev) +{ + static int prev[32]; + static int off; + int i; + + for (i = 0; i < off; i++) + if (prev[i] == ev) + return; + prev[off++] = ev; + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, + &restart_fs_task, NULL); +} + + +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) +{ + switch (event->status) + { + case GNUNET_FS_STATUS_PUBLISH_PROGRESS: +#if VERBOSE + printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.publish.completed, + (unsigned long long) event->value.publish.size, + event->value.publish.specifics.progress.depth, + (unsigned long long) event->value.publish.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_COMPLETED: + printf ("Publishing complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000 / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024)); + start = GNUNET_TIME_absolute_get (); + unindex = GNUNET_FS_unindex_start (fs, fn, "unindex"); + GNUNET_assert (unindex != NULL); + break; + case GNUNET_FS_STATUS_UNINDEX_COMPLETED: + printf ("Unindex complete, %llu kbps.\n", + (unsigned long long) (FILESIZE * 1000 / + (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value) / 1024)); + GNUNET_SCHEDULER_add_continuation (&abort_unindex_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_UNINDEX_PROGRESS: + consider_restart (event->status); + GNUNET_assert (unindex == event->value.unindex.uc); +#if VERBOSE + printf ("Unindex is progressing (%llu/%llu at level %u off %llu)...\n", + (unsigned long long) event->value.unindex.completed, + (unsigned long long) event->value.unindex.size, + event->value.unindex.specifics.progress.depth, + (unsigned long long) event->value.unindex.specifics. + progress.offset); +#endif + break; + case GNUNET_FS_STATUS_PUBLISH_SUSPEND: + if (event->value.publish.pc == publish) + publish = NULL; + break; + case GNUNET_FS_STATUS_PUBLISH_RESUME: + if (NULL == publish) + { + publish = event->value.publish.pc; + return "publish-context"; + } + break; + case GNUNET_FS_STATUS_UNINDEX_SUSPEND: + GNUNET_assert (event->value.unindex.uc == unindex); + unindex = NULL; + break; + case GNUNET_FS_STATUS_UNINDEX_RESUME: + GNUNET_assert (NULL == unindex); + unindex = event->value.unindex.uc; + return "unindex"; + case GNUNET_FS_STATUS_PUBLISH_ERROR: + FPRINTF (stderr, "Error publishing file: %s\n", + event->value.publish.specifics.error.message); + GNUNET_break (0); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_UNINDEX_ERROR: + FPRINTF (stderr, "Error unindexing file: %s\n", + event->value.unindex.specifics.error.message); + GNUNET_SCHEDULER_add_continuation (&abort_unindex_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + case GNUNET_FS_STATUS_PUBLISH_START: + GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); + GNUNET_assert (NULL == event->value.publish.pctx); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (0 == event->value.publish.completed); + GNUNET_assert (1 == event->value.publish.anonymity); + break; + case GNUNET_FS_STATUS_PUBLISH_STOPPED: + GNUNET_assert (publish == event->value.publish.pc); + GNUNET_assert (FILESIZE == event->value.publish.size); + GNUNET_assert (1 == event->value.publish.anonymity); + GNUNET_FS_stop (fs); + fs = NULL; + break; + case GNUNET_FS_STATUS_UNINDEX_START: + consider_restart (event->status); + GNUNET_assert (unindex == NULL); + GNUNET_assert (0 == strcmp ("unindex", event->value.unindex.cctx)); + GNUNET_assert (0 == strcmp (fn, event->value.unindex.filename)); + GNUNET_assert (FILESIZE == event->value.unindex.size); + GNUNET_assert (0 == event->value.unindex.completed); + break; + case GNUNET_FS_STATUS_UNINDEX_STOPPED: + GNUNET_assert (unindex == event->value.unindex.uc); + GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + break; + default: + printf ("Unexpected event: %d\n", event->status); + break; + } + return NULL; +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + const char *keywords[] = { + "down_foo", + "down_bar", + }; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri *kuri; + struct GNUNET_FS_FileInformation *fi; + size_t i; + struct GNUNET_FS_BlockOptions bo; + + cfg = c; + setup_peer (&p1, "test_fs_unindex_data.conf"); + fn = GNUNET_DISK_mktemp ("gnunet-unindex-test-dst"); + fs = GNUNET_FS_start (cfg, "test-fs-unindex-persistence", &progress_cb, NULL, + GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); + GNUNET_assert (NULL != fs); + buf = GNUNET_malloc (FILESIZE); + for (i = 0; i < FILESIZE; i++) + buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); + GNUNET_assert (FILESIZE == + GNUNET_DISK_fn_write (fn, buf, FILESIZE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)); + GNUNET_free (buf); + meta = GNUNET_CONTAINER_meta_data_create (); + kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); + bo.content_priority = 42; + bo.anonymity_level = 1; + bo.replication_level = 0; + bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); + fi = GNUNET_FS_file_information_create_from_file (fs, "publish-context", fn, + kuri, meta, GNUNET_YES, + &bo); + GNUNET_FS_uri_destroy (kuri); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_assert (NULL != fi); + start = GNUNET_TIME_absolute_get (); + publish = + GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE); + GNUNET_assert (publish != NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-fs-unindex", + "-c", + "test_fs_unindex_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_log_setup ("test_fs_unindex_persistence", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-fs-unindex", "nohelp", options, &run, NULL); + stop_arm (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-unindex/"); + if (NULL != fn) + { + GNUNET_DISK_directory_remove (fn); + GNUNET_free (fn); + } + return 0; +} + +/* end of test_fs_unindex_persistence.c */ diff --git a/src/fs/test_fs_uri.c b/src/fs/test_fs_uri.c new file mode 100644 index 0000000..b7a58ec --- /dev/null +++ b/src/fs/test_fs_uri.c @@ -0,0 +1,330 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_fs_uri.c + * @brief Test for fs_uri.c + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" + +#define ABORT() { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); return 1; } + +static int +testKeyword () +{ + char *uri; + struct GNUNET_FS_Uri *ret; + char *emsg; + + if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/ksk/++", &emsg))) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + GNUNET_free (emsg); + ret = GNUNET_FS_uri_parse ("gnunet://fs/ksk/foo+bar", &emsg); + if (ret == NULL) + { + GNUNET_free (emsg); + ABORT (); + } + if (!GNUNET_FS_uri_test_ksk (ret)) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + if ((2 != ret->data.ksk.keywordCount) || + (0 != strcmp (" foo", ret->data.ksk.keywords[0])) || + (0 != strcmp (" bar", ret->data.ksk.keywords[1]))) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + + uri = GNUNET_FS_uri_to_string (ret); + if (0 != strcmp (uri, "gnunet://fs/ksk/foo+bar")) + { + GNUNET_free (uri); + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + GNUNET_free (uri); + GNUNET_FS_uri_destroy (ret); + return 0; +} + +static int +testLocation () +{ + struct GNUNET_FS_Uri *uri; + char *uric; + struct GNUNET_FS_Uri *uri2; + struct GNUNET_FS_Uri *baseURI; + char *emsg; + struct GNUNET_CONFIGURATION_Handle *cfg; + + baseURI = + GNUNET_FS_uri_parse + ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42", + &emsg); + GNUNET_assert (baseURI != NULL); + GNUNET_assert (emsg == NULL); + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, "test_fs_uri_data.conf")) + { + FPRINTF (stderr, "%s", "Failed to parse configuration file\n"); + GNUNET_FS_uri_destroy (baseURI); + GNUNET_CONFIGURATION_destroy (cfg); + return 1; + } + uri = GNUNET_FS_uri_loc_create (baseURI, cfg, GNUNET_TIME_absolute_get ()); + if (uri == NULL) + { + GNUNET_break (0); + GNUNET_FS_uri_destroy (baseURI); + GNUNET_CONFIGURATION_destroy (cfg); + return 1; + } + if (!GNUNET_FS_uri_test_loc (uri)) + { + GNUNET_break (0); + GNUNET_FS_uri_destroy (uri); + GNUNET_FS_uri_destroy (baseURI); + GNUNET_CONFIGURATION_destroy (cfg); + return 1; + } + uri2 = GNUNET_FS_uri_loc_get_uri (uri); + if (!GNUNET_FS_uri_test_equal (baseURI, uri2)) + { + GNUNET_break (0); + GNUNET_FS_uri_destroy (uri); + GNUNET_FS_uri_destroy (uri2); + GNUNET_FS_uri_destroy (baseURI); + GNUNET_CONFIGURATION_destroy (cfg); + return 1; + } + GNUNET_FS_uri_destroy (uri2); + GNUNET_FS_uri_destroy (baseURI); + uric = GNUNET_FS_uri_to_string (uri); +#if 0 + /* not for the faint of heart: */ + printf ("URI: `%s'\n", uric); +#endif + uri2 = GNUNET_FS_uri_parse (uric, &emsg); + GNUNET_free (uric); + if (uri2 == NULL) + { + GNUNET_break (0); + GNUNET_FS_uri_destroy (uri); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (emsg); + return 1; + } + GNUNET_assert (NULL == emsg); + if (GNUNET_YES != GNUNET_FS_uri_test_equal (uri, uri2)) + { + GNUNET_break (0); + GNUNET_FS_uri_destroy (uri); + GNUNET_FS_uri_destroy (uri2); + GNUNET_CONFIGURATION_destroy (cfg); + return 1; + } + GNUNET_FS_uri_destroy (uri2); + GNUNET_FS_uri_destroy (uri); + GNUNET_CONFIGURATION_destroy (cfg); + return 0; +} + +static int +testNamespace (int i) +{ + char *uri; + struct GNUNET_FS_Uri *ret; + char *emsg; + + if (NULL != + (ret = + GNUNET_FS_uri_parse ("gnunet://fs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3VUK", + &emsg))) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + GNUNET_free (emsg); + if (NULL != + (ret = + GNUNET_FS_uri_parse + ("gnunet://fs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3V/test", &emsg))) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + GNUNET_free (emsg); + if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/sks/test", &emsg))) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + GNUNET_free (emsg); + ret = + GNUNET_FS_uri_parse + ("gnunet://fs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test", + &emsg); + if (ret == NULL) + { + GNUNET_free (emsg); + ABORT (); + } + if (GNUNET_FS_uri_test_ksk (ret)) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + if (!GNUNET_FS_uri_test_sks (ret)) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + + uri = GNUNET_FS_uri_to_string (ret); + if (0 != + strcmp (uri, + "gnunet://fs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test")) + { + GNUNET_FS_uri_destroy (ret); + GNUNET_free (uri); + ABORT (); + } + GNUNET_free (uri); + GNUNET_FS_uri_destroy (ret); + return 0; +} + +static int +testFile (int i) +{ + char *uri; + struct GNUNET_FS_Uri *ret; + char *emsg; + + if (NULL != + (ret = + GNUNET_FS_uri_parse + ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H00000440000.42", + &emsg))) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + GNUNET_free (emsg); + if (NULL != + (ret = + GNUNET_FS_uri_parse + ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000", + &emsg))) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + GNUNET_free (emsg); + if (NULL != + (ret = + GNUNET_FS_uri_parse + ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.FGH", + &emsg))) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + GNUNET_free (emsg); + ret = + GNUNET_FS_uri_parse + ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42", + &emsg); + if (ret == NULL) + { + GNUNET_free (emsg); + ABORT (); + } + if (GNUNET_FS_uri_test_ksk (ret)) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + if (GNUNET_FS_uri_test_sks (ret)) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + if (GNUNET_ntohll (ret->data.chk.file_length) != 42) + { + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + + uri = GNUNET_FS_uri_to_string (ret); + if (0 != + strcmp (uri, + "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42")) + { + GNUNET_free (uri); + GNUNET_FS_uri_destroy (ret); + ABORT (); + } + GNUNET_free (uri); + GNUNET_FS_uri_destroy (ret); + return 0; +} + +int +main (int argc, char *argv[]) +{ + int failureCount = 0; + int i; + + GNUNET_log_setup ("test_fs_uri", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_CRYPTO_random_disable_entropy_gathering (); + failureCount += testKeyword (); + failureCount += testLocation (); + for (i = 0; i < 255; i++) + { + /* FPRINTF (stderr, "%s", "."); */ + failureCount += testNamespace (i); + failureCount += testFile (i); + } + /* FPRINTF (stderr, "%s", "\n"); */ + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-uri"); + if (failureCount != 0) + return 1; + return 0; +} + +/* end of test_fs_uri.c */ diff --git a/src/fs/test_fs_uri_data.conf b/src/fs/test_fs_uri_data.conf new file mode 100644 index 0000000..abc5a73 --- /dev/null +++ b/src/fs/test_fs_uri_data.conf @@ -0,0 +1,7 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-uri/ + +[arm] +DEFAULTSERVICES = topology hostlist + diff --git a/src/fs/test_gnunet_fs_idx.py.in b/src/fs/test_gnunet_fs_idx.py.in new file mode 100755 index 0000000..6bb7d0d --- /dev/null +++ b/src/fs/test_gnunet_fs_idx.py.in @@ -0,0 +1,73 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Testcase for file-sharing command-line tools (indexing and unindexing) +import sys +import os +import subprocess +import re +import shutil + +srcdir = "../.." +gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") +if gnunet_pyexpect_dir not in sys.path: + sys.path.append (gnunet_pyexpect_dir) + +from gnunet_pyexpect import pexpect + +if os.name == 'posix': + download = 'gnunet-download' + gnunetarm = 'gnunet-arm' + publish = 'gnunet-publish' + unindex = 'gnunet-unindex' +elif os.name == 'nt': + download = 'gnunet-download.exe' + gnunetarm = 'gnunet-arm.exe' + publish = 'gnunet-publish.exe' + unindex = 'gnunet-unindex.exe' + +if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-idx"), True) +else: + shutil.rmtree ("/tmp/gnunet-test-fs-py-idx", True) + +arm = subprocess.Popen ([gnunetarm, '-sq', '-c', 'test_gnunet_fs_idx_data.conf']) +arm.communicate () + +try: + pub = pexpect () + pub.spawn (None, [publish, '-c', 'test_gnunet_fs_idx_data.conf', '-m', "description:The GNU Public License", '-k', 'gpl', '../../COPYING'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O\.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG\.35147'\.\r?\n")) + + down = pexpect () + down.spawn (None, [download, '-c', 'test_gnunet_fs_idx_data.conf', '-o', 'COPYING', 'gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG.35147'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + down.expect ("stdout", re.compile (r"Downloading `COPYING' done (.*).\r?\n")) + os.remove ("COPYING") + + un = pexpect () + un.spawn (None, [unindex, '-c', 'test_gnunet_fs_idx_data.conf', '../../COPYING'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + un.expect ("stdout", re.compile (r'Unindexing done\.\r?\n')) + +finally: + arm = subprocess.Popen ([gnunetarm, '-eq', '-c', 'test_gnunet_fs_idx_data.conf']) + arm.communicate () + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-idx"), True) + else: + 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 new file mode 100644 index 0000000..f852011 --- /dev/null +++ b/src/fs/test_gnunet_fs_idx_data.conf @@ -0,0 +1,8 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-py-idx/ +DEFAULTCONFIG = test_gnunet_fs_idx_data.conf + +[transport] +PLUGINS = + diff --git a/src/fs/test_gnunet_fs_ns.py.in b/src/fs/test_gnunet_fs_ns.py.in new file mode 100755 index 0000000..ff892b4 --- /dev/null +++ b/src/fs/test_gnunet_fs_ns.py.in @@ -0,0 +1,80 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Testcase for file-sharing command-line tools (namespaces) +import sys +import os +import subprocess +import re +import shutil + +srcdir = "../.." +gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") +if gnunet_pyexpect_dir not in sys.path: + sys.path.append (gnunet_pyexpect_dir) + +from gnunet_pyexpect import pexpect + +if os.name == 'posix': + pseudonym = 'gnunet-pseudonym' + gnunetarm = 'gnunet-arm' + publish = 'gnunet-publish' + unindex = 'gnunet-unindex' + search = 'gnunet-search' +elif os.name == 'nt': + pseudonym = 'gnunet-pseudonym.exe' + gnunetarm = 'gnunet-arm.exe' + publish = 'gnunet-publish.exe' + unindex = 'gnunet-unindex.exe' + search = 'gnunet-search.exe' + +if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) +else: + shutil.rmtree ("/tmp/gnunet-test-fs-py-ns", True) + +arm = subprocess.Popen ([gnunetarm, '-sq', '-c', 'test_gnunet_fs_ns_data.conf']) +arm.communicate () + +try: + pseu = pexpect () + pseu.spawn (None, [pseudonym, '-c', 'test_gnunet_fs_ns_data.conf', '-C', 'licenses', '-k', 'gplad', '-m', 'description:Free Software Licenses', '-R', 'myroot'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pseu.spawn (None, [pseudonym, '-c', 'test_gnunet_fs_ns_data.conf', '-o'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pseu.expect ("stdout", re.compile (r"licenses (.*)\r?\n")) + + pub = pexpect () + pub.spawn (None, [publish, '-c', 'test_gnunet_fs_ns_data.conf', '-k', 'licenses', '-P', 'licenses', '-u', 'gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG.35147', '-t', 'gpl', '-N', 'gpl3'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + + s = pexpect () + s.spawn (None, [search, '-V', '-t', '1000', '-N', '1', '-c', 'test_gnunet_fs_ns_data.conf', 'gplad'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + s.expect ("stdout", re.compile (r'#0:\r?\n')) + s.expect ("stdout", re.compile (r'gnunet-download gnunet://fs/sks/.*/myroot\r?\n')) + s.expect ("stdout", re.compile (r'\s*description: Free Software Licenses\r?\n')) + + pseu = pexpect () + pseu.spawn (None, [pseudonym, '-c', 'test_gnunet_fs_ns_data.conf'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pseu.expect ("stdout", re.compile (r'Free Software Licenses.*:\r?\n')) + +finally: + arm = subprocess.Popen ([gnunetarm, '-eq', '-c', 'test_gnunet_fs_ns_data.conf']) + arm.communicate () + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) + else: + shutil.rmtree ("/tmp/gnunet-test-fs-py-ns", True) diff --git a/src/fs/test_gnunet_fs_ns_data.conf b/src/fs/test_gnunet_fs_ns_data.conf new file mode 100644 index 0000000..5f297ab --- /dev/null +++ b/src/fs/test_gnunet_fs_ns_data.conf @@ -0,0 +1,8 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-py-ns/ +DEFAULTCONFIG = test_gnunet_fs_ns_data.conf + +[transport] +PLUGINS = + diff --git a/src/fs/test_gnunet_fs_psd.py.in b/src/fs/test_gnunet_fs_psd.py.in new file mode 100755 index 0000000..9790e13 --- /dev/null +++ b/src/fs/test_gnunet_fs_psd.py.in @@ -0,0 +1,79 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Testcase for file-sharing command-line tools (publish, search, download) +import sys +import os +import subprocess +import re +import shutil + +srcdir = "../.." +gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") +if gnunet_pyexpect_dir not in sys.path: + sys.path.append (gnunet_pyexpect_dir) + +from gnunet_pyexpect import pexpect + +if os.name == 'posix': + download = 'gnunet-download' + gnunetarm = 'gnunet-arm' + publish = 'gnunet-publish' + unindex = 'gnunet-unindex' + search = 'gnunet-search' +elif os.name == 'nt': + download = 'gnunet-download.exe' + gnunetarm = 'gnunet-arm.exe' + publish = 'gnunet-publish.exe' + unindex = 'gnunet-unindex.exe' + search = 'gnunet-search.exe' + +if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-psd"), True) +else: + shutil.rmtree ("/tmp/gnunet-test-fs-py-psd", True) + +arm = subprocess.Popen ([gnunetarm, '-sq', '-c', 'test_gnunet_fs_psd_data.conf']) +arm.communicate () + +# first, basic publish-search-download run +try: + pub = pexpect () + pub.spawn (None, [publish, '-c', 'test_gnunet_fs_psd_data.conf', '-n', '-m', "description:The GNU Public License", '-k', 'gpl', '../../COPYING'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pub.expect ("stdout", re.compile (r"Publishing `.+[\\/]..[\\/]..[\\/]COPYING' done\.\r?\n")) + pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O\.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG\.35147'\.\r?\n")) + + s = pexpect () + s.spawn (None, [search, '-V', '-t', '1000', '-N', '1', '-c', 'test_gnunet_fs_psd_data.conf', 'gpl'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + s.expect ("stdout", re.compile (r'#0:\r?\n')) + s.expect ("stdout", re.compile (r'gnunet-download -o "COPYING" gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O\.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG\.35147\r?\n')) + s.expect ("stdout", re.compile (r"\s*description: The GNU Public License\r?\n")) + + down = pexpect () + down.spawn (None, [download, '-c', 'test_gnunet_fs_psd_data.conf', '-o', 'COPYING', 'gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG.35147'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + down.expect ("stdout", re.compile (r"Downloading `COPYING' done (.*).\r?\n")) + os.remove ("COPYING") + +finally: + arm = subprocess.Popen ([gnunetarm, '-eq', '-c', 'test_gnunet_fs_psd_data.conf']) + arm.communicate () + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-psd"), True) + else: + 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 new file mode 100644 index 0000000..b68c6b5 --- /dev/null +++ b/src/fs/test_gnunet_fs_psd_data.conf @@ -0,0 +1,8 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-py-psd/ +DEFAULTCONFIG = test_gnunet_fs_psd_data.conf + +[transport] +PLUGINS = + diff --git a/src/fs/test_gnunet_fs_rec.py.in b/src/fs/test_gnunet_fs_rec.py.in new file mode 100755 index 0000000..e86bb0a --- /dev/null +++ b/src/fs/test_gnunet_fs_rec.py.in @@ -0,0 +1,109 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Testcase for file-sharing command-line tools (recursive publishing & download) +import sys +import os +import subprocess +import re +import shutil + +srcdir = "../.." +gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") +if gnunet_pyexpect_dir not in sys.path: + sys.path.append (gnunet_pyexpect_dir) + +from gnunet_pyexpect import pexpect + +if os.name == 'posix': + download = 'gnunet-download' + gnunetarm = 'gnunet-arm' + publish = 'gnunet-publish' + unindex = 'gnunet-unindex' + search = 'gnunet-search' + directory = 'gnunet-directory' +elif os.name == 'nt': + download = 'gnunet-download.exe' + gnunetarm = 'gnunet-arm.exe' + publish = 'gnunet-publish.exe' + unindex = 'gnunet-unindex.exe' + search = 'gnunet-search.exe' + directory = 'gnunet-directory.exe' + +if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-rec"), True) +else: + shutil.rmtree ("/tmp/gnunet-test-fs-py-rec", True) + +arm = subprocess.Popen ([gnunetarm, '-sq', '-c', 'test_gnunet_fs_rec_data.conf']) +arm.communicate () + +# pray that `tar' is in PATH +os.system ('tar xfz test_gnunet_fs_rec_data.tgz') +# first, basic publish-search-download run +try: + pub = pexpect () + pub.spawn (None, [publish, '-c', 'test_gnunet_fs_rec_data.conf', '-d', '-k', 'testdir', 'dir/'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + # Can't say much for publishing, except that the last one is the toplevel directory + pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) + pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) + pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) + pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) + pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) + pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) + pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) + pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) + pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) + pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) + pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) + pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) + pub.expect ("stdout", re.compile (r"Publishing `.+[\\/]dir[\\/]' done\.\r?\n")) + m = pub.expect ("stdout", re.compile (r".+\r?\n")) + if not m: + sys.exit (3) + output = m.string + url = output[output.find ("`")+1:output.find("'")] + + down = pexpect () + down.spawn (None, [download, '-c', 'test_gnunet_fs_rec_data.conf', '-R', '-o', 'rdir.gnd', url], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + down.expect ("stdout", re.compile (r"Downloading `rdir.gnd' done (.*).\r?\n")) + + d = pexpect () + d.spawn (None, [directory, '-c', 'test_gnunet_fs_rec_data.conf', 'rdir/a.gnd'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + d.expect ("stdout", re.compile (r"Directory `a/' meta data:\r?\n")) + d.expect ("stdout", re.compile (r"Directory `a/' contents:\r?\n")) + d.expect ("stdout", re.compile (r"COPYING (.*)\r?\n")) + d.expect ("stdout", re.compile (r"INSTALL (.*)\r?\n")) + + os.remove ("rdir/b.gnd") + os.remove ("rdir/a.gnd") + if 0 != os.system ("diff -r dir rdir"): + raise Exception ("Unexpected difference between source directory and downloaded result") + + +finally: + arm = subprocess.Popen ([gnunetarm, '-eq', '-c', 'test_gnunet_fs_rec_data.conf']) + arm.communicate () + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-rec"), True) + else: + shutil.rmtree ("/tmp/gnunet-test-fs-py-rec", True) + shutil.rmtree ("dir", True) + shutil.rmtree ("rdir", True) + 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 new file mode 100644 index 0000000..dae8b19 --- /dev/null +++ b/src/fs/test_gnunet_fs_rec_data.conf @@ -0,0 +1,8 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/gnunet-test-fs-py-rec/ +DEFAULTCONFIG = test_gnunet_fs_rec_data.conf + +[transport] +PLUGINS = + diff --git a/src/fs/test_gnunet_fs_rec_data.tgz b/src/fs/test_gnunet_fs_rec_data.tgz new file mode 100644 index 0000000..6977943 Binary files /dev/null and b/src/fs/test_gnunet_fs_rec_data.tgz differ diff --git a/src/fs/test_gnunet_service_fs_migration.c b/src/fs/test_gnunet_service_fs_migration.c new file mode 100644 index 0000000..8b85e5e --- /dev/null +++ b/src/fs/test_gnunet_service_fs_migration.c @@ -0,0 +1,221 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_gnunet_service_fs_migration.c + * @brief test content migration between two peers + * @author Christian Grothoff + */ +#include "platform.h" +#include "fs_test_lib.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_NO + +/** + * File-size we use for testing. + */ +#define FILESIZE (2 * 32 * 1024) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * How long do we give the peers for content migration? + */ +#define MIGRATION_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90) + +#define SEED 42 + +static struct GNUNET_FS_TestDaemon *daemons[2]; + +static int ok; + +static struct GNUNET_TIME_Absolute start_time; + +static struct GNUNET_FS_TEST_ConnectContext *cc; + +static void +do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TIME_Relative del; + char *fancy; + + if (NULL != cc) + { + GNUNET_FS_TEST_daemons_connect_cancel (cc); + cc = NULL; + } + GNUNET_FS_TEST_daemons_stop (2, daemons); + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + del = GNUNET_TIME_absolute_get_duration (start_time); + if (del.rel_value == 0) + del.rel_value = 1; + fancy = + GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) * + 1000LL / del.rel_value); + FPRINTF (stdout, "Download speed was %s/s\n", fancy); + GNUNET_free (fancy); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished download, shutting down\n", + (unsigned long long) FILESIZE); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout during download, shutting down with error\n"); + ok = 1; + } +} + + +static void +do_download (void *cls, const char *emsg) +{ + struct GNUNET_FS_Uri *uri = cls; + + if (emsg != NULL) + { + GNUNET_FS_TEST_daemons_stop (2, daemons); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to stop source daemon: %s\n", + emsg); + GNUNET_FS_uri_destroy (uri); + ok = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", + (unsigned long long) FILESIZE); + start_time = GNUNET_TIME_absolute_get (); + GNUNET_FS_TEST_download (daemons[0], TIMEOUT, 1, SEED, uri, VERBOSE, &do_stop, + NULL); + GNUNET_FS_uri_destroy (uri); +} + + +static void +stop_source_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_Uri *uri = cls; + struct GNUNET_TESTING_PeerGroup *pg; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping source peer\n"); + pg = GNUNET_FS_TEST_get_group (daemons); + GNUNET_TESTING_daemons_vary (pg, 1, GNUNET_NO, TIMEOUT, &do_download, uri); +} + + +static void +do_wait (void *cls, const struct GNUNET_FS_Uri *uri) +{ + struct GNUNET_FS_Uri *d; + + if (NULL == uri) + { + GNUNET_FS_TEST_daemons_stop (2, daemons); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout during upload attempt, shutting down with error\n"); + ok = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Waiting to allow content to migrate\n"); + d = GNUNET_FS_uri_dup (uri); + (void) GNUNET_SCHEDULER_add_delayed (MIGRATION_DELAY, &stop_source_peer, d); +} + + +static void +do_publish (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + cc = NULL; + if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + GNUNET_FS_TEST_daemons_stop (2, daemons); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout during connect attempt, shutting down with error\n"); + ok = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", + (unsigned long long) FILESIZE); + GNUNET_FS_TEST_publish (daemons[1], TIMEOUT, 1, GNUNET_NO, FILESIZE, SEED, + VERBOSE, &do_wait, NULL); +} + + +static void +do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + FPRINTF (stderr, "%s", "Daemons failed to start!\n"); + GNUNET_break (0); + ok = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Daemons started, will now try to connect them\n"); + cc = GNUNET_FS_TEST_daemons_connect (daemons[0], daemons[1], TIMEOUT, + &do_publish, NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_FS_TEST_daemons_start ("test_gnunet_service_fs_migration_data.conf", + TIMEOUT, 2, daemons, &do_connect, NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-gnunet-service-fs-migration", + "-c", + "fs_test_lib_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-service-fs-migration/"); + GNUNET_log_setup ("test_gnunet_service_fs_migration", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-gnunet-service-fs-migration", "nohelp", options, + &run, NULL); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-service-fs-migration/"); + return ok; +} + +/* 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 new file mode 100644 index 0000000..9c05a88 --- /dev/null +++ b/src/fs/test_gnunet_service_fs_migration_data.conf @@ -0,0 +1,9 @@ +@INLINE@ test_fs_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-service-fs-migration/ +DEFAULTCONFIG = test_gnunet_service_fs_migration_data.conf + + +[ats] +WAN_QUOTA_IN = 3932160 +WAN_QUOTA_OUT = 3932160 diff --git a/src/fs/test_gnunet_service_fs_p2p.c b/src/fs/test_gnunet_service_fs_p2p.c new file mode 100644 index 0000000..a853897 --- /dev/null +++ b/src/fs/test_gnunet_service_fs_p2p.c @@ -0,0 +1,176 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/test_gnunet_service_fs_p2p.c + * @brief test P2P routing using simple publish + download operation + * @author Christian Grothoff + */ +#include "platform.h" +#include "fs_test_lib.h" + +#define VERBOSE GNUNET_NO + +/** + * File-size we use for testing. + */ +#define FILESIZE (1024 * 1024 * 1) + +/** + * How long until we give up on the download? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define NUM_DAEMONS 2 + +#define SEED 42 + +static struct GNUNET_FS_TestDaemon *daemons[NUM_DAEMONS]; + +static int ok; + +static struct GNUNET_TIME_Absolute start_time; + +static struct GNUNET_FS_TEST_ConnectContext *cc; + +static void +do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TIME_Relative del; + char *fancy; + + if (NULL != cc) + { + GNUNET_FS_TEST_daemons_connect_cancel (cc); + cc = NULL; + } + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + del = GNUNET_TIME_absolute_get_duration (start_time); + if (del.rel_value == 0) + del.rel_value = 1; + fancy = + GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) * + 1000LL / del.rel_value); + FPRINTF (stdout, "Download speed was %s/s\n", fancy); + GNUNET_free (fancy); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished download, shutting down\n", + (unsigned long long) FILESIZE); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout during download, shutting down with error\n"); + ok = 1; + } +} + + +static void +do_download (void *cls, const struct GNUNET_FS_Uri *uri) +{ + if (NULL == uri) + { + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout during upload attempt, shutting down with error\n"); + ok = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", + (unsigned long long) FILESIZE); + start_time = GNUNET_TIME_absolute_get (); + GNUNET_FS_TEST_download (daemons[0], TIMEOUT, 1, SEED, uri, VERBOSE, &do_stop, + NULL); +} + + +static void +do_publish (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + cc = NULL; + if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout during connect attempt, shutting down with error\n"); + ok = 1; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", + (unsigned long long) FILESIZE); + GNUNET_FS_TEST_publish (daemons[1], TIMEOUT, 1, GNUNET_NO, FILESIZE, SEED, + VERBOSE, &do_download, NULL); +} + + +static void +do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Daemons started, will now try to connect them\n"); + cc = GNUNET_FS_TEST_daemons_connect (daemons[0], daemons[1], TIMEOUT, + &do_publish, NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_FS_TEST_daemons_start ("fs_test_lib_data.conf", TIMEOUT, NUM_DAEMONS, + daemons, &do_connect, NULL); +} + + +int +main (int argc, char *argv[]) +{ + char *const argvx[] = { + "test-gnunet-service-fs-p2p", + "-c", + "fs_test_lib_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); + GNUNET_log_setup ("test_gnunet_service_fs_p2p", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test-gnunet-service-fs-p2p", "nohelp", options, &run, + NULL); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); + return ok; +} + +/* end of test_gnunet_service_fs_p2p.c */ diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am new file mode 100644 index 0000000..cc19939 --- /dev/null +++ b/src/gns/Makefile.am @@ -0,0 +1,113 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +plugindir = $(libdir)/gnunet + +pkgcfg_DATA = \ + gns.conf + +lib_LTLIBRARIES = \ + libgnunetgns.la libgnunetnamestore.la + +bin_PROGRAMS = \ + gnunet-service-gns + +#noinst_PROGRAMS = \ +# gnunet-gns-lookup + +check_SCRIPTS = \ + test_gnunet_gns.sh + +check_PROGRAMS = \ + test_gns_twopeer + + +plugin_LTLIBRARIES = \ + libgnunet_plugin_block_gns.la + +test_gns_twopeer_SOURCES = \ + test_gns_twopeer.c +test_gns_twopeer_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_gns_twopeer_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +#gnunet_gns_lookup_SOURCES = \ +# gnunet-gns-lookup.c +#gnunet_gns_lookup_LDADD = \ +# $(top_builddir)/src/gns/libgnunetgns.la \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(GN_LIBINTL) +#gnunet_dns_lookup_DEPENDENCIES = \ +# libgnunetgns.la + +gnunet_service_gns_SOURCES = \ + gnunet-service-gns.c +gnunet_service_gns_LDADD = \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetnamestore.la \ + $(GN_LIBINTL) +gnunet_service_gns_DEPENDENCIES = \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetnamestore.la + +libgnunetgns_la_SOURCES = \ + gns_api.c gns.h +libgnunetgns_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +libgnunetgns_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) +libgnunetgns_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_block_gns_la_SOURCES = \ + plugin_block_gns.c +libgnunet_plugin_block_gns_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/block/libgnunetblock.la +libgnunet_plugin_block_gns_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) +libgnunet_plugin_block_gns_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/block/libgnunetblock.la + +#Build stub api +libgnunetnamestore_la_SOURCES = \ + namestore_stub_api.c +libgnunetnamestore_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +libgnunetnamestore_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) +libgnunetnamestore_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +endif + +EXTRA_DIST = \ + $(check_SCRIPTS) \ + test_gns_twopeer.conf diff --git a/src/gns/Makefile.in b/src/gns/Makefile.in new file mode 100644 index 0000000..87422ab --- /dev/null +++ b/src/gns/Makefile.in @@ -0,0 +1,998 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-gns$(EXEEXT) +check_PROGRAMS = test_gns_twopeer$(EXEEXT) +subdir = src/gns +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/gns.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = gns.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) +am_libgnunet_plugin_block_gns_la_OBJECTS = plugin_block_gns.lo +libgnunet_plugin_block_gns_la_OBJECTS = \ + $(am_libgnunet_plugin_block_gns_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_block_gns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_block_gns_la_LDFLAGS) $(LDFLAGS) -o $@ +am_libgnunetgns_la_OBJECTS = gns_api.lo +libgnunetgns_la_OBJECTS = $(am_libgnunetgns_la_OBJECTS) +libgnunetgns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetgns_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +am_libgnunetnamestore_la_OBJECTS = namestore_stub_api.lo +libgnunetnamestore_la_OBJECTS = $(am_libgnunetnamestore_la_OBJECTS) +libgnunetnamestore_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetnamestore_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_service_gns_OBJECTS = gnunet-service-gns.$(OBJEXT) +gnunet_service_gns_OBJECTS = $(am_gnunet_service_gns_OBJECTS) +am__DEPENDENCIES_1 = +am_test_gns_twopeer_OBJECTS = test_gns_twopeer.$(OBJEXT) +test_gns_twopeer_OBJECTS = $(am_test_gns_twopeer_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunet_plugin_block_gns_la_SOURCES) \ + $(libgnunetgns_la_SOURCES) $(libgnunetnamestore_la_SOURCES) \ + $(gnunet_service_gns_SOURCES) $(test_gns_twopeer_SOURCES) +DIST_SOURCES = $(libgnunet_plugin_block_gns_la_SOURCES) \ + $(libgnunetgns_la_SOURCES) $(libgnunetnamestore_la_SOURCES) \ + $(gnunet_service_gns_SOURCES) $(test_gns_twopeer_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +pkgcfgdir = $(pkgdatadir)/config.d/ +plugindir = $(libdir)/gnunet +pkgcfg_DATA = \ + gns.conf + +lib_LTLIBRARIES = \ + libgnunetgns.la libgnunetnamestore.la + + +#noinst_PROGRAMS = \ +# gnunet-gns-lookup +check_SCRIPTS = \ + test_gnunet_gns.sh + +plugin_LTLIBRARIES = \ + libgnunet_plugin_block_gns.la + +test_gns_twopeer_SOURCES = \ + test_gns_twopeer.c + +test_gns_twopeer_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_twopeer_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + + +#gnunet_gns_lookup_SOURCES = \ +# gnunet-gns-lookup.c +#gnunet_gns_lookup_LDADD = \ +# $(top_builddir)/src/gns/libgnunetgns.la \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(GN_LIBINTL) +#gnunet_dns_lookup_DEPENDENCIES = \ +# libgnunetgns.la +gnunet_service_gns_SOURCES = \ + gnunet-service-gns.c + +gnunet_service_gns_LDADD = \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetnamestore.la \ + $(GN_LIBINTL) + +gnunet_service_gns_DEPENDENCIES = \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetnamestore.la + +libgnunetgns_la_SOURCES = \ + gns_api.c gns.h + +libgnunetgns_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) + +libgnunetgns_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) + +libgnunetgns_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_block_gns_la_SOURCES = \ + plugin_block_gns.c + +libgnunet_plugin_block_gns_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/block/libgnunetblock.la + +libgnunet_plugin_block_gns_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_block_gns_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/block/libgnunetblock.la + + +#Build stub api +libgnunetnamestore_la_SOURCES = \ + namestore_stub_api.c + +libgnunetnamestore_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) + +libgnunetnamestore_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) + +libgnunetnamestore_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +EXTRA_DIST = \ + $(check_SCRIPTS) \ + test_gns_twopeer.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/gns/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/gns/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +gns.conf: $(top_builddir)/config.status $(srcdir)/gns.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_block_gns.la: $(libgnunet_plugin_block_gns_la_OBJECTS) $(libgnunet_plugin_block_gns_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_block_gns_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_gns_la_OBJECTS) $(libgnunet_plugin_block_gns_la_LIBADD) $(LIBS) +libgnunetgns.la: $(libgnunetgns_la_OBJECTS) $(libgnunetgns_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetgns_la_LINK) -rpath $(libdir) $(libgnunetgns_la_OBJECTS) $(libgnunetgns_la_LIBADD) $(LIBS) +libgnunetnamestore.la: $(libgnunetnamestore_la_OBJECTS) $(libgnunetnamestore_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetnamestore_la_LINK) -rpath $(libdir) $(libgnunetnamestore_la_OBJECTS) $(libgnunetnamestore_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-service-gns$(EXEEXT): $(gnunet_service_gns_OBJECTS) $(gnunet_service_gns_DEPENDENCIES) + @rm -f gnunet-service-gns$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_gns_OBJECTS) $(gnunet_service_gns_LDADD) $(LIBS) +test_gns_twopeer$(EXEEXT): $(test_gns_twopeer_OBJECTS) $(test_gns_twopeer_DEPENDENCIES) + @rm -f test_gns_twopeer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_twopeer_OBJECTS) $(test_gns_twopeer_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gns_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-gns.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namestore_stub_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_gns.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_twopeer.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-pkgcfgDATA \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/gns/gns.conf.in b/src/gns/gns.conf.in new file mode 100644 index 0000000..422efdb --- /dev/null +++ b/src/gns/gns.conf.in @@ -0,0 +1,17 @@ +[gns] +AUTOSTART = YES +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-gns +UNIXPATH = /tmp/gnunet-service-gns.sock +ZONEKEY = /tmp/zonekey +TRUSTED = bob:/tmp/bobkey +HIJACK_DNS = YES +OPTIONS = -L INFO + +# Access to this service can compromise all DNS queries in this +# system. Thus access should be restricted to the same UID. +# (see https://gnunet.org/gnunet-access-control-model) +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES diff --git a/src/gns/gns.h b/src/gns/gns.h new file mode 100644 index 0000000..cb47c81 --- /dev/null +++ b/src/gns/gns.h @@ -0,0 +1,97 @@ +/* + This file is part of GNUnet + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file gns/gns.h + * @brief IPC messages between GNS API and GNS service + * @author Martin Schanzenbach + */ +#ifndef GNS_H +#define GNS_H + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message from client to GNS service to lookup records. + */ +struct GNUNET_GNS_ClientLookupMessage +{ + /** + * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP + */ + struct GNUNET_MessageHeader header; + + /** + * A key. TODO some uid + */ + GNUNET_HashCode key; + + /** + * Unique identifier for this request (for key collisions). + */ + // FIXME: unaligned + uint64_t unique_id; + + /** + * the type of record to look up + */ + // FIXME: bad type - should be of GNUNET_GNS_RecordType + int type; + + /* Followed by the name to look up */ +}; + + +/** + * Message from GNS service to client: new results. + */ +struct GNUNET_GNS_ClientResultMessage +{ + /** + * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + // FIXME: unaligned + uint64_t unique_id; + + /** + * A key. TODO some uid + * // FIXME: why hash? + */ + GNUNET_HashCode key; + + /** + * The number of records contained in response + */ + uint32_t num_records; + + // FIXME: what format has a GNS_Record? + /* followed by num_records GNUNET_GNS_Records*/ + +}; + + +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/gns/gns_api.c b/src/gns/gns_api.c new file mode 100644 index 0000000..ec9c159 --- /dev/null +++ b/src/gns/gns_api.c @@ -0,0 +1,635 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * TODO: Do we really need a client API? + * + * @file gns/gns_api.c + * @brief library to access the GNS service + * @author Martin Schanzenbach + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_dht_service.h" +#include "gns.h" +#include "gnunet_gns_service.h" + +#define DEBUG_GNS_API GNUNET_EXTRA_LOGGING + +#define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) + +/* TODO into gnunet_protocols */ +#define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23 +#define GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT 24 + +/** + * Entry in our list of messages to be (re-)transmitted. + */ +struct PendingMessage +{ + /** + * This is a doubly-linked list. + */ + struct PendingMessage *prev; + + /** + * This is a doubly-linked list. + */ + struct PendingMessage *next; + + /** + * Message that is pending, allocated at the end + * of this struct. + */ + const struct GNUNET_MessageHeader *msg; + + /** + * Handle to the GNS API context. + */ + struct GNUNET_GNS_Handle *handle; + + /** + * Continuation to call when the request has been + * transmitted (for the first time) to the service; can be NULL. + */ + GNUNET_SCHEDULER_Task cont; + + /** + * Closure for 'cont'. + */ + void *cont_cls; + + /** + * Timeout task for this message + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * Unique ID for this request + */ + uint64_t unique_id; + + /** + * Free the saved message once sent, set to GNUNET_YES for messages + * that do not receive responses; GNUNET_NO if this pending message + * is aliased from a 'struct GNUNET_DHT_RouteHandle' and will be freed + * from there. + */ + + int free_on_send; + /** + * GNUNET_YES if this message is in our pending queue right now. + */ + int in_pending_queue; + +}; + +/** + * Handle to a Lookup request + */ +struct GNUNET_GNS_LookupHandle +{ + + /** + * Iterator to call on data receipt + */ + GNUNET_GNS_LookupIterator iter; + + /** + * Closure for the iterator callback + */ + void *iter_cls; + + /** + * Main handle to this GNS api + */ + struct GNUNET_GNS_Handle *gns_handle; + + /** + * Key that this get request is for + */ + GNUNET_HashCode key; + + /** + * Unique identifier for this request (for key collisions). + */ + uint64_t unique_id; + + struct PendingMessage *message; + +}; + +/** + * Connection to the GNS service. + */ +struct GNUNET_GNS_Handle +{ + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Socket (if available). + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Currently pending transmission request (or NULL). + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Head of linked list of messages we would like to transmit. + */ + struct PendingMessage *pending_head; + + /** + * Tail of linked list of messages we would like to transmit. + */ + struct PendingMessage *pending_tail; + + /** + * Hash map containing the current outstanding unique requests. + */ + struct GNUNET_CONTAINER_MultiHashMap *active_requests; + + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * How quickly should we retry? Used for exponential back-off on + * connect-errors. + */ + struct GNUNET_TIME_Relative retry_time; + + /** + * Generator for unique ids. + */ + uint64_t uid_gen; + + /** + * Did we start our receive loop yet? + */ + int in_receive; +}; + +/** + * Try to send messages from list of messages to send + * @param handle GNS_Handle + */ +static void +process_pending_messages (struct GNUNET_GNS_Handle *handle); + +/** + * Try to (re)connect to the GNS service. + * + * @return GNUNET_YES on success, GNUNET_NO on failure. + */ +static int +try_connect (struct GNUNET_GNS_Handle *handle) +{ + if (handle->client != NULL) + return GNUNET_OK; + handle->in_receive = GNUNET_NO; + handle->client = GNUNET_CLIENT_connect ("gns", handle->cfg); + if (handle->client == NULL) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Failed to connect to the GNS service!\n")); + return GNUNET_NO; + } + return GNUNET_YES; +} + +/** + * Add the request corresponding to the given handle + * to the pending queue (if it is not already in there). + * + * @param cls the 'struct GNUNET_GNS_Handle*' + * @param key key for the request (not used) + * @param value the 'struct GNUNET_GNS_LookupHandle*' + * @return GNUNET_YES (always) + */ +static int +add_request_to_pending (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_GNS_Handle *handle = cls; + struct GNUNET_GNS_LookupHandle *rh = value; + + if (GNUNET_NO == rh->message->in_pending_queue) + { +#if DEBUG_DHT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Retransmitting request related to %s to GNS %p\n", GNUNET_h2s(key), + handle); +#endif + GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, + rh->message); + rh->message->in_pending_queue = GNUNET_YES; + } + return GNUNET_YES; +} + +/** + * Try reconnecting to the GNS service. + * + * @param cls GNUNET_GNS_Handle + * @param tc scheduler context + */ +static void +try_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_GNS_Handle *handle = cls; + +#if DEBUG_GNS + LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting with GNS %p\n", handle); +#endif + handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + if (handle->retry_time.rel_value < GNUNET_CONSTANTS_SERVICE_RETRY.rel_value) + handle->retry_time = GNUNET_CONSTANTS_SERVICE_RETRY; + else + handle->retry_time = GNUNET_TIME_relative_multiply (handle->retry_time, 2); + if (handle->retry_time.rel_value > GNUNET_CONSTANTS_SERVICE_TIMEOUT.rel_value) + handle->retry_time = GNUNET_CONSTANTS_SERVICE_TIMEOUT; + handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + if (GNUNET_YES != try_connect (handle)) + { +#if DEBUG_GNS + LOG (GNUNET_ERROR_TYPE_DEBUG, "GNS reconnect failed(!)\n"); +#endif + return; + } + GNUNET_CONTAINER_multihashmap_iterate (handle->active_requests, + &add_request_to_pending, handle); + process_pending_messages (handle); +} + + +/** + * Try reconnecting to the GNS service. + * + * @param handle handle to gns to (possibly) disconnect and reconnect + */ +static void +do_disconnect (struct GNUNET_GNS_Handle *handle) +{ + if (handle->client == NULL) + return; + GNUNET_assert (handle->reconnect_task == GNUNET_SCHEDULER_NO_TASK); + if (NULL != handle->th) + GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); + handle->th = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Disconnecting from GNS service, will try to reconnect in %llu ms\n", + (unsigned long long) handle->retry_time.rel_value); + GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO); + handle->client = NULL; + handle->reconnect_task = + GNUNET_SCHEDULER_add_delayed (handle->retry_time, &try_reconnect, handle); +} + +/** + * Transmit the next pending message, called by notify_transmit_ready + */ +static size_t +transmit_pending (void *cls, size_t size, void *buf); + +/** + * Handler for messages received from the GNS service + * + * @param cls the 'struct GNUNET_GNS_Handle' + * @param msg the incoming message + */ +static void +message_handler (void *cls, const struct GNUNET_MessageHeader *msg); + +/** + * Try to send messages from list of messages to send + */ +static void +process_pending_messages (struct GNUNET_GNS_Handle *handle) +{ + struct PendingMessage *head; + + if (handle->client == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "process_pending_messages called, but client is null, reconnecting\n"); + do_disconnect (handle); + return; + } + if (handle->th != NULL) + return; + if (NULL == (head = handle->pending_head)) + return; + handle->th = + GNUNET_CLIENT_notify_transmit_ready (handle->client, + ntohs (head->msg->size), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &transmit_pending, + handle); + if (NULL != handle->th) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "notify_transmit_ready returned NULL, reconnecting\n"); + do_disconnect (handle); +} + + +/** + * Transmit the next pending message, called by notify_transmit_ready + */ +static size_t +transmit_pending (void *cls, size_t size, void *buf) +{ + struct GNUNET_GNS_Handle *handle = cls; + struct PendingMessage *head; + size_t tsize; + + handle->th = NULL; + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmission to GNS service failed! Reconnecting!\n"); + do_disconnect (handle); + return 0; + } + if (NULL == (head = handle->pending_head)) + return 0; + + tsize = ntohs (head->msg->size); + if (size < tsize) + { + process_pending_messages (handle); + return 0; + } + memcpy (buf, head->msg, tsize); + GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, + head); + head->in_pending_queue = GNUNET_NO; + if (head->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (head->timeout_task); + head->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_YES == head->free_on_send) + GNUNET_free (head); + process_pending_messages (handle); +#if DEBUG_GNS + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Forwarded request of %u bytes to GNS service\n", (unsigned int) tsize); +#endif + if (GNUNET_NO == handle->in_receive) + { +#if DEBUG_GNS + LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting to process replies from GNS\n"); +#endif + handle->in_receive = GNUNET_YES; + GNUNET_CLIENT_receive (handle->client, &message_handler, handle, + GNUNET_TIME_UNIT_FOREVER_REL); + } + return tsize; +} + +/** + * Process a given reply that might match the given + * request. + * + * @param cls the 'struct GNUNET_GNS_ClientResultMessage' + * @param key query of the request + * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key + * @return GNUNET_YES to continue to iterate over all results, + * GNUNET_NO if the reply is malformed + */ +static int +process_reply (void *cls, const GNUNET_HashCode * key, void *value) +{ + const struct GNUNET_GNS_ClientResultMessage *gns_msg = cls; + struct GNUNET_GNS_LookupHandle *lookup_handle = value; + const char *name = (const char*) &lookup_handle[1]; + const struct GNUNET_NAMESTORE_RecordData *records; + uint32_t num_records; + size_t meta_length; + size_t msize; + + if (gns_msg->unique_id != lookup_handle->unique_id) + { + /* UID mismatch */ +#if DEBUG_GNS + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Ignoring reply for %s: UID mismatch: %llu/%llu\n", GNUNET_h2s (key), + gns_msg->unique_id, lookup_handle->unique_id); +#endif + return GNUNET_YES; + } + msize = ntohs (gns_msg->header.size); + num_records = ntohl (gns_msg->num_records); + meta_length = + sizeof (struct GNUNET_GNS_ClientResultMessage) + + sizeof (struct GNUNET_NAMESTORE_RecordData) * (num_records); + if ((msize < meta_length) || + (num_records > + GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_NAMESTORE_RecordData))) + { + GNUNET_break (0); + return GNUNET_NO; + } +#if DEBUG_GNS + LOG (GNUNET_ERROR_TYPE_DEBUG, "Giving %u byte reply for %s to application\n", + (unsigned int) (msize - meta_length), GNUNET_h2s (key)); +#endif + records = (const struct GNUNET_NAMESTORE_RecordData *) &gns_msg[1]; + lookup_handle->iter (lookup_handle->iter_cls, name, records, num_records); + return GNUNET_YES; +} + + +/** + * Handler for messages received from the GNS service + * + * @param cls the 'struct GNUNET_GNS_Handle' + * @param msg the incoming message + */ +static void +message_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_GNS_Handle *handle = cls; + const struct GNUNET_GNS_ClientResultMessage *gns_msg; + + if (msg == NULL) + { +#if DEBUG_GNS + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Error receiving data from GNS service, reconnecting\n"); +#endif + do_disconnect (handle); + return; + } + if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT) + { + GNUNET_break (0); + do_disconnect (handle); + return; + } + if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientResultMessage)) + { + GNUNET_break (0); + do_disconnect (handle); + return; + } + gns_msg = (const struct GNUNET_GNS_ClientResultMessage *) msg; +#if DEBUG_GNS + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received reply for `%s' from GNS service %p\n", + &gns_msg->name, handle); +#endif + /* TODO uniquely identify requests... maybe hash(name) or uid */ + GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_requests, + &gns_msg->key, &process_reply, + (void *) gns_msg); + GNUNET_CLIENT_receive (handle->client, &message_handler, handle, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Initialize the connection with the GNS service. + * + * @param cfg configuration to use + * @param ht_len size of the internal hash table to use for parallel requests + * @return handle to the GNS service, or NULL on error + */ +struct GNUNET_GNS_Handle * +GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int ht_len) +{ + struct GNUNET_GNS_Handle *handle; + + handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle)); + handle->cfg = cfg; + handle->uid_gen = + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); + handle->active_requests = GNUNET_CONTAINER_multihashmap_create (ht_len); + if (GNUNET_NO == try_connect (handle)) + { + GNUNET_GNS_disconnect (handle); + return NULL; + } + return handle; +} + + +/** + * Shutdown connection with the GNS service. + * + * @param handle handle of the GNS connection to stop + */ +void +GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle) +{ + /* disco from GNS */ +} + + +/** + * Perform an asynchronous Lookup operation on the GNS. + * TODO: + * - Still not sure what we query for... "names" it is for now + * - Do we need such sophisticated message queueing like dht? simplify? + * + * @param handle handle to the GNS service + * @param timeout how long to wait for transmission of this request to the service + * @param name the name to look up + * @param iter function to call on each result + * @param iter_cls closure for iter + * @return handle to stop the async get + */ +struct GNUNET_GNS_LookupHandle * +GNUNET_GNS_lookup_start (struct GNUNET_GNS_Handle *handle, + struct GNUNET_TIME_Relative timeout, + const char * name, + enum GNUNET_GNS_RecordType type, + GNUNET_GNS_LookupIterator iter, + void *iter_cls) +{ + /* IPC to look for local entries, start dht lookup, return lookup_handle */ + struct GNUNET_GNS_ClientLookupMessage *lookup_msg; + struct GNUNET_GNS_LookupHandle *lookup_handle; + GNUNET_HashCode key; + size_t msize; + struct PendingMessage *pending; + + if (NULL == name) + { + return NULL; + } + + GNUNET_CRYPTO_hash (name, strlen(name), &key); + + msize = sizeof (struct GNUNET_GNS_ClientLookupMessage) + strlen(name); +#if DEBUG_GNS + LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting lookup for %s in GNS %p\n", + name, handle); +#endif + pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1]; + pending->msg = &lookup_msg->header; + pending->handle = handle; + pending->free_on_send = GNUNET_NO; + lookup_msg->header.size = htons (msize); + lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP); + lookup_msg->key = key; + memcpy(&lookup_msg[1], name, strlen(name)); + handle->uid_gen++; + lookup_msg->unique_id = handle->uid_gen; + GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, + pending); + pending->in_pending_queue = GNUNET_YES; + lookup_handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_LookupHandle)); + lookup_handle->iter = iter; + lookup_handle->iter_cls = iter_cls; + lookup_handle->message = pending; + lookup_handle->unique_id = lookup_msg->unique_id; + GNUNET_CONTAINER_multihashmap_put (handle->active_requests, &lookup_msg->key, + lookup_handle, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + process_pending_messages (handle); + return lookup_handle; +} + + +/** + * Stop async GNS lookup. + * + * @param lookup_handle handle to the GNS lookup operation to stop + */ +void +GNUNET_GNS_lookup_stop (struct GNUNET_GNS_LookupHandle *lookup_handle) +{ + /* TODO Stop dht lookups */ +} + + +/* end of gns_api.c */ diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c new file mode 100644 index 0000000..b5649f3 --- /dev/null +++ b/src/gns/gnunet-service-gns.c @@ -0,0 +1,1399 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * + * TODO: + * - Write xquery and block plugin + * - The smaller FIXME issues all around + * + * @file gns/gnunet-service-gns.c + * @brief GNUnet GNS service + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_dns_service.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_namestore_service.h" +#include "gnunet_gns_service.h" +#include "block_gns.h" +#include "gns.h" + +/* Ignore for now not used anyway and probably never will */ +#define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23 +#define GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT 24 + +/** + * Handle to a currenty pending resolution + */ +struct GNUNET_GNS_ResolverHandle +{ + /* The name to resolve */ + char *name; + + /* the request handle to reply to */ + struct GNUNET_DNS_RequestHandle *request_handle; + + /* the dns parser packet received */ + struct GNUNET_DNSPARSER_Packet *packet; + + /* the query parsed from the packet */ + + struct GNUNET_DNSPARSER_Query *query; + + /* has this query been answered? how many matches */ + int answered; + + /* the authoritative zone to query */ + GNUNET_HashCode authority; + + /* the name of the authoritative zone to query */ + char *authority_name; + + /** + * we have an authority in namestore that + * may be able to resolve + */ + int authority_found; + + /* a handle for dht lookups. should be NULL if no lookups are in progress */ + struct GNUNET_DHT_GetHandle *get_handle; + +}; + + +/** + * Our handle to the DNS handler library + */ +struct GNUNET_DNS_Handle *dns_handle; + +/** + * Our handle to the DHT + */ +struct GNUNET_DHT_Handle *dht_handle; + +/** + * Our zone's private key + */ +struct GNUNET_CRYPTO_RsaPrivateKey *zone_key; + +/** + * Our handle to the namestore service + * FIXME maybe need a second handle for iteration + */ +struct GNUNET_NAMESTORE_Handle *namestore_handle; + +/** + * Handle to iterate over our authoritative zone in namestore + */ +struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter; + +/** + * The configuration the GNS service is running with + */ +const struct GNUNET_CONFIGURATION_Handle *GNS_cfg; + +/** + * Our notification context. + */ +static struct GNUNET_SERVER_NotificationContext *nc; + +/** + * Our zone hash + */ +GNUNET_HashCode zone_hash; + +/** + * Our tld. Maybe get from config file + */ +const char* gnunet_tld = ".gnunet"; + +/** + * Useful for zone update for DHT put + */ +static int num_public_records = 3600; +struct GNUNET_TIME_Relative dht_update_interval; +GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK; + +/* Prototypes */ +void reply_to_dns(struct GNUNET_GNS_ResolverHandle *answer, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd); +void resolve_name(struct GNUNET_GNS_ResolverHandle *rh); + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + /* Kill zone task for it may make the scheduler hang */ + GNUNET_SCHEDULER_cancel(zone_update_taskid); + + GNUNET_DNS_disconnect(dns_handle); + GNUNET_NAMESTORE_disconnect(namestore_handle, 0); + GNUNET_DHT_disconnect(dht_handle); +} + +/** + * Callback when record data is put into namestore + * + * @param cls the closure + * @param success GNUNET_OK on success + * @param emsg the error message. NULL if SUCCESS==GNUNET_OK + */ +void +on_namestore_record_put_result(void *cls, + int32_t success, + const char *emsg) +{ + if (GNUNET_NO == success) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n"); + return; + } + else if (GNUNET_YES == success) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "records successfully put in namestore\n"); + return; + } + + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Error putting records into namestore: %s\n", emsg); +} + +/** + * Function called when we get a result from the dht + * for our query + * + * @param cls the request handle + * @param exp lifetime + * @param key the key the record was stored under + * @param get_path get path + * @param get_path_length get path length + * @param put_path put path + * @param put_path_length put path length + * @param type the block type + * @param size the size of the record + * @param data the record data + */ +void +process_authority_dht_result(void* cls, + struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, + enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + struct GNUNET_GNS_ResolverHandle *rh; + struct GNSNameRecordBlock *nrb; + struct GNSRecordBlock *rb; + uint32_t num_records; + char* name = NULL; + int i; + GNUNET_HashCode zone, name_hash; + + if (data == NULL) + return; + + //FIXME check expiration? + + rh = (struct GNUNET_GNS_ResolverHandle *)cls; + nrb = (struct GNSNameRecordBlock*)data; + + GNUNET_DHT_get_stop (rh->get_handle); + rh->get_handle = NULL; + num_records = ntohl(nrb->rd_count); + struct GNUNET_NAMESTORE_RecordData rd[num_records]; + name = (char*)&nrb[1]; + rb = (struct GNSRecordBlock *)&name[strlen(name) + 1]; + + for (i=0; itype); + rd[i].data_size = ntohl(rb->data_length); + rd[i].data = &rb[1]; + rd[i].expiration = GNUNET_TIME_absolute_ntoh(rb->expiration); + rd[i].flags = ntohl(rb->flags); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got name: %s (wanted %s)\n", name, rh->authority_name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got type: %d raw %d (wanted %d)\n", + rd[i].record_type, rb->type, GNUNET_GNS_RECORD_PKEY); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got data length: %d\n", rd[i].data_size); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got flag %d\n", rd[i].flags); + + if ((strcmp(name, rh->authority_name) == 0) && + (rd[i].record_type == GNUNET_GNS_RECORD_PKEY)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n"); + rh->answered = 1; + GNUNET_CRYPTO_hash( + (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *)rd[i].data, + rd[i].data_size, + &rh->authority); + } + rb = (struct GNSRecordBlock*)((char*)&rb[1] + rd[i].data_size); + + } + + GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); + GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone); + + /* Save to namestore */ + if (0 == GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone)) + { + GNUNET_NAMESTORE_record_put (namestore_handle, + &nrb->public_key, + name, + exp, + num_records, + rd, + &nrb->signature, + &on_namestore_record_put_result, //cont + NULL); //cls + } + + if (rh->answered) + { + rh->answered = 0; + resolve_name(rh); + return; + } + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No authority in records\n"); + reply_to_dns(rh, 0, NULL); +} + +/** + * Start DHT lookup for a name -> PKEY (compare NS) record in + * query->authority's zone + * + * @param rh the pending gns query + * @param name the name of the PKEY record + */ +void +resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh) +{ + uint32_t xquery; + struct GNUNET_TIME_Relative timeout; + GNUNET_HashCode name_hash; + GNUNET_HashCode lookup_key; + + GNUNET_CRYPTO_hash(rh->authority_name, + strlen(rh->authority_name), + &name_hash); + GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key); + + timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5); + + xquery = htonl(GNUNET_GNS_RECORD_PKEY); + //FIXME how long to wait for results? + rh->get_handle = GNUNET_DHT_get_start(dht_handle, timeout, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + &lookup_key, + 5, //Replication level FIXME + GNUNET_DHT_RO_NONE, + &xquery, + sizeof(xquery), + &process_authority_dht_result, + rh); + +} + +/** + * Function called when we get a result from the dht + * for our query + * + * @param cls the request handle + * @param exp lifetime + * @param key the key the record was stored under + * @param get_path get path + * @param get_path_length get path length + * @param put_path put path + * @param put_path_length put path length + * @param type the block type + * @param size the size of the record + * @param data the record data + */ +void +process_name_dht_result(void* cls, + struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, + enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + struct GNUNET_GNS_ResolverHandle *rh; + struct GNSNameRecordBlock *nrb; + struct GNSRecordBlock *rb; + uint32_t num_records; + char* name = NULL; + int i; + GNUNET_HashCode zone, name_hash; + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size); + + if (data == NULL) + return; + + //FIXME maybe check expiration here, check block type + + rh = (struct GNUNET_GNS_ResolverHandle *)cls; + nrb = (struct GNSNameRecordBlock*)data; + + GNUNET_DHT_get_stop (rh->get_handle); + rh->get_handle = NULL; + num_records = ntohl(nrb->rd_count); + struct GNUNET_NAMESTORE_RecordData rd[num_records]; + + name = (char*)&nrb[1]; + rb = (struct GNSRecordBlock*)&name[strlen(name) + 1]; + + for (i=0; itype); + rd[i].data_size = ntohl(rb->data_length); + rd[i].data = (char*)&rb[1]; + rd[i].expiration = GNUNET_TIME_absolute_ntoh(rb->expiration); + rd[i].flags = ntohl(rb->flags); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got name: %s (wanted %s)\n", name, rh->name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got type: %d raw %d (wanted %d)\n", + rd[i].record_type, rb->type, rh->query->type); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got data length: %d\n", rd[i].data_size); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got flag %d\n", rd[i].flags); + + /* FIXME class? */ + if ((strcmp(name, rh->name) == 0) && + (rd[i].record_type == rh->query->type)) + { + rh->answered++; + } + + rb = (struct GNSRecordBlock*)((char*)&rb[1] + rd[i].data_size); + + } + + GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); + GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone); + + /** + * FIXME check pubkey against existing key in namestore? + * https://gnunet.org/bugs/view.php?id=2179 + */ + + /* Save to namestore */ + GNUNET_NAMESTORE_record_put (namestore_handle, + &nrb->public_key, + name, + exp, + num_records, + rd, + &nrb->signature, + &on_namestore_record_put_result, //cont + NULL); //cls + + if (rh->answered) + reply_to_dns(rh, num_records, rd); + else + reply_to_dns(rh, 0, NULL); + +} + +/** + * Start DHT lookup for a (name -> query->record_type) record in + * query->authority's zone + * + * @param rh the pending gns query context + * @param name the name to query record + */ +void +resolve_name_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name) +{ + uint32_t xquery; + struct GNUNET_TIME_Relative timeout; + GNUNET_HashCode name_hash; + GNUNET_HashCode lookup_key; + struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string; + + GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); + GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key); + GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "starting dht lookup for %s with key: %s\n", + name, (char*)&lookup_key_string); + + timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5); + + xquery = htonl(rh->query->type); + //FIXME how long to wait for results? + rh->get_handle = GNUNET_DHT_get_start(dht_handle, timeout, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + &lookup_key, + 5, //Replication level FIXME + GNUNET_DHT_RO_NONE, + &xquery, //xquery FIXME is this bad? + sizeof(xquery), + &process_name_dht_result, + rh); + +} + +//Prototype +void +resolve_name(struct GNUNET_GNS_ResolverHandle *rh); + +/** + * This is a callback function that should give us only PKEY + * records. Used to query the namestore for the authority (PKEY) + * for 'name' + * + * @param cls the pending query + * @param key the key of the zone we did the lookup + * @param expiration expiration date of the record data set in the namestore + * @param name the name for which we need an authority + * @param rd_count the number of records with 'name' + * @param rd the record data + * @param signature the signature of the authority for the record data + */ +void +process_authority_lookup(void* cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, + struct GNUNET_TIME_Absolute expiration, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct GNUNET_GNS_ResolverHandle *rh; + struct GNUNET_TIME_Relative remaining_time; + GNUNET_HashCode zone; + + rh = (struct GNUNET_GNS_ResolverHandle *)cls; + GNUNET_CRYPTO_hash(key, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zone); + remaining_time = GNUNET_TIME_absolute_get_remaining (expiration); + + /** + * No authority found in namestore. + */ + if (rd_count == 0) + { + /** + * We did not find an authority in the namestore + * _IF_ the current authoritative zone is us we cannot resolve + * _ELSE_ we can still check the _expired_ dht + */ + if (0 != GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash) && + (remaining_time.rel_value == 0)) + { + resolve_authority_dht(rh); + return; + } + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority %s unknown\n", + rh->authority_name); + reply_to_dns(rh, 0, NULL); + return; + } + + //Note only 1 pkey should have been returned.. anything else would be strange + /** + * We found an authority that may be able to help us + * move on with query + */ + int i; + for (i=0; iauthority); + resolve_name(rh); + return; + + } + + /** + * no answers found + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Authority lookup successful but no PKEY... never get here\n"); + reply_to_dns(rh, 0, NULL); +} + + +/** + * Reply to client with the result from our lookup. + * + * @param rh the request handle of the lookup + * @param rd_count the number of records to return + * @param rd the record data + */ +void +reply_to_dns(struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + int i; + size_t len; + int ret; + char *buf; + struct GNUNET_DNSPARSER_Packet *packet = rh->packet; + struct GNUNET_DNSPARSER_Record answer_records[rh->answered]; + struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)]; + packet->answers = answer_records; + packet->additional_records = additional_records; + + /** + * Put records in the DNS packet and modify it + * to a response + */ + len = sizeof(struct GNUNET_DNSPARSER_Record*); + for (i=0; i < rd_count; i++) + { + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Adding type %d to DNS response\n", rd[i].record_type); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", rh->query->name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size); + + if (rd[i].record_type == rh->query->type) + { + answer_records[i].name = rh->query->name; + answer_records[i].type = rd[i].record_type; + answer_records[i].data.raw.data_len = rd[i].data_size; + answer_records[i].data.raw.data = (char*)rd[i].data; + answer_records[i].expiration_time = rd[i].expiration; + answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn + } + else + { + additional_records[i].name = rh->query->name; + additional_records[i].type = rd[i].record_type; + additional_records[i].data.raw.data_len = rd[i].data_size; + additional_records[i].data.raw.data = (char*)rd[i].data; + additional_records[i].expiration_time = rd[i].expiration; + additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn + } + } + + packet->num_answers = rh->answered; + packet->num_additional_records = rd_count-(rh->answered); + + if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash)) + packet->flags.authoritative_answer = 1; + else + packet->flags.authoritative_answer = 0; + + if (rd == NULL) + packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR; + else + packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR; + + packet->flags.query_or_response = 1; + + + /** + * Reply to DNS + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Building DNS response\n"); + ret = GNUNET_DNSPARSER_pack (packet, + 1024, /* FIXME magic from dns redirector */ + &buf, + &len); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Built DNS response! (ret=%d,len=%d)\n", ret, len); + if (ret == GNUNET_OK) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Answering DNS request\n"); + GNUNET_DNS_request_answer(rh->request_handle, + len, + buf); + //GNUNET_free(answer); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n"); + } + else + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Error building DNS response! (ret=%d)", ret); + } + + GNUNET_free(rh->name); + GNUNET_free(rh); +} + + +/** + * Namestore calls this function if we have record for this name. + * (or with rd_count=0 to indicate no matches) + * + * @param cls the pending query + * @param key the key of the zone we did the lookup + * @param expiration expiration date of the namestore entry + * @param name the name for which we need an authority + * @param rd_count the number of records with 'name' + * @param rd the record data + * @param signature the signature of the authority for the record data + */ +static void +process_authoritative_result(void* cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, + struct GNUNET_TIME_Absolute expiration, + const char *name, unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct GNUNET_GNS_ResolverHandle *rh; + struct GNUNET_TIME_Relative remaining_time; + GNUNET_HashCode zone; + + rh = (struct GNUNET_GNS_ResolverHandle *) cls; + GNUNET_CRYPTO_hash(key, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zone); + remaining_time = GNUNET_TIME_absolute_get_remaining (expiration); + + if (rd_count == 0) + { + /** + * Lookup terminated and no results + * -> DHT Phase unless data is recent + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Namestore lookup for %s terminated without results\n", name); + + /** + * if this is not our zone we cannot rely on the namestore to be + * complete. -> Query DHT + */ + if (GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash)) + { + if (remaining_time.rel_value == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "trying dht...\n"); + resolve_name_dht(rh, name); + return; + } + else + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Record is still recent. No DHT lookup\n"); + } + } + + /** + * Our zone and no result? Cannot resolve TT + */ + GNUNET_assert(rh->answered == 0); + reply_to_dns(rh, 0, NULL); + return; + + } + else + { + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Processing additional result %s from namestore\n", name); + int i; + for (i=0; iquery->name) == 0) + && (rd[i].record_type != rh->query->type)) + continue; + + if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value + == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n"); + continue; + } + + rh->answered++; + + } + + /** + * no answers found + * consult dht if expired + */ + if ((remaining_time.rel_value == 0) && (rh->answered == 0)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "This dht entry is old. Refreshing.\n"); + resolve_name_dht(rh, name); + return; + } + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n", + rh->answered); + + reply_to_dns(rh, rd_count, rd); + } +} + +/** + * Determine if this name is canonical. + * i.e. + * a.b.gnunet = not canonical + * a = canonical + * + * @param name the name to test + * @return 1 if canonical + */ +int +is_canonical(char* name) +{ + uint32_t len = strlen(name); + int i; + + for (i=0; i 0; len--) + { + if (*(name+len) == '.') + break; + } + + if (len == 0) + return NULL; + + name[len] = '\0'; + + return (name+len+1); +} + + +/** + * The first phase of resolution. + * First check if the name is canonical. + * If it is then try to resolve directly. + * If not then we first have to resolve the authoritative entities. + * + * @param rh the pending lookup + */ +void +resolve_name(struct GNUNET_GNS_ResolverHandle *rh) +{ + if (is_canonical(rh->name)) + { + /* We only need to check the current zone's ns */ + GNUNET_NAMESTORE_lookup_record(namestore_handle, + &rh->authority, + rh->name, + rh->query->type, + &process_authoritative_result, + rh); + } + else + { + /* We have to resolve the authoritative entity first */ + rh->authority_name = pop_tld(rh->name); + GNUNET_NAMESTORE_lookup_record(namestore_handle, + &rh->authority, + rh->authority_name, + GNUNET_GNS_RECORD_PKEY, + &process_authority_lookup, + rh); + } +} + +/** + * Entry point for name resolution + * Setup a new query and try to resolve + * + * @param request the request handle of the DNS request from a client + * @param p the DNS query packet we received + * @param q the DNS query we received parsed from p + */ +void +start_resolution(struct GNUNET_DNS_RequestHandle *request, + struct GNUNET_DNSPARSER_Packet *p, + struct GNUNET_DNSPARSER_Query *q) +{ + struct GNUNET_GNS_ResolverHandle *rh; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting resolution for (%s)!\n", + q->name); + + rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle)); + rh->packet = p; + rh->query = q; + rh->authority = zone_hash; + + rh->name = GNUNET_malloc(strlen(q->name) + - strlen(gnunet_tld) + 1); + memset(rh->name, 0, + strlen(q->name)-strlen(gnunet_tld) + 1); + memcpy(rh->name, q->name, + strlen(q->name)-strlen(gnunet_tld)); + + rh->request_handle = request; + + /* Start resolution in our zone */ + resolve_name(rh); +} + +/** + * The DNS request handler + * Called for every incoming DNS request. + * + * @param cls closure + * @param rh request handle to user for reply + * @param request_length number of bytes in request + * @param request udp payload of the DNS request + */ +void +handle_dns_request(void *cls, + struct GNUNET_DNS_RequestHandle *rh, + size_t request_length, + const char *request) +{ + struct GNUNET_DNSPARSER_Packet *p; + char *tldoffset; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n"); + p = GNUNET_DNSPARSER_parse (request, request_length); + + if (NULL == p) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Received malformed DNS packet, leaving it untouched\n"); + GNUNET_DNS_request_forward (rh); + return; + } + + /** + * Check tld and decide if we or + * legacy dns is responsible + * + * FIXME now in theory there could be more than 1 query in the request + * but if this is case we get into trouble: + * either we query the GNS or the DNS. We cannot do both! + * So I suggest to either only allow a single query per request or + * only allow GNS or DNS requests. + * The way it is implemented here now is buggy and will lead to erratic + * behaviour (if multiple queries are present). + */ + if (p->num_queries == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No Queries in DNS packet... forwarding\n"); + GNUNET_DNS_request_forward (rh); + } + + if (p->num_queries > 1) + { + /* Note: We could also look for .gnunet */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + ">1 queriy in DNS packet... odd. We only process #1\n"); + } + + + /** + * Check for .gnunet + */ + tldoffset = p->queries[0].name + strlen(p->queries[0].name); + + while ((*tldoffset) != '.') + tldoffset--; + + if (0 == strcmp(tldoffset, gnunet_tld)) + { + start_resolution(rh, p, p->queries); + } + else + { + /** + * This request does not concern us. Forward to real DNS. + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Request for %s is forwarded to DNS\n", p->queries[0].name); + GNUNET_DNS_request_forward (rh); + } + +} + +/** + * test function that stores some data in the namestore + * This will also be replaced by a test progrm that + * directl interfaces with the namestore + */ +void +put_some_records(void) +{ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Populating namestore\n"); + /* put an A record into namestore FIXME use gnunet.org */ + char* ipB = "5.6.7.8"; + + struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); + struct GNUNET_NAMESTORE_RecordData rdb_web; + + GNUNET_assert(1 == inet_pton (AF_INET, ipB, web)); + + rdb_web.data_size = sizeof(struct in_addr); + rdb_web.data = web; + rdb_web.record_type = GNUNET_DNSPARSER_TYPE_A; + rdb_web.expiration = GNUNET_TIME_absolute_get_forever (); + + GNUNET_NAMESTORE_record_create (namestore_handle, + zone_key, + "www", + &rdb_web, + NULL, + NULL); +} + +/** + * Method called periodicattluy that triggers + * iteration over root zone + * + * @param cls closure + * @param tc task context + */ +void +update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_NAMESTORE_zone_iterator_next(namestore_iter); +} + +/** + * Continuation for DHT put + * + * @param cls closure + * @param tc task context + */ +void +record_dht_put(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n"); +} + +/* prototype */ +static void +update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Function used to put all records successively into the DHT. + * FIXME bug here + * + * @param cls the closure (NULL) + * @param key the public key of the authority (ours) + * @param expiration lifetime of the namestore entry + * @param name the name of the records + * @param rd_count the number of records in data + * @param rd the record data + * @param signature the signature for the record data + */ +void +put_gns_record(void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, + struct GNUNET_TIME_Absolute expiration, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Putting records for %s into the DHT\n", name); + struct GNUNET_TIME_Relative timeout; + struct GNSNameRecordBlock *nrb; + struct GNSRecordBlock *rb; + GNUNET_HashCode name_hash; + GNUNET_HashCode xor_hash; + struct GNUNET_CRYPTO_HashAsciiEncoded xor_hash_string; + int i; + uint32_t rd_payload_length; + + /* we're done */ + if (NULL == name) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished\n"); + GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter); + zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, + NULL); + return; + } + + rd_payload_length = rd_count * sizeof(struct GNSRecordBlock); + rd_payload_length += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock); + + /* calculate payload size */ + for (i=0; isignature, signature, + sizeof(struct GNUNET_CRYPTO_RsaSignature)); + //FIXME signature purpose + memcpy(&nrb->public_key, key, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + + nrb->rd_count = htonl(rd_count); + + memcpy(&nrb[1], name, strlen(name) + 1); //FIXME is this 0 terminated?? + + rb = (struct GNSRecordBlock *)((char*)&nrb[1] + strlen(name) + 1); + + for (i=0; itype = htonl(rd[i].record_type); + rb->expiration = GNUNET_TIME_absolute_hton(rd[i].expiration); + rb->data_length = htonl(rd[i].data_size); + rb->flags = htonl(rd[i].flags); + memcpy(&rb[1], rd[i].data, rd[i].data_size); + rb = &rb[1] + rd[i].data_size; + } + + /** + * FIXME magic number 20 move to config file + * DHT_WAIT_TIMEOUT + */ + timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20); + + /* + * calculate DHT key: H(name) xor H(pubkey) + */ + GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); + GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash); + GNUNET_CRYPTO_hash_to_enc (&xor_hash, &xor_hash_string); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "putting records for %s under key: %s with size %d\n", + name, (char*)&xor_hash_string, rd_payload_length); + + GNUNET_DHT_put (dht_handle, &xor_hash, + 5, //replication level + GNUNET_DHT_RO_NONE, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, //FIXME todo block plugin + rd_payload_length, + (char*)nrb, + expiration, + timeout, + &record_dht_put, //FIXME continuation needed? success check? yes ofc + NULL); //cls for cont + + num_public_records++; + + /** + * Reschedule periodic put + */ + zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval, + &update_zone_dht_next, + NULL); + +} + +/** + * Puts a single trusted entity into the + * namestore. Will be replaced in a testcase + * that directly interacts with a persistent + * namestore. + * + * @param name name of entity + * @param keyfile keyfile + */ +void +put_trusted(char* name, char* keyfile) +{ + struct GNUNET_NAMESTORE_RecordData rd; + struct GNUNET_CRYPTO_RsaPrivateKey *key; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey; + pkey = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + + key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_CRYPTO_rsa_key_get_public (key, pkey); + rd.data = pkey; + rd.expiration = GNUNET_TIME_absolute_get_forever (); + rd.data_size = sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded); + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + GNUNET_NAMESTORE_record_create (namestore_handle, + zone_key, + name, + &rd, + NULL, + NULL); +} + + + +/** + * Periodically iterate over our zone and store everything in dht + * + * @param cls NULL + * @param tc task context + */ +static void +update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting DHT zone update!\n"); + if (0 == num_public_records) + { + dht_update_interval = GNUNET_TIME_relative_multiply( + GNUNET_TIME_UNIT_SECONDS, + 1); + } + else + { + dht_update_interval = GNUNET_TIME_relative_multiply( + GNUNET_TIME_UNIT_SECONDS, + (3600/num_public_records)); + } + num_public_records = 0; //start counting again + namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle, + &zone_hash, + GNUNET_NAMESTORE_RF_AUTHORITY, + GNUNET_NAMESTORE_RF_PRIVATE, + &put_gns_record, + NULL); +} + +/** + * Process GNS requests. + * + * @param cls closure + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n"); + + char* keyfile; + char* trusted_entities; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "gns", + "ZONEKEY", &keyfile)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No private key for root zone specified%s!\n", keyfile); + GNUNET_SCHEDULER_shutdown(0); + return; + } + + zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey); + + GNUNET_CRYPTO_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zone_hash); + + nc = GNUNET_SERVER_notification_context_create (server, 1); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (c, "gns", + "HIJACK_DNS")) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, + "DNS hijacking enabled... connecting to service.\n"); + /** + * Do gnunet dns init here + */ + dns_handle = GNUNET_DNS_connect(c, + GNUNET_DNS_FLAG_PRE_RESOLUTION, + &handle_dns_request, /* rh */ + NULL); /* Closure */ + if (NULL == dns_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to the dnsservice!\n"); + } + } + + + + /** + * handle to our local namestore + */ + namestore_handle = GNUNET_NAMESTORE_connect(c); + + if (NULL == namestore_handle) + { + //FIXME do error handling; + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to the namestore!\n"); + GNUNET_SCHEDULER_shutdown(0); + return; + } + + char* trusted_start; + char* trusted_name; + char *trusted_key; + int trusted_len; + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (c, "gns", + "TRUSTED", + &trusted_entities)) + { + trusted_start = trusted_entities; + trusted_len = strlen(trusted_entities); + GNUNET_log(GNUNET_ERROR_TYPE_INFO, + "Found trusted entities in config file, importing\n"); + while ((trusted_entities-trusted_start) < trusted_len) + { + trusted_name = trusted_entities; + while (*trusted_entities != ':') + trusted_entities++; + *trusted_entities = '\0'; + trusted_entities++; + trusted_key = trusted_entities; + while (*trusted_entities != ',' && (*trusted_entities != '\0')) + trusted_entities++; + *trusted_entities = '\0'; + trusted_entities++; + + if (GNUNET_YES == GNUNET_DISK_file_test (trusted_key)) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Adding %s:%s to root zone\n", + trusted_name, + trusted_key); + put_trusted(trusted_name, trusted_key); + } + else + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Keyfile %s does not exist!\n", + trusted_key); + //put_trusted(trusted_name, trusted_key); //FIXME for testing + } + } + + } + + /** + * handle to the dht + */ + dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg + + if (NULL == dht_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n"); + } + + put_some_records(); //FIXME for testing + + /** + * Schedule periodic put + * for our records + * We have roughly an hour for all records; + */ + dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, + 1); + zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL); + +} + + +/** + * The main function for the GNS service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + int ret; + + ret = + (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run, + NULL)) ? 0 : 1; + return ret; +} + +/* end of gnunet-service-gns.c */ diff --git a/src/gns/namestore_stub_api.c b/src/gns/namestore_stub_api.c new file mode 100644 index 0000000..d067bca --- /dev/null +++ b/src/gns/namestore_stub_api.c @@ -0,0 +1,438 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file gns/namestore_stub_api.c + * @brief stub library to access the NAMESTORE service + * @author Martin Schanzenbach + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_namestore_service.h" + +#define DEBUG_GNS_API GNUNET_EXTRA_LOGGING + +#define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) + +/** + * A QueueEntry. + */ +struct GNUNET_NAMESTORE_QueueEntry +{ + char *data; /*stub data pointer*/ +}; + +/** + * Connection to the NAMESTORE service. + */ +struct GNUNET_NAMESTORE_Handle +{ + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Socket (if available). + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Currently pending transmission request (or NULL). + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /* dll to use for records */ + struct GNUNET_NAMESTORE_SimpleRecord * records_head; + struct GNUNET_NAMESTORE_SimpleRecord * records_tail; + + uint32_t locked; + +}; + +struct GNUNET_NAMESTORE_ZoneIterator +{ + struct GNUNET_NAMESTORE_Handle *handle; + GNUNET_NAMESTORE_RecordProcessor proc; + void* proc_cls; + const GNUNET_HashCode * zone; + uint32_t no_flags; + uint32_t flags; + struct GNUNET_NAMESTORE_Handle *h; + struct GNUNET_NAMESTORE_SimpleRecord *sr; +}; + +struct GNUNET_NAMESTORE_SimpleRecord +{ + /** + * DLL + */ + struct GNUNET_NAMESTORE_SimpleRecord *next; + + /** + * DLL + */ + struct GNUNET_NAMESTORE_SimpleRecord *prev; + + const char *name; + const GNUNET_HashCode *zone; + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key; + uint32_t rd_count; + struct GNUNET_NAMESTORE_RecordData rd[100]; +}; + + +/** + * Initialize the connection with the NAMESTORE service. + * + * @param cfg configuration to use + * @return handle to the GNS service, or NULL on error + */ +struct GNUNET_NAMESTORE_Handle * +GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_NAMESTORE_Handle *handle; + + handle = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Handle)); + handle->cfg = cfg; + handle->records_head = NULL; + handle->records_tail = NULL; + return handle; +} + +/** + * Shutdown connection with the NAMESTORE service. + * + * @param handle handle of the NAMESTORE connection to stop + */ +void +GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *handle, int drop) +{ + GNUNET_free(handle); +} + +/** + * Store an item in the namestore. If the item is already present, + * the expiration time is updated to the max of the existing time and + * the new time. The operation must fail if there is no matching + * entry in the signature tree. + * + * @param h handle to the namestore + * @param zone hash of the public key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param record_type type of the record (A, AAAA, PKEY, etc.) + * @param expiration expiration time for the content + * @param flags flags for the content + * @param data_size number of bytes in data + * @param data value, semantics depend on 'record_type' (see RFCs for DNS and + * GNS specification for GNS extensions) + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return handle to abort the request + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_record_put (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const char *name, + struct GNUNET_TIME_Absolute expiration, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_NAMESTORE_QueueEntry *qe; + qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); + struct GNUNET_NAMESTORE_SimpleRecord* sr; + GNUNET_HashCode *zone; + int i; + + zone = GNUNET_malloc(sizeof(GNUNET_HashCode)); + GNUNET_CRYPTO_hash(public_key, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + zone); + + sr = h->records_head; + for (; sr != NULL; sr = sr->next) + { + if (GNUNET_CRYPTO_hash_cmp(zone, sr->zone) == 0) + { + sr->rd_count = rd_count; + for (i=0; ird[i] = rd[i]; + } + //Expiration, Signature etc + return qe; + } + } + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "new records for %s\n", name); + // Not present + sr = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_SimpleRecord)); + sr->rd_count = rd_count; + sr->name = GNUNET_malloc(strlen(name)); + sr->zone = zone; + sr->zone_key = public_key; //pkey FIXME; + sr->next = NULL; + sr->prev = NULL; + strcpy((char*)sr->name, name); + + for (i=0; ird[i] = rd[i]; + + if (h->records_head == NULL && h->records_tail == NULL) + { + h->records_head = sr; + h->records_tail = sr; + } + else + { + GNUNET_CONTAINER_DLL_insert(h->records_head, h->records_tail, sr); + } + + return qe; +} + +int +GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + return GNUNET_OK; +} + +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_record_create (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_RsaPrivateKey *key, + const char *name, + const struct GNUNET_NAMESTORE_RecordData *rd, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_NAMESTORE_QueueEntry *qe; + qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); + struct GNUNET_NAMESTORE_SimpleRecord* sr; + + GNUNET_HashCode *zone_hash; + + //memleakage.. but only stub so w/e + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey; + pkey = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + GNUNET_CRYPTO_rsa_key_get_public (key, pkey); + + zone_hash = GNUNET_malloc(sizeof(GNUNET_HashCode)); + + GNUNET_CRYPTO_hash(pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + zone_hash); + + sr = h->records_head; + for (; sr != NULL; sr = sr->next) + { + if ((strcmp(sr->name, name) == 0) && + (0 == GNUNET_CRYPTO_hash_cmp(sr->zone, zone_hash))) + { + //Dangerous + memcpy (&(sr->rd[sr->rd_count-1]), rd, + sizeof(struct GNUNET_NAMESTORE_RecordData)); + + sr->rd_count++; + return qe; + } + } + + sr = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_SimpleRecord)); + + sr->rd_count = 1; + sr->name = GNUNET_malloc(strlen(name)); + sr->zone = zone_hash; + sr->zone_key = pkey; + sr->next = NULL; + sr->prev = NULL; + strcpy((char*)sr->name, name); + + memcpy (&(sr->rd), rd, + sizeof(struct GNUNET_NAMESTORE_RecordData)); + if (h->records_head == NULL && h->records_tail == NULL) + { + h->records_head = sr; + h->records_tail = sr; + } + else + { + GNUNET_CONTAINER_DLL_insert(h->records_head, h->records_tail, sr); + } + + return qe; +} + +/** + * Explicitly remove some content from the database. The + * "cont"inuation will be called with status "GNUNET_OK" if content + * was removed, "GNUNET_NO" if no matching entry was found and + * "GNUNET_SYSERR" on all other types of errors. + * + * @param h handle to the namestore + * @param zone hash of the public key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param record_type type of the record (A, AAAA, PKEY, etc.) + * @param size number of bytes in data + * @param data content stored + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return handle to abort the request + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_record_remove (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, + const char *name, + const struct GNUNET_NAMESTORE_RecordData *rd, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_NAMESTORE_QueueEntry *qe; + qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); + + //FIXME + return qe; +} + +/** + * Get a result for a particular key from the namestore. The processor + * will only be called once. + * + * @param h handle to the namestore + * @param zone zone to look up a record from + * @param name name to look up + * @param record_type desired record type + * @param proc function to call on each matching value; + * will be called once with a NULL value at the end + * @param proc_cls closure for proc + * @return a handle that can be used to + * cancel + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_lookup_record (struct GNUNET_NAMESTORE_Handle *h, + const GNUNET_HashCode *zone, + const char *name, + uint32_t record_type, + GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls) +{ + struct GNUNET_NAMESTORE_QueueEntry *qe; + qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); + struct GNUNET_NAMESTORE_SimpleRecord *sr; + struct GNUNET_CRYPTO_HashAsciiEncoded zone_string, zone_string_ex; + + GNUNET_CRYPTO_hash_to_enc (zone, &zone_string); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking up %s in %s\n", name, (char*)&zone_string); + sr = h->records_head; + for (; sr != NULL; sr = sr->next) + { + GNUNET_CRYPTO_hash_to_enc (sr->zone, &zone_string_ex); + if ((strcmp(sr->name, name) == 0) && + (0 == (GNUNET_CRYPTO_hash_cmp(sr->zone, zone)))) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Found match for %s in %s with %d entries\n", + sr->name, (char*)&zone_string_ex, sr->rd_count); + //Simply always return all records + proc(proc_cls, sr->zone_key, GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME + name, sr->rd_count, sr->rd, NULL); + return qe; + } + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No match\n"); + } + proc(proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, name, 0, NULL, NULL); + //FIXME + return qe; +} + +struct GNUNET_NAMESTORE_ZoneIterator * +GNUNET_NAMESTORE_zone_iteration_start(struct GNUNET_NAMESTORE_Handle *h, + const GNUNET_HashCode *zone, + enum GNUNET_NAMESTORE_RecordFlags must_have_flags, + enum GNUNET_NAMESTORE_RecordFlags must_not_have_flags, + GNUNET_NAMESTORE_RecordProcessor proc, + void *proc_cls) +{ + struct GNUNET_NAMESTORE_ZoneIterator *it; + h->locked = 1; + it = GNUNET_malloc(sizeof(struct GNUNET_NAMESTORE_ZoneIterator)); + it->h = h; + it->sr = h->records_head; + it->proc = proc; + it->proc_cls = proc_cls; + it->zone = zone; + it->no_flags = must_not_have_flags; + it->flags = must_have_flags; + GNUNET_NAMESTORE_zone_iterator_next(it); + return it; +} + +void +GNUNET_NAMESTORE_zone_iterator_next(struct GNUNET_NAMESTORE_ZoneIterator *it) +{ + + if (it->h->locked == 0) + return; + if (it->sr == NULL) + { + it->proc(it->proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, + NULL, 0, NULL, NULL); + return; + } + if (GNUNET_CRYPTO_hash_cmp(it->sr->zone, it->zone) == 0) + { + //Simply always return all records + //check flags + it->proc(it->proc_cls, it->sr->zone_key, GNUNET_TIME_UNIT_FOREVER_ABS, + it->sr->name, it->sr->rd_count, it->sr->rd, NULL); + } + it->sr = it->sr->next; +} + +void +GNUNET_NAMESTORE_zone_iteration_stop(struct GNUNET_NAMESTORE_ZoneIterator *it) +{ + //it->h->locked = 0; +} + +/** + * Cancel a namestore operation. The final callback from the + * operation must not have been done yet. + * + * @param qe operation to cancel + */ +void +GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe) +{ + if (qe) + GNUNET_free(qe); +} + + + + +/* end of namestore_stub_api.c */ diff --git a/src/gns/plugin_block_gns.c b/src/gns/plugin_block_gns.c new file mode 100644 index 0000000..a4d6ad9 --- /dev/null +++ b/src/gns/plugin_block_gns.c @@ -0,0 +1,226 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file gns/plugin_block_gns.c + * @brief blocks used for GNS records + * @author Martin Schanzenbach + */ + +#include "platform.h" +#include "gnunet_block_plugin.h" +#include "gnunet_namestore_service.h" +#include "block_gns.h" +#include "gnunet_signatures.h" + +/** + * Number of bits we set per entry in the bloomfilter. + * Do not change! -from fs + */ +#define BLOOMFILTER_K 16 + +/** + * Function called to validate a reply or a request. For + * request evaluation, simply pass "NULL" for the reply_block. + * Note that it is assumed that the reply has already been + * matched to the key (and signatures checked) as it would + * be done with the "get_key" function. + * + * @param cls closure + * @param type block type + * @param query original query (hash) + * @param bf pointer to bloom filter associated with query; possibly updated (!) + * @param bf_mutator mutation value for bf + * @param xquery extrended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in reply block + * @return characterization of result + */ +static enum GNUNET_BLOCK_EvaluationResult +block_plugin_gns_evaluate (void *cls, enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode * query, + struct GNUNET_CONTAINER_BloomFilter **bf, + int32_t bf_mutator, const void *xquery, + size_t xquery_size, const void *reply_block, + size_t reply_block_size) +{ + if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) + return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; + if (reply_block_size == 0) + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + + char* name; + GNUNET_HashCode pkey_hash; + GNUNET_HashCode query_key; + GNUNET_HashCode name_hash; + GNUNET_HashCode mhash; + GNUNET_HashCode chash; + struct GNSNameRecordBlock *nrb; + struct GNSRecordBlock *rb; + uint32_t rd_count; + + nrb = (struct GNSNameRecordBlock *)reply_block; + name = (char*)&nrb[1]; + GNUNET_CRYPTO_hash(&nrb->public_key, + sizeof(nrb->public_key), + &pkey_hash); + + GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); + + GNUNET_CRYPTO_hash_xor(&pkey_hash, &name_hash, &query_key); + + /* Check query key against public key */ + if (0 != GNUNET_CRYPTO_hash_cmp(query, &query_key)) + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + + rd_count = ntohl(nrb->rd_count); + + struct GNUNET_NAMESTORE_RecordData rd[rd_count]; + int i = 0; + int record_match = 0; + uint32_t record_xquery = ntohl(*((uint32_t*)xquery)); + rb = (struct GNSRecordBlock*)(&name[strlen(name) + 1]); + + for (i=0; itype); + rd[i].expiration = + GNUNET_TIME_absolute_ntoh(rb->expiration); + rd[i].data_size = ntohl(rb->data_length); + rd[i].flags = ntohl(rb->flags); + rd[i].data = (char*)&rb[1]; + rb = (struct GNSRecordBlock *)((char*)&rb[1] + rd[i].data_size); + + if (xquery_size == 0) + continue; + + if (rd[i].record_type == record_xquery) + { + record_match++; + } + } + + + /*if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature (&nrb->public_key, + name, + rd_count, + rd, + NULL)) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Signature invalid\n"); + return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; + }*/ + + //No record matches query + if ((xquery_size > 0) && (record_match == 0)) + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + + GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Records match\n"); + //FIXME do bf check before or after crypto?? + if (NULL != bf) + { + GNUNET_CRYPTO_hash(reply_block, reply_block_size, &chash); + GNUNET_BLOCK_mingle_hash(&chash, bf_mutator, &mhash); + if (NULL != *bf) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Check BF\n"); + if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test(*bf, &mhash)) + return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; + } + else + { + *bf = GNUNET_CONTAINER_bloomfilter_init(NULL, 8, BLOOMFILTER_K); + } + GNUNET_CONTAINER_bloomfilter_add(*bf, &mhash); + } + GNUNET_log(GNUNET_ERROR_TYPE_INFO, "No dup\n"); + return GNUNET_BLOCK_EVALUATION_OK_MORE; +} + + +/** + * Function called to obtain the key for a block. + * + * @param cls closure + * @param type block type + * @param block block to get the key for + * @param block_size number of bytes in block + * @param key set to the key (query) for the given block + * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported + * (or if extracting a key from a block of this type does not work) + */ +static int +block_plugin_gns_get_key (void *cls, enum GNUNET_BLOCK_Type type, + const void *block, size_t block_size, + GNUNET_HashCode * key) +{ + if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) + return GNUNET_SYSERR; + GNUNET_HashCode name_hash; + GNUNET_HashCode pkey_hash; + struct GNSNameRecordBlock *nrb = (struct GNSNameRecordBlock *)block; + + GNUNET_CRYPTO_hash(&nrb[1], strlen((char*)&nrb[1]), &name_hash); + GNUNET_CRYPTO_hash(&nrb->public_key, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &pkey_hash); + + GNUNET_CRYPTO_hash_xor(&name_hash, &pkey_hash, key); + + //FIXME calculate key from name and hash(pkey) here + return GNUNET_OK; +} + + +/** + * Entry point for the plugin. + */ +void * +libgnunet_plugin_block_gns_init (void *cls) +{ + static enum GNUNET_BLOCK_Type types[] = + { + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + GNUNET_BLOCK_TYPE_ANY /* end of list */ + }; + struct GNUNET_BLOCK_PluginFunctions *api; + + api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); + api->evaluate = &block_plugin_gns_evaluate; + api->get_key = &block_plugin_gns_get_key; + api->types = types; + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +libgnunet_plugin_block_gns_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + +/* end of plugin_block_gns.c */ diff --git a/src/gns/test_gns_twopeer.c b/src/gns/test_gns_twopeer.c new file mode 100644 index 0000000..3bd36fb --- /dev/null +++ b/src/gns/test_gns_twopeer.c @@ -0,0 +1,463 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_twopeer.c + * @brief base testcase for testing DHT service with + * two running peers. + * + * This testcase starts peers using the GNUNET_TESTING_daemons_start + * function call. On peer start, connects to the peers DHT service + * by calling GNUNET_DHT_connected. Once notified about all peers + * being started (by the peers_started_callback function), calls + * GNUNET_TESTING_connect_topology, which connects the peers in a + * "straight line" topology. On notification that all peers have + * been properly connected, calls the do_get function which initiates + * a GNUNET_DHT_get from the *second* peer. Once the GNUNET_DHT_get + * function starts, runs the do_put function to insert data at the first peer. + * If the GET is successful, schedules finish_testing + * to stop the test and shut down peers. If GET is unsuccessful + * after GET_TIMEOUT seconds, prints an error message and shuts down + * the peers. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_dht_service.h" +#include "block_dns.h" +#include "gnunet_signatures.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 40) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +/** + * Variable used to store the number of connections we should wait for. + */ +static unsigned int expected_connections; + +/** + * Variable used to keep track of how many peers aren't yet started. + */ +static unsigned long long peers_left; + +struct GNUNET_TESTING_Daemon *d1; +struct GNUNET_TESTING_Daemon *d2; + + +/** + * Total number of peers to run, set based on config file. + */ +static unsigned long long num_peers; + +/** + * Global used to count how many connections we have currently + * been notified about (how many times has topology_callback been called + * with success?) + */ +static unsigned int total_connections; + +/** + * Global used to count how many failed connections we have + * been notified about (how many times has topology_callback + * been called with failure?) + */ +static unsigned int failed_connections; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +GNUNET_SCHEDULER_TaskIdentifier bob_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +int bob_online, alice_online; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + if (ok == 0) + ok = 2; + } +} + +/** + * Function scheduled to be run on the successful completion of this + * testcase. Specifically, called when our get request completes. + */ +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + ok = 0; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); + GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &shutdown_callback, NULL, + GNUNET_YES, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer2!\n"); + GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &shutdown_callback, NULL, + GNUNET_YES, GNUNET_NO); + GNUNET_SCHEDULER_cancel(bob_task); + GNUNET_SCHEDULER_cancel(die_task); +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (d1 != NULL) + GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &shutdown_callback, NULL, + GNUNET_YES, GNUNET_NO); + if (d2 != NULL) + GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &shutdown_callback, NULL, + GNUNET_YES, GNUNET_NO); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Failing test with error: `%s'!\n", + (char *) cls); + GNUNET_SCHEDULER_cancel(bob_task); + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +static void +do_lookup(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + //do lookup here + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 30), + &finish_testing, NULL); +} + +static void +gns_started(void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (NULL != emsg) + { + if (d == d1) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNS failed to start alice\n"); + else + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNS failed to start bob\n"); + return; + } + if (d == d1) + { + /* start gns for bob */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNS started on alice\n"); + GNUNET_TESTING_daemon_start_service (d2, "gns", TIMEOUT, &gns_started, + NULL); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNS started on bob\n"); + + /* start the lookup tests */ + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), + &do_lookup, NULL); +} + +/** + * This function is called whenever a connection attempt is finished between two of + * the started peers (started with GNUNET_TESTING_daemons_start). The total + * number of times this function is called should equal the number returned + * from the GNUNET_TESTING_connect_topology call. + * + * The emsg variable is NULL on success (peers connected), and non-NULL on + * failure (peers failed to connect). + */ +void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "connected peer %s to peer %s, distance %u\n", + first_daemon->shortname, second_daemon->shortname, distance); +#endif + } +#if VERBOSE + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + } +#endif + + if (total_connections == expected_connections) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Created %d total connections, which is our target number! Starting next phase of testing.\n", + total_connections); +#endif + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from test lookup"); + + /* start gns for alice */ + GNUNET_TESTING_daemon_start_service (d1, "gns", TIMEOUT, &gns_started, NULL); + + } + else if (total_connections + failed_connections == expected_connections) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many failed connections)"); + } +} + +/** + * Set up some data, and call API PUT function + */ +static void +alice_idle (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + alice_online = 1; + if (!bob_online) + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 2), + &alice_idle, NULL); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting peers\n"); + GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, 5, 1, + ¬ify_connect, NULL); +} + +static void +bob_idle (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + /* he's lazy FIXME forever */ + bob_online = 1; + bob_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 20), + &bob_idle, NULL); +} + + + + +/** + * Callback which is called whenever a peer is started (as a result of the + * GNUNET_TESTING_daemons_start call. + * + * @param cls closure argument given to GNUNET_TESTING_daemons_start + * @param id the GNUNET_PeerIdentity of the started peer + * @param cfg the configuration for this specific peer (needed to connect + * to the DHT) + * @param d the handle to the daemon started + * @param emsg NULL if peer started, non-NULL on error + */ +static void +alice_started (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 2), + &alice_idle, NULL); +} + +static void +bob_started (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 2), + &bob_idle, NULL); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + /* Get number of peers to start from configuration (should be two) */ + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + /* Set peers_left so we know when all peers started */ + peers_left = num_peers; + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + alice_online = 0; + bob_online = 0; + expected_connections = 1; + + /* Start alice */ + d1 = GNUNET_TESTING_daemon_start(cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, + NULL, NULL, NULL, &alice_started, NULL); + + /* Somebody care to explain? */ + uint16_t port = 6000; + uint32_t upnum = 23; + uint32_t fdnum = 42; + + + /** + * Modify some config options for bob + * namely swap keys and disable dns hijacking + */ + struct GNUNET_CONFIGURATION_Handle *cfg2 = GNUNET_TESTING_create_cfg(cfg, + 23, &port, &upnum, + NULL, &fdnum); + + GNUNET_CONFIGURATION_set_value_string (cfg2, "paths", "servicehome", + "/tmp/test-gnunetd-gns-peer-2/"); + GNUNET_CONFIGURATION_set_value_string (cfg2, "gns", "HIJACK_DNS", + "NO"); + GNUNET_CONFIGURATION_set_value_string (cfg2, "gns", "ZONEKEY", + "/tmp/bobkey"); + GNUNET_CONFIGURATION_set_value_string (cfg2, "gns", "TRUSTED", + "alice:/tmp/alicekey"); + + //Start bob + d2 = GNUNET_TESTING_daemon_start(cfg2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, + NULL, NULL, NULL, &bob_started, NULL); + + +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-twopeer", /* Name to give running binary */ + "-c", + "test_gns_twopeer.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-twopeer", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-twopeer': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-twopeer", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_twopeer.conf b/src/gns/test_gns_twopeer.conf new file mode 100644 index 0000000..4048297 --- /dev/null +++ b/src/gns/test_gns_twopeer.conf @@ -0,0 +1,80 @@ +[fs] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 2100 +BINARY = gnunet-service-dht + +[block] +plugins = dht test gns + +[dhtcache] +QUOTA = 1 MB +DATABASE = sqlite + +[transport] +PLUGINS = tcp +DEBUG = NO +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +NEIGHBOUR_LIMIT = 50 +PORT = 12365 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +PORT = 12092 + +[arm] +DEFAULTSERVICES = core +PORT = 12366 +DEBUG = NO + +[transport-tcp] +TIMEOUT = 300 s +PORT = 12368 +BINDTO = 127.0.0.1 + +[TESTING] +WEAKRANDOM = YES + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[PATHS] +DEFAULTCONFIG = gns.conf +SERVICEHOME = /tmp/test-gnunetd-gns-peer-1/ + + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[dns] +AUTOSTART = YES + +[gns] +AUTOSTART = YES +BINARY = gnunet-service-gns +ZONEKEY = /tmp/alicekey + + +[nse] +AUTOSTART = NO + + diff --git a/src/gns/test_gnunet_gns.sh b/src/gns/test_gnunet_gns.sh new file mode 100755 index 0000000..cd68027 --- /dev/null +++ b/src/gns/test_gnunet_gns.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +ME=`whoami` +if [ "$ME" != "root" ] +then + echo "This test only works if run as root. Skipping." + exit 0 +fi +export PATH=".:$PATH" +gnunet-service-gns -c gns.conf & +sleep 1 +LO=`nslookup alice.gnunet | grep Address | tail -n1` +if [ "$LO" != "Address: 1.2.3.4" ] +then + echo "Fail: $LO" +fi +LO=`nslookup www.bob.gnunet | grep Address | tail -n1` +if [ "$LO" != "Address: 4.5.6.7" ] +then + echo "Fail: $LO" +fi +kill `jobs -p` diff --git a/src/hello/Makefile.am b/src/hello/Makefile.am new file mode 100644 index 0000000..1788e8f --- /dev/null +++ b/src/hello/Makefile.am @@ -0,0 +1,34 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +lib_LTLIBRARIES = libgnunethello.la + +libgnunethello_la_SOURCES = \ + hello.c address.c +libgnunethello_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +libgnunethello_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +check_PROGRAMS = \ + test_hello + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_hello_SOURCES = \ + test_hello.c +test_hello_LDADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la + diff --git a/src/hello/Makefile.in b/src/hello/Makefile.in new file mode 100644 index 0000000..283d209 --- /dev/null +++ b/src/hello/Makefile.in @@ -0,0 +1,779 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +check_PROGRAMS = test_hello$(EXEEXT) +subdir = src/hello +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunethello_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunethello_la_OBJECTS = hello.lo address.lo +libgnunethello_la_OBJECTS = $(am_libgnunethello_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunethello_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunethello_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +am_test_hello_OBJECTS = test_hello.$(OBJEXT) +test_hello_OBJECTS = $(am_test_hello_OBJECTS) +test_hello_DEPENDENCIES = $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunethello_la_SOURCES) $(test_hello_SOURCES) +DIST_SOURCES = $(libgnunethello_la_SOURCES) $(test_hello_SOURCES) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +lib_LTLIBRARIES = libgnunethello.la +libgnunethello_la_SOURCES = \ + hello.c address.c + +libgnunethello_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) + +libgnunethello_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_hello_SOURCES = \ + test_hello.c + +test_hello_LDADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/hello/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/hello/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunethello.la: $(libgnunethello_la_OBJECTS) $(libgnunethello_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunethello_la_LINK) -rpath $(libdir) $(libgnunethello_la_OBJECTS) $(libgnunethello_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +test_hello$(EXEEXT): $(test_hello_OBJECTS) $(test_hello_DEPENDENCIES) + @rm -f test_hello$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_hello_OBJECTS) $(test_hello_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/address.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hello.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_hello.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-libLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/hello/address.c b/src/hello/address.c new file mode 100644 index 0000000..893a6dc --- /dev/null +++ b/src/hello/address.c @@ -0,0 +1,120 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file hello/address.c + * @brief helper functions for handling addresses + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_hello_lib.h" +#include "gnunet_util_lib.h" + + +/** + * Allocate an address struct. + * + * @param peer the peer + * @param transport_name plugin name + * @param address binary address + * @param address_length number of bytes in 'address' + * @return the address struct + */ +struct GNUNET_HELLO_Address * +GNUNET_HELLO_address_allocate (const struct GNUNET_PeerIdentity *peer, + const char *transport_name, const void *address, + size_t address_length) +{ + struct GNUNET_HELLO_Address *addr; + size_t slen; + char *end; + + GNUNET_assert (transport_name != NULL); + + slen = strlen (transport_name) + 1; + addr = + GNUNET_malloc (sizeof (struct GNUNET_HELLO_Address) + address_length + + slen); + addr->peer = *peer; + addr->address = &addr[1]; + end = (char *) &addr[1]; + memcpy (end, address, address_length); + addr->address_length = address_length; + addr->transport_name = &end[address_length]; + memcpy (&end[address_length], transport_name, slen); + return addr; +} + + +/** + * Get the size of an address struct. + * + * @param address address + * @return the size + */ +size_t +GNUNET_HELLO_address_get_size (const struct GNUNET_HELLO_Address * address) +{ + return sizeof (struct GNUNET_HELLO_Address) + address->address_length + + strlen (address->transport_name) + 1; +} + + +/** + * Copy an address struct. + * + * @param address address to copy + * @return a copy of the address struct + */ +struct GNUNET_HELLO_Address * +GNUNET_HELLO_address_copy (const struct GNUNET_HELLO_Address *address) +{ + return GNUNET_HELLO_address_allocate (&address->peer, address->transport_name, + address->address, + address->address_length); +} + + +/** + * Compare two addresses. Does NOT compare the peer identity, + * that is assumed already to match! + * + * @param a1 first address + * @param a2 second address + * @return 0 if the addresses are equal, -1 if a1a2. + */ +int +GNUNET_HELLO_address_cmp (const struct GNUNET_HELLO_Address *a1, + const struct GNUNET_HELLO_Address *a2) +{ + int ret; + + ret = strcmp (a1->transport_name, a2->transport_name); + if (0 != ret) + return ret; + if (a1->address_length < a2->address_length) + return -1; + if (a1->address_length > a2->address_length) + return 1; + return memcmp (a1->address, a1->address, a1->address_length); +} + + +/* end of address.c */ diff --git a/src/hello/hello.c b/src/hello/hello.c new file mode 100644 index 0000000..7aa9740 --- /dev/null +++ b/src/hello/hello.c @@ -0,0 +1,645 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file hello/hello.c + * @brief helper library for handling HELLOs + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_util_lib.h" + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * A HELLO message is used to exchange information about + * transports with other peers. This struct is always + * followed by the actual network addresses which have + * the format: + * + * 1) transport-name (0-terminated) + * 2) address-length (uint16_t, network byte order; possibly + * unaligned!) + * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly + * unaligned!) + * 4) address (address-length bytes; possibly unaligned!) + */ +struct GNUNET_HELLO_Message +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_HELLO. + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero (for alignment). + */ + uint32_t reserved GNUNET_PACKED; + + /** + * The public key of the peer. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey; + +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Copy the given address information into + * the given buffer using the format of HELLOs. + * + * @param address the address + * @param expiration expiration for the address + * @param target where to copy the address + * @param max maximum number of bytes to copy to target + * @return number of bytes copied, 0 if + * the target buffer was not big enough. + */ +size_t +GNUNET_HELLO_add_address (const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration, char *target, + size_t max) +{ + uint16_t alen; + size_t slen; + struct GNUNET_TIME_AbsoluteNBO exp; + + slen = strlen (address->transport_name) + 1; + if (slen + sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + + address->address_length > max) + return 0; + exp = GNUNET_TIME_absolute_hton (expiration); + alen = htons ((uint16_t) address->address_length); + memcpy (target, address->transport_name, slen); + memcpy (&target[slen], &alen, sizeof (uint16_t)); + slen += sizeof (uint16_t); + memcpy (&target[slen], &exp, sizeof (struct GNUNET_TIME_AbsoluteNBO)); + slen += sizeof (struct GNUNET_TIME_AbsoluteNBO); + memcpy (&target[slen], address->address, address->address_length); + slen += address->address_length; + return slen; +} + + +/** + * Get the size of an address entry in a HELLO message. + * + * @param buf pointer to the start of the address entry + * @param max maximum size of the entry (end of buf) + * @param ralen set to the address length + * @return size of the entry, or 0 if max is not large enough + */ +static size_t +get_hello_address_size (const char *buf, size_t max, uint16_t * ralen) +{ + const char *pos; + uint16_t alen; + size_t left; + size_t slen; + + left = max; + pos = buf; + slen = 1; + while ((left > 0) && ('\0' != *pos)) + { + left--; + pos++; + slen++; + } + if (left == 0) + { + /* 0-termination not found */ + GNUNET_break_op (0); + return 0; + } + pos++; + if (left < sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO)) + { + /* not enough space for addrlen */ + GNUNET_break_op (0); + return 0; + } + memcpy (&alen, pos, sizeof (uint16_t)); + alen = ntohs (alen); + *ralen = alen; + slen += alen + sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO); + if (max < slen) + { + /* not enough space for addr */ + GNUNET_break_op (0); + return 0; + } + return slen; +} + + +/** + * Construct a HELLO message given the public key, + * expiration time and an iterator that spews the + * transport addresses. + * + * @return the hello message + */ +struct GNUNET_HELLO_Message * +GNUNET_HELLO_create (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *publicKey, + GNUNET_HELLO_GenerateAddressListCallback addrgen, + void *addrgen_cls) +{ + char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - 256 - + sizeof (struct GNUNET_HELLO_Message)]; + size_t max; + size_t used; + size_t ret; + struct GNUNET_HELLO_Message *hello; + + max = sizeof (buffer); + used = 0; + if (addrgen != NULL) + { + while (0 != (ret = addrgen (addrgen_cls, max, &buffer[used]))) + { + max -= ret; + used += ret; + } + } + hello = GNUNET_malloc (sizeof (struct GNUNET_HELLO_Message) + used); + hello->header.type = htons (GNUNET_MESSAGE_TYPE_HELLO); + hello->header.size = htons (sizeof (struct GNUNET_HELLO_Message) + used); + memcpy (&hello->publicKey, publicKey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + memcpy (&hello[1], buffer, used); + return hello; +} + + +/** + * Iterate over all of the addresses in the HELLO. + * + * @param msg HELLO to iterate over + * @param return_modified if a modified copy should be returned, + * otherwise NULL will be returned + * @param it iterator to call on each address + * @param it_cls closure for it + */ +struct GNUNET_HELLO_Message * +GNUNET_HELLO_iterate_addresses (const struct GNUNET_HELLO_Message *msg, + int return_modified, + GNUNET_HELLO_AddressIterator it, void *it_cls) +{ + struct GNUNET_HELLO_Address address; + uint16_t msize; + struct GNUNET_HELLO_Message *ret; + const char *inptr; + size_t insize; + size_t esize; + size_t wpos; + char *woff; + uint16_t alen; + struct GNUNET_TIME_AbsoluteNBO expire; + int iret; + + msize = GNUNET_HELLO_size (msg); + if ((msize < sizeof (struct GNUNET_HELLO_Message)) || + (ntohs (msg->header.type) != GNUNET_MESSAGE_TYPE_HELLO)) + return NULL; + ret = NULL; + if (return_modified) + { + ret = GNUNET_malloc (msize); + memcpy (ret, msg, msize); + } + inptr = (const char *) &msg[1]; + insize = msize - sizeof (struct GNUNET_HELLO_Message); + wpos = 0; + woff = (ret != NULL) ? (char *) &ret[1] : NULL; + GNUNET_CRYPTO_hash (&msg->publicKey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &address.peer.hashPubKey); + while (insize > 0) + { + esize = get_hello_address_size (inptr, insize, &alen); + if (esize == 0) + { + GNUNET_break (0); + GNUNET_free_non_null (ret); + return NULL; + } + memcpy (&expire, + &inptr[esize - alen - sizeof (struct GNUNET_TIME_AbsoluteNBO)], + sizeof (struct GNUNET_TIME_AbsoluteNBO)); + address.address = &inptr[esize - alen]; + address.address_length = alen; + address.transport_name = inptr; + iret = it (it_cls, &address, GNUNET_TIME_absolute_ntoh (expire)); + if (iret == GNUNET_SYSERR) + { + if (ret != NULL) + ret->header.size = ntohs (sizeof (struct GNUNET_HELLO_Message) + wpos); + return ret; + } + if ((iret == GNUNET_OK) && (ret != NULL)) + { + memcpy (woff, inptr, esize); + woff += esize; + wpos += esize; + } + insize -= esize; + inptr += esize; + } + if (ret != NULL) + ret->header.size = ntohs (sizeof (struct GNUNET_HELLO_Message) + wpos); + return ret; +} + + +struct ExpireContext +{ + const struct GNUNET_HELLO_Address *address; + int found; + struct GNUNET_TIME_Absolute expiration; +}; + + +static int +get_match_exp (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + struct ExpireContext *ec = cls; + + if (0 == GNUNET_HELLO_address_cmp (address, ec->address)) + { + ec->found = GNUNET_YES; + ec->expiration = expiration; + return GNUNET_SYSERR; /* done here */ + } + return GNUNET_OK; +} + + +struct MergeContext +{ + const struct GNUNET_HELLO_Message *h1; + const struct GNUNET_HELLO_Message *h2; + const struct GNUNET_HELLO_Message *other; + char *buf; + size_t max; + size_t ret; + int take_equal; + +}; + + +static int +copy_latest (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + struct MergeContext *mc = cls; + struct ExpireContext ec; + + ec.address = address; + ec.found = GNUNET_NO; + GNUNET_HELLO_iterate_addresses (mc->other, GNUNET_NO, &get_match_exp, &ec); + if ((ec.found == GNUNET_NO) || + (ec.expiration.abs_value < expiration.abs_value) || + ((ec.expiration.abs_value == expiration.abs_value) && + (mc->take_equal == GNUNET_YES))) + { + mc->ret += + GNUNET_HELLO_add_address (address, expiration, &mc->buf[mc->ret], + mc->max - mc->ret); + } + return GNUNET_OK; +} + + +static size_t +merge_addr (void *cls, size_t max, void *buf) +{ + struct MergeContext *mc = cls; + + if (mc->h1 == NULL) + return 0; + mc->ret = 0; + mc->max = max; + mc->buf = buf; + mc->take_equal = GNUNET_NO; + mc->other = mc->h2; + GNUNET_HELLO_iterate_addresses (mc->h1, GNUNET_NO, ©_latest, mc); + mc->take_equal = GNUNET_YES; + mc->other = mc->h1; + GNUNET_HELLO_iterate_addresses (mc->h2, GNUNET_NO, ©_latest, mc); + mc->h1 = NULL; + return mc->ret; +} + + +/** + * Construct a HELLO message by merging the + * addresses in two existing HELLOs (which + * must be for the same peer). + * + * @param h1 first HELLO message + * @param h2 the second HELLO message + * @return the combined hello message + */ +struct GNUNET_HELLO_Message * +GNUNET_HELLO_merge (const struct GNUNET_HELLO_Message *h1, + const struct GNUNET_HELLO_Message *h2) +{ + struct MergeContext mc = { h1, h2, NULL, NULL, 0, 0, 0 }; + + return GNUNET_HELLO_create (&h1->publicKey, &merge_addr, &mc); +} + + +struct DeltaContext +{ + struct GNUNET_TIME_Absolute expiration_limit; + + GNUNET_HELLO_AddressIterator it; + + void *it_cls; + + const struct GNUNET_HELLO_Message *old_hello; +}; + + +static int +delta_match (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + struct DeltaContext *dc = cls; + int ret; + struct ExpireContext ec; + + ec.address = address; + ec.found = GNUNET_NO; + GNUNET_HELLO_iterate_addresses (dc->old_hello, GNUNET_NO, &get_match_exp, + &ec); + if ((ec.found == GNUNET_YES) && + ((ec.expiration.abs_value > expiration.abs_value) || + (ec.expiration.abs_value >= dc->expiration_limit.abs_value))) + return GNUNET_YES; /* skip */ + ret = dc->it (dc->it_cls, address, expiration); + return ret; +} + + +/** + * Iterate over addresses in "new_hello" that + * are NOT already present in "old_hello". + * + * @param new_hello a HELLO message + * @param old_hello a HELLO message + * @param expiration_limit ignore addresses in old_hello + * that expired before the given time stamp + * @param it iterator to call on each address + * @param it_cls closure for it + */ +void +GNUNET_HELLO_iterate_new_addresses (const struct GNUNET_HELLO_Message + *new_hello, + const struct GNUNET_HELLO_Message + *old_hello, + struct GNUNET_TIME_Absolute + expiration_limit, + GNUNET_HELLO_AddressIterator it, + void *it_cls) +{ + struct DeltaContext dc; + + dc.expiration_limit = expiration_limit; + dc.it = it; + dc.it_cls = it_cls; + dc.old_hello = old_hello; + GNUNET_HELLO_iterate_addresses (new_hello, GNUNET_NO, &delta_match, &dc); +} + + +/** + * Return the size of the given HELLO message. + * @param hello to inspect + * @return the size, 0 if HELLO is invalid + */ +uint16_t +GNUNET_HELLO_size (const struct GNUNET_HELLO_Message *hello) +{ + uint16_t ret = ntohs (hello->header.size); + + if ((ret < sizeof (struct GNUNET_HELLO_Message)) || + (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO)) + return 0; + return ret; +} + + +/** + * Get the public key from a HELLO message. + * + * @param hello the hello message + * @param publicKey where to copy the public key information, can be NULL + * @return GNUNET_SYSERR if the HELLO was malformed + */ +int +GNUNET_HELLO_get_key (const struct GNUNET_HELLO_Message *hello, + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey) +{ + uint16_t ret = ntohs (hello->header.size); + + if ((ret < sizeof (struct GNUNET_HELLO_Message)) || + (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO)) + return GNUNET_SYSERR; + *publicKey = hello->publicKey; + return GNUNET_OK; +} + + +/** + * Get the peer identity from a HELLO message. + * + * @param hello the hello message + * @param peer where to store the peer's identity + * @return GNUNET_SYSERR if the HELLO was malformed + */ +int +GNUNET_HELLO_get_id (const struct GNUNET_HELLO_Message *hello, + struct GNUNET_PeerIdentity *peer) +{ + uint16_t ret = ntohs (hello->header.size); + + if ((ret < sizeof (struct GNUNET_HELLO_Message)) || + (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO)) + return GNUNET_SYSERR; + GNUNET_CRYPTO_hash (&hello->publicKey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &peer->hashPubKey); + return GNUNET_OK; +} + + +/** + * Get the header from a HELLO message, used so other code + * can correctly send HELLO messages. + * + * @param hello the hello message + * + * @return header or NULL if the HELLO was malformed + */ +struct GNUNET_MessageHeader * +GNUNET_HELLO_get_header (struct GNUNET_HELLO_Message *hello) +{ + uint16_t ret = ntohs (hello->header.size); + + if ((ret < sizeof (struct GNUNET_HELLO_Message)) || + (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO)) + return NULL; + + return &hello->header; +} + + +struct EqualsContext +{ + struct GNUNET_TIME_Absolute expiration_limit; + + struct GNUNET_TIME_Absolute result; + + const struct GNUNET_HELLO_Message *h2; + + const struct GNUNET_HELLO_Address *address; + + struct GNUNET_TIME_Absolute expiration; + + int found; + +}; + + +static int +find_other_matching (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + struct EqualsContext *ec = cls; + + if (expiration.abs_value < ec->expiration_limit.abs_value) + return GNUNET_YES; + if (0 == GNUNET_HELLO_address_cmp (address, ec->address)) + { + ec->found = GNUNET_YES; + if (expiration.abs_value < ec->expiration.abs_value) + ec->result = GNUNET_TIME_absolute_min (expiration, ec->result); + return GNUNET_SYSERR; + } + return GNUNET_YES; +} + + +static int +find_matching (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + struct EqualsContext *ec = cls; + + if (expiration.abs_value < ec->expiration_limit.abs_value) + return GNUNET_YES; + ec->address = address; + ec->expiration = expiration; + ec->found = GNUNET_NO; + GNUNET_HELLO_iterate_addresses (ec->h2, GNUNET_NO, &find_other_matching, ec); + if (ec->found == GNUNET_NO) + { + ec->result = GNUNET_TIME_UNIT_ZERO_ABS; + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Test if two HELLO messages contain the same addresses. + * If they only differ in expiration time, the lowest + * expiration time larger than 'now' where they differ + * is returned. + * + * @param h1 first HELLO message + * @param h2 the second HELLO message + * @param now time to use for deciding which addresses have + * expired and should not be considered at all + * @return absolute time forever if the two HELLOs are + * totally identical; smallest timestamp >= now if + * they only differ in timestamps; + * zero if the some addresses with expirations >= now + * do not match at all + */ +struct GNUNET_TIME_Absolute +GNUNET_HELLO_equals (const struct GNUNET_HELLO_Message *h1, + const struct GNUNET_HELLO_Message *h2, + struct GNUNET_TIME_Absolute now) +{ + struct EqualsContext ec; + + if (0 != + memcmp (&h1->publicKey, &h2->publicKey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) + return GNUNET_TIME_UNIT_ZERO_ABS; + ec.expiration_limit = now; + ec.result = GNUNET_TIME_UNIT_FOREVER_ABS; + ec.h2 = h2; + GNUNET_HELLO_iterate_addresses (h1, GNUNET_NO, &find_matching, &ec); + if (ec.result.abs_value == GNUNET_TIME_UNIT_ZERO.rel_value) + return ec.result; + ec.h2 = h1; + GNUNET_HELLO_iterate_addresses (h2, GNUNET_NO, &find_matching, &ec); + return ec.result; +} + + +static int +find_min_expire (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + struct GNUNET_TIME_Absolute *min = cls; + + *min = GNUNET_TIME_absolute_min (*min, expiration); + return GNUNET_OK; +} + + +/** + * When does the last address in the given HELLO expire? + * + * @param msg HELLO to inspect + * @return time the last address expires, 0 if there are no addresses in the HELLO + */ +struct GNUNET_TIME_Absolute +GNUNET_HELLO_get_last_expiration (const struct GNUNET_HELLO_Message *msg) +{ + struct GNUNET_TIME_Absolute ret; + + ret.abs_value = 0; + GNUNET_HELLO_iterate_addresses (msg, GNUNET_NO, &find_min_expire, &ret); + return ret; +} + + +/* end of hello.c */ diff --git a/src/hello/test_hello.c b/src/hello/test_hello.c new file mode 100644 index 0000000..0efbdee --- /dev/null +++ b/src/hello/test_hello.c @@ -0,0 +1,205 @@ +/* + This file is part of GNUnet + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file hello/test_hello.c + * @brief test for hello.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_hello_lib.h" + +#define DEBUG GNUNET_EXTRA_LOGGING + +#define VERBOSE GNUNET_NO + + +static size_t +my_addr_gen (void *cls, size_t max, void *buf) +{ + unsigned int *i = cls; + size_t ret; + struct GNUNET_HELLO_Address address; + +#if DEBUG + FPRINTF (stderr, "DEBUG: my_addr_gen called with i = %d\n", *i); +#endif + if (0 == *i) + return 0; + memset (&address.peer, 0, sizeof (struct GNUNET_PeerIdentity)); + address.address = "address_information"; + address.transport_name = "test"; + address.address_length = *i; + ret = + GNUNET_HELLO_add_address (&address, GNUNET_TIME_absolute_get (), buf, + max); + (*i)--; + return ret; +} + + +static int +check_addr (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + unsigned int *i = cls; + +#if DEBUG + FPRINTF (stderr, "DEBUG: check_addr called with i = %d and addrlen = %u\n", + *i, (unsigned int) address->address_length); +#endif + GNUNET_assert (address->address_length > 0); + GNUNET_assert (*i & (1 << (address->address_length - 1))); + *i -= (1 << (address->address_length - 1)); + GNUNET_assert (0 == + strncmp ("address_information", address->address, + address->address_length)); + GNUNET_assert (0 == strcmp ("test", address->transport_name)); + return GNUNET_OK; +} + + +static int +remove_some (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + unsigned int *i = cls; + +#if DEBUG + FPRINTF (stderr, "DEBUG: remove_some called with i = %d and addrlen = %u\n", + *i, (unsigned int) address->address_length); +#endif + GNUNET_assert (address->address_length > 0); + if (*i & (1 << (address->address_length - 1))) + { + *i -= (1 << (address->address_length - 1)); + return GNUNET_NO; + } + return GNUNET_OK; +} + + +int +main (int argc, char *argv[]) +{ + struct GNUNET_HELLO_Message *msg1; + struct GNUNET_HELLO_Message *msg2; + struct GNUNET_HELLO_Message *msg3; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk; + struct GNUNET_TIME_Absolute startup_time; + unsigned int i; + + GNUNET_log_setup ("test-hello", "DEBUG", NULL); + startup_time = GNUNET_TIME_absolute_get (); + memset (&publicKey, 42, sizeof (publicKey)); +#if VERBOSE + FPRINTF (stderr, "%s", "Testing HELLO creation (without addresses)...\n"); +#endif + i = 0; + msg1 = GNUNET_HELLO_create (&publicKey, &my_addr_gen, &i); + GNUNET_assert (msg1 != NULL); + GNUNET_assert (0 < GNUNET_HELLO_size (msg1)); + +#if VERBOSE + FPRINTF (stderr, "%s", "Testing address iteration (empty set)...\n"); +#endif + GNUNET_assert (NULL == + GNUNET_HELLO_iterate_addresses (msg1, GNUNET_NO, &check_addr, + &i)); + +#if VERBOSE + FPRINTF (stderr, "%s", "Testing HELLO creation (with one address)...\n"); +#endif + i = 1; + msg2 = GNUNET_HELLO_create (&publicKey, &my_addr_gen, &i); + GNUNET_assert (msg2 != NULL); + GNUNET_assert (GNUNET_HELLO_size (msg1) < GNUNET_HELLO_size (msg2)); + +#if VERBOSE + FPRINTF (stderr, "%s", "Testing address iteration (one address)...\n"); +#endif + i = 1; + GNUNET_assert (NULL == + GNUNET_HELLO_iterate_addresses (msg2, GNUNET_NO, &check_addr, + &i)); + GNUNET_assert (i == 0); + +#if VERBOSE + FPRINTF (stderr, "%s", "Testing get_key from HELLO...\n"); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_key (msg2, &pk)); + GNUNET_assert (0 == memcmp (&publicKey, &pk, sizeof (pk))); + GNUNET_free (msg1); + +#if VERBOSE + FPRINTF (stderr, "%s", "Testing HELLO creation (with two addresses)...\n"); +#endif + i = 2; + msg3 = GNUNET_HELLO_create (&publicKey, &my_addr_gen, &i); + GNUNET_assert (msg3 != NULL); + GNUNET_assert (GNUNET_HELLO_size (msg2) < GNUNET_HELLO_size (msg3)); + +#if VERBOSE + FPRINTF (stderr, "%s", "Testing address iteration (two addresses)...\n"); +#endif + i = 3; + GNUNET_assert (NULL == + GNUNET_HELLO_iterate_addresses (msg3, GNUNET_NO, &check_addr, + &i)); + GNUNET_assert (i == 0); + +#if VERBOSE + FPRINTF (stderr, "%s", "Testing HELLO merge...\n"); +#endif + msg1 = GNUNET_HELLO_merge (msg2, msg3); + GNUNET_assert (GNUNET_HELLO_size (msg1) == GNUNET_HELLO_size (msg3)); + + i = 3; + GNUNET_assert (NULL == + GNUNET_HELLO_iterate_addresses (msg1, GNUNET_NO, &check_addr, + &i)); + GNUNET_assert (i == 0); + GNUNET_free (msg1); + +#if VERBOSE + FPRINTF (stderr, "%s", "Testing address iteration to copy HELLO...\n"); +#endif + i = 2; + msg1 = GNUNET_HELLO_iterate_addresses (msg3, GNUNET_YES, &remove_some, &i); + GNUNET_assert (msg1 != NULL); + GNUNET_assert (i == 0); + i = 1; + GNUNET_assert (NULL == + GNUNET_HELLO_iterate_addresses (msg1, GNUNET_NO, &check_addr, + &i)); + GNUNET_assert (i == 0); + GNUNET_free (msg1); + +#if VERBOSE + FPRINTF (stderr, "%s", "Testing delta address iteration...\n"); +#endif + i = 2; + GNUNET_HELLO_iterate_new_addresses (msg3, msg2, startup_time, &check_addr, + &i); + GNUNET_assert (i == 0); + GNUNET_free (msg2); + GNUNET_free (msg3); + return 0; /* testcase passed */ +} diff --git a/src/hostlist/Makefile.am b/src/hostlist/Makefile.am new file mode 100644 index 0000000..f764f2f --- /dev/null +++ b/src/hostlist/Makefile.am @@ -0,0 +1,81 @@ +INCLUDES = -I$(top_srcdir)/src/include + +pkgcfgdir= $(pkgdatadir)/config.d/ + +dist_pkgcfg_DATA = \ + hostlist.conf + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 +endif + +if HAVE_MHD + HOSTLIST_SERVER_SOURCES = hostlist-server.c hostlist-server.h + GN_LIBMHD = -lmicrohttpd +endif + +bin_PROGRAMS = \ + gnunet-daemon-hostlist + +gnunet_daemon_hostlist_SOURCES = \ + gnunet-daemon-hostlist.c gnunet-daemon-hostlist.h \ + hostlist-client.c hostlist-client.h \ + $(HOSTLIST_SERVER_SOURCES) + +gnunet_daemon_hostlist_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBMHD) \ + @LIBCURL@ \ + $(GN_LIBINTL) + +gnunet_daemon_hostlist_CPPFLAGS = \ + @LIBCURL_CPPFLAGS@ + +check_PROGRAMS = \ + test_gnunet_daemon_hostlist \ + test_gnunet_daemon_hostlist_reconnect \ + test_gnunet_daemon_hostlist_learning + +if HAVE_MHD +if ENABLE_TEST_RUN +TESTS = \ + test_gnunet_daemon_hostlist \ + test_gnunet_daemon_hostlist_reconnect \ + test_gnunet_daemon_hostlist_learning +endif +endif + +test_gnunet_daemon_hostlist_SOURCES = \ + test_gnunet_daemon_hostlist.c +test_gnunet_daemon_hostlist_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_daemon_hostlist_reconnect_SOURCES = \ + test_gnunet_daemon_hostlist_reconnect.c +test_gnunet_daemon_hostlist_reconnect_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_daemon_hostlist_learning_SOURCES = \ + test_gnunet_daemon_hostlist_learning.c +test_gnunet_daemon_hostlist_learning_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_hostlist_defaults.conf \ + test_gnunet_daemon_hostlist_data.conf \ + test_gnunet_daemon_hostlist_peer1.conf \ + test_gnunet_daemon_hostlist_peer2.conf \ + test_learning_adv_peer.conf \ + test_learning_learn_peer.conf \ + test_learning_learn_peer2.conf \ + learning_data.conf diff --git a/src/hostlist/Makefile.in b/src/hostlist/Makefile.in new file mode 100644 index 0000000..737e87c --- /dev/null +++ b/src/hostlist/Makefile.in @@ -0,0 +1,949 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-daemon-hostlist$(EXEEXT) +check_PROGRAMS = test_gnunet_daemon_hostlist$(EXEEXT) \ + test_gnunet_daemon_hostlist_reconnect$(EXEEXT) \ + test_gnunet_daemon_hostlist_learning$(EXEEXT) +@ENABLE_TEST_RUN_TRUE@@HAVE_MHD_TRUE@TESTS = test_gnunet_daemon_hostlist$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@@HAVE_MHD_TRUE@ test_gnunet_daemon_hostlist_reconnect$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@@HAVE_MHD_TRUE@ test_gnunet_daemon_hostlist_learning$(EXEEXT) +subdir = src/hostlist +DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +PROGRAMS = $(bin_PROGRAMS) +am__gnunet_daemon_hostlist_SOURCES_DIST = gnunet-daemon-hostlist.c \ + gnunet-daemon-hostlist.h hostlist-client.c hostlist-client.h \ + hostlist-server.c hostlist-server.h +@HAVE_MHD_TRUE@am__objects_1 = gnunet_daemon_hostlist-hostlist-server.$(OBJEXT) +am_gnunet_daemon_hostlist_OBJECTS = \ + gnunet_daemon_hostlist-gnunet-daemon-hostlist.$(OBJEXT) \ + gnunet_daemon_hostlist-hostlist-client.$(OBJEXT) \ + $(am__objects_1) +gnunet_daemon_hostlist_OBJECTS = $(am_gnunet_daemon_hostlist_OBJECTS) +am__DEPENDENCIES_1 = +gnunet_daemon_hostlist_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am_test_gnunet_daemon_hostlist_OBJECTS = \ + test_gnunet_daemon_hostlist.$(OBJEXT) +test_gnunet_daemon_hostlist_OBJECTS = \ + $(am_test_gnunet_daemon_hostlist_OBJECTS) +test_gnunet_daemon_hostlist_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_gnunet_daemon_hostlist_learning_OBJECTS = \ + test_gnunet_daemon_hostlist_learning.$(OBJEXT) +test_gnunet_daemon_hostlist_learning_OBJECTS = \ + $(am_test_gnunet_daemon_hostlist_learning_OBJECTS) +test_gnunet_daemon_hostlist_learning_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_gnunet_daemon_hostlist_reconnect_OBJECTS = \ + test_gnunet_daemon_hostlist_reconnect.$(OBJEXT) +test_gnunet_daemon_hostlist_reconnect_OBJECTS = \ + $(am_test_gnunet_daemon_hostlist_reconnect_OBJECTS) +test_gnunet_daemon_hostlist_reconnect_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(gnunet_daemon_hostlist_SOURCES) \ + $(test_gnunet_daemon_hostlist_SOURCES) \ + $(test_gnunet_daemon_hostlist_learning_SOURCES) \ + $(test_gnunet_daemon_hostlist_reconnect_SOURCES) +DIST_SOURCES = $(am__gnunet_daemon_hostlist_SOURCES_DIST) \ + $(test_gnunet_daemon_hostlist_SOURCES) \ + $(test_gnunet_daemon_hostlist_learning_SOURCES) \ + $(test_gnunet_daemon_hostlist_reconnect_SOURCES) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +DATA = $(dist_pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +pkgcfgdir = $(pkgdatadir)/config.d/ +dist_pkgcfg_DATA = \ + hostlist.conf + +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@HAVE_MHD_TRUE@HOSTLIST_SERVER_SOURCES = hostlist-server.c hostlist-server.h +@HAVE_MHD_TRUE@GN_LIBMHD = -lmicrohttpd +gnunet_daemon_hostlist_SOURCES = \ + gnunet-daemon-hostlist.c gnunet-daemon-hostlist.h \ + hostlist-client.c hostlist-client.h \ + $(HOSTLIST_SERVER_SOURCES) + +gnunet_daemon_hostlist_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBMHD) \ + @LIBCURL@ \ + $(GN_LIBINTL) + +gnunet_daemon_hostlist_CPPFLAGS = \ + @LIBCURL_CPPFLAGS@ + +test_gnunet_daemon_hostlist_SOURCES = \ + test_gnunet_daemon_hostlist.c + +test_gnunet_daemon_hostlist_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_daemon_hostlist_reconnect_SOURCES = \ + test_gnunet_daemon_hostlist_reconnect.c + +test_gnunet_daemon_hostlist_reconnect_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_daemon_hostlist_learning_SOURCES = \ + test_gnunet_daemon_hostlist_learning.c + +test_gnunet_daemon_hostlist_learning_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_hostlist_defaults.conf \ + test_gnunet_daemon_hostlist_data.conf \ + test_gnunet_daemon_hostlist_peer1.conf \ + test_gnunet_daemon_hostlist_peer2.conf \ + test_learning_adv_peer.conf \ + test_learning_learn_peer.conf \ + test_learning_learn_peer2.conf \ + learning_data.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/hostlist/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/hostlist/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-daemon-hostlist$(EXEEXT): $(gnunet_daemon_hostlist_OBJECTS) $(gnunet_daemon_hostlist_DEPENDENCIES) + @rm -f gnunet-daemon-hostlist$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_daemon_hostlist_OBJECTS) $(gnunet_daemon_hostlist_LDADD) $(LIBS) +test_gnunet_daemon_hostlist$(EXEEXT): $(test_gnunet_daemon_hostlist_OBJECTS) $(test_gnunet_daemon_hostlist_DEPENDENCIES) + @rm -f test_gnunet_daemon_hostlist$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_hostlist_OBJECTS) $(test_gnunet_daemon_hostlist_LDADD) $(LIBS) +test_gnunet_daemon_hostlist_learning$(EXEEXT): $(test_gnunet_daemon_hostlist_learning_OBJECTS) $(test_gnunet_daemon_hostlist_learning_DEPENDENCIES) + @rm -f test_gnunet_daemon_hostlist_learning$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_hostlist_learning_OBJECTS) $(test_gnunet_daemon_hostlist_learning_LDADD) $(LIBS) +test_gnunet_daemon_hostlist_reconnect$(EXEEXT): $(test_gnunet_daemon_hostlist_reconnect_OBJECTS) $(test_gnunet_daemon_hostlist_reconnect_DEPENDENCIES) + @rm -f test_gnunet_daemon_hostlist_reconnect$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_hostlist_reconnect_OBJECTS) $(test_gnunet_daemon_hostlist_reconnect_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_hostlist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_hostlist_learning.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_hostlist_reconnect.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +gnunet_daemon_hostlist-gnunet-daemon-hostlist.o: gnunet-daemon-hostlist.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-gnunet-daemon-hostlist.o -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.o `test -f 'gnunet-daemon-hostlist.c' || echo '$(srcdir)/'`gnunet-daemon-hostlist.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gnunet-daemon-hostlist.c' object='gnunet_daemon_hostlist-gnunet-daemon-hostlist.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.o `test -f 'gnunet-daemon-hostlist.c' || echo '$(srcdir)/'`gnunet-daemon-hostlist.c + +gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj: gnunet-daemon-hostlist.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj `if test -f 'gnunet-daemon-hostlist.c'; then $(CYGPATH_W) 'gnunet-daemon-hostlist.c'; else $(CYGPATH_W) '$(srcdir)/gnunet-daemon-hostlist.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gnunet-daemon-hostlist.c' object='gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj `if test -f 'gnunet-daemon-hostlist.c'; then $(CYGPATH_W) 'gnunet-daemon-hostlist.c'; else $(CYGPATH_W) '$(srcdir)/gnunet-daemon-hostlist.c'; fi` + +gnunet_daemon_hostlist-hostlist-client.o: hostlist-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-client.o -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo -c -o gnunet_daemon_hostlist-hostlist-client.o `test -f 'hostlist-client.c' || echo '$(srcdir)/'`hostlist-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-client.c' object='gnunet_daemon_hostlist-hostlist-client.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-client.o `test -f 'hostlist-client.c' || echo '$(srcdir)/'`hostlist-client.c + +gnunet_daemon_hostlist-hostlist-client.obj: hostlist-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-client.obj -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo -c -o gnunet_daemon_hostlist-hostlist-client.obj `if test -f 'hostlist-client.c'; then $(CYGPATH_W) 'hostlist-client.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-client.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-client.c' object='gnunet_daemon_hostlist-hostlist-client.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-client.obj `if test -f 'hostlist-client.c'; then $(CYGPATH_W) 'hostlist-client.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-client.c'; fi` + +gnunet_daemon_hostlist-hostlist-server.o: hostlist-server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-server.o -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo -c -o gnunet_daemon_hostlist-hostlist-server.o `test -f 'hostlist-server.c' || echo '$(srcdir)/'`hostlist-server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-server.c' object='gnunet_daemon_hostlist-hostlist-server.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-server.o `test -f 'hostlist-server.c' || echo '$(srcdir)/'`hostlist-server.c + +gnunet_daemon_hostlist-hostlist-server.obj: hostlist-server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-server.obj -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo -c -o gnunet_daemon_hostlist-hostlist-server.obj `if test -f 'hostlist-server.c'; then $(CYGPATH_W) 'hostlist-server.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-server.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-server.c' object='gnunet_daemon_hostlist-hostlist-server.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-server.obj `if test -f 'hostlist-server.c'; then $(CYGPATH_W) 'hostlist-server.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-server.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-dist_pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am \ + install-dist_pkgcfgDATA install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-dist_pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/hostlist/gnunet-daemon-hostlist.c b/src/hostlist/gnunet-daemon-hostlist.c new file mode 100644 index 0000000..0eedb56 --- /dev/null +++ b/src/hostlist/gnunet-daemon-hostlist.c @@ -0,0 +1,347 @@ +/* + This file is part of GNUnet. + (C) 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file hostlist/gnunet-daemon-hostlist.c + * @brief code for bootstrapping via hostlist servers + * @author Christian Grothoff + */ + +#include +#include "platform.h" +#include "hostlist-client.h" +#include "gnunet_core_service.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_program_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_strings_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_util_lib.h" + +#if HAVE_MHD + +#include "hostlist-server.h" + +/** + * Set if we are allowed to advertise our hostlist to others. + */ +static int advertising; + +/** + * Set if the user wants us to run a hostlist server. + */ +static int provide_hostlist; + +/** + * Handle to hostlist server's connect handler + */ +static GNUNET_CORE_ConnectEventHandler server_ch; + +/** + * Handle to hostlist server's disconnect handler + */ +static GNUNET_CORE_DisconnectEventHandler server_dh; + +#endif + +/** + * Set if we are allowed to learn about peers by accessing + * hostlist servers. + */ +static int bootstrapping; + +/** + * Set if the user allows us to learn about new hostlists + * from the network. + */ +static int learning; + +/** + * Statistics handle. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * Handle to the core service (NULL until we've connected to it). + */ +static struct GNUNET_CORE_Handle *core; + +/** + * Handle to the hostlist client's advertisement handler + */ +static GNUNET_CORE_MessageCallback client_adv_handler; + +/** + * Handle to hostlist client's connect handler + */ +static GNUNET_CORE_ConnectEventHandler client_ch; + +/** + * Handle to hostlist client's disconnect handler + */ +static GNUNET_CORE_DisconnectEventHandler client_dh; + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * A HOSTLIST_ADV message is used to exchange information about + * hostlist advertisements. This struct is always + * followed by the actual url under which the hostlist can be obtained: + * + * 1) transport-name (0-terminated) + * 2) address-length (uint32_t, network byte order; possibly + * unaligned!) + * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly + * unaligned!) + * 4) address (address-length bytes; possibly unaligned!) + */ +struct GNUNET_HOSTLIST_ADV_Message +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT. + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero (for alignment). + */ + uint32_t reserved GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + +static struct GNUNET_PeerIdentity me; + +static void +core_init (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + me = *my_identity; +} + +/** + * Core handler for p2p hostlist advertisements + * + * @param cls closure + * @param peer identity of the sender + * @param message advertisement message we got + * @param atsi performance information + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK on success + */ +static int +advertisement_handler (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + GNUNET_assert (NULL != client_adv_handler); + return (*client_adv_handler) (cls, peer, message, atsi, atsi_count); +} + + +/** + * Method called whenever a given peer connects. Wrapper to call both client's and server's functions + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + */ +static void +connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + if (0 == memcmp (&me, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "A new peer connected, notifying client and server\n"); + if (NULL != client_ch) + (*client_ch) (cls, peer, atsi, atsi_count); +#if HAVE_MHD + if (NULL != server_ch) + (*server_ch) (cls, peer, atsi, atsi_count); +#endif +} + +/** + * Method called whenever a given peer disconnects. Wrapper to call both client's and server's functions + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + if (0 == memcmp (&me, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + /* call hostlist client disconnect handler */ + if (NULL != client_dh) + (*client_dh) (cls, peer); +#if HAVE_MHD + /* call hostlist server disconnect handler */ + if (NULL != server_dh) + (*server_dh) (cls, peer); +#endif +} + +/** + * Last task run during shutdown. Disconnects us from + * the other services. + */ +static void +cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist daemon is shutting down\n"); + if (core != NULL) + { + GNUNET_CORE_disconnect (core); + core = NULL; + } + if (bootstrapping) + { + GNUNET_HOSTLIST_client_stop (); + } +#if HAVE_MHD + if (provide_hostlist) + { + GNUNET_HOSTLIST_server_stop (); + } +#endif + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + stats = NULL; + } +} + + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + static const struct GNUNET_CORE_MessageHandler learn_handlers[] = { + {&advertisement_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0}, + {NULL, 0, 0} + }; + static const struct GNUNET_CORE_MessageHandler no_learn_handlers[] = { + {NULL, 0, 0} + }; + if ((!bootstrapping) && (!learning) +#if HAVE_MHD + && (!provide_hostlist) +#endif + ) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("None of the functions for the hostlist daemon were enabled. I have no reason to run!\n")); + return; + } + + + + stats = GNUNET_STATISTICS_create ("hostlist", cfg); + + core = + GNUNET_CORE_connect (cfg, 1, NULL, &core_init, &connect_handler, + &disconnect_handler, NULL, GNUNET_NO, NULL, + GNUNET_NO, + learning ? learn_handlers : no_learn_handlers); + + if (bootstrapping) + { + GNUNET_HOSTLIST_client_start (cfg, stats, &client_ch, &client_dh, + &client_adv_handler, learning); + } + +#if HAVE_MHD + if (provide_hostlist) + { + GNUNET_HOSTLIST_server_start (cfg, stats, core, &server_ch, &server_dh, + advertising); + } +#endif + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task, + NULL); + + if (NULL == core) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to `%s' service.\n"), "core"); + GNUNET_SCHEDULER_shutdown (); + return; + } +} + + +/** + * The main function for the hostlist daemon. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { +#if HAVE_MHD + {'a', "advertise", NULL, + gettext_noop ("advertise our hostlist to other peers"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &advertising}, +#endif + {'b', "bootstrap", NULL, + gettext_noop + ("bootstrap using hostlists (it is highly recommended that you always use this option)"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &bootstrapping}, + {'e', "enable-learning", NULL, + gettext_noop ("enable learning about hostlist servers from other peers"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &learning}, +#if HAVE_MHD + {'p', "provide-hostlist", NULL, + gettext_noop ("provide a hostlist server"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &provide_hostlist}, +#endif + GNUNET_GETOPT_OPTION_END + }; + + int ret; + + GNUNET_log_setup ("hostlist", "WARNING", NULL); + ret = + (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "hostlist", + _("GNUnet hostlist server and client"), options, + &run, NULL)) ? 0 : 1; + + return ret; +} + +/* end of gnunet-daemon-hostlist.c */ diff --git a/src/hostlist/gnunet-daemon-hostlist.h b/src/hostlist/gnunet-daemon-hostlist.h new file mode 100644 index 0000000..8c9824e --- /dev/null +++ b/src/hostlist/gnunet-daemon-hostlist.h @@ -0,0 +1,47 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file hostlist/gnunet-daemon-hostlist.h + * @brief common internal definitions for hostlist daemon + * @author Matthias Wachs + */ +#include +#include "platform.h" +#include "hostlist-client.h" +#include "hostlist-server.h" +#include "gnunet_core_service.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_program_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_strings_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_util_lib.h" + +/** + * General hostlist daemon debugging. + */ +#define DEBUG_HOSTLIST GNUNET_EXTRA_LOGGING + +#define MAX_URL_LEN 1000 +#define MAX_BYTES_PER_HOSTLISTS 500000 + +/* end of gnunet-daemon-hostlist.h */ diff --git a/src/hostlist/hostlist-client.c b/src/hostlist/hostlist-client.c new file mode 100644 index 0000000..350a0ba --- /dev/null +++ b/src/hostlist/hostlist-client.c @@ -0,0 +1,1568 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file hostlist/hostlist-client.c + * @brief hostlist support. Downloads HELLOs via HTTP. + * @author Christian Grothoff + * @author Matthias Wachs + */ + +#include "platform.h" +#include "hostlist-client.h" +#include "gnunet_core_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet-daemon-hostlist.h" +#include +#include "gnunet_common.h" +#include "gnunet_bio_lib.h" + +#define DEBUG_HOSTLIST_CLIENT GNUNET_EXTRA_LOGGING + + +/** + * Number of connections that we must have to NOT download + * hostlists anymore. + */ +#define MIN_CONNECTIONS 4 + +/** + * Interval between two advertised hostlist tests + */ +#define TESTING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +/** + * A single hostlist obtained by hostlist advertisements + */ +struct Hostlist +{ + /** + * previous entry, used to manage entries in a double linked list + */ + struct Hostlist *prev; + + /** + * next entry, used to manage entries in a double linked list + */ + struct Hostlist *next; + + /** + * URI where hostlist can be obtained + */ + const char *hostlist_uri; + + /** + * Value describing the quality of the hostlist, the bigger the better but (should) never < 0 + * used for deciding which hostlist is replaced if MAX_NUMBER_HOSTLISTS in data structure is reached + * intial value = HOSTLIST_INITIAL + * increased every successful download by HOSTLIST_SUCCESSFULL_DOWNLOAD + * increased every successful download by number of obtained HELLO messages + * decreased every failed download by HOSTLIST_SUCCESSFULL_DOWNLOAD + */ + uint64_t quality; + + /** + * Time the hostlist advertisement was recieved and the entry was created + */ + struct GNUNET_TIME_Absolute time_creation; + + /** + * Last time the hostlist was obtained + */ + struct GNUNET_TIME_Absolute time_last_usage; + + /** + * Number of HELLO messages obtained during last download + */ + uint32_t hello_count; + + /** + * Number of times the hostlist was successfully obtained + */ + uint32_t times_used; + +}; + + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Statistics handle. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * Transport handle. + */ +static struct GNUNET_TRANSPORT_Handle *transport; + +/** + * Proxy that we are using (can be NULL). + */ +static char *proxy; + +/** + * Number of bytes valid in 'download_buffer'. + */ +static size_t download_pos; + +/** + * Current URL that we are using. + */ +static char *current_url; + +/** + * Current CURL handle. + */ +static CURL *curl; + +/** + * Current multi-CURL handle. + */ +static CURLM *multi; + +/** + * How many bytes did we download from the current hostlist URL? + */ +static uint32_t stat_bytes_downloaded; + +/** + * Amount of time we wait between hostlist downloads. + */ +static struct GNUNET_TIME_Relative hostlist_delay; + +/** + * ID of the task, checking if hostlist download should take plate + */ +static GNUNET_SCHEDULER_TaskIdentifier ti_check_download; + +/** + * ID of the task downloading the hostlist + */ +static GNUNET_SCHEDULER_TaskIdentifier ti_download; + +/** + * ID of the task saving the hostlsit in a regular intervall + */ +static GNUNET_SCHEDULER_TaskIdentifier ti_saving_task; + +/** + * ID of the task called to initiate a download + */ +static GNUNET_SCHEDULER_TaskIdentifier ti_download_dispatcher_task; + +/** + * ID of the task controlling the locking between two hostlist tests + */ +static GNUNET_SCHEDULER_TaskIdentifier ti_testing_intervall_task; + +/** + * At what time MUST the current hostlist request be done? + */ +static struct GNUNET_TIME_Absolute end_time; + +/** + * Head of the linked list used to store hostlists + */ +static struct Hostlist *linked_list_head; + +/** + * Tail of the linked list used to store hostlists + */ +static struct Hostlist *linked_list_tail; + +/** + * Current hostlist used for downloading + */ +static struct Hostlist *current_hostlist; + +/** + * Size of the linke list used to store hostlists + */ +static unsigned int linked_list_size; + +/** + * Head of the linked list used to store hostlists + */ +static struct Hostlist *hostlist_to_test; + +/** + * Set to GNUNET_YES if the current URL had some problems. + */ +static int stat_bogus_url; + +/** + * Value controlling if a hostlist is tested at the moment + */ +static int stat_testing_hostlist; + +/** + * Value controlling if a hostlist testing is allowed at the moment + */ +static int stat_testing_allowed; + +/** + * Value controlling if a hostlist download is running at the moment + */ +static int stat_download_in_progress; + +/** + * Value saying if a preconfigured bootstrap server is used + */ +static unsigned int stat_use_bootstrap; + +/** + * Set if we are allowed to learn new hostlists and use them + */ +static int stat_learning; + +/** + * Value saying if hostlist download was successful + */ +static unsigned int stat_download_successful; + +/** + * Value saying how many valid HELLO messages were obtained during download + */ +static unsigned int stat_hellos_obtained; + +/** + * Number of active connections (according to core service). + */ +static unsigned int stat_connection_count; + + +/** + * Process downloaded bits by calling callback on each HELLO. + * + * @param ptr buffer with downloaded data + * @param size size of a record + * @param nmemb number of records downloaded + * @param ctx unused + * @return number of bytes that were processed (always size*nmemb) + */ +static size_t +callback_download (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + const char *cbuf = ptr; + const struct GNUNET_MessageHeader *msg; + size_t total; + size_t cpy; + size_t left; + uint16_t msize; + + total = size * nmemb; + stat_bytes_downloaded += total; + if ((total == 0) || (stat_bogus_url)) + { + return total; /* ok, no data or bogus data */ + } + + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# bytes downloaded from hostlist servers"), + (int64_t) total, GNUNET_NO); + left = total; + while ((left > 0) || (download_pos > 0)) + { + cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - download_pos); + memcpy (&download_buffer[download_pos], cbuf, cpy); + cbuf += cpy; + download_pos += cpy; + left -= cpy; + if (download_pos < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_assert (left == 0); + break; + } + msg = (const struct GNUNET_MessageHeader *) download_buffer; + msize = ntohs (msg->size); + if (msize < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# invalid HELLOs downloaded from hostlist servers"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Invalid `%s' message received from hostlist at `%s'\n"), + "HELLO", current_url); + stat_hellos_obtained++; + stat_bogus_url = 1; + return total; + } + if (download_pos < msize) + { + GNUNET_assert (left == 0); + break; + } + if (GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *) msg) == msize) + { +#if DEBUG_HOSTLIST_CLIENT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received valid `%s' message from hostlist server.\n", + "HELLO"); +#endif + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# valid HELLOs downloaded from hostlist servers"), + 1, GNUNET_NO); + stat_hellos_obtained++; + GNUNET_TRANSPORT_offer_hello (transport, msg, NULL, NULL); + } + else + { + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# invalid HELLOs downloaded from hostlist servers"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Invalid `%s' message received from hostlist at `%s'\n"), + "HELLO", current_url); + stat_bogus_url = GNUNET_YES; + stat_hellos_obtained++; + return total; + } + memmove (download_buffer, &download_buffer[msize], download_pos - msize); + download_pos -= msize; + } + return total; +} + + +/** + * Obtain a hostlist URL that we should use. + * + * @return NULL if there is no URL available + */ +static char * +get_bootstrap_server () +{ + char *servers; + char *ret; + size_t urls; + size_t pos; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "SERVERS", + &servers)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("No `%s' specified in `%s' configuration, will not bootstrap.\n"), + "SERVERS", "HOSTLIST"); + return NULL; + } + + urls = 0; + if (strlen (servers) > 0) + { + urls++; + pos = strlen (servers) - 1; + while (pos > 0) + { + if (servers[pos] == ' ') + urls++; + pos--; + } + } + if (urls == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("No `%s' specified in `%s' configuration, will not bootstrap.\n"), + "SERVERS", "HOSTLIST"); + GNUNET_free (servers); + return NULL; + } + + urls = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, urls) + 1; + pos = strlen (servers) - 1; + while (pos > 0) + { + if (servers[pos] == ' ') + { + urls--; + servers[pos] = '\0'; + } + if (urls == 0) + { + pos++; + break; + } + pos--; + } + ret = GNUNET_strdup (&servers[pos]); + GNUNET_free (servers); + return ret; +} + +/** + * Method deciding if a preconfigured or advertisied hostlist is used on a 50:50 ratio + * @return uri to use, NULL if there is no URL available + */ +static char * +download_get_url () +{ + uint32_t index; + unsigned int counter; + struct Hostlist *pos; + + if (GNUNET_NO == stat_learning) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using preconfigured bootstrap server\n"); + current_hostlist = NULL; + return get_bootstrap_server (); + } + + if ((GNUNET_YES == stat_testing_hostlist) && (NULL != hostlist_to_test)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Testing new advertised hostlist if it is obtainable\n"); + current_hostlist = hostlist_to_test; + return GNUNET_strdup (hostlist_to_test->hostlist_uri); + } + + if ((GNUNET_YES == stat_use_bootstrap) || (linked_list_size == 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using preconfigured bootstrap server\n"); + current_hostlist = NULL; + return get_bootstrap_server (); + } + index = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, linked_list_size); + counter = 0; + pos = linked_list_head; + while (counter < index) + { + pos = pos->next; + counter++; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using learned hostlist `%s'\n", + pos->hostlist_uri); + current_hostlist = pos; + return GNUNET_strdup (pos->hostlist_uri); +} + + +#define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt(c, a, b); if (ret != CURLE_OK) GNUNET_log(GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror(ret)); } while (0) + + +/** + * Method to save hostlist to a file during hostlist client shutdown + * @param shutdown set if called because of shutdown, entries in linked list will be destroyed + */ +static void +save_hostlist_file (int shutdown); + + +/** + * add val2 to val1 with overflow check + * @param val1 value 1 + * @param val2 value 2 + * @return result + */ +static uint64_t +checked_add (uint64_t val1, uint64_t val2) +{ + static uint64_t temp; + static uint64_t maxv; + + maxv = 0; + maxv--; + + temp = val1 + val2; + if (temp < val1) + return maxv; + else + return temp; +} + +/** + * Subtract val2 from val1 with underflow check + * @param val1 value 1 + * @param val2 value 2 + * @return result + */ +static uint64_t +checked_sub (uint64_t val1, uint64_t val2) +{ + if (val1 <= val2) + return 0; + else + return (val1 - val2); +} + +/** + * Method to check if a URI is in hostlist linked list + * @param uri uri to check + * @return GNUNET_YES if existing in linked list, GNUNET_NO if not + */ +static int +linked_list_contains (const char *uri) +{ + struct Hostlist *pos; + + pos = linked_list_head; + while (pos != NULL) + { + if (0 == strcmp (pos->hostlist_uri, uri)) + return GNUNET_YES; + pos = pos->next; + } + return GNUNET_NO; +} + + +/** + * Method returning the hostlist element with the lowest quality in the datastore + * @return hostlist with lowest quality + */ +static struct Hostlist * +linked_list_get_lowest_quality () +{ + struct Hostlist *pos; + struct Hostlist *lowest; + + if (linked_list_size == 0) + return NULL; + lowest = linked_list_head; + pos = linked_list_head->next; + while (pos != NULL) + { + if (pos->quality < lowest->quality) + lowest = pos; + pos = pos->next; + } + return lowest; +} + + +/** + * Method to insert a hostlist into the datastore. If datastore + * contains maximum number of elements, the elements with lowest + * quality is dismissed + */ +static void +insert_hostlist () +{ + struct Hostlist *lowest_quality; + + if (MAX_NUMBER_HOSTLISTS <= linked_list_size) + { + /* No free entries available, replace existing entry */ + lowest_quality = linked_list_get_lowest_quality (); + GNUNET_assert (lowest_quality != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Removing hostlist with URI `%s' which has the worst quality of all (%llu)\n", + lowest_quality->hostlist_uri, + (unsigned long long) lowest_quality->quality); + GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, + lowest_quality); + linked_list_size--; + GNUNET_free (lowest_quality); + } + GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail, + hostlist_to_test); + linked_list_size++; + GNUNET_STATISTICS_set (stats, gettext_noop ("# advertised hostlist URIs"), + linked_list_size, GNUNET_NO); + stat_testing_hostlist = GNUNET_NO; +} + + +/** + * Method updating hostlist statistics + */ +static void +update_hostlist () +{ + char *stat; + + if (((stat_use_bootstrap == GNUNET_NO) && (NULL != current_hostlist)) || + ((stat_testing_hostlist == GNUNET_YES) && (NULL != current_hostlist))) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Updating hostlist statics for URI `%s'\n", + current_hostlist->hostlist_uri); + current_hostlist->hello_count = stat_hellos_obtained; + current_hostlist->time_last_usage = GNUNET_TIME_absolute_get (); + current_hostlist->quality = + checked_add (current_hostlist->quality, + (stat_hellos_obtained * HOSTLIST_SUCCESSFUL_HELLO)); + if (GNUNET_YES == stat_download_successful) + { + current_hostlist->times_used++; + current_hostlist->quality = + checked_add (current_hostlist->quality, HOSTLIST_SUCCESSFUL_DOWNLOAD); + GNUNET_asprintf (&stat, gettext_noop ("# advertised URI `%s' downloaded"), + current_hostlist->hostlist_uri); + + GNUNET_STATISTICS_update (stats, stat, 1, GNUNET_YES); + GNUNET_free (stat); + } + else + current_hostlist->quality = + checked_sub (current_hostlist->quality, HOSTLIST_FAILED_DOWNLOAD); + } + current_hostlist = NULL; + /* Alternating the usage of preconfigured and learned hostlists */ + + if (stat_testing_hostlist == GNUNET_YES) + return; + + if (GNUNET_YES == stat_learning) + { + if (stat_use_bootstrap == GNUNET_YES) + stat_use_bootstrap = GNUNET_NO; + else + stat_use_bootstrap = GNUNET_YES; + } + else + stat_use_bootstrap = GNUNET_YES; +} + +/** + * Clean up the state from the task that downloaded the + * hostlist and schedule the next task. + */ +static void +clean_up () +{ + CURLMcode mret; + + if ((stat_testing_hostlist == GNUNET_YES) && + (GNUNET_NO == stat_download_successful) && (NULL != hostlist_to_test)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Advertised hostlist with URI `%s' could not be downloaded. Advertised URI gets dismissed.\n"), + hostlist_to_test->hostlist_uri); + } + + if (stat_testing_hostlist == GNUNET_YES) + { + stat_testing_hostlist = GNUNET_NO; + } + if (NULL != hostlist_to_test) + { + GNUNET_free (hostlist_to_test); + hostlist_to_test = NULL; + } + + if (multi != NULL) + { + mret = curl_multi_remove_handle (multi, curl); + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_remove_handle", __FILE__, __LINE__, + curl_multi_strerror (mret)); + } + mret = curl_multi_cleanup (multi); + if (mret != CURLM_OK) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_cleanup", __FILE__, __LINE__, + curl_multi_strerror (mret)); + multi = NULL; + } + if (curl != NULL) + { + curl_easy_cleanup (curl); + curl = NULL; + } + GNUNET_free_non_null (current_url); + current_url = NULL; + stat_bytes_downloaded = 0; + stat_download_in_progress = GNUNET_NO; +} + + +/** + * Task that is run when we are ready to receive more data from the hostlist + * server. + * + * @param cls closure, unused + * @param tc task context, unused + */ +static void +task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Ask CURL for the select set and then schedule the + * receiving task with the scheduler. + */ +static void +download_prepare () +{ + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + struct GNUNET_NETWORK_FDSet *grs; + struct GNUNET_NETWORK_FDSet *gws; + long timeout; + struct GNUNET_TIME_Relative rtime; + + max = -1; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_fdset", __FILE__, __LINE__, + curl_multi_strerror (mret)); + clean_up (); + return; + } + mret = curl_multi_timeout (multi, &timeout); + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_timeout", __FILE__, __LINE__, + curl_multi_strerror (mret)); + clean_up (); + return; + } + rtime = + GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (end_time), + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, timeout)); + grs = GNUNET_NETWORK_fdset_create (); + gws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); +#if DEBUG_HOSTLIST_CLIENT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling task for hostlist download using cURL\n"); +#endif + ti_download = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, rtime, grs, gws, + &task_download, multi); + GNUNET_NETWORK_fdset_destroy (gws); + GNUNET_NETWORK_fdset_destroy (grs); +} + + +/** + * Task that is run when we are ready to receive more data from the hostlist + * server. + * + * @param cls closure, unused + * @param tc task context, unused + */ +static void +task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int running; + struct CURLMsg *msg; + CURLMcode mret; + + ti_download = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { +#if DEBUG_HOSTLIST_CLIENT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Shutdown requested while trying to download hostlist from `%s'\n", + current_url); +#endif + update_hostlist (); + clean_up (); + return; + } + if (GNUNET_TIME_absolute_get_remaining (end_time).rel_value == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Timeout trying to download hostlist from `%s'\n"), + current_url); + update_hostlist (); + clean_up (); + return; + } +#if DEBUG_HOSTLIST_CLIENT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Ready for processing hostlist client request\n"); +#endif + + do + { + running = 0; + if (stat_bytes_downloaded > MAX_BYTES_PER_HOSTLISTS) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Download limit of %u bytes exceeded, stopping download\n"), + MAX_BYTES_PER_HOSTLISTS); + clean_up (); + return; + } + mret = curl_multi_perform (multi, &running); + if (running == 0) + { + do + { + msg = curl_multi_info_read (multi, &running); + GNUNET_break (msg != NULL); + if (msg == NULL) + break; + switch (msg->msg) + { + case CURLMSG_DONE: + if ((msg->data.result != CURLE_OK) && + (msg->data.result != CURLE_GOT_NOTHING)) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("%s failed for `%s' at %s:%d: `%s'\n"), + "curl_multi_perform", current_url, __FILE__, __LINE__, + curl_easy_strerror (msg->data.result)); + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Download of hostlist `%s' completed.\n"), + current_url); + stat_download_successful = GNUNET_YES; + update_hostlist (); + if (GNUNET_YES == stat_testing_hostlist) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Adding successfully tested hostlist `%s' datastore.\n"), + current_url); + insert_hostlist (); + hostlist_to_test = NULL; + stat_testing_hostlist = GNUNET_NO; + } + } + clean_up (); + return; + default: + break; + } + + } + while ((running > 0)); + } + } + while (mret == CURLM_CALL_MULTI_PERFORM); + + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_perform", __FILE__, __LINE__, + curl_multi_strerror (mret)); + clean_up (); + } + download_prepare (); +} + + +/** + * Main function that will download a hostlist and process its + * data. + */ +static void +download_hostlist () +{ + CURLcode ret; + CURLMcode mret; + + + current_url = download_get_url (); + if (current_url == NULL) + return; + curl = curl_easy_init (); + multi = NULL; + if (curl == NULL) + { + GNUNET_break (0); + clean_up (); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, + _("Bootstrapping using hostlist at `%s'.\n"), current_url); + + stat_download_in_progress = GNUNET_YES; + stat_download_successful = GNUNET_NO; + stat_hellos_obtained = 0; + stat_bytes_downloaded = 0; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# hostlist downloads initiated"), 1, + GNUNET_NO); + if (proxy != NULL) + CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy); + download_pos = 0; + stat_bogus_url = 0; + CURL_EASY_SETOPT (curl, CURLOPT_WRITEFUNCTION, &callback_download); + if (ret != CURLE_OK) + { + clean_up (); + return; + } + CURL_EASY_SETOPT (curl, CURLOPT_WRITEDATA, NULL); + if (ret != CURLE_OK) + { + clean_up (); + return; + } + CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1); + CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4); + /* no need to abort if the above failed */ + CURL_EASY_SETOPT (curl, CURLOPT_URL, current_url); + if (ret != CURLE_OK) + { + clean_up (); + return; + } + CURL_EASY_SETOPT (curl, CURLOPT_FAILONERROR, 1); +#if 0 + CURL_EASY_SETOPT (curl, CURLOPT_VERBOSE, 1); +#endif + CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE); + if (0 == strncmp (current_url, "http", 4)) + CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet"); + CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 60L); + CURL_EASY_SETOPT (curl, CURLOPT_TIMEOUT, 60L); +#if 0 + /* this should no longer be needed; we're now single-threaded! */ + CURL_EASY_SETOPT (curl, CURLOPT_NOSIGNAL, 1); +#endif + multi = curl_multi_init (); + if (multi == NULL) + { + GNUNET_break (0); + /* clean_up (); */ + return; + } + mret = curl_multi_add_handle (multi, curl); + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_add_handle", __FILE__, __LINE__, + curl_multi_strerror (mret)); + mret = curl_multi_cleanup (multi); + if (mret != CURLM_OK) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_cleanup", __FILE__, __LINE__, + curl_multi_strerror (mret)); + multi = NULL; + clean_up (); + return; + } + end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); + download_prepare (); +} + + +static void +task_download_dispatcher (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + ti_download_dispatcher_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download is initiated...\n"); + if (GNUNET_NO == stat_download_in_progress) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download can start immediately...\n"); + download_hostlist (); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Download in progess, have to wait...\n"); + ti_download_dispatcher_task = + GNUNET_SCHEDULER_add_delayed (WAITING_INTERVALL, + &task_download_dispatcher, NULL); + } +} + +/** + * Task that checks if we should try to download a hostlist. + * If so, we initiate the download, otherwise we schedule + * this task again for a later time. + */ +static void +task_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static int once; + struct GNUNET_TIME_Relative delay; + + ti_check_download = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + if (stat_connection_count < MIN_CONNECTIONS) + { + ti_download_dispatcher_task = + GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL); + } + + if (stats == NULL) + { + curl_global_cleanup (); + return; /* in shutdown */ + } + delay = hostlist_delay; + if (hostlist_delay.rel_value == 0) + hostlist_delay = GNUNET_TIME_UNIT_SECONDS; + else + hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2); + if (hostlist_delay.rel_value > + GNUNET_TIME_UNIT_HOURS.rel_value * (1 + stat_connection_count)) + hostlist_delay = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, + (1 + stat_connection_count)); + GNUNET_STATISTICS_set (stats, + gettext_noop + ("# milliseconds between hostlist downloads"), + hostlist_delay.rel_value, GNUNET_YES); + if (0 == once) + { + delay = GNUNET_TIME_UNIT_ZERO; + once = 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Have %u/%u connections. Will consider downloading hostlist in %llums\n"), + stat_connection_count, MIN_CONNECTIONS, + (unsigned long long) delay.rel_value); + ti_check_download = GNUNET_SCHEDULER_add_delayed (delay, &task_check, NULL); +} + + +/** + * This tasks sets hostlist testing to allowed after intervall between to testings is reached + * + * @param cls closure + * @param tc TaskContext + */ +static void +task_testing_intervall_reset (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + ti_testing_intervall_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + stat_testing_allowed = GNUNET_OK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Testing new hostlist advertisements is allowed again\n"); +} + + +/** + * Task that writes hostlist entries to a file on a regular base + * + * @param cls closure + * @param tc TaskContext + */ +static void +task_hostlist_saving (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + ti_saving_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Scheduled saving of hostlists\n")); + save_hostlist_file (GNUNET_NO); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Hostlists will be saved to file again in %llums\n"), + (unsigned long long) SAVING_INTERVALL.rel_value); + ti_saving_task = + GNUNET_SCHEDULER_add_delayed (SAVING_INTERVALL, &task_hostlist_saving, + NULL); +} + + +/** + * Method called whenever a given peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + */ +static void +handler_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + GNUNET_assert (stat_connection_count < UINT_MAX); + stat_connection_count++; + GNUNET_STATISTICS_update (stats, gettext_noop ("# active connections"), 1, + GNUNET_NO); +} + + +/** + * Method called whenever a given peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +handler_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_assert (stat_connection_count > 0); + stat_connection_count--; + GNUNET_STATISTICS_update (stats, gettext_noop ("# active connections"), -1, + GNUNET_NO); +} + + +/** + * Method called whenever an advertisement message arrives. + * + * @param cls closure (always NULL) + * @param peer the peer sending the message + * @param message the actual message + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handler_advertisement (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + size_t size; + size_t uri_size; + const struct GNUNET_MessageHeader *incoming; + const char *uri; + struct Hostlist *hostlist; + + GNUNET_assert (ntohs (message->type) == + GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT); + size = ntohs (message->size); + if (size <= sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + incoming = (const struct GNUNET_MessageHeader *) message; + uri = (const char *) &incoming[1]; + uri_size = size - sizeof (struct GNUNET_MessageHeader); + if (uri[uri_size - 1] != '\0') + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Hostlist client recieved advertisement from `%s' containing URI `%s'\n", + GNUNET_i2s (peer), uri); + if (GNUNET_NO != linked_list_contains (uri)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URI `%s' is already known\n", uri); + return GNUNET_OK; + } + + if (GNUNET_NO == stat_testing_allowed) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Currently not accepting new advertisements: interval between to advertisements is not reached\n"); + return GNUNET_SYSERR; + } + if (GNUNET_YES == stat_testing_hostlist) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Currently not accepting new advertisements: we are already testing a hostlist\n"); + return GNUNET_SYSERR; + } + + hostlist = GNUNET_malloc (sizeof (struct Hostlist) + uri_size); + hostlist->hostlist_uri = (const char *) &hostlist[1]; + memcpy (&hostlist[1], uri, uri_size); + hostlist->time_creation = GNUNET_TIME_absolute_get (); + hostlist->time_last_usage = GNUNET_TIME_absolute_get_zero (); + hostlist->quality = HOSTLIST_INITIAL; + hostlist_to_test = hostlist; + + stat_testing_hostlist = GNUNET_YES; + stat_testing_allowed = GNUNET_NO; + ti_testing_intervall_task = + GNUNET_SCHEDULER_add_delayed (TESTING_INTERVAL, + &task_testing_intervall_reset, NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Testing new hostlist advertisements is locked for the next %u ms\n", + TESTING_INTERVAL.rel_value); + + ti_download_dispatcher_task = + GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL); + + return GNUNET_OK; +} + + + +/** + * Continuation called by the statistics code once + * we go the stat. Initiates hostlist download scheduling. + * + * @param cls closure + * @param success GNUNET_OK if statistics were + * successfully obtained, GNUNET_SYSERR if not. + */ +static void +primary_task (void *cls, int success) +{ + if (stats == NULL) + return; /* in shutdown */ +#if DEBUG_HOSTLIST_CLIENT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Statistics request done, scheduling hostlist download\n"); +#endif + ti_check_download = GNUNET_SCHEDULER_add_now (&task_check, NULL); +} + + +static int +process_stat (void *cls, const char *subsystem, const char *name, + uint64_t value, int is_persistent) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Initial time between hostlist downloads is %llums\n"), + (unsigned long long) value); + hostlist_delay.rel_value = value; + return GNUNET_OK; +} + +/** + * Method to load persistent hostlist file during hostlist client startup + */ +static void +load_hostlist_file () +{ + char *filename; + char *uri; + char *emsg; + struct Hostlist *hostlist; + + uri = NULL; + uint32_t times_used; + uint32_t hellos_returned; + uint64_t quality; + uint64_t last_used; + uint64_t created; + uint32_t counter; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE", + &filename)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("No `%s' specified in `%s' configuration, cannot load hostlists from file.\n"), + "HOSTLISTFILE", "HOSTLIST"); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Loading saved hostlist entries from file `%s' \n"), filename); + if (GNUNET_NO == GNUNET_DISK_file_test (filename)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Hostlist file `%s' is not existing\n"), filename); + GNUNET_free (filename); + return; + } + + struct GNUNET_BIO_ReadHandle *rh = GNUNET_BIO_read_open (filename); + + if (NULL == rh) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Could not open file `%s' for reading to load hostlists: %s\n"), + filename, STRERROR (errno)); + GNUNET_free (filename); + return; + } + + counter = 0; + while ((GNUNET_OK == GNUNET_BIO_read_string (rh, "url", &uri, MAX_URL_LEN)) && + (NULL != uri) && (GNUNET_OK == GNUNET_BIO_read_int32 (rh, ×_used)) + && (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &quality)) && + (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &last_used)) && + (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &created)) && + (GNUNET_OK == GNUNET_BIO_read_int32 (rh, &hellos_returned))) + { + hostlist = GNUNET_malloc (sizeof (struct Hostlist) + strlen (uri) + 1); + hostlist->hello_count = hellos_returned; + hostlist->hostlist_uri = (const char *) &hostlist[1]; + memcpy (&hostlist[1], uri, strlen (uri) + 1); + hostlist->quality = quality; + hostlist->time_creation.abs_value = created; + hostlist->time_last_usage.abs_value = last_used; + GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail, hostlist); + linked_list_size++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Added hostlist entry eith URI `%s' \n", + hostlist->hostlist_uri); + GNUNET_free (uri); + uri = NULL; + counter++; + if (counter >= MAX_NUMBER_HOSTLISTS) + break; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%u hostlist URIs loaded from file\n"), + counter); + GNUNET_STATISTICS_set (stats, gettext_noop ("# hostlist URIs read from file"), + counter, GNUNET_YES); + GNUNET_STATISTICS_set (stats, gettext_noop ("# advertised hostlist URIs"), + linked_list_size, GNUNET_NO); + + GNUNET_free_non_null (uri); + emsg = NULL; + GNUNET_BIO_read_close (rh, &emsg); + if (emsg != NULL) + GNUNET_free (emsg); + GNUNET_free (filename); +} + + +/** + * Method to save persistent hostlist file during hostlist client shutdown + * @param shutdown set if called because of shutdown, entries in linked list will be destroyed + */ +static void +save_hostlist_file (int shutdown) +{ + char *filename; + struct Hostlist *pos; + struct GNUNET_BIO_WriteHandle *wh; + int ok; + uint32_t counter; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE", + &filename)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("No `%s' specified in `%s' configuration, cannot save hostlists to file.\n"), + "HOSTLISTFILE", "HOSTLIST"); + return; + } + if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) + { + GNUNET_free (filename); + return; + } + wh = GNUNET_BIO_write_open (filename); + if (NULL == wh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Could not open file `%s' for writing to save hostlists: %s\n"), + filename, STRERROR (errno)); + GNUNET_free (filename); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Writing %u hostlist URIs to `%s'\n"), + linked_list_size, filename); + /* add code to write hostlists to file using bio */ + ok = GNUNET_YES; + counter = 0; + while (NULL != (pos = linked_list_head)) + { + if (GNUNET_YES == shutdown) + { + GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, pos); + linked_list_size--; + } + if (GNUNET_YES == ok) + { + if ((GNUNET_OK != GNUNET_BIO_write_string (wh, pos->hostlist_uri)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pos->times_used)) || + (GNUNET_OK != GNUNET_BIO_write_int64 (wh, pos->quality)) || + (GNUNET_OK != + GNUNET_BIO_write_int64 (wh, pos->time_last_usage.abs_value)) || + (GNUNET_OK != + GNUNET_BIO_write_int64 (wh, pos->time_creation.abs_value)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pos->hello_count))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Error writing hostlist URIs to file `%s'\n"), filename); + ok = GNUNET_NO; + } + } + + if (GNUNET_YES == shutdown) + GNUNET_free (pos); + counter++; + if (counter >= MAX_NUMBER_HOSTLISTS) + break; + } + GNUNET_STATISTICS_set (stats, + gettext_noop ("# hostlist URIs written to file"), + counter, GNUNET_YES); + + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Error writing hostlist URIs to file `%s'\n"), filename); + GNUNET_free (filename); +} + +/** + * Start downloading hostlists from hostlist servers as necessary. + */ +int +GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_STATISTICS_Handle *st, + GNUNET_CORE_ConnectEventHandler *ch, + GNUNET_CORE_DisconnectEventHandler *dh, + GNUNET_CORE_MessageCallback *msgh, int learn) +{ + char *filename; + int result; + + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + transport = GNUNET_TRANSPORT_connect (c, NULL, NULL, NULL, NULL, NULL); + if (NULL == transport) + { + curl_global_cleanup (); + return GNUNET_SYSERR; + } + cfg = c; + stats = st; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "HTTP-PROXY", + &proxy)) + proxy = NULL; + stat_learning = learn; + *ch = &handler_connect; + *dh = &handler_disconnect; + linked_list_head = NULL; + linked_list_tail = NULL; + stat_use_bootstrap = GNUNET_YES; + stat_testing_hostlist = GNUNET_NO; + stat_testing_allowed = GNUNET_YES; + + if (GNUNET_YES == stat_learning) + { + *msgh = &handler_advertisement; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Learning is enabled on this peer\n")); + load_hostlist_file (); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Hostlists will be saved to file again in %llums\n"), + (unsigned long long) SAVING_INTERVALL.rel_value); + ti_saving_task = + GNUNET_SCHEDULER_add_delayed (SAVING_INTERVALL, &task_hostlist_saving, + NULL); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Learning is not enabled on this peer\n")); + *msgh = NULL; + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", + "HOSTLISTFILE", &filename)) + { + if (GNUNET_YES == GNUNET_DISK_file_test (filename)) + { + result = remove (filename); + if (result == 0) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Since learning is not enabled on this peer, hostlist file `%s' was removed\n"), + filename); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Hostlist file `%s' could not be removed\n"), filename); + } + } + GNUNET_free (filename); + } + GNUNET_STATISTICS_get (stats, "hostlist", + gettext_noop + ("# milliseconds between hostlist downloads"), + GNUNET_TIME_UNIT_MINUTES, &primary_task, &process_stat, + NULL); + return GNUNET_OK; +} + + +/** + * Stop downloading hostlists from hostlist servers as necessary. + */ +void +GNUNET_HOSTLIST_client_stop () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client shutdown\n"); +#if DEBUG_HOSTLIST_CLIENT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client shutdown\n"); +#endif + if (GNUNET_YES == stat_learning) + save_hostlist_file (GNUNET_YES); + + if (ti_saving_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ti_saving_task); + } + + if (ti_download_dispatcher_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ti_download_dispatcher_task); + } + if (ti_testing_intervall_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ti_testing_intervall_task); + } + if (ti_download != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ti_download); + } + if (ti_check_download != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ti_check_download); + curl_global_cleanup (); + } + if (transport != NULL) + { + GNUNET_TRANSPORT_disconnect (transport); + transport = NULL; + } + GNUNET_assert (NULL == transport); + GNUNET_free_non_null (proxy); + proxy = NULL; + cfg = NULL; +} + +/* end of hostlist-client.c */ diff --git a/src/hostlist/hostlist-client.h b/src/hostlist/hostlist-client.h new file mode 100644 index 0000000..3def865 --- /dev/null +++ b/src/hostlist/hostlist-client.h @@ -0,0 +1,108 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file hostlist/hostlist-client.h + * @brief hostlist support. Downloads HELLOs via HTTP. + * @author Christian Grothoff + */ + +#ifndef HOSTLIST_CLIENT_H +#define HOSTLIST_CLIENT_H + +#include "gnunet_core_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_util_lib.h" +#include "gnunet_time_lib.h" + +/** + * Maximum number of hostlist that are saved + */ +#define MAX_NUMBER_HOSTLISTS 30 + +/** + * Time intervall hostlists are saved to disk + */ +#define SAVING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) + +/** + * Time interval between two hostlist tests + */ +#define TESTING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) + +/** + * Time interval for download dispatcher before a download is re-scheduled + */ +#define WAITING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * Defines concerning the hostlist quality metric + */ + +/** + * Initial quality of a new created hostlist + */ +#define HOSTLIST_INITIAL 10000 + +/** + * Value subtracted each time a hostlist download fails + */ +#define HOSTLIST_FAILED_DOWNLOAD 100 + +/** + * Value added each time a hostlist download is successful + */ +#define HOSTLIST_SUCCESSFUL_DOWNLOAD 100 + +/** + * Value added for each valid HELLO recived during a hostlist download + */ +#define HOSTLIST_SUCCESSFUL_HELLO 1 + + + +/** + * Start downloading hostlists from hostlist servers as necessary. + * + * @param c the configuration to use + * @param st hande for publishing statistics + * @param ch set to handler for connect notifications + * @param dh set to handler for disconnect notifications + * @param msgh set to handler for message handler notifications + * @param learn set if client is learning new hostlists + * @return GNUNET_OK on success + */ +int +GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_STATISTICS_Handle *st, + GNUNET_CORE_ConnectEventHandler *ch, + GNUNET_CORE_DisconnectEventHandler *dh, + GNUNET_CORE_MessageCallback *msgh, int learn); + + +/** + * Stop downloading hostlists from hostlist servers as necessary. + */ +void +GNUNET_HOSTLIST_client_stop (void); + + +#endif +/* end of hostlist-client.h */ diff --git a/src/hostlist/hostlist-server.c b/src/hostlist/hostlist-server.c new file mode 100644 index 0000000..8e79ace --- /dev/null +++ b/src/hostlist/hostlist-server.c @@ -0,0 +1,700 @@ +/* + This file is part of GNUnet. + (C) 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file hostlist/hostlist-server.c + * @author Christian Grothoff, Matthias Wachs + * @brief application to provide an integrated hostlist HTTP server + */ + +#include "platform.h" +#include +#include "hostlist-server.h" +#include "gnunet_hello_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet-daemon-hostlist.h" +#include "gnunet_resolver_service.h" + +#define DEBUG_HOSTLIST_SERVER GNUNET_EXTRA_LOGGING + +/** + * Handle to the HTTP server as provided by libmicrohttpd for IPv6. + */ +static struct MHD_Daemon *daemon_handle_v6; + +/** + * Handle to the HTTP server as provided by libmicrohttpd for IPv4. + */ +static struct MHD_Daemon *daemon_handle_v4; + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * For keeping statistics. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * Handle to the core service (NULL until we've connected to it). + */ +static struct GNUNET_CORE_Handle *core; + +/** + * Handle to the peerinfo notify service (NULL until we've connected to it). + */ +static struct GNUNET_PEERINFO_NotifyContext *notify; + +/** + * Our primary task for IPv4. + */ +static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v4; + +/** + * Our primary task for IPv6. + */ +static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v6; + +/** + * Our canonical response. + */ +static struct MHD_Response *response; + +/** + * NULL if we are not currenlty iterating over peer information. + */ +static struct GNUNET_PEERINFO_IteratorContext *pitr; + +/** + * Handle for accessing peerinfo service. + */ +static struct GNUNET_PEERINFO_Handle *peerinfo; + +/** + * Context for host processor. + */ +struct HostSet +{ + unsigned int size; + + char *data; +}; + +/** + * Set if we are allowed to advertise our hostlist to others. + */ +static int advertising; + +/** + * Buffer for the hostlist address + */ +static char *hostlist_uri; + + +/** + * Function that assembles our response. + */ +static void +finish_response (struct HostSet *results) +{ + if (response != NULL) + MHD_destroy_response (response); +#if DEBUG_HOSTLIST_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating hostlist response with %u bytes\n", + (unsigned int) results->size); +#endif + response = + MHD_create_response_from_data (results->size, results->data, MHD_YES, + MHD_NO); + if ((daemon_handle_v4 == NULL) && (daemon_handle_v6 == NULL)) + { + MHD_destroy_response (response); + response = NULL; + } + GNUNET_STATISTICS_set (stats, gettext_noop ("bytes in hostlist"), + results->size, GNUNET_YES); + GNUNET_free (results); +} + + +/** + * Set 'cls' to GNUNET_YES (we have an address!). + * + * @param cls closure, an 'int*' + * @param address the address (ignored) + * @param expiration expiration time (call is ignored if this is in the past) + * @return GNUNET_SYSERR to stop iterating (unless expiration has occured) + */ +static int +check_has_addr (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + int *arg = cls; + + if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("expired addresses encountered"), 1, + GNUNET_YES); + return GNUNET_YES; /* ignore this address */ + } + *arg = GNUNET_YES; + return GNUNET_SYSERR; +} + + +/** + * Callback that processes each of the known HELLOs for the + * hostlist response construction. + */ +static void +host_processor (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, const char *err_msg) +{ + struct HostSet *results = cls; + size_t old; + size_t s; + int has_addr; + + if (err_msg != NULL) + { + GNUNET_assert (NULL == peer); + pitr = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Error in communication with PEERINFO service: %s\n"), + err_msg); + return; + } + if (peer == NULL) + { + pitr = NULL; + finish_response (results); + return; + } + if (hello == NULL) + return; + has_addr = GNUNET_NO; + GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &check_has_addr, &has_addr); + if (GNUNET_NO == has_addr) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "HELLO for peer `%4s' has no address, not suitable for hostlist!\n", + GNUNET_i2s (peer)); + GNUNET_STATISTICS_update (stats, + gettext_noop + ("HELLOs without addresses encountered (ignored)"), + 1, GNUNET_NO); + return; + } + old = results->size; + s = GNUNET_HELLO_size (hello); +#if DEBUG_HOSTLIST_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received %u bytes of `%s' from peer `%s' for hostlist.\n", + (unsigned int) s, "HELLO", GNUNET_i2s (peer)); +#endif + if ((old + s >= GNUNET_MAX_MALLOC_CHECKED) || + (old + s >= MAX_BYTES_PER_HOSTLISTS)) + { + GNUNET_STATISTICS_update (stats, + gettext_noop + ("bytes not included in hostlist (size limit)"), + s, GNUNET_NO); + return; /* too large, skip! */ + } +#if DEBUG_HOSTLIST_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Adding peer `%s' to hostlist (%u bytes)\n", GNUNET_i2s (peer), + (unsigned int) s); +#endif + GNUNET_array_grow (results->data, results->size, old + s); + memcpy (&results->data[old], hello, s); +} + + + +/** + * Hostlist access policy (very permissive, allows everything). + */ +static int +accept_policy_callback (void *cls, const struct sockaddr *addr, + socklen_t addrlen) +{ + if (NULL == response) + { +#if DEBUG_HOSTLIST_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received request for hostlist, but I am not yet ready; rejecting!\n"); +#endif + return MHD_NO; + } + return MHD_YES; /* accept all */ +} + + +/** + * Main request handler. + */ +static int +access_handler_callback (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, + const char *version, const char *upload_data, + size_t * upload_data_size, void **con_cls) +{ + static int dummy; + + if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Refusing `%s' request to hostlist server\n"), method); + GNUNET_STATISTICS_update (stats, + gettext_noop + ("hostlist requests refused (not HTTP GET)"), 1, + GNUNET_YES); + return MHD_NO; + } + if (NULL == *con_cls) + { + (*con_cls) = &dummy; +#if DEBUG_HOSTLIST_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Sending 100 CONTINUE reply\n")); +#endif + return MHD_YES; /* send 100 continue */ + } + if (*upload_data_size != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Refusing `%s' request with %llu bytes of upload data\n"), + method, (unsigned long long) *upload_data_size); + GNUNET_STATISTICS_update (stats, + gettext_noop + ("hostlist requests refused (upload data)"), 1, + GNUNET_YES); + return MHD_NO; /* do not support upload data */ + } + if (response == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Could not handle hostlist request since I do not have a response yet\n")); + GNUNET_STATISTICS_update (stats, + gettext_noop + ("hostlist requests refused (not ready)"), 1, + GNUNET_YES); + return MHD_NO; /* internal error, no response yet */ + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received request for our hostlist\n")); + GNUNET_STATISTICS_update (stats, gettext_noop ("hostlist requests processed"), + 1, GNUNET_YES); + return MHD_queue_response (connection, MHD_HTTP_OK, response); +} + + +/** + * Handler called by core when core is ready to transmit message + * @param cls closure + * @param size size of buffer to copy message to + * @param buf buffer to copy message to + */ +static size_t +adv_transmit_ready (void *cls, size_t size, void *buf) +{ + static uint64_t hostlist_adv_count; + + size_t transmission_size; + size_t uri_size; /* Including \0 termination! */ + struct GNUNET_MessageHeader header; + char *cbuf; + + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmission failed, buffer invalid!\n"); + return 0; + } + uri_size = strlen (hostlist_uri) + 1; + transmission_size = sizeof (struct GNUNET_MessageHeader) + uri_size; + header.type = htons (GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT); + header.size = htons (transmission_size); + GNUNET_assert (size >= transmission_size); + memcpy (buf, &header, sizeof (struct GNUNET_MessageHeader)); + cbuf = buf; + memcpy (&cbuf[sizeof (struct GNUNET_MessageHeader)], hostlist_uri, uri_size); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sent advertisement message: Copied %u bytes into buffer!\n", + (unsigned int) transmission_size); + hostlist_adv_count++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " # Sent advertisement message: %u\n", + hostlist_adv_count); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# hostlist advertisements send"), 1, + GNUNET_NO); + return transmission_size; +} + + +/** + * Method called whenever a given peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + */ +static void +connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + size_t size; + + if (!advertising) + return; + if (hostlist_uri == NULL) + return; + size = strlen (hostlist_uri) + 1; + if (size + sizeof (struct GNUNET_MessageHeader) >= + GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + size += sizeof (struct GNUNET_MessageHeader); + if (NULL == core) + { + GNUNET_break (0); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asked core to transmit advertisement message with a size of %u bytes to peer `%s'\n", + size, GNUNET_i2s (peer)); + if (NULL == + GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 0, + GNUNET_ADV_TIMEOUT, peer, size, + &adv_transmit_ready, NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Advertisement message could not be queued by core\n")); + } +} + + +/** + * Method called whenever a given peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + /* nothing to do */ +} + +/** + * PEERINFO calls this function to let us know about a possible peer + * that we might want to connect to. + * + * @param cls closure (not used) + * @param peer potential peer to connect to + * @param hello HELLO for this peer (or NULL) + * @param err_msg NULL if successful, otherwise contains error message + */ +static void +process_notify (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, const char *err_msg) +{ + struct HostSet *results; + +#if DEBUG_HOSTLIST_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peerinfo is notifying us to rebuild our hostlist\n"); +#endif + if (err_msg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Error in communication with PEERINFO service\n")); + /* return; */ + } + results = GNUNET_malloc (sizeof (struct HostSet)); + GNUNET_assert (peerinfo != NULL); + pitr = + GNUNET_PEERINFO_iterate (peerinfo, NULL, GNUNET_TIME_UNIT_MINUTES, + &host_processor, results); +} + +/** + * Function that queries MHD's select sets and + * starts the task waiting for them. + */ +static GNUNET_SCHEDULER_TaskIdentifier +prepare_daemon (struct MHD_Daemon *daemon_handle); + + +/** + * Call MHD to process pending requests and then go back + * and schedule the next run. + */ +static void +run_daemon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct MHD_Daemon *daemon_handle = cls; + + if (daemon_handle == daemon_handle_v4) + hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK; + else + hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + GNUNET_assert (MHD_YES == MHD_run (daemon_handle)); + if (daemon_handle == daemon_handle_v4) + hostlist_task_v4 = prepare_daemon (daemon_handle); + else + hostlist_task_v6 = prepare_daemon (daemon_handle); +} + + +/** + * Function that queries MHD's select sets and + * starts the task waiting for them. + */ +static GNUNET_SCHEDULER_TaskIdentifier +prepare_daemon (struct MHD_Daemon *daemon_handle) +{ + GNUNET_SCHEDULER_TaskIdentifier ret; + fd_set rs; + fd_set ws; + fd_set es; + struct GNUNET_NETWORK_FDSet *wrs; + struct GNUNET_NETWORK_FDSet *wws; + struct GNUNET_NETWORK_FDSet *wes; + int max; + unsigned long long timeout; + int haveto; + struct GNUNET_TIME_Relative tv; + + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + wrs = GNUNET_NETWORK_fdset_create (); + wes = GNUNET_NETWORK_fdset_create (); + wws = GNUNET_NETWORK_fdset_create (); + max = -1; + GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); + haveto = MHD_get_timeout (daemon_handle, &timeout); + if (haveto == MHD_YES) + tv.rel_value = (uint64_t) timeout; + else + tv = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); + GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws, + &run_daemon, daemon_handle); + GNUNET_NETWORK_fdset_destroy (wrs); + GNUNET_NETWORK_fdset_destroy (wws); + GNUNET_NETWORK_fdset_destroy (wes); + return ret; +} + + + +/** + * Start server offering our hostlist. + * + * @return GNUNET_OK on success + */ +int +GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_STATISTICS_Handle *st, + struct GNUNET_CORE_Handle *co, + GNUNET_CORE_ConnectEventHandler *server_ch, + GNUNET_CORE_DisconnectEventHandler *server_dh, + int advertise) +{ + unsigned long long port; + char *hostname; + size_t size; + + advertising = advertise; + if (!advertising) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Advertising not enabled on this hostlist server\n"); + else + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Advertising enabled on this hostlist server\n"); + cfg = c; + stats = st; + peerinfo = GNUNET_PEERINFO_connect (cfg); + if (peerinfo == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access PEERINFO service. Exiting.\n")); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "HOSTLIST", "HTTPPORT", + &port)) + return GNUNET_SYSERR; + if ((port == 0) || (port > UINT16_MAX)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Invalid port number %llu. Exiting.\n"), port); + return GNUNET_SYSERR; + } + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", + "EXTERNAL_DNS_NAME", &hostname)) + hostname = GNUNET_RESOLVER_local_fqdn_get (); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Hostlist service starts on %s:%llu\n"), + hostname, port); + if (NULL != hostname) + { + size = strlen (hostname); + if (size + 15 > MAX_URL_LEN) + { + GNUNET_break (0); + } + else + { + GNUNET_asprintf (&hostlist_uri, "http://%s:%u/", hostname, + (unsigned int) port); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Address to obtain hostlist: `%s'\n"), hostlist_uri); + } + GNUNET_free (hostname); + } + daemon_handle_v6 = MHD_start_daemon (MHD_USE_IPv6 +#if DEBUG_HOSTLIST_SERVER + | MHD_USE_DEBUG +#endif + , (unsigned short) port, + &accept_policy_callback, NULL, + &access_handler_callback, NULL, + MHD_OPTION_CONNECTION_LIMIT, + (unsigned int) 16, + MHD_OPTION_PER_IP_CONNECTION_LIMIT, + (unsigned int) 1, + MHD_OPTION_CONNECTION_TIMEOUT, + (unsigned int) 16, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (16 * 1024), MHD_OPTION_END); + daemon_handle_v4 = MHD_start_daemon (MHD_NO_FLAG +#if DEBUG_HOSTLIST_SERVER + | MHD_USE_DEBUG +#endif + , (unsigned short) port, + &accept_policy_callback, NULL, + &access_handler_callback, NULL, + MHD_OPTION_CONNECTION_LIMIT, + (unsigned int) 16, + MHD_OPTION_PER_IP_CONNECTION_LIMIT, + (unsigned int) 1, + MHD_OPTION_CONNECTION_TIMEOUT, + (unsigned int) 16, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (16 * 1024), MHD_OPTION_END); + + if ((daemon_handle_v6 == NULL) && (daemon_handle_v4 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not start hostlist HTTP server on port %u\n"), + (unsigned short) port); + return GNUNET_SYSERR; + } + + core = co; + + *server_ch = &connect_handler; + *server_dh = &disconnect_handler; + + if (daemon_handle_v4 != NULL) + hostlist_task_v4 = prepare_daemon (daemon_handle_v4); + if (daemon_handle_v6 != NULL) + hostlist_task_v6 = prepare_daemon (daemon_handle_v6); + + notify = GNUNET_PEERINFO_notify (cfg, process_notify, NULL); + + return GNUNET_OK; +} + +/** + * Stop server offering our hostlist. + */ +void +GNUNET_HOSTLIST_server_stop () +{ +#if DEBUG_HOSTLIST_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist server shutdown\n"); +#endif + if (NULL != notify) + { + GNUNET_PEERINFO_notify_cancel (notify); + notify = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v6) + { + GNUNET_SCHEDULER_cancel (hostlist_task_v6); + hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v4) + { + GNUNET_SCHEDULER_cancel (hostlist_task_v4); + hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK; + } + if (pitr != NULL) + { + GNUNET_PEERINFO_iterate_cancel (pitr); + pitr = NULL; + } + if (NULL != daemon_handle_v4) + { + MHD_stop_daemon (daemon_handle_v4); + daemon_handle_v4 = NULL; + } + if (NULL != daemon_handle_v6) + { + MHD_stop_daemon (daemon_handle_v6); + daemon_handle_v6 = NULL; + } + if (response != NULL) + { + MHD_destroy_response (response); + response = NULL; + } + if (peerinfo != NULL) + { + GNUNET_PEERINFO_disconnect (peerinfo); + peerinfo = NULL; + } + cfg = NULL; + stats = NULL; + core = NULL; +} + +/* end of hostlist-server.c */ diff --git a/src/hostlist/hostlist-server.h b/src/hostlist/hostlist-server.h new file mode 100644 index 0000000..e0f8eb4 --- /dev/null +++ b/src/hostlist/hostlist-server.h @@ -0,0 +1,58 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file hostlist/hostlist-server.h + * @brief hostlist support. Downloads HELLOs via HTTP. + * @author Christian Grothoff + */ + +#ifndef HOSTLIST_SERVER_H +#define HOSTLIST_SERVER_H + +#include "gnunet_core_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_util_lib.h" + +#define GNUNET_ADV_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) + +/** + * Start server offering our hostlist. + * + * @return GNUNET_OK on success + */ +int +GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_STATISTICS_Handle *st, + struct GNUNET_CORE_Handle *core, + GNUNET_CORE_ConnectEventHandler *server_ch, + GNUNET_CORE_DisconnectEventHandler *server_dh, + int advertise); + + +/** + * Stop server offering our hostlist. + */ +void +GNUNET_HOSTLIST_server_stop (void); + + +#endif +/* end of hostlist-server.h */ diff --git a/src/hostlist/hostlist.conf b/src/hostlist/hostlist.conf new file mode 100644 index 0000000..b13e1e5 --- /dev/null +++ b/src/hostlist/hostlist.conf @@ -0,0 +1,14 @@ +[hostlist] +# port for hostlist http server +HTTPPORT = 8080 +HOME = $SERVICEHOME +HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-hostlist +# consider having "-e" as default as well once implemented +OPTIONS = -b +SERVERS = http://v9.gnunet.org:58080/ http://ioerror.gnunet.org:65535/ +# proxy for downloading hostlists +HTTP-PROXY = + + diff --git a/src/hostlist/learning_data.conf b/src/hostlist/learning_data.conf new file mode 100644 index 0000000..e3a3897 --- /dev/null +++ b/src/hostlist/learning_data.conf @@ -0,0 +1,14 @@ +@INLINE@ test_hostlist_defaults.conf +[hostlist] +HTTPPORT = 28080 +OPTIONS = -b -e +SERVERS = http://gnunet.org:8080/ +PORT = 23354 +HOSTNAME = localhost + +[datastore] +AUTOSTART = YES + +[fs] +AUTOSTART = YES + diff --git a/src/hostlist/test_gnunet_daemon_hostlist.c b/src/hostlist/test_gnunet_daemon_hostlist.c new file mode 100644 index 0000000..da3ab8b --- /dev/null +++ b/src/hostlist/test_gnunet_daemon_hostlist.c @@ -0,0 +1,255 @@ +/* + This file is part of GNUnet + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file hostlist/test_gnunet_daemon_hostlist.c + * @brief test for gnunet_daemon_hostslist.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_transport_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150) + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier timeout_task; + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_TRANSPORT_Handle *th; + struct GNUNET_MessageHeader *hello; + struct GNUNET_TRANSPORT_GetHelloHandle *ghh; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct PeerContext p2; + + +static void +clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (p1.th != NULL) + { + if (p1.ghh != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); + p1.ghh = NULL; + } + GNUNET_TRANSPORT_disconnect (p1.th); + p1.th = NULL; + } + if (p2.th != NULL) + { + if (p2.ghh != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); + p2.ghh = NULL; + } + GNUNET_TRANSPORT_disconnect (p2.th); + p2.th = NULL; + } + GNUNET_SCHEDULER_shutdown (); +} + +/** + * Timeout, give up. + */ +static void +timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout trying to connect peers, test failed.\n"); + clean_up (NULL, tc); +} + + +/** + * Function called to notify transport users that another + * peer connected to us. + * + * @param cls closure + * @param peer the peer that connected + * @param latency current latency of the connection + * @param distance in overlay hops, as given by transport plugin + */ +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + if (peer == NULL) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected, shutting down.\n"); + ok = 0; + if (timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (timeout_task); + timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_SCHEDULER_add_now (&clean_up, NULL); +} + + +static void +process_hello (void *cls, const struct GNUNET_MessageHeader *message) +{ + struct PeerContext *p = cls; + + GNUNET_TRANSPORT_get_hello_cancel (p->ghh); + p->ghh = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received HELLO, starting hostlist service.\n"); +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + p->th = + GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, ¬ify_connect, NULL); + GNUNET_assert (p->th != NULL); + p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p); +} + + +static void +waitpid_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerContext *p = cls; + +#if START_ARM + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Killing ARM process.\n"); + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +stop_arm (struct PeerContext *p) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking ARM to stop core service\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &waitpid_task, p); +} + + +/** + * Try again to connect to transport service. + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + stop_arm (&p1); + stop_arm (&p2); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_assert (ok == 1); + ok++; + timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + setup_peer (&p1, "test_gnunet_daemon_hostlist_peer1.conf"); + setup_peer (&p2, "test_gnunet_daemon_hostlist_peer2.conf"); +} + + +static int +check () +{ + char *const argv[] = { "test-gnunet-daemon-hostlist", + "-c", "test_gnunet_daemon_hostlist_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gnunet-daemon-hostlist", "nohelp", options, &run, + &ok); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + + int ret; + + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist"); + GNUNET_log_setup ("test-gnunet-daemon-hostlist", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist"); + return ret; +} + +/* end of test_gnunet_daemon_hostlist.c */ diff --git a/src/hostlist/test_gnunet_daemon_hostlist_data.conf b/src/hostlist/test_gnunet_daemon_hostlist_data.conf new file mode 100644 index 0000000..74d16be --- /dev/null +++ b/src/hostlist/test_gnunet_daemon_hostlist_data.conf @@ -0,0 +1,29 @@ +@INLINE@ test_hostlist_defaults.conf +[transport-tcp] +PORT = 12968 + +[arm] +PORT = 12966 +DEFAULTSERVICES = hostlist topology + +[statistics] +PORT = 12967 + +[resolver] +PORT = 12964 + +[peerinfo] +PORT = 12969 + +[transport] +PORT = 12965 + +[core] +PORT = 12970 + +[hostlist] +HTTPPORT = 28080 +SERVERS = http://gnunet.org:8080/ +PORT = 23354 +HOSTNAME = localhost + diff --git a/src/hostlist/test_gnunet_daemon_hostlist_learning.c b/src/hostlist/test_gnunet_daemon_hostlist_learning.c new file mode 100644 index 0000000..9ef8812 --- /dev/null +++ b/src/hostlist/test_gnunet_daemon_hostlist_learning.c @@ -0,0 +1,533 @@ +/* + This file is part of GNUnet + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file hostlist/test_gnunet_daemon_hostlist.c + * @brief test for gnunet_daemon_hostslist.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_core_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_resolver_service.h" +#include "gnunet_statistics_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + +#define MAX_URL_LEN 1000 + +/** + * How long until wait until testcases fails + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 180) + +#define CHECK_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_TRANSPORT_Handle *th; + struct GNUNET_MessageHeader *hello; + struct GNUNET_CORE_Handle *core; + struct GNUNET_STATISTICS_Handle *stats; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static int timeout; + +static int adv_sent; + +static int adv_arrived; + +static int learned_hostlist_saved; + +static int learned_hostlist_downloaded; + +static char *current_adv_uri; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static GNUNET_SCHEDULER_TaskIdentifier timeout_task; + +static GNUNET_SCHEDULER_TaskIdentifier check_task; + +static struct PeerContext adv_peer; + +static struct PeerContext learn_peer; + +static struct GNUNET_STATISTICS_GetHandle *download_stats; + +static struct GNUNET_STATISTICS_GetHandle *urisrecv_stat; + +static struct GNUNET_STATISTICS_GetHandle *advsent_stat; + + +static void +shutdown_testcase () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown testcase....\n"); + if (timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (timeout_task); + timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != download_stats) + { + GNUNET_STATISTICS_get_cancel (download_stats); + download_stats = NULL; + } + if (NULL != urisrecv_stat) + { + GNUNET_STATISTICS_get_cancel (urisrecv_stat); + urisrecv_stat = NULL; + } + if (NULL != advsent_stat) + { + GNUNET_STATISTICS_get_cancel (advsent_stat); + advsent_stat = NULL; + } + if (check_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (check_task); + check_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != current_adv_uri) + { + GNUNET_free (current_adv_uri); + current_adv_uri = NULL; + } + if (adv_peer.th != NULL) + { + GNUNET_TRANSPORT_disconnect (adv_peer.th); + adv_peer.th = NULL; + } + if (learn_peer.th != NULL) + { + GNUNET_TRANSPORT_disconnect (learn_peer.th); + learn_peer.th = NULL; + } + if (adv_peer.core != NULL) + { + GNUNET_CORE_disconnect (adv_peer.core); + adv_peer.core = NULL; + } + if (learn_peer.core != NULL) + { + GNUNET_CORE_disconnect (learn_peer.core); + learn_peer.core = NULL; + } +#if START_ARM + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Killing hostlist server ARM process.\n"); + if (0 != GNUNET_OS_process_kill (adv_peer.arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (adv_peer.arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_OS_process_close (adv_peer.arm_proc); + adv_peer.arm_proc = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Killing hostlist client ARM process.\n"); + if (0 != GNUNET_OS_process_kill (learn_peer.arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (learn_peer.arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_OS_process_close (learn_peer.arm_proc); + learn_peer.arm_proc = NULL; +#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown complete....\n"); +} + +/** + * Timeout, give up. + */ +static void +timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout while executing testcase, test failed.\n"); + timeout = GNUNET_YES; + shutdown_testcase (); +} + + +static void +process_downloads_done (void *cls, int success) +{ + download_stats = NULL; +} + + +static int +process_downloads (void *cls, const char *subsystem, const char *name, + uint64_t value, int is_persistent) +{ + if ((value >= 2) && (learned_hostlist_downloaded == GNUNET_NO)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Peer has successfully downloaded advertised URI\n"); + learned_hostlist_downloaded = GNUNET_YES; + if ((learned_hostlist_saved == GNUNET_YES) && (adv_sent == GNUNET_YES)) + shutdown_testcase (); + } + return GNUNET_OK; +} + + +static void +process_uris_recv_done (void *cls, int success) +{ + urisrecv_stat = NULL; +} + + +static int +process_uris_recv (void *cls, const char *subsystem, const char *name, + uint64_t value, int is_persistent) +{ + if (((struct PeerContext *) cls == &learn_peer) && (value == 1) && + (learned_hostlist_saved == GNUNET_NO)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Peer has successfully saved advertised URI\n"); + learned_hostlist_saved = GNUNET_YES; + if ((learned_hostlist_downloaded == GNUNET_YES) && (adv_sent == GNUNET_YES)) + shutdown_testcase (); + } + return GNUNET_OK; +} + + +static void +process_adv_sent_done (void *cls, int success) +{ + advsent_stat = NULL; +} + + +static int +process_adv_sent (void *cls, const char *subsystem, const char *name, + uint64_t value, int is_persistent) +{ + if ((value >= 1) && (adv_sent == GNUNET_NO)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Server has successfully sent advertisement\n"); + adv_sent = GNUNET_YES; + if ((learned_hostlist_downloaded == GNUNET_YES) && + (learned_hostlist_saved == GNUNET_YES)) + shutdown_testcase (); + } + return GNUNET_OK; +} + + +/** + * Check the server statistics regularly + */ +static void +check_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *stat; + + check_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + GNUNET_asprintf (&stat, gettext_noop ("# advertised URI `%s' downloaded"), + current_adv_uri); + if (NULL != learn_peer.stats) + { + if (NULL != download_stats) + GNUNET_STATISTICS_get_cancel (download_stats); + download_stats = + GNUNET_STATISTICS_get (learn_peer.stats, "hostlist", stat, + GNUNET_TIME_UNIT_MINUTES, + &process_downloads_done, &process_downloads, + &learn_peer); + if (NULL != urisrecv_stat) + GNUNET_STATISTICS_get_cancel (urisrecv_stat); + urisrecv_stat = + GNUNET_STATISTICS_get (learn_peer.stats, "hostlist", + gettext_noop ("# advertised hostlist URIs"), + GNUNET_TIME_UNIT_MINUTES, + &process_uris_recv_done, &process_uris_recv, + &learn_peer); + } + GNUNET_free (stat); + if (NULL != adv_peer.stats) + { + if (NULL != advsent_stat) + GNUNET_STATISTICS_get_cancel (advsent_stat); + advsent_stat = + GNUNET_STATISTICS_get (adv_peer.stats, "hostlist", + gettext_noop ("# hostlist advertisements send"), + GNUNET_TIME_UNIT_MINUTES, &process_adv_sent_done, + &process_adv_sent, NULL); + } + check_task = + GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL, &check_statistics, NULL); +} + + +/** + * Core handler for p2p hostlist advertisements + */ +static int +ad_arrive_handler (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + char *hostname; + char *expected_uri; + unsigned long long port; + const struct GNUNET_MessageHeader *incoming; + const char *end; + + if (-1 == + GNUNET_CONFIGURATION_get_value_number (adv_peer.cfg, "HOSTLIST", + "HTTPPORT", &port)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not read advertising server's configuration\n"); + return GNUNET_SYSERR; + } + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (adv_peer.cfg, "HOSTLIST", + "EXTERNAL_DNS_NAME", &hostname)) + hostname = GNUNET_RESOLVER_local_fqdn_get (); + GNUNET_asprintf (&expected_uri, "http://%s:%u/", + hostname != NULL ? hostname : "localhost", + (unsigned int) port); + incoming = (const struct GNUNET_MessageHeader *) message; + end = (const char *) &incoming[1]; + if ('\0' != + end[ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - 1]) + { + GNUNET_break (0); + GNUNET_free (expected_uri); + GNUNET_free_non_null (hostname); + return GNUNET_SYSERR; + } + current_adv_uri = GNUNET_strdup (end); + if (0 == strcmp (expected_uri, current_adv_uri)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received hostlist advertisement with URI `%s' as expected\n", + current_adv_uri); + adv_arrived = GNUNET_YES; + adv_sent = GNUNET_YES; + } + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected URI `%s' and recieved URI `%s' differ\n", + expected_uri, current_adv_uri); + GNUNET_free (expected_uri); + GNUNET_free_non_null (hostname); + return GNUNET_OK; +} + + +/** + * List of handlers if we are learning. + */ +static struct GNUNET_CORE_MessageHandler learn_handlers[] = { + {&ad_arrive_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0}, + {NULL, 0, 0} +}; + + +static void +setup_learn_peer (struct PeerContext *p, const char *cfgname) +{ + char *filename; + unsigned int result; + + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (p->cfg, "HOSTLIST", "HOSTLISTFILE", + &filename)) + { + if (GNUNET_YES == GNUNET_DISK_file_test (filename)) + { + result = UNLINK (filename); + if (result == 0) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Hostlist file `%s' was removed\n"), filename); + } + GNUNET_free (filename); + } + p->core = + GNUNET_CORE_connect (p->cfg, 1, NULL, NULL, NULL, NULL, NULL, GNUNET_NO, + NULL, GNUNET_NO, learn_handlers); + GNUNET_assert (NULL != p->core); + p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg); + GNUNET_assert (NULL != p->stats); +} + + +static void +setup_adv_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg); + GNUNET_assert (NULL != p->stats); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + timeout = GNUNET_NO; + adv_sent = GNUNET_NO; + + adv_arrived = 0; + learned_hostlist_saved = GNUNET_NO; + learned_hostlist_downloaded = GNUNET_NO; + + cfg = c; + + setup_adv_peer (&adv_peer, "test_learning_adv_peer.conf"); + setup_learn_peer (&learn_peer, "test_learning_learn_peer.conf"); + timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL); + + check_task = + GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL, &check_statistics, NULL); +} + + +static int +check () +{ + unsigned int failed; + + char *const argv[] = { + "test-gnunet-daemon-hostlist-learning", + "-c", "learning_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gnunet-daemon-hostlist-learning", "nohelp", options, + &run, NULL); + failed = GNUNET_NO; + if (timeout == GNUNET_YES) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testcase timeout\n"); + failed = GNUNET_YES; + } + if (adv_arrived != GNUNET_YES) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Learning peer did not receive advertisement from server\n"); + failed = GNUNET_YES; + } + if (learned_hostlist_saved == GNUNET_NO) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Advertised hostlist was not saved in datastore\n"); + failed = GNUNET_YES; + } + if (learned_hostlist_downloaded == GNUNET_NO) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Advertised hostlist could not be downloaded from server\n"); + failed = GNUNET_YES; + } + if (adv_sent == GNUNET_NO) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Advertised was not sent from server to client\n"); + failed = GNUNET_YES; + } + if (GNUNET_YES == failed) + return GNUNET_YES; + return GNUNET_NO; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); + GNUNET_log_setup ("test-gnunet-daemon-hostlist", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); +#if !WINDOWS + system ("gnunet-peerinfo -s -c test_learning_adv_peer.conf > /dev/null"); + system ("gnunet-peerinfo -s -c test_learning_learn_peer.conf > /dev/null"); +#else + system ("gnunet-peerinfo -s -c test_learning_adv_peer.conf > NUL"); + system ("gnunet-peerinfo -s -c test_learning_learn_peer.conf > NUL"); +#endif + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); + if (GNUNET_YES == GNUNET_DISK_file_test ("hostlists_learn_peer.file")) + { + if (0 == UNLINK ("hostlists_learn_peer.file")) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Hostlist file hostlists_learn_peer.file was removed\n"); + } + return ret; +} + +/* end of test_gnunet_daemon_hostlist.c */ diff --git a/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf b/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf new file mode 100644 index 0000000..535b60e --- /dev/null +++ b/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf @@ -0,0 +1,43 @@ +@INLINE@ test_hostlist_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-hostlist-peer-1/ +DEFAULTCONFIG = test_gnunet_daemon_hostlist_peer1.conf + +[transport-tcp] +PORT = 12968 + +[arm] +PORT = 12966 +DEFAULTSERVICES = hostlist topology +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12967 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12964 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12969 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12965 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +DEBUG = NO + +[core] +PORT = 12970 +UNIXPATH = /tmp/gnunet-p1-service-core.sock + +[hostlist] +HTTPPORT = 12980 +HOSTLISTFILE = hostlists_peer1.file +OPTIONS = -b -p +SERVERS = http://localhost:12981/ + +PORT = 12971 +UNIXPATH = /tmp/gnunet-p1-service-ats.sock + diff --git a/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf b/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf new file mode 100644 index 0000000..41862da --- /dev/null +++ b/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf @@ -0,0 +1,43 @@ +@INLINE@ test_hostlist_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-hostlist-peer-2/ +DEFAULTCONFIG = test_gnunet_daemon_hostlist_peer2.conf + +[transport-tcp] +PORT = 22968 + +[arm] +PORT = 22966 +DEFAULTSERVICES = hostlist topology +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 22967 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 22964 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 22969 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 22965 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + +[core] +PORT = 22970 +UNIXPATH = /tmp/gnunet-p2-service-core.sock + +[hostlist] +HTTPPORT = 12981 +HOSTLISTFILE = hostlists_peer2.file +OPTIONS = -b -p +SERVERS = http://localhost:12980/ + +[ats] +PORT = 22971 +UNIXPATH = /tmp/gnunet-p2-service-ats.sock + diff --git a/src/hostlist/test_gnunet_daemon_hostlist_reconnect.c b/src/hostlist/test_gnunet_daemon_hostlist_reconnect.c new file mode 100644 index 0000000..a991557 --- /dev/null +++ b/src/hostlist/test_gnunet_daemon_hostlist_reconnect.c @@ -0,0 +1,266 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file hostlist/test_gnunet_daemon_hostlist_reconnect.c + * @brief test for gnunet_daemon_hostslist.c; tries to re-start the peers + * and connect a second time + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_transport_service.h" + +#define VERBOSE GNUNET_NO + +#define START_ARM GNUNET_YES + + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150) + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier timeout_task; + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_TRANSPORT_Handle *th; + struct GNUNET_MessageHeader *hello; + struct GNUNET_TRANSPORT_GetHelloHandle *ghh; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +static struct PeerContext p2; + + +static void +clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != p1.ghh) + { + GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); + p1.ghh = NULL; + } + if (p1.th != NULL) + { + GNUNET_TRANSPORT_disconnect (p1.th); + p1.th = NULL; + } + if (NULL != p2.ghh) + { + GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); + p2.ghh = NULL; + } + if (p2.th != NULL) + { + GNUNET_TRANSPORT_disconnect (p2.th); + p2.th = NULL; + } + GNUNET_SCHEDULER_shutdown (); +} + +/** + * Timeout, give up. + */ +static void +timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout trying to connect peers, test failed.\n"); + clean_up (NULL, tc); +} + + +/** + * Function called to notify transport users that another + * peer connected to us. + * + * @param cls closure + * @param peer the peer that connected + * @param latency current latency of the connection + * @param distance in overlay hops, as given by transport plugin + */ +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + if (peer == NULL) + return; +#if VERBOSE + FPRINTF (stderr, "Peer %s connected\n", GNUNET_i2s (peer)); +#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected, shutting down.\n"); + ok = 0; + if (timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (timeout_task); + timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_SCHEDULER_add_now (&clean_up, NULL); +} + + +static void +process_hello (void *cls, const struct GNUNET_MessageHeader *message) +{ + struct PeerContext *p = cls; + + GNUNET_TRANSPORT_get_hello_cancel (p->ghh); + p->ghh = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received HELLO, starting hostlist service.\n"); +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + p->th = + GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, ¬ify_connect, NULL); + GNUNET_assert (p->th != NULL); + p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p); +} + + +static void +waitpid_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerContext *p = cls; + +#if START_ARM + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Killing ARM process.\n"); + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +static void +stop_arm (struct PeerContext *p) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking ARM to stop core service\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &waitpid_task, p); +} + + +/** + * Try again to connect to transport service. + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + stop_arm (&p1); + stop_arm (&p2); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_assert (ok == 1); + ok++; + timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + setup_peer (&p1, "test_gnunet_daemon_hostlist_peer1.conf"); + setup_peer (&p2, "test_gnunet_daemon_hostlist_peer2.conf"); +} + + +static int +check () +{ + char *const argv[] = { "test-gnunet-daemon-hostlist", + "-c", "test_gnunet_daemon_hostlist_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gnunet-daemon-hostlist", "nohelp", options, &run, + &ok); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + + int ret; + + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-3"); + GNUNET_log_setup ("test-gnunet-daemon-hostlist", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + if (ret == 0) + { + FPRINTF (stderr, "%s", "."); + /* now do it again */ + ret = check (); + FPRINTF (stderr, "%s", ".\n"); + } + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-3"); + return ret; +} + +/* end of test_gnunet_daemon_hostlist_reconnect.c */ diff --git a/src/hostlist/test_hostlist_defaults.conf b/src/hostlist/test_hostlist_defaults.conf new file mode 100644 index 0000000..5772250 --- /dev/null +++ b/src/hostlist/test_hostlist_defaults.conf @@ -0,0 +1,62 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunet-hostlist/ +DEFAULTCONFIG = test_hostlist_default.conf + +[resolver] +PORT = 12464 + +[transport] +PORT = 12465 +PLUGINS = tcp + +[arm] +PORT = 12466 +DEFAULTSERVICES = hostlist + +[statistics] +PORT = 12467 + +[tcp] +PORT = 12468 + +[peerinfo] +PORT = 12469 + +[core] +PORT = 12470 + +[testing] +WEAKRANDOM = YES + +[hostlist] +HTTP-PROXY = + +[mesh] +AUTOSTART = NO + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[fs] +AUTOSTART = NO + +[dht] +AUTOSTART = NO + +[dv] +AUTOSTART = NO + +[chat] +AUTOSTART = NO + +[gns] +AUTOSTART = NO + +[vpn] +AUTOSTART = NO diff --git a/src/hostlist/test_learning_adv_peer.conf b/src/hostlist/test_learning_adv_peer.conf new file mode 100644 index 0000000..fe50bd5 --- /dev/null +++ b/src/hostlist/test_learning_adv_peer.conf @@ -0,0 +1,47 @@ +@INLINE@ test_hostlist_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-hostlist-peer-1/ +DEFAULTCONFIG = test_learning_adv_peer.conf + +[transport-tcp] +PORT = 22968 + +[arm] +PORT = 22966 +DEFAULTSERVICES = topology hostlist +UNIXPATH = /tmp/gnunet-hostlist-p2-service-arm.sock + +[statistics] +PORT = 22967 +UNIXPATH = /tmp/gnunet-hostlist-p2-service-statistics.sock + +[resolver] +PORT = 22964 +UNIXPATH = /tmp/gnunet-hostlist-p2-service-resolver.sock + +[peerinfo] +PORT = 22969 +UNIXPATH = /tmp/gnunet-hostlist-p2-service-peerinfo.sock + +[transport] +PORT = 22965 +UNIXPATH = /tmp/gnunet-hostlist-p2-service-transport.sock + +[core] +PORT = 22970 +UNIXPATH = /tmp/gnunet-hostlist-p2-service-core.sock + +[hostlist] +HTTPPORT = 12981 +HOSTLISTFILE = hostlists_adv_peer.file +OPTIONS = -p -a +SERVERS = http://localhost:12981/ +EXTERNAL_DNS_NAME = localhost + +[dht] +AUTOSTART = NO + + +[ats] +PORT = 22971 +UNIXPATH = /tmp/gnunet-ats-p2-service-core.sock diff --git a/src/hostlist/test_learning_learn_peer.conf b/src/hostlist/test_learning_learn_peer.conf new file mode 100644 index 0000000..0136d77 --- /dev/null +++ b/src/hostlist/test_learning_learn_peer.conf @@ -0,0 +1,46 @@ +@INLINE@ test_hostlist_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-hostlist-peer-2/ +DEFAULTCONFIG = test_learning_learn_peer.conf + +[transport-tcp] +PORT = 12968 + +[arm] +PORT = 12966 +DEFAULTSERVICES = topology hostlist +UNIXPATH = /tmp/gnunet-hostlist-p1-service-arm.sock + +[statistics] +PORT = 12967 +UNIXPATH = /tmp/gnunet-hostlist-p1-service-statistics.sock + +[resolver] +PORT = 12964 +UNIXPATH = /tmp/gnunet-hostlist-p1-service-resolver.sock + +[peerinfo] +PORT = 12969 +UNIXPATH = /tmp/gnunet-hostlist-p1-service-peerinfo.sock + +[transport] +PORT = 12965 +UNIXPATH = /tmp/gnunet-hostlist-p1-service-transport.sock + +[core] +PORT = 12970 +UNIXPATH = /tmp/gnunet-hostlist-p1-service-core.sock + +[hostlist] +HTTPPORT = 12980 +HOSTLISTFILE = hostlists_learn_peer.file +OPTIONS = -b -e +SERVERS = http://localhost:12981/ + +[dht] +AUTOSTART = NO + + +[ats] +PORT = 12971 +UNIXPATH = /tmp/gnunet-ats-p1-service-core.sock diff --git a/src/hostlist/test_learning_learn_peer2.conf b/src/hostlist/test_learning_learn_peer2.conf new file mode 100644 index 0000000..4fd54bb --- /dev/null +++ b/src/hostlist/test_learning_learn_peer2.conf @@ -0,0 +1,39 @@ +@INLINE@ test_hostlist_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-hostlist-peer-3/ +DEFAULTCONFIG = test_learning_learn_peer2.conf + +[transport-tcp] +PORT = 32968 + +[arm] +PORT = 32966 +DEFAULTSERVICES = topology hostlist +UNIXPATH = /tmp/gnunet-p3-service-arm.sock + +[statistics] +PORT = 32967 +UNIXPATH = /tmp/gnunet-p3-service-statistics.sock + +[resolver] +PORT = 32964 +UNIXPATH = /tmp/gnunet-p3-service-resolver.sock + +[peerinfo] +PORT = 32969 +UNIXPATH = /tmp/gnunet-p3-service-peerinfo.sock + +[transport] +PORT = 32965 +UNIXPATH = /tmp/gnunet-p3-service-transport.sock + +[core] +PORT = 32970 +UNIXPATH = /tmp/gnunet-p3-service-core.sock + +[hostlist] +HTTPPORT = 32980 +HOSTLISTFILE = hostlists_learn_peer2.file +OPTIONS = -b -e +SERVERS = http://localhost:12981/ + diff --git a/src/include/Makefile.am b/src/include/Makefile.am new file mode 100644 index 0000000..afe4ecb --- /dev/null +++ b/src/include/Makefile.am @@ -0,0 +1,82 @@ +SUBDIRS = . + +gnunetincludedir = $(includedir)/gnunet + +nodist_gnunetinclude_HEADERS = \ + gnunet_directories.h \ + block_fs.h + +if MINGW + WINPROC = winproc.h +endif + +gnunetinclude_HEADERS = \ + gauger.h \ + gettext.h \ + platform.h \ + plibc.h \ + $(WINPROC) \ + block_dns.h \ + block_gns.h \ + block_fs.h \ + gnunet_applications.h \ + gnunet_arm_service.h \ + gnunet_ats_service.h \ + gnunet_bandwidth_lib.h \ + gnunet_bio_lib.h \ + gnunet_block_lib.h \ + gnunet_block_plugin.h \ + gnunet_client_lib.h \ + gnunet_chat_service.h \ + gnunet_common.h \ + gnunet_constants.h \ + gnunet_configuration_lib.h \ + gnunet_container_lib.h \ + gnunet_connection_lib.h \ + gnunet_core_service.h \ + gnunet_crypto_lib.h \ + gnunet_datacache_lib.h \ + gnunet_datacache_plugin.h \ + gnunet_datastore_service.h \ + gnunet_datastore_plugin.h \ + gnunet_dht_service.h \ + gnunet_disk_lib.h \ + gnunet_dnsparser_lib.h \ + gnunet_dns_service.h \ + gnunet_dv_service.h \ + gnunet_fragmentation_lib.h \ + gnunet_fs_service.h \ + gnunet_getopt_lib.h \ + gnunet_gns_service.h \ + gnunet_hello_lib.h \ + gnunet_helper_lib.h \ + gnunet_load_lib.h \ + gnunet_mesh_service.h \ + gnunet_namestore_plugin.h \ + gnunet_namestore_service.h \ + gnunet_nat_lib.h \ + gnunet_network_lib.h \ + gnunet_nse_service.h \ + gnunet_os_lib.h \ + gnunet_peer_lib.h \ + gnunet_peerinfo_service.h \ + gnunet_plugin_lib.h \ + gnunet_program_lib.h \ + gnunet_protocols.h \ + gnunet_pseudonym_lib.h \ + gnunet_resolver_service.h \ + gnunet_scheduler_lib.h \ + gnunet_server_lib.h \ + gnunet_service_lib.h \ + gnunet_signal_lib.h \ + gnunet_signatures.h \ + gnunet_statistics_service.h \ + gnunet_stream_lib.h \ + gnunet_strings_lib.h \ + gnunet_testing_lib.h \ + gnunet_time_lib.h \ + gnunet_transport_service.h \ + gnunet_transport_plugin.h \ + gnunet_tun_lib.h \ + gnunet_util_lib.h \ + gnunet_vpn_service.h diff --git a/src/include/Makefile.in b/src/include/Makefile.in new file mode 100644 index 0000000..ce91bd7 --- /dev/null +++ b/src/include/Makefile.in @@ -0,0 +1,840 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src/include +DIST_COMMON = $(am__gnunetinclude_HEADERS_DIST) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/gnunet_directories.h.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = gnunet_directories.h +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__gnunetinclude_HEADERS_DIST = gauger.h gettext.h platform.h plibc.h \ + winproc.h block_dns.h block_gns.h block_fs.h \ + gnunet_applications.h gnunet_arm_service.h \ + gnunet_ats_service.h gnunet_bandwidth_lib.h gnunet_bio_lib.h \ + gnunet_block_lib.h gnunet_block_plugin.h gnunet_client_lib.h \ + gnunet_chat_service.h gnunet_common.h gnunet_constants.h \ + gnunet_configuration_lib.h gnunet_container_lib.h \ + gnunet_connection_lib.h gnunet_core_service.h \ + gnunet_crypto_lib.h gnunet_datacache_lib.h \ + gnunet_datacache_plugin.h gnunet_datastore_service.h \ + gnunet_datastore_plugin.h gnunet_dht_service.h \ + gnunet_disk_lib.h gnunet_dnsparser_lib.h gnunet_dns_service.h \ + gnunet_dv_service.h gnunet_fragmentation_lib.h \ + gnunet_fs_service.h gnunet_getopt_lib.h gnunet_gns_service.h \ + gnunet_hello_lib.h gnunet_helper_lib.h gnunet_load_lib.h \ + gnunet_mesh_service.h gnunet_namestore_plugin.h \ + gnunet_namestore_service.h gnunet_nat_lib.h \ + gnunet_network_lib.h gnunet_nse_service.h gnunet_os_lib.h \ + gnunet_peer_lib.h gnunet_peerinfo_service.h \ + gnunet_plugin_lib.h gnunet_program_lib.h gnunet_protocols.h \ + gnunet_pseudonym_lib.h gnunet_resolver_service.h \ + gnunet_scheduler_lib.h gnunet_server_lib.h \ + gnunet_service_lib.h gnunet_signal_lib.h gnunet_signatures.h \ + gnunet_statistics_service.h gnunet_stream_lib.h \ + gnunet_strings_lib.h gnunet_testing_lib.h gnunet_time_lib.h \ + gnunet_transport_service.h gnunet_transport_plugin.h \ + gnunet_tun_lib.h gnunet_util_lib.h gnunet_vpn_service.h +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(gnunetincludedir)" \ + "$(DESTDIR)$(gnunetincludedir)" +HEADERS = $(gnunetinclude_HEADERS) $(nodist_gnunetinclude_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +gnunetincludedir = $(includedir)/gnunet +nodist_gnunetinclude_HEADERS = \ + gnunet_directories.h \ + block_fs.h + +@MINGW_TRUE@WINPROC = winproc.h +gnunetinclude_HEADERS = \ + gauger.h \ + gettext.h \ + platform.h \ + plibc.h \ + $(WINPROC) \ + block_dns.h \ + block_gns.h \ + block_fs.h \ + gnunet_applications.h \ + gnunet_arm_service.h \ + gnunet_ats_service.h \ + gnunet_bandwidth_lib.h \ + gnunet_bio_lib.h \ + gnunet_block_lib.h \ + gnunet_block_plugin.h \ + gnunet_client_lib.h \ + gnunet_chat_service.h \ + gnunet_common.h \ + gnunet_constants.h \ + gnunet_configuration_lib.h \ + gnunet_container_lib.h \ + gnunet_connection_lib.h \ + gnunet_core_service.h \ + gnunet_crypto_lib.h \ + gnunet_datacache_lib.h \ + gnunet_datacache_plugin.h \ + gnunet_datastore_service.h \ + gnunet_datastore_plugin.h \ + gnunet_dht_service.h \ + gnunet_disk_lib.h \ + gnunet_dnsparser_lib.h \ + gnunet_dns_service.h \ + gnunet_dv_service.h \ + gnunet_fragmentation_lib.h \ + gnunet_fs_service.h \ + gnunet_getopt_lib.h \ + gnunet_gns_service.h \ + gnunet_hello_lib.h \ + gnunet_helper_lib.h \ + gnunet_load_lib.h \ + gnunet_mesh_service.h \ + gnunet_namestore_plugin.h \ + gnunet_namestore_service.h \ + gnunet_nat_lib.h \ + gnunet_network_lib.h \ + gnunet_nse_service.h \ + gnunet_os_lib.h \ + gnunet_peer_lib.h \ + gnunet_peerinfo_service.h \ + gnunet_plugin_lib.h \ + gnunet_program_lib.h \ + gnunet_protocols.h \ + gnunet_pseudonym_lib.h \ + gnunet_resolver_service.h \ + gnunet_scheduler_lib.h \ + gnunet_server_lib.h \ + gnunet_service_lib.h \ + gnunet_signal_lib.h \ + gnunet_signatures.h \ + gnunet_statistics_service.h \ + gnunet_stream_lib.h \ + gnunet_strings_lib.h \ + gnunet_testing_lib.h \ + gnunet_time_lib.h \ + gnunet_transport_service.h \ + gnunet_transport_plugin.h \ + gnunet_tun_lib.h \ + gnunet_util_lib.h \ + gnunet_vpn_service.h + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/include/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/include/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +gnunet_directories.h: $(top_builddir)/config.status $(srcdir)/gnunet_directories.h.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-gnunetincludeHEADERS: $(gnunetinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(gnunetincludedir)" || $(MKDIR_P) "$(DESTDIR)$(gnunetincludedir)" + @list='$(gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(gnunetincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(gnunetincludedir)" || exit $$?; \ + done + +uninstall-gnunetincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(gnunetincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(gnunetincludedir)" && rm -f $$files +install-nodist_gnunetincludeHEADERS: $(nodist_gnunetinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(gnunetincludedir)" || $(MKDIR_P) "$(DESTDIR)$(gnunetincludedir)" + @list='$(nodist_gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(gnunetincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(gnunetincludedir)" || exit $$?; \ + done + +uninstall-nodist_gnunetincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nodist_gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(gnunetincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(gnunetincludedir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(gnunetincludedir)" "$(DESTDIR)$(gnunetincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-gnunetincludeHEADERS \ + install-nodist_gnunetincludeHEADERS + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-gnunetincludeHEADERS \ + uninstall-nodist_gnunetincludeHEADERS + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-gnunetincludeHEADERS install-html \ + install-html-am install-info install-info-am install-man \ + install-nodist_gnunetincludeHEADERS install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-gnunetincludeHEADERS \ + uninstall-nodist_gnunetincludeHEADERS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/include/block_dns.h b/src/include/block_dns.h new file mode 100644 index 0000000..4c2f1a3 --- /dev/null +++ b/src/include/block_dns.h @@ -0,0 +1,87 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/block_dns.h + * @author Philipp Toelke + */ +#ifndef _GNVPN_BLOCKDNS_H_ +#define _GNVPN_BLOCKDNS_H_ + +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" + +/** + * Bitmask describing what IP-protocols are supported by the service + */ +enum GNUNET_DNS_ServiceTypes +{ + GNUNET_DNS_SERVICE_TYPE_UDP = 1, + GNUNET_DNS_SERVICE_TYPE_TCP = 2 +}; + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * This is the structure describing an dns-record such as www.gnunet. + */ +struct GNUNET_DNS_Record +{ + /** + * Signature of the peer affirming that he is offering the service. + */ + struct GNUNET_CRYPTO_RsaSignature signature; + + /** + * Beginning of signed portion of the record, signs everything until + * the end of the struct. + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * The peer providing this service + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded peer; + + /** + * The descriptor for the service + * (a peer may provide more than one service) + */ + GNUNET_HashCode service_descriptor GNUNET_PACKED; + + /** + * When does this record expire? + */ + struct GNUNET_TIME_AbsoluteNBO expiration_time; + + /** + * Four TCP and UDP-Ports that are used by this service, big endian format + */ + uint64_t ports GNUNET_PACKED; + + /** + * What connection-types (UDP, TCP, ...) are supported by the service. + * Contains an 'enum GNUNET_DNS_ServiceTypes' in big endian format. + */ + uint32_t service_type GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/include/block_fs.h b/src/include/block_fs.h new file mode 100644 index 0000000..aae741e --- /dev/null +++ b/src/include/block_fs.h @@ -0,0 +1,167 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/block_fs.h + * @brief fs block formats (shared between fs and block) + * @author Christian Grothoff + */ +#ifndef BLOCK_FS_H +#define BLOCK_FS_H + +#include "gnunet_util_lib.h" + +/** + * @brief keyword block (advertising data under a keyword) + */ +struct KBlock +{ + + /** + * GNUNET_RSA_Signature using RSA-key generated from search keyword. + */ + struct GNUNET_CRYPTO_RsaSignature signature; + + /** + * What is being signed and why? + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * Key generated (!) from the H(keyword) as the seed! + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded keyspace; + + /* 0-terminated URI here */ + + /* variable-size Meta-Data follows here */ + +}; + + +/** + * @brief namespace content block (advertising data under an identifier in a namespace) + */ +struct SBlock +{ + + /** + * GNUNET_RSA_Signature using RSA-key of the namespace + */ + struct GNUNET_CRYPTO_RsaSignature signature; + + /** + * What is being signed and why? + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * Hash of the hash of the human-readable identifier used for + * this entry (the hash of the human-readable identifier is + * used as the key for decryption; the xor of this identifier + * and the hash of the "keyspace" is the datastore-query hash). + */ + GNUNET_HashCode identifier; + + /** + * Public key of the namespace. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded subspace; + + /* 0-terminated update-identifier here */ + + /* 0-terminated URI here (except for NBlocks) */ + + /* variable-size Meta-Data follows here */ + +}; + + +/** + * @brief namespace advertisement block (advertising root of a namespace) + */ +struct NBlock +{ + + /** + * GNUNET_RSA_Signature using RSA-key generated from search keyword. + */ + struct GNUNET_CRYPTO_RsaSignature ksk_signature; + + /** + * What is being signed and why? + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose ksk_purpose; + + /** + * Key generated (!) from the H(keyword) as the seed! + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded keyspace; + + /** + * GNUNET_RSA_Signature using RSA-key of the namespace + */ + struct GNUNET_CRYPTO_RsaSignature ns_signature; + + /** + * What is being signed and why? + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose ns_purpose; + + /** + * Public key of the namespace. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded subspace; + + /* from here on, data is encrypted with H(keyword) */ + + /* 0-terminated root identifier here */ + + /* variable-size Meta-Data follows here */ + +}; + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief index block (indexing a DBlock that + * can be obtained directly from reading + * the plaintext file) + */ +struct OnDemandBlock +{ + /** + * Hash code of the entire content of the + * file that was indexed (used to uniquely + * identify the plaintext file). + */ + GNUNET_HashCode file_id; + + /** + * At which offset should we be able to find + * this on-demand encoded block? (in NBO) + */ + uint64_t offset GNUNET_PACKED; + +}; +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/include/block_gns.h b/src/include/block_gns.h new file mode 100644 index 0000000..4514acf --- /dev/null +++ b/src/include/block_gns.h @@ -0,0 +1,93 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/block_gns.h + * @brief fs block formats (shared between fs and block) + * @author Martin Schanzenbach + */ +#ifndef BLOCK_GNS_H +#define BLOCK_GNS_H + +#include "gnunet_util_lib.h" + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief a simgle record inside a record block + */ +struct GNSRecordBlock +{ + /** + * the record type + */ + uint32_t type GNUNET_PACKED; + + /** + * expiration time of the record + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /** + * length of the data + */ + uint32_t data_length GNUNET_PACKED; + + /* record flags */ + uint32_t flags GNUNET_PACKED; + + //Class of the record? + + /* followed by the record data */ +}; + +/** + * @brief a record block for a given name of a single authority + */ +struct GNSNameRecordBlock +{ + + /** + * GNUNET_RSA_Signature using RSA-key generated from the records. + */ + struct GNUNET_CRYPTO_RsaSignature signature; + + /** + * What is being signed and why? + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * The public key of the authority + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + + /* number of records that follow */ + uint32_t rd_count GNUNET_PACKED; + + /* 0-terminated name here */ + + /* variable-size GNSRecordBlocks follows here */ + + +}; + +GNUNET_NETWORK_STRUCT_END +#endif diff --git a/src/include/gauger.h b/src/include/gauger.h new file mode 100644 index 0000000..9761cbe --- /dev/null +++ b/src/include/gauger.h @@ -0,0 +1,89 @@ +/** --------------------------------------------------------------------------- + * This software is in the public domain, furnished "as is", without technical + * support, and with no warranty, express or implied, as to its usefulness for + * any purpose. + * + * gauger.h + * Interface for C programs to log remotely to a gauger server + * + * Author: Bartlomiej Polot + * -------------------------------------------------------------------------*/ +#ifndef __GAUGER_H__ +#define __GAUGER_H__ + +#ifndef WINDOWS + +#include +#include +#include + +#define GAUGER(category, counter, value, unit)\ +{\ + char* __gauger_v[10];\ + char __gauger_s[32];\ + pid_t __gauger_p;\ + if(!(__gauger_p=fork())){\ + close (1); \ + close (2); \ + if(!fork()){\ + sprintf(__gauger_s,"%Lf", (long double) (value));\ + __gauger_v[0] = "gauger";\ + __gauger_v[1] = "-n";\ + __gauger_v[2] = counter;\ + __gauger_v[3] = "-d";\ + __gauger_v[4] = __gauger_s;\ + __gauger_v[5] = "-u";\ + __gauger_v[6] = unit;\ + __gauger_v[7] = "-c";\ + __gauger_v[8] = category;\ + __gauger_v[9] = (char *)NULL;\ + execvp("gauger",__gauger_v);\ + _exit(1);\ + }else{\ + _exit(0);\ + }\ + }else{\ + waitpid(__gauger_p,NULL,0);\ + }\ +} + +#define GAUGER_ID(category, counter, value, unit, id)\ +{\ + char* __gauger_v[12];\ + char __gauger_s[32];\ + pid_t __gauger_p;\ + if(!(__gauger_p=fork())){\ + close (1); \ + close (2); \ + if(!fork()){\ + sprintf(__gauger_s,"%Lf", (long double) (value));\ + __gauger_v[0] = "gauger";\ + __gauger_v[1] = "-n";\ + __gauger_v[2] = counter;\ + __gauger_v[3] = "-d";\ + __gauger_v[4] = __gauger_s;\ + __gauger_v[5] = "-u";\ + __gauger_v[6] = unit;\ + __gauger_v[7] = "-i";\ + __gauger_v[8] = id;\ + __gauger_v[9] = "-c";\ + __gauger_v[10] = category;\ + __gauger_v[11] = (char *)NULL;\ + execvp("gauger",__gauger_v);\ + _exit(1);\ + }else{\ + _exit(0);\ + }\ + }else{\ + waitpid(__gauger_p,NULL,0);\ + }\ +} + +#else + +#define GAUGER_ID(category, counter, value, unit, id) {} +#define GAUGER(category, counter, value, unit) {} + +#endif // WINDOWS + +#endif diff --git a/src/include/gettext.h b/src/include/gettext.h new file mode 100644 index 0000000..0295ac2 --- /dev/null +++ b/src/include/gettext.h @@ -0,0 +1,71 @@ +/* Convenience header for conditional use of GNU . + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +#include + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of a NOP. We don't include + as well because people using "gettext.h" will not include , + and also including would fail on SunOS 4, whereas + is GNUNET_OK. */ +#if defined(__sun) +#include +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +#define gettext(Msgid) ((const char *) (Msgid)) +#define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +#define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +#define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +#define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +#define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +/* slight modification here to avoid warnings: generate GNUNET_NO code, + not even the cast... */ +#define textdomain(Domainname) +#define bindtextdomain(Domainname, Dirname) +#define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ diff --git a/src/include/gnunet_applications.h b/src/include/gnunet_applications.h new file mode 100644 index 0000000..5feaeec --- /dev/null +++ b/src/include/gnunet_applications.h @@ -0,0 +1,74 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_applications.h + * @brief constants for network applications operating on top of the MESH service + * @author Christian Grothoff + */ + +#ifndef GNUNET_APPLICATIONS_H +#define GNUNET_APPLICATIONS_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * End of list marker. + */ +#define GNUNET_APPLICATION_TYPE_END 0 + +/** + * Test. + */ +#define GNUNET_APPLICATION_TYPE_TEST 1 + +/** + * Internet DNS resolution (external DNS gateway). + */ +#define GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER 2 + + +/** + * Internet IPv4 gateway (any TCP/UDP/ICMP). + */ +#define GNUNET_APPLICATION_TYPE_IPV4_GATEWAY 16 + +/** + * Internet IPv6 gateway (any TCP/UDP/ICMP). + */ +#define GNUNET_APPLICATION_TYPE_IPV6_GATEWAY 17 + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_APPLICATIONS_H */ +#endif +/* end of gnunet_applications.h */ diff --git a/src/include/gnunet_arm_service.h b/src/include/gnunet_arm_service.h new file mode 100644 index 0000000..af1c8cd --- /dev/null +++ b/src/include/gnunet_arm_service.h @@ -0,0 +1,194 @@ +/* + This file is part of GNUnet + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_arm_service.h + * @brief API to access gnunet-arm + * @author Christian Grothoff + */ + +#ifndef GNUNET_ARM_SERVICE_H +#define GNUNET_ARM_SERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_configuration_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +/** + * Version of the arm API. + */ +#define GNUNET_ARM_VERSION 0x00000001 + + +/** + * Values characterizing GNUnet process states. + */ +enum GNUNET_ARM_ProcessStatus +{ + /** + * Service name is unknown to ARM. + */ + GNUNET_ARM_PROCESS_UNKNOWN = -1, + + /** + * Service is now down (due to client request). + */ + GNUNET_ARM_PROCESS_DOWN = 0, + + /** + * Service is already running. + */ + GNUNET_ARM_PROCESS_ALREADY_RUNNING = 1, + + /** + * Service is currently being started (due to client request). + */ + GNUNET_ARM_PROCESS_STARTING = 2, + + /** + * Service is already being stopped by some other client. + */ + GNUNET_ARM_PROCESS_ALREADY_STOPPING = 3, + + /** + * Service is already down (no action taken) + */ + GNUNET_ARM_PROCESS_ALREADY_DOWN = 4, + + /** + * ARM is currently being shut down (no more process starts) + */ + GNUNET_ARM_PROCESS_SHUTDOWN = 5, + + /** + * Error in communication with ARM + */ + GNUNET_ARM_PROCESS_COMMUNICATION_ERROR = 6, + + /** + * Timeout in communication with ARM + */ + GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT = 7, + + /** + * Failure to perform operation + */ + GNUNET_ARM_PROCESS_FAILURE = 8 +}; + + +/** + * Callback function invoked when operation is complete. + * + * @param cls closure + * @param result outcome of the operation + */ +typedef void (*GNUNET_ARM_Callback) (void *cls, + enum GNUNET_ARM_ProcessStatus result); + + +/** + * Handle for interacting with ARM. + */ +struct GNUNET_ARM_Handle; + + +/** + * Setup a context for communicating with ARM. Note that this + * can be done even if the ARM service is not yet running. + * + * @param cfg configuration to use (needed to contact ARM; + * the ARM service may internally use a different + * configuration to determine how to start the service). + * @param service service that *this* process is implementing/providing, can be NULL + * @return context to use for further ARM operations, NULL on error + */ +struct GNUNET_ARM_Handle * +GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *service); + + +/** + * Disconnect from the ARM service. + * + * @param h the handle that was being used + */ +void +GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h); + + +/** + * Start a service. Note that this function merely asks ARM to start + * the service and that ARM merely confirms that it forked the + * respective process. The specified callback may thus return before + * the service has started to listen on the server socket and it may + * also be that the service has crashed in the meantime. Clients + * should repeatedly try to connect to the service at the respective + * port (with some delays in between) before assuming that the service + * actually failed to start. Note that if an error is returned to the + * callback, clients obviously should not bother with trying to + * contact the service. + * + * @param h handle to ARM + * @param service_name name of the service + * @param timeout how long to wait before failing for good + * @param cb callback to invoke when service is ready + * @param cb_cls closure for callback + */ +void +GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h, const char *service_name, + struct GNUNET_TIME_Relative timeout, + GNUNET_ARM_Callback cb, void *cb_cls); + + +/** + * Stop a service. Note that the callback is invoked as soon + * as ARM confirms that it will ask the service to terminate. + * The actual termination may still take some time. + * + * @param h handle to ARM + * @param service_name name of the service + * @param timeout how long to wait before failing for good + * @param cb callback to invoke when service is ready + * @param cb_cls closure for callback + */ +void +GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, const char *service_name, + struct GNUNET_TIME_Relative timeout, + GNUNET_ARM_Callback cb, void *cb_cls); + + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/gnunet_ats_service.h b/src/include/gnunet_ats_service.h new file mode 100644 index 0000000..858ae1d --- /dev/null +++ b/src/include/gnunet_ats_service.h @@ -0,0 +1,767 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file include/gnunet_ats_service.h + * @brief automatic transport selection and outbound bandwidth determination + * @author Christian Grothoff + * @author Matthias Wachs + */ +#ifndef GNUNET_ATS_SERVICE_H +#define GNUNET_ATS_SERVICE_H + +#include "gnunet_constants.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" + + +enum GNUNET_ATS_Network_Type +{ + GNUNET_ATS_NET_UNSPECIFIED = 0, + GNUNET_ATS_NET_LOOPBACK = 1, + GNUNET_ATS_NET_LAN = 2, + GNUNET_ATS_NET_WAN = 3, + GNUNET_ATS_NET_WLAN = 4, +}; + +/** + * Enum defining all known property types for ATS Enum values are used + * in the GNUNET_ATS_Information struct as + * (key,value)-pairs. + * + * Cost are always stored in uint32_t, so all units used to define costs + * have to be normalized to fit in uint32_t [0 .. 4.294.967.295] + */ +enum GNUNET_ATS_Property +{ + + /** + * End of the array. + * @deprecated + */ + GNUNET_ATS_ARRAY_TERMINATOR = 0, + + /** + * Actual traffic on this connection from the other peer to this peer. + * + * Unit: [bytes/second] + */ + GNUNET_ATS_UTILIZATION_UP, + + /** + * Actual traffic on this connection from this peer to the other peer. + * + * Unit: [bytes/second] + */ + GNUNET_ATS_UTILIZATION_DOWN, + + /** + * Is this address located in WAN, LAN or a loopback address + * Value is element of GNUNET_ATS_Network_Type + */ + GNUNET_ATS_NETWORK_TYPE, + + /** + * Delay + * Time between when the time packet is sent and the packet arrives + * + * Unit: [ms] + * + * Examples: + * + * LAN : 1 + * WLAN : 2 + * Dialup: 500 + */ + GNUNET_ATS_QUALITY_NET_DELAY, + + /** + * Distance on network layer (required for distance-vector routing). + * + * Unit: [DV-hops] + */ + GNUNET_ATS_QUALITY_NET_DISTANCE, + + /** + * Network overhead on WAN (Wide-Area Network) + * + * How many bytes are sent on the WAN when 1 kilobyte (1024 bytes) + * of application data is transmitted? + * A factor used with connect cost, bandwidth cost and energy cost + * to describe the overhead produced by the transport protocol + * + * Unit: [bytes/kb] + * + * Interpretation: less is better + * + * Examples: + * + * TCP/IPv4 over Ethernet: 1024 + 38 + 20 + 20 = 1102 [bytes/kb] + * TCP/IPv6 over Ethernet: 1024 + 38 + 20 + 40 = 1122 [bytes/kb] + * UDP/IPv4 over Ethernet: 1024 + 38 + 20 + 8 = 1090 [bytes/kb] + * UDP/IPv6 over Ethernet: 1024 + 38 + 40 + 8 = 1110 [bytes/kb] + */ + GNUNET_ATS_COST_WAN, + + /** + * Network overhead on LAN (Local-Area Network) + * + * How many bytes are sent on the LAN when 1 kilobyte (1024 bytes) + * of application data is transmitted? + * A factor used with connect cost, bandwidth cost and energy cost + * to describe the overhead produced by the transport protocol + * + * Unit: [bytes/kb] + * + * Interpretation: less is better + * + * Examples: + * + * TCP/IPv4 over Ethernet: 1024 + 38 + 20 + 20 = 1102 [bytes/kb] + * TCP/IPv6 over Ethernet: 1024 + 38 + 20 + 40 = 1122 [bytes/kb] + * UDP/IPv4 over Ethernet: 1024 + 38 + 20 + 8 = 1090 [bytes/kb] + * UDP/IPv6 over Ethernet: 1024 + 38 + 40 + 8 = 1110 [bytes/kb] + */ + GNUNET_ATS_COST_LAN, + + /** + * Network overhead on WLAN (Wireless Local Area Network) + * + * How many bytes are sent on the LAN when 1 kilobyte (1024 bytes) + * of application data is transmitted? + * A factor used with connect cost, bandwidth cost and energy cost + * to describe the overhead produced by the transport protocol + * + * Unit: [bytes/kb] + * + * Interpretation: less is better + * + * Examples: + * + * TCP/IPv4 over Ethernet: 1024 + 38 + 20 + 20 = 1102 [bytes/kb] + * TCP/IPv6 over Ethernet: 1024 + 38 + 20 + 40 = 1122 [bytes/kb] + * UDP/IPv4 over Ethernet: 1024 + 38 + 20 + 8 = 1090 [bytes/kb] + * UDP/IPv6 over Ethernet: 1024 + 38 + 40 + 8 = 1110 [bytes/kb] + */ + GNUNET_ATS_COST_WLAN + /* Cost related values */ + /* =================== */ + /** + * Volume based cost in financial units to transmit data + * + * Note: This value is not bound to a specific currency or unit and only + * used locally. + * "cent" just refers the smallest amount of money in the respective + * currency. + * + * Unit: [cent/MB] + * + * Interpretation: less is better + * + * Examples: + * LAN: 0 [cent/MB] + * 2G : 10 [cent/MB] + */ + // GNUNET_ATS_COST_FINANCIAL_PER_VOLUME = 1, + /** + * Time based cost in financial units to transmit data + * + * Note: This value is not bound to a specific currency or unit and only + * used locally. + * "cent" just refers the smallest amount of money in the respective + * currency. + * + * Unit: [cent/h] + * + * Interpretation: less is better + * + * Examples: + * LAN : 0 [cent/h] + * Dialup: 10 [cent/h] + */ + // GNUNET_ATS_COST_FINANCIAL_PER_TIME = 2, + /** + * Computational costs + * + * Effort of preparing data to be sent with this transport + * Includes encoding, encryption and conversion of data + * Partial values can be summed up: c_sum = c_enc + c_enc + c_conv + * Resulting values depend on local system properties, e.g. CPU + * + * Unit: [ms/GB] + * + * Interpretation: less is better + * + * Examples: + * + * HTTPS with AES CBC-256: 7,382 + * HTTPS with AES CBC-128: 5,279 + * HTTPS with RC4-1024: 2,652 + */ + // GNUNET_ATS_COST_COMPUTATIONAL = 3, + /** + * Energy consumption + * + * Energy consumption using this transport when sending with a certain + * power at a certain bitrate. This is only an approximation based on: + * Energy consumption E = P / D + * + * with: + * Power P in Watt (J/s) + * Datarate D in MBit/s + * + * Conversion between power P and dBm used by WLAN in radiotap's dBm TX power: + * + * Lp(dbm) = 10 log10 (P/ 1mW) + * + * => P = 1 mW * 10^(Lp(dbm)/10) + * + * Unit: [mJ/MB] + * + * Interpretation: less is better + * + * Examples: + * + * LAN: 0 + * WLAN: 89 (600 mW @ 802.11g /w 54 MBit/s) + * Bluetooth: 267 (100 mW @ BT2.0 EDR /w 3 MBit/s) + */ + // GNUNET_ATS_COST_ENERGY_CONSUMPTION = 4, + /** + * Connect cost + * How many bytes are transmitted to initiate a new connection using + * this transport? + * + * Unit: [bytes] + * + * Interpretation: less is better + * + * Examples: + * + * UDP (No connection) : + * 0 bytes + * TCP (TCP 3-Way handshake): + * 220 bytes Ethernet, 172 bytes TCP/IP, 122 bytes TCP + * HTTP (TCP + Header) : + * 477 bytes Ethernet, 429 bytes TCP/IP, 374 bytes TCP, 278 bytes HTTP + * HTTPS HTTP+TLS Handshake: + * 2129 bytes Ethernet, 1975 bytes TCP/IP, 1755 bytes TCP, 1403 bytes HTTPS + * + * */ + // GNUNET_ATS_COST_CONNECT = 5, + /** + * Bandwidth cost + * + * How many bandwidth is available to consume? + * Used to calculate which impact sending data with this transport has + * + * Unit: [kB/s] + * + * Interpretation: more is better + * + * Examples: + * LAN: 12,800 (100 MBit/s) + * WLAN: 6,912 (54 MBit/s) + * Dial-up: 8 (64 Kbit/s) + * + */ + // GNUNET_ATS_COST_BANDWITH_AVAILABLE = 6, + /** + * Network overhead + * + * How many bytes are sent over the wire when 1 kilobyte (1024 bytes) + * of application data is transmitted? + * A factor used with connect cost, bandwidth cost and energy cost + * to describe the overhead produced by the transport protocol + * + * Unit: [bytes/kb] + * + * Interpretation: less is better + * + * Examples: + * + * TCP/IPv4 over Ethernet: 1024 + 38 + 20 + 20 = 1102 [bytes/kb] + * TCP/IPv6 over Ethernet: 1024 + 38 + 20 + 40 = 1122 [bytes/kb] + * UDP/IPv4 over Ethernet: 1024 + 38 + 20 + 8 = 1090 [bytes/kb] + * UDP/IPv6 over Ethernet: 1024 + 38 + 40 + 8 = 1110 [bytes/kb] + */ + // GNUNET_ATS_COST_NETWORK_OVERHEAD = 7, + /* Quality related values */ + /* ====================== */ + /* Physical layer quality properties */ + /** + * Signal strength on physical layer + * + * Unit: [dBm] + */ + // GNUNET_ATS_QUALITY_PHY_SIGNAL_STRENGTH = 1025, + /** + * Collision rate on physical layer + * + * Unit: [B/s] + */ + // GNUNET_ATS_QUALITY_PHY_COLLISION_RATE = 1026, + /** + * Error rate on physical layer + * + * Unit: [B/s] + */ + // GNUNET_ATS_QUALITY_PHY_ERROR_RATE = 1027, + /** + * Jitter + * Time variations of the delay + * 1st derivative of a delay function + * + * Unit: [ms] + */ + // GNUNET_ATS_QUALITY_NET_JITTER = 1029, + /** + * Error rate on network layer + * + * Unit: [B/s] + * + * Examples: + * + * LAN : 0 + * WLAN : 400 + * Bluetooth : 100 + * Note: This numbers are just assumptions as an example, not + * measured or somehow determined + */ + // GNUNET_ATS_QUALITY_NET_ERRORRATE = 1030, + /** + * Drop rate on network layer + * Bytes actively dismissed by a network component during transmission + * Reasons for dropped data can be full queues, congestion, quota violations... + * + * Unit: [B/s] + * + * Examples: + * + * LAN : 0 + * WLAN : 400 + * Bluetooth : 100 + * Note: This numbers are just assumptions as an example, not + * measured or somehow determined + */ + // GNUNET_ATS_QUALITY_NET_DROPRATE = 1031, + /** + * Loss rate on network layer + * Bytes lost during transmission + * Reasons can be collisions, ... + * + * Unit: [B/s] + * + * Examples: + * + * LAN : 0 + * WLAN : 40 + * Bluetooth : 10 + * Note: This numbers are just assumptions as an example, not measured + * or somehow determined + */ + // GNUNET_ATS_QUALITY_NET_LOSSRATE = 1032, + /** + * Throughput on network layer + * + * Unit: [kB/s] + * + * Examples: + * + * LAN : 3400 + * WLAN : 1200 + * Dialup: 4 + * + */ + // GNUNET_ATS_QUALITY_NET_THROUGHPUT = 1033, + /* Availability related values */ + /* =========================== */ + /** + * Is a peer reachable? + */ + // GNUNET_ATS_AVAILABILITY_REACHABLE = 2048, + /** + * Is there a connection established to a peer using this transport + */ + // GNUNET_ATS_AVAILABILITY_CONNECTED = 2049 +}; + +/** + * Number of ATS quality properties + */ +#define GNUNET_ATS_QualityPropertiesCount 2 + +/** + * ATS quality properties as array initializer + */ +#define GNUNET_ATS_QualityProperties {GNUNET_ATS_QUALITY_NET_DELAY, GNUNET_ATS_QUALITY_NET_DISTANCE} + +/** + * Number of ATS quality properties + */ +#define GNUNET_ATS_NetworkTypeCount 5 + +/** + * ATS quality properties as array initializer + */ +#define GNUNET_ATS_NetworkType {GNUNET_ATS_NET_UNSPECIFIED, GNUNET_ATS_NET_LOOPBACK, GNUNET_ATS_NET_LAN, GNUNET_ATS_NET_WAN, GNUNET_ATS_NET_WLAN} + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * struct used to communicate the transport's properties like cost and + * quality of service as well as high-level constraints on resource + * consumption. + * + * +---+ + * +-----------+ Constraints | | Plugin properties +---------+ + * | Highlevel |------------> |ATS| <------------------|Transport| + * | Component | ATS struct | | ATS struct | Plugin | + * +-----------+ | | +---------+ + * +---+ + * + * This structure will be used by transport plugins to communicate + * costs to ATS or by higher level components to tell ATS their + * constraints. Always a pair of (GNUNET_ATS_Property, + * uint32_t value). Value is always uint32_t, so all units used to + * define costs have to be normalized to fit uint32_t. + */ +struct GNUNET_ATS_Information +{ + /** + * ATS property type, in network byte order. + */ + uint32_t type GNUNET_PACKED; + + /** + * ATS property value, in network byte order. + */ + uint32_t value GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + + +/* ******************************** Scheduling API ***************************** */ + +/** + * Handle to the ATS subsystem for bandwidth/transport scheduling information. + */ +struct GNUNET_ATS_SchedulingHandle; + + +/** + * Opaque session handle, defined by plugins. Contents not known to ATS. + */ +struct Session; + + +/** + * Signature of a function called by ATS with the current bandwidth + * and address preferences as determined by ATS. + * + * @param cls closure + * @param address suggested address (including peer identity of the peer) + * @param session session to use + * @param bandwidth_out assigned outbound bandwidth for the connection + * @param bandwidth_in assigned inbound bandwidth for the connection + * @param ats performance data for the address (as far as known) + * @param ats_count number of performance records in 'ats' + */ +typedef void (*GNUNET_ATS_AddressSuggestionCallback) (void *cls, + const struct + GNUNET_HELLO_Address * + address, + struct Session * session, + struct + GNUNET_BANDWIDTH_Value32NBO + bandwidth_out, + struct + GNUNET_BANDWIDTH_Value32NBO + bandwidth_in, + const struct + GNUNET_ATS_Information * + ats, uint32_t ats_count); + + +/** + * Initialize the ATS subsystem. + * + * @param cfg configuration to use + * @param suggest_cb notification to call whenever the suggestation changed + * @param suggest_cb_cls closure for 'suggest_cb' + * @return ats context + */ +struct GNUNET_ATS_SchedulingHandle * +GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_ATS_AddressSuggestionCallback suggest_cb, + void *suggest_cb_cls); + + +/** + * Client is done with ATS scheduling, release resources. + * + * @param sh handle to release + */ +void +GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh); + + +/** + * We would like to establish a new connection with a peer. ATS + * should suggest a good address to begin with. + * + * @param sh handle + * @param peer identity of the peer we need an address for + */ +void +GNUNET_ATS_suggest_address (struct GNUNET_ATS_SchedulingHandle *sh, + const struct GNUNET_PeerIdentity *peer); + + +/** + * We want to cancel ATS suggesting addresses for a peer. + * + * @param sh handle + * @param peer identity of the peer + */ +void +GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SchedulingHandle *sh, + const struct GNUNET_PeerIdentity *peer); + + +/** + * Returns where the address is located: LAN or WAN or ... + * @param sh the GNUNET_ATS_SchedulingHandle handle + * @param addr address + * @param addrlen address length + * @return location as GNUNET_ATS_Information + */ +const struct GNUNET_ATS_Information +GNUNET_ATS_address_get_type (struct GNUNET_ATS_SchedulingHandle *sh, + const struct sockaddr * addr, + socklen_t addrlen); + + +/** + * We have updated performance statistics for a given address. Note + * that this function can be called for addresses that are currently + * in use as well as addresses that are valid but not actively in use. + * Furthermore, the peer may not even be connected to us right now (in + * which case the call may be ignored or the information may be stored + * for later use). Update bandwidth assignments. + * + * @param sh handle + * @param address updated address + * @param session session handle (if available) + * @param ats performance data for the address + * @param ats_count number of performance records in 'ats' + */ +void +GNUNET_ATS_address_update (struct GNUNET_ATS_SchedulingHandle *sh, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count); + + +/** + * An address is now in use or not used any more. + * + * @param sh handle + * @param address the address + * @param session session handle + * @param in_use GNUNET_YES if this address is now used, GNUNET_NO + * if address is not used any more + */ +void +GNUNET_ATS_address_in_use (struct GNUNET_ATS_SchedulingHandle *sh, + const struct GNUNET_HELLO_Address *address, + struct Session *session, int in_use); + +/** + * A session got destroyed, stop including it as a valid address. + * + * @param sh handle + * @param address the address + * @param session session handle that is no longer valid (if available) + */ +void +GNUNET_ATS_address_destroyed (struct GNUNET_ATS_SchedulingHandle *sh, + const struct GNUNET_HELLO_Address *address, + struct Session *session); + + +/* ******************************** Performance API ***************************** */ + +/** + * ATS Handle to obtain and/or modify performance information. + */ +struct GNUNET_ATS_PerformanceHandle; + + +/** + * Signature of a function that is called with QoS information about a peer. + * + * @param cls closure + * @param address the address + * @param bandwidth_out assigned outbound bandwidth for the connection + * @param bandwidth_in assigned inbound bandwidth for the connection + * @param ats performance data for the address (as far as known) + * @param ats_count number of performance records in 'ats' + */ +typedef void (*GNUNET_ATS_PeerInformationCallback) (void *cls, + const struct + GNUNET_HELLO_Address * + address, + struct + GNUNET_BANDWIDTH_Value32NBO + bandwidth_out, + struct + GNUNET_BANDWIDTH_Value32NBO + bandwidth_in, + const struct + GNUNET_ATS_Information * + ats, uint32_t ats_count); + + +/** + * Get handle to access performance API of the ATS subsystem. + * + * @param cfg configuration to use + * @param infocb function to call on performance changes, can be NULL + * @param infocb_cls closure for infocb + * @return ats performance context + */ +struct GNUNET_ATS_PerformanceHandle * +GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_ATS_PeerInformationCallback infocb, + void *infocb_cls); + + +/** + * Client is done using the ATS performance subsystem, release resources. + * + * @param ph handle + */ +void +GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph); + + +/** + * Function called with reservation result. + * + * @param cls closure + * @param peer identifies the peer + * @param amount set to the amount that was actually reserved or unreserved; + * either the full requested amount or zero (no partial reservations) + * @param res_delay if the reservation could not be satisfied (amount was 0), how + * long should the client wait until re-trying? + */ +typedef void (*GNUNET_ATS_ReservationCallback) (void *cls, + const struct GNUNET_PeerIdentity + * peer, int32_t amount, + struct GNUNET_TIME_Relative + res_delay); + + + +/** + * Context that can be used to cancel a peer information request. + */ +struct GNUNET_ATS_ReservationContext; + + +/** + * Reserve inbound bandwidth from the given peer. ATS will look at + * the current amount of traffic we receive from the peer and ensure + * that the peer could add 'amount' of data to its stream. + * + * @param ph performance handle + * @param peer identifies the peer + * @param amount reserve N bytes for receiving, negative + * amounts can be used to undo a (recent) reservation; + * @param rcb function to call with the resulting reservation information + * @param rcb_cls closure for info + * @return NULL on error + * @deprecated will be replaced soon + */ +struct GNUNET_ATS_ReservationContext * +GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph, + const struct GNUNET_PeerIdentity *peer, + int32_t amount, + GNUNET_ATS_ReservationCallback rcb, + void *rcb_cls); + + +/** + * Cancel request for reserving bandwidth. + * + * @param rc context returned by the original GNUNET_ATS_reserve_bandwidth call + */ +void +GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc); + + + +/** + * Enum defining all known preference categories. + */ +enum GNUNET_ATS_PreferenceKind +{ + + /** + * End of preference list. + */ + GNUNET_ATS_PREFERENCE_END = 0, + + /** + * Change the peer's bandwidth value (value per byte of bandwidth in + * the goal function) to the given amount. The argument is followed + * by a double value giving the desired value (can be negative). + * Preference changes are forgotten if peers disconnect. + */ + GNUNET_ATS_PREFERENCE_BANDWIDTH, + + /** + * Change the peer's latency value to the given amount. The + * argument is followed by a double value giving the desired value + * (can be negative). The absolute score in the goal function is + * the inverse of the latency in ms (minimum: 1 ms) multiplied by + * the latency preferences. + */ + GNUNET_ATS_PREFERENCE_LATENCY +}; + + +/** + * Change preferences for the given peer. Preference changes are forgotten if peers + * disconnect. + * + * @param ph performance handle + * @param peer identifies the peer + * @param ... 0-terminated specification of the desired changes + */ +void +GNUNET_ATS_change_preference (struct GNUNET_ATS_PerformanceHandle *ph, + const struct GNUNET_PeerIdentity *peer, ...); + + + +#endif +/* end of file gnunet-service-transport_ats.h */ diff --git a/src/include/gnunet_bandwidth_lib.h b/src/include/gnunet_bandwidth_lib.h new file mode 100644 index 0000000..fabe47b --- /dev/null +++ b/src/include/gnunet_bandwidth_lib.h @@ -0,0 +1,227 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_bandwidth_lib.h + * @brief functions related to bandwidth (unit) + * @author Christian Grothoff + */ + +#ifndef GNUNET_BANDWIDTH_LIB_H +#define GNUNET_BANDWIDTH_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_time_lib.h" + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * 32-bit bandwidth used for network exchange by GNUnet, in bytes per second. + */ +struct GNUNET_BANDWIDTH_Value32NBO +{ + /** + * The actual value (bytes per second). + */ + uint32_t value__ GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Struct to track available bandwidth. Combines a time stamp with a + * number of bytes transmitted, a quota and a maximum amount that + * carries over. Not opaque so that it can be inlined into data + * structures (reducing malloc-ing); however, values should not be + * accessed directly by clients (hence the '__'). + */ +struct GNUNET_BANDWIDTH_Tracker +{ + /** + * Number of bytes consumed since we last updated the tracker. + */ + int64_t consumption_since_last_update__; + + /** + * Time when we last updated the tracker. + */ + struct GNUNET_TIME_Absolute last_update__; + + /** + * Bandwidth limit to enforce in bytes per s. + */ + uint32_t available_bytes_per_s__; + + /** + * Maximum number of seconds over which bandwidth may "accumulate". + * Note that additionally, we also always allow at least + * GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. + */ + uint32_t max_carry_s__; +}; + + +/** + * Create a new bandwidth value. + * + * @param bytes_per_second value to create + * @return the new bandwidth value + */ +struct GNUNET_BANDWIDTH_Value32NBO +GNUNET_BANDWIDTH_value_init (uint32_t bytes_per_second); + + +/** + * Maximum possible bandwidth value. + */ +#define GNUNET_BANDWIDTH_VALUE_MAX GNUNET_BANDWIDTH_value_init(UINT32_MAX) + + +/** + * At the given bandwidth, calculate how much traffic will be + * available until the given deadline. + * + * @param bps bandwidth + * @param deadline when is the deadline + * @return number of bytes available at bps until deadline + */ +uint64_t +GNUNET_BANDWIDTH_value_get_available_until (struct GNUNET_BANDWIDTH_Value32NBO + bps, + struct GNUNET_TIME_Relative + deadline); + + +/** + * At the given bandwidth, calculate how long it would take for + * 'size' bytes to be transmitted. + * + * @param bps bandwidth + * @param size number of bytes we want to have available + * @return how long it would take + */ +struct GNUNET_TIME_Relative +GNUNET_BANDWIDTH_value_get_delay_for (struct GNUNET_BANDWIDTH_Value32NBO bps, + uint64_t size); + + + +/** + * Compute the MIN of two bandwidth values. + * + * @param b1 first value + * @param b2 second value + * @return the min of b1 and b2 + */ +struct GNUNET_BANDWIDTH_Value32NBO +GNUNET_BANDWIDTH_value_min (struct GNUNET_BANDWIDTH_Value32NBO b1, + struct GNUNET_BANDWIDTH_Value32NBO b2); + + +/** + * Initialize bandwidth tracker. Note that in addition to the + * 'max_carry_s' limit, we also always allow at least + * GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the + * bytes-per-second limit is so small that within 'max_carry_s' not + * even GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is + * ignored and replaced by GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in + * bytes). + * + * @param av tracker to initialize + * @param bytes_per_second_limit initial limit to assume + * @param max_carry_s maximum number of seconds unused bandwidth + * may accumulate before it expires + */ +void +GNUNET_BANDWIDTH_tracker_init (struct GNUNET_BANDWIDTH_Tracker *av, + struct GNUNET_BANDWIDTH_Value32NBO + bytes_per_second_limit, uint32_t max_carry_s); + + +/** + * Notify the tracker that a certain number of bytes of bandwidth have + * been consumed. Note that it is legal to consume bytes even if not + * enough bandwidth is available (in that case, + * GNUNET_BANDWIDTH_tracker_get_delay may return non-zero delay values + * even for a size of zero for a while). + * + * @param av tracker to update + * @param size number of bytes consumed + * @return GNUNET_YES if this consumption is above the limit + */ +int +GNUNET_BANDWIDTH_tracker_consume (struct GNUNET_BANDWIDTH_Tracker *av, + ssize_t size); + + +/** + * Compute how long we should wait until consuming 'size' + * bytes of bandwidth in order to stay within the given + * quota. + * + * @param av tracker to query + * @param size number of bytes we would like to consume + * @return time to wait for consumption to be OK + */ +struct GNUNET_TIME_Relative +GNUNET_BANDWIDTH_tracker_get_delay (struct GNUNET_BANDWIDTH_Tracker *av, + size_t size); + + +/** + * Compute how many bytes are available for consumption right now. + * quota. + * + * @param av tracker to query + * @return number of bytes available for consumption right now + */ +int64_t +GNUNET_BANDWIDTH_tracker_get_available (struct GNUNET_BANDWIDTH_Tracker *av); + + +/** + * Update quota of bandwidth tracker. + * + * @param av tracker to initialize + * @param bytes_per_second_limit new limit to assume + */ +void +GNUNET_BANDWIDTH_tracker_update_quota (struct GNUNET_BANDWIDTH_Tracker *av, + struct GNUNET_BANDWIDTH_Value32NBO + bytes_per_second_limit); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_BANDWIDTH_LIB_H */ +#endif +/* end of gnunet_bandwidth_lib.h */ diff --git a/src/include/gnunet_bio_lib.h b/src/include/gnunet_bio_lib.h new file mode 100644 index 0000000..47d8d5e --- /dev/null +++ b/src/include/gnunet_bio_lib.h @@ -0,0 +1,303 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_bio_lib.h + * @brief buffered IO API + * @author Christian Grothoff + */ + +#ifndef GNUNET_BIO_LIB_H +#define GNUNET_BIO_LIB_H + +#include "gnunet_container_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * Handle for buffered reading. + */ +struct GNUNET_BIO_ReadHandle; + + +/** + * Open a file for reading. + * + * @param fn file name to be opened + * @return IO handle on success, NULL on error + */ +struct GNUNET_BIO_ReadHandle * +GNUNET_BIO_read_open (const char *fn); + + +/** + * Close an open file. Reports if any errors reading + * from the file were encountered. + * + * @param h file handle + * @param emsg set to the error message + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h, char **emsg); + + +/** + * Read the contents of a binary file into a buffer. + * + * @param h handle to an open file + * @param what describes what is being read (for error message creation) + * @param result the buffer to write the result to + * @param len the number of bytes to read + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h, const char *what, + void *result, size_t len); + + +/** + * Read the contents of a binary file into a buffer. + * + * @param h handle to an open file + * @param file name of the source file + * @param line line number in the source file + * @param result the buffer to write the result to + * @param len the number of bytes to read + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_BIO_read_fn (struct GNUNET_BIO_ReadHandle *h, const char *file, int line, + void *result, size_t len); + +/** + * Read 0-terminated string from a file. + * + * @param h handle to an open file + * @param what describes what is being read (for error message creation) + * @param result the buffer to store a pointer to the (allocated) string to + * (note that *result could be set to NULL as well) + * @param maxLen maximum allowed length for the string + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h, const char *what, + char **result, size_t maxLen); + + +/** + * Read metadata container from a file. + * + * @param h handle to an open file + * @param what describes what is being read (for error message creation) + * @param result the buffer to store a pointer to the (allocated) metadata + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h, const char *what, + struct GNUNET_CONTAINER_MetaData **result); + + +/** + * Read a float. + * + * @param h hande to open file + * @param f address of float to read + */ +#define GNUNET_BIO_read_float(h, f) (GNUNET_BIO_read_fn (h, __FILE__, __LINE__, f, sizeof(float))) + + + +/** + * Read a double. + * + * @param h hande to open file + * @param f address of double to read + */ +#define GNUNET_BIO_read_double(h, f) (GNUNET_BIO_read_fn (h, __FILE__, __LINE__, f, sizeof(double))) + + +/** + * Read an (u)int32_t. + * + * @param h hande to open file + * @param file name of the source file + * @param line line number in the code + * @param i address of 32-bit integer to read + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h, const char *file, + int line, int32_t * i); + + +/** + * Read an (u)int32_t. + * + * @param h hande to open file + * @param i address of 32-bit integer to read + */ +#define GNUNET_BIO_read_int32(h, i) GNUNET_BIO_read_int32__ (h, __FILE__, __LINE__, (int32_t*) i) + + +/** + * Read an (u)int64_t. + * + * @param h hande to open file + * @param file name of the source file + * @param line line number in the code + * @param i address of 64-bit integer to read + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h, const char *file, + int line, int64_t * i); + + +/** + * Read an (u)int64_t. + * + * @param h hande to open file + * @param i address of 64-bit integer to read + */ +#define GNUNET_BIO_read_int64(h, i) GNUNET_BIO_read_int64__ (h, __FILE__, __LINE__, (int64_t*) i) + + +/** + * Handle for buffered writing. + */ +struct GNUNET_BIO_WriteHandle; + +/** + * Open a file for writing. + * + * @param fn file name to be opened + * @return IO handle on success, NULL on error + */ +struct GNUNET_BIO_WriteHandle * +GNUNET_BIO_write_open (const char *fn); + + +/** + * Close an open file for writing. + * + * @param h file handle + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h); + + +/** + * Write a buffer to a file. + * + * @param h handle to open file + * @param buffer the data to write + * @param n number of bytes to write + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h, const void *buffer, + size_t n); + + +/** + * Write a string to a file. + * + * @param h handle to open file + * @param s string to write (can be NULL) + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, const char *s); + + + + +/** + * Write metadata container to a file. + * + * @param h handle to open file + * @param m metadata to write + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h, + const struct GNUNET_CONTAINER_MetaData *m); + + + +/** + * Write a float. + * + * @param h hande to open file + * @param f float to write (must be a variable) + */ +#define GNUNET_BIO_write_float(h, f) GNUNET_BIO_write (h, &f, sizeof(float)) + + + +/** + * Write a double. + * + * @param h hande to open file + * @param f double to write (must be a variable) + */ +#define GNUNET_BIO_write_double(h, f) GNUNET_BIO_write (h, &f, sizeof(double)) + + +/** + * Write an (u)int32_t. + * + * @param h hande to open file + * @param i 32-bit integer to write + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h, int32_t i); + + +/** + * Write an (u)int64_t. + * + * @param h hande to open file + * @param i 64-bit integer to write + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h, int64_t i); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_BIO_LIB_H */ +#endif +/* end of gnunet_bio_lib.h */ diff --git a/src/include/gnunet_block_lib.h b/src/include/gnunet_block_lib.h new file mode 100644 index 0000000..adc1775 --- /dev/null +++ b/src/include/gnunet_block_lib.h @@ -0,0 +1,260 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_block_lib.h + * @brief library for data block manipulation + * @author Christian Grothoff + */ +#ifndef GNUNET_BLOCK_LIB_H +#define GNUNET_BLOCK_LIB_H + +#include "gnunet_util_lib.h" +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Blocks in the datastore and the datacache must have a unique type. + */ +enum GNUNET_BLOCK_Type +{ + /** + * Any type of block, used as a wildcard when searching. Should + * never be attached to a specific block. + */ + GNUNET_BLOCK_TYPE_ANY = 0, + + /** + * Data block (leaf) in the CHK tree. + */ + GNUNET_BLOCK_TYPE_FS_DBLOCK = 1, + + /** + * Inner block in the CHK tree. + */ + GNUNET_BLOCK_TYPE_FS_IBLOCK = 2, + + /** + * Type of a block representing a keyword search result. Note that + * the values for KBLOCK, SBLOCK and NBLOCK must be consecutive. + */ + GNUNET_BLOCK_TYPE_FS_KBLOCK = 3, + + /** + * Type of a block that is used to advertise content in a namespace. + */ + GNUNET_BLOCK_TYPE_FS_SBLOCK = 4, + + /** + * Type of a block that is used to advertise a namespace. + */ + GNUNET_BLOCK_TYPE_FS_NBLOCK = 5, + + /** + * Type of a block representing a block to be encoded on demand from disk. + * Should never appear on the network directly. + */ + GNUNET_BLOCK_TYPE_FS_ONDEMAND = 6, + + /** + * Type of a block that contains a HELLO for a peer (for + * DHT find-peer operations). + */ + GNUNET_BLOCK_TYPE_DHT_HELLO = 7, + + /** + * Block for testing. + */ + GNUNET_BLOCK_TYPE_TEST = 8, + + /** + * Block for storing .gnunet-domains + */ + GNUNET_BLOCK_TYPE_DNS = 10, + + /** + * Block for storing record data + */ + GNUNET_BLOCK_TYPE_GNS_NAMERECORD = 11 +}; + + +/** + * Possible ways for how a block may relate to a query. + */ +enum GNUNET_BLOCK_EvaluationResult +{ + /** + * Valid result, and there may be more. + */ + GNUNET_BLOCK_EVALUATION_OK_MORE = 0, + + /** + * Last possible valid result. + */ + GNUNET_BLOCK_EVALUATION_OK_LAST = 1, + + /** + * Valid result, but suppressed because it is a duplicate. + */ + GNUNET_BLOCK_EVALUATION_OK_DUPLICATE = 2, + + /** + * Block does not match query (invalid result) + */ + GNUNET_BLOCK_EVALUATION_RESULT_INVALID = 3, + + /** + * Query is valid, no reply given. + */ + GNUNET_BLOCK_EVALUATION_REQUEST_VALID = 4, + + /** + * Query format does not match block type (invalid query). For + * example, xquery not given or xquery_size not appropriate for + * type. + */ + GNUNET_BLOCK_EVALUATION_REQUEST_INVALID = 5, + + /** + * Specified block type not supported by this plugin. + */ + GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED = 6 +}; + + +/** + * Handle to an initialized block library. + */ +struct GNUNET_BLOCK_Context; + + +/** + * Mingle hash with the mingle_number to produce different bits. + * + * @param in original hash code + * @param mingle_number number for hash permutation + * @param hc where to store the result. + */ +void +GNUNET_BLOCK_mingle_hash (const GNUNET_HashCode * in, uint32_t mingle_number, + GNUNET_HashCode * hc); + + +/** + * Create a block context. Loads the block plugins. + * + * @param cfg configuration to use + * @return NULL on error + */ +struct GNUNET_BLOCK_Context * +GNUNET_BLOCK_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Destroy the block context. + * + * @param ctx context to destroy + */ +void +GNUNET_BLOCK_context_destroy (struct GNUNET_BLOCK_Context *ctx); + + +/** + * Function called to validate a reply or a request. For + * request evaluation, simply pass "NULL" for the reply_block. + * Note that it is assumed that the reply has already been + * matched to the key (and signatures checked) as it would + * be done with the "get_key" function. + * + * @param ctx block contxt + * @param type block type + * @param query original query (hash) + * @param bf pointer to bloom filter associated with query; possibly updated (!) + * @param bf_mutator mutation value for bf + * @param xquery extrended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in reply block + * @return characterization of result + */ +enum GNUNET_BLOCK_EvaluationResult +GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx, + enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode * query, + struct GNUNET_CONTAINER_BloomFilter **bf, + int32_t bf_mutator, const void *xquery, + size_t xquery_size, const void *reply_block, + size_t reply_block_size); + + +/** + * Function called to obtain the key for a block. + * + * @param ctx block context + * @param type block type + * @param block block to get the key for + * @param block_size number of bytes in block + * @param key set to the key (query) for the given block + * @return GNUNET_YES on success, + * GNUNET_NO if the block is malformed + * GNUNET_SYSERR if type not supported + * (or if extracting a key from a block of this type does not work) + */ +int +GNUNET_BLOCK_get_key (struct GNUNET_BLOCK_Context *ctx, + enum GNUNET_BLOCK_Type type, const void *block, + size_t block_size, GNUNET_HashCode * key); + + + +/** + * Construct a bloom filter that would filter out the given + * results. + * + * @param bf_mutator mutation value to use + * @param seen_results results already seen + * @param seen_results_count number of entries in 'seen_results' + * @return NULL if seen_results_count is 0, otherwise a BF + * that would match the given results. + */ +struct GNUNET_CONTAINER_BloomFilter * +GNUNET_BLOCK_construct_bloomfilter (int32_t bf_mutator, + const GNUNET_HashCode * seen_results, + unsigned int seen_results_count); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_BLOCK_LIB_H */ +#endif +/* end of gnunet_block_lib.h */ diff --git a/src/include/gnunet_block_plugin.h b/src/include/gnunet_block_plugin.h new file mode 100644 index 0000000..0ead4af --- /dev/null +++ b/src/include/gnunet_block_plugin.h @@ -0,0 +1,128 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_block_plugin.h + * @brief API for block plugins. Each block plugin must conform to + * the API specified by this header. + * @author Christian Grothoff + */ +#ifndef PLUGIN_BLOCK_H +#define PLUGIN_BLOCK_H + +#include "gnunet_util_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_block_lib.h" + + +/** + * Function called to validate a reply or a request. For + * request evaluation, simply pass "NULL" for the reply_block. + * Note that it is assumed that the reply has already been + * matched to the key (and signatures checked) as it would + * be done with the "get_key" function. + * + * @param cls closure + * @param type block type + * @param query original query (hash) + * @param bf pointer to bloom filter associated with query; possibly updated (!) + * @param bf_mutator mutation value for bf + * @param xquery extrended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param reply_block response to validate + * @param reply_block_size number of bytes in reply block + * @return characterization of result + */ +typedef enum + GNUNET_BLOCK_EvaluationResult (*GNUNET_BLOCK_EvaluationFunction) (void *cls, + enum + GNUNET_BLOCK_Type + type, + const + GNUNET_HashCode + * query, + struct + GNUNET_CONTAINER_BloomFilter + ** bf, + int32_t + bf_mutator, + const void + *xquery, + size_t + xquery_size, + const void + *reply_block, + size_t + reply_block_size); + + +/** + * Function called to obtain the key for a block. + * + * @param cls closure + * @param type block type + * @param block block to get the key for + * @param block_size number of bytes in block + * @param key set to the key (query) for the given block + * @return GNUNET_YES on success, + * GNUNET_NO if the block is malformed + * GNUNET_SYSERR if type not supported + * (or if extracting a key from a block of this type does not work) + */ +typedef int (*GNUNET_BLOCK_GetKeyFunction) (void *cls, + enum GNUNET_BLOCK_Type type, + const void *block, + size_t block_size, + GNUNET_HashCode * key); + + + +/** + * Each plugin is required to return a pointer to a struct of this + * type as the return value from its entry point. + */ +struct GNUNET_BLOCK_PluginFunctions +{ + + /** + * Closure for all of the callbacks. + */ + void *cls; + + /** + * 0-terminated array of block types supported by this plugin. + */ + const enum GNUNET_BLOCK_Type *types; + + /** + * Main function of a block plugin. Allows us to check if a + * block matches a query. + */ + GNUNET_BLOCK_EvaluationFunction evaluate; + + /** + * Obtain the key for a given block (if possible). + */ + GNUNET_BLOCK_GetKeyFunction get_key; + +}; + + +#endif diff --git a/src/include/gnunet_chat_service.h b/src/include/gnunet_chat_service.h new file mode 100644 index 0000000..938b434 --- /dev/null +++ b/src/include/gnunet_chat_service.h @@ -0,0 +1,253 @@ +/* + This file is part of GNUnet. + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_chat_service.h + * @brief API for chatting via GNUnet + * @author Christian Grothoff + * @author Nathan Evans + * @author Vitaly Minko + */ + +#ifndef GNUNET_CHAT_SERVICE_H +#define GNUNET_CHAT_SERVICE_H + +#include "gnunet_util_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +#define GNUNET_CHAT_VERSION 0x00000003 +#define MAX_MESSAGE_LENGTH (32 * 1024) + +/** + * Options for messaging. Compatible options can be OR'ed together. + */ +enum GNUNET_CHAT_MsgOptions +{ + /** + * No special options. + */ + GNUNET_CHAT_MSG_OPTION_NONE = 0, + + /** + * Encrypt the message so that only the receiver can decrypt it. + */ + GNUNET_CHAT_MSG_PRIVATE = 1, + + /** + * Hide the identity of the sender. + */ + GNUNET_CHAT_MSG_ANONYMOUS = 2, + + /** + * Sign the content, authenticating the sender (using the provided private + * key, which may represent a pseudonym). + */ + GNUNET_CHAT_MSG_AUTHENTICATED = 4, + + /** + * Require signed acknowledgment before completing delivery (and of course, + * only acknowledge if delivery is guaranteed). + */ + GNUNET_CHAT_MSG_ACKNOWLEDGED = 8, + + /** + * Authenticate for the receiver, but ensure that receiver cannot prove + * authenticity to third parties later. (not yet implemented) + */ + GNUNET_CHAT_MSG_OFF_THE_RECORD = 16, + +}; + +/** + * Handle for a (joined) chat room. + */ +struct GNUNET_CHAT_Room; + +/** + * Callback used for notification that we have joined the room. + * + * @param cls closure + * @return GNUNET_OK + */ +typedef int (*GNUNET_CHAT_JoinCallback) (void *cls); + +/** + * Callback used for notification about incoming messages. + * + * @param cls closure + * @param room in which room was the message received? + * @param sender what is the ID of the sender? (maybe NULL) + * @param member_info information about the joining member + * @param message the message text + * @param timestamp when was the message sent? + * @param options options for the message + * @return GNUNET_OK to accept the message now, GNUNET_NO to + * accept (but user is away), GNUNET_SYSERR to signal denied delivery + */ +typedef int (*GNUNET_CHAT_MessageCallback) (void *cls, + struct GNUNET_CHAT_Room * room, + const GNUNET_HashCode * sender, + const struct + GNUNET_CONTAINER_MetaData * + member_info, const char *message, + struct GNUNET_TIME_Absolute + timestamp, + enum GNUNET_CHAT_MsgOptions + options); + +/** + * Callback used for notification that another room member has joined or left. + * + * @param cls closure + * @param member_info will be non-null if the member is joining, NULL if he is + * leaving + * @param member_id hash of public key of the user (for unique identification) + * @param options what types of messages is this member willing to receive? + * @return GNUNET_OK + */ +typedef int (*GNUNET_CHAT_MemberListCallback) (void *cls, + const struct + GNUNET_CONTAINER_MetaData * + member_info, + const struct + GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + * member_id, + enum GNUNET_CHAT_MsgOptions + options); + +/** + * Callback used for message delivery confirmations. + * + * @param cls closure + * @param room in which room was the message received? + * @param orig_seq_number sequence number of the original message + * @param timestamp when was the message received? + * @param receiver who is confirming the receipt? + * @return GNUNET_OK to continue, GNUNET_SYSERR to refuse processing further + * confirmations from anyone for this message + */ +typedef int (*GNUNET_CHAT_MessageConfirmation) (void *cls, + struct GNUNET_CHAT_Room * room, + uint32_t orig_seq_number, + struct GNUNET_TIME_Absolute + timestamp, + const GNUNET_HashCode * + receiver); + +/** + * Join a chat room. + * + * @param cfg configuration + * @param nick_name nickname of the user joining (used to + * determine which public key to use); + * the nickname should probably also + * be used in the member_info (as "EXTRACTOR_TITLE") + * @param member_info information about the joining member + * @param room_name name of the room + * @param msg_options message options of the joining user + * @param joinCallback which function to call when we've joined the room + * @param join_cls argument to callback + * @param messageCallback which function to call if a message has + * been received? + * @param message_cls argument to callback + * @param memberCallback which function to call for join/leave notifications + * @param member_cls argument to callback + * @param confirmationCallback which function to call for confirmations + * (maybe NULL) + * @param confirmation_cls argument to callback + * @param me member ID (pseudonym) + * @return NULL on error + */ +struct GNUNET_CHAT_Room * +GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *nick_name, + struct GNUNET_CONTAINER_MetaData *member_info, + const char *room_name, + enum GNUNET_CHAT_MsgOptions msg_options, + GNUNET_CHAT_JoinCallback joinCallback, void *join_cls, + GNUNET_CHAT_MessageCallback messageCallback, + void *message_cls, + GNUNET_CHAT_MemberListCallback memberCallback, + void *member_cls, + GNUNET_CHAT_MessageConfirmation confirmationCallback, + void *confirmation_cls, GNUNET_HashCode * me); + +/** + * Send a message. + * + * @param room handle for the chat room + * @param message message to be sent + * @param options options for the message + * @param receiver use NULL to send to everyone in the room + * @param sequence_number where to write the sequence id of the message + */ +void +GNUNET_CHAT_send_message (struct GNUNET_CHAT_Room *room, const char *message, + enum GNUNET_CHAT_MsgOptions options, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *receiver, uint32_t * sequence_number); + + +/** + * Leave a chat room. + */ +void +GNUNET_CHAT_leave_room (struct GNUNET_CHAT_Room *chat_room); + + +#if 0 +/* these are not yet implemented / supported */ +/** + * Callback function to iterate over rooms. + * + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +typedef int (*GNUNET_CHAT_RoomIterator) (const char *room, const char *topic, + void *cls); + +/** + * List all of the (publically visible) chat rooms. + * @return number of rooms on success, GNUNET_SYSERR if iterator aborted + */ +int +GNUNET_CHAT_list_rooms (struct GNUNET_GE_Context *ectx, + struct GNUNET_GC_Configuration *cfg, + GNUNET_CHAT_RoomIterator it, void *cls); +#endif + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif + +/* end of gnunet_chat_service.h */ diff --git a/src/include/gnunet_client_lib.h b/src/include/gnunet_client_lib.h new file mode 100644 index 0000000..60fa938 --- /dev/null +++ b/src/include/gnunet_client_lib.h @@ -0,0 +1,222 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_client_lib.h + * @brief functions related to accessing services + * @author Christian Grothoff + */ + +#ifndef GNUNET_CLIENT_LIB_H +#define GNUNET_CLIENT_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +/** + * Opaque handle for a connection to a service. + */ +struct GNUNET_CLIENT_Connection; + +/** + * Get a connection with a service. + * + * @param service_name name of the service + * @param cfg configuration to use + * @return NULL on error (service unknown to configuration) + */ +struct GNUNET_CLIENT_Connection * +GNUNET_CLIENT_connect (const char *service_name, + const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Destroy connection with the service. This will automatically + * cancel any pending "receive" request (however, the handler will + * *NOT* be called, not even with a NULL message). Any pending + * transmission request will also be cancelled UNLESS the callback for + * the transmission request has already been called, in which case the + * transmission 'finish_pending_write' argument determines whether or + * not the write is guaranteed to complete before the socket is fully + * destroyed (unless, of course, there is an error with the server in + * which case the message may still be lost). + * + * @param sock handle to the service connection + * @param finish_pending_write should a transmission already passed to the + * handle be completed? + */ +void +GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *sock, + int finish_pending_write); + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +typedef void (*GNUNET_CLIENT_MessageHandler) (void *cls, + const struct GNUNET_MessageHeader + * msg); + + +/** + * Type of a function to call when we have finished shutting + * down a service, or failed. + * + * @param cls closure + * @param reason what is the result of the shutdown + * GNUNET_NO on shutdown (not running) + * GNUNET_YES on running + * GNUNET_SYSERR on failure to transmit message + */ +typedef void (*GNUNET_CLIENT_ShutdownTask) (void *cls, int reason); + + +/** + * Read from the service. + * + * @param sock the service + * @param handler function to call with the message + * @param handler_cls closure for handler + * @param timeout how long to wait until timing out + */ +void +GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *sock, + GNUNET_CLIENT_MessageHandler handler, void *handler_cls, + struct GNUNET_TIME_Relative timeout); + + +/** + * Transmit handle for client connections. + */ +struct GNUNET_CLIENT_TransmitHandle; + + +/** + * Ask the client to call us once the specified number of bytes + * are free in the transmission buffer. May call the notify + * method immediately if enough space is available. + * + * @param sock connection to the service + * @param size number of bytes to send + * @param timeout after how long should we give up (and call + * notify with buf NULL and size 0)? + * @param auto_retry if the connection to the service dies, should we + * automatically re-connect and retry (within the timeout period) + * or should we immediately fail in this case? Pass GNUNET_YES + * if the caller does not care about temporary connection errors, + * for example because the protocol is stateless + * @param notify function to call + * @param notify_cls closure for notify + * @return NULL if someone else is already waiting to be notified + * non-NULL if the notify callback was queued (can be used to cancel + * using GNUNET_CONNECTION_notify_transmit_ready_cancel) + */ +struct GNUNET_CLIENT_TransmitHandle * +GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *sock, + size_t size, + struct GNUNET_TIME_Relative timeout, + int auto_retry, + GNUNET_CONNECTION_TransmitReadyNotify + notify, void *notify_cls); + + +/** + * Cancel a request for notification. + * + * @param th handle from the original request. + */ +void +GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle + *th); + + +/** + * Convenience API that combines sending a request + * to the service and waiting for a response. + * If either operation times out, the callback + * will be called with a "NULL" response (in which + * case the connection should probably be destroyed). + * + * @param sock connection to use + * @param hdr message to transmit + * @param timeout when to give up (for both transmission + * and for waiting for a response) + * @param auto_retry if the connection to the service dies, should we + * automatically re-connect and retry (within the timeout period) + * or should we immediately fail in this case? Pass GNUNET_YES + * if the caller does not care about temporary connection errors, + * for example because the protocol is stateless + * @param rn function to call with the response + * @param rn_cls closure for rn + * @return GNUNET_OK on success, GNUNET_SYSERR if a request + * is already pending + */ +int +GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *sock, + const struct GNUNET_MessageHeader *hdr, + struct GNUNET_TIME_Relative timeout, + int auto_retry, + GNUNET_CLIENT_MessageHandler rn, + void *rn_cls); + + +/** + * Wait until the service is running. + * + * @param service name of the service to wait for + * @param cfg configuration to use + * @param timeout how long to wait at most in ms + * @param task task to run if service is running + * (reason will be "PREREQ_DONE" (service running) + * or "TIMEOUT" (service not known to be running)) + * @param task_cls closure for task + */ +void +GNUNET_CLIENT_service_test (const char *service, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TIME_Relative timeout, + GNUNET_SCHEDULER_Task task, void *task_cls); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_CLIENT_LIB_H */ +#endif +/* end of gnunet_client_lib.h */ diff --git a/src/include/gnunet_common.h b/src/include/gnunet_common.h new file mode 100644 index 0000000..a1ef4ee --- /dev/null +++ b/src/include/gnunet_common.h @@ -0,0 +1,840 @@ +/* + This file is part of GNUnet. + (C) 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_common.h + * @brief commonly used definitions; globals in this file + * are exempt from the rule that the module name ("common") + * must be part of the symbol name. + * + * @author Christian Grothoff + * @author Nils Durner + */ +#ifndef GNUNET_COMMON_H +#define GNUNET_COMMON_H + +#if HAVE_SYS_SOCKET_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#ifdef MINGW +#include "winproc.h" +#endif +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_STDARG_H +#include +#endif + +/** + * Version of the API (for entire gnunetutil.so library). + */ +#define GNUNET_UTIL_VERSION 0x00090200 + +/** + * Named constants for return values. The following + * invariants hold: "GNUNET_NO == 0" (to allow "if (GNUNET_NO)") + * "GNUNET_OK != GNUNET_SYSERR", "GNUNET_OK != GNUNET_NO", "GNUNET_NO != GNUNET_SYSERR" + * and finally "GNUNET_YES != GNUNET_NO". + */ +#define GNUNET_OK 1 +#define GNUNET_SYSERR -1 +#define GNUNET_YES 1 +#define GNUNET_NO 0 + +#define GNUNET_MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#define GNUNET_MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/* some systems use one underscore only, and mingw uses no underscore... */ +#ifndef __BYTE_ORDER +#ifdef _BYTE_ORDER +#define __BYTE_ORDER _BYTE_ORDER +#else +#ifdef BYTE_ORDER +#define __BYTE_ORDER BYTE_ORDER +#endif +#endif +#endif +#ifndef __BIG_ENDIAN +#ifdef _BIG_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +#else +#ifdef BIG_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#endif +#endif +#endif +#ifndef __LITTLE_ENDIAN +#ifdef _LITTLE_ENDIAN +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#else +#ifdef LITTLE_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#endif +#endif +#endif + +/** + * Endian operations + */ + +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define GNUNET_htobe16(x) __bswap_16 (x) +# define GNUNET_htole16(x) (x) +# define GNUNET_be16toh(x) __bswap_16 (x) +# define GNUNET_le16toh(x) (x) + +# define GNUNET_htobe32(x) __bswap_32 (x) +# define GNUNET_htole32(x) (x) +# define GNUNET_be32toh(x) __bswap_32 (x) +# define GNUNET_le32toh(x) (x) + +# define GNUNET_htobe64(x) __bswap_64 (x) +# define GNUNET_htole64(x) (x) +# define GNUNET_be64toh(x) __bswap_64 (x) +# define GNUNET_le64toh(x) (x) +#endif +# if __BYTE_ORDER == __BIG_ENDIAN +# define GNUNET_htobe16(x) (x) +# define GNUNET_htole16(x) __bswap_16 (x) +# define GNUNET_be16toh(x) (x) +# define GNUNET_le16toh(x) __bswap_16 (x) + +# define GNUNET_htobe32(x) (x) +# define GNUNET_htole32(x) __bswap_32 (x) +# define GNUNET_be32toh(x) (x) +# define GNUNET_le32toh(x) __bswap_32 (x) + +# define GNUNET_htobe64(x) (x) +# define GNUNET_htole64(x) __bswap_64 (x) +# define GNUNET_be64toh(x) (x) +# define GNUNET_le64toh(x) __bswap_64 (x) +#endif + + + + +/** + * gcc-ism to get packed structs. + */ +#define GNUNET_PACKED __attribute__((packed)) + +/** + * gcc-ism to document unused arguments + */ +#define GNUNET_UNUSED __attribute__((unused)) + +/** + * gcc-ism to document functions that don't return + */ +#define GNUNET_NORETURN __attribute__((noreturn)) + +#if __GNUC__ > 3 +/** + * gcc 4.x-ism to pack structures even on W32 (to be used before structs) + */ +#define GNUNET_NETWORK_STRUCT_BEGIN \ + _Pragma("pack(push)") \ + _Pragma("pack(1)") + +/** + * gcc 4.x-ism to pack structures even on W32 (to be used after structs) + */ +#define GNUNET_NETWORK_STRUCT_END _Pragma("pack(pop)") +#else +#ifdef MINGW +#error gcc 4.x or higher required on W32 systems +#endif +/** + * Good luck, GNUNET_PACKED should suffice, but this won't work on W32 + */ +#define GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Good luck, GNUNET_PACKED should suffice, but this won't work on W32 + */ +#define GNUNET_NETWORK_STRUCT_END +#endif + +/* ************************ super-general types *********************** */ + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Header for all communications. + */ +struct GNUNET_MessageHeader +{ + + /** + * The length of the struct (in bytes, including the length field itself), + * in big-endian format. + */ + uint16_t size GNUNET_PACKED; + + /** + * The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format. + */ + uint16_t type GNUNET_PACKED; + +}; +GNUNET_NETWORK_STRUCT_END + +/** + * @brief 512-bit hashcode + */ +typedef struct +{ + uint32_t bits[512 / 8 / sizeof (uint32_t)]; /* = 16 */ +} +GNUNET_HashCode; + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * The identity of the host (basically the SHA-512 hashcode of + * it's public key). + */ +struct GNUNET_PeerIdentity +{ + GNUNET_HashCode hashPubKey GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Function called with a filename. + * + * @param cls closure + * @param filename complete filename (absolute path) + * @return GNUNET_OK to continue to iterate, + * GNUNET_SYSERR to abort iteration with error! + */ +typedef int (*GNUNET_FileNameCallback) (void *cls, const char *filename); + + +/* ****************************** logging ***************************** */ + +/** + * Types of errors. + */ +enum GNUNET_ErrorType +{ + GNUNET_ERROR_TYPE_UNSPECIFIED = -1, + GNUNET_ERROR_TYPE_NONE = 0, + GNUNET_ERROR_TYPE_ERROR = 1, + GNUNET_ERROR_TYPE_WARNING = 2, + GNUNET_ERROR_TYPE_INFO = 4, + GNUNET_ERROR_TYPE_DEBUG = 8, + GNUNET_ERROR_TYPE_INVALID = 16, + GNUNET_ERROR_TYPE_BULK = 32 +}; + + +/** + * User-defined handler for log messages. + * + * @param cls closure + * @param kind severeity + * @param component what component is issuing the message? + * @param date when was the message logged? + * @param message what is the message + */ +typedef void (*GNUNET_Logger) (void *cls, enum GNUNET_ErrorType kind, + const char *component, const char *date, + const char *message); + + +/** + * Number of log calls to ignore. + */ +extern unsigned int skip_log; + +#if !defined(GNUNET_CULL_LOGGING) +int +GNUNET_get_log_call_status (int caller_level, const char *comp, + const char *file, const char *function, int line); +#endif +/** + * Main log function. + * + * @param kind how serious is the error? + * @param message what is the message (format string) + * @param ... arguments for format string + */ +void +GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...); + +/* from glib */ +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +#define _GNUNET_BOOLEAN_EXPR(expr) \ + __extension__ ({ \ + int _gnunet_boolean_var_; \ + if (expr) \ + _gnunet_boolean_var_ = 1; \ + else \ + _gnunet_boolean_var_ = 0; \ + _gnunet_boolean_var_; \ +}) +#define GN_LIKELY(expr) (__builtin_expect (_GNUNET_BOOLEAN_EXPR(expr), 1)) +#define GN_UNLIKELY(expr) (__builtin_expect (_GNUNET_BOOLEAN_EXPR(expr), 0)) +#else +#define GN_LIKELY(expr) (expr) +#define GN_UNLIKELY(expr) (expr) +#endif + +#if !defined(GNUNET_LOG_CALL_STATUS) +#define GNUNET_LOG_CALL_STATUS -1 +#endif + +/** + * Log function that specifies an alternative component. + * This function should be used by plugins. + * + * @param kind how serious is the error? + * @param comp component responsible for generating the message + * @param message what is the message (format string) + * @param ... arguments for format string + */ +void +GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind, const char *comp, + const char *message, ...); + +#if !defined(GNUNET_CULL_LOGGING) +#define GNUNET_log_from(kind,comp,...) do { int log_line = __LINE__;\ + static int log_call_enabled = GNUNET_LOG_CALL_STATUS;\ + if ((GNUNET_EXTRA_LOGGING > 0) || ((GNUNET_ERROR_TYPE_DEBUG & (kind)) == 0)) { \ + if (GN_UNLIKELY(log_call_enabled == -1))\ + log_call_enabled = GNUNET_get_log_call_status ((kind) & (~GNUNET_ERROR_TYPE_BULK), (comp), __FILE__, __FUNCTION__, log_line); \ + if (GN_UNLIKELY(skip_log > 0)) {skip_log--;}\ + else {\ + if (GN_UNLIKELY(log_call_enabled))\ + GNUNET_log_from_nocheck ((kind), comp, __VA_ARGS__); \ + }\ + }\ +} while (0) + +#define GNUNET_log(kind,...) do { int log_line = __LINE__;\ + static int log_call_enabled = GNUNET_LOG_CALL_STATUS;\ + if ((GNUNET_EXTRA_LOGGING > 0) || ((GNUNET_ERROR_TYPE_DEBUG & (kind)) == 0)) { \ + if (GN_UNLIKELY(log_call_enabled == -1))\ + log_call_enabled = GNUNET_get_log_call_status ((kind) & (~GNUNET_ERROR_TYPE_BULK), NULL, __FILE__, __FUNCTION__, log_line);\ + if (GN_UNLIKELY(skip_log > 0)) {skip_log--;}\ + else {\ + if (GN_UNLIKELY(log_call_enabled))\ + GNUNET_log_nocheck ((kind), __VA_ARGS__); \ + }\ + }\ +} while (0) +#else +#define GNUNET_log(...) +#define GNUNET_log_from(...) +#endif + + +/** + * Abort the process, generate a core dump if possible. + */ +void +GNUNET_abort (void) GNUNET_NORETURN; + +/** + * Ignore the next n calls to the log function. + * + * @param n number of log calls to ignore + * @param check_reset GNUNET_YES to assert that the log skip counter is currently zero + */ +void +GNUNET_log_skip (unsigned int n, int check_reset); + + +/** + * Setup logging. + * + * @param comp default component to use + * @param loglevel what types of messages should be logged + * @param logfile change logging to logfile (use NULL to keep stderr) + * @return GNUNET_OK on success, GNUNET_SYSERR if logfile could not be opened + */ +int +GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile); + + +/** + * Add a custom logger. + * + * @param logger log function + * @param logger_cls closure for logger + */ +void +GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls); + + +/** + * Remove a custom logger. + * + * @param logger log function + * @param logger_cls closure for logger + */ +void +GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls); + + +/** + * Convert a hash value to a string (for printing debug messages). + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param hc the hash code + * @return string + */ +const char * +GNUNET_h2s (const GNUNET_HashCode * hc); + + +/** + * Convert a hash value to a string (for printing debug messages). + * This prints all 104 characters of a hashcode! + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param hc the hash code + * @return string + */ +const char * +GNUNET_h2s_full (const GNUNET_HashCode * hc); + + +/** + * Convert a peer identity to a string (for printing debug messages). + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param pid the peer identity + * @return string form of the pid; will be overwritten by next + * call to GNUNET_i2s. + */ +const char * +GNUNET_i2s (const struct GNUNET_PeerIdentity *pid); + +/** + * Convert a peer identity to a string (for printing debug messages). + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param pid the peer identity + * @return string form of the pid; will be overwritten by next + * call to GNUNET_i2s. + */ +const char * +GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid); + +/** + * Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string + * (for printing debug messages). This is one of the very few calls + * in the entire API that is NOT reentrant! + * + * @param addr the address + * @param addrlen the length of the address + * @return nicely formatted string for the address + * will be overwritten by next call to GNUNET_a2s. + */ +const char * +GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen); + +/** + * Convert error type to string. + * + * @param kind type to convert + * @return string corresponding to the type + */ +const char * +GNUNET_error_type_to_string (enum GNUNET_ErrorType kind); + + +/** + * Use this for fatal errors that cannot be handled + */ +#define GNUNET_assert(cond) do { if (! (cond)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Assertion failed at %s:%d.\n"), __FILE__, __LINE__); GNUNET_abort(); } } while(0) + +/** + * Use this for fatal errors that cannot be handled + */ +#define GNUNET_assert_at(cond, f, l) do { if (! (cond)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Assertion failed at %s:%d.\n"), f, l); GNUNET_abort(); } } while(0) + +/** + * Use this for internal assertion violations that are + * not fatal (can be handled) but should not occur. + */ +#define GNUNET_break(cond) do { if (! (cond)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Assertion failed at %s:%d.\n"), __FILE__, __LINE__); } } while(0) + +/** + * Use this for assertion violations caused by other + * peers (i.e. protocol violations). We do not want to + * confuse end-users (say, some other peer runs an + * older, broken or incompatible GNUnet version), but + * we still want to see these problems during + * development and testing. "OP == other peer". + */ +#define GNUNET_break_op(cond) do { if (! (cond)) { GNUNET_log(GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, _("External protocol violation detected at %s:%d.\n"), __FILE__, __LINE__); } } while(0) + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' with the message given + * by strerror(errno). + */ +#define GNUNET_log_strerror(level, cmd) do { GNUNET_log(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, STRERROR(errno)); } while(0) + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' with the message given + * by strerror(errno). + */ +#define GNUNET_log_from_strerror(level, component, cmd) do { GNUNET_log_from (level, component, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, STRERROR(errno)); } while(0) + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' with the message given + * by strerror(errno). + */ +#define GNUNET_log_strerror_file(level, cmd, filename) do { GNUNET_log(level, _("`%s' failed on file `%s' at %s:%d with error: %s\n"), cmd, filename,__FILE__, __LINE__, STRERROR(errno)); } while(0) + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' with the message given + * by strerror(errno). + */ +#define GNUNET_log_from_strerror_file(level, component, cmd, filename) do { GNUNET_log_from (level, component, _("`%s' failed on file `%s' at %s:%d with error: %s\n"), cmd, filename,__FILE__, __LINE__, STRERROR(errno)); } while(0) + +/* ************************* endianess conversion ****************** */ + +/** + * Convert unsigned 64-bit integer to host-byte-order. + * @param n the value in network byte order + * @return the same value in host byte order + */ +uint64_t +GNUNET_ntohll (uint64_t n); + +/** + * Convert unsigned 64-bit integer to network-byte-order. + * @param n the value in host byte order + * @return the same value in network byte order + */ +uint64_t +GNUNET_htonll (uint64_t n); + +/** + * Convert double to network-byte-order. + * @param d the value in network byte order + * @return the same value in host byte order + */ +double +GNUNET_hton_double (double d); + +/** + * Convert double to host-byte-order + * @param d the value in network byte order + * @return the same value in host byte order + */ +double +GNUNET_ntoh_double (double d); + +/* ************************* allocation functions ****************** */ + +/** + * Maximum allocation with GNUNET_malloc macro. + */ +#define GNUNET_MAX_MALLOC_CHECKED (1024 * 1024 * 40) + +/** + * Wrapper around malloc. Allocates size bytes of memory. + * The memory will be zero'ed out. + * + * @param size the number of bytes to allocate, must be + * smaller than 40 MB. + * @return pointer to size bytes of memory, never NULL (!) + */ +#define GNUNET_malloc(size) GNUNET_xmalloc_(size, __FILE__, __LINE__) + +/** + * Allocate and initialize a block of memory. + * + * @param buf data to initalize the block with + * @param size the number of bytes in buf (and size of the allocation) + * @return pointer to size bytes of memory, never NULL (!) + */ +#define GNUNET_memdup(buf,size) GNUNET_xmemdup_(buf, size, __FILE__, __LINE__) + +/** + * Wrapper around malloc. Allocates size bytes of memory. + * The memory will be zero'ed out. + * + * @param size the number of bytes to allocate + * @return pointer to size bytes of memory, NULL if we do not have enough memory + */ +#define GNUNET_malloc_large(size) GNUNET_xmalloc_unchecked_(size, __FILE__, __LINE__) + +/** + * Wrapper around realloc. Rellocates size bytes of memory. + * + * @param ptr the pointer to reallocate + * @param size the number of bytes to reallocate + * @return pointer to size bytes of memory + */ +#define GNUNET_realloc(ptr, size) GNUNET_xrealloc_(ptr, size, __FILE__, __LINE__) + +/** + * Wrapper around free. Frees the memory referred to by ptr. + * Note that is is generally better to free memory that was + * allocated with GNUNET_array_grow using GNUNET_array_grow(mem, size, 0) instead of GNUNET_free. + * + * @param ptr location where to free the memory. ptr must have + * been returned by GNUNET_strdup, GNUNET_strndup, GNUNET_malloc or GNUNET_array_grow earlier. + */ +#define GNUNET_free(ptr) GNUNET_xfree_(ptr, __FILE__, __LINE__) + +/** + * Free the memory pointed to by ptr if ptr is not NULL. + * Equivalent to if (ptr!=null)GNUNET_free(ptr). + * + * @param ptr the location in memory to free + */ +#define GNUNET_free_non_null(ptr) do { void * __x__ = ptr; if (__x__ != NULL) { GNUNET_free(__x__); } } while(0) + +/** + * Wrapper around GNUNET_strdup. Makes a copy of the zero-terminated string + * pointed to by a. + * + * @param a pointer to a zero-terminated string + * @return a copy of the string including zero-termination + */ +#define GNUNET_strdup(a) GNUNET_xstrdup_(a,__FILE__,__LINE__) + +/** + * Wrapper around GNUNET_strndup. Makes a partial copy of the string + * pointed to by a. + * + * @param a pointer to a string + * @param length of the string to duplicate + * @return a partial copy of the string including zero-termination + */ +#define GNUNET_strndup(a,length) GNUNET_xstrndup_(a,length,__FILE__,__LINE__) + +/** + * Grow a well-typed (!) array. This is a convenience + * method to grow a vector arr of size size + * to the new (target) size tsize. + *

+ * + * Example (simple, well-typed stack): + * + *

+ * static struct foo * myVector = NULL;
+ * static int myVecLen = 0;
+ *
+ * static void push(struct foo * elem) {
+ *   GNUNET_array_grow(myVector, myVecLen, myVecLen+1);
+ *   memcpy(&myVector[myVecLen-1], elem, sizeof(struct foo));
+ * }
+ *
+ * static void pop(struct foo * elem) {
+ *   if (myVecLen == 0) die();
+ *   memcpy(elem, myVector[myVecLen-1], sizeof(struct foo));
+ *   GNUNET_array_grow(myVector, myVecLen, myVecLen-1);
+ * }
+ * 
+ * + * @param arr base-pointer of the vector, may be NULL if size is 0; + * will be updated to reflect the new address. The TYPE of + * arr is important since size is the number of elements and + * not the size in bytes + * @param size the number of elements in the existing vector (number + * of elements to copy over) + * @param tsize the target size for the resulting vector, use 0 to + * free the vector (then, arr will be NULL afterwards). + */ +#define GNUNET_array_grow(arr,size,tsize) GNUNET_xgrow_((void**)&arr, sizeof(arr[0]), &size, tsize, __FILE__, __LINE__) + +/** + * Append an element to a list (growing the + * list by one). + */ +#define GNUNET_array_append(arr,size,element) do { GNUNET_array_grow(arr,size,size+1); arr[size-1] = element; } while(0) + +/** + * Like snprintf, just aborts if the buffer is of insufficient size. + * + * @param buf pointer to buffer that is written to + * @param size number of bytes in buf + * @param format format strings + * @param ... data for format string + * @return number of bytes written to buf or negative value on error + */ +int +GNUNET_snprintf (char *buf, size_t size, const char *format, ...); + + +/** + * Like asprintf, just portable. + * + * @param buf set to a buffer of sufficient size (allocated, caller must free) + * @param format format string (see printf, fprintf, etc.) + * @param ... data for format string + * @return number of bytes in "*buf" excluding 0-termination + */ +int +GNUNET_asprintf (char **buf, const char *format, ...); + + +/* ************** internal implementations, use macros above! ************** */ + +/** + * Allocate memory. Checks the return value, aborts if no more + * memory is available. Don't use GNUNET_xmalloc_ directly. Use the + * GNUNET_malloc macro. + * The memory will be zero'ed out. + * + * @param size number of bytes to allocate + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + * @return allocated memory, never NULL + */ +void * +GNUNET_xmalloc_ (size_t size, const char *filename, int linenumber); + + +/** + * Allocate and initialize memory. Checks the return value, aborts if no more + * memory is available. Don't use GNUNET_xmemdup_ directly. Use the + * GNUNET_memdup macro. + * + * @param buf buffer to initialize from (must contain size bytes) + * @param size number of bytes to allocate + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + * @return allocated memory, never NULL + */ +void * +GNUNET_xmemdup_ (const void *buf, size_t size, const char *filename, + int linenumber); + + +/** + * Allocate memory. This function does not check if the allocation + * request is within reasonable bounds, allowing allocations larger + * than 40 MB. If you don't expect the possibility of very large + * allocations, use GNUNET_malloc instead. The memory will be zero'ed + * out. + * + * @param size number of bytes to allocate + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + * @return pointer to size bytes of memory, NULL if we do not have enough memory + */ +void * +GNUNET_xmalloc_unchecked_ (size_t size, const char *filename, int linenumber); + +/** + * Reallocate memory. Checks the return value, aborts if no more + * memory is available. + */ +void * +GNUNET_xrealloc_ (void *ptr, size_t n, const char *filename, int linenumber); + +/** + * Free memory. Merely a wrapper for the case that we + * want to keep track of allocations. Don't use GNUNET_xfree_ + * directly. Use the GNUNET_free macro. + * + * @param ptr pointer to memory to free + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + */ +void +GNUNET_xfree_ (void *ptr, const char *filename, int linenumber); + + +/** + * Dup a string. Don't call GNUNET_xstrdup_ directly. Use the GNUNET_strdup macro. + * @param str string to duplicate + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + * @return the duplicated string + */ +char * +GNUNET_xstrdup_ (const char *str, const char *filename, int linenumber); + +/** + * Dup partially a string. Don't call GNUNET_xstrndup_ directly. Use the GNUNET_strndup macro. + * + * @param str string to duplicate + * @param len length of the string to duplicate + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + * @return the duplicated string + */ +char * +GNUNET_xstrndup_ (const char *str, size_t len, const char *filename, + int linenumber); + +/** + * Grow an array, the new elements are zeroed out. + * Grows old by (*oldCount-newCount)*elementSize + * bytes and sets *oldCount to newCount. + * + * Don't call GNUNET_xgrow_ directly. Use the GNUNET_array_grow macro. + * + * @param old address of the pointer to the array + * *old may be NULL + * @param elementSize the size of the elements of the array + * @param oldCount address of the number of elements in the *old array + * @param newCount number of elements in the new array, may be 0 (then *old will be NULL afterwards) + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + */ +void +GNUNET_xgrow_ (void **old, size_t elementSize, unsigned int *oldCount, + unsigned int newCount, const char *filename, int linenumber); + + +/** + * Create a copy of the given message. + * + * @param msg message to copy + * @return duplicate of the message + */ +struct GNUNET_MessageHeader * +GNUNET_copy_message (const struct GNUNET_MessageHeader *msg); + + +#if __STDC_VERSION__ < 199901L +#if __GNUC__ >= 2 +#define __func__ __FUNCTION__ +#else +#define __func__ "" +#endif +#endif + +#endif /*GNUNET_COMMON_H_ */ diff --git a/src/include/gnunet_configuration_lib.h b/src/include/gnunet_configuration_lib.h new file mode 100644 index 0000000..f8f302a --- /dev/null +++ b/src/include/gnunet_configuration_lib.h @@ -0,0 +1,442 @@ +/* + This file is part of GNUnet. + (C) 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_configuration_lib.h + * @brief configuration API + * + * @author Christian Grothoff + */ + +#ifndef GNUNET_CONFIGURATION_LIB_H +#define GNUNET_CONFIGURATION_LIB_H + + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_time_lib.h" + +/** + * A configuration object. + */ +struct GNUNET_CONFIGURATION_Handle; + +/** + * Create a new configuration object. + * @return fresh configuration object + */ +struct GNUNET_CONFIGURATION_Handle * +GNUNET_CONFIGURATION_create (void); + + +/** + * Duplicate an existing configuration object. + * + * @param cfg configuration to duplicate + * @return duplicate configuration + */ +struct GNUNET_CONFIGURATION_Handle * +GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Destroy configuration object. + * + * @param cfg configuration to destroy + */ +void +GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Load configuration. This function will first parse the + * defaults and then parse the specific configuration file + * to overwrite the defaults. + * + * @param cfg configuration to update + * @param filename name of the configuration file, NULL to load defaults + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *filename); + + +/** + * Parse a configuration file, add all of the options in the + * file to the configuration environment. + * + * @param cfg configuration to update + * @param filename name of the configuration file + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *filename); + + +/** + * Write configuration file. + * + * @param cfg configuration to write + * @param filename where to write the configuration + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *filename); + +/** + * Write only configuration entries that have been changed to configuration file + * @param cfgDefault default configuration + * @param cfgNew new configuration + * @param filename where to write the configuration diff between default and new + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_write_diffs (const struct GNUNET_CONFIGURATION_Handle + *cfgDefault, + const struct GNUNET_CONFIGURATION_Handle + *cfgNew, const char *filename); + +/** + * Test if there are configuration options that were + * changed since the last save. + * + * @param cfg configuration to inspect + * @return GNUNET_NO if clean, GNUNET_YES if dirty, GNUNET_SYSERR on error (i.e. last save failed) + */ +int +GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Function to iterate over options. + * + * @param cls closure + * @param section name of the section + * @param option name of the option + * @param value value of the option + */ +typedef void (*GNUNET_CONFIGURATION_Iterator) (void *cls, const char *section, + const char *option, + const char *value); + + +/** + * Function to iterate over section. + * + * @param cls closure + * @param section name of the section + */ +typedef void (*GNUNET_CONFIGURATION_Section_Iterator) (void *cls, + const char *section); + + +/** + * Iterate over all options in the configuration. + * + * @param cfg configuration to inspect + * @param iter function to call on each option + * @param iter_cls closure for iter + */ +void +GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_CONFIGURATION_Iterator iter, + void *iter_cls); + + +/** + * Iterate over all sections in the configuration. + * + * @param cfg configuration to inspect + * @param iter function to call on each section + * @param iter_cls closure for iter + */ +void +GNUNET_CONFIGURATION_iterate_sections (const struct GNUNET_CONFIGURATION_Handle + *cfg, + GNUNET_CONFIGURATION_Section_Iterator + iter, void *iter_cls); + + +/** + * Remove the given section and all options in it. + * + * @param cfg configuration to inspect + * @param section name of the section to remove + */ +void +GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section); + +/** + * Get a configuration value that should be a number. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param number where to store the numeric value of the option + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_number (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + unsigned long long *number); + + +/** + * Get a configuration value that should be a relative time. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param time set to the time value stored in the configuration + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + struct GNUNET_TIME_Relative *time); + + + +/** + * Get a configuration value that should be a size in bytes. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param size set to the size in bytes as stored in the configuration + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_size (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + unsigned long long *size); + + +/** + * Test if we have a value for a particular option + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @return GNUNET_YES if so, GNUNET_NO if not. + */ +int +GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, const char *option); + + +/** + * Get a configuration value that should be a string. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param value will be set to a freshly allocated configuration + * value, or NULL if option is not specified + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_string (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, char **value); + + +/** + * Get a configuration value that should be the name of a file + * or directory. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param value will be set to a freshly allocated configuration + * value, or NULL if option is not specified + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_filename (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + const char *option, char **value); + +/** + * Iterate over the set of filenames stored in a configuration value. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param cb function to call on each filename + * @param cb_cls closure for cb + * @return number of filenames iterated over, -1 on error + */ +int +GNUNET_CONFIGURATION_iterate_value_filenames (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + const char *option, + GNUNET_FileNameCallback cb, + void *cb_cls); + +/** + * Iterate over values of a section in the configuration. + * + * @param cfg configuration to inspect + * @param section the section + * @param iter function to call on each option + * @param iter_cls closure for iter + */ +void +GNUNET_CONFIGURATION_iterate_section_values (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + GNUNET_CONFIGURATION_Iterator iter, + void *iter_cls); + +/** + * Get a configuration value that should be in a set of + * predefined strings + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param choices NULL-terminated list of legal values + * @param value will be set to an entry in the legal list, + * or NULL if option is not specified and no default given + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_choice (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, const char **choices, + const char **value); + +/** + * Get a configuration value that should be in a set of + * "YES" or "NO". + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @return GNUNET_YES, GNUNET_NO or if option has no valid value, GNUNET_SYSERR + */ +int +GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option); + + +/** + * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" + * where either in the "PATHS" section or the environtment + * "FOO" is set to "DIRECTORY". + * + * @param cfg configuration to use for path expansion + * @param orig string to $-expand (will be freed!) + * @return $-expanded string + */ +char * +GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle + *cfg, char *orig); + + +/** + * Set a configuration value that should be a number. + * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest + * @param number value to set + */ +void +GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, const char *option, + unsigned long long number); + + +/** + * Set a configuration value that should be a string. + * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest + * @param value value to set + */ +void +GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, const char *option, + const char *value); + + +/** + * Remove a filename from a configuration value that + * represents a list of filenames + * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest + * @param value filename to remove + * @return GNUNET_OK on success, + * GNUNET_SYSERR if the filename is not in the list + */ +int +GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + const char *value); + +/** + * Append a filename to a configuration value that + * represents a list of filenames + * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest + * @param value filename to append + * @return GNUNET_OK on success, + * GNUNET_SYSERR if the filename already in the list + */ +int +GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + const char *value); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/gnunet_connection_lib.h b/src/include/gnunet_connection_lib.h new file mode 100644 index 0000000..3e48d32 --- /dev/null +++ b/src/include/gnunet_connection_lib.h @@ -0,0 +1,373 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_connection_lib.h + * @brief basic, low-level TCP networking interface + * @author Christian Grothoff + */ +#ifndef GNUNET_CONNECTION_LIB_H +#define GNUNET_CONNECTION_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_network_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +/** + * Timeout we use on TCP connect before trying another + * result from the DNS resolver. Actual value used + * is this value divided by the number of address families. + * Default is 5s. + */ +#define GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +/** + * @brief handle for a network connection + */ +struct GNUNET_CONNECTION_Handle; + + +/** + * Credentials for UNIX domain sockets. + */ +struct GNUNET_CONNECTION_Credentials +{ + /** + * UID of the other end of the connection. + */ + uid_t uid; + + /** + * GID of the other end of the connection. + */ + gid_t gid; +}; + + +/** + * Function to call for access control checks. + * + * @param cls closure + * @param ucred credentials, if available, otherwise NULL + * @param addr address + * @param addrlen length of address + * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR + * for unknown address family (will be denied). + */ +typedef int (*GNUNET_CONNECTION_AccessCheck) (void *cls, + const struct + GNUNET_CONNECTION_Credentials * + ucred, + const struct sockaddr * addr, + socklen_t addrlen); + + +/** + * Callback function for data received from the network. Note that + * both "available" and "err" would be 0 if the read simply timed out. + * + * @param cls closure + * @param buf pointer to received data + * @param available number of bytes availabe in "buf", + * possibly 0 (on errors) + * @param addr address of the sender + * @param addrlen size of addr + * @param errCode value of errno (on errors receiving) + */ +typedef void (*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf, + size_t available, + const struct sockaddr * addr, + socklen_t addrlen, int errCode); + +/** + * Set the persist option on this connection handle. Indicates + * that the underlying socket or fd should never really be closed. + * Used for indicating process death. + * + * @param sock the connection to set persistent + */ +void +GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *sock); + +/** + * Disable the "CORK" feature for communication with the given socket, + * forcing the OS to immediately flush the buffer on transmission + * instead of potentially buffering multiple messages. Essentially + * reduces the OS send buffers to zero. + * Used to make sure that the last messages sent through the connection + * reach the other side before the process is terminated. + * + * @param sock the connection to make flushing and blocking + * @return GNUNET_OK on success + */ +int +GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *sock); + + +/** + * Create a socket handle by boxing an existing OS socket. The OS + * socket should henceforth be no longer used directly. + * GNUNET_socket_destroy will close it. + * + * @param osSocket existing socket to box + * @return the boxed socket handle + */ +struct GNUNET_CONNECTION_Handle * +GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket); + + +/** + * Create a socket handle by accepting on a listen socket. This + * function may block if the listen socket has no connection ready. + * + * @param access function to use to check if access is allowed + * @param access_cls closure for access + * @param lsock listen socket + * @return the socket handle, NULL on error (for example, access refused) + */ +struct GNUNET_CONNECTION_Handle * +GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, + void *access_cls, + struct GNUNET_NETWORK_Handle *lsock); + + +/** + * Create a socket handle by (asynchronously) connecting to a host. + * This function returns immediately, even if the connection has not + * yet been established. This function only creates TCP connections. + * + * @param cfg configuration to use + * @param hostname name of the host to connect to + * @param port port to connect to + * @return the socket handle + */ +struct GNUNET_CONNECTION_Handle * +GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *hostname, + uint16_t port); + + +/** + * Create a socket handle by connecting to a UNIX domain service. + * This function returns immediately, even if the connection has not + * yet been established. This function only creates UNIX connections. + * + * @param cfg configuration to use + * @param unixpath path to connect to) + * @return the socket handle, NULL on systems without UNIX support + */ +struct GNUNET_CONNECTION_Handle * +GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct + GNUNET_CONFIGURATION_Handle + *cfg, const char *unixpath); + + + + +/** + * Create a socket handle by (asynchronously) connecting to a host. + * This function returns immediately, even if the connection has not + * yet been established. This function only creates TCP connections. + * + * @param af_family address family to use + * @param serv_addr server address + * @param addrlen length of server address + * @return the socket handle + */ +struct GNUNET_CONNECTION_Handle * +GNUNET_CONNECTION_create_from_sockaddr (int af_family, + const struct sockaddr *serv_addr, + socklen_t addrlen); + +/** + * Check if socket is valid (no fatal errors have happened so far). + * Note that a socket that is still trying to connect is considered + * valid. + * + * @param sock socket to check + * @return GNUNET_YES if valid, GNUNET_NO otherwise + */ +int +GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *sock); + + +/** + * Obtain the network address of the other party. + * + * @param sock the client to get the address for + * @param addr where to store the address + * @param addrlen where to store the length of the address + * @return GNUNET_OK on success + */ +int +GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *sock, + void **addr, size_t * addrlen); + + +/** + * Close the socket and free associated resources. Pending + * transmissions may be completed or dropped depending on the + * arguments. If a receive call is pending and should + * NOT be completed, 'GNUNET_CONNECTION_receive_cancel' + * should be called explicitly first. + * + * @param sock socket to destroy + * @param finish_pending_write should pending writes be completed or aborted? + * (this applies to transmissions where the data has already been + * read from the application; all other transmissions should be + * aborted using 'GNUNET_CONNECTION_notify_transmit_ready_cancel'). + */ +void +GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *sock, + int finish_pending_write); + + +/** + * Receive data from the given socket. Note that this function will + * call "receiver" asynchronously using the scheduler. It will + * "immediately" return. Note that there MUST only be one active + * receive call per socket at any given point in time (so do not + * call receive again until the receiver callback has been invoked). + * + * @param sock socket handle + * @param max maximum number of bytes to read + * @param timeout maximum amount of time to wait + * @param receiver function to call with received data + * @param receiver_cls closure for receiver + */ +void +GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *sock, size_t max, + struct GNUNET_TIME_Relative timeout, + GNUNET_CONNECTION_Receiver receiver, + void *receiver_cls); + + +/** + * Cancel receive job on the given socket. Note that the + * receiver callback must not have been called yet in order + * for the cancellation to be valid. + * + * @param sock socket handle + * @return closure of the original receiver callback closure + */ +void * +GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock); + + +/** + * Function called to notify a client about the socket + * begin ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +typedef size_t (*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls, size_t size, + void *buf); + + +/** + * Opaque handle that can be used to cancel + * a transmit-ready notification. + */ +struct GNUNET_CONNECTION_TransmitHandle; + +/** + * Ask the socket to call us once the specified number of bytes + * are free in the transmission buffer. May call the notify + * method immediately if enough space is available. Note that + * this function will abort if "size" is greater than + * GNUNET_SERVER_MAX_MESSAGE_SIZE. + * + * Note that "notify" will be called either when enough + * buffer space is available OR when the socket is destroyed. + * The size parameter given to notify is guaranteed to be + * larger or equal to size if the buffer is ready, or zero + * if the socket was destroyed (or at least closed for + * writing). Finally, any time before 'notify' is called, a + * client may call "notify_transmit_ready_cancel" to cancel + * the transmission request. + * + * Only one transmission request can be scheduled at the same + * time. Notify will be run with the same scheduler priority + * as that of the caller. + * + * @param sock socket + * @param size number of bytes to send + * @param timeout after how long should we give up (and call + * notify with buf NULL and size 0)? + * @param notify function to call when buffer space is available + * @param notify_cls closure for notify + * @return non-NULL if the notify callback was queued, + * NULL if we are already going to notify someone else (busy) + */ +struct GNUNET_CONNECTION_TransmitHandle * +GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *sock, + size_t size, + struct GNUNET_TIME_Relative timeout, + GNUNET_CONNECTION_TransmitReadyNotify + notify, void *notify_cls); + + +/** + * Cancel the specified transmission-ready + * notification. + * + * @param th handle for notification to cancel + */ +void +GNUNET_CONNECTION_notify_transmit_ready_cancel (struct + GNUNET_CONNECTION_TransmitHandle + *th); + + +/** + * Configure this connection to ignore shutdown signals. + * + * @param sock socket handle + * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default + */ +void +GNUNET_CONNECTION_ignore_shutdown (struct GNUNET_CONNECTION_Handle *sock, + int do_ignore); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_CONNECTION_LIB_H */ +#endif +/* end of gnunet_connection_lib.h */ diff --git a/src/include/gnunet_constants.h b/src/include/gnunet_constants.h new file mode 100644 index 0000000..771b473 --- /dev/null +++ b/src/include/gnunet_constants.h @@ -0,0 +1,161 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_constants.h + * @brief "global" constants for performance tuning + * @author Christian Grothoff + */ + +#ifndef GNUNET_CONSTANTS_H +#define GNUNET_CONSTANTS_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_bandwidth_lib.h" + +/** + * Bandwidth (in/out) to assume initially (before either peer has + * communicated any particular preference). Should be rather low; set + * so that at least one maximum-size message can be send roughly once + * per minute. + */ +#define GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT GNUNET_BANDWIDTH_value_init (1024) + +/** + * After how long do we consider a connection to a peer dead + * if we don't receive messages from the peer? + */ +#define GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) + +/** + * After how long do we consider a connection to a peer dead + * if we got an explicit disconnect and were unable to reconnect? + */ +#define GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) + +/** + * How long do we delay reading more from a peer after a quota violation? + */ +#define GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) + +/** + * How long do we wait after a FORK+EXEC before testing for the + * resulting process to be up (port open, waitpid, etc.)? + */ +#define GNUNET_CONSTANTS_EXEC_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 200) + +/** + * After how long do we retry a service connection that was + * unavailable? Used in cases where an exponential back-off + * seems inappropriate. + */ +#define GNUNET_CONSTANTS_SERVICE_RETRY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500) + +/** + * After how long do we consider a service unresponsive + * even if we assume that the service commonly does not + * respond instantly (DNS, Database, etc.). + */ +#define GNUNET_CONSTANTS_SERVICE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 10) + +/** + * How long do we delay messages to get larger packet sizes (CORKing)? + */ +#define GNUNET_CONSTANTS_MAX_CORK_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * Until which load do we consider the peer overly idle + * (which means that we would like to use more resources).

+ * + * Note that we use 70 to leave some room for applications + * to consume resources "idly" (i.e. up to 85%) and then + * still have some room for "paid for" resource consumption. + */ +#define GNUNET_CONSTANTS_IDLE_LOAD_THRESHOLD 70 + +/** + * For how long do we allow unused bandwidth + * from the past to carry over into the future? (in seconds) + */ +#define GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S 5 + + +/** + * After how long do we expire an address in a HELLO that we just + * validated? This value is also used for our own addresses when we + * create a HELLO. + */ +#define GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) + + +/** + * Size of the 'struct EncryptedMessage' of the core (which + * is the per-message overhead of the core). + */ +#define GNUNET_CONSTANTS_CORE_SIZE_ENCRYPTED_MESSAGE (24 + sizeof (GNUNET_HashCode)) + +/** + * Size of the 'struct OutboundMessage' of the transport + * (which, in combination with the + * GNUNET_CONSTANTS_CORE_SIZE_ENCRYPTED_MESSAGE) defines + * the headers that must be pre-pendable to all GNUnet + * messages. Taking GNUNET_SERVER_MAX_MESSAGE_SIZE + * and subtracting these two constants defines the largest + * message core can handle. + */ +#define GNUNET_CONSTANTS_TRANSPORT_SIZE_OUTBOUND_MESSAGE (16 + sizeof (struct GNUNET_PeerIdentity)) + + +/** + * What is the maximum size for encrypted messages? Note that this + * number imposes a clear limit on the maximum size of any message. + * Set to a value close to 64k but not so close that transports will + * have trouble with their headers. + * + * Could theoretically be 64k minus (GNUNET_CONSTANTS_CORE_SIZE_ENCRYPTED_MESSAGE + + * GNUNET_CONSTANTS_TRANSPORT_SIZE_OUTBOUND_MESSAGE), but we're going + * to be more conservative for now. + */ +#define GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE (63 * 1024) + + +/** + * K-value that must be used for the bloom filters in 'GET' + * queries. + */ +#define GNUNET_CONSTANTS_BLOOMFILTER_K 16 + + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/gnunet_container_lib.h b/src/include/gnunet_container_lib.h new file mode 100644 index 0000000..75443b6 --- /dev/null +++ b/src/include/gnunet_container_lib.h @@ -0,0 +1,1240 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_container_lib.h + * @brief container classes for GNUnet + * + * @author Christian Grothoff + * @author Nils Durner + */ + +#ifndef GNUNET_CONTAINER_LIB_H +#define GNUNET_CONTAINER_LIB_H + +/* add error and config prototypes */ +#include "gnunet_crypto_lib.h" +#include + +#ifndef EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME +/* hack for LE < 0.6.3 */ +#define EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME 180 +#endif + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/* ******************* bloomfilter ***************** */ + +/** + * @brief bloomfilter representation (opaque) + */ +struct GNUNET_CONTAINER_BloomFilter; + +/** + * Iterator over HashCodes. + * + * @param cls closure + * @param next set to the next hash code + * @return GNUNET_YES if next was updated + * GNUNET_NO if there are no more entries + */ +typedef int (*GNUNET_HashCodeIterator) (void *cls, GNUNET_HashCode * next); + + +/** + * Load a bloom-filter from a file. + * + * @param filename the name of the file (or the prefix) + * @param size the size of the bloom-filter (number of + * bytes of storage space to use) + * @param k the number of GNUNET_CRYPTO_hash-functions to apply per + * element (number of bits set per element in the set) + * @return the bloomfilter + */ +struct GNUNET_CONTAINER_BloomFilter * +GNUNET_CONTAINER_bloomfilter_load (const char *filename, size_t size, + unsigned int k); + + +/** + * Create a bloom filter from raw bits. + * + * @param data the raw bits in memory (maybe NULL, + * in which case all bits should be considered + * to be zero). + * @param size the size of the bloom-filter (number of + * bytes of storage space to use); also size of data + * -- unless data is NULL. Must be a power of 2. + * @param k the number of GNUNET_CRYPTO_hash-functions to apply per + * element (number of bits set per element in the set) + * @return the bloomfilter + */ +struct GNUNET_CONTAINER_BloomFilter * +GNUNET_CONTAINER_bloomfilter_init (const char *data, size_t size, + unsigned int k); + + +/** + * Copy the raw data of this bloomfilter into + * the given data array. + * + * @param data where to write the data + * @param size the size of the given data array + * @return GNUNET_SYSERR if the data array of the wrong size + */ +int +GNUNET_CONTAINER_bloomfilter_get_raw_data (const struct + GNUNET_CONTAINER_BloomFilter *bf, + char *data, size_t size); + + +/** + * Test if an element is in the filter. + * @param e the element + * @param bf the filter + * @return GNUNET_YES if the element is in the filter, GNUNET_NO if not + */ +int +GNUNET_CONTAINER_bloomfilter_test (const struct GNUNET_CONTAINER_BloomFilter + *bf, const GNUNET_HashCode * e); + + +/** + * Add an element to the filter + * @param bf the filter + * @param e the element + */ +void +GNUNET_CONTAINER_bloomfilter_add (struct GNUNET_CONTAINER_BloomFilter *bf, + const GNUNET_HashCode * e); + + +/** + * Remove an element from the filter. + * @param bf the filter + * @param e the element to remove + */ +void +GNUNET_CONTAINER_bloomfilter_remove (struct GNUNET_CONTAINER_BloomFilter *bf, + const GNUNET_HashCode * e); + + +/** + * Create a copy of a bloomfilter. + * + * @param bf the filter + * @return copy of bf + */ +struct GNUNET_CONTAINER_BloomFilter * +GNUNET_CONTAINER_bloomfilter_copy (const struct GNUNET_CONTAINER_BloomFilter + *bf); + + + +/** + * Free the space associcated with a filter + * in memory, flush to drive if needed (do not + * free the space on the drive) + * @param bf the filter + */ +void +GNUNET_CONTAINER_bloomfilter_free (struct GNUNET_CONTAINER_BloomFilter *bf); + + +/** + * Get size of the bloom filter. + * + * @param bf the filter + * @return number of bytes used for the data of the bloom filter + */ +size_t +GNUNET_CONTAINER_bloomfilter_get_size (const struct GNUNET_CONTAINER_BloomFilter + *bf); + + +/** + * Reset a bloom filter to empty. + * @param bf the filter + */ +void +GNUNET_CONTAINER_bloomfilter_clear (struct GNUNET_CONTAINER_BloomFilter *bf); + +/** + * Or the entries of the given raw data array with the + * data of the given bloom filter. Assumes that + * the size of the data array and the current filter + * match. + * + * @param bf the filter + * @param data data to OR-in + * @param size size of data + * @return GNUNET_OK on success + */ +int +GNUNET_CONTAINER_bloomfilter_or (struct GNUNET_CONTAINER_BloomFilter *bf, + const char *data, size_t size); + +/** + * Or the entries of the given raw data array with the + * data of the given bloom filter. Assumes that + * the size of the data array and the current filter + * match. + * + * @param bf the filter + * @param to_or the bloomfilter to or-in + * @param size number of bytes in data + */ +int +GNUNET_CONTAINER_bloomfilter_or2 (struct GNUNET_CONTAINER_BloomFilter *bf, + const struct GNUNET_CONTAINER_BloomFilter + *to_or, size_t size); + +/** + * Resize a bloom filter. Note that this operation + * is pretty costly. Essentially, the bloom filter + * needs to be completely re-build. + * + * @param bf the filter + * @param iterator an iterator over all elements stored in the BF + * @param iterator_cls closure for iterator + * @param size the new size for the filter + * @param k the new number of GNUNET_CRYPTO_hash-function to apply per element + */ +void +GNUNET_CONTAINER_bloomfilter_resize (struct GNUNET_CONTAINER_BloomFilter *bf, + GNUNET_HashCodeIterator iterator, + void *iterator_cls, size_t size, + unsigned int k); + +/* ****************** metadata ******************* */ + +/** + * Meta data to associate with a file, directory or namespace. + */ +struct GNUNET_CONTAINER_MetaData; + +/** + * Create a fresh MetaData token. + * + * @return empty meta-data container + */ +struct GNUNET_CONTAINER_MetaData * +GNUNET_CONTAINER_meta_data_create (void); + +/** + * Duplicate a MetaData token. + * + * @param md what to duplicate + * @return duplicate meta-data container + */ +struct GNUNET_CONTAINER_MetaData * +GNUNET_CONTAINER_meta_data_duplicate (const struct GNUNET_CONTAINER_MetaData + *md); + +/** + * Free meta data. + * + * @param md what to free + */ +void +GNUNET_CONTAINER_meta_data_destroy (struct GNUNET_CONTAINER_MetaData *md); + +/** + * Test if two MDs are equal. We consider them equal if + * the meta types, formats and content match (we do not + * include the mime types and plugins names in this + * consideration). + * + * @param md1 first value to check + * @param md2 other value to check + * @return GNUNET_YES if they are equal + */ +int +GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData + *md1, + const struct GNUNET_CONTAINER_MetaData + *md2); + + +/** + * Extend metadata. + * + * @param md metadata to extend + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_len number of bytes in data + * @return GNUNET_OK on success, GNUNET_SYSERR if this entry already exists + * data_mime_type and plugin_name are not considered for "exists" checks + */ +int +GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md, + const char *plugin_name, + enum EXTRACTOR_MetaType type, + enum EXTRACTOR_MetaFormat format, + const char *data_mime_type, const char *data, + size_t data_len); + + +/** + * Extend metadata. Merges the meta data from the second argument + * into the first, discarding duplicate key-value pairs. + * + * @param md metadata to extend + * @param in metadata to merge + */ +void +GNUNET_CONTAINER_meta_data_merge (struct GNUNET_CONTAINER_MetaData *md, + const struct GNUNET_CONTAINER_MetaData *in); + + +/** + * Remove an item. + * + * @param md metadata to manipulate + * @param type type of the item to remove + * @param data specific value to remove, NULL to remove all + * entries of the given type + * @param data_len number of bytes in data + * @return GNUNET_OK on success, GNUNET_SYSERR if the item does not exist in md + */ +int +GNUNET_CONTAINER_meta_data_delete (struct GNUNET_CONTAINER_MetaData *md, + enum EXTRACTOR_MetaType type, + const char *data, size_t data_len); + + +/** + * Remove all items in the container. + * + * @param md metadata to manipulate + */ +void +GNUNET_CONTAINER_meta_data_clear (struct GNUNET_CONTAINER_MetaData *md); + + +/** + * Add the current time as the publication date + * to the meta-data. + * + * @param md metadata to modify + */ +void +GNUNET_CONTAINER_meta_data_add_publication_date (struct + GNUNET_CONTAINER_MetaData *md); + + +/** + * Iterate over MD entries. + * + * @param md metadata to inspect + * @param iter function to call on each entry + * @param iter_cls closure for iterator + * @return number of entries + */ +int +GNUNET_CONTAINER_meta_data_iterate (const struct GNUNET_CONTAINER_MetaData *md, + EXTRACTOR_MetaDataProcessor iter, + void *iter_cls); + +/** + * Get the first MD entry of the given type. Caller + * is responsible for freeing the return value. + * Also, only meta data items that are strings (0-terminated) + * are returned by this function. + * + * @param md metadata to inspect + * @param type type to look for + * @return NULL if no entry was found + */ +char * +GNUNET_CONTAINER_meta_data_get_by_type (const struct GNUNET_CONTAINER_MetaData + *md, enum EXTRACTOR_MetaType type); + + +/** + * Get the first matching MD entry of the given types. Caller is + * responsible for freeing the return value. Also, only meta data + * items that are strings (0-terminated) are returned by this + * function. + * + * @param md metadata to inspect + * @param ... -1-terminated list of types + * @return NULL if we do not have any such entry, + * otherwise client is responsible for freeing the value! + */ +char * +GNUNET_CONTAINER_meta_data_get_first_by_types (const struct + GNUNET_CONTAINER_MetaData *md, + ...); + +/** + * Get a thumbnail from the meta-data (if present). Only matches meta + * data with mime type "image" and binary format. + * + * @param md metadata to inspect + * @param thumb will be set to the thumbnail data. Must be + * freed by the caller! + * @return number of bytes in thumbnail, 0 if not available + */ +size_t +GNUNET_CONTAINER_meta_data_get_thumbnail (const struct GNUNET_CONTAINER_MetaData + *md, unsigned char **thumb); + + + +/** + * Options for metadata serialization. + */ +enum GNUNET_CONTAINER_MetaDataSerializationOptions +{ + /** + * Serialize all of the data. + */ + GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL = 0, + + /** + * If not enough space is available, it is acceptable + * to only serialize some of the metadata. + */ + GNUNET_CONTAINER_META_DATA_SERIALIZE_PART = 1, + + /** + * Speed is of the essence, do not allow compression. + */ + GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS = 2 +}; + + +/** + * Serialize meta-data to target. + * + * @param md metadata to serialize + * @param target where to write the serialized metadata; + * *target can be NULL, in which case memory is allocated + * @param max maximum number of bytes available + * @param opt is it ok to just write SOME of the + * meta-data to match the size constraint, + * possibly discarding some data? + * @return number of bytes written on success, + * -1 on error (typically: not enough + * space) + */ +ssize_t +GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData + *md, char **target, size_t max, + enum + GNUNET_CONTAINER_MetaDataSerializationOptions + opt); + + +/** + * Get the size of the full meta-data in serialized form. + * + * @param md metadata to inspect + * @return number of bytes needed for serialization, -1 on error + */ +ssize_t +GNUNET_CONTAINER_meta_data_get_serialized_size (const struct + GNUNET_CONTAINER_MetaData *md); + + +/** + * Deserialize meta-data. Initializes md. + * + * @param input serialized meta-data. + * @param size number of bytes available + * @return MD on success, NULL on error (i.e. + * bad format) + */ +struct GNUNET_CONTAINER_MetaData * +GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size); + + +/* ******************************* HashMap **************************** */ + +/** + * Opaque handle for a HashMap. + */ +struct GNUNET_CONTAINER_MultiHashMap; + +/** + * Options for storing values in the HashMap. + */ +enum GNUNET_CONTAINER_MultiHashMapOption +{ + + /** + * If a value with the given key exists, replace it. Note that the + * old value would NOT be freed by replace (the application has to + * make sure that this happens if required). + */ + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE, + + /** + * Allow multiple values with the same key. + */ + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE, + + /** + * There must only be one value per key; storing a value should fail + * if a value under the same key already exists. + */ + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, + + /** + * There must only be one value per key, but don't bother checking + * if a value already exists (faster than UNIQUE_ONLY; implemented + * just like MULTIPLE but this option documents better what is + * intended if UNIQUE is what is desired). + */ + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST +}; + + +/** + * Iterator over hash map entries. + * + * @param cls closure + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +typedef int (*GNUNET_CONTAINER_HashMapIterator) (void *cls, + const GNUNET_HashCode * key, + void *value); + + +/** + * Create a multi hash map. + * + * @param len initial size (map will grow as needed) + * @return NULL on error + */ +struct GNUNET_CONTAINER_MultiHashMap * +GNUNET_CONTAINER_multihashmap_create (unsigned int len); + + +/** + * Destroy a hash map. Will not free any values + * stored in the hash map! + * + * @param map the map + */ +void +GNUNET_CONTAINER_multihashmap_destroy (struct GNUNET_CONTAINER_MultiHashMap + *map); + + +/** + * Given a key find a value in the map matching the key. + * + * @param map the map + * @param key what to look for + * @return NULL if no value was found; note that + * this is indistinguishable from values that just + * happen to be NULL; use "contains" to test for + * key-value pairs with value NULL + */ +void * +GNUNET_CONTAINER_multihashmap_get (const struct GNUNET_CONTAINER_MultiHashMap + *map, const GNUNET_HashCode * key); + + +/** + * Remove the given key-value pair from the map. Note that if the + * key-value pair is in the map multiple times, only one of the pairs + * will be removed. + * + * @param map the map + * @param key key of the key-value pair + * @param value value of the key-value pair + * @return GNUNET_YES on success, GNUNET_NO if the key-value pair + * is not in the map + */ +int +GNUNET_CONTAINER_multihashmap_remove (struct GNUNET_CONTAINER_MultiHashMap *map, + const GNUNET_HashCode * key, void *value); + +/** + * Remove all entries for the given key from the map. + * Note that the values would not be "freed". + * + * @param map the map + * @param key identifies values to be removed + * @return number of values removed + */ +int +GNUNET_CONTAINER_multihashmap_remove_all (struct GNUNET_CONTAINER_MultiHashMap + *map, const GNUNET_HashCode * key); + + +/** + * Check if the map contains any value under the given + * key (including values that are NULL). + * + * @param map the map + * @param key the key to test if a value exists for it + * @return GNUNET_YES if such a value exists, + * GNUNET_NO if not + */ +int +GNUNET_CONTAINER_multihashmap_contains (const struct + GNUNET_CONTAINER_MultiHashMap *map, + const GNUNET_HashCode * key); + + +/** + * Check if the map contains the given value under the given + * key. + * + * @param map the map + * @param key the key to test if a value exists for it + * @param value value to test for + * @return GNUNET_YES if such a value exists, + * GNUNET_NO if not + */ +int +GNUNET_CONTAINER_multihashmap_contains_value (const struct + GNUNET_CONTAINER_MultiHashMap + *map, const GNUNET_HashCode * key, + const void *value); + + +/** + * Store a key-value pair in the map. + * + * @param map the map + * @param key key to use + * @param value value to use + * @param opt options for put + * @return GNUNET_OK on success, + * GNUNET_NO if a value was replaced (with REPLACE) + * GNUNET_SYSERR if UNIQUE_ONLY was the option and the + * value already exists + */ +int +GNUNET_CONTAINER_multihashmap_put (struct GNUNET_CONTAINER_MultiHashMap *map, + const GNUNET_HashCode * key, void *value, + enum GNUNET_CONTAINER_MultiHashMapOption + opt); + +/** + * Get the number of key-value pairs in the map. + * + * @param map the map + * @return the number of key value pairs + */ +unsigned int +GNUNET_CONTAINER_multihashmap_size (const struct GNUNET_CONTAINER_MultiHashMap + *map); + + +/** + * Iterate over all entries in the map. + * + * @param map the map + * @param it function to call on each entry + * @param it_cls extra argument to it + * @return the number of key value pairs processed, + * GNUNET_SYSERR if it aborted iteration + */ +int +GNUNET_CONTAINER_multihashmap_iterate (const struct + GNUNET_CONTAINER_MultiHashMap *map, + GNUNET_CONTAINER_HashMapIterator it, + void *it_cls); + + +/** + * Iterate over all entries in the map that match a particular key. + * + * @param map the map + * @param key key that the entries must correspond to + * @param it function to call on each entry + * @param it_cls extra argument to it + * @return the number of key value pairs processed, + * GNUNET_SYSERR if it aborted iteration + */ +int +GNUNET_CONTAINER_multihashmap_get_multiple (const struct + GNUNET_CONTAINER_MultiHashMap *map, + const GNUNET_HashCode * key, + GNUNET_CONTAINER_HashMapIterator it, + void *it_cls); + + +/* ******************** doubly-linked list *************** */ +/* To avoid mistakes: head->prev == tail->next == NULL */ + +/** + * Insert an element at the head of a DLL. Assumes that head, tail and + * element are structs with prev and next fields. + * + * @param head pointer to the head of the DLL + * @param tail pointer to the tail of the DLL + * @param element element to insert + */ +#define GNUNET_CONTAINER_DLL_insert(head,tail,element) do { \ + GNUNET_assert ( ( (element)->prev == NULL) && ((head) != (element))); \ + GNUNET_assert ( ( (element)->next == NULL) && ((tail) != (element))); \ + (element)->next = (head); \ + (element)->prev = NULL; \ + if ((tail) == NULL) \ + (tail) = element; \ + else \ + (head)->prev = element; \ + (head) = (element); } while (0) + + +/** + * Insert an element at the tail of a DLL. Assumes that head, tail and + * element are structs with prev and next fields. + * + * @param head pointer to the head of the DLL + * @param tail pointer to the tail of the DLL + * @param element element to insert + */ +#define GNUNET_CONTAINER_DLL_insert_tail(head,tail,element) do { \ + GNUNET_assert ( ( (element)->prev == NULL) && ((head) != (element))); \ + GNUNET_assert ( ( (element)->next == NULL) && ((tail) != (element))); \ + (element)->prev = (tail); \ + (element)->next = NULL; \ + if ((head) == NULL) \ + (head) = element; \ + else \ + (tail)->next = element; \ + (tail) = (element); } while (0) + + +/** + * Insert an element into a DLL after the given other element. Insert + * at the head if the other element is NULL. + * + * @param head pointer to the head of the DLL + * @param tail pointer to the tail of the DLL + * @param other prior element, NULL for insertion at head of DLL + * @param element element to insert + */ +#define GNUNET_CONTAINER_DLL_insert_after(head,tail,other,element) do { \ + GNUNET_assert ( ( (element)->prev == NULL) && ((head) != (element))); \ + GNUNET_assert ( ( (element)->next == NULL) && ((tail) != (element))); \ + (element)->prev = (other); \ + if (NULL == other) \ + { \ + (element)->next = (head); \ + (head) = (element); \ + } \ + else \ + { \ + (element)->next = (other)->next; \ + (other)->next = (element); \ + } \ + if (NULL == (element)->next) \ + (tail) = (element); \ + else \ + (element)->next->prev = (element); } while (0) + + +/** + * Insert an element into a DLL before the given other element. Insert + * at the tail if the other element is NULL. + * + * @param head pointer to the head of the DLL + * @param tail pointer to the tail of the DLL + * @param other prior element, NULL for insertion at head of DLL + * @param element element to insert + */ +#define GNUNET_CONTAINER_DLL_insert_before(head,tail,other,element) do { \ + GNUNET_assert ( ( (element)->prev == NULL) && ((head) != (element))); \ + GNUNET_assert ( ( (element)->next == NULL) && ((tail) != (element))); \ + (element)->next = (other); \ + if (NULL == other) \ + { \ + (element)->prev = (tail); \ + (tail) = (element); \ + } \ + else \ + { \ + (element)->prev = (other)->prev; \ + (other)->prev = (element); \ + } \ + if (NULL == (element)->prev) \ + (head) = (element); \ + else \ + (element)->prev->next = (element); } while (0) + + +/** + * Remove an element from a DLL. Assumes + * that head, tail and element are structs + * with prev and next fields. + * + * @param head pointer to the head of the DLL + * @param tail pointer to the tail of the DLL + * @param element element to remove + */ +#define GNUNET_CONTAINER_DLL_remove(head,tail,element) do { \ + GNUNET_assert ( ( (element)->prev != NULL) || ((head) == (element))); \ + GNUNET_assert ( ( (element)->next != NULL) || ((tail) == (element))); \ + if ((element)->prev == NULL) \ + (head) = (element)->next; \ + else \ + (element)->prev->next = (element)->next; \ + if ((element)->next == NULL) \ + (tail) = (element)->prev; \ + else \ + (element)->next->prev = (element)->prev; \ + (element)->next = NULL; \ + (element)->prev = NULL; } while (0) + + + +/* ******************** Heap *************** */ + + +/** + * Cost by which elements in a heap can be ordered. + */ +typedef uint64_t GNUNET_CONTAINER_HeapCostType; + + +/* + * Heap type, either max or min. Hopefully makes the + * implementation more useful. + */ +enum GNUNET_CONTAINER_HeapOrder +{ + /** + * Heap with the maximum cost at the root. + */ + GNUNET_CONTAINER_HEAP_ORDER_MAX, + + /** + * Heap with the minimum cost at the root. + */ + GNUNET_CONTAINER_HEAP_ORDER_MIN +}; + + +/** + * Handle to a Heap. + */ +struct GNUNET_CONTAINER_Heap; + + + +/** + * Handle to a node in a heap. + */ +struct GNUNET_CONTAINER_HeapNode; + + +/** + * Create a new heap. + * + * @param order how should the heap be sorted? + * @return handle to the heap + */ +struct GNUNET_CONTAINER_Heap * +GNUNET_CONTAINER_heap_create (enum GNUNET_CONTAINER_HeapOrder order); + + +/** + * Destroys the heap. Only call on a heap that + * is already empty. + * + * @param heap heap to destroy + */ +void +GNUNET_CONTAINER_heap_destroy (struct GNUNET_CONTAINER_Heap *heap); + + +/** + * Get element stored at root of heap. + * + * @param heap heap to inspect + * @return NULL if heap is empty + */ +void * +GNUNET_CONTAINER_heap_peek (const struct GNUNET_CONTAINER_Heap *heap); + + +/** + * Get the current size of the heap + * + * @param heap the heap to get the size of + * @return number of elements stored + */ +unsigned int +GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap); + + +/** + * Get the current cost of the node + * + * @param node the node to get the cost of + * @return cost of the node + */ +GNUNET_CONTAINER_HeapCostType +GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode + *node); + +/** + * Iterator for heap + * + * @param cls closure + * @param node internal node of the heap + * @param element value stored at the node + * @param cost cost associated with the node + * @return GNUNET_YES if we should continue to iterate, + * GNUNET_NO if not. + */ +typedef int (*GNUNET_CONTAINER_HeapIterator) (void *cls, + struct GNUNET_CONTAINER_HeapNode * + node, void *element, + GNUNET_CONTAINER_HeapCostType + cost); + + +/** + * Iterate over all entries in the heap. + * + * @param heap the heap + * @param iterator function to call on each entry + * @param iterator_cls closure for iterator + */ +void +GNUNET_CONTAINER_heap_iterate (const struct GNUNET_CONTAINER_Heap *heap, + GNUNET_CONTAINER_HeapIterator iterator, + void *iterator_cls); + + +/** + * Return a *uniform* random element from the heap. Choose a random + * number between 0 and heap size and then walk directly to it. + * This cost can be between 0 and n, amortized cost of logN. + * + * @param heap heap to choose random element from + * @param max how many nodes from the heap to choose from + * + * @return data stored at the chosen random node, + * NULL if the heap is empty. + * + */ +void * +GNUNET_CONTAINER_heap_get_random (struct GNUNET_CONTAINER_Heap *heap, + uint32_t max); + + +/** + * Perform a random walk of the tree. The walk is biased + * towards elements closer to the root of the tree (since + * each walk starts at the root and ends at a random leaf). + * The heap internally tracks the current position of the + * walk. + * + * @param heap heap to walk + * @return data stored at the next random node in the walk; + * NULL if the tree is empty. + */ +void * +GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap); + + +/** + * Inserts a new element into the heap. + * + * @param heap heap to modify + * @param element element to insert + * @param cost cost for the element + * @return node for the new element + */ +struct GNUNET_CONTAINER_HeapNode * +GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, void *element, + GNUNET_CONTAINER_HeapCostType cost); + + +/** + * Remove root of the heap. + * + * @param heap heap to modify + * @return element data stored at the root node + */ +void * +GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap); + + +/** + * Removes a node from the heap. + * + * @param node node to remove + * @return element data stored at the node, NULL if heap is empty + */ +void * +GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node); + + +/** + * Updates the cost of any node in the tree + * + * @param heap heap to modify + * @param node node for which the cost is to be changed + * @param new_cost new cost for the node + */ +void +GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap, + struct GNUNET_CONTAINER_HeapNode *node, + GNUNET_CONTAINER_HeapCostType new_cost); + + +/* ******************** Singly linked list *************** */ + +/** + * Possible ways for how data stored in the linked list + * might be allocated. + */ +enum GNUNET_CONTAINER_SListDisposition +{ + /** + * Single-linked list must copy the buffer. + */ + GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT = 0, + + /** + * Data is static, no need to copy or free. + */ + GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC = 2, + + /** + * Data is dynamic, do not copy but free when done. + */ + GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC = 4 +}; + + + +/** + * Handle to a singly linked list + */ +struct GNUNET_CONTAINER_SList; + +/** + * Handle to a singly linked list iterator + */ +struct GNUNET_CONTAINER_SList_Iterator +{ + /** + * Linked list that we are iterating over. + */ + struct GNUNET_CONTAINER_SList *list; + + /** + * Last element accessed. + */ + struct GNUNET_CONTAINER_SList_Elem *last; + + /** + * Current list element. + */ + struct GNUNET_CONTAINER_SList_Elem *elem; +}; + + + +/** + * Add a new element to the list + * @param l list + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the buffer + */ +void +GNUNET_CONTAINER_slist_add (struct GNUNET_CONTAINER_SList *l, + enum GNUNET_CONTAINER_SListDisposition disp, + const void *buf, size_t len); + + +/** + * Add a new element to the end of the list + * @param l list + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the buffer + */ +void +GNUNET_CONTAINER_slist_add_end (struct GNUNET_CONTAINER_SList *l, + enum GNUNET_CONTAINER_SListDisposition disp, + const void *buf, size_t len); + + +/** + * Append a singly linked list to another + * @param dst list to append to + * @param src source + */ +void +GNUNET_CONTAINER_slist_append (struct GNUNET_CONTAINER_SList *dst, + struct GNUNET_CONTAINER_SList *src); + + +/** + * Create a new singly linked list + * @return the new list + */ +struct GNUNET_CONTAINER_SList * +GNUNET_CONTAINER_slist_create (void); + + +/** + * Destroy a singly linked list + * @param l the list to be destroyed + */ +void +GNUNET_CONTAINER_slist_destroy (struct GNUNET_CONTAINER_SList *l); + + +/** + * Return the beginning of a list + * + * @param l list + * @return iterator pointing to the beginning (by value! Either allocate the + * structure on the stack, or use GNUNET_malloc() yourself! All other + * functions do take pointer to this struct though) + */ +struct GNUNET_CONTAINER_SList_Iterator +GNUNET_CONTAINER_slist_begin (struct GNUNET_CONTAINER_SList *l); + + +/** + * Clear a list + * + * @param l list + */ +void +GNUNET_CONTAINER_slist_clear (struct GNUNET_CONTAINER_SList *l); + + +/** + * Check if a list contains a certain element + * @param l list + * @param buf payload buffer to find + * @param len length of the payload (number of bytes in buf) + */ +int +GNUNET_CONTAINER_slist_contains (const struct GNUNET_CONTAINER_SList *l, + const void *buf, size_t len); + + +/** + * Count the elements of a list + * @param l list + * @return number of elements in the list + */ +int +GNUNET_CONTAINER_slist_count (const struct GNUNET_CONTAINER_SList *l); + + +/** + * Remove an element from the list + * @param i iterator that points to the element to be removed + */ +void +GNUNET_CONTAINER_slist_erase (struct GNUNET_CONTAINER_SList_Iterator *i); + + +/** + * Insert an element into a list at a specific position + * @param before where to insert the new element + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the payload + */ +void +GNUNET_CONTAINER_slist_insert (struct GNUNET_CONTAINER_SList_Iterator *before, + enum GNUNET_CONTAINER_SListDisposition disp, + const void *buf, size_t len); + + +/** + * Advance an iterator to the next element + * @param i iterator + * @return GNUNET_YES on success, GNUNET_NO if the end has been reached + */ +int +GNUNET_CONTAINER_slist_next (struct GNUNET_CONTAINER_SList_Iterator *i); + + +/** + * Check if an iterator points beyond the end of a list + * @param i iterator + * @return GNUNET_YES if the end has been reached, GNUNET_NO if the iterator + * points to a valid element + */ +int +GNUNET_CONTAINER_slist_end (struct GNUNET_CONTAINER_SList_Iterator *i); + + +/** + * Retrieve the element at a specific position in a list + * + * @param i iterator + * @param len set to the payload length + * @return payload + */ +void * +GNUNET_CONTAINER_slist_get (const struct GNUNET_CONTAINER_SList_Iterator *i, + size_t * len); + + +/** + * Release an iterator + * @param i iterator + */ +void +GNUNET_CONTAINER_slist_iter_destroy (struct GNUNET_CONTAINER_SList_Iterator *i); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_CONTAINER_LIB_H */ +#endif +/* end of gnunet_container_lib.h */ diff --git a/src/include/gnunet_core_service.h b/src/include/gnunet_core_service.h new file mode 100644 index 0000000..1f6c0f3 --- /dev/null +++ b/src/include/gnunet_core_service.h @@ -0,0 +1,328 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_core_service.h + * @brief core service; this is the main API for encrypted P2P + * communications + * @author Christian Grothoff + */ + +#ifndef GNUNET_CORE_SERVICE_H +#define GNUNET_CORE_SERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" + +/** + * Version number of GNUnet-core API. + */ +#define GNUNET_CORE_VERSION 0x00000000 + + +/** + * Opaque handle to the service. + */ +struct GNUNET_CORE_Handle; + + +/** + * Method called whenever a given peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data for the connection + * @param atsi_count number of records in 'atsi' + */ +typedef void (*GNUNET_CORE_ConnectEventHandler) (void *cls, + const struct + GNUNET_PeerIdentity * peer, + const struct + GNUNET_ATS_Information * atsi, + unsigned int atsi_count); + + +/** + * Method called whenever a peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +typedef void (*GNUNET_CORE_DisconnectEventHandler) (void *cls, + const struct + GNUNET_PeerIdentity * peer); + + +/** + * Functions with this signature are called whenever a message is + * received or transmitted. + * + * @param cls closure (set from GNUNET_CORE_connect) + * @param peer the other peer involved (sender or receiver, NULL + * for loopback messages where we are both sender and receiver) + * @param message the actual message + * @param atsi performance data for the connection + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +typedef int (*GNUNET_CORE_MessageCallback) (void *cls, + const struct GNUNET_PeerIdentity * + other, + const struct GNUNET_MessageHeader * + message, + const struct GNUNET_ATS_Information + * atsi, unsigned int atsi_count); + + +/** + * Message handler. Each struct specifies how to handle on particular + * type of message received. + */ +struct GNUNET_CORE_MessageHandler +{ + /** + * Function to call for messages of "type". + */ + GNUNET_CORE_MessageCallback callback; + + /** + * Type of the message this handler covers. + */ + uint16_t type; + + /** + * Expected size of messages of this type. Use 0 for variable-size. + * If non-zero, messages of the given type will be discarded if they + * do not have the right size. + */ + uint16_t expected_size; + +}; + + +/** + * Function called after GNUNET_CORE_connect has succeeded (or failed + * for good). Note that the private key of the peer is intentionally + * not exposed here; if you need it, your process should try to read + * the private key file directly (which should work if you are + * authorized...). + * + * @param cls closure + * @param server handle to the server, NULL if we failed + * @param my_identity ID of this peer, NULL if we failed + */ +typedef void (*GNUNET_CORE_StartupCallback) (void *cls, + struct GNUNET_CORE_Handle * server, + const struct GNUNET_PeerIdentity * + my_identity); + + +/** + * Connect to the core service. Note that the connection may complete + * (or fail) asynchronously. This function primarily causes the given + * callback notification functions to be invoked whenever the + * specified event happens. The maximum number of queued + * notifications (queue length) is per client but the queue is shared + * across all types of notifications. So a slow client that registers + * for 'outbound_notify' also risks missing 'inbound_notify' messages. + * Certain events (such as connect/disconnect notifications) are not + * subject to queue size limitations. + * + * @param cfg configuration to use + * @param queue_size size of the per-peer message queue + * @param cls closure for the various callbacks that follow (including handlers in the handlers array) + * @param init callback to call on timeout or once we have successfully + * connected to the core service; note that timeout is only meaningful if init is not NULL + * @param connects function to call on peer connect, can be NULL + * @param disconnects function to call on peer disconnect / timeout, can be NULL + * @param inbound_notify function to call for all inbound messages, can be NULL + * note that the core is allowed to drop notifications about inbound + * messages if the client does not process them fast enough (for this + * notification type, a bounded queue is used) + * @param inbound_hdr_only set to GNUNET_YES if inbound_notify will only read the + * GNUNET_MessageHeader and hence we do not need to give it the full message; + * can be used to improve efficiency, ignored if inbound_notify is NULL + * note that the core is allowed to drop notifications about inbound + * messages if the client does not process them fast enough (for this + * notification type, a bounded queue is used) + * @param outbound_notify function to call for all outbound messages, can be NULL; + * note that the core is allowed to drop notifications about outbound + * messages if the client does not process them fast enough (for this + * notification type, a bounded queue is used) + * @param outbound_hdr_only set to GNUNET_YES if outbound_notify will only read the + * GNUNET_MessageHeader and hence we do not need to give it the full message + * can be used to improve efficiency, ignored if outbound_notify is NULL + * note that the core is allowed to drop notifications about outbound + * messages if the client does not process them fast enough (for this + * notification type, a bounded queue is used) + * @param handlers callbacks for messages we care about, NULL-terminated + * note that the core is allowed to drop notifications about inbound + * messages if the client does not process them fast enough (for this + * notification type, a bounded queue is used) + * @return handle to the core service (only useful for disconnect until 'init' is called), + * NULL on error (in this case, init is never called) + */ +struct GNUNET_CORE_Handle * +GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int queue_size, void *cls, + GNUNET_CORE_StartupCallback init, + GNUNET_CORE_ConnectEventHandler connects, + GNUNET_CORE_DisconnectEventHandler disconnects, + GNUNET_CORE_MessageCallback inbound_notify, + int inbound_hdr_only, + GNUNET_CORE_MessageCallback outbound_notify, + int outbound_hdr_only, + const struct GNUNET_CORE_MessageHandler *handlers); + + +/** + * Disconnect from the core service. This function can only + * be called *after* all pending 'GNUNET_CORE_notify_transmit_ready' + * requests have been explicitly cancelled. + * + * @param handle connection to core to disconnect + */ +void +GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle); + + +/** + * Handle for a transmission request. + */ +struct GNUNET_CORE_TransmitHandle; + + +/** + * Ask the core to call "notify" once it is ready to transmit the + * given number of bytes to the specified "target". Must only be + * called after a connection to the respective peer has been + * established (and the client has been informed about this). + * + * + * @param handle connection to core service + * @param cork is corking allowed for this transmission? + * @param priority how important is the message? + * @param maxdelay how long can the message wait? + * @param target who should receive the message, + * use NULL for this peer (loopback) + * @param notify_size how many bytes of buffer space does notify want? + * @param notify function to call when buffer space is available; + * will be called with NULL on timeout or if the overall queue + * for this peer is larger than queue_size and this is currently + * the message with the lowest priority; will also be called + * with 'NULL' buf if the peer disconnects; since the disconnect + * signal will be emmitted even later, clients MUST cancel + * all pending transmission requests DURING the disconnect + * handler (unless they ensure that 'notify' never calls + * 'GNUNET_CORE_notify_transmit_ready'). + * @param notify_cls closure for notify + * @return non-NULL if the notify callback was queued, + * NULL if we can not even queue the request (insufficient + * memory); if NULL is returned, "notify" will NOT be called. + */ +struct GNUNET_CORE_TransmitHandle * +GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle, int cork, + uint32_t priority, + struct GNUNET_TIME_Relative maxdelay, + const struct GNUNET_PeerIdentity *target, + size_t notify_size, + GNUNET_CONNECTION_TransmitReadyNotify notify, + void *notify_cls); + + +/** + * Cancel the specified transmission-ready notification. + * + * @param th handle that was returned by "notify_transmit_ready". + */ +void +GNUNET_CORE_notify_transmit_ready_cancel (struct GNUNET_CORE_TransmitHandle + *th); + + + + + +/** + * Iterate over all connected peers. Calls peer_cb with each + * connected peer, and then once with NULL to indicate that all peers + * have been handled. Normal users of the CORE API are not expected + * to use this function. It is different in that it truly lists + * all connections, not just those relevant to the application. This + * function is used by special applications for diagnostics. This + * function is NOT part of the 'versioned', 'official' API. + * + * FIXME: we should probably make it possible to 'cancel' the + * operation... + * + * @param cfg configuration handle + * @param peer_cb function to call with the peer information + * @param cb_cls closure for peer_cb + * @return GNUNET_OK on success, GNUNET_SYSERR on errors + */ +int +GNUNET_CORE_iterate_peers (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_CORE_ConnectEventHandler peer_cb, + void *cb_cls); + + +/** + * Check if the given peer is currently connected and return information + * about the session if so. This function is for special cirumstances + * (GNUNET_TESTING uses it), normal users of the CORE API are + * expected to track which peers are connected based on the + * connect/disconnect callbacks from GNUNET_CORE_connect. This + * function is NOT part of the 'versioned', 'official' API. + * + * FIXME: we should probably make it possible to 'cancel' the + * operation... + * + * @param cfg configuration to use + * @param peer the specific peer to check for + * @param peer_cb function to call with the peer information + * @param cb_cls closure for peer_cb + * @return GNUNET_OK if iterating, GNUNET_SYSERR on error + */ +int +GNUNET_CORE_is_peer_connected (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_PeerIdentity *peer, + GNUNET_CORE_ConnectEventHandler peer_cb, + void *cb_cls); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_CORE_SERVICE_H */ +#endif +/* end of gnunet_core_service.h */ diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h new file mode 100644 index 0000000..6e37266 --- /dev/null +++ b/src/include/gnunet_crypto_lib.h @@ -0,0 +1,882 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_crypto_lib.h + * @brief cryptographic primitives for GNUnet + * + * @author Christian Grothoff + * @author Krista Bennett + * @author Gerd Knorr + * @author Ioana Patrascu + * @author Tzvetan Horozov + */ + +#ifndef GNUNET_CRYPTO_LIB_H +#define GNUNET_CRYPTO_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_scheduler_lib.h" + +/** + * Desired quality level for cryptographic operations. + */ +enum GNUNET_CRYPTO_Quality +{ + /** + * No good quality of the operation is needed (i.e., + * random numbers can be pseudo-random). + */ + GNUNET_CRYPTO_QUALITY_WEAK, + + /** + * High-quality operations are desired. + */ + GNUNET_CRYPTO_QUALITY_STRONG, + + /** + * Randomness for IVs etc. is required. + */ + GNUNET_CRYPTO_QUALITY_NONCE +}; + + +/** + * @brief length of the sessionkey in bytes (256 BIT sessionkey) + */ +#define GNUNET_CRYPTO_AES_KEY_LENGTH (256/8) + + +/** + * @brief Length of RSA encrypted data (2048 bit) + * + * We currently do not handle encryption of data + * that can not be done in a single call to the + * RSA methods (read: large chunks of data). + * We should never need that, as we can use + * the GNUNET_CRYPTO_hash for larger pieces of data for signing, + * and for encryption, we only need to encode sessionkeys! + */ +#define GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH 256 + + +/** + * Length of an RSA KEY (d,e,len), 2048 bit (=256 octests) key d, 2 byte e + */ +#define GNUNET_CRYPTO_RSA_KEY_LENGTH 258 + + +/** + * Length of a hash value + */ +#define GNUNET_CRYPTO_HASH_LENGTH 512/8 + +/** + * The private information of an RSA key pair. + */ +struct GNUNET_CRYPTO_RsaPrivateKey; + + +/** + * @brief 0-terminated ASCII encoding of a GNUNET_HashCode. + */ +struct GNUNET_CRYPTO_HashAsciiEncoded +{ + unsigned char encoding[104]; +}; + + + +/** + * @brief an RSA signature + */ +struct GNUNET_CRYPTO_RsaSignature +{ + unsigned char sig[GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH]; +}; + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief header of what an RSA signature signs + * this must be followed by "size - 8" bytes of + * the actual signed data + */ +struct GNUNET_CRYPTO_RsaSignaturePurpose +{ + /** + * How many bytes does this signature sign? + * (including this purpose header); in network + * byte order (!). + */ + uint32_t size GNUNET_PACKED; + + /** + * What does this signature vouch for? This + * must contain a GNUNET_SIGNATURE_PURPOSE_XXX + * constant (from gnunet_signatures.h). In + * network byte order! + */ + uint32_t purpose GNUNET_PACKED; + +}; + + +/** + * @brief A public key. + */ +struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded +{ + /** + * In big-endian, must be GNUNET_CRYPTO_RSA_KEY_LENGTH+4 + */ + uint16_t len GNUNET_PACKED; + + /** + * Size of n in key; in big-endian! + */ + uint16_t sizen GNUNET_PACKED; + + /** + * The key itself, contains n followed by e. + */ + unsigned char key[GNUNET_CRYPTO_RSA_KEY_LENGTH]; + + /** + * Padding (must be 0) + */ + uint16_t padding GNUNET_PACKED; +}; + + +/** + * RSA Encrypted data. + */ +struct GNUNET_CRYPTO_RsaEncryptedData +{ + unsigned char encoding[GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH]; +}; + + +/** + * @brief type for session keys + */ +struct GNUNET_CRYPTO_AesSessionKey +{ + /** + * Actual key. + */ + unsigned char key[GNUNET_CRYPTO_AES_KEY_LENGTH]; + + /** + * checksum! + */ + uint32_t crc32 GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * @brief IV for sym cipher + * + * NOTE: must be smaller (!) in size than the + * GNUNET_HashCode. + */ +struct GNUNET_CRYPTO_AesInitializationVector +{ + unsigned char iv[GNUNET_CRYPTO_AES_KEY_LENGTH / 2]; +}; + + +/** + * @brief type for (message) authentication keys + */ +struct GNUNET_CRYPTO_AuthKey +{ + unsigned char key[GNUNET_CRYPTO_HASH_LENGTH]; +}; + + +/* **************** Functions and Macros ************* */ + +/** + * Seed a weak random generator. Only GNUNET_CRYPTO_QUALITY_WEAK-mode generator + * can be seeded. + * + * @param seed the seed to use + */ +void +GNUNET_CRYPTO_seed_weak_random (int32_t seed); + + +/** + * Perform an incremental step in a CRC16 (for TCP/IP) calculation. + * + * @param sum current sum, initially 0 + * @param buf buffer to calculate CRC over (must be 16-bit aligned) + * @param len number of bytes in hdr, must be multiple of 2 + * @return updated crc sum (must be subjected to GNUNET_CRYPTO_crc16_finish to get actual crc16) + */ +uint32_t +GNUNET_CRYPTO_crc16_step (uint32_t sum, const void *buf, size_t len); + + +/** + * Convert results from GNUNET_CRYPTO_crc16_step to final crc16. + * + * @param sum cummulative sum + * @return crc16 value + */ +uint16_t +GNUNET_CRYPTO_crc16_finish (uint32_t sum); + + +/** + * Calculate the checksum of a buffer in one step. + * + * @param buf buffer to calculate CRC over (must be 16-bit aligned) + * @param len number of bytes in hdr, must be multiple of 2 + * @return crc16 value + */ +uint16_t +GNUNET_CRYPTO_crc16_n (const void *buf, size_t len); + + +/** + * Compute the CRC32 checksum for the first len + * bytes of the buffer. + * + * @param buf the data over which we're taking the CRC + * @param len the length of the buffer in bytes + * @return the resulting CRC32 checksum + */ +int32_t +GNUNET_CRYPTO_crc32_n (const void *buf, size_t len); + + +/** + * Produce a random value. + * + * @param mode desired quality of the random number + * @param i the upper limit (exclusive) for the random number + * @return a random value in the interval [0,i) (exclusive). + */ +uint32_t +GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, uint32_t i); + + +/** + * Random on unsigned 64-bit values. + * + * @param mode desired quality of the random number + * @param max value returned will be in range [0,max) (exclusive) + * @return random 64-bit number + */ +uint64_t +GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max); + + +/** + * Get an array with a random permutation of the + * numbers 0...n-1. + * @param mode GNUNET_CRYPTO_QUALITY_STRONG if the strong (but expensive) PRNG should be used, GNUNET_CRYPTO_QUALITY_WEAK otherwise + * @param n the size of the array + * @return the permutation array (allocated from heap) + */ +unsigned int * +GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode, unsigned int n); + + +/** + * Create a new Session key. + * + * @param key key to initialize + */ +void +GNUNET_CRYPTO_aes_create_session_key (struct GNUNET_CRYPTO_AesSessionKey *key); + +/** + * Check that a new session key is well-formed. + * + * @param key key to check + * @return GNUNET_OK if the key is valid + */ +int +GNUNET_CRYPTO_aes_check_session_key (const struct GNUNET_CRYPTO_AesSessionKey + *key); + + +/** + * Encrypt a block with the public key of another + * host that uses the same cyper. + * + * @param block the block to encrypt + * @param len the size of the block + * @param sessionkey the key used to encrypt + * @param iv the initialization vector to use, use INITVALUE + * for streams. + * @return the size of the encrypted block, -1 for errors + */ +ssize_t +GNUNET_CRYPTO_aes_encrypt (const void *block, size_t len, + const struct GNUNET_CRYPTO_AesSessionKey *sessionkey, + const struct GNUNET_CRYPTO_AesInitializationVector + *iv, void *result); + + +/** + * Decrypt a given block with the sessionkey. + * + * @param block the data to decrypt, encoded as returned by encrypt + * @param size how big is the block? + * @param sessionkey the key used to decrypt + * @param iv the initialization vector to use + * @param result address to store the result at + * @return -1 on failure, size of decrypted block on success + */ +ssize_t +GNUNET_CRYPTO_aes_decrypt (const void *block, size_t size, + const struct GNUNET_CRYPTO_AesSessionKey *sessionkey, + const struct GNUNET_CRYPTO_AesInitializationVector + *iv, void *result); + + +/** + * @brief Derive an IV + * @param iv initialization vector + * @param skey session key + * @param salt salt for the derivation + * @param salt_len size of the salt + * @param ... pairs of void * & size_t for context chunks, terminated by NULL + */ +void +GNUNET_CRYPTO_aes_derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, + const struct GNUNET_CRYPTO_AesSessionKey *skey, + const void *salt, size_t salt_len, ...); + + +/** + * @brief Derive an IV + * @param iv initialization vector + * @param skey session key + * @param salt salt for the derivation + * @param salt_len size of the salt + * @param argp pairs of void * & size_t for context chunks, terminated by NULL + */ +void +GNUNET_CRYPTO_aes_derive_iv_v (struct GNUNET_CRYPTO_AesInitializationVector *iv, + const struct GNUNET_CRYPTO_AesSessionKey *skey, + const void *salt, size_t salt_len, va_list argp); + + +/** + * Convert hash to ASCII encoding. + * @param block the hash code + * @param result where to store the encoding (struct GNUNET_CRYPTO_HashAsciiEncoded can be + * safely cast to char*, a '\\0' termination is set). + */ +void +GNUNET_CRYPTO_hash_to_enc (const GNUNET_HashCode * block, + struct GNUNET_CRYPTO_HashAsciiEncoded *result); + + +/** + * Convert ASCII encoding back to GNUNET_CRYPTO_hash + * + * @param enc the encoding + * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) + * @param result where to store the GNUNET_CRYPTO_hash code + * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding + */ +int +GNUNET_CRYPTO_hash_from_string2 (const char *enc, size_t enclen, + GNUNET_HashCode * result); + + +/** + * Convert ASCII encoding back to GNUNET_CRYPTO_hash + * @param enc the encoding + * @param result where to store the GNUNET_CRYPTO_hash code + * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding + */ +#define GNUNET_CRYPTO_hash_from_string(enc, result) \ + GNUNET_CRYPTO_hash_from_string2 (enc, strlen(enc), result) + + +/** + * Compute the distance between 2 hashcodes. + * The computation must be fast, not involve + * a.a or a.e (they're used elsewhere), and + * be somewhat consistent. And of course, the + * result should be a positive number. + * + * @param a some hash code + * @param b some hash code + * @return number between 0 and UINT32_MAX + */ +uint32_t +GNUNET_CRYPTO_hash_distance_u32 (const GNUNET_HashCode * a, + const GNUNET_HashCode * b); + + +/** + * Compute hash of a given block. + * + * @param block the data to hash + * @param size size of the block + * @param ret pointer to where to write the hashcode + */ +void +GNUNET_CRYPTO_hash (const void *block, size_t size, GNUNET_HashCode * ret); + + +/** + * Calculate HMAC of a message (RFC 2104) + * + * @param key secret key + * @param plaintext input plaintext + * @param plaintext_len length of plaintext + * @param hmac where to store the hmac + */ +void +GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key, + const void *plaintext, size_t plaintext_len, + GNUNET_HashCode * hmac); + + +/** + * Function called once the hash computation over the + * specified file has completed. + * + * @param cls closure + * @param res resulting hash, NULL on error + */ +typedef void (*GNUNET_CRYPTO_HashCompletedCallback) (void *cls, + const GNUNET_HashCode * + res); + + +/** + * Handle to file hashing operation. + */ +struct GNUNET_CRYPTO_FileHashContext; + +/** + * Compute the hash of an entire file. + * + * @param priority scheduling priority to use + * @param filename name of file to hash + * @param blocksize number of bytes to process in one task + * @param callback function to call upon completion + * @param callback_cls closure for callback + * @return NULL on (immediate) errror + */ +struct GNUNET_CRYPTO_FileHashContext * +GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority, + const char *filename, size_t blocksize, + GNUNET_CRYPTO_HashCompletedCallback callback, + void *callback_cls); + + +/** + * Cancel a file hashing operation. + * + * @param fhc operation to cancel (callback must not yet have been invoked) + */ +void +GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc); + + +/** + * Create a random hash code. + * + * @param mode desired quality level + * @param result hash code that is randomized + */ +void +GNUNET_CRYPTO_hash_create_random (enum GNUNET_CRYPTO_Quality mode, + GNUNET_HashCode * result); + + +/** + * compute result(delta) = b - a + * + * @param a some hash code + * @param b some hash code + * @param result set to b - a + */ +void +GNUNET_CRYPTO_hash_difference (const GNUNET_HashCode * a, + const GNUNET_HashCode * b, + GNUNET_HashCode * result); + + +/** + * compute result(b) = a + delta + * + * @param a some hash code + * @param delta some hash code + * @param result set to a + delta + */ +void +GNUNET_CRYPTO_hash_sum (const GNUNET_HashCode * a, + const GNUNET_HashCode * delta, + GNUNET_HashCode * result); + + +/** + * compute result = a ^ b + * + * @param a some hash code + * @param b some hash code + * @param result set to a ^ b + */ +void +GNUNET_CRYPTO_hash_xor (const GNUNET_HashCode * a, const GNUNET_HashCode * b, + GNUNET_HashCode * result); + + +/** + * Convert a hashcode into a key. + * + * @param hc hash code that serves to generate the key + * @param skey set to a valid session key + * @param iv set to a valid initialization vector + */ +void +GNUNET_CRYPTO_hash_to_aes_key (const GNUNET_HashCode * hc, + struct GNUNET_CRYPTO_AesSessionKey *skey, + struct GNUNET_CRYPTO_AesInitializationVector + *iv); + + +/** + * Obtain a bit from a hashcode. + * + * @param code the GNUNET_CRYPTO_hash to index bit-wise + * @param bit index into the hashcode, [0...159] + * @return Bit \a bit from hashcode \a code, -1 for invalid index + */ +int +GNUNET_CRYPTO_hash_get_bit (const GNUNET_HashCode * code, unsigned int bit); + +/** + * Determine how many low order bits match in two + * GNUNET_HashCodes. i.e. - 010011 and 011111 share + * the first two lowest order bits, and therefore the + * return value is two (NOT XOR distance, nor how many + * bits match absolutely!). + * + * @param first the first hashcode + * @param second the hashcode to compare first to + * + * @return the number of bits that match + */ +unsigned int +GNUNET_CRYPTO_hash_matching_bits (const GNUNET_HashCode * first, + const GNUNET_HashCode * second); + + +/** + * Compare function for HashCodes, producing a total ordering + * of all hashcodes. + * + * @param h1 some hash code + * @param h2 some hash code + * @return 1 if h1 > h2, -1 if h1 < h2 and 0 if h1 == h2. + */ +int +GNUNET_CRYPTO_hash_cmp (const GNUNET_HashCode * h1, const GNUNET_HashCode * h2); + + +/** + * Find out which of the two GNUNET_CRYPTO_hash codes is closer to target + * in the XOR metric (Kademlia). + * + * @param h1 some hash code + * @param h2 some hash code + * @param target some hash code + * @return -1 if h1 is closer, 1 if h2 is closer and 0 if h1==h2. + */ +int +GNUNET_CRYPTO_hash_xorcmp (const GNUNET_HashCode * h1, + const GNUNET_HashCode * h2, + const GNUNET_HashCode * target); + + +/** + * @brief Derive an authentication key + * @param key authentication key + * @param rkey root key + * @param salt salt + * @param salt_len size of the salt + * @param argp pair of void * & size_t for context chunks, terminated by NULL + */ +void +GNUNET_CRYPTO_hmac_derive_key_v (struct GNUNET_CRYPTO_AuthKey *key, + const struct GNUNET_CRYPTO_AesSessionKey *rkey, + const void *salt, size_t salt_len, + va_list argp); + + +/** + * @brief Derive an authentication key + * @param key authentication key + * @param rkey root key + * @param salt salt + * @param salt_len size of the salt + * @param ... pair of void * & size_t for context chunks, terminated by NULL + */ +void +GNUNET_CRYPTO_hmac_derive_key (struct GNUNET_CRYPTO_AuthKey *key, + const struct GNUNET_CRYPTO_AesSessionKey *rkey, + const void *salt, size_t salt_len, ...); + +/** + * @brief Derive key + * @param result buffer for the derived key, allocated by caller + * @param out_len desired length of the derived key + * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... + * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... + * @param xts salt + * @param xts_len length of xts + * @param skm source key material + * @param skm_len length of skm + * @return GNUNET_YES on success + */ +int +GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo, + const void *xts, size_t xts_len, const void *skm, + size_t skm_len, ...); + + +/** + * @brief Derive key + * @param result buffer for the derived key, allocated by caller + * @param out_len desired length of the derived key + * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... + * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... + * @param xts salt + * @param xts_len length of xts + * @param skm source key material + * @param skm_len length of skm + * @param argp va_list of void * & size_t pairs for context chunks + * @return GNUNET_YES on success + */ +int +GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo, + const void *xts, size_t xts_len, const void *skm, + size_t skm_len, va_list argp); + + +/** + * @brief Derive key + * @param result buffer for the derived key, allocated by caller + * @param out_len desired length of the derived key + * @param xts salt + * @param xts_len length of xts + * @param skm source key material + * @param skm_len length of skm + * @param argp va_list of void * & size_t pairs for context chunks + * @return GNUNET_YES on success + */ +int +GNUNET_CRYPTO_kdf_v (void *result, size_t out_len, const void *xts, + size_t xts_len, const void *skm, size_t skm_len, + va_list argp); + + +/** + * @brief Derive key + * @param result buffer for the derived key, allocated by caller + * @param out_len desired length of the derived key + * @param xts salt + * @param xts_len length of xts + * @param skm source key material + * @param skm_len length of skm + * @param ... void * & size_t pairs for context chunks + * @return GNUNET_YES on success + */ +int +GNUNET_CRYPTO_kdf (void *result, size_t out_len, const void *xts, + size_t xts_len, const void *skm, size_t skm_len, ...); + + +/** + * Create a new private key. Caller must free return value. + * + * @return fresh private key + */ +struct GNUNET_CRYPTO_RsaPrivateKey * +GNUNET_CRYPTO_rsa_key_create (void); + +/** + * Decode the private key from the data-format back + * to the "normal", internal format. + * + * @param buf the buffer where the private key data is stored + * @param len the length of the data in 'buffer' + */ +struct GNUNET_CRYPTO_RsaPrivateKey * +GNUNET_CRYPTO_rsa_decode_key (const char *buf, uint16_t len); + +/** + * Create a new private key by reading it from a file. If the + * files does not exist, create a new key and write it to the + * file. Caller must free return value. Note that this function + * can not guarantee that another process might not be trying + * the same operation on the same file at the same time. + * If the contents of the file + * are invalid the old file is deleted and a fresh key is + * created. + * + * @param filename name of file to use for storage + * @return new private key, NULL on error (for example, + * permission denied) + */ +struct GNUNET_CRYPTO_RsaPrivateKey * +GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename); + + +/** + * Deterministically (!) create a private key using only the + * given HashCode as input to the PRNG. + * + * @param hc "random" input to PRNG + * @return some private key purely dependent on input + */ +struct GNUNET_CRYPTO_RsaPrivateKey * +GNUNET_CRYPTO_rsa_key_create_from_hash (const GNUNET_HashCode * hc); + + +/** + * Free memory occupied by the private key. + * @param hostkey pointer to the memory to free + */ +void +GNUNET_CRYPTO_rsa_key_free (struct GNUNET_CRYPTO_RsaPrivateKey *hostkey); + + +/** + * Extract the public key of the host. + * + * @param priv the private key + * @param pub where to write the public key + */ +void +GNUNET_CRYPTO_rsa_key_get_public (const struct GNUNET_CRYPTO_RsaPrivateKey + *priv, + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *pub); + + +/** + * Encrypt a block with the public key of another host that uses the + * same cyper. + * + * @param block the block to encrypt + * @param size the size of block + * @param publicKey the encoded public key used to encrypt + * @param target where to store the encrypted block + * @return GNUNET_SYSERR on error, GNUNET_OK if ok + */ +int +GNUNET_CRYPTO_rsa_encrypt (const void *block, size_t size, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *publicKey, + struct GNUNET_CRYPTO_RsaEncryptedData *target); + + +/** + * Decrypt a given block with the hostkey. + * + * @param key the key to use + * @param block the data to decrypt, encoded as returned by encrypt, not consumed + * @param result pointer to a location where the result can be stored + * @param max how many bytes of a result are expected? Must be exact. + * @return the size of the decrypted block (that is, size) or -1 on error + */ +ssize_t +GNUNET_CRYPTO_rsa_decrypt (const struct GNUNET_CRYPTO_RsaPrivateKey *key, + const struct GNUNET_CRYPTO_RsaEncryptedData *block, + void *result, size_t max); + + +/** + * Sign a given block. + * + * @param key private key to use for the signing + * @param purpose what to sign (size, purpose) + * @param sig where to write the signature + * @return GNUNET_SYSERR on error, GNUNET_OK on success + */ +int +GNUNET_CRYPTO_rsa_sign (const struct GNUNET_CRYPTO_RsaPrivateKey *key, + const struct GNUNET_CRYPTO_RsaSignaturePurpose *purpose, + struct GNUNET_CRYPTO_RsaSignature *sig); + + +/** + * Verify signature. Note that the caller MUST have already + * checked that "validate->size" bytes are actually available. + * + * @param purpose what is the purpose that validate should have? + * @param validate block to validate (size, purpose, data) + * @param sig signature that is being validated + * @param publicKey public key of the signer + * @return GNUNET_OK if ok, GNUNET_SYSERR if invalid + */ +int +GNUNET_CRYPTO_rsa_verify (uint32_t purpose, + const struct GNUNET_CRYPTO_RsaSignaturePurpose + *validate, + const struct GNUNET_CRYPTO_RsaSignature *sig, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *publicKey); + + + +/** + * This function should only be called in testcases + * where strong entropy gathering is not desired + * (for example, for hostkey generation). + */ +void +GNUNET_CRYPTO_random_disable_entropy_gathering (void); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_CRYPTO_LIB_H */ +#endif +/* end of gnunet_crypto_lib.h */ diff --git a/src/include/gnunet_datacache_lib.h b/src/include/gnunet_datacache_lib.h new file mode 100644 index 0000000..84cb4d6 --- /dev/null +++ b/src/include/gnunet_datacache_lib.h @@ -0,0 +1,134 @@ +/* + This file is part of GNUnet + (C) 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_datacache_lib.h + * @brief datacache is a simple, transient hash table + * of bounded size with content expiration. + * In contrast to the sqstore there is + * no prioritization, deletion or iteration. + * All of the data is discarded when the peer shuts down! + * @author Christian Grothoff + */ + +#ifndef GNUNET_DATACACHE_LIB_H +#define GNUNET_DATACACHE_LIB_H + +#include "gnunet_util_lib.h" +#include "gnunet_block_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Handle to the cache. + */ +struct GNUNET_DATACACHE_Handle; + + +/** + * Create a data cache. + * + * @param cfg configuration to use + * @param section section in the configuration that contains our options + * @return handle to use to access the service + */ +struct GNUNET_DATACACHE_Handle * +GNUNET_DATACACHE_create (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section); + + +/** + * Destroy a data cache (and free associated resources). + * + * @param h handle to the datastore + */ +void +GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h); + + +/** + * An iterator over a set of items stored in the datacache. + * + * @param cls closure + * @param exp when will the content expire? + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort + */ +typedef int (*GNUNET_DATACACHE_Iterator) (void *cls, + struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + size_t size, const char *data, + enum GNUNET_BLOCK_Type type); + + +/** + * Store an item in the datacache. + * + * @param h handle to the datacache + * @param key key to store data under + * @param size number of bytes in data + * @param data data to store + * @param type type of the value + * @param discard_time when to discard the value in any case + * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.) + */ +int +GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, + const GNUNET_HashCode * key, size_t size, + const char *data, enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute discard_time); + + +/** + * Iterate over the results for a particular key + * in the datacache. + * + * @param h handle to the datacache + * @param key what to look up + * @param type entries of which type are relevant? + * @param iter maybe NULL (to just count) + * @param iter_cls closure for iter + * @return the number of results found + */ +unsigned int +GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h, + const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, + GNUNET_DATACACHE_Iterator iter, void *iter_cls); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* end of gnunet_datacache_lib.h */ +#endif diff --git a/src/include/gnunet_datacache_plugin.h b/src/include/gnunet_datacache_plugin.h new file mode 100644 index 0000000..fbfcdf1 --- /dev/null +++ b/src/include/gnunet_datacache_plugin.h @@ -0,0 +1,154 @@ +/* + This file is part of GNUnet + (C) 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_datacache_plugin.h + * @brief API for database backends for the datacache + * @author Christian Grothoff + */ +#ifndef PLUGIN_DATACACHE_H +#define PLUGIN_DATACACHE_H + +#include "gnunet_datacache_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Function called by plugins to notify the datacache + * about content deletions. + * + * @param cls closure + * @param key key of the content that was deleted + * @param size number of bytes that were made available + */ +typedef void (*GNUNET_DATACACHE_DeleteNotifyCallback) (void *cls, + const GNUNET_HashCode * + key, size_t size); + + +/** + * The datastore service will pass a pointer to a struct + * of this type as the first and only argument to the + * entry point of each datastore plugin. + */ +struct GNUNET_DATACACHE_PluginEnvironment +{ + + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Configuration section to use. + */ + const char *section; + + /** + * Closure to use for callbacks. + */ + void *cls; + + /** + * Function to call whenever the plugin needs to + * discard content that it was asked to store. + */ + GNUNET_DATACACHE_DeleteNotifyCallback delete_notify; + + /** + * How much space are we allowed to use? + */ + unsigned long long quota; + +}; + + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct GNUNET_DATACACHE_PluginFunctions +{ + + /** + * Closure to pass to all plugin functions. + */ + void *cls; + + /** + * Store an item in the datastore. + * + * @param cls closure (internal context for the plugin) + * @param size number of bytes in data + * @param data data to store + * @param type type of the value + * @param discard_time when to discard the value in any case + * @return 0 on error, number of bytes used otherwise + */ + size_t (*put) (void *cls, const GNUNET_HashCode * key, size_t size, + const char *data, enum GNUNET_BLOCK_Type type, + struct GNUNET_TIME_Absolute discard_time); + + + /** + * Iterate over the results for a particular key + * in the datastore. + * + * @param cls closure (internal context for the plugin) + * @param key + * @param type entries of which type are relevant? + * @param iter maybe NULL (to just count) + * @param iter_cls closure for iter + * @return the number of results found + */ + unsigned int (*get) (void *cls, const GNUNET_HashCode * key, + enum GNUNET_BLOCK_Type type, + GNUNET_DATACACHE_Iterator iter, void *iter_cls); + + + /** + * Delete the entry with the lowest expiration value + * from the datacache right now. + * + * @param cls closure (internal context for the plugin) + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ + int (*del) (void *cls); + + +}; + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* end of gnunet_datacache_plugin.h */ +#endif diff --git a/src/include/gnunet_datastore_plugin.h b/src/include/gnunet_datastore_plugin.h new file mode 100644 index 0000000..bbf0ce2 --- /dev/null +++ b/src/include/gnunet_datastore_plugin.h @@ -0,0 +1,333 @@ +/* + This file is part of GNUnet + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_datastore_plugin.h + * @brief API for the database backend plugins. + * @author Christian Grothoff + */ +#ifndef PLUGIN_DATASTORE_H +#define PLUGIN_DATASTORE_H + +#include "gnunet_block_lib.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_datastore_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_scheduler_lib.h" + + +/** + * How many bytes of overhead will we assume per entry + * in any DB (for reservations)? + */ +#define GNUNET_DATASTORE_ENTRY_OVERHEAD 256 + + +/** + * Function invoked to notify service of disk utilization + * changes. + * + * @param cls closure + * @param delta change in disk utilization, + * 0 for "reset to empty" + */ +typedef void (*DiskUtilizationChange) (void *cls, int delta); + + +/** + * The datastore service will pass a pointer to a struct + * of this type as the first and only argument to the + * entry point of each datastore plugin. + */ +struct GNUNET_DATASTORE_PluginEnvironment +{ + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Function to call on disk utilization change. + */ + DiskUtilizationChange duc; + + /** + * Closure. + */ + void *cls; + +}; + + +/** + * An processor over a set of items stored in the datastore. + * + * @param cls closure + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum + * + * @return GNUNET_OK to keep the item + * GNUNET_NO to delete the item + */ +typedef int (*PluginDatumProcessor) (void *cls, const GNUNET_HashCode * key, + uint32_t size, const void *data, + enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + struct GNUNET_TIME_Absolute expiration, + uint64_t uid); + +/** + * Get an estimate of how much space the database is + * currently using. + * + * @param cls closure + * @return number of bytes used on disk + */ +typedef unsigned long long (*PluginEstimateSize) (void *cls); + + +/** + * Store an item in the datastore. If the item is already present, + * the priorities and replication levels are summed up and the higher + * expiration time and lower anonymity level is used. + * + * @param cls closure + * @param key key for the item + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param replication replication-level for the content + * @param expiration expiration time for the content + * @param msg set to an error message (on failure) + * @return GNUNET_OK on success, + * GNUNET_SYSERR on failure + */ +typedef int (*PluginPut) (void *cls, const GNUNET_HashCode * key, uint32_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + uint32_t replication, + struct GNUNET_TIME_Absolute expiration, char **msg); + + +/** + * An processor over a set of keys stored in the datastore. + * + * @param cls closure + * @param key key in the data store + * @param count how many values are stored under this key in the datastore + */ +typedef void (*PluginKeyProcessor) (void *cls, + const GNUNET_HashCode *key, + unsigned int count); + + +/** + * Get all of the keys in the datastore. + * + * @param cls closure + * @param proc function to call on each key + * @param proc_cls closure for proc + */ +typedef void (*PluginGetKeys) (void *cls, + PluginKeyProcessor proc, void *proc_cls); + + +/** + * Get one of the results for a particular key in the datastore. + * + * @param cls closure + * @param offset offset of the result (modulo num-results); + * specific ordering does not matter for the offset + * @param key key to match, never NULL + * @param vhash hash of the value, maybe NULL (to + * match all values that have the right key). + * Note that for DBlocks there is no difference + * betwen key and vhash, but for other blocks + * there may be! + * @param type entries of which type are relevant? + * Use 0 for any type. + * @param min find the smallest key that is larger than the given min, + * NULL for no minimum (return smallest key) + * @param proc function to call on the matching value; + * proc should be called with NULL if there is no result + * @param proc_cls closure for proc + */ +typedef void (*PluginGetKey) (void *cls, uint64_t offset, + const GNUNET_HashCode * key, + const GNUNET_HashCode * vhash, + enum GNUNET_BLOCK_Type type, + PluginDatumProcessor proc, void *proc_cls); + + +/** + * Get a random item (additional constraints may apply depending on + * the specific implementation). Calls 'proc' with all values ZERO or + * NULL if no item applies, otherwise 'proc' is called once and only + * once with an item. + * + * @param cls closure + * @param proc function to call the value (once only). + * @param proc_cls closure for proc + */ +typedef void (*PluginGetRandom) (void *cls, PluginDatumProcessor proc, + void *proc_cls); + + + + +/** + * Update the priority for a particular key in the datastore. If + * the expiration time in value is different than the time found in + * the datastore, the higher value should be kept. For the + * anonymity level, the lower value is to be used. The specified + * priority should be added to the existing priority, ignoring the + * priority in value. + * + * Note that it is possible for multiple values to match this put. + * In that case, all of the respective values are updated. + * + * @param cls closure + * @param uid unique identifier of the datum + * @param delta by how much should the priority + * change? If priority + delta < 0 the + * priority should be set to 0 (never go + * negative). + * @param expire new expiration time should be the + * MAX of any existing expiration time and + * this value + * @param msg set to an error message (on error) + * @return GNUNET_OK on success + */ +typedef int (*PluginUpdate) (void *cls, uint64_t uid, int delta, + struct GNUNET_TIME_Absolute expire, char **msg); + + +/** + * Select a single item from the datastore at the specified offset + * (among those applicable). + * + * @param cls closure + * @param offset offset of the result (modulo num-results); + * specific ordering does not matter for the offset + * @param type entries of which type should be considered? + * Must not be zero (ANY). + * @param proc function to call on the matching value + * @param proc_cls closure for proc + */ +typedef void (*PluginGetType) (void *cls, uint64_t offset, + enum GNUNET_BLOCK_Type type, + PluginDatumProcessor proc, void *proc_cls); + + +/** + * Drop database. + * + * @param cls closure + */ +typedef void (*PluginDrop) (void *cls); + + + +/** + * Each plugin is required to return a pointer to a struct of this + * type as the return value from its entry point. + */ +struct GNUNET_DATASTORE_PluginFunctions +{ + + /** + * Closure to use for all of the following callbacks + * (except "next_request"). + */ + void *cls; + + /** + * Calculate the current on-disk size of the SQ store. Estimates + * are fine, if that's the only thing available. + */ + PluginEstimateSize estimate_size; + + /** + * Function to store an item in the datastore. + */ + PluginPut put; + + /** + * Update the priority for a particular key in the datastore. If + * the expiration time in value is different than the time found in + * the datastore, the higher value should be kept. For the + * anonymity level, the lower value is to be used. The specified + * priority should be added to the existing priority, ignoring the + * priority in value. + */ + PluginUpdate update; + + /** + * Get a particular datum matching a given hash from the datastore. + */ + PluginGetKey get_key; + + /** + * Get datum (of the specified type) with anonymity level zero. + * This function is allowed to ignore the 'offset' argument + * and instead return a random result (with zero anonymity of + * the correct type) if implementing an offset is expensive. + */ + PluginGetType get_zero_anonymity; + + /** + * Function to get a random item with high replication score from + * the database, lowering the item's replication score. Returns a + * single random item from those with the highest replication + * counters. The item's replication counter is decremented by one + * IF it was positive before. + */ + PluginGetRandom get_replication; + + /** + * Function to get a random expired item or, if none are expired, + * either the oldest entry or one with a low priority (depending + * on what was efficiently implementable). + */ + PluginGetRandom get_expiration; + + /** + * Delete the database. The next operation is + * guaranteed to be unloading of the module. + */ + PluginDrop drop; + + /** + * Iterate over all keys in the database. + */ + PluginGetKeys get_keys; + +}; + + +#endif diff --git a/src/include/gnunet_datastore_service.h b/src/include/gnunet_datastore_service.h new file mode 100644 index 0000000..b4af0e6 --- /dev/null +++ b/src/include/gnunet_datastore_service.h @@ -0,0 +1,393 @@ +/* + This file is part of GNUnet + (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_datastore_service.h + * @brief API that can be used manage the + * datastore for files stored on a GNUnet node; + * note that the datastore is NOT responsible for + * on-demand encoding, that is achieved using + * a special kind of entry. + * @author Christian Grothoff + */ + +#ifndef GNUNET_DATASTORE_SERVICE_H +#define GNUNET_DATASTORE_SERVICE_H + +#include "gnunet_util_lib.h" +#include "gnunet_block_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * Entry in the queue. + */ +struct GNUNET_DATASTORE_QueueEntry; + +/** + * Handle to the datastore service. + */ +struct GNUNET_DATASTORE_Handle; + +/** + * Maximum size of a value that can be stored in the datastore. + */ +#define GNUNET_DATASTORE_MAX_VALUE_SIZE 65536 + +/** + * Connect to the datastore service. + * + * @param cfg configuration to use + * @return handle to use to access the service + */ +struct GNUNET_DATASTORE_Handle * +GNUNET_DATASTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Disconnect from the datastore service (and free + * associated resources). + * + * @param h handle to the datastore + * @param drop set to GNUNET_YES to delete all data in datastore (!) + */ +void +GNUNET_DATASTORE_disconnect (struct GNUNET_DATASTORE_Handle *h, int drop); + + +/** + * Continuation called to notify client about result of the + * operation. + * + * @param cls closure + * @param success GNUNET_SYSERR on failure (including timeout/queue drop) + * GNUNET_NO if content was already there + * GNUNET_YES (or other positive value) on success + * @param min_expiration minimum expiration time required for 0-priority content to be stored + * by the datacache at this time, zero for unknown, forever if we have no + * space for 0-priority content + * @param msg NULL on success, otherwise an error message + */ +typedef void (*GNUNET_DATASTORE_ContinuationWithStatus) (void *cls, + int32_t success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg); + + +/** + * Reserve space in the datastore. This function should be used + * to avoid "out of space" failures during a longer sequence of "put" + * operations (for example, when a file is being inserted). + * + * @param h handle to the datastore + * @param amount how much space (in bytes) should be reserved (for content only) + * @param entries how many entries will be created (to calculate per-entry overhead) + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response (or before dying in queue) + * @param cont continuation to call when done; "success" will be set to + * a positive reservation value if space could be reserved. + * @param cont_cls closure for cont + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel; note that even if NULL is returned, the callback will be invoked + * (or rather, will already have been invoked) + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_reserve (struct GNUNET_DATASTORE_Handle *h, uint64_t amount, + uint32_t entries, unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_ContinuationWithStatus cont, + void *cont_cls); + + +/** + * Store an item in the datastore. If the item is already present, + * the priorities and replication values are summed up and the higher + * expiration time and lower anonymity level is used. + * + * @param h handle to the datastore + * @param rid reservation ID to use (from "reserve"); use 0 if no + * prior reservation was made + * @param key key for the value + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param replication how often should the content be replicated to other peers? + * @param expiration expiration time for the content + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout timeout for the operation + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel; note that even if NULL is returned, the callback will be invoked + * (or rather, will already have been invoked) + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h, uint32_t rid, + const GNUNET_HashCode * key, size_t size, + const void *data, enum GNUNET_BLOCK_Type type, + uint32_t priority, uint32_t anonymity, + uint32_t replication, + struct GNUNET_TIME_Absolute expiration, + unsigned int queue_priority, unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_ContinuationWithStatus cont, + void *cont_cls); + + +/** + * Signal that all of the data for which a reservation was made has + * been stored and that whatever excess space might have been reserved + * can now be released. + * + * @param h handle to the datastore + * @param rid reservation ID (value of "success" in original continuation + * from the "reserve" function). + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel; note that even if NULL is returned, the callback will be invoked + * (or rather, will already have been invoked) + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_release_reserve (struct GNUNET_DATASTORE_Handle *h, + uint32_t rid, unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_ContinuationWithStatus cont, + void *cont_cls); + + +/** + * Update a value in the datastore. + * + * @param h handle to the datastore + * @param uid identifier for the value + * @param priority how much to increase the priority of the value + * @param expiration new expiration value should be MAX of existing and this argument + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel; note that even if NULL is returned, the callback will be invoked + * (or rather, will already have been invoked) + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h, uint64_t uid, + uint32_t priority, + struct GNUNET_TIME_Absolute expiration, + unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_ContinuationWithStatus cont, + void *cont_cls); + + +/** + * Explicitly remove some content from the database. + * The "cont"inuation will be called with status + * "GNUNET_OK" if content was removed, "GNUNET_NO" + * if no matching entry was found and "GNUNET_SYSERR" + * on all other types of errors. + * + * @param h handle to the datastore + * @param key key for the value + * @param size number of bytes in data + * @param data content stored + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel; note that even if NULL is returned, the callback will be invoked + * (or rather, will already have been invoked) + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h, + const GNUNET_HashCode * key, size_t size, + const void *data, unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_ContinuationWithStatus cont, + void *cont_cls); + + +/** + * Process a datum that was stored in the datastore. + * + * @param cls closure + * @param key key for the content + * @param size number of bytes in data + * @param data content stored + * @param type type of the content + * @param priority priority of the content + * @param anonymity anonymity-level for the content + * @param expiration expiration time for the content + * @param uid unique identifier for the datum; + * maybe 0 if no unique identifier is available + */ +typedef void (*GNUNET_DATASTORE_DatumProcessor) (void *cls, + const GNUNET_HashCode * key, + size_t size, const void *data, + enum GNUNET_BLOCK_Type type, + uint32_t priority, + uint32_t anonymity, + struct GNUNET_TIME_Absolute + expiration, uint64_t uid); + + +/** + * Get a result for a particular key from the datastore. The processor + * will only be called once. + * + * @param h handle to the datastore + * @param offset offset of the result (modulo num-results); set to + * a random 64-bit value initially; then increment by + * one each time; detect that all results have been found by uid + * being again the first uid ever returned. + * @param key maybe NULL (to match all entries) + * @param type desired type, 0 for any + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param proc function to call on each matching value; + * will be called once with a NULL value at the end + * @param proc_cls closure for proc + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h, uint64_t offset, + const GNUNET_HashCode * key, + enum GNUNET_BLOCK_Type type, + unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_DatumProcessor proc, void *proc_cls); + + +/** + * Get a single zero-anonymity value from the datastore. + * Note that some implementations can ignore the 'offset' and + * instead return a random zero-anonymity value. In that case, + * detecting the wrap-around based on a repeating UID is at best + * probabilistic. + * + * @param h handle to the datastore + * @param offset offset of the result (modulo num-results); set to + * a random 64-bit value initially; then increment by + * one each time; detect that all results have been found by uid + * being again the first uid ever returned. + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param type allowed type for the operation (never zero) + * @param proc function to call on a random value; it + * will be called once with a value (if available) + * or with NULL if none value exists. + * @param proc_cls closure for proc + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h, + uint64_t offset, + unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + enum GNUNET_BLOCK_Type type, + GNUNET_DATASTORE_DatumProcessor proc, + void *proc_cls); + + +/** + * Get a random value from the datastore for content replication. + * Returns a single, random value among those with the highest + * replication score, lowering positive replication scores by one for + * the chosen value (if only content with a replication score exists, + * a random value is returned and replication scores are not changed). + * + * @param h handle to the datastore + * @param queue_priority ranking of this request in the priority queue + * @param max_queue_size at what queue size should this request be dropped + * (if other requests of higher priority are in the queue) + * @param timeout how long to wait at most for a response + * @param proc function to call on a random value; it + * will be called once with a value (if available) + * and always once with a value of NULL. + * @param proc_cls closure for proc + * @return NULL if the entry was not queued, otherwise a handle that can be used to + * cancel + */ +struct GNUNET_DATASTORE_QueueEntry * +GNUNET_DATASTORE_get_for_replication (struct GNUNET_DATASTORE_Handle *h, + unsigned int queue_priority, + unsigned int max_queue_size, + struct GNUNET_TIME_Relative timeout, + GNUNET_DATASTORE_DatumProcessor proc, + void *proc_cls); + + + +/** + * Cancel a datastore operation. The final callback from the + * operation must not have been done yet. + * + * @param qe operation to cancel + */ +void +GNUNET_DATASTORE_cancel (struct GNUNET_DATASTORE_QueueEntry *qe); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* end of gnunet_datastore_service.h */ +#endif diff --git a/src/include/gnunet_dht_service.h b/src/include/gnunet_dht_service.h new file mode 100644 index 0000000..e533ef2 --- /dev/null +++ b/src/include/gnunet_dht_service.h @@ -0,0 +1,290 @@ +/* + This file is part of GNUnet + (C) 2004, 2005, 2006, 2008, 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_dht_service.h + * @brief API to the DHT service + * @author Christian Grothoff + */ + +#ifndef GNUNET_DHT_SERVICE_H +#define GNUNET_DHT_SERVICE_H + +#include "gnunet_util_lib.h" +#include "gnunet_block_lib.h" +#include "gnunet_hello_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Default republication frequency for stored data in the DHT. + */ +#define GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 60) + + + +/** + * Connection to the DHT service. + */ +struct GNUNET_DHT_Handle; + +/** + * Handle to control a get operation. + */ +struct GNUNET_DHT_GetHandle; + +/** + * Handle to control a find peer operation. + */ +struct GNUNET_DHT_FindPeerHandle; + + +/** + * Options for routing. + */ +enum GNUNET_DHT_RouteOption +{ + /** + * Default. Do nothing special. + */ + GNUNET_DHT_RO_NONE = 0, + + /** + * Each peer along the way should look at 'enc' (otherwise + * only the k-peers closest to the key should look at it). + */ + GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE = 1, + + /** + * We should keep track of the route that the message + * took in the P2P network. + */ + GNUNET_DHT_RO_RECORD_ROUTE = 2, + + /** + * This is a 'FIND-PEER' request, so approximate results are fine. + */ + GNUNET_DHT_RO_FIND_PEER = 4, + + /** + * Possible message option for query key randomization. + */ + GNUNET_DHT_RO_BART = 8 +}; + + +/** + * Initialize the connection with the DHT service. + * + * @param cfg configuration to use + * @param ht_len size of the internal hash table to use for + * processing multiple GET/FIND requests in parallel + * @return NULL on error + */ +struct GNUNET_DHT_Handle * +GNUNET_DHT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int ht_len); + + +/** + * Shutdown connection with the DHT service. + * + * @param handle connection to shut down + */ +void +GNUNET_DHT_disconnect (struct GNUNET_DHT_Handle *handle); + + +/* *************** Standard API: get and put ******************* */ + +/** + * Perform a PUT operation storing data in the DHT. + * + * @param handle handle to DHT service + * @param key the key to store under + * @param desired_replication_level estimate of how many + * nearest peers this request should reach + * @param options routing options for this message + * @param type type of the value + * @param size number of bytes in data; must be less than 64k + * @param data the data to store + * @param exp desired expiration time for the value + * @param timeout how long to wait for transmission of this request + * @param cont continuation to call when done (transmitting request to service) + * @param cont_cls closure for cont + */ +void +GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle, const GNUNET_HashCode * key, + uint32_t desired_replication_level, + enum GNUNET_DHT_RouteOption options, + enum GNUNET_BLOCK_Type type, size_t size, const char *data, + struct GNUNET_TIME_Absolute exp, + struct GNUNET_TIME_Relative timeout, GNUNET_SCHEDULER_Task cont, + void *cont_cls); + + +/** + * Iterator called on each result obtained for a DHT + * operation that expects a reply + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param get_path peers on reply path (or NULL if not recorded) + * @param get_path_length number of entries in get_path + * @param put_path peers on the PUT path (or NULL if not recorded) + * @param put_path_length number of entries in get_path + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +typedef void (*GNUNET_DHT_GetIterator) (void *cls, + struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity * + get_path, unsigned int get_path_length, + const struct GNUNET_PeerIdentity * + put_path, unsigned int put_path_length, + enum GNUNET_BLOCK_Type type, + size_t size, const void *data); + + + +/** + * Perform an asynchronous GET operation on the DHT identified. See + * also "GNUNET_BLOCK_evaluate". + * + * @param handle handle to the DHT service + * @param timeout how long to wait for transmission of this request to the service + * @param type expected type of the response object + * @param key the key to look up + * @param desired_replication_level estimate of how many + nearest peers this request should reach + * @param options routing options for this message + * @param xquery extended query data (can be NULL, depending on type) + * @param xquery_size number of bytes in xquery + * @param iter function to call on each result + * @param iter_cls closure for iter + * + * @return handle to stop the async get + */ +struct GNUNET_DHT_GetHandle * +GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle, + struct GNUNET_TIME_Relative timeout, + enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * key, + uint32_t desired_replication_level, + enum GNUNET_DHT_RouteOption options, const void *xquery, + size_t xquery_size, GNUNET_DHT_GetIterator iter, + void *iter_cls); + + +/** + * Stop async DHT-get. Frees associated resources. + * + * @param get_handle GET operation to stop. + * + * On return get_handle will no longer be valid, caller + * must not use again!!! + */ +void +GNUNET_DHT_get_stop (struct GNUNET_DHT_GetHandle *get_handle); + + +/* *************** Extended API: monitor ******************* */ + +struct GNUNET_DHT_MonitorHandle; + +/** + * Callback called on each request going through the DHT. + * + * @param cls Closure. + * @param mtype Type of the DHT message monitored. + * @param exp When will this value expire. + * @param key Key of the result/request. + * @param get_path Peers on reply path (or NULL if not recorded). + * @param get_path_length number of entries in get_path. + * @param put_path peers on the PUT path (or NULL if not recorded). + * @param put_path_length number of entries in get_path. + * @param desired_replication_level Desired replication level. + * @param type Type of the result/request. + * @param data Pointer to the result data. + * @param size Number of bytes in data. + */ +typedef void (*GNUNET_DHT_MonitorCB) (void *cls, + uint16_t mtype, + struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity * + get_path, unsigned int get_path_length, + const struct GNUNET_PeerIdentity * + put_path, unsigned int put_path_length, + uint32_t desired_replication_level, + enum GNUNET_DHT_RouteOption options, + enum GNUNET_BLOCK_Type type, + const void *data, + size_t size); + +/** + * Start monitoring the local DHT service. + * + * @param handle Handle to the DHT service. + * @param type Type of blocks that are of interest. + * @param key Key of data of interest, NULL for all. + * @param cb Callback to process all monitored data. + * @param cb_cls Closure for cb. + * + * @return Handle to stop monitoring. + */ +struct GNUNET_DHT_MonitorHandle * +GNUNET_DHT_monitor_start (struct GNUNET_DHT_Handle *handle, + enum GNUNET_BLOCK_Type type, + const GNUNET_HashCode *key, + GNUNET_DHT_MonitorCB cb, + void *cb_cls); + + +/** + * Stop monitoring. + * + * @param handle The handle to the monitor request returned by monitor_start. + * + * On return handle will no longer be valid, caller must not use again!!! + */ +void +GNUNET_DHT_monitor_stop (struct GNUNET_DHT_MonitorHandle *handle); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +#endif +/* gnunet_dht_service.h */ diff --git a/src/include/gnunet_directories.h.in b/src/include/gnunet_directories.h.in new file mode 100644 index 0000000..3f6898a --- /dev/null +++ b/src/include/gnunet_directories.h.in @@ -0,0 +1,33 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_directories.h + * @brief directories and files in GNUnet (default locations) + * + * @author Christian Grothoff + */ + +#ifndef GNUNET_DIRECTORIES +#define GNUNET_DIRECTORIES + +#define GNUNET_DEFAULT_USER_CONFIG_FILE "@GN_USER_HOME_DIR@/gnunet.conf" + +#endif diff --git a/src/include/gnunet_disk_lib.h b/src/include/gnunet_disk_lib.h new file mode 100644 index 0000000..18f5535 --- /dev/null +++ b/src/include/gnunet_disk_lib.h @@ -0,0 +1,768 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_disk_lib.h + * @brief disk IO apis + */ +#ifndef GNUNET_DISK_LIB_H +#define GNUNET_DISK_LIB_H + +#if WINDOWS +#define OFF_T uint64_t +#else +#define OFF_T off_t +#endif + +/** + * Handle used to manage a pipe. + */ +struct GNUNET_DISK_PipeHandle; + + +enum GNUNET_FILE_Type +{ + GNUNET_DISK_FILE, GNUNET_PIPE +}; + +/** + * Handle used to access files (and pipes). + */ +struct GNUNET_DISK_FileHandle +{ + +#if WINDOWS + /** + * File handle under W32. + */ + HANDLE h; + + /** + * Type + */ + enum GNUNET_FILE_Type type; + + /** + * Structure for overlapped reading (for pipes) + */ + OVERLAPPED *oOverlapRead; + + /** + * Structure for overlapped writing (for pipes) + */ + OVERLAPPED *oOverlapWrite; +#else + + /** + * File handle on other OSes. + */ + int fd; + +#endif /* + */ +}; + + +/* we need size_t, and since it can be both unsigned int + or unsigned long long, this IS platform dependent; + but "stdlib.h" should be portable 'enough' to be + unconditionally available... */ +#include +#include "gnunet_configuration_lib.h" +#include "gnunet_scheduler_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Specifies how a file should be opened. + */ +enum GNUNET_DISK_OpenFlags +{ + + /** + * Open the file for reading + */ + GNUNET_DISK_OPEN_READ = 1, + + /** + * Open the file for writing + */ + GNUNET_DISK_OPEN_WRITE = 2, + + /** + * Open the file for both reading and writing + */ + GNUNET_DISK_OPEN_READWRITE = 3, + + /** + * Fail if file already exists + */ + GNUNET_DISK_OPEN_FAILIFEXISTS = 4, + + /** + * Truncate file if it exists + */ + GNUNET_DISK_OPEN_TRUNCATE = 8, + + /** + * Create file if it doesn't exist + */ + GNUNET_DISK_OPEN_CREATE = 16, + + /** + * Append to the file + */ + GNUNET_DISK_OPEN_APPEND = 32 +}; + +/** + * Specifies what type of memory map is desired. + */ +enum GNUNET_DISK_MapType +{ + /** + * Read-only memory map. + */ + GNUNET_DISK_MAP_TYPE_READ = 1, + + /** + * Write-able memory map. + */ + GNUNET_DISK_MAP_TYPE_WRITE = 2, + /** + * Read-write memory map. + */ + GNUNET_DISK_MAP_TYPE_READWRITE = 3 +}; + + +/** + * File access permissions, UNIX-style. + */ +enum GNUNET_DISK_AccessPermissions +{ + /** + * Nobody is allowed to do anything to the file. + */ + GNUNET_DISK_PERM_NONE = 0, + + /** + * Owner can read. + */ + GNUNET_DISK_PERM_USER_READ = 1, + + /** + * Owner can write. + */ + GNUNET_DISK_PERM_USER_WRITE = 2, + + /** + * Owner can execute. + */ + GNUNET_DISK_PERM_USER_EXEC = 4, + + /** + * Group can read. + */ + GNUNET_DISK_PERM_GROUP_READ = 8, + + /** + * Group can write. + */ + GNUNET_DISK_PERM_GROUP_WRITE = 16, + + /** + * Group can execute. + */ + GNUNET_DISK_PERM_GROUP_EXEC = 32, + + /** + * Everybody can read. + */ + GNUNET_DISK_PERM_OTHER_READ = 64, + + /** + * Everybody can write. + */ + GNUNET_DISK_PERM_OTHER_WRITE = 128, + + /** + * Everybody can execute. + */ + GNUNET_DISK_PERM_OTHER_EXEC = 256 +}; + + +/** + * Constants for specifying how to seek. + */ +enum GNUNET_DISK_Seek +{ + /** + * Seek an absolute position (from the start of the file). + */ + GNUNET_DISK_SEEK_SET, + + /** + * Seek a relative position (from the current offset). + */ + GNUNET_DISK_SEEK_CUR, + + /** + * Seek an absolute position from the end of the file. + */ + GNUNET_DISK_SEEK_END +}; + + +/** + * Enumeration identifying the two ends of a pipe. + */ +enum GNUNET_DISK_PipeEnd +{ + /** + * The reading-end of a pipe. + */ + GNUNET_DISK_PIPE_END_READ = 0, + + /** + * The writing-end of a pipe. + */ + GNUNET_DISK_PIPE_END_WRITE = 1 +}; + + +/** + * Get the number of blocks that are left on the partition that + * contains the given file (for normal users). + * + * @param part a file on the partition to check + * @return -1 on errors, otherwise the number of free blocks + */ +long +GNUNET_DISK_get_blocks_available (const char *part); + + +/** + * Checks whether a handle is invalid + * + * @param h handle to check + * @return GNUNET_YES if invalid, GNUNET_NO if valid + */ +int +GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h); + + +/** + * Check that fil corresponds to a filename + * (of a file that exists and that is not a directory). + * + * @param fil filename to check + * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something + * else (will print an error message in that case, too). + */ +int +GNUNET_DISK_file_test (const char *fil); + + +/** + * Move the read/write pointer in a file + * @param h handle of an open file + * @param offset position to move to + * @param whence specification to which position the offset parameter relates to + * @return the new position on success, GNUNET_SYSERR otherwise + */ +OFF_T +GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h, OFF_T offset, + enum GNUNET_DISK_Seek whence); + + +/** + * Get the size of the file (or directory) + * of the given file (in bytes). + * + * @param filename name of the file or directory + * @param size set to the size of the file (or, + * in the case of directories, the sum + * of all sizes of files in the directory) + * @param includeSymLinks should symbolic links be + * included? + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_file_size (const char *filename, uint64_t * size, + int includeSymLinks); + + +/** + * Obtain some unique identifiers for the given file + * that can be used to identify it in the local system. + * This function is used between GNUnet processes to + * quickly check if two files with the same absolute path + * are actually identical. The two processes represent + * the same peer but may communicate over the network + * (and the file may be on an NFS volume). This function + * may not be supported on all operating systems. + * + * @param filename name of the file + * @param dev set to the device ID + * @param ino set to the inode ID + * @return GNUNET_OK on success + */ +int +GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev, + uint64_t * ino); + + +/** + * Create an (empty) temporary file on disk. If the given name is not + * an absolute path, the current 'TMPDIR' will be prepended. In any case, + * 6 random characters will be appended to the name to create a unique + * filename. + * + * @param t component to use for the name; + * does NOT contain "XXXXXX" or "/tmp/". + * @return NULL on error, otherwise name of fresh + * file on disk in directory for temporary files + */ +char * +GNUNET_DISK_mktemp (const char *t); + + +/** + * Open a file. Note that the access permissions will only be + * used if a new file is created and if the underlying operating + * system supports the given permissions. + * + * @param fn file name to be opened + * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags + * @param perm permissions for the newly created file, use + * GNUNET_DISK_PERM_NONE if a file could not be created by this + * call (because of flags) + * @return IO handle on success, NULL on error + */ +struct GNUNET_DISK_FileHandle * +GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags, + enum GNUNET_DISK_AccessPermissions perm); + + +/** + * Get the size of an open file. + * + * @param fh open file handle + * @param size where to write size of the file + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh, + OFF_T *size); + + +/** + * Creates an interprocess channel + * + * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO + * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO + * @param inherit_read 1 to make read handle inheritable, 0 otherwise (NT only) + * @param inherit_write 1 to make write handle inheritable, 0 otherwise (NT only) + * @return handle to the new pipe, NULL on error + */ +struct GNUNET_DISK_PipeHandle * +GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write); + + +/** + * Creates a pipe object from a couple of file descriptors. + * Useful for wrapping existing pipe FDs. + * + * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO + * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO + * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes + * + * @return handle to the new pipe, NULL on error + */ +struct GNUNET_DISK_PipeHandle * +GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]); + +/** + * Closes an interprocess channel + * @param p pipe + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p); + +/** + * Closes one half of an interprocess channel + * + * @param p pipe to close end of + * @param end which end of the pipe to close + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p, + enum GNUNET_DISK_PipeEnd end); + +/** + * Close an open file. + * + * @param h file handle + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h); + + +/** + * Get the handle to a particular pipe end + * + * @param p pipe + * @param n end to access + * @return handle for the respective end + */ +const struct GNUNET_DISK_FileHandle * +GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p, + enum GNUNET_DISK_PipeEnd n); + +/** + * Read the contents of a binary file into a buffer. + * @param h handle to an open file + * @param result the buffer to write the result to + * @param len the maximum number of bytes to read + * @return the number of bytes read on success, GNUNET_SYSERR on failure + */ +ssize_t +GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h, void *result, + size_t len); + +/** + * Read the contents of a binary file into a buffer. + * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN + * when no data can be read). + * + * @param h handle to an open file + * @param result the buffer to write the result to + * @param len the maximum number of bytes to read + * @return the number of bytes read on success, GNUNET_SYSERR on failure + */ +ssize_t +GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h, + void *result, size_t len); + +/** + * Read the contents of a binary file into a buffer. + * + * @param fn file name + * @param result the buffer to write the result to + * @param len the maximum number of bytes to read + * @return number of bytes read, GNUNET_SYSERR on failure + */ +ssize_t +GNUNET_DISK_fn_read (const char *fn, void *result, size_t len); + + +/** + * Write a buffer to a file. + * + * @param h handle to open file + * @param buffer the data to write + * @param n number of bytes to write + * @return number of bytes written on success, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h, + const void *buffer, size_t n); + + +/** + * Write a buffer to a file, blocking, if necessary. + * @param h handle to open file + * @param buffer the data to write + * @param n number of bytes to write + * @return number of bytes written on success, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h, + const void *buffer, size_t n); + +/** + * Write a buffer to a file. If the file is longer than + * the given buffer size, it will be truncated. + * + * @param fn file name + * @param buffer the data to write + * @param n number of bytes to write + * @param mode file permissions + * @return number of bytes written on success, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n, + enum GNUNET_DISK_AccessPermissions mode); + + +/** + * Copy a file. + * + * @param src file to copy + * @param dst destination file name + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_file_copy (const char *src, const char *dst); + + +/** + * Scan a directory for files. + * + * @param dirName the name of the directory + * @param callback the method to call for each file + * @param callback_cls closure for callback + * @return the number of files found, -1 on error + */ +int +GNUNET_DISK_directory_scan (const char *dirName, + GNUNET_FileNameCallback callback, + void *callback_cls); + + +/** + * Opaque handle used for iterating over a directory. + */ +struct GNUNET_DISK_DirectoryIterator; + + +/** + * Function called to iterate over a directory. + * + * @param cls closure + * @param di argument to pass to "GNUNET_DISK_directory_iterator_next" to + * get called on the next entry (or finish cleanly); + * NULL on error (will be the last call in that case) + * @param filename complete filename (absolute path) + * @param dirname directory name (absolute path) + */ +typedef void (*GNUNET_DISK_DirectoryIteratorCallback) (void *cls, + struct + GNUNET_DISK_DirectoryIterator + * di, + const char *filename, + const char *dirname); + + +/** + * This function must be called during the DiskIteratorCallback + * (exactly once) to schedule the task to process the next + * filename in the directory (if there is one). + * + * @param iter opaque handle for the iterator + * @param can set to GNUNET_YES to terminate the iteration early + * @return GNUNET_YES if iteration will continue, + * GNUNET_NO if this was the last entry (and iteration is complete), + * GNUNET_SYSERR if "can" was YES + */ +int +GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter, + int can); + + +/** + * Scan a directory for files using the scheduler to run a task for + * each entry. The name of the directory must be expanded first (!). + * If a scheduler does not need to be used, GNUNET_DISK_directory_scan + * may provide a simpler API. + * + * @param prio priority to use + * @param dirName the name of the directory + * @param callback the method to call for each file + * @param callback_cls closure for callback + * @return GNUNET_YES if directory is not empty and 'callback' + * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error. + */ +int +GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio, + const char *dirName, + GNUNET_DISK_DirectoryIteratorCallback + callback, void *callback_cls); + + +/** + * Create the directory structure for storing + * a file. + * + * @param filename name of a file in the directory + * @returns GNUNET_OK on success, GNUNET_SYSERR on failure, + * GNUNET_NO if directory exists but is not writeable + */ +int +GNUNET_DISK_directory_create_for_file (const char *filename); + + +/** + * Test if "fil" is a directory that can be accessed. + * Will not print an error message if the directory + * does not exist. Will log errors if GNUNET_SYSERR is + * returned. + * + * @param fil filename to test + * @return GNUNET_YES if yes, GNUNET_NO if does not exist, GNUNET_SYSERR + * on any error and if exists but not directory + */ +int +GNUNET_DISK_directory_test (const char *fil); + + +/** + * Remove all files in a directory (rm -rf). Call with + * caution. + * + * @param fileName the file to remove + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_directory_remove (const char *fileName); + + +/** + * Implementation of "mkdir -p" + * + * @param dir the directory to create + * @returns GNUNET_SYSERR on failure, GNUNET_OK otherwise + */ +int +GNUNET_DISK_directory_create (const char *dir); + + +/** + * Lock a part of a file. + * + * @param fh file handle + * @param lockStart absolute position from where to lock + * @param lockEnd absolute position until where to lock + * @param excl GNUNET_YES for an exclusive lock + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart, + OFF_T lockEnd, int excl); + + +/** + * Unlock a part of a file + * @param fh file handle + * @param unlockStart absolute position from where to unlock + * @param unlockEnd absolute position until where to unlock + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart, + OFF_T unlockEnd); + + +/** + * @brief Removes special characters as ':' from a filename. + * @param fn the filename to canonicalize + */ +void +GNUNET_DISK_filename_canonicalize (char *fn); + + +/** + * @brief Change owner of a file + * @param filename file to change + * @param user new owner of the file + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_DISK_file_change_owner (const char *filename, const char *user); + + +/** + * Construct full path to a file inside of the private + * directory used by GNUnet. Also creates the corresponding + * directory. If the resulting name is supposed to be + * a directory, end the last argument in '/' (or pass + * DIR_SEPARATOR_STR as the last argument before NULL). + * + * @param cfg configuration to use + * @param serviceName name of the service asking + * @param ... is NULL-terminated list of + * path components to append to the + * private directory name. + * @return the constructed filename + */ +char * +GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *serviceName, ...); + + +/** + * Opaque handle for a memory-mapping operation. + */ +struct GNUNET_DISK_MapHandle; + +/** + * Map a file into memory + * @param h open file handle + * @param m handle to the new mapping (will be set) + * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx + * @param len size of the mapping + * @return pointer to the mapped memory region, NULL on failure + */ +void * +GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h, + struct GNUNET_DISK_MapHandle **m, + enum GNUNET_DISK_MapType access, size_t len); + +/** + * Unmap a file + * + * @param h mapping handle + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h); + +/** + * Write file changes to disk + * @param h handle to an open file + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_DISK_LIB_H */ +#endif +/* end of gnunet_disk_lib.h */ diff --git a/src/include/gnunet_dns_service.h b/src/include/gnunet_dns_service.h new file mode 100644 index 0000000..a822b06 --- /dev/null +++ b/src/include/gnunet_dns_service.h @@ -0,0 +1,186 @@ +/* + This file is part of GNUnet + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_dns_service.h + * @brief API to access the DNS service. + * @author Christian Grothoff + */ +#ifndef GNUNET_DNS_SERVICE_NEW_H +#define GNUNET_DNS_SERVICE_NEW_H + +#include "gnunet_common.h" +#include "gnunet_util_lib.h" + + +/** + * Opaque DNS handle + */ +struct GNUNET_DNS_Handle; + +/** + * Handle to identify an individual DNS request. + */ +struct GNUNET_DNS_RequestHandle; + +/** + * Flags that specify when to call the client's handler. + */ +enum GNUNET_DNS_Flags +{ + + /** + * Useless option: never call the client. + */ + GNUNET_DNS_FLAG_NEVER = 0, + + /** + * Set this flag to see all requests first prior to resolution + * (for monitoring). Clients that set this flag must then + * call "GNUNET_DNS_request_forward" when they process a request + * for the first time. Caling "GNUNET_DNS_request_answer" is + * not allowed for MONITOR peers. + */ + GNUNET_DNS_FLAG_REQUEST_MONITOR = 1, + + /** + * This client should be called on requests that have not + * yet been resolved as this client provides a resolution + * service. Note that this does not guarantee that the + * client will see all requests as another client might be + * called first and that client might have already done the + * resolution, in which case other pre-resolution clients + * won't see the request anymore. + */ + GNUNET_DNS_FLAG_PRE_RESOLUTION = 2, + + /** + * This client wants to be called on the results of a DNS resolution + * (either resolved by PRE-RESOLUTION clients or the global DNS). + * The client then has a chance to modify the answer (or cause it to + * be dropped). There is no guarantee that other POST-RESOLUTION + * client's won't modify (or drop) the answer afterwards. + */ + GNUNET_DNS_FLAG_POST_RESOLUTION = 4, + + /** + * Set this flag to see all requests just before they are + * returned to the network. Clients that set this flag must then + * call "GNUNET_DNS_request_forward" when they process a request + * for the last time. Caling "GNUNET_DNS_request_answer" is + * not allowed for MONITOR peers. + */ + GNUNET_DNS_FLAG_RESPONSE_MONITOR = 8 + +}; + + + +/** + * Signature of a function that is called whenever the DNS service + * encounters a DNS request and needs to do something with it. The + * function has then the chance to generate or modify the response by + * calling one of the three "GNUNET_DNS_request_*" continuations. + * + * When a request is intercepted, this function is called first to + * give the client a chance to do the complete address resolution; + * "rdata" will be NULL for this first call for a DNS request, unless + * some other client has already filled in a response. + * + * If multiple clients exist, all of them are called before the global + * DNS. The global DNS is only called if all of the clients' + * functions call GNUNET_DNS_request_forward. Functions that call + * GNUNET_DNS_request_forward will be called again before a final + * response is returned to the application. If any of the clients' + * functions call GNUNET_DNS_request_drop, the response is dropped. + * + * @param cls closure + * @param rh request handle to user for reply + * @param request_length number of bytes in request + * @param request udp payload of the DNS request + */ +typedef void (*GNUNET_DNS_RequestHandler)(void *cls, + struct GNUNET_DNS_RequestHandle *rh, + size_t request_length, + const char *request); + + +/** + * If a GNUNET_DNS_RequestHandler calls this function, the client + * has no desire to interfer with the request and it should + * continue to be processed normally. + * + * @param rh request that should now be forwarded + */ +void +GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh); + + +/** + * If a GNUNET_DNS_RequestHandler calls this function, the request is + * to be dropped and no response should be generated. + * + * @param rh request that should now be dropped + */ +void +GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh); + + +/** + * If a GNUNET_DNS_RequestHandler calls this function, the request is + * supposed to be answered with the data provided to this call (with + * the modifications the function might have made). The reply given + * must always be a valid DNS reply and not a mutated DNS request. + * + * @param rh request that should now be answered + * @param reply_length size of reply (uint16_t to force sane size) + * @param reply reply data + */ +void +GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, + uint16_t reply_length, + const char *reply); + + +/** + * Connect to the service-dns + * + * @param cfg configuration to use + * @param flags when to call rh + * @param rh function to call with DNS requests + * @param rh_cls closure to pass to rh + * @return DNS handle + */ +struct GNUNET_DNS_Handle * +GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + enum GNUNET_DNS_Flags flags, + GNUNET_DNS_RequestHandler rh, + void *rh_cls); + + +/** + * Disconnect from the DNS service. + * + * @param dh DNS handle + */ +void +GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh); + +#endif diff --git a/src/include/gnunet_dnsparser_lib.h b/src/include/gnunet_dnsparser_lib.h new file mode 100644 index 0000000..0c310ba --- /dev/null +++ b/src/include/gnunet_dnsparser_lib.h @@ -0,0 +1,397 @@ +/* + This file is part of GNUnet + (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_dnsparser_lib.h + * @brief API for helper library to parse DNS packets. + * @author Philipp Toelke + * @author Christian Grothoff + */ +#ifndef GNUNET_DNSPARSER_LIB_H +#define GNUNET_DNSPARSER_LIB_H + +#include "platform.h" +#include "gnunet_common.h" + +/** + * A few common DNS types. + */ +#define GNUNET_DNSPARSER_TYPE_A 1 +#define GNUNET_DNSPARSER_TYPE_NS 2 +#define GNUNET_DNSPARSER_TYPE_CNAME 5 +#define GNUNET_DNSPARSER_TYPE_SOA 6 +#define GNUNET_DNSPARSER_TYPE_PTR 12 +#define GNUNET_DNSPARSER_TYPE_MX 15 +#define GNUNET_DNSPARSER_TYPE_TXT 16 +#define GNUNET_DNSPARSER_TYPE_AAAA 28 + +/** + * A few common DNS classes (ok, only one is common, but I list a + * couple more to make it clear what we're talking about here). + */ +#define GNUNET_DNSPARSER_CLASS_INTERNET 1 +#define GNUNET_DNSPARSER_CLASS_CHAOS 3 +#define GNUNET_DNSPARSER_CLASS_HESIOD 4 + +#define GNUNET_DNSPARSER_OPCODE_QUERY 0 +#define GNUNET_DNSPARSER_OPCODE_INVERSE_QUERY 1 +#define GNUNET_DNSPARSER_OPCODE_STATUS 2 + +/** + * RFC 1035 codes. + */ +#define GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR 0 +#define GNUNET_DNSPARSER_RETURN_CODE_FORMAT_ERROR 1 +#define GNUNET_DNSPARSER_RETURN_CODE_SERVER_FAILURE 2 +#define GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR 3 +#define GNUNET_DNSPARSER_RETURN_CODE_NOT_IMPLEMENTED 4 +#define GNUNET_DNSPARSER_RETURN_CODE_REFUSED 5 + +/** + * RFC 2136 codes + */ +#define GNUNET_DNSPARSER_RETURN_CODE_YXDOMAIN 6 +#define GNUNET_DNSPARSER_RETURN_CODE_YXRRSET 7 +#define GNUNET_DNSPARSER_RETURN_CODE_NXRRSET 8 +#define GNUNET_DNSPARSER_RETURN_CODE_NOT_AUTH 9 +#define GNUNET_DNSPARSER_RETURN_CODE_NOT_ZONE 10 + +/** + * DNS flags (largely RFC 1035 / RFC 2136). + */ +struct GNUNET_DNSPARSER_Flags +{ + /** + * Set to 1 if recursion is desired (client -> server) + */ + unsigned int recursion_desired : 1 GNUNET_PACKED; + + /** + * Set to 1 if message is truncated + */ + unsigned int message_truncated : 1 GNUNET_PACKED; + + /** + * Set to 1 if this is an authoritative answer + */ + unsigned int authoritative_answer : 1 GNUNET_PACKED; + + /** + * See GNUNET_DNSPARSER_OPCODE_ defines. + */ + unsigned int opcode : 4 GNUNET_PACKED; + + /** + * query:0, response:1 + */ + unsigned int query_or_response : 1 GNUNET_PACKED; + + /** + * See GNUNET_DNSPARSER_RETURN_CODE_ defines. + */ + unsigned int return_code : 4 GNUNET_PACKED; + + /** + * See RFC 4035. + */ + unsigned int checking_disabled : 1 GNUNET_PACKED; + + /** + * Response has been cryptographically verified, RFC 4035. + */ + unsigned int authenticated_data : 1 GNUNET_PACKED; + + /** + * Always zero. + */ + unsigned int zero : 1 GNUNET_PACKED; + + /** + * Set to 1 if recursion is available (server -> client) + */ + unsigned int recursion_available : 1 GNUNET_PACKED; + +}; + + +/** + * A DNS query. + */ +struct GNUNET_DNSPARSER_Query +{ + + /** + * Name of the record that the query is for (0-terminated). + */ + char *name; + + /** + * See GNUNET_DNSPARSER_TYPE_*. + */ + uint16_t type; + + /** + * See GNUNET_DNSPARSER_CLASS_*. + */ + uint16_t class; + +}; + + +/** + * Information from MX records (RFC 1035). + */ +struct GNUNET_DNSPARSER_MxRecord +{ + + /** + * Preference for this entry (lower value is higher preference). + */ + uint16_t preference; + + /** + * Name of the mail server. + */ + char *mxhost; + +}; + + +/** + * Information from SOA records (RFC 1035). + */ +struct GNUNET_DNSPARSER_SoaRecord +{ + + /** + *The domainname of the name server that was the + * original or primary source of data for this zone. + */ + char *mname; + + /** + * A domainname which specifies the mailbox of the + * person responsible for this zone. + */ + char *rname; + + /** + * The version number of the original copy of the zone. + */ + uint32_t serial; + + /** + * Time interval before the zone should be refreshed. + */ + uint32_t refresh; + + /** + * Time interval that should elapse before a failed refresh should + * be retried. + */ + uint32_t retry; + + /** + * Time value that specifies the upper limit on the time interval + * that can elapse before the zone is no longer authoritative. + */ + uint32_t expire; + + /** + * The bit minimum TTL field that should be exported with any RR + * from this zone. + */ + uint32_t minimum_ttl; + +}; + + +/** + * Binary record information (unparsed). + */ +struct GNUNET_DNSPARSER_RawRecord +{ + + /** + * Binary record data. + */ + void *data; + + /** + * Number of bytes in data. + */ + size_t data_len; +}; + + +/** + * A DNS response record. + */ +struct GNUNET_DNSPARSER_Record +{ + + /** + * Name of the record that the query is for (0-terminated). + */ + char *name; + + union + { + + /** + * For NS, CNAME and PTR records, this is the uncompressed 0-terminated hostname. + */ + char *hostname; + + /** + * SOA data for SOA records. + */ + struct GNUNET_DNSPARSER_SoaRecord *soa; + + /** + * MX data for MX records. + */ + struct GNUNET_DNSPARSER_MxRecord *mx; + + /** + * Raw data for all other types. + */ + struct GNUNET_DNSPARSER_RawRecord raw; + + } data; + + + /** + * When does the record expire? + */ + struct GNUNET_TIME_Absolute expiration_time; + + /** + * See GNUNET_DNSPARSER_TYPE_*. + */ + uint16_t type; + + /** + * See GNUNET_DNSPARSER_CLASS_*. + */ + uint16_t class; + +}; + + +/** + * Easy-to-process, parsed version of a DNS packet. + */ +struct GNUNET_DNSPARSER_Packet +{ + /** + * Array of all queries in the packet, must contain "num_queries" entries. + */ + struct GNUNET_DNSPARSER_Query *queries; + + /** + * Array of all answers in the packet, must contain "num_answers" entries. + */ + struct GNUNET_DNSPARSER_Record *answers; + + /** + * Array of all authority records in the packet, must contain "num_authority_records" entries. + */ + struct GNUNET_DNSPARSER_Record *authority_records; + + /** + * Array of all additional answers in the packet, must contain "num_additional_records" entries. + */ + struct GNUNET_DNSPARSER_Record *additional_records; + + /** + * Number of queries in the packet. + */ + unsigned int num_queries; + + /** + * Number of answers in the packet, should be 0 for queries. + */ + unsigned int num_answers; + + /** + * Number of authoritative answers in the packet, should be 0 for queries. + */ + unsigned int num_authority_records; + + /** + * Number of additional records in the packet, should be 0 for queries. + */ + unsigned int num_additional_records; + + /** + * Bitfield of DNS flags. + */ + struct GNUNET_DNSPARSER_Flags flags; + + /** + * DNS ID (to match replies to requests). + */ + uint16_t id; + +}; + + +/** + * Parse a UDP payload of a DNS packet in to a nice struct for further + * processing and manipulation. + * + * @param udp_payload wire-format of the DNS packet + * @param udp_payload_length number of bytes in udp_payload + * @return NULL on error, otherwise the parsed packet + */ +struct GNUNET_DNSPARSER_Packet * +GNUNET_DNSPARSER_parse (const char *udp_payload, + size_t udp_payload_length); + + +/** + * Free memory taken by a packet. + * + * @param p packet to free + */ +void +GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p); + + +/** + * Given a DNS packet, generate the corresponding UDP payload. + * + * @param p packet to pack + * @param max maximum allowed size for the resulting UDP payload + * @param buf set to a buffer with the packed message + * @param buf_length set to the length of buf + * @return GNUNET_SYSERR if 'p' is invalid + * GNUNET_NO if 'p' was truncated (but there is still a result in 'buf') + * GNUNET_OK if 'p' was packed completely into '*buf' + */ +int +GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p, + uint16_t max, + char **buf, + size_t *buf_length); + + +#endif diff --git a/src/include/gnunet_dv_service.h b/src/include/gnunet_dv_service.h new file mode 100644 index 0000000..3454ebc --- /dev/null +++ b/src/include/gnunet_dv_service.h @@ -0,0 +1,88 @@ +/* + This file is part of GNUnet + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_dv_service.h + * @brief API to deal with dv service + * + * @author Christian Grothoff + * @author Nathan Evans + */ + +#ifndef GNUNET_DV_SERVICE_H +#define GNUNET_DV_SERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_plugin.h" + +/** + * Version of the dv API. + */ +#define GNUNET_DV_VERSION 0x00000000 + +/** + * Opaque handle for the dv service. + */ +struct GNUNET_DV_Handle; + +/** + * Send a message from the plugin to the DV service indicating that + * a message should be sent via DV to some peer. + * + * @param dv_handle the handle to the DV api + * @param target the final target of the message + * @param msgbuf the msg(s) to send + * @param msgbuf_size the size of msgbuf + * @param priority priority to pass on to core when sending the message + * @param timeout how long can this message be delayed (pass through to core) + * @param addr the address of this peer (internally known to DV) + * @param addrlen the length of the peer address + * @param cont continuation to call once the message has been sent (or failed) + * @param cont_cls closure for continuation + * + */ +int +GNUNET_DV_send (struct GNUNET_DV_Handle *dv_handle, + const struct GNUNET_PeerIdentity *target, const char *msgbuf, + size_t msgbuf_size, unsigned int priority, + struct GNUNET_TIME_Relative timeout, const void *addr, + size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont, + void *cont_cls); + + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/gnunet_fragmentation_lib.h b/src/include/gnunet_fragmentation_lib.h new file mode 100644 index 0000000..a953bd2 --- /dev/null +++ b/src/include/gnunet_fragmentation_lib.h @@ -0,0 +1,203 @@ +/* + This file is part of GNUnet + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file include/gnunet_fragmentation_lib.h + * @brief library to help fragment messages + * @author Christian Grothoff + * + * TODO: consider additional flow-control for sending from + * fragmentation based on continuations. + */ + +#ifndef GNUNET_FRAGMENTATION_LIB_H +#define GNUNET_FRAGMENTATION_LIB_H + +#include "gnunet_util_lib.h" +#include "gnunet_bandwidth_lib.h" +#include "gnunet_statistics_service.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Fragmentation context. + */ +struct GNUNET_FRAGMENT_Context; + + +/** + * Function that is called with messages created by the fragmentation + * module. In the case of the 'proc' callback of the + * GNUNET_FRAGMENT_context_create function, this function must + * eventually call 'GNUNET_FRAGMENT_context_transmission_done'. + * + * @param cls closure + * @param msg the message that was created + */ +typedef void (*GNUNET_FRAGMENT_MessageProcessor) (void *cls, + const struct + GNUNET_MessageHeader * msg); + + +/** + * Create a fragmentation context for the given message. + * Fragments the message into fragments of size "mtu" or + * less. Calls 'proc' on each un-acknowledged fragment, + * using both the expected 'delay' between messages and + * acknowledgements and the given 'tracker' to guide the + * frequency of calls to 'proc'. + * + * @param stats statistics context + * @param mtu the maximum message size for each fragment + * @param tracker bandwidth tracker to use for flow control (can be NULL) + * @param delay expected delay between fragment transmission + * and ACK based on previous messages + * @param msg the message to fragment + * @param proc function to call for each fragment to transmit + * @param proc_cls closure for proc + * @return the fragmentation context + */ +struct GNUNET_FRAGMENT_Context * +GNUNET_FRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats, + uint16_t mtu, + struct GNUNET_BANDWIDTH_Tracker *tracker, + struct GNUNET_TIME_Relative delay, + const struct GNUNET_MessageHeader *msg, + GNUNET_FRAGMENT_MessageProcessor proc, + void *proc_cls); + + +/** + * Continuation to call from the 'proc' function after the fragment + * has been transmitted (and hence the next fragment can now be + * given to proc). + * + * @param fc fragmentation context + */ +void +GNUNET_FRAGMENT_context_transmission_done (struct GNUNET_FRAGMENT_Context *fc); + + +/** + * Process an acknowledgement message we got from the other + * side (to control re-transmits). + * + * @param fc fragmentation context + * @param msg acknowledgement message we received + * @return GNUNET_OK if this ack completes the work of the 'fc' + * (all fragments have been received); + * GNUNET_NO if more messages are pending + * GNUNET_SYSERR if this ack is not valid for this fc + */ +int +GNUNET_FRAGMENT_process_ack (struct GNUNET_FRAGMENT_Context *fc, + const struct GNUNET_MessageHeader *msg); + + +/** + * Destroy the given fragmentation context (stop calling 'proc', free + * resources). + * + * @param fc fragmentation context + * @return average delay between transmission and ACK for the + * last message, FOREVER if the message was not fully transmitted + */ +struct GNUNET_TIME_Relative +GNUNET_FRAGMENT_context_destroy (struct GNUNET_FRAGMENT_Context *fc); + + +/** + * Defragmentation context (one per connection). + */ +struct GNUNET_DEFRAGMENT_Context; + + +/** + * Function that is called with acknowledgement messages created by + * the fragmentation module. Acknowledgements are cummulative, + * so it is OK to only transmit the 'latest' ack message for the same + * message ID. + * + * @param cls closure + * @param id unique message ID (modulo collisions) + * @param msg the message that was created + */ +typedef void (*GNUNET_DEFRAGMENT_AckProcessor) (void *cls, uint32_t id, + const struct + GNUNET_MessageHeader * msg); + + +/** + * Create a defragmentation context. + * + * @param stats statistics context + * @param mtu the maximum message size for each fragment + * @param num_msgs how many fragmented messages + * to we defragment at most at the same time? + * @param cls closure for proc and ackp + * @param proc function to call with defragmented messages + * @param ackp function to call with acknowledgements (to send + * back to the other side) + * @return the defragmentation context + */ +struct GNUNET_DEFRAGMENT_Context * +GNUNET_DEFRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats, + uint16_t mtu, unsigned int num_msgs, + void *cls, + GNUNET_FRAGMENT_MessageProcessor proc, + GNUNET_DEFRAGMENT_AckProcessor ackp); + + +/** + * Destroy the given defragmentation context. + * + * @param dc defragmentation context + */ +void +GNUNET_DEFRAGMENT_context_destroy (struct GNUNET_DEFRAGMENT_Context *dc); + + +/** + * We have received a fragment. Process it. + * + * @param dc the context + * @param msg the message that was received + * @return GNUNET_OK on success, GNUNET_NO if this was a duplicate, GNUNET_SYSERR on error + */ +int +GNUNET_DEFRAGMENT_process_fragment (struct GNUNET_DEFRAGMENT_Context *dc, + const struct GNUNET_MessageHeader *msg); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* end of gnunet_fragmentation_lib.h */ +#endif diff --git a/src/include/gnunet_fs_service.h b/src/include/gnunet_fs_service.h new file mode 100644 index 0000000..3eb5892 --- /dev/null +++ b/src/include/gnunet_fs_service.h @@ -0,0 +1,2843 @@ +/* + This file is part of GNUnet + (C) 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file include/gnunet_fs_service.h + * @brief API for file-sharing via GNUnet + * @author Christian Grothoff + */ +#ifndef GNUNET_FS_LIB_H +#define GNUNET_FS_LIB_H + +#include "gnunet_util_lib.h" +#include "gnunet_scheduler_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * Version number of the implementation. + * History: + * + * 1.x.x: initial version with triple GNUNET_hash and merkle tree + * 2.x.x: root node with mime-type, filename and version number + * 2.1.x: combined GNUNET_EC_ContentHashKey/3HASH encoding with 25:1 super-nodes + * 2.2.x: with directories + * 3.0.x: with namespaces + * 3.1.x: with namespace meta-data + * 3.2.x: with collections + * 4.0.x: with expiration, variable meta-data, kblocks + * 4.1.x: with new error and configuration handling + * 5.0.x: with location URIs + * 6.0.0: with support for OR in KSKs + * 6.1.x: with simplified namespace support + * 9.0.0: CPS-style integrated API + * 9.1.1: asynchronous directory scanning + */ +#define GNUNET_FS_VERSION 0x00090102 + + +/* ******************** URI API *********************** */ + +#define GNUNET_FS_URI_PREFIX "gnunet://fs/" +#define GNUNET_FS_URI_KSK_INFIX "ksk/" +#define GNUNET_FS_URI_SKS_INFIX "sks/" +#define GNUNET_FS_URI_CHK_INFIX "chk/" +#define GNUNET_FS_URI_LOC_INFIX "loc/" + + +/** + * A Universal Resource Identifier (URI), opaque. + */ +struct GNUNET_FS_Uri; + +/** + * Iterator over keywords + * + * @param cls closure + * @param keyword the keyword + * @param is_mandatory is the keyword mandatory (in a search) + * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort + */ +typedef int (*GNUNET_FS_KeywordIterator) (void *cls, const char *keyword, + int is_mandatory); + +/** + * Get a unique key from a URI. This is for putting URIs + * into HashMaps. The key may change between FS implementations. + * + * @param uri uri to convert to a unique key + * @param key wherer to store the unique key + */ +void +GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri, GNUNET_HashCode * key); + +/** + * Convert a URI to a UTF-8 String. + * + * @param uri uri to convert to a string + * @return the UTF-8 string + */ +char * +GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri); + +/** + * Convert keyword URI to a human readable format + * (i.e. the search query that was used in the first place) + * + * @param uri ksk uri to convert to a string + * @return string with the keywords + */ +char * +GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri); + + +/** + * Add the given keyword to the set of keywords represented by the URI. + * Does nothing if the keyword is already present. + * + * @param uri ksk uri to modify + * @param keyword keyword to add + * @param is_mandatory is this keyword mandatory? + */ +void +GNUNET_FS_uri_ksk_add_keyword (struct GNUNET_FS_Uri *uri, const char *keyword, + int is_mandatory); + + +/** + * Remove the given keyword from the set of keywords represented by the URI. + * Does nothing if the keyword is not present. + * + * @param uri ksk uri to modify + * @param keyword keyword to add + */ +void +GNUNET_FS_uri_ksk_remove_keyword (struct GNUNET_FS_Uri *uri, + const char *keyword); + + +/** + * Convert a UTF-8 String to a URI. + * + * @param uri string to parse + * @param emsg where to store the parser error message (if any) + * @return NULL on error + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_parse (const char *uri, char **emsg); + +/** + * Free URI. + * + * @param uri uri to free + */ +void +GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri); + + +/** + * How many keywords are ANDed in this keyword URI? + * + * @param uri ksk uri to get the number of keywords from + * @return 0 if this is not a keyword URI + */ +unsigned int +GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri); + + +/** + * Iterate over all keywords in this keyword URI. + * + * @param uri ksk uri to get the keywords from + * @param iterator function to call on each keyword + * @param iterator_cls closure for iterator + * @return -1 if this is not a keyword URI, otherwise number of + * keywords iterated over until iterator aborted + */ +int +GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri, + GNUNET_FS_KeywordIterator iterator, + void *iterator_cls); + + +/** + * Obtain the identity of the peer offering the data + * + * @param uri the location URI to inspect + * @param peer where to store the identify of the peer (presumably) offering the content + * @return GNUNET_SYSERR if this is not a location URI, otherwise GNUNET_OK + */ +int +GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri, + struct GNUNET_PeerIdentity *peer); + + +/** + * Obtain the URI of the content itself. + * + * @param uri location URI to get the content URI from + * @return NULL if argument is not a location URI + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri); + + +/** + * Obtain the expiration of the LOC URI. + * + * @param uri location URI to get the expiration from + * @return expiration time of the URI + */ +struct GNUNET_TIME_Absolute +GNUNET_FS_uri_loc_get_expiration (const struct GNUNET_FS_Uri *uri); + + +/** + * Construct a location URI (this peer will be used for the location). + * + * @param baseUri content offered by the sender + * @param cfg configuration information (used to find our hostkey) + * @param expiration_time how long will the content be offered? + * @return the location URI, NULL on error + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *baseUri, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TIME_Absolute expiration_time); + + +/** + * Merge the sets of keywords from two KSK URIs. + * + * @param u1 first uri + * @param u2 second uri + * @return merged URI, NULL on error + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1, + const struct GNUNET_FS_Uri *u2); + + +/** + * Duplicate URI. + * + * @param uri the URI to duplicate + * @return copy of the URI + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri); + + +/** + * Create an FS URI from a single user-supplied string of keywords. + * The string is broken up at spaces into individual keywords. + * Keywords that start with "+" are mandatory. Double-quotes can + * be used to prevent breaking up strings at spaces (and also + * to specify non-mandatory keywords starting with "+"). + * + * Keywords must contain a balanced number of double quotes and + * double quotes can not be used in the actual keywords (for + * example, the string '""foo bar""' will be turned into two + * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'. + * + * @param keywords the keyword string + * @param emsg where to store an error message + * @return an FS URI for the given keywords, NULL + * if keywords is not legal (i.e. empty). + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_ksk_create (const char *keywords, char **emsg); + + +/** + * Create an FS URI from a user-supplied command line of keywords. + * Arguments should start with "+" to indicate mandatory + * keywords. + * + * @param argc number of keywords + * @param argv keywords (double quotes are not required for + * keywords containing spaces; however, double + * quotes are required for keywords starting with + * "+"); there is no mechanism for having double + * quotes in the actual keywords (if the user + * did specifically specify double quotes, the + * caller should convert each double quote + * into two single quotes). + * @return an FS URI for the given keywords, NULL + * if keywords is not legal (i.e. empty). + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, const char **argv); + + +/** + * Test if two URIs are equal. + * + * @param u1 one of the URIs + * @param u2 the other URI + * @return GNUNET_YES if the URIs are equal + */ +int +GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1, + const struct GNUNET_FS_Uri *u2); + + +/** + * Is this a namespace URI? + * + * @param uri the uri to check + * @return GNUNET_YES if this is an SKS uri + */ +int +GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri); + + +/** + * Handle to one of our namespaces. + */ +struct GNUNET_FS_Namespace; + + +/** + * Create an SKS URI from a namespace and an identifier. + * + * @param ns namespace + * @param id identifier + * @param emsg where to store an error message + * @return an FS URI for the given namespace and identifier + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_sks_create (struct GNUNET_FS_Namespace *ns, const char *id, + char **emsg); + + +/** + * Create an SKS URI from a namespace ID and an identifier. + * + * @param nsid namespace ID + * @param id identifier + * @return an FS URI for the given namespace and identifier + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_sks_create_from_nsid (GNUNET_HashCode * nsid, const char *id); + + +/** + * Get the ID of a namespace from the given + * namespace URI. + * + * @param uri the uri to get the namespace ID from + * @param nsid where to store the ID of the namespace + * @return GNUNET_OK on success + */ +int +GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri, + GNUNET_HashCode * nsid); + + +/** + * Get the content identifier of an SKS URI. + * + * @param uri the sks uri + * @return NULL on error (not a valid SKS URI) + */ +char * +GNUNET_FS_uri_sks_get_content_id (const struct GNUNET_FS_Uri *uri); + + +/** + * Convert namespace URI to a human readable format + * (using the namespace description, if available). + * + * @param cfg configuration to use + * @param uri SKS uri to convert + * @return NULL on error (not an SKS URI) + */ +char * +GNUNET_FS_uri_sks_to_string_fancy (struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_FS_Uri *uri); + + +/** + * Is this a keyword URI? + * + * @param uri the uri + * @return GNUNET_YES if this is a KSK uri + */ +int +GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri); + + +/** + * Is this a file (or directory) URI? + * + * @param uri the uri to check + * @return GNUNET_YES if this is a CHK uri + */ +int +GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri); + + +/** + * What is the size of the file that this URI + * refers to? + * + * @param uri the CHK (or LOC) URI to inspect + * @return size of the file as specified in the CHK URI + */ +uint64_t +GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri *uri); + + +/** + * Is this a location URI? + * + * @param uri the uri to check + * @return GNUNET_YES if this is a LOC uri + */ +int +GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri); + + +/** + * Construct a keyword-URI from meta-data (take all entries + * in the meta-data and construct one large keyword URI + * that lists all keywords that can be found in the meta-data). + * + * @param md metadata to use + * @return NULL on error, otherwise a KSK URI + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData + *md); + + +/* ******************** command-line option parsing API *********************** */ + +/** + * Command-line option parser function that allows the user + * to specify one or more '-k' options with keywords. Each + * specified keyword will be added to the URI. A pointer to + * the URI must be passed as the "scls" argument. + * + * @param ctx command line processor context + * @param scls must be of type "struct GNUNET_FS_Uri **" + * @param option name of the option (typically 'k') + * @param value command line argument given + * @return GNUNET_OK on success + */ +int +GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext + *ctx, void *scls, const char *option, + const char *value); + + +/** + * Command-line option parser function that allows the user to specify + * one or more '-m' options with metadata. Each specified entry of + * the form "type=value" will be added to the metadata. A pointer to + * the metadata must be passed as the "scls" argument. + * + * @param ctx command line processor context + * @param scls must be of type "struct GNUNET_CONTAINER_MetaData **" + * @param option name of the option (typically 'k') + * @param value command line argument given + * @return GNUNET_OK on success + */ +int +GNUNET_FS_getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext + *ctx, void *scls, const char *option, + const char *value); + + + +/* ************************* sharing API ***************** */ + + +/** + * Possible status codes used in the callback for the + * various file-sharing operations. On each file (or search), + * the callback is guaranteed to be called once with "START" + * and once with STOPPED; calls with PROGRESS, ERROR or COMPLETED + * are optional and depend on the circumstances; parent operations + * will be STARTED before child-operations and STOPPED after + * their respective child-operations. START and STOP signals + * are typically generated either due to explicit client requests + * or because of suspend/resume operations. + */ +enum GNUNET_FS_Status +{ + /** + * Notification that we have started to publish a file structure. + */ + GNUNET_FS_STATUS_PUBLISH_START = 0, + + /** + * Notification that we have resumed sharing a file structure. + */ + GNUNET_FS_STATUS_PUBLISH_RESUME = 1, + + /** + * Notification that we have suspended sharing a file structure. + */ + GNUNET_FS_STATUS_PUBLISH_SUSPEND = 2, + + /** + * Notification that we are making progress sharing a file structure. + */ + GNUNET_FS_STATUS_PUBLISH_PROGRESS = 3, + + /** + * Notification that an error was encountered sharing a file structure. + * The application will continue to receive resume/suspend events for + * this structure until "GNUNET_FS_publish_stop" is called. + */ + GNUNET_FS_STATUS_PUBLISH_ERROR = 4, + + /** + * Notification that we completed sharing a file structure. + * The application will continue to receive resume/suspend events for + * this structure until "GNUNET_FS_publish_stop" is called. + */ + GNUNET_FS_STATUS_PUBLISH_COMPLETED = 5, + + /** + * Notification that we have stopped + * the process of uploading a file structure; no + * futher events will be generated for this action. + */ + GNUNET_FS_STATUS_PUBLISH_STOPPED = 6, + + /** + * Notification that we have started this download. + */ + GNUNET_FS_STATUS_DOWNLOAD_START = 7, + + /** + * Notification that this download is being resumed. + */ + GNUNET_FS_STATUS_DOWNLOAD_RESUME = 8, + + /** + * Notification that this download was suspended. + */ + GNUNET_FS_STATUS_DOWNLOAD_SUSPEND = 9, + + /** + * Notification about progress with this download. + */ + GNUNET_FS_STATUS_DOWNLOAD_PROGRESS = 10, + + /** + * Notification that this download encountered an error. + */ + GNUNET_FS_STATUS_DOWNLOAD_ERROR = 11, + + /** + * Notification that this download completed. Note that for + * directories, completion does not imply completion of all files in + * the directory. + */ + GNUNET_FS_STATUS_DOWNLOAD_COMPLETED = 12, + + /** + * Notification that this download was stopped + * (final event with respect to this action). + */ + GNUNET_FS_STATUS_DOWNLOAD_STOPPED = 13, + + /** + * Notification that this download is now actively being + * pursued (as opposed to waiting in the queue). + */ + GNUNET_FS_STATUS_DOWNLOAD_ACTIVE = 14, + + /** + * Notification that this download is no longer actively + * being pursued (back in the queue). + */ + GNUNET_FS_STATUS_DOWNLOAD_INACTIVE = 15, + + /** + * Notification that this download is no longer part of a + * recursive download or search but now a 'stand-alone' + * download (and may thus need to be moved in the GUI + * into a different category). + */ + GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT = 16, + + /** + * First event generated when a client requests + * a search to begin or when a namespace result + * automatically triggers the search for updates. + */ + GNUNET_FS_STATUS_SEARCH_START = 17, + + /** + * Last event when a search is being resumed; + * note that "GNUNET_FS_SEARCH_START" will not + * be generated in this case. + */ + GNUNET_FS_STATUS_SEARCH_RESUME = 18, + + /** + * Event generated for each search result + * when the respective search is resumed. + */ + GNUNET_FS_STATUS_SEARCH_RESUME_RESULT = 19, + + /** + * Last event when a search is being suspended; + * note that "GNUNET_FS_SEARCH_STOPPED" will not + * be generated in this case. + */ + GNUNET_FS_STATUS_SEARCH_SUSPEND = 20, + + /** + * This search has yielded a result. + */ + GNUNET_FS_STATUS_SEARCH_RESULT = 21, + + /** + * We have discovered a new namespace. + */ + GNUNET_FS_STATUS_SEARCH_RESULT_NAMESPACE = 22, + + /** + * We have additional data about the quality + * or availability of a search result. + */ + GNUNET_FS_STATUS_SEARCH_UPDATE = 23, + + /** + * Signals a problem with this search. + */ + GNUNET_FS_STATUS_SEARCH_ERROR = 24, + + /** + * Signals that this search was paused. + */ + GNUNET_FS_STATUS_SEARCH_PAUSED = 25, + + /** + * Signals that this search was continued (unpaused). + */ + GNUNET_FS_STATUS_SEARCH_CONTINUED = 26, + + /** + * Event generated for each search result + * when the respective search is stopped. + */ + GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED = 27, + + /** + * Event generated for each search result + * when the respective search is suspended. + */ + GNUNET_FS_STATUS_SEARCH_RESULT_SUSPEND = 28, + + /** + * Last message from a search; this signals + * that there will be no further events associated + * with this search. + */ + GNUNET_FS_STATUS_SEARCH_STOPPED = 29, + + /** + * Notification that we started to unindex a file. + */ + GNUNET_FS_STATUS_UNINDEX_START = 30, + + /** + * Notification that we resumed unindexing of a file. + */ + GNUNET_FS_STATUS_UNINDEX_RESUME = 31, + + /** + * Notification that we suspended unindexing a file. + */ + GNUNET_FS_STATUS_UNINDEX_SUSPEND = 32, + + /** + * Notification that we made progress unindexing a file. + */ + GNUNET_FS_STATUS_UNINDEX_PROGRESS = 33, + + /** + * Notification that we encountered an error unindexing + * a file. + */ + GNUNET_FS_STATUS_UNINDEX_ERROR = 34, + + /** + * Notification that the unindexing of this file + * was completed. + */ + GNUNET_FS_STATUS_UNINDEX_COMPLETED = 35, + + /** + * Notification that the unindexing of this file + * was stopped (final event for this action). + */ + GNUNET_FS_STATUS_UNINDEX_STOPPED = 36 +}; + + +/** + * Handle for controlling an upload. + */ +struct GNUNET_FS_PublishContext; + + +/** + * Handle for controlling an unindexing operation. + */ +struct GNUNET_FS_UnindexContext; + + +/** + * Handle for controlling a search. + */ +struct GNUNET_FS_SearchContext; + + +/** + * Result from a search. Opaque handle to refer to the search + * (typically used when starting a download associated with the search + * result). + */ +struct GNUNET_FS_SearchResult; + + +/** + * Context for controlling a download. + */ +struct GNUNET_FS_DownloadContext; + + +/** + * Handle for detail information about a file that is being publishd. + * Specifies metadata, keywords, how to get the contents of the file + * (i.e. data-buffer in memory, filename on disk) and other options. + */ +struct GNUNET_FS_FileInformation; + + +/** + * Argument given to the progress callback with + * information about what is going on. + */ +struct GNUNET_FS_ProgressInfo +{ + + /** + * Values that depend on the event type. + */ + union + { + + /** + * Values for all "GNUNET_FS_STATUS_PUBLISH_*" events. + */ + struct + { + + /** + * Context for controlling the upload. + */ + struct GNUNET_FS_PublishContext *pc; + + /** + * Information about the file that is being publishd. + */ + const struct GNUNET_FS_FileInformation *fi; + + /** + * Client context pointer (set the last time by the client for + * this operation; initially NULL on START/RESUME events). + */ + void *cctx; + + /** + * Client context pointer for the parent operation + * (if this is a file in a directory or a subdirectory). + */ + void *pctx; + + /** + * Name of the file being published; can be NULL. + */ + const char *filename; + + /** + * How large is the file overall? For directories, + * this is only the size of the directory itself, + * not of the other files contained within the + * directory. + */ + uint64_t size; + + /** + * At what time do we expect to finish the upload? + * (will be a value in the past for completed + * uploads). + */ + struct GNUNET_TIME_Relative eta; + + /** + * How long has this upload been actively running + * (excludes times where the upload was suspended). + */ + struct GNUNET_TIME_Relative duration; + + /** + * How many bytes have we completed? + */ + uint64_t completed; + + /** + * What anonymity level is used for this upload? + */ + uint32_t anonymity; + + /** + * Additional values for specific events. + */ + union + { + + /** + * These values are only valid for + * GNUNET_FS_STATUS_PUBLISH_PROGRESS events. + */ + struct + { + + /** + * Data block we just published. + */ + const void *data; + + /** + * At what offset in the file is "data"? + */ + uint64_t offset; + + /** + * Length of the data block. + */ + uint64_t data_len; + + /** + * Depth of the given block in the tree; + * 0 would be the lowest level (DBLOCKs). + */ + unsigned int depth; + + } progress; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_PUBLISH_RESUME events. + */ + struct + { + + /** + * Error message, NULL if no error was encountered so far. + */ + const char *message; + + /** + * URI of the file (if the download had been completed) + */ + const struct GNUNET_FS_Uri *chk_uri; + + } resume; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_PUBLISH_COMPLETED events. + */ + struct + { + + /** + * URI of the file. + */ + const struct GNUNET_FS_Uri *chk_uri; + + } completed; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_PUBLISH_ERROR events. + */ + struct + { + + /** + * Error message, never NULL. + */ + const char *message; + + } error; + + } specifics; + + } publish; + + + /** + * Values for all "GNUNET_FS_STATUS_DOWNLOAD_*" events. + */ + struct + { + + /** + * Context for controlling the download. + */ + struct GNUNET_FS_DownloadContext *dc; + + /** + * Client context pointer (set the last time + * by the client for this operation; initially + * NULL on START/RESUME events). + */ + void *cctx; + + /** + * Client context pointer for the parent operation + * (if this is a file in a directory or a subdirectory). + */ + void *pctx; + + /** + * Client context pointer for the associated search operation + * (specifically, context pointer for the specific search + * result, not the overall search); only set if this + * download was started from a search result. + */ + void *sctx; + + /** + * URI used for this download. + */ + const struct GNUNET_FS_Uri *uri; + + /** + * Name of the file that we are downloading. + */ + const char *filename; + + /** + * How large is the download overall? This + * is NOT necessarily the size from the + * URI since we may be doing a partial download. + */ + uint64_t size; + + /** + * At what time do we expect to finish the download? + * (will be a value in the past for completed + * uploads). + */ + struct GNUNET_TIME_Relative eta; + + /** + * How long has this download been active? + */ + struct GNUNET_TIME_Relative duration; + + /** + * How many bytes have we completed? + */ + uint64_t completed; + + /** + * What anonymity level is used for this download? + */ + uint32_t anonymity; + + /** + * Is the download currently active. + */ + int is_active; + + /** + * Additional values for specific events. + */ + union + { + + /** + * These values are only valid for + * GNUNET_FS_STATUS_DOWNLOAD_PROGRESS events. + */ + struct + { + + /** + * Data block we just obtained, can be NULL (even if + * data_len > 0) if we found the entire block 'intact' on + * disk. In this case, it is also possible for 'data_len' + * to be larger than an individual (32k) block. + */ + const void *data; + + /** + * At what offset in the file is "data"? + */ + uint64_t offset; + + /** + * Length of the data block. + */ + uint64_t data_len; + + /** + * Depth of the given block in the tree; + * 0 would be the lowest level (DBLOCKS). + */ + unsigned int depth; + + /** + * How much trust did we offer for downloading this block? + */ + unsigned int trust_offered; + + /** + * How much time passed between us asking for this block and + * actually getting it? GNUNET_TIME_UNIT_FOREVER_REL if unknown. + */ + struct GNUNET_TIME_Relative block_download_duration; + + } progress; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_DOWNLOAD_START events. + */ + struct + { + + /** + * Known metadata for the download. + */ + const struct GNUNET_CONTAINER_MetaData *meta; + + } start; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_DOWNLOAD_RESUME events. + */ + struct + { + + /** + * Known metadata for the download. + */ + const struct GNUNET_CONTAINER_MetaData *meta; + + /** + * Error message, NULL if we have not encountered any error yet. + */ + const char *message; + + } resume; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_DOWNLOAD_ERROR events. + */ + struct + { + + /** + * Error message. + */ + const char *message; + + } error; + + } specifics; + + } download; + + /** + * Values for all "GNUNET_FS_STATUS_SEARCH_*" events. + */ + struct + { + + /** + * Context for controlling the search, NULL for + * searches that were not explicitly triggered + * by the client (i.e., searches for updates in + * namespaces). + */ + struct GNUNET_FS_SearchContext *sc; + + /** + * Client context pointer (set the last time by the client for + * this operation; initially NULL on START/RESUME events). Note + * that this value can only be set on START/RESUME; returning + * non-NULL on RESULT/RESUME_RESULT will actually update the + * private context for "UPDATE" events. + */ + void *cctx; + + /** + * Client parent-context pointer; NULL for top-level searches, + * refers to the client context of the associated search result + * for automatically triggered searches for updates in + * namespaces. In this case, 'presult' refers to that search + * result. + */ + void *pctx; + + /** + * What query is used for this search + * (list of keywords or SKS identifier). + */ + const struct GNUNET_FS_Uri *query; + + /** + * How long has this search been actively running + * (excludes times where the search was paused or + * suspended). + */ + struct GNUNET_TIME_Relative duration; + + /** + * What anonymity level is used for this search? + */ + uint32_t anonymity; + + /** + * Additional values for specific events. + */ + union + { + + /** + * These values are only valid for + * GNUNET_FS_STATUS_SEARCH_RESULT events. + */ + struct + { + + /** + * Metadata for the search result. + */ + const struct GNUNET_CONTAINER_MetaData *meta; + + /** + * URI for the search result. + */ + const struct GNUNET_FS_Uri *uri; + + /** + * Handle to the result (for starting downloads). + */ + struct GNUNET_FS_SearchResult *result; + + /** + * Applicability rank (the larger, the better the result + * fits the search criteria). + */ + uint32_t applicability_rank; + + } result; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_SEARCH_RESUME_RESULT events. + */ + struct + { + + /** + * Metadata for the search result. + */ + const struct GNUNET_CONTAINER_MetaData *meta; + + /** + * URI for the search result. + */ + const struct GNUNET_FS_Uri *uri; + + /** + * Handle to the result (for starting downloads). + */ + struct GNUNET_FS_SearchResult *result; + + /** + * Current availability rank (negative: + * unavailable, positive: available) + */ + int32_t availability_rank; + + /** + * On how many total queries is the given + * availability_rank based? + */ + uint32_t availability_certainty; + + /** + * Updated applicability rank (the larger, + * the better the result fits the search + * criteria). + */ + uint32_t applicability_rank; + + } resume_result; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_SEARCH_UPDATE events. + */ + struct + { + + /** + * Private context set for for this result + * during the "RESULT" event. + */ + void *cctx; + + /** + * Metadata for the search result. + */ + const struct GNUNET_CONTAINER_MetaData *meta; + + /** + * URI for the search result. + */ + const struct GNUNET_FS_Uri *uri; + + /** + * Current availability rank (negative: + * unavailable, positive: available) + */ + int32_t availability_rank; + + /** + * On how many total queries is the given + * availability_rank based? + */ + uint32_t availability_certainty; + + /** + * Updated applicability rank (the larger, + * the better the result fits the search + * criteria). + */ + uint32_t applicability_rank; + + } update; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_SEARCH_RESULT_SUSPEND events. + * These events are automatically triggered for + * each search result before the + * GNUNET_FS_STATUS_SEARCH_SUSPEND event. This + * happens primarily to give the client a chance + * to clean up the "cctx" (if needed). + */ + struct + { + + /** + * Private context set for for this result + * during the "RESULT" event. + */ + void *cctx; + + /** + * Metadata for the search result. + */ + const struct GNUNET_CONTAINER_MetaData *meta; + + /** + * URI for the search result. + */ + const struct GNUNET_FS_Uri *uri; + + } result_suspend; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED events. + * These events are automatically triggered for + * each search result before the + * GNUNET_FS_STATUS_SEARCH_STOPPED event. This + * happens primarily to give the client a chance + * to clean up the "cctx" (if needed). + */ + struct + { + + /** + * Private context set for for this result + * during the "RESULT" event. + */ + void *cctx; + + /** + * Metadata for the search result. + */ + const struct GNUNET_CONTAINER_MetaData *meta; + + /** + * URI for the search result. + */ + const struct GNUNET_FS_Uri *uri; + + } result_stopped; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_SEARCH_RESUME events. + */ + struct + { + + /** + * Error message, NULL if we have not encountered any error yet. + */ + const char *message; + + /** + * Is this search currently paused? + */ + int is_paused; + + } resume; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_SEARCH_ERROR events. + */ + struct + { + + /** + * Error message. + */ + const char *message; + + } error; + + /** + * Values for all "GNUNET_FS_STATUS_SEARCH_RESULT_NAMESPACE" events. + */ + struct + { + + /** + * Handle to the namespace (NULL if it is not a local + * namespace). + */ + struct GNUNET_FS_Namespace *ns; + + /** + * Short, human-readable name of the namespace. + */ + const char *name; + + /** + * Root identifier for the namespace, can be NULL. + */ + const char *root; + + /** + * Metadata for the namespace. + */ + const struct GNUNET_CONTAINER_MetaData *meta; + + /** + * Hash-identifier for the namespace. + */ + GNUNET_HashCode id; + + } namespace; + + } specifics; + + } search; + + /** + * Values for all "GNUNET_FS_STATUS_UNINDEX_*" events. + */ + struct + { + + /** + * Context for controlling the unindexing. + */ + struct GNUNET_FS_UnindexContext *uc; + + /** + * Client context pointer (set the last time + * by the client for this operation; initially + * NULL on START/RESUME events). + */ + void *cctx; + + /** + * Name of the file that is being unindexed. + */ + const char *filename; + + /** + * How large is the file overall? + */ + uint64_t size; + + /** + * At what time do we expect to finish unindexing? + * (will be a value in the past for completed + * unindexing opeations). + */ + struct GNUNET_TIME_Relative eta; + + /** + * How long has this upload been actively running + * (excludes times where the upload was suspended). + */ + struct GNUNET_TIME_Relative duration; + + /** + * How many bytes have we completed? + */ + uint64_t completed; + + /** + * Additional values for specific events. + */ + union + { + + /** + * These values are only valid for + * GNUNET_FS_STATUS_UNINDEX_PROGRESS events. + */ + struct + { + + /** + * Data block we just unindexed. + */ + const void *data; + + /** + * At what offset in the file is "data"? + */ + uint64_t offset; + + /** + * Length of the data block. + */ + uint64_t data_len; + + /** + * Depth of the given block in the tree; + * 0 would be the lowest level (DBLOCKS). + */ + unsigned int depth; + + } progress; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_UNINDEX_RESUME events. + */ + struct + { + + /** + * Error message, NULL if we have not encountered any error yet. + */ + const char *message; + + } resume; + + /** + * These values are only valid for + * GNUNET_FS_STATUS_UNINDEX_ERROR events. + */ + struct + { + + /** + * Error message. + */ + const char *message; + + } error; + + } specifics; + + } unindex; + + } value; + + /** + * Specific status code (determines the event type). + */ + enum GNUNET_FS_Status status; + +}; + + +/** + * Notification of FS to a client about the progress of an + * operation. Callbacks of this type will be used for uploads, + * downloads and searches. Some of the arguments depend a bit + * in their meaning on the context in which the callback is used. + * + * @param cls closure + * @param info details about the event, specifying the event type + * and various bits about the event + * @return client-context (for the next progress call + * for this operation; should be set to NULL for + * SUSPEND and STOPPED events). The value returned + * will be passed to future callbacks in the respective + * field in the GNUNET_FS_ProgressInfo struct. + */ +typedef void *(*GNUNET_FS_ProgressCallback) (void *cls, + const struct GNUNET_FS_ProgressInfo + * info); + + +/** + * General (global) option flags for file-sharing. + */ +enum GNUNET_FS_Flags +{ + /** + * No special flags set. + */ + GNUNET_FS_FLAGS_NONE = 0, + + /** + * Is persistence of operations desired? + * (will create SUSPEND/RESUME events). + */ + GNUNET_FS_FLAGS_PERSISTENCE = 1, + + /** + * Should we automatically trigger probes for search results + * to determine availability? + * (will create GNUNET_FS_STATUS_SEARCH_UPDATE events). + */ + GNUNET_FS_FLAGS_DO_PROBES = 2 +}; + +/** + * Options specified in the VARARGs portion of GNUNET_FS_start. + */ +enum GNUNET_FS_OPTIONS +{ + + /** + * Last option in the VARARG list. + */ + GNUNET_FS_OPTIONS_END = 0, + + /** + * Select the desired amount of parallelism (this option should be + * followed by an "unsigned int" giving the desired maximum number + * of parallel downloads). + */ + GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM = 1, + + /** + * Maximum number of requests that should be pending at a given + * point in time (invidivual downloads may go above this, but + * if we are above this threshold, we should not activate any + * additional downloads. + */ + GNUNET_FS_OPTIONS_REQUEST_PARALLELISM = 2 +}; + + +/** + * Settings for publishing a block (which may of course also + * apply to an entire directory or file). + */ +struct GNUNET_FS_BlockOptions +{ + + /** + * At what time should the block expire? Data blocks (DBLOCKS and + * IBLOCKS) may still be used even if they are expired (however, + * they'd be removed quickly from the datastore if we are short on + * space), all other types of blocks will no longer be returned + * after they expire. + */ + struct GNUNET_TIME_Absolute expiration_time; + + /** + * At which anonymity level should the block be shared? + * (0: no anonymity, 1: normal GAP, >1: with cover traffic). + */ + uint32_t anonymity_level; + + /** + * How important is it for us to store the block? If we run + * out of space, the highest-priority, non-expired blocks will + * be kept. + */ + uint32_t content_priority; + + /** + * How often should we try to migrate the block to other peers? + * Only used if "CONTENT_PUSHING" is set to YES, in which case we + * first push each block to other peers according to their + * replication levels. Once each block has been pushed that many + * times to other peers, blocks are chosen for migration at random. + * Naturally, there is no guarantee that the other peers will keep + * these blocks for any period of time (since they won't have any + * priority or might be too busy to even store the block in the + * first place). + */ + uint32_t replication_level; + +}; + + +/** + * Return the current year (i.e. '2011'). + */ +unsigned int +GNUNET_FS_get_current_year (void); + + +/** + * Convert a year to an expiration time of January 1st of that year. + * + * @param year a year (after 1970, please ;-)). + * @return absolute time for January 1st of that year. + */ +struct GNUNET_TIME_Absolute +GNUNET_FS_year_to_time (unsigned int year); + + +/** + * Convert an expiration time to the respective year (rounds) + * + * @param at absolute time + * @return year a year (after 1970), 0 on error + */ +unsigned int +GNUNET_FS_time_to_year (struct GNUNET_TIME_Absolute at); + + +/** + * Handle to the file-sharing service. + */ +struct GNUNET_FS_Handle; + + +/** + * Setup a connection to the file-sharing service. + * + * @param cfg configuration to use + * @param client_name unique identifier for this client + * @param upcb function to call to notify about FS actions + * @param upcb_cls closure for upcb + * @param flags specific attributes for fs-operations + * @param ... list of optional options, terminated with GNUNET_FS_OPTIONS_END + * @return NULL on error + */ +struct GNUNET_FS_Handle * +GNUNET_FS_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *client_name, GNUNET_FS_ProgressCallback upcb, + void *upcb_cls, enum GNUNET_FS_Flags flags, ...); + + +/** + * Close our connection with the file-sharing service. + * The callback given to GNUNET_FS_start will no longer be + * called after this function returns. + * + * @param h handle that was returned from GNUNET_FS_start + */ +void +GNUNET_FS_stop (struct GNUNET_FS_Handle *h); + + +/** + * Function called on entries in a GNUNET_FS_FileInformation publish-structure. + * + * @param cls closure + * @param fi the entry in the publish-structure + * @param length length of the file or directory + * @param meta metadata for the file or directory (can be modified) + * @param uri pointer to the keywords that will be used for this entry (can be modified) + * @param bo block options (can be modified) + * @param do_index should we index (can be modified) + * @param client_info pointer to client context set upon creation (can be modified) + * @return GNUNET_OK to continue, GNUNET_NO to remove + * this entry from the directory, GNUNET_SYSERR + * to abort the iteration + */ +typedef int (*GNUNET_FS_FileInformationProcessor) (void *cls, + struct + GNUNET_FS_FileInformation * + fi, uint64_t length, + struct + GNUNET_CONTAINER_MetaData * + meta, + struct GNUNET_FS_Uri ** uri, + struct GNUNET_FS_BlockOptions + * bo, int *do_index, + void **client_info); + + +/** + * Obtain the name under which this file information + * structure is stored on disk. Only works for top-level + * file information structures. + * + * @param s structure to get the filename for + * @return NULL on error, otherwise filename that + * can be passed to "GNUNET_FS_file_information_recover" + * to read this fi-struct from disk. + */ +const char * +GNUNET_FS_file_information_get_id (struct GNUNET_FS_FileInformation *s); + + +/** + * Obtain the filename from the file information structure. + * + * @param s structure to get the filename for + * @return "filename" field of the structure (can be NULL) + */ +const char * +GNUNET_FS_file_information_get_filename (struct GNUNET_FS_FileInformation *s); + + +/** + * Set the filename in the file information structure. + * If filename was already set, frees it before setting the new one. + * Makes a copy of the argument. + * + * @param s structure to get the filename for + * @param filename filename to set + */ +void +GNUNET_FS_file_information_set_filename (struct GNUNET_FS_FileInformation *s, + const char *filename); + + +/** + * Create an entry for a file in a publish-structure. + * + * @param h handle to the file sharing subsystem + * @param client_info initial client-info value for this entry + * @param filename name of the file or directory to publish + * @param keywords under which keywords should this file be available + * directly; can be NULL + * @param meta metadata for the file + * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, + * GNUNET_SYSERR for simulation + * @param bo block options + * @return publish structure entry for the file + */ +struct GNUNET_FS_FileInformation * +GNUNET_FS_file_information_create_from_file (struct GNUNET_FS_Handle *h, + void *client_info, + const char *filename, + const struct GNUNET_FS_Uri + *keywords, + const struct + GNUNET_CONTAINER_MetaData *meta, + int do_index, + const struct GNUNET_FS_BlockOptions + *bo); + + +/** + * Create an entry for a file in a publish-structure. + * + * @param h handle to the file sharing subsystem + * @param client_info initial client-info value for this entry + * @param length length of the file + * @param data data for the file (should not be used afterwards by + * the caller; callee will "free") + * @param keywords under which keywords should this file be available + * directly; can be NULL + * @param meta metadata for the file + * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, + * GNUNET_SYSERR for simulation + * @param bo block options + * @return publish structure entry for the file + */ +struct GNUNET_FS_FileInformation * +GNUNET_FS_file_information_create_from_data (struct GNUNET_FS_Handle *h, + void *client_info, uint64_t length, + void *data, + const struct GNUNET_FS_Uri + *keywords, + const struct + GNUNET_CONTAINER_MetaData *meta, + int do_index, + const struct GNUNET_FS_BlockOptions + *bo); + + +/** + * Function that provides data. + * + * @param cls closure + * @param offset offset to read from; it is possible + * that the caller might need to go backwards + * a bit at times + * @param max maximum number of bytes that should be + * copied to buf; readers are not allowed + * to provide less data unless there is an error; + * a value of "0" will be used at the end to allow + * the reader to clean up its internal state + * @param buf where the reader should write the data + * @param emsg location for the reader to store an error message + * @return number of bytes written, usually "max", 0 on error + */ +typedef size_t (*GNUNET_FS_DataReader) (void *cls, uint64_t offset, size_t max, + void *buf, char **emsg); + + +/** + * Create an entry for a file in a publish-structure. + * + * @param h handle to the file sharing subsystem + * @param client_info initial client-info value for this entry + * @param length length of the file + * @param reader function that can be used to obtain the data for the file + * @param reader_cls closure for "reader" + * @param keywords under which keywords should this file be available + * directly; can be NULL + * @param meta metadata for the file + * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, + * GNUNET_SYSERR for simulation + * @param bo block options + * @return publish structure entry for the file + */ +struct GNUNET_FS_FileInformation * +GNUNET_FS_file_information_create_from_reader (struct GNUNET_FS_Handle *h, + void *client_info, + uint64_t length, + GNUNET_FS_DataReader reader, + void *reader_cls, + const struct GNUNET_FS_Uri + *keywords, + const struct + GNUNET_CONTAINER_MetaData *meta, + int do_index, + const struct + GNUNET_FS_BlockOptions *bo); + + +/** + * Create an entry for an empty directory in a publish-structure. + * This function should be used by applications for which the + * use of "GNUNET_FS_file_information_create_from_directory" + * is not appropriate. + * + * @param h handle to the file sharing subsystem + * @param client_info initial client-info value for this entry + * @param keywords under which keywords should this directory be available + * directly; can be NULL + * @param meta metadata for the directory + * @param bo block options + * @param filename name of the directory; can be NULL + * @return publish structure entry for the directory , NULL on error + */ +struct GNUNET_FS_FileInformation * +GNUNET_FS_file_information_create_empty_directory (struct GNUNET_FS_Handle *h, + void *client_info, + const struct GNUNET_FS_Uri + *keywords, + const struct + GNUNET_CONTAINER_MetaData + *meta, + const struct + GNUNET_FS_BlockOptions *bo, + const char *filename); + + +/** + * Test if a given entry represents a directory. + * + * @param ent check if this FI represents a directory + * @return GNUNET_YES if so, GNUNET_NO if not + */ +int +GNUNET_FS_file_information_is_directory (const struct GNUNET_FS_FileInformation + *ent); + + +/** + * Add an entry to a directory in a publish-structure. Clients + * should never modify publish structures that were passed to + * "GNUNET_FS_publish_start" already. + * + * @param dir the directory + * @param ent the entry to add; the entry must not have been + * added to any other directory at this point and + * must not include "dir" in its structure + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_FS_file_information_add (struct GNUNET_FS_FileInformation *dir, + struct GNUNET_FS_FileInformation *ent); + + +/** + * Inspect a file or directory in a publish-structure. Clients + * should never modify publish structures that were passed to + * "GNUNET_FS_publish_start" already. When called on a directory, + * this function will FIRST call "proc" with information about + * the directory itself and then for each of the files in the + * directory (but not for files in subdirectories). When called + * on a file, "proc" will be called exactly once (with information + * about the specific file). + * + * @param dir the directory + * @param proc function to call on each entry + * @param proc_cls closure for proc + */ +void +GNUNET_FS_file_information_inspect (struct GNUNET_FS_FileInformation *dir, + GNUNET_FS_FileInformationProcessor proc, + void *proc_cls); + + +/** + * Destroy publish-structure. Clients should never destroy publish + * structures that were passed to "GNUNET_FS_publish_start" already. + * + * @param fi structure to destroy + * @param cleaner function to call on each entry in the structure + * (useful to clean up client_info); can be NULL; return + * values are ignored + * @param cleaner_cls closure for cleaner + */ +void +GNUNET_FS_file_information_destroy (struct GNUNET_FS_FileInformation *fi, + GNUNET_FS_FileInformationProcessor cleaner, + void *cleaner_cls); + + +/** + * Options for publishing. Compatible options + * can be OR'ed together. + */ +enum GNUNET_FS_PublishOptions +{ + /** + * No options (use defaults for everything). + */ + GNUNET_FS_PUBLISH_OPTION_NONE = 0, + + /** + * Simulate publishing. With this option, no data will be stored + * in the datastore. Useful for computing URIs from files. + */ + GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY = 1 +}; + +/** + * Publish a file or directory. + * + * @param h handle to the file sharing subsystem + * @param fi information about the file or directory structure to publish + * @param namespace namespace to publish the file in, NULL for no namespace + * @param nid identifier to use for the publishd content in the namespace + * (can be NULL, must be NULL if namespace is NULL) + * @param nuid update-identifier that will be used for future updates + * (can be NULL, must be NULL if namespace or nid is NULL) + * @param options options for the publication + * @return context that can be used to control the publish operation + */ +struct GNUNET_FS_PublishContext * +GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h, + struct GNUNET_FS_FileInformation *fi, + struct GNUNET_FS_Namespace *namespace, const char *nid, + const char *nuid, + enum GNUNET_FS_PublishOptions options); + + +/** + * Stop a publication. Will abort incomplete publications (but + * not remove blocks that have already been published) or + * simply clean up the state for completed publications. + * Must NOT be called from within the event callback! + * + * @param pc context for the publication to stop + */ +void +GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *pc); + + +/** + * Signature of a function called as the continuation of a KBlock or + * SBlock publication. + * + * @param cls closure + * @param uri URI under which the block is now available, NULL on error + * @param emsg error message, NULL on success + */ +typedef void (*GNUNET_FS_PublishContinuation) (void *cls, + const struct GNUNET_FS_Uri * uri, + const char *emsg); + + +/** + * Handle to cancel publish KSK operation. + */ +struct GNUNET_FS_PublishKskContext; + + +/** + * Publish a KBlock on GNUnet. + * + * @param h handle to the file sharing subsystem + * @param ksk_uri keywords to use + * @param meta metadata to use + * @param uri URI to refer to in the KBlock + * @param bo block options + * @param options publication options + * @param cont continuation + * @param cont_cls closure for cont + * @return NULL on error ('cont' will still be called) + */ +struct GNUNET_FS_PublishKskContext * +GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, + const struct GNUNET_FS_Uri *ksk_uri, + const struct GNUNET_CONTAINER_MetaData *meta, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_FS_BlockOptions *bo, + enum GNUNET_FS_PublishOptions options, + GNUNET_FS_PublishContinuation cont, void *cont_cls); + + +/** + * Abort the KSK publishing operation. + * + * @param pkc context of the operation to abort. + */ +void +GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc); + + +/** + * Handle to cancel publish SKS operation. + */ +struct GNUNET_FS_PublishSksContext; + + +/** + * Publish an SBlock on GNUnet. + * + * @param h handle to the file sharing subsystem + * @param namespace namespace to publish in + * @param identifier identifier to use + * @param update update identifier to use + * @param meta metadata to use + * @param uri URI to refer to in the SBlock + * @param bo block options + * @param options publication options + * @param cont continuation + * @param cont_cls closure for cont + * @return NULL on error ('cont' will still be called) + */ +struct GNUNET_FS_PublishSksContext * +GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, + struct GNUNET_FS_Namespace *namespace, + const char *identifier, const char *update, + const struct GNUNET_CONTAINER_MetaData *meta, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_FS_BlockOptions *bo, + enum GNUNET_FS_PublishOptions options, + GNUNET_FS_PublishContinuation cont, void *cont_cls); + + +/** + * Abort the SKS publishing operation. + * + * @param psc context of the operation to abort. + */ +void +GNUNET_FS_publish_sks_cancel (struct GNUNET_FS_PublishSksContext *psc); + + +/** + * Type of a function called by "GNUNET_FS_get_indexed_files". + * + * @param cls closure + * @param filename the name of the file, NULL for end of list + * @param file_id hash of the contents of the indexed file + * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort + */ +typedef int (*GNUNET_FS_IndexedFileProcessor) (void *cls, const char *filename, + const GNUNET_HashCode * file_id); + + +/** + * Handle to cancel 'GNUNET_FS_get_indexed_files'. + */ +struct GNUNET_FS_GetIndexedContext; + + +/** + * Iterate over all indexed files. + * + * @param h handle to the file sharing subsystem + * @param iterator function to call on each indexed file + * @param iterator_cls closure for iterator + * @return NULL on error ('iter' is not called) + */ +struct GNUNET_FS_GetIndexedContext * +GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h, + GNUNET_FS_IndexedFileProcessor iterator, + void *iterator_cls); + + +/** + * Cancel iteration over all indexed files. + * + * @param gic operation to cancel + */ +void +GNUNET_FS_get_indexed_files_cancel (struct GNUNET_FS_GetIndexedContext *gic); + + +/** + * Unindex a file. + * + * @param h handle to the file sharing subsystem + * @param filename file to unindex + * @param cctx initial value for the client context + * @return NULL on error, otherwise handle + */ +struct GNUNET_FS_UnindexContext * +GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h, const char *filename, + void *cctx); + + +/** + * Clean up after completion of an unindex operation. + * + * @param uc handle + */ +void +GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc); + + +/** + * Context for advertising a namespace. + */ +struct GNUNET_FS_AdvertisementContext; + + +/** + * Publish an advertismement for a namespace. + * + * @param h handle to the file sharing subsystem + * @param ksk_uri keywords to use for advertisment + * @param namespace handle for the namespace that should be advertised + * @param meta meta-data for the namespace advertisement + * @param bo block options + * @param rootEntry name of the root of the namespace + * @param cont continuation + * @param cont_cls closure for cont + * @return NULL on error ('cont' will still be called) + */ +struct GNUNET_FS_AdvertisementContext * +GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, + struct GNUNET_FS_Uri *ksk_uri, + struct GNUNET_FS_Namespace *namespace, + const struct GNUNET_CONTAINER_MetaData *meta, + const struct GNUNET_FS_BlockOptions *bo, + const char *rootEntry, + GNUNET_FS_PublishContinuation cont, + void *cont_cls); + + +/** + * Abort the namespace advertisement operation. + * + * @param ac context of the operation to abort. + */ +void +GNUNET_FS_namespace_advertise_cancel (struct GNUNET_FS_AdvertisementContext *ac); + + +/** + * Create a namespace with the given name; if one already + * exists, return a handle to the existing namespace. + * + * @param h handle to the file sharing subsystem + * @param name name to use for the namespace + * @return handle to the namespace, NULL on error + */ +struct GNUNET_FS_Namespace * +GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h, const char *name); + + +/** + * Duplicate a namespace handle. + * + * @param ns namespace handle + * @return duplicated handle to the namespace + */ +struct GNUNET_FS_Namespace * +GNUNET_FS_namespace_dup (struct GNUNET_FS_Namespace *ns); + + +/** + * Delete a namespace handle. Can be used for a clean shutdown (free + * memory) or also to freeze the namespace to prevent further + * insertions by anyone. + * + * @param namespace handle to the namespace that should be deleted / freed + * @param freeze prevents future insertions; creating a namespace + * with the same name again will create a fresh namespace instead + * + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace, int freeze); + + +/** + * Callback with information about local (!) namespaces. + * Contains the names of the local namespace and the global + * ID. + * + * @param cls closure + * @param name human-readable identifier of the namespace + * @param id hash identifier for the namespace + */ +typedef void (*GNUNET_FS_NamespaceInfoProcessor) (void *cls, const char *name, + const GNUNET_HashCode * id); + + +/** + * Build a list of all available local (!) namespaces The returned + * names are only the nicknames since we only iterate over the local + * namespaces. + * + * @param h handle to the file sharing subsystem + * @param cb function to call on each known namespace + * @param cb_cls closure for cb + */ +void +GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h, + GNUNET_FS_NamespaceInfoProcessor cb, void *cb_cls); + + +/** + * Function called on updateable identifiers. + * + * @param cls closure + * @param last_id last identifier + * @param last_uri uri used for the content published under the last_id + * @param last_meta metadata associated with last_uri + * @param next_id identifier that should be used for updates + */ +typedef void (*GNUNET_FS_IdentifierProcessor) (void *cls, const char *last_id, + const struct GNUNET_FS_Uri * + last_uri, + const struct + GNUNET_CONTAINER_MetaData * + last_meta, const char *next_id); + + +/** + * List all of the identifiers in the namespace for which we could + * produce an update. Namespace updates form a graph where each node + * has a name. Each node can have any number of URI/meta-data entries + * which can each be linked to other nodes. Cycles are possible. + * + * Calling this function with "next_id" NULL will cause the library to + * call "ip" with a root for each strongly connected component of the + * graph (a root being a node from which all other nodes in the Scc + * are reachable). + * + * Calling this function with "next_id" being the name of a node will + * cause the library to call "ip" with all children of the node. Note + * that cycles within an SCC are possible (including self-loops). + * + * @param namespace namespace to inspect for updateable content + * @param next_id ID to look for; use NULL to look for SCC roots + * @param ip function to call on each updateable identifier + * @param ip_cls closure for ip + */ +void +GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace, + const char *next_id, + GNUNET_FS_IdentifierProcessor ip, + void *ip_cls); + + +/** + * Options for searching. Compatible options + * can be OR'ed together. + */ +enum GNUNET_FS_SearchOptions +{ + /** + * No options (use defaults for everything). + */ + GNUNET_FS_SEARCH_OPTION_NONE = 0, + + /** + * Only search the local host, do not search remote systems (no P2P) + */ + GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY = 1 +}; + + +/** + * Start search for content. + * + * @param h handle to the file sharing subsystem + * @param uri specifies the search parameters; can be + * a KSK URI or an SKS URI. + * @param anonymity desired level of anonymity + * @param options options for the search + * @param cctx initial value for the client context + * @return context that can be used to control the search + */ +struct GNUNET_FS_SearchContext * +GNUNET_FS_search_start (struct GNUNET_FS_Handle *h, + const struct GNUNET_FS_Uri *uri, uint32_t anonymity, + enum GNUNET_FS_SearchOptions options, void *cctx); + + +/** + * Pause search. + * + * @param sc context for the search that should be paused + */ +void +GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc); + + +/** + * Continue paused search. + * + * @param sc context for the search that should be resumed + */ +void +GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc); + + +/** + * Stop search for content. + * + * @param sc context for the search that should be stopped + */ +void +GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc); + + + + +/** + * Options for downloading. Compatible options + * can be OR'ed together. + */ +enum GNUNET_FS_DownloadOptions +{ + /** + * No options (use defaults for everything). + */ + GNUNET_FS_DOWNLOAD_OPTION_NONE = 0, + + /** + * Only download from the local host, do not access remote systems (no P2P) + */ + GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY = 1, + + /** + * Do a recursive download (that is, automatically trigger the + * download of files in directories). + */ + GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE = 2, + + /** + * Do not append temporary data to + * the target file (for the IBlocks). + */ + GNUNET_FS_DOWNLOAD_NO_TEMPORARIES = 4, + + /** + * Internal option used to flag this download as a 'probe' for a + * search result. Impacts the priority with which the download is + * run and causes signalling callbacks to be done differently. + * Also, probe downloads are not serialized on suspension. Normal + * clients should not use this! + */ + GNUNET_FS_DOWNLOAD_IS_PROBE = (1 << 31) +}; + + + +/** + * Download parts of a file. Note that this will store + * the blocks at the respective offset in the given file. Also, the + * download is still using the blocking of the underlying FS + * encoding. As a result, the download may *write* outside of the + * given boundaries (if offset and length do not match the 32k FS + * block boundaries).

+ * + * The given range can be used to focus a download towards a + * particular portion of the file (optimization), not to strictly + * limit the download to exactly those bytes. + * + * @param h handle to the file sharing subsystem + * @param uri the URI of the file (determines what to download); CHK or LOC URI + * @param meta known metadata for the file (can be NULL) + * @param filename where to store the file, maybe NULL (then no file is + * created on disk and data must be grabbed from the callbacks) + * @param tempname where to store temporary file data, not used if filename is non-NULL; + * can be NULL (in which case we will pick a name if needed); the temporary file + * may already exist, in which case we will try to use the data that is there and + * if it is not what is desired, will overwrite it + * @param offset at what offset should we start the download (typically 0) + * @param length how many bytes should be downloaded starting at offset + * @param anonymity anonymity level to use for the download + * @param options various download options + * @param cctx initial value for the client context for this download + * @param parent parent download to associate this download with (use NULL + * for top-level downloads; useful for manually-triggered recursive downloads) + * @return context that can be used to control this download + */ +struct GNUNET_FS_DownloadContext * +GNUNET_FS_download_start (struct GNUNET_FS_Handle *h, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_CONTAINER_MetaData *meta, + const char *filename, const char *tempname, + uint64_t offset, uint64_t length, uint32_t anonymity, + enum GNUNET_FS_DownloadOptions options, void *cctx, + struct GNUNET_FS_DownloadContext *parent); + + +/** + * Download parts of a file based on a search result. The download + * will be associated with the search result (and the association + * will be preserved when serializing/deserializing the state). + * If the search is stopped, the download will not be aborted but + * be 'promoted' to a stand-alone download. + * + * As with the other download function, this will store + * the blocks at the respective offset in the given file. Also, the + * download is still using the blocking of the underlying FS + * encoding. As a result, the download may *write* outside of the + * given boundaries (if offset and length do not match the 32k FS + * block boundaries).

+ * + * The given range can be used to focus a download towards a + * particular portion of the file (optimization), not to strictly + * limit the download to exactly those bytes. + * + * @param h handle to the file sharing subsystem + * @param sr the search result to use for the download (determines uri and + * meta data and associations) + * @param filename where to store the file, maybe NULL (then no file is + * created on disk and data must be grabbed from the callbacks) + * @param tempname where to store temporary file data, not used if filename is non-NULL; + * can be NULL (in which case we will pick a name if needed); the temporary file + * may already exist, in which case we will try to use the data that is there and + * if it is not what is desired, will overwrite it + * @param offset at what offset should we start the download (typically 0) + * @param length how many bytes should be downloaded starting at offset + * @param anonymity anonymity level to use for the download + * @param options various download options + * @param cctx initial value for the client context for this download + * @return context that can be used to control this download + */ +struct GNUNET_FS_DownloadContext * +GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h, + struct GNUNET_FS_SearchResult *sr, + const char *filename, + const char *tempname, uint64_t offset, + uint64_t length, uint32_t anonymity, + enum GNUNET_FS_DownloadOptions options, + void *cctx); + + +/** + * Stop a download (aborts if download is incomplete). + * + * @param dc handle for the download + * @param do_delete delete files of incomplete downloads + */ +void +GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc, int do_delete); + + + +/* ******************** Directory API *********************** */ + + +#define GNUNET_FS_DIRECTORY_MIME "application/gnunet-directory" +#define GNUNET_FS_DIRECTORY_MAGIC "\211GND\r\n\032\n" +#define GNUNET_FS_DIRECTORY_EXT ".gnd" + +/** + * Does the meta-data claim that this is a directory? + * Checks if the mime-type is that of a GNUnet directory. + * + * @return GNUNET_YES if it is, GNUNET_NO if it is not, GNUNET_SYSERR if + * we have no mime-type information (treat as 'GNUNET_NO') + */ +int +GNUNET_FS_meta_data_test_for_directory (const struct GNUNET_CONTAINER_MetaData + *md); + + +/** + * Set the MIMETYPE information for the given + * metadata to "application/gnunet-directory". + * + * @param md metadata to add mimetype to + */ +void +GNUNET_FS_meta_data_make_directory (struct GNUNET_CONTAINER_MetaData *md); + + +/** + * Suggest a filename based on given metadata. + * + * @param md given meta data + * @return NULL if meta data is useless for suggesting a filename + */ +char * +GNUNET_FS_meta_data_suggest_filename (const struct GNUNET_CONTAINER_MetaData + *md); + + +/** + * Function used to process entries in a directory. + * + * @param cls closure + * @param filename name of the file in the directory + * @param uri URI of the file + * @param metadata metadata for the file; metadata for + * the directory if everything else is NULL/zero + * @param length length of the available data for the file + * (of type size_t since data must certainly fit + * into memory; if files are larger than size_t + * permits, then they will certainly not be + * embedded with the directory itself). + * @param data data available for the file (length bytes) + */ +typedef void (*GNUNET_FS_DirectoryEntryProcessor) (void *cls, + const char *filename, + const struct GNUNET_FS_Uri * + uri, + const struct + GNUNET_CONTAINER_MetaData * + meta, size_t length, + const void *data); + + +/** + * Iterate over all entries in a directory. Note that directories + * are structured such that it is possible to iterate over the + * individual blocks as well as over the entire directory. Thus + * a client can call this function on the buffer in the + * GNUNET_FS_ProgressCallback. Also, directories can optionally + * include the contents of (small) files embedded in the directory + * itself; for those files, the processor may be given the + * contents of the file directly by this function. + * + * @param size number of bytes in data + * @param data pointer to the beginning of the directory + * @param offset offset of data in the directory + * @param dep function to call on each entry + * @param dep_cls closure for dep + * @return GNUNET_OK if this could be a block in a directory, + * GNUNET_NO if this could be part of a directory (but not 100% OK) + * GNUNET_SYSERR if 'data' does not represent a directory + */ +int +GNUNET_FS_directory_list_contents (size_t size, const void *data, + uint64_t offset, + GNUNET_FS_DirectoryEntryProcessor dep, + void *dep_cls); + + +/** + * Opaque handle to a directory builder. + */ +struct GNUNET_FS_DirectoryBuilder; + +/** + * Create a directory builder. + * + * @param mdir metadata for the directory + */ +struct GNUNET_FS_DirectoryBuilder * +GNUNET_FS_directory_builder_create (const struct GNUNET_CONTAINER_MetaData + *mdir); + + +/** + * Add an entry to a directory. + * + * @param bld directory to extend + * @param uri uri of the entry (must not be a KSK) + * @param md metadata of the entry + * @param data raw data of the entry, can be NULL, otherwise + * data must point to exactly the number of bytes specified + * by the uri + */ +void +GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_CONTAINER_MetaData *md, + const void *data); + + +/** + * Finish building the directory. Frees the + * builder context and returns the directory + * in-memory. + * + * @param bld directory to finish + * @param rsize set to the number of bytes needed + * @param rdata set to the encoded directory + * @return GNUNET_OK on success + */ +int +GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld, + size_t * rsize, void **rdata); + + +/* ******************** DirScanner API *********************** */ + +/** + * Progress reasons of the directory scanner. + */ +enum GNUNET_FS_DirScannerProgressUpdateReason +{ + + /** + * We've started processing a file or directory. + */ + GNUNET_FS_DIRSCANNER_FILE_START = 0, + + /** + * We're having trouble accessing a file (soft-error); it will + * be ignored. + */ + GNUNET_FS_DIRSCANNER_FILE_IGNORED, + + /** + * We've found all files (in the pre-pass). + */ + GNUNET_FS_DIRSCANNER_ALL_COUNTED, + + /** + * We've finished extracting meta data from a file. + */ + GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED, + + /** + * Last call to the progress function: we have finished scanning + * the directory. + */ + GNUNET_FS_DIRSCANNER_FINISHED, + + /** + * There was an internal error. Application should abort the scan. + */ + GNUNET_FS_DIRSCANNER_INTERNAL_ERROR + +}; + + +/** + * Function called over time as the directory scanner makes + * progress on the job at hand. + * + * @param cls closure + * @param filename which file we are making progress on + * @param is_directory GNUNET_YES if this is a directory, + * GNUNET_NO if this is a file + * GNUNET_SYSERR if it is neither (or unknown) + * @param reason kind of progress we are making + */ +typedef void (*GNUNET_FS_DirScannerProgressCallback) (void *cls, + const char *filename, + int is_directory, + enum GNUNET_FS_DirScannerProgressUpdateReason reason); + + +/** + * A node of a directory tree (produced by dirscanner) + */ +struct GNUNET_FS_ShareTreeItem +{ + /** + * This is a doubly-linked list + */ + struct GNUNET_FS_ShareTreeItem *prev; + + /** + * This is a doubly-linked list + */ + struct GNUNET_FS_ShareTreeItem *next; + + /** + * This is a doubly-linked tree + * NULL for top-level entries. + */ + struct GNUNET_FS_ShareTreeItem *parent; + + /** + * This is a doubly-linked tree + * NULL for files and empty directories + */ + struct GNUNET_FS_ShareTreeItem *children_head; + + /** + * This is a doubly-linked tree + * NULL for files and empty directories + */ + struct GNUNET_FS_ShareTreeItem *children_tail; + + /** + * Metadata for this file or directory + */ + struct GNUNET_CONTAINER_MetaData *meta; + + /** + * Keywords for this file or directory (derived from metadata). + */ + struct GNUNET_FS_Uri *ksk_uri; + + /** + * Name of the file/directory + */ + char *filename; + + /** + * Base name of the file/directory. + */ + char *short_filename; + + /** + * GNUNET_YES if this is a directory + */ + int is_directory; + +}; + + +/** + * Opaqe handle to an asynchronous directory scanning activity. + */ +struct GNUNET_FS_DirScanner; + + +/** + * Start a directory scanner. + * + * @param filename name of the directory to scan + * @param disable_extractor GNUNET_YES to not to run libextractor on files (only build a tree) + * @param ex if not NULL, must be a list of extra plugins for extractor + * @param cb the callback to call when there are scanning progress messages + * @param cb_cls closure for 'cb' + * @return directory scanner object to be used for controlling the scanner + */ +struct GNUNET_FS_DirScanner * +GNUNET_FS_directory_scan_start (const char *filename, + int disable_extractor, + const char *ex, + GNUNET_FS_DirScannerProgressCallback cb, + void *cb_cls); + + +/** + * Abort the scan. Must not be called from within the progress_callback + * function. + * + * @param ds directory scanner structure + */ +void +GNUNET_FS_directory_scan_abort (struct GNUNET_FS_DirScanner *ds); + + +/** + * Obtain the result of the scan after the scan has signalled + * completion. Must not be called prior to completion. The 'ds' is + * freed as part of this call. + * + * @param ds directory scanner structure + * @return the results of the scan (a directory tree) + */ +struct GNUNET_FS_ShareTreeItem * +GNUNET_FS_directory_scan_get_result (struct GNUNET_FS_DirScanner *ds); + + +/** + * Process a share item tree, moving frequent keywords up and + * copying frequent metadata up. + * + * @param toplevel toplevel directory in the tree, returned by the scanner + */ +void +GNUNET_FS_share_tree_trim (struct GNUNET_FS_ShareTreeItem *toplevel); + + +/** + * Release memory of a share item tree. + * + * @param toplevel toplevel of the tree to be freed + */ +void +GNUNET_FS_share_tree_free (struct GNUNET_FS_ShareTreeItem *toplevel); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/include/gnunet_getopt_lib.h b/src/include/gnunet_getopt_lib.h new file mode 100644 index 0000000..4b1873c --- /dev/null +++ b/src/include/gnunet_getopt_lib.h @@ -0,0 +1,349 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_getopt_lib.h + * @brief command line parsing and --help formatting + * + * @author Christian Grothoff + */ + +#ifndef GNUNET_GETOPT_LIB_H +#define GNUNET_GETOPT_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_configuration_lib.h" + +/** + * @brief General context for command line processors. + */ +struct GNUNET_GETOPT_CommandLineProcessorContext +{ + + /** + * Name of the application + */ + const char *binaryName; + + /** + * Name of application with option summary + */ + const char *binaryOptions; + + /** + * Array with all command line options. + */ + const struct GNUNET_GETOPT_CommandLineOption *allOptions; + + /** + * Original command line + */ + char *const *argv; + + /** + * Total number of argv's. + */ + unsigned int argc; + + /** + * Current argument. + */ + unsigned int currentArgument; + +}; + +/** + * @brief Process a command line option + * + * @param ctx context for all options + * @param scls specific closure (for this processor) + * @param option long name of the option (i.e. "config" for --config) + * @param value argument, NULL if none was given + * @return GNUNET_OK to continue processing other options, GNUNET_SYSERR to abort + */ +typedef int (*GNUNET_GETOPT_CommandLineOptionProcessor) (struct + GNUNET_GETOPT_CommandLineProcessorContext + * ctx, void *scls, + const char *option, + const char *value); + +/** + * @brief Definition of a command line option. + */ +struct GNUNET_GETOPT_CommandLineOption +{ + + /** + * Short name of the option (use '\\0' for none). + */ + const char shortName; + + /** + * Long name of the option (may not be NULL) + */ + const char *name; + + /** + * Name of the argument for the user in help text + */ + const char *argumentHelp; + + /** + * Help text for the option (description) + */ + const char *description; + + /** + * Is an argument required? 0: GNUNET_NO (includes optional), 1: GNUNET_YES. + */ + int require_argument; + + /** + * Handler for the option. + */ + GNUNET_GETOPT_CommandLineOptionProcessor processor; + + /** + * Specific closure to pass to the processor. + */ + void *scls; + +}; + +/** + * Macro defining the option to print the command line + * help text (-h option). + * + * @param about string with brief description of the application + */ +#define GNUNET_GETOPT_OPTION_HELP(about) \ + { 'h', "help", (const char *) NULL, gettext_noop("print this help"), 0, &GNUNET_GETOPT_format_help_, (void *) about } + + +/** + * Macro defining the option to print the version of + * the application (-v option) + * + * @param version string with the version number + */ +#define GNUNET_GETOPT_OPTION_VERSION(version) \ + { 'v', "version", (const char *) NULL, gettext_noop("print the version number"), 0, &GNUNET_GETOPT_print_version_, (void *) version } + + +/** + * Allow user to specify log file name (-l option) + * + * @param logfn set to the name of the logfile + */ +#define GNUNET_GETOPT_OPTION_LOGFILE(logfn) \ + { 'l', "logfile", "LOGFILE", gettext_noop("configure logging to write logs to LOGFILE"), 1, &GNUNET_GETOPT_set_string, (void *) logfn } + + +/** + * Allow user to specify log level (-L option) + * + * @param loglev set to the log level + */ +#define GNUNET_GETOPT_OPTION_LOGLEVEL(loglev) \ + { 'L', "log", "LOGLEVEL", gettext_noop("configure logging to use LOGLEVEL"), 1, &GNUNET_GETOPT_set_string, (void *) loglev } + + +/** + * Get number of verbose (-V) flags + * + * @param level where to store the verbosity level (should be an 'int') + */ +#define GNUNET_GETOPT_OPTION_VERBOSE(level) \ + { 'V', "verbose", (const char *) NULL, gettext_noop("be verbose"), 0, &GNUNET_GETOPT_increment_value, (void *) level } + + +/** + * Get configuration file name (-c option) + * + * @param fn set to the configuration file name + */ +#define GNUNET_GETOPT_OPTION_CFG_FILE(fn) \ + { 'c', "config", "FILENAME", gettext_noop("use configuration file FILENAME"), 1, &GNUNET_GETOPT_set_string, (void *) fn } + + +/** + * Marker for the end of the list of options. + */ +#define GNUNET_GETOPT_OPTION_END \ + { '\0', NULL, NULL, NULL, 0, NULL, NULL } + + +/** + * Parse the command line. + * + * @param binaryOptions Name of application with option summary + * @param allOptions defined options and handlers + * @param argc number of arguments + * @param argv actual arguments + * @return index into argv with first non-option + * argument, or GNUNET_SYSERR on error + */ +int +GNUNET_GETOPT_run (const char *binaryOptions, + const struct GNUNET_GETOPT_CommandLineOption *allOptions, + unsigned int argc, char *const *argv); + + +/** + * Set an option of type 'unsigned long long' from the command line. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'unsigned long long'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'unsigned long long') + * @param option name of the option + * @param value actual value of the option as a string. + * @return GNUNET_OK if parsing the value worked + */ +int +GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, + void *scls, const char *option, const char *value); + + +/** + * Set an option of type 'unsigned int' from the command line. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'unsigned int'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'unsigned int') + * @param option name of the option + * @param value actual value of the option as a string. + * @return GNUNET_OK if parsing the value worked + */ +int +GNUNET_GETOPT_set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, + void *scls, const char *option, const char *value); + + +/** + * Set an option of type 'int' from the command line to 1 if the + * given option is present. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'int'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'int') + * @param option name of the option + * @param value not used (NULL) + * @return GNUNET_OK + */ +int +GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, + void *scls, const char *option, const char *value); + + +/** + * Set an option of type 'char *' from the command line. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'char *'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'char *', + * which will be allocated) + * @param option name of the option + * @param value actual value of the option (a string) + * @return GNUNET_OK + */ +int +GNUNET_GETOPT_set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, + void *scls, const char *option, const char *value); + +/** + * Set an option of type 'unsigned int' from the command line. Each + * time the option flag is given, the value is incremented by one. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'int'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'int') + * @param option name of the option + * @param value not used (NULL) + * @return GNUNET_OK + */ +int +GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext + *ctx, void *scls, const char *option, + const char *value); + + +/* *************** internal prototypes - use macros above! ************* */ + +/** + * Print out details on command line options (implements --help). + * + * @param ctx command line processing context + * @param scls additional closure (points to about text) + * @param option name of the option + * @param value not used (NULL) + * @return GNUNET_SYSERR (do not continue) + */ +int +GNUNET_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext + *ctx, void *scls, const char *option, + const char *value); + +/** + * Print out program version (implements --version). + * + * @param ctx command line processing context + * @param scls additional closure (points to version string) + * @param option name of the option + * @param value not used (NULL) + * @return GNUNET_SYSERR (do not continue) + */ +int +GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext + *ctx, void *scls, const char *option, + const char *value); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_GETOPT_LIB_H */ +#endif +/* end of gnunet_getopt_lib.h */ diff --git a/src/include/gnunet_gns_service.h b/src/include/gnunet_gns_service.h new file mode 100644 index 0000000..2422178 --- /dev/null +++ b/src/include/gnunet_gns_service.h @@ -0,0 +1,163 @@ +/* + This file is part of GNUnet + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_gns_service.h + * @brief API to the GNS service + * @author Martin Schanzenbach + * + * TODO: + * - decide what goes into storage API and what into GNS-service API + * - decide where to pass/expose/check keys / signatures + * - are GNS private keys per peer or per user? + */ + + +#ifndef GNUNET_GNS_SERVICE_H +#define GNUNET_GNS_SERVICE_H + +#include "gnunet_util_lib.h" +#include "gnunet_namestore_service.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Connection to the GNS service. + */ +struct GNUNET_GNS_Handle; + +/** + * Handle to control a get operation. + */ +struct GNUNET_GNS_LookupHandle; + +/** + * Record types + * Based on GNUNET_DNSPARSER_TYPEs (standard DNS) + */ +enum GNUNET_GNS_RecordType +{ + /* Standard DNS */ + GNUNET_GNS_RECORD_TYPE_A = 1, + GNUNET_GNS_RECORD_TYPE_NS = 2, + GNUNET_GNS_RECORD_TYPE_CNAME = 5, + GNUNET_GNS_RECORD_TYPE_SOA = 6, + GNUNET_GNS_RECORD_TYPE_PTR = 12, + GNUNET_GNS_RECORD_MX = 15, + GNUNET_GNS_RECORD_TXT = 16, + GNUNET_GNS_RECORD_AAAA = 28, + + /* GNS specific */ + GNUNET_GNS_RECORD_PKEY = 256 +}; + +/** + * Initialize the connection with the GNS service. + * FIXME: Do we need the ht_len? + * + * @param cfg configuration to use + * @param ht_len size of the internal hash table to use for parallel lookups + * @return NULL on error + */ +struct GNUNET_GNS_Handle * +GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int ht_len); + + +/** + * Shutdown connection with the GNS service. + * + * @param handle connection to shut down + */ +void +GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle); + + +/* *************** Standard API: lookup ******************* */ + +/** + * Iterator called on each result obtained for a GNS + * lookup + * + * @param cls closure + * @param name "name" of the original lookup + * @param record the records in reply + * @param num_records the number of records in reply + */ +typedef void (*GNUNET_GNS_LookupIterator) (void *cls, + const char * name, + const struct GNUNET_NAMESTORE_RecordData *record, + unsigned int num_records); + + + +/** + * Perform an asynchronous lookup operation on the GNS. + * + * @param handle handle to the GNS service + * @param timeout how long to wait for transmission of this request to the service + * // FIXME: what happens afterwards? + * @param handle handle to the GNS service + * @param timeout timeout of request + * @param name the name to look up + * @param type the GNUNET_GNS_RecordType to look for + * @param iter function to call on each result + * @param iter_cls closure for iter + * + * @return handle to stop the async lookup + */ +struct GNUNET_GNS_LookupHandle * +GNUNET_GNS_lookup_start (struct GNUNET_GNS_Handle *handle, + struct GNUNET_TIME_Relative timeout, + const char * name, + enum GNUNET_GNS_RecordType type, + GNUNET_GNS_LookupIterator iter, + void *iter_cls); + + +/** + * Stop async GNS lookup. Frees associated resources. + * + * @param lookup_handle lookup operation to stop. + * + * On return lookup_handle will no longer be valid, caller + * must not use again!!! + */ +void +GNUNET_GNS_lookup_stop (struct GNUNET_GNS_LookupHandle *lookup_handle); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +#endif +/* gnunet_gns_service.h */ diff --git a/src/include/gnunet_hello_lib.h b/src/include/gnunet_hello_lib.h new file mode 100644 index 0000000..ffddb0b --- /dev/null +++ b/src/include/gnunet_hello_lib.h @@ -0,0 +1,336 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_hello_lib.h + * @brief helper library for handling HELLOs + * @author Christian Grothoff + */ + +#ifndef GNUNET_HELLO_LIB_H +#define GNUNET_HELLO_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" + + +/** + * An address for communicating with a peer. We frequently + * need this tuple and the components cannot really be + * separated. This is NOT the format that would be used + * on the wire. + */ +struct GNUNET_HELLO_Address +{ + + /** + * For which peer is this an address? + */ + struct GNUNET_PeerIdentity peer; + + /** + * Name of the transport plugin enabling the communication using + * this address. + */ + const char *transport_name; + + /** + * Binary representation of the address (plugin-specific). + */ + const void *address; + + /** + * Number of bytes in 'address'. + */ + size_t address_length; + +}; + + +/** + * Allocate an address struct. + * + * @param peer the peer + * @param transport_name plugin name + * @param address binary address + * @param address_length number of bytes in 'address' + * @return the address struct + */ +struct GNUNET_HELLO_Address * +GNUNET_HELLO_address_allocate (const struct GNUNET_PeerIdentity *peer, + const char *transport_name, const void *address, + size_t address_length); + + +/** + * Copy an address struct. + * + * @param address address to copy + * @return a copy of the address struct + */ +struct GNUNET_HELLO_Address * +GNUNET_HELLO_address_copy (const struct GNUNET_HELLO_Address *address); + + +/** + * Compare two addresses. Does NOT compare the peer identity, + * that is assumed already to match! + * + * @param a1 first address + * @param a2 second address + * @return 0 if the addresses are equal, -1 if a1a2. + */ +int +GNUNET_HELLO_address_cmp (const struct GNUNET_HELLO_Address *a1, + const struct GNUNET_HELLO_Address *a2); + + +/** + * Get the size of an address struct. + * + * @param address address + * @return the size + */ +size_t +GNUNET_HELLO_address_get_size (const struct GNUNET_HELLO_Address *address); + +/** + * Free an address. + * + * @param addr address to free + */ +#define GNUNET_HELLO_address_free(addr) GNUNET_free(addr) + + +/** + * A HELLO message is used to exchange information about + * transports with other peers. This struct is guaranteed + * to start with a "GNUNET_MessageHeader", everything else + * should be internal to the HELLO library. + */ +struct GNUNET_HELLO_Message; + + +/** + * Copy the given address information into + * the given buffer using the format of HELLOs. + * + * @param address address to add + * @param expiration expiration for the address + * @param target where to copy the address + * @param max maximum number of bytes to copy to target + * @return number of bytes copied, 0 if + * the target buffer was not big enough. + */ +size_t +GNUNET_HELLO_add_address (const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration, char *target, + size_t max); + + +/** + * Callback function used to fill a buffer of max bytes with a list of + * addresses in the format used by HELLOs. Should use + * "GNUNET_HELLO_add_address" as a helper function. + * + * @param cls closure + * @param max maximum number of bytes that can be written to buf + * @param buf where to write the address information + * @return number of bytes written, 0 to signal the + * end of the iteration. + */ +typedef size_t (*GNUNET_HELLO_GenerateAddressListCallback) (void *cls, + size_t max, + void *buf); + + +/** + * Construct a HELLO message given the public key, + * expiration time and an iterator that spews the + * transport addresses. + * + * @return the hello message + */ +struct GNUNET_HELLO_Message * +GNUNET_HELLO_create (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *publicKey, + GNUNET_HELLO_GenerateAddressListCallback addrgen, + void *addrgen_cls); + + +/** + * Return the size of the given HELLO message. + * @param hello to inspect + * @return the size, 0 if HELLO is invalid + */ +uint16_t +GNUNET_HELLO_size (const struct GNUNET_HELLO_Message *hello); + + +/** + * Construct a HELLO message by merging the + * addresses in two existing HELLOs (which + * must be for the same peer). + * + * @param h1 first HELLO message + * @param h2 the second HELLO message + * @return the combined hello message + */ +struct GNUNET_HELLO_Message * +GNUNET_HELLO_merge (const struct GNUNET_HELLO_Message *h1, + const struct GNUNET_HELLO_Message *h2); + + +/** + * Test if two HELLO messages contain the same addresses. + * If they only differ in expiration time, the lowest + * expiration time larger than 'now' where they differ + * is returned. + * + * @param h1 first HELLO message + * @param h2 the second HELLO message + * @param now time to use for deciding which addresses have + * expired and should not be considered at all + * @return absolute time forever if the two HELLOs are + * totally identical; smallest timestamp >= now if + * they only differ in timestamps; + * zero if the some addresses with expirations >= now + * do not match at all + */ +struct GNUNET_TIME_Absolute +GNUNET_HELLO_equals (const struct GNUNET_HELLO_Message *h1, + const struct GNUNET_HELLO_Message *h2, + struct GNUNET_TIME_Absolute now); + + +/** + * Iterator callback to go over all addresses. + * + * @param cls closure + * @param address the address + * @param expiration expiration time + * @return GNUNET_OK to keep the address, + * GNUNET_NO to delete it from the HELLO + * GNUNET_SYSERR to stop iterating (but keep current address) + */ +typedef int (*GNUNET_HELLO_AddressIterator) (void *cls, + const struct GNUNET_HELLO_Address * + address, + struct GNUNET_TIME_Absolute + expiration); + + +/** + * When does the last address in the given HELLO expire? + * + * @param msg HELLO to inspect + * @return time the last address expires, 0 if there are no addresses in the HELLO + */ +struct GNUNET_TIME_Absolute +GNUNET_HELLO_get_last_expiration (const struct GNUNET_HELLO_Message *msg); + + +/** + * Iterate over all of the addresses in the HELLO. + * + * @param msg HELLO to iterate over; client does not need to + * have verified that msg is well-formed (beyond starting + * with a GNUNET_MessageHeader of the right type). + * @param return_modified if a modified copy should be returned, + * otherwise NULL will be returned + * @param it iterator to call on each address + * @param it_cls closure for it + * @return the modified HELLO or NULL + */ +struct GNUNET_HELLO_Message * +GNUNET_HELLO_iterate_addresses (const struct GNUNET_HELLO_Message *msg, + int return_modified, + GNUNET_HELLO_AddressIterator it, void *it_cls); + + +/** + * Iterate over addresses in "new_hello" that + * are NOT already present in "old_hello". + * + * @param new_hello a HELLO message + * @param old_hello a HELLO message + * @param expiration_limit ignore addresses in old_hello + * that expired before the given time stamp + * @param it iterator to call on each address + * @param it_cls closure for it + */ +void +GNUNET_HELLO_iterate_new_addresses (const struct GNUNET_HELLO_Message + *new_hello, + const struct GNUNET_HELLO_Message + *old_hello, + struct GNUNET_TIME_Absolute + expiration_limit, + GNUNET_HELLO_AddressIterator it, + void *it_cls); + + +/** + * Get the public key from a HELLO message. + * + * @param hello the hello message + * @param publicKey where to copy the public key information, can be NULL + * @return GNUNET_SYSERR if the HELLO was malformed + */ +int +GNUNET_HELLO_get_key (const struct GNUNET_HELLO_Message *hello, + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *publicKey); + + +/** + * Get the peer identity from a HELLO message. + * + * @param hello the hello message + * @param peer where to store the peer's identity + * @return GNUNET_SYSERR if the HELLO was malformed + */ +int +GNUNET_HELLO_get_id (const struct GNUNET_HELLO_Message *hello, + struct GNUNET_PeerIdentity *peer); + + +/** + * Get the header from a HELLO message, used so other code + * can correctly send HELLO messages. + * + * @param hello the hello message + * + * @return header or NULL if the HELLO was malformed + */ +struct GNUNET_MessageHeader * +GNUNET_HELLO_get_header (struct GNUNET_HELLO_Message *hello); + +/* ifndef GNUNET_HELLO_LIB_H */ +#endif +/* end of gnunet_hello_lib.h */ diff --git a/src/include/gnunet_helper_lib.h b/src/include/gnunet_helper_lib.h new file mode 100644 index 0000000..7115748 --- /dev/null +++ b/src/include/gnunet_helper_lib.h @@ -0,0 +1,96 @@ +/* + This file is part of GNUnet. + (C) 2011, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_helper_lib.h + * @brief API for dealing with (SUID) helper processes that communicate via GNUNET_MessageHeaders on stdin/stdout + * @author Philipp Toelke + * @author Christian Grothoff + */ +#ifndef GNUNET_HELPER_LIB_H +#define GNUNET_HELPER_LIB_H + +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" + +/** + * The handle to a helper process. + */ +struct GNUNET_HELPER_Handle; + + +/** + * @brief Starts a helper and begins reading from it + * + * @param binary_name name of the binary to run + * @param binary_argv NULL-terminated list of arguments to give when starting the binary (this + * argument must not be modified by the client for + * the lifetime of the helper handle) + * @param cb function to call if we get messages from the helper + * @param cb_cls Closure for the callback + * @return the new Handle, NULL on error + */ +struct GNUNET_HELPER_Handle * +GNUNET_HELPER_start (const char *binary_name, + char *const binary_argv[], + GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls); + + +/** + * @brief Kills the helper, closes the pipe and frees the handle + * + * @param h handle to helper to stop + */ +void +GNUNET_HELPER_stop (struct GNUNET_HELPER_Handle *h); + + +/** + * Continuation function. + * + * @param cls closure + * @param result GNUNET_OK on success, + * GNUNET_NO if helper process died + * GNUNET_SYSERR during GNUNET_HELPER_stop + */ +typedef void (*GNUNET_HELPER_Continuation)(void *cls, + int result); + + +/** + * Send an message to the helper. + * + * @param h helper to send message to + * @param msg message to send + * @param can_drop can the message be dropped if there is already one in the queue? + * @param cont continuation to run once the message is out + * @param cont_cls closure for 'cont' + * @return GNUNET_YES if the message will be sent + * GNUNET_NO if the message was dropped + */ +int +GNUNET_HELPER_send (struct GNUNET_HELPER_Handle *h, + const struct GNUNET_MessageHeader *msg, + int can_drop, + GNUNET_HELPER_Continuation cont, + void *cont_cls); + + +#endif /* end of include guard: GNUNET_HELPER_LIB_H */ diff --git a/src/include/gnunet_load_lib.h b/src/include/gnunet_load_lib.h new file mode 100644 index 0000000..6dfe80c --- /dev/null +++ b/src/include/gnunet_load_lib.h @@ -0,0 +1,119 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_load_lib.h + * @brief functions related to load calculations + * @author Christian Grothoff + */ + +#ifndef GNUNET_LOAD_LIB_H +#define GNUNET_LOAD_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_time_lib.h" + +/** + * Opaque load handle. + */ +struct GNUNET_LOAD_Value; + +/** + * Create a new load value. + * + * @param autodecline speed at which this value should automatically + * decline in the absence of external events; at the given + * frequency, 0-load values will be added to the load + * @return the new load value + */ +struct GNUNET_LOAD_Value * +GNUNET_LOAD_value_init (struct GNUNET_TIME_Relative autodecline); + + +/** + * Change the value by which the load automatically declines. + * + * @param load load to update + * @param autodecline frequency of load decline + */ +void +GNUNET_LOAD_value_set_decline (struct GNUNET_LOAD_Value *load, + struct GNUNET_TIME_Relative autodecline); + + +/** + * Free a load value. + * + * @param lv value to free + */ +#define GNUNET_LOAD_value_free(lv) GNUNET_free (lv) + + +/** + * Get the current load. + * + * @param load load handle + * @return zero for below-average load, otherwise + * number of std. devs we are above average; + * 100 if the latest updates were so large + * that we could not do proper calculations + */ +double +GNUNET_LOAD_get_load (struct GNUNET_LOAD_Value *load); + + +/** + * Get the average value given to update so far. + * + * @param load load handle + * @return zero if update was never called + */ +double +GNUNET_LOAD_get_average (struct GNUNET_LOAD_Value *load); + + +/** + * Update the current load. + * + * @param load to update + * @param data latest measurement value (for example, delay) + */ +void +GNUNET_LOAD_update (struct GNUNET_LOAD_Value *load, uint64_t data); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_LOAD_LIB_H */ +#endif +/* end of gnunet_load_lib.h */ diff --git a/src/include/gnunet_mesh_service.h b/src/include/gnunet_mesh_service.h new file mode 100644 index 0000000..7c2437e --- /dev/null +++ b/src/include/gnunet_mesh_service.h @@ -0,0 +1,358 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_mesh_service.h + * @brief mesh service; establish tunnels to distant peers + * @author Christian Grothoff + */ + +#ifndef GNUNET_MESH_SERVICE_H +#define GNUNET_MESH_SERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" + +/** + * Version number of GNUnet-mesh API. + */ +#define GNUNET_MESH_VERSION 0x00000000 + + +/** + * Opaque handle to the service. + */ +struct GNUNET_MESH_Handle; + +/** + * Opaque handle to a tunnel. + */ +struct GNUNET_MESH_Tunnel; + +/** + * Functions with this signature are called whenever a message is + * received. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx place to store local state associated with the tunnel + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +typedef int (*GNUNET_MESH_MessageCallback) (void *cls, + struct GNUNET_MESH_Tunnel * tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity * + sender, + const struct GNUNET_MessageHeader * + message, + const struct GNUNET_ATS_Information + * atsi); + + +/** + * Message handler. Each struct specifies how to handle on particular + * type of message received. + */ +struct GNUNET_MESH_MessageHandler +{ + /** + * Function to call for messages of "type". + */ + GNUNET_MESH_MessageCallback callback; + + /** + * Type of the message this handler covers. + */ + uint16_t type; + + /** + * Expected size of messages of this type. Use 0 for variable-size. + * If non-zero, messages of the given type will be discarded if they + * do not have the right size. + */ + uint16_t expected_size; + +}; + + +/** + * Method called whenever another peer has added us to a tunnel + * the other peer initiated. + * + * @param cls closure + * @param tunnel new handle to the tunnel + * @param initiator peer that started the tunnel + * @param atsi performance information for the tunnel + * @return initial tunnel context for the tunnel + * (can be NULL -- that's not an error) + */ +typedef void *(GNUNET_MESH_InboundTunnelNotificationHandler) (void *cls, + struct + GNUNET_MESH_Tunnel + * tunnel, + const struct + GNUNET_PeerIdentity + * initiator, + const struct + GNUNET_ATS_Information + * atsi); + + +/** + * Function called whenever an inbound tunnel is destroyed. Should clean up + * any associated state. This function is NOT called if the client has + * explicitly asked for the tunnel to be destroyed using + * GNUNET_MESH_tunnel_destroy. It must NOT call GNUNET_MESH_tunnel_destroy on + * the tunnel. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end (henceforth invalid) + * @param tunnel_ctx place where local state associated + * with the tunnel is stored + */ +typedef void (GNUNET_MESH_TunnelEndHandler) (void *cls, + const struct GNUNET_MESH_Tunnel * + tunnel, void *tunnel_ctx); + + +/** + * Type for an application. Values defined in gnunet_applications.h + */ +typedef uint32_t GNUNET_MESH_ApplicationType; + + +/** + * Connect to the mesh service. + * + * @param cfg configuration to use + * @param queue_size size of the data message queue, shared among all tunnels + * (each tunnel is guaranteed to accept at least one message, + * no matter what is the status of other tunnels) + * @param cls closure for the various callbacks that follow + * (including handlers in the handlers array) + * @param new_tunnel function called when an *inbound* tunnel is created + * @param cleaner function called when an *inbound* tunnel is destroyed by the + * remote peer, it is *not* called if GNUNET_MESH_tunnel_destroy + * is called on the tunnel + * @param handlers callbacks for messages we care about, NULL-terminated + * note that the mesh is allowed to drop notifications about + * inbound messages if the client does not process them fast + * enough (for this notification type, a bounded queue is used) + * @param stypes list of the applications that this client claims to provide + * @return handle to the mesh service NULL on error + * (in this case, init is never called) + */ +struct GNUNET_MESH_Handle * +GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int queue_size, void *cls, + GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel, + GNUNET_MESH_TunnelEndHandler cleaner, + const struct GNUNET_MESH_MessageHandler *handlers, + const GNUNET_MESH_ApplicationType *stypes); + + +/** + * Disconnect from the mesh service. All tunnels will be destroyed. All tunnel + * disconnect callbacks will be called on any still connected peers, notifying + * about their disconnection. The registered inbound tunnel cleaner will be + * called should any inbound tunnels still exist. + * + * @param handle connection to mesh to disconnect + */ +void +GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle); + + +/** + * Method called whenever a peer has disconnected from the tunnel. + * Implementations of this callback must NOT call + * GNUNET_MESH_tunnel_destroy immediately, but instead schedule those + * to run in some other task later. However, calling + * "GNUNET_MESH_notify_transmit_ready_cancel" is allowed. + * + * @param cls closure + * @param peer peer identity the tunnel stopped working with + */ +typedef void (*GNUNET_MESH_PeerDisconnectHandler) (void *cls, + const struct + GNUNET_PeerIdentity * peer); + + +/** + * Method called whenever a peer has connected to the tunnel. + * + * @param cls closure + * @param peer peer identity the tunnel was created to, NULL on timeout + * @param atsi performance data for the connection + * + * TODO: change to return int to let client allow the new peer or not? + */ +typedef void (*GNUNET_MESH_PeerConnectHandler) (void *cls, + const struct GNUNET_PeerIdentity + * peer, + const struct + GNUNET_ATS_Information * atsi); + + + +/** + * Create a new tunnel (we're initiator and will be allowed to add/remove peers + * and to broadcast). + * + * @param h mesh handle + * @param tunnel_ctx client's tunnel context to associate with the tunnel + * @param connect_handler function to call when peers are actually connected + * @param disconnect_handler function to call when peers are disconnected + * @param handler_cls closure for connect/disconnect handlers + */ +struct GNUNET_MESH_Tunnel * +GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx, + GNUNET_MESH_PeerConnectHandler connect_handler, + GNUNET_MESH_PeerDisconnectHandler disconnect_handler, + void *handler_cls); + +/** + * Destroy an existing tunnel. The existing callback for the tunnel will NOT + * be called. + * + * @param tunnel tunnel handle + */ +void +GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tunnel); + + +/** + * Request that a peer should be added to the tunnel. The connect handler + * will be called when the peer connects + * + * @param tunnel handle to existing tunnel + * @param peer peer to add + */ +void +GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *peer); + + +/** + * Request that a peer should be removed from the tunnel. The existing + * disconnect handler will be called ONCE if we were connected. + * + * @param tunnel handle to existing tunnel + * @param peer peer to remove + */ +void +GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *peer); + + +/** + * Request that the mesh should try to connect to a peer supporting the given + * message type. + * + * @param tunnel handle to existing tunnel + * @param app_type application type that must be supported by the peer + * (MESH should discover peer in proximity handling this type) + */ +void +GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel, + GNUNET_MESH_ApplicationType app_type); + + +/** + * Handle for a transmission request. + */ +struct GNUNET_MESH_TransmitHandle; + + +/** + * Ask the mesh to call "notify" once it is ready to transmit the + * given number of bytes to the specified tunnel or target. + * + * @param tunnel tunnel to use for transmission + * @param cork is corking allowed for this transmission? + * @param priority how important is the message? + * @param maxdelay how long can the message wait? + * @param target destination for the message + * NULL for multicast to all tunnel targets + * @param notify_size how many bytes of buffer space does notify want? + * @param notify function to call when buffer space is available; + * will be called with NULL on timeout or if the overall queue + * for this peer is larger than queue_size and this is currently + * the message with the lowest priority + * @param notify_cls closure for notify + * @return non-NULL if the notify callback was queued, + * NULL if we can not even queue the request (insufficient + * memory); if NULL is returned, "notify" will NOT be called. + */ +struct GNUNET_MESH_TransmitHandle * +GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork, + uint32_t priority, + struct GNUNET_TIME_Relative maxdelay, + const struct GNUNET_PeerIdentity *target, + size_t notify_size, + GNUNET_CONNECTION_TransmitReadyNotify notify, + void *notify_cls); + + +/** + * Cancel the specified transmission-ready notification. + * + * @param th handle that was returned by "notify_transmit_ready". + */ +void +GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle + *th); + + +/** + * Transition API for tunnel ctx management + */ +void +GNUNET_MESH_tunnel_set_data (struct GNUNET_MESH_Tunnel *tunnel, void *data); + +/** + * Transition API for tunnel ctx management + */ +void * +GNUNET_MESH_tunnel_get_data (struct GNUNET_MESH_Tunnel *tunnel); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_MESH_SERVICE_H */ +#endif +/* end of gnunet_mesh_service.h */ diff --git a/src/include/gnunet_namestore_plugin.h b/src/include/gnunet_namestore_plugin.h new file mode 100644 index 0000000..5468513 --- /dev/null +++ b/src/include/gnunet_namestore_plugin.h @@ -0,0 +1,152 @@ +/* + This file is part of GNUnet + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_namestore_plugin.h + * @brief plugin API for the namestore database backend + * @author Christian Grothoff + */ +#ifndef GNUNET_NAMESTORE_PLUGIN_H +#define GNUNET_NAMESTORE_PLUGIN_H + +#include "gnunet_common.h" +#include "gnunet_util_lib.h" +#include "gnunet_namestore_service.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Function called by for each matching record. + * + * @param cls closure + * @param zone_key public key of the zone + * @param expire when does the corresponding block in the DHT expire (until + * when should we never do a DHT lookup for the same name again)? + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature of the record block, NULL if signature is unavailable (i.e. + * because the user queried for a particular record type only) + */ +typedef void (*GNUNET_NAMESTORE_RecordIterator) (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature); + + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct GNUNET_NAMESTORE_PluginFunctions +{ + + /** + * Closure to pass to all plugin functions. + */ + void *cls; + + /** + * Store a record in the datastore. Removes any existing record in the + * same zone with the same name. + * + * @param cls closure (internal context for the plugin) + * @param zone_key public key of the zone + * @param expire when does the corresponding block in the DHT expire (until + * when should we never do a DHT lookup for the same name again)? + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature of the record block, NULL if signature is unavailable (i.e. + * because the user queried for a particular record type only) + * @return GNUNET_OK on success + */ + int (*put_records) (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature); + + + /** + * Removes any existing record in the given zone with the same name. + * + * @param cls closure (internal context for the plugin) + * @param zone hash of the public key of the zone + * @param name name to remove (at most 255 characters long) + * @return GNUNET_OK on success + */ + int (*remove_records) (void *cls, + const GNUNET_HashCode *zone, + const char *name); + + + /** + * Iterate over the results for a particular key and zone in the + * datastore. Will return at most one result to the iterator. + * + * @param cls closure (internal context for the plugin) + * @param zone hash of public key of the zone, NULL to iterate over all zones + * @param name_hash hash of name, NULL to iterate over all records of the zone + * @param offset offset in the list of all matching records + * @param iter function to call with the result + * @param iter_cls closure for iter + * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error + */ + int (*iterate_records) (void *cls, + const GNUNET_HashCode *zone, + const GNUNET_HashCode *name_hash, + uint64_t offset, + GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls); + + + /** + * Delete an entire zone (all records). Not used in normal operation. + * + * @param cls closure (internal context for the plugin) + * @param zone zone to delete + */ + void (*delete_zone) (void *cls, + const GNUNET_HashCode *zone); + + +}; + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* end of gnunet_namestore_plugin.h */ +#endif diff --git a/src/include/gnunet_namestore_service.h b/src/include/gnunet_namestore_service.h new file mode 100644 index 0000000..8ab2ce8 --- /dev/null +++ b/src/include/gnunet_namestore_service.h @@ -0,0 +1,368 @@ +/* + This file is part of GNUnet + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_namestore_service.h + * @brief API that can be used to store naming information on a GNUnet node; + * @author Christian Grothoff + * + * Other functions we might want: + * - enumerate all known zones + * - convenience function to gather record and the full affilliated stree + * in one shot + */ + +#ifndef GNUNET_NAMESTORE_SERVICE_H +#define GNUNET_NAMESTORE_SERVICE_H + +#include "gnunet_util_lib.h" +#include "gnunet_block_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * Entry in the queue. + */ +struct GNUNET_NAMESTORE_QueueEntry; + +/** + * Handle to the namestore service. + */ +struct GNUNET_NAMESTORE_Handle; + +/** + * Handle to the namestore zone iterator. + */ +struct GNUNET_NAMESTORE_ZoneIterator; + +/** + * Maximum size of a value that can be stored in the namestore. + */ +#define GNUNET_NAMESTORE_MAX_VALUE_SIZE (63 * 1024) + +/** + * Connect to the namestore service. + * + * @param cfg configuration to use + * @return handle to use to access the service + */ +struct GNUNET_NAMESTORE_Handle * +GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Disconnect from the namestore service (and free associated + * resources). + * + * @param h handle to the namestore + * @param drop set to GNUNET_YES to delete all data in namestore (!) + */ +void +GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h, int drop); + + +/** + * Continuation called to notify client about result of the + * operation. + * + * @param cls closure + * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) + * GNUNET_NO if content was already there + * GNUNET_YES (or other positive value) on success + * @param emsg NULL on success, otherwise an error message + */ +typedef void (*GNUNET_NAMESTORE_ContinuationWithStatus) (void *cls, + int32_t success, + const char *emsg); + + +/** + * Flags that can be set for a record. + */ +enum GNUNET_NAMESTORE_RecordFlags +{ + + /** + * No special options. + */ + GNUNET_NAMESTORE_RF_NONE = 0, + + /** + * This peer is the authority for this record; it must thus + * not be deleted (other records can be deleted if we run + * out of space). + */ + GNUNET_NAMESTORE_RF_AUTHORITY = 1, + + /** + * This is a private record of this peer and it should + * thus not be handed out to other peers. + */ + GNUNET_NAMESTORE_RF_PRIVATE = 2 + +}; + + +/** + * A GNS record. + */ +struct GNUNET_NAMESTORE_RecordData +{ + + /** + * Binary value stored in the DNS record. + */ + const void *data; + + /** + * Expiration time for the DNS record. + */ + struct GNUNET_TIME_Absolute expiration; + + /** + * Number of bytes in 'data'. + */ + size_t data_size; + + /** + * Type of the GNS/DNS record. + */ + uint32_t record_type; + + /** + * Flags for the record. + */ + enum GNUNET_NAMESTORE_RecordFlags flags; +}; + + +/** + * Store an item in the namestore. If the item is already present, + * the expiration time is updated to the max of the existing time and + * the new time. This API is used when we cache signatures from other + * authorities. + * + * @param h handle to the namestore + * @param zone_key public key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param expire when does the corresponding block in the DHT expire (until + * when should we never do a DHT lookup for the same name again)? + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature for all the records in the zone under the given name + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return handle to abort the request + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_record_put (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + const char *name, + struct GNUNET_TIME_Absolute expire, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls); + + +/** + * Check if a signature is valid. This API is used by the GNS Block + * to validate signatures received from the network. + * + * @param public_key public key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature for all the records in the zone under the given name + * @return GNUNET_OK if the signature is valid + */ +int +GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature); + + +/** + * Store an item in the namestore. If the item is already present, + * the expiration time is updated to the max of the existing time and + * the new time. This API is used by the authority of a zone. + * + * @param h handle to the namestore + * @param pkey private key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param rd record data to store + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return handle to abort the request + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_record_create (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, + const char *name, + const struct GNUNET_NAMESTORE_RecordData *rd, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls); + + +/** + * Explicitly remove some content from the database. The + * "cont"inuation will be called with status "GNUNET_OK" if content + * was removed, "GNUNET_NO" if no matching entry was found and + * "GNUNET_SYSERR" on all other types of errors. + * This API is used by the authority of a zone. + * + * @param h handle to the namestore + * @param pkey private key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param rd record data + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return handle to abort the request + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_record_remove (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, + const char *name, + const struct GNUNET_NAMESTORE_RecordData *rd, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls); + + +/** + * Process a record that was stored in the namestore. + * + * @param cls closure + * @param zone_key public key of the zone + * @param expire when does the corresponding block in the DHT expire (until + * when should we never do a DHT lookup for the same name again)?; + * GNUNET_TIME_UNIT_ZERO_ABS if there are no records of any type in the namestore, + * or the expiration time of the block in the namestore (even if there are zero + * records matching the desired record type) + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature of the record block, NULL if signature is unavailable (i.e. + * because the user queried for a particular record type only) + */ +typedef void (*GNUNET_NAMESTORE_RecordProcessor) (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature); + + +/** + * Get a result for a particular key from the namestore. The processor + * will only be called once. + * + * @param h handle to the namestore + * @param zone zone to look up a record from + * @param name name to look up + * @param record_type desired record type, 0 for all + * @param proc function to call on the matching records, or with + * NULL (rd_count == 0) if there are no matching records + * @param proc_cls closure for proc + * @return a handle that can be used to + * cancel + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_lookup_record (struct GNUNET_NAMESTORE_Handle *h, + const GNUNET_HashCode *zone, + const char *name, + uint32_t record_type, + GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls); + + +/** + * Starts a new zone iteration (used to periodically PUT all of our + * records into our DHT). This MUST lock the GNUNET_NAMESTORE_Handle + * for any other calls than GNUNET_NAMESTORE_zone_iterator_next and + * GNUNET_NAMESTORE_zone_iteration_stop. "proc" will be called once + * immediately, and then again after + * "GNUNET_NAMESTORE_zone_iterator_next" is invoked. + * + * @param h handle to the namestore + * @param zone zone to access, NULL for all zones + * @param must_have_flags flags that must be set for the record to be returned + * @param must_not_have_flags flags that must NOT be set for the record to be returned + * @param proc function to call on each name from the zone; it + * will be called repeatedly with a value (if available) + * and always once at the end with a name of NULL. + * @param proc_cls closure for proc + * @return an iterator handle to use for iteration + */ +struct GNUNET_NAMESTORE_ZoneIterator * +GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h, + const GNUNET_HashCode *zone, + enum GNUNET_NAMESTORE_RecordFlags must_have_flags, + enum GNUNET_NAMESTORE_RecordFlags must_not_have_flags, + GNUNET_NAMESTORE_RecordProcessor proc, + void *proc_cls); + + +/** + * Calls the record processor specified in GNUNET_NAMESTORE_zone_iteration_start + * for the next record. + * + * @param it the iterator + */ +void +GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it); + + +/** + * Stops iteration and releases the namestore handle for further calls. + * + * @param it the iterator + */ +void +GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it); + + +/** + * Cancel a namestore operation. The final callback from the + * operation must not have been done yet. + * + * @param qe operation to cancel + */ +void +GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* end of gnunet_namestore_service.h */ +#endif diff --git a/src/include/gnunet_nat_lib.h b/src/include/gnunet_nat_lib.h new file mode 100644 index 0000000..6c1db80 --- /dev/null +++ b/src/include/gnunet_nat_lib.h @@ -0,0 +1,256 @@ +/* + This file is part of GNUnet. + (C) 2007, 2008, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_nat_lib.h + * @brief Library handling UPnP and NAT-PMP port forwarding and + * external IP address retrieval + * + * @author Milan Bouchet-Valat + */ + +#ifndef GNUNET_NAT_LIB_H +#define GNUNET_NAT_LIB_H + +#include "gnunet_util_lib.h" + +/** + * Signature of the callback passed to GNUNET_NAT_register for + * a function to call whenever our set of 'valid' addresses changes. + * + * @param cls closure + * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean + * the previous (now invalid) one + * @param addr either the previous or the new public IP address + * @param addrlen actual lenght of the address + */ +typedef void (*GNUNET_NAT_AddressCallback) (void *cls, int add_remove, + const struct sockaddr * addr, + socklen_t addrlen); + + +/** + * Signature of the callback passed to GNUNET_NAT_register + * for a function to call whenever someone asks us to do connection + * reversal. + * + * @param cls closure + * @param addr public IP address of the other peer + * @param addrlen actual lenght of the address + */ +typedef void (*GNUNET_NAT_ReversalCallback) (void *cls, + const struct sockaddr * addr, + socklen_t addrlen); + + +/** + * Handle for active NAT registrations. + */ +struct GNUNET_NAT_Handle; + + +/** + * Attempt to enable port redirection and detect public IP address contacting + * UPnP or NAT-PMP routers on the local network. Use addr to specify to which + * of the local host's addresses should the external port be mapped. The port + * is taken from the corresponding sockaddr_in[6] field. The NAT module + * should call the given callback for any 'plausible' external address. + * + * @param cfg configuration to use + * @param is_tcp GNUNET_YES for TCP, GNUNET_NO for UDP + * @param adv_port advertised port (port we are either bound to or that our OS + * locally performs redirection from to our bound port). + * @param num_addrs number of addresses in 'addrs' + * @param addrs list of local addresses packets should be redirected to + * @param addrlens actual lengths of the addresses + * @param address_callback function to call everytime the public IP address changes + * @param reversal_callback function to call if someone wants connection reversal from us, + * NULL if connection reversal is not supported + * @param callback_cls closure for callback + * @return NULL on error, otherwise handle that can be used to unregister + */ +struct GNUNET_NAT_Handle * +GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, int is_tcp, + uint16_t adv_port, unsigned int num_addrs, + const struct sockaddr **addrs, const socklen_t * addrlens, + GNUNET_NAT_AddressCallback address_callback, + GNUNET_NAT_ReversalCallback reversal_callback, + void *callback_cls); + + +/** + * Test if the given address is (currently) a plausible IP address for this peer. + * + * @param h the handle returned by register + * @param addr IP address to test (IPv4 or IPv6) + * @param addrlen number of bytes in addr + * @return GNUNET_YES if the address is plausible, + * GNUNET_NO if the address is not plausible, + * GNUNET_SYSERR if the address is malformed + */ +int +GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *h, const void *addr, + socklen_t addrlen); + + +/** + * We learned about a peer (possibly behind NAT) so run the + * gnunet-nat-client to send dummy ICMP responses to cause + * that peer to connect to us (connection reversal). + * + * @param h handle (used for configuration) + * @param sa the address of the peer (IPv4-only) + */ +void +GNUNET_NAT_run_client (struct GNUNET_NAT_Handle *h, + const struct sockaddr_in *sa); + + + +/** + * Stop port redirection and public IP address detection for the given handle. + * This frees the handle, after having sent the needed commands to close open ports. + * + * @param h the handle to stop + */ +void +GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h); + + +/** + * Handle to a NAT test. + */ +struct GNUNET_NAT_Test; + +/** + * Function called to report success or failure for + * NAT configuration test. + * + * @param cls closure + * @param success GNUNET_OK on success, GNUNET_NO on failure, + * GNUNET_SYSERR if the test could not be + * properly started (internal failure) + */ +typedef void (*GNUNET_NAT_TestCallback) (void *cls, int success); + +/** + * Start testing if NAT traversal works using the + * given configuration (IPv4-only). + * + * @param cfg configuration for the NAT traversal + * @param is_tcp GNUNET_YES to test TCP, GNUNET_NO to test UDP + * @param bnd_port port to bind to, 0 for connection reversal + * @param adv_port externally advertised port to use + * @param report function to call with the result of the test + * @param report_cls closure for report + * @return handle to cancel NAT test + */ +struct GNUNET_NAT_Test * +GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + int is_tcp, uint16_t bnd_port, uint16_t adv_port, + GNUNET_NAT_TestCallback report, void *report_cls); + + +/** + * Stop an active NAT test. + * + * @param tst test to stop. + */ +void +GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst); + + +/** + * Signature of a callback that is given an IP address. + * + * @param cls closure + * @param addr the address, NULL on errors + */ +typedef void (*GNUNET_NAT_IPCallback) (void *cls, const struct in_addr * addr); + + + +/** + * Opaque handle to cancel "GNUNET_NAT_mini_get_external_ipv4" operation. + */ +struct GNUNET_NAT_ExternalHandle; + + +/** + * Try to get the external IPv4 address of this peer. + * + * @param timeout when to fail + * @param cb function to call with result + * @param cb_cls closure for 'cb' + * @return handle for cancellation (can only be used until 'cb' is called), NULL on error + */ +struct GNUNET_NAT_ExternalHandle * +GNUNET_NAT_mini_get_external_ipv4 (struct GNUNET_TIME_Relative timeout, + GNUNET_NAT_IPCallback cb, void *cb_cls); + + +/** + * Cancel operation. + * + * @param eh operation to cancel + */ +void +GNUNET_NAT_mini_get_external_ipv4_cancel (struct GNUNET_NAT_ExternalHandle *eh); + + +/** + * Handle to a mapping created with upnpc. + */ +struct GNUNET_NAT_MiniHandle; + + +/** + * Start mapping the given port using (mini)upnpc. This function + * should typically not be used directly (it is used within the + * general-purpose 'GNUNET_NAT_register' code). However, it can be + * used if specifically UPnP-based NAT traversal is to be used or + * tested. + * + * @param port port to map + * @param is_tcp GNUNET_YES to map TCP, GNUNET_NO for UDP + * @param ac function to call with mapping result + * @param ac_cls closure for 'ac' + * @return NULL on error + */ +struct GNUNET_NAT_MiniHandle * +GNUNET_NAT_mini_map_start (uint16_t port, int is_tcp, + GNUNET_NAT_AddressCallback ac, void *ac_cls); + + +/** + * Remove a mapping created with (mini)upnpc. Calling + * this function will give 'upnpc' 1s to remove tha mapping, + * so while this function is non-blocking, a task will be + * left with the scheduler for up to 1s past this call. + * + * @param mini the handle + */ +void +GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini); + + +#endif + +/* end of gnunet_nat_lib.h */ diff --git a/src/include/gnunet_network_lib.h b/src/include/gnunet_network_lib.h new file mode 100644 index 0000000..a14d5f0 --- /dev/null +++ b/src/include/gnunet_network_lib.h @@ -0,0 +1,464 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_network_lib.h + * @brief basic low-level networking interface + * @author Nils Durner + */ + +#ifndef GNUNET_NETWORK_LIB_H +#define GNUNET_NETWORK_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * @brief handle to a socket + */ +struct GNUNET_NETWORK_Handle; + + +/** + * @brief collection of IO descriptors + */ +struct GNUNET_NETWORK_FDSet +{ + + /** + * Maximum number of any socket socket descriptor in the set (plus one) + */ + int nsds; + + /** + * Bitset with the descriptors. + */ + fd_set sds; + +#ifdef WINDOWS + /** + * Linked list of handles + */ + struct GNUNET_CONTAINER_SList *handles; +#endif + +}; + + + +#include "gnunet_disk_lib.h" +#include "gnunet_time_lib.h" + + +/** + * Accept a new connection on a socket. Configure it for non-blocking + * IO and mark it as non-inheritable to child processes (set the + * close-on-exec flag). + * + * @param desc bound socket + * @param address address of the connecting peer, may be NULL + * @param address_len length of address + * @return client socket + */ +struct GNUNET_NETWORK_Handle * +GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc, + struct sockaddr *address, + socklen_t * address_len); + + +/** + * Box a native socket (and check that it is a socket). + * + * @param fd socket to box + * @return NULL on error (including not supported on target platform) + */ +struct GNUNET_NETWORK_Handle * +GNUNET_NETWORK_socket_box_native (SOCKTYPE fd); + + +/** + * Bind to a connected socket + * + * @param desc socket to bind + * @param address address to be bound + * @param address_len length of address + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc, + const struct sockaddr *address, + socklen_t address_len); + +/** + * Close a socket. + * + * @param desc socket to close + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc); + + +/** + * Connect a socket + * + * @param desc socket to connect + * @param address peer address + * @param address_len of address + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc, + const struct sockaddr *address, + socklen_t address_len); + + +/** + * Get socket options + * + * @param desc socket to inspect + * @param level protocol level of the option + * @param optname identifier of the option + * @param optval options + * @param optlen length of optval + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc, + int level, int optname, void *optval, + socklen_t * optlen); + + +/** + * Listen on a socket + * + * @param desc socket to start listening on + * @param backlog length of the listen queue + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, + int backlog); + + +/** + * How much data is available to be read on this descriptor? + * @param desc socket + */ +ssize_t +GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle + *desc); + + +/** + * Read data from a connected socket (always non-blocking). + * @param desc socket + * @param buffer buffer + * @param length length of buffer + * @param src_addr either the source to recv from, or all zeroes + * to be filled in by recvfrom + * @param addrlen length of the addr + */ +ssize_t +GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle *desc, + void *buffer, size_t length, + struct sockaddr *src_addr, socklen_t * addrlen); + + +/** + * Read data from a connected socket (always non-blocking). + * + * @param desc socket + * @param buffer buffer + * @param length length of buffer + * @return number of bytes read + */ +ssize_t +GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle *desc, + void *buffer, size_t length); + + +/** + * Check if sockets meet certain conditions + * @param rfds set of sockets to be checked for readability + * @param wfds set of sockets to be checked for writability + * @param efds set of sockets to be checked for exceptions + * @param timeout relative value when to return + * @return number of selected sockets, GNUNET_SYSERR on error + */ +int +GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, + struct GNUNET_NETWORK_FDSet *wfds, + struct GNUNET_NETWORK_FDSet *efds, + struct GNUNET_TIME_Relative timeout); + + +/** + * Send data (always non-blocking). + * + * @param desc socket + * @param buffer data to send + * @param length size of the buffer + * @return number of bytes sent, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle *desc, + const void *buffer, size_t length); + + +/** + * Send data to a particular destination (always non-blocking). + * This function only works for UDP sockets. + * + * @param desc socket + * @param message data to send + * @param length size of the data + * @param dest_addr destination address + * @param dest_len length of address + * @return number of bytes sent, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle *desc, + const void *message, size_t length, + const struct sockaddr *dest_addr, + socklen_t dest_len); + + +/** + * Set socket option + * + * @param fd socket + * @param level protocol level of the option + * @param option_name option identifier + * @param option_value value to set + * @param option_len size of option_value + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd, int level, + int option_name, const void *option_value, + socklen_t option_len); + + +/** + * Shut down socket operations + * + * @param desc socket + * @param how type of shutdown + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, int how); + + +/** + * Disable the "CORK" feature for communication with the given socket, + * forcing the OS to immediately flush the buffer on transmission + * instead of potentially buffering multiple messages. Essentially + * reduces the OS send buffers to zero. + * + * @param desc socket + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_disable_corking (struct GNUNET_NETWORK_Handle *desc); + + +/** + * Create a new socket. Configure it for non-blocking IO and + * mark it as non-inheritable to child processes (set the + * close-on-exec flag). + * + * @param domain domain of the socket + * @param type socket type + * @param protocol network protocol + * @return new socket, NULL on error + */ +struct GNUNET_NETWORK_Handle * +GNUNET_NETWORK_socket_create (int domain, int type, int protocol); + + +/** + * Reset FD set (clears all file descriptors). + * + * @param fds fd set to clear + */ +void +GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds); + + +/** + * Add a socket to the FD set + * @param fds fd set + * @param desc socket to add + */ +void +GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_NETWORK_Handle *desc); + + +#if WINDOWS +/** + * Add a W32 file handle to the fd set + * @param fds fd set + * @param h the file handle to add + */ +void +GNUNET_NETWORK_fdset_handle_set_native_w32_handle (struct GNUNET_NETWORK_FDSet + *fds, HANDLE h); +#endif + + +/** + * Check whether a socket is part of the fd set + * @param fds fd set + * @param desc socket + * @return GNUNET_YES if the socket is in the set + */ +int +GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_NETWORK_Handle *desc); + + +/** + * Add one fd set to another + * @param dst the fd set to add to + * @param src the fd set to add from + */ +void +GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst, + const struct GNUNET_NETWORK_FDSet *src); + + +/** + * Copy one fd set to another + * @param to destination + * @param from source + */ +void +GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, + const struct GNUNET_NETWORK_FDSet *from); + + +/** + * Return file descriptor for this network handle + * + * @param desc wrapper to process + * @return POSIX file descriptor + */ +int +GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc); + + +/** + * Copy a native fd set + * @param to destination + * @param from native source set + * @param nfds the biggest socket number in from + 1 + */ +void +GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to, + const fd_set * from, int nfds); + + +/** + * Set a native fd in a set + * + * @param to destination + * @param nfd native FD to set + */ +void +GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to, int nfd); + + +/** + * Test native fd in a set + * + * @param to set to test, NULL for empty set + * @param nfd native FD to test, -1 for none + * @return GNUNET_YES if to contains nfd + */ +int +GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to, + int nfd); + + +/** + * Add a file handle to the fd set + * @param fds fd set + * @param h the file handle to add + */ +void +GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_DISK_FileHandle *h); + + +/** + * Check if a file handle is part of an fd set + * @param fds fd set + * @param h file handle + * @return GNUNET_YES if the file handle is part of the set + */ +int +GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_DISK_FileHandle *h); + + +/** + * Checks if two fd sets overlap + * @param fds1 first fd set + * @param fds2 second fd set + * @return GNUNET_YES if they do overlap, GNUNET_NO otherwise + */ +int +GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1, + const struct GNUNET_NETWORK_FDSet *fds2); + + +/** + * Creates an fd set + * @return a new fd set + */ +struct GNUNET_NETWORK_FDSet * +GNUNET_NETWORK_fdset_create (void); + + +/** + * Releases the associated memory of an fd set + * @param fds fd set + */ +void +GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif /* GNUNET_NETWORK_LIB_H */ diff --git a/src/include/gnunet_nse_service.h b/src/include/gnunet_nse_service.h new file mode 100644 index 0000000..a0c6016 --- /dev/null +++ b/src/include/gnunet_nse_service.h @@ -0,0 +1,109 @@ +/* + This file is part of GNUnet + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +#ifndef GNUNET_NSE_SERVICE_H_ +#define GNUNET_NSE_SERVICE_H_ + +/** + * @file include/gnunet_nse_service.h + * @brief API to retrieve the current network size estimate, + * also to register for notifications whenever a new + * network size estimate is calculated. + * + * @author Nathan Evans + */ + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_scheduler_lib.h" + +/** + * Version of the network size estimation API. + */ +#define GNUNET_NSE_VERSION 0x00000000 + +/** + * Handle for the network size estimation service. + */ +struct GNUNET_NSE_Handle; + +/** + * Callback to call when network size estimate is updated. + * + * @param cls closure + * @param timestamp time when the estimate was received from the server (or created by the server) + * @param logestimate the log(Base 2) value of the current network size estimate + * @param std_dev standard deviation for the estimate + * + */ +typedef void (*GNUNET_NSE_Callback) (void *cls, + struct GNUNET_TIME_Absolute timestamp, + double logestimate, double std_dev); + + +/** + * Convert the logarithmic estimated returned to the 'GNUNET_NSE_Callback' + * into an absolute estimate in terms of the number of peers in the network. + * + * @param loge logarithmic estimate + * @return absolute number of peers in the network (estimated) + */ +#define GNUNET_NSE_log_estimate_to_n(loge) pow(2.0, (loge)) + +/** + * Connect to the network size estimation service. + * + * @param cfg the configuration to use + * @param func funtion to call with network size estimate + * @param func_cls closure to pass for network size estimate callback + * + * @return handle to use + */ +struct GNUNET_NSE_Handle * +GNUNET_NSE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_NSE_Callback func, void *func_cls); + + +/** + * Disconnect from network size estimation service + * + * @param h handle to destroy + * + */ +void +GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif /* GNUNET_NSE_SERVICE_H_ */ diff --git a/src/include/gnunet_os_lib.h b/src/include/gnunet_os_lib.h new file mode 100644 index 0000000..e9e484f --- /dev/null +++ b/src/include/gnunet_os_lib.h @@ -0,0 +1,434 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_os_lib.h + * @brief low level process routines + * @author Christian Grothoff + * @author Krista Bennett + * @author Gerd Knorr + * @author Ioana Patrascu + * @author Tzvetan Horozov + * @author Milan + * + * This code manages child processes. We can communicate with child + * processes using signals. Because signals are not supported on W32 + * and Java (at least not nicely), we can alternatively use a pipe + * to send signals to the child processes (if the child process is + * a full-blown GNUnet process that supports reading signals from + * a pipe, of course). Naturally, this also only works for 'normal' + * termination via signals, and not as a replacement for SIGKILL. + * Thus using pipes to communicate signals should only be enabled if + * the child is a Java process OR if we are on Windoze. + */ + +#ifndef GNUNET_OS_LIB_H +#define GNUNET_OS_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_scheduler_lib.h" + +/** + * Process information (OS-dependent) + */ +struct GNUNET_OS_Process; + + +/** + * Possible installation paths to request + */ +enum GNUNET_OS_InstallationPathKind +{ + /** + * Return the "PREFIX" directory given to configure. + */ + GNUNET_OS_IPK_PREFIX, + + /** + * Return the directory where the program binaries are installed. (bin/) + */ + GNUNET_OS_IPK_BINDIR, + + /** + * Return the directory where libraries are installed. (lib/gnunet/) + */ + GNUNET_OS_IPK_LIBDIR, + + /** + * Return the directory where data is installed (share/gnunet/) + */ + GNUNET_OS_IPK_DATADIR, + + /** + * Return the directory where translations are installed (share/locale/) + */ + GNUNET_OS_IPK_LOCALEDIR, + + /** + * Return the installation directory of this application, not + * the one of the overall GNUnet installation (in case they + * are different). + */ + GNUNET_OS_IPK_SELF_PREFIX, + + /** + * Return the prefix of the path with application icons (share/icons/). + */ + GNUNET_OS_IPK_ICONDIR, + + /** + * Return the prefix of the path with documentation files, including the + * license (share/doc/gnunet/). + */ + GNUNET_OS_IPK_DOCDIR +}; + + +/** + * Process status types + */ +enum GNUNET_OS_ProcessStatusType +{ + /** + * The process is not known to the OS (or at + * least not one of our children). + */ + GNUNET_OS_PROCESS_UNKNOWN, + + /** + * The process is still running. + */ + GNUNET_OS_PROCESS_RUNNING, + + /** + * The process is paused (but could be resumed). + */ + GNUNET_OS_PROCESS_STOPPED, + + /** + * The process exited with a return code. + */ + GNUNET_OS_PROCESS_EXITED, + + /** + * The process was killed by a signal. + */ + GNUNET_OS_PROCESS_SIGNALED +}; + + +/** + * Get the path to a specific GNUnet installation directory or, with + * GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation + * directory. + * + * @param dirkind what kind of directory is desired? + * @return a pointer to the dir path (to be freed by the caller) + */ +char * +GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind); + + +/** + * Callback function invoked for each interface found. + * + * @param cls closure + * @param name name of the interface (can be NULL for unknown) + * @param isDefault is this presumably the default interface + * @param addr address of this interface (can be NULL for unknown or unassigned) + * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) + * @param netmask the network mask (can be NULL for unknown or unassigned)) + * @param addrlen length of the address + * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort + */ +typedef int (*GNUNET_OS_NetworkInterfaceProcessor) (void *cls, const char *name, + int isDefault, + const struct sockaddr * + addr, + const struct sockaddr * + broadcast_addr, + const struct sockaddr * + netmask, socklen_t addrlen); + + +/** + * @brief Enumerate all network interfaces + * @param proc the callback function + * @param proc_cls closure for proc + */ +void +GNUNET_OS_network_interfaces_list (GNUNET_OS_NetworkInterfaceProcessor proc, + void *proc_cls); + +/** + * @brief Get maximum string length returned by gethostname() + */ +#if HAVE_SYSCONF && defined(_SC_HOST_NAME_MAX) +#define GNUNET_OS_get_hostname_max_length() ({ int __sc_tmp = sysconf(_SC_HOST_NAME_MAX); __sc_tmp <= 0 ? 255 : __sc_tmp; }) +#elif defined(HOST_NAME_MAX) +#define GNUNET_OS_get_hostname_max_length() HOST_NAME_MAX +#else +#define GNUNET_OS_get_hostname_max_length() 255 +#endif + + +/** + * Get process structure for current process + * + * The pointer it returns points to static memory location and must not be + * deallocated/closed + * + * @return pointer to the process sturcutre for this process + */ +struct GNUNET_OS_Process * +GNUNET_OS_process_current (void); + + +/** + * Sends a signal to the process + * + * @param proc pointer to process structure + * @param sig signal + * @return 0 on success, -1 on error + */ +int +GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig); + + +/** + * Cleans up process structure contents (OS-dependent) and deallocates it + * + * @param proc pointer to process structure + */ +void +GNUNET_OS_process_close (struct GNUNET_OS_Process *proc); + + +/** + * Get the pid of the process in question + * + * @param proc the process to get the pid of + * + * @return the current process id + */ +pid_t +GNUNET_OS_process_get_pid (struct GNUNET_OS_Process *proc); + + +/** + * Set process priority + * + * @param proc pointer to process structure + * @param prio priority value + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc, + enum GNUNET_SCHEDULER_Priority prio); + + +/** + * Start a process. + * + * @param pipe_control should a pipe be used to send signals to the child? + * @param pipe_stdin pipe to use to send input to child process (or NULL) + * @param pipe_stdout pipe to use to get output from child process (or NULL) + * @param filename name of the binary + * @param argv NULL-terminated array of arguments to the process + * @return pointer to process structure of the new process, NULL on error + */ +struct GNUNET_OS_Process * +GNUNET_OS_start_process_vap (int pipe_control, + struct GNUNET_DISK_PipeHandle *pipe_stdin, + struct GNUNET_DISK_PipeHandle *pipe_stdout, + const char *filename, + char *const argv[]); + + +/** + * Start a process. + * + * @param pipe_control should a pipe be used to send signals to the child? + * @param pipe_stdin pipe to use to send input to child process (or NULL) + * @param pipe_stdout pipe to use to get output from child process (or NULL) + * @param filename name of the binary + * @param ... NULL-terminated list of arguments to the process + * @return pointer to process structure of the new process, NULL on error + */ +struct GNUNET_OS_Process * +GNUNET_OS_start_process (int pipe_control, + struct GNUNET_DISK_PipeHandle *pipe_stdin, + struct GNUNET_DISK_PipeHandle *pipe_stdout, + const char *filename, ...); + + +/** + * Start a process. + * + * @param pipe_control should a pipe be used to send signals to the child? + * @param pipe_stdin pipe to use to send input to child process (or NULL) + * @param pipe_stdout pipe to use to get output from child process (or NULL) + * @param filename name of the binary + * @param va NULL-terminated list of arguments to the process + * @return pointer to process structure of the new process, NULL on error + */ +struct GNUNET_OS_Process * +GNUNET_OS_start_process_va (int pipe_control, + struct GNUNET_DISK_PipeHandle *pipe_stdin, + struct GNUNET_DISK_PipeHandle *pipe_stdout, + const char *filename, va_list va); + +/** + * Start a process. + * + * @param pipe_control should a pipe be used to send signals to the child? + * @param lsocks array of listen sockets to dup systemd-style (or NULL); + * must be NULL on platforms where dup is not supported + * @param filename name of the binary + * @param argv NULL-terminated list of arguments to the process, + * including the process name as the first argument + * @return pointer to process structure of the new process, NULL on error + */ +struct GNUNET_OS_Process * +GNUNET_OS_start_process_v (int pipe_control, + const SOCKTYPE *lsocks, + const char *filename, + char *const argv[]); + + +/** + * Handle to a command action. + */ +struct GNUNET_OS_CommandHandle; + + +/** + * Type of a function to process a line of output. + * + * @param cls closure + * @param line line of output from a command, NULL for the end + */ +typedef void (*GNUNET_OS_LineProcessor) (void *cls, const char *line); + + +/** + * Stop/kill a command. + * + * @param cmd handle to the process + */ +void +GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd); + + +/** + * Run the given command line and call the given function + * for each line of the output. + * + * @param proc function to call for each line of the output + * @param proc_cls closure for proc + * @param timeout when to time out + * @param binary command to run + * @param ... arguments to command + * @return NULL on error + */ +struct GNUNET_OS_CommandHandle * +GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls, + struct GNUNET_TIME_Relative timeout, const char *binary, + ...); + + +/** + * Retrieve the status of a process. Nonblocking version. + * + * @param proc pointer to process structure + * @param type status type + * @param code return code/signal number + * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise + */ +int +GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, + enum GNUNET_OS_ProcessStatusType *type, + unsigned long *code); + + +/** + * Wait for a process to terminate. The return code is discarded. + * You must not use 'GNUNET_OS_process_status' on the same process + * after calling this function! This function is blocking and should + * thus only be used if the child process is known to have terminated + * or to terminate very soon. + * + * @param proc pointer to process structure of the process to wait for + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc); + + +/** + * Connects this process to its parent via pipe; + * essentially, the parent control handler will read signal numbers + * from the 'GNUNET_OS_CONTROL_PIPE' (as given in an environment + * variable) and raise those signals. + * + * @param cls closure (unused) + * @param tc scheduler context (unused) + */ +void +GNUNET_OS_install_parent_control_handler (void *cls, + const struct + GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Check whether an executable exists and possibly + * if the suid bit is set on the file. + * Attempts to find the file using the current + * PATH environment variable as a search path. + * + * @param binary the name of the file to check + * @return GNUNET_YES if the file is SUID, + * GNUNET_NO if not SUID (but binary exists) + * GNUNET_SYSERR on error (no such binary or not executable) + */ +int +GNUNET_OS_check_helper_binary (const char *binary); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_OS_LIB_H */ +#endif +/* end of gnunet_os_lib.h */ diff --git a/src/include/gnunet_peer_lib.h b/src/include/gnunet_peer_lib.h new file mode 100644 index 0000000..0121e84 --- /dev/null +++ b/src/include/gnunet_peer_lib.h @@ -0,0 +1,103 @@ +/* + This file is part of GNUnet. + (C) 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_peer_lib.h + * @brief helper library for interning of peer identifiers + * @author Christian Grothoff + */ + +#ifndef GNUNET_PEER_LIB_H +#define GNUNET_PEER_LIB_H + +#include "gnunet_util_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * A GNUNET_PEER_Id is simply a shorter + * version of a "struct GNUNET_PeerIdentifier" + * that can be used inside of a GNUnet peer + * to save memory when the same identifier + * needs to be used over and over again. + */ +typedef unsigned int GNUNET_PEER_Id; + + +/** + * Search for a peer identity. The reference counter is not changed. + * + * @param pid identity to find + * @return the interned identity or 0. + */ +GNUNET_PEER_Id +GNUNET_PEER_search (const struct GNUNET_PeerIdentity *pid); + + +/** + * Intern an peer identity. If the identity is already known, its + * reference counter will be increased by one. + * + * @param pid identity to intern + * @return the interned identity. + */ +GNUNET_PEER_Id +GNUNET_PEER_intern (const struct GNUNET_PeerIdentity *pid); + + +/** + * Change the reference counter of an interned PID. + * + * @param id identity to change the RC of + * @param delta how much to change the RC + */ +void +GNUNET_PEER_change_rc (GNUNET_PEER_Id id, int delta); + + +/** + * Decrement multiple RCs of peer identities by one. + * + * @param ids array of PIDs to decrement the RCs of + * @param count size of the ids array + */ +void +GNUNET_PEER_decrement_rcs (const GNUNET_PEER_Id *ids, unsigned int count); + + +/** + * Convert an interned PID to a normal peer identity. + * + * @param id interned PID to convert + * @param pid where to write the normal peer identity + */ +void +GNUNET_PEER_resolve (GNUNET_PEER_Id id, struct GNUNET_PeerIdentity *pid); + + +/* ifndef GNUNET_PEER_LIB_H */ +#endif +/* end of gnunet_peer_lib.h */ diff --git a/src/include/gnunet_peerinfo_service.h b/src/include/gnunet_peerinfo_service.h new file mode 100644 index 0000000..12264fb --- /dev/null +++ b/src/include/gnunet_peerinfo_service.h @@ -0,0 +1,190 @@ +/* + This file is part of GNUnet + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file include/gnunet_peerinfo_service.h + * @brief Code to maintain the list of currently known hosts + * (in memory structure of data/hosts). + * @author Christian Grothoff + */ + +#ifndef GNUNET_PEERINFO_SERVICE_H +#define GNUNET_PEERINFO_SERVICE_H + +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_hello_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Handle to the peerinfo service. + */ +struct GNUNET_PEERINFO_Handle; + + +/** + * Connect to the peerinfo service. + * + * @param cfg configuration to use + * @return NULL on error (configuration related, actual connection + * etablishment may happen asynchronously). + */ +struct GNUNET_PEERINFO_Handle * +GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); + + + +/** + * Disconnect from the peerinfo service. Note that all iterators must + * have completed or have been cancelled by the time this function is + * called (otherwise, calling this function is a serious error). + * Furthermore, if 'GNUNET_PEERINFO_add_peer' operations are still + * pending, they will be cancelled silently on disconnect. + * + * @param h handle to disconnect + */ +void +GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h); + + +/** + * Add a host to the persistent list. This method operates in + * semi-reliable mode: if the transmission is not completed by + * the time 'GNUNET_PEERINFO_disconnect' is called, it will be + * aborted. Furthermore, if a second HELLO is added for the + * same peer before the first one was transmitted, PEERINFO may + * merge the two HELLOs prior to transmission to the service. + * + * @param h handle to the peerinfo service + * @param hello the verified (!) HELLO message + */ +void +GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h, + const struct GNUNET_HELLO_Message *hello); + + +/** + * Type of an iterator over the hosts. Note that each + * host will be called with each available protocol. + * + * @param cls closure + * @param peer id of the peer, NULL for last call + * @param hello hello message for the peer (can be NULL) + * @param error message + */ +typedef void (*GNUNET_PEERINFO_Processor) (void *cls, + const struct GNUNET_PeerIdentity * + peer, + const struct GNUNET_HELLO_Message * + hello, const char *err_msg); + + +/** + * Handle for cancellation of iteration over peers. + */ +struct GNUNET_PEERINFO_IteratorContext; + + +/** + * Call a method for each known matching host to get its HELLO. + * The callback method will be invoked once for each matching + * host and then finally once with a NULL pointer. After that final + * invocation, the iterator context must no longer be used. + * + * Instead of calling this function with 'peer == NULL' + * it is often better to use 'GNUNET_PEERINFO_notify'. + * + * @param h handle to the peerinfo service + * @param peer restrict iteration to this peer only (can be NULL) + * @param timeout how long to wait until timing out + * @param callback the method to call for each peer + * @param callback_cls closure for callback + * @return NULL on error (in this case, 'callback' is never called!), + * otherwise an iterator context + */ +struct GNUNET_PEERINFO_IteratorContext * +GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h, + const struct GNUNET_PeerIdentity *peer, + struct GNUNET_TIME_Relative timeout, + GNUNET_PEERINFO_Processor callback, + void *callback_cls); + + + +/** + * Cancel an iteration over peer information. + * + * @param ic context of the iterator to cancel + */ +void +GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic); + + + +/** + * Handle for notifications about changes to the set of known peers. + */ +struct GNUNET_PEERINFO_NotifyContext; + + +/** + * Call a method whenever our known information about peers + * changes. Initially calls the given function for all known + * peers and then only signals changes. Note that it is + * possible (i.e. on disconnects) that the callback is called + * twice with the same peer information. + * + * @param cfg configuration to use + * @param callback the method to call for each peer + * @param callback_cls closure for callback + * @return NULL on error + */ +struct GNUNET_PEERINFO_NotifyContext * +GNUNET_PEERINFO_notify (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_PEERINFO_Processor callback, void *callback_cls); + + +/** + * Stop notifying about changes. + * + * @param nc context to stop notifying + */ +void +GNUNET_PEERINFO_notify_cancel (struct GNUNET_PEERINFO_NotifyContext *nc); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* end of gnunet_peerinfo_service.h */ +#endif diff --git a/src/include/gnunet_plugin_lib.h b/src/include/gnunet_plugin_lib.h new file mode 100644 index 0000000..387ca38 --- /dev/null +++ b/src/include/gnunet_plugin_lib.h @@ -0,0 +1,137 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_plugin_lib.h + * @brief plugin loading and unloading + * @author Christian Grothoff + */ + +#ifndef GNUNET_PLUGIN_LIB_H +#define GNUNET_PLUGIN_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" + + +/** + * Signature of any function exported by a plugin. + * + * @param arg argument to the function (context) + * @return some pointer, NULL if the plugin was + * shutdown or if there was an error, otherwise + * the plugin's API on success + */ +typedef void *(*GNUNET_PLUGIN_Callback) (void *arg); + + +/** + * Test if a plugin exists. + * + * Note that the library must export a symbol called + * "library_name_init" for the test to succeed. + * + * @param library_name name of the plugin to test if it is installed + * @return GNUNET_YES if the plugin exists, GNUNET_NO if not + */ +int +GNUNET_PLUGIN_test (const char *library_name); + + +/** + * Setup plugin (runs the "init" callback and returns whatever "init" + * returned). If "init" returns NULL, the plugin is unloaded. + * + * Note that the library must export symbols called + * "library_name_init" and "library_name_done". These will be called + * when the library is loaded and unloaded respectively. + * + * @param library_name name of the plugin to load + * @param arg argument to the plugin initialization function + * @return whatever the initialization function returned, NULL on error + */ +void * +GNUNET_PLUGIN_load (const char *library_name, void *arg); + + +/** + * Signature of a function called by 'GNUNET_PLUGIN_load_all'. + * + * @param cls closure + * @param library_name full name of the library (to be used with + * 'GNUNET_PLUGIN_unload') + * @param lib_ret return value from the initialization function + * of the library (same as what 'GNUNET_PLUGIN_load' would + * have returned for the given library name) + */ +typedef void (*GNUNET_PLUGIN_LoaderCallback) (void *cls, + const char *library_name, + void *lib_ret); + + +/** + * Load all compatible plugins with the given base name. + * + * Note that the library must export symbols called + * "basename_ANYTHING_init" and "basename_ANYTHING__done". These will + * be called when the library is loaded and unloaded respectively. + * + * @param basename basename of the plugins to load + * @param arg argument to the plugin initialization function + * @param cb function to call for each plugin found + * @param cb_cls closure for 'cb' + */ +void +GNUNET_PLUGIN_load_all (const char *basename, void *arg, + GNUNET_PLUGIN_LoaderCallback cb, void *cb_cls); + + +/** + * Unload plugin (runs the "done" callback and returns whatever "done" + * returned). The plugin is then unloaded. + * + * @param library_name name of the plugin to unload + * @param arg argument to the plugin shutdown function + * @return whatever the shutdown function returned, typically NULL + * or a "char *" representing the error message + */ +void * +GNUNET_PLUGIN_unload (const char *library_name, void *arg); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_PLUGIN_LIB_H */ +#endif +/* end of gnunet_plugin_lib.h */ diff --git a/src/include/gnunet_program_lib.h b/src/include/gnunet_program_lib.h new file mode 100644 index 0000000..48d5280 --- /dev/null +++ b/src/include/gnunet_program_lib.h @@ -0,0 +1,86 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_program_lib.h + * @brief functions related to starting programs + * @author Christian Grothoff + */ + +#ifndef GNUNET_PROGRAM_LIB_H +#define GNUNET_PROGRAM_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_configuration_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_scheduler_lib.h" + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +typedef void (*GNUNET_PROGRAM_Main) (void *cls, char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle * + cfg); + + +/** + * Run a standard GNUnet command startup sequence (initialize loggers + * and configuration, parse options). + * + * @param argc number of command line arguments + * @param argv command line arguments + * @param binaryName our expected name + * @param binaryHelp helptext for "-h" option (about the app) + * @param options command line options + * @param task main function to run + * @param task_cls closure for task + * @return GNUNET_SYSERR on error, GNUNET_OK on success + */ +int +GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName, + const char *binaryHelp, + const struct GNUNET_GETOPT_CommandLineOption *options, + GNUNET_PROGRAM_Main task, void *task_cls); + + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_PROGRAM_LIB_H */ +#endif +/* end of gnunet_program_lib.h */ diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h new file mode 100644 index 0000000..dd7c7fe --- /dev/null +++ b/src/include/gnunet_protocols.h @@ -0,0 +1,1289 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_protocols.h + * @brief constants for network protocols + * @author Christian Grothoff + */ + +#ifndef GNUNET_PROTOCOLS_H +#define GNUNET_PROTOCOLS_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/******************************************************************************* + * UTIL message types + ******************************************************************************/ + +/** + * Test if service is online. + */ +#define GNUNET_MESSAGE_TYPE_TEST 1 + +/** + * Dummy messages for testing / benchmarking. + */ +#define GNUNET_MESSAGE_TYPE_DUMMY 2 + +/******************************************************************************* + * RESOLVER message types + ******************************************************************************/ + +/** + * Request DNS resolution. + */ +#define GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST 4 + +/** + * Response to a DNS resolution request. + */ +#define GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE 5 + +/******************************************************************************* + * ARM message types + ******************************************************************************/ + +/** + * Request to ARM to start a service. + */ +#define GNUNET_MESSAGE_TYPE_ARM_START 8 + +/** + * Request to ARM to stop a service. + */ +#define GNUNET_MESSAGE_TYPE_ARM_STOP 9 + +/** + * Request ARM service itself to shutdown. + */ +#define GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN 10 + +/** + * Response from ARM. + */ +#define GNUNET_MESSAGE_TYPE_ARM_RESULT 11 + + +/******************************************************************************* + * HELLO message types + ******************************************************************************/ + +/** + * HELLO message used for communicating peer addresses. + * Managed by libgnunethello. + */ +#define GNUNET_MESSAGE_TYPE_HELLO 16 + +/******************************************************************************* + * FRAGMENTATION message types + ******************************************************************************/ + +/** + * FRAGMENT of a larger message. + * Managed by libgnunetfragment. + */ +#define GNUNET_MESSAGE_TYPE_FRAGMENT 18 + +/** + * Acknowledgement of a FRAGMENT of a larger message. + * Managed by libgnunetfragment. + */ +#define GNUNET_MESSAGE_TYPE_FRAGMENT_ACK 19 + +/******************************************************************************* + * Transport-WLAN message types + ******************************************************************************/ + +/** + * Type of messages between the gnunet-wlan-helper and the daemon + * + */ +#define GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA 40 + +/** + * Control messages between the gnunet-wlan-helper and the daemon + */ + +#define GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL 41 + +/** + * Type of messages for advertisement over wlan + */ +#define GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT 42 + +/** + * Type of messages for data over the wlan + */ +#define GNUNET_MESSAGE_TYPE_WLAN_DATA 43 + + +/******************************************************************************* + * Transport-DV message types + ******************************************************************************/ + +/** + * DV service to DV Plugin message, when a message is + * unwrapped by the DV service and handed to the plugin + * for processing + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE 44 + +/** + * DV Plugin to DV service message, indicating a message + * should be sent out. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND 45 + +/** + * DV service to DV api message, containing a confirmation + * or failure of a DV_SEND message. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT 46 + +/** + * P2P DV message encapsulating some real message + */ +#define GNUNET_MESSAGE_TYPE_DV_DATA 47 + +/** + * P2P DV message gossipping peer information + */ +#define GNUNET_MESSAGE_TYPE_DV_GOSSIP 48 + +/** + * DV Plugin to DV service message, indicating + * startup. + */ +#define GNUNET_MESSAGE_TYPE_DV_START 49 + +/** + * P2P DV message notifying connected peers of a disconnect + */ +#define GNUNET_MESSAGE_TYPE_DV_DISCONNECT 50 + +/******************************************************************************* + * Transport-UDP message types + ******************************************************************************/ + +/** + * Normal UDP message type. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE 56 + +/** + * UDP ACK. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK 57 + +/******************************************************************************* + * Transport-TCP message types + ******************************************************************************/ + +/** + * TCP NAT probe message, send from NAT'd peer to + * other peer to establish bi-directional communication + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE 60 + +/** + * Welcome message between TCP transports. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME 61 + +/** + * Message to force transport to update bandwidth assignment (LEGACY) + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_ATS 62 + +/******************************************************************************* + * NAT message types + ******************************************************************************/ + +/** + * Message to ask NAT server to perform traversal test + */ +#define GNUNET_MESSAGE_TYPE_NAT_TEST 63 + +/******************************************************************************* + * CORE message types + ******************************************************************************/ + +/** + * Initial setup message from core client to core. + */ +#define GNUNET_MESSAGE_TYPE_CORE_INIT 64 + +/** + * Response from core to core client to INIT message. + */ +#define GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY 65 + +/** + * Notify clients about new peer-to-peer connections (before + * key exchange and authentication). + */ +#define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_PRE_CONNECT 66 + +/** + * Notify clients about new peer-to-peer connections (triggered + * after key exchange). + */ +#define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT 67 + +/** + * Notify clients about peer disconnecting. + */ +#define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT 68 + +/** + * Notify clients about peer status change. + */ +#define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE 69 + +/** + * Notify clients about incoming P2P messages. + */ +#define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND 70 + +/** + * Notify clients about outgoing P2P transmissions. + */ +#define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND 71 + +/** + * Request from client to transmit message. + */ +#define GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST 74 + +/** + * Confirmation from core that message can now be sent + */ +#define GNUNET_MESSAGE_TYPE_CORE_SEND_READY 75 + +/** + * Client with message to transmit (after SEND_READY confirmation + * was received). + */ +#define GNUNET_MESSAGE_TYPE_CORE_SEND 76 + + +/** + * Request for peer iteration from CORE service. + */ +#define GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS 78 + +/** + * Last reply from core to request for peer iteration from CORE service. + */ +#define GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END 79 + +/** + * Check whether a given peer is currently connected to CORE. + */ +#define GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED 80 + +/** + * Session key exchange between peers. + */ +#define GNUNET_MESSAGE_TYPE_CORE_SET_KEY 81 + +/** + * Encapsulation for an encrypted message between peers. + */ +#define GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE 82 + +/** + * Check that other peer is alive (challenge). + */ +#define GNUNET_MESSAGE_TYPE_CORE_PING 83 + +/** + * Confirmation that other peer is alive. + */ +#define GNUNET_MESSAGE_TYPE_CORE_PONG 84 + +/** + * Request by the other peer to terminate the connection. + */ +#define GNUNET_MESSAGE_TYPE_CORE_HANGUP 85 + +/** + * gzip-compressed type map of the sender + */ +#define GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP 86 + +/** + * uncompressed type map of the sender + */ +#define GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP 87 + +/******************************************************************************* + * DATASTORE message types + ******************************************************************************/ + +/** + * Message sent by datastore client on join. + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE 92 + +/** + * Message sent by datastore client on join. + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE 93 + +/** + * Message sent by datastore to client informing about status + * processing a request + * (in response to RESERVE, RELEASE_RESERVE, PUT, UPDATE and REMOVE requests). + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_STATUS 94 + +/** + * Message sent by datastore client to store data. + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_PUT 95 + +/** + * Message sent by datastore client to update data. + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE 96 + +/** + * Message sent by datastore client to get data. + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_GET 97 + +/** + * Message sent by datastore client to get random data. + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_GET_REPLICATION 98 + +/** + * Message sent by datastore client to get random data. + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY 99 + +/** + * Message sent by datastore to client providing requested data + * (in response to GET or GET_RANDOM request). + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_DATA 100 + +/** + * Message sent by datastore to client signaling end of matching data. + * This message will also be sent for "GET_RANDOM", even though + * "GET_RANDOM" returns at most one data item. + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END 101 + +/** + * Message sent by datastore client to remove data. + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE 102 + +/** + * Message sent by datastore client to drop the database. + */ +#define GNUNET_MESSAGE_TYPE_DATASTORE_DROP 103 + + +/******************************************************************************* + * FS message types + ******************************************************************************/ + +/** + * Message sent by fs client to start indexing. + */ +#define GNUNET_MESSAGE_TYPE_FS_INDEX_START 128 + +/** + * Affirmative response to a request for start indexing. + */ +#define GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK 129 + +/** + * Response to a request for start indexing that + * refuses. + */ +#define GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED 130 + +/** + * Request from client for list of indexed files. + */ +#define GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET 131 + +/** + * Reply to client with an indexed file name. + */ +#define GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY 132 + +/** + * Reply to client indicating end of list. + */ +#define GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END 133 + +/** + * Request from client to unindex a file. + */ +#define GNUNET_MESSAGE_TYPE_FS_UNINDEX 134 + +/** + * Reply to client indicating unindex receipt. + */ +#define GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK 135 + +/** + * Client asks FS service to start a (keyword) search. + */ +#define GNUNET_MESSAGE_TYPE_FS_START_SEARCH 136 + +/** + * P2P request for content (one FS to another). + */ +#define GNUNET_MESSAGE_TYPE_FS_GET 137 + +/** + * P2P response with content or active migration of content. Also + * used between the service and clients (in response to START_SEARCH). + */ +#define GNUNET_MESSAGE_TYPE_FS_PUT 138 + +/** + * Peer asks us to stop migrating content towards it for a while. + */ +#define GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP 139 + + +/******************************************************************************* + * DHT message types + ******************************************************************************/ + +/** + * Client wants to store item in DHT. + */ +#define GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT 142 + +/** + * Client wants to lookup item in DHT. + */ +#define GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET 143 + +/** + * Client wants to stop search in DHT. + */ +#define GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP 144 + +/** + * Service returns result to client. + */ +#define GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT 145 + +/** + * Peer is storing data in DHT. + */ +#define GNUNET_MESSAGE_TYPE_DHT_P2P_PUT 146 + +/** + * Peer tries to find data in DHT. + */ +#define GNUNET_MESSAGE_TYPE_DHT_P2P_GET 147 + +/** + * Data is returned to peer from DHT. + */ +#define GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT 148 + +/** + * Request / receive information about transiting GETs + */ +#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET 149 + +/** + * Request / receive information about transiting GET responses + */ +#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP 150 + +/** + * Request / receive information about transiting PUTs + */ +#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT 151 + +/** + * Request / receive information about transiting PUT responses (TODO) + */ +#define GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT_RESP 152 + + +/******************************************************************************* + * HOSTLIST message types + ******************************************************************************/ + +/** + * Hostlist advertisement message + */ +#define GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT 160 + + +/******************************************************************************* + * STATISTICS message types + ******************************************************************************/ + +/** + * Set a statistical value. + */ +#define GNUNET_MESSAGE_TYPE_STATISTICS_SET 168 + +/** + * Get a statistical value(s). + */ +#define GNUNET_MESSAGE_TYPE_STATISTICS_GET 169 + +/** + * Response to a STATISTICS_GET message (with value). + */ +#define GNUNET_MESSAGE_TYPE_STATISTICS_VALUE 170 + +/** + * Response to a STATISTICS_GET message (end of value stream). + */ +#define GNUNET_MESSAGE_TYPE_STATISTICS_END 171 + +/** + * Watch changes to a statistical value. Message format is the same + * as for GET, except that the subsystem and entry name must be given. + */ +#define GNUNET_MESSAGE_TYPE_STATISTICS_WATCH 172 + +/** + * Changes to a watched value. + */ +#define GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE 173 + + +/******************************************************************************* + * VPN message types + ******************************************************************************/ + +/** + * Type of messages between the gnunet-vpn-helper and the daemon + */ +#define GNUNET_MESSAGE_TYPE_VPN_HELPER 185 + +/** + * Type of messages containing an ICMP packet for a service. + */ +#define GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE 190 + +/** + * Type of messages containing an ICMP packet for the Internet. + */ +#define GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET 191 + +/** + * Type of messages containing an ICMP packet for the VPN + */ +#define GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN 192 + +/** + * Type of messages containing an DNS request for a DNS exit service. + */ +#define GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET 193 + +/** + * Type of messages containing an DNS reply from a DNS exit service. + */ +#define GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET 194 + +/** + * Type of messages containing an TCP packet for a service. + */ +#define GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START 195 + +/** + * Type of messages containing an TCP packet for the Internet. + */ +#define GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START 196 + +/** + * Type of messages containing an TCP packet of an established connection. + */ +#define GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT 197 + +/** + * Type of messages containing an TCP packet of an established connection. + */ +#define GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN 198 + +/** + * Type of messages containing an UDP packet for a service. + */ +#define GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE 199 + +/** + * Type of messages containing an UDP packet for the Internet. + */ +#define GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET 200 + +/** + * Type of messages containing an UDP packet from a remote host + */ +#define GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY 201 + + +/** + * Client asks VPN service to setup an IP to redirect traffic + * via an exit node to some global IP address. + */ +#define GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP 202 + +/** + * Client asks VPN service to setup an IP to redirect traffic + * to some peer offering a service. + */ +#define GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE 203 + +/** + * VPN service responds to client with an IP to use for the + * requested redirection. + */ +#define GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP 204 + + +/******************************************************************************* + * VPN-DNS message types + ******************************************************************************/ + + +/** + * Initial message from client to DNS service for registration. + */ +#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT 211 + +/** + * Type of messages between the gnunet-helper-dns and the service + */ +#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST 212 + +/** + * Type of messages between the gnunet-helper-dns and the service + */ +#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE 213 + +/** + * Type of messages between the gnunet-helper-dns and the service + */ +#define GNUNET_MESSAGE_TYPE_DNS_HELPER 214 + + +/******************************************************************************* + * MESH message types + ******************************************************************************/ + +/** + * Type of message used to transport messages throug a MESH-tunnel (LEGACY) + */ +#define GNUNET_MESSAGE_TYPE_MESH 215 + +/** + * Type of message used to send another peer which messages we want to receive + * through a mesh-tunnel (LEGACY) + */ +#define GNUNET_MESSAGE_TYPE_MESH_HELLO 216 + +/** + * Request the creation of a path + */ +#define GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE 256 + +/** + * Request the modification of an existing path + */ +#define GNUNET_MESSAGE_TYPE_MESH_PATH_CHANGE 257 + +/** + * Notify that a connection of a path is no longer valid + */ +#define GNUNET_MESSAGE_TYPE_MESH_PATH_BROKEN 258 + +/** + * At some point, the route will spontaneously change + */ +#define GNUNET_MESSAGE_TYPE_MESH_PATH_CHANGED 259 + +/** + * Transport data in the mesh (origin->end) unicast + */ +#define GNUNET_MESSAGE_TYPE_MESH_UNICAST 260 + +/** + * Transport data to all peers in a tunnel + */ +#define GNUNET_MESSAGE_TYPE_MESH_MULTICAST 261 + +/** + * Transport data back in the mesh (end->origin) + */ +#define GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN 262 + +/** + * Send origin an ACK that the path is complete + */ +#define GNUNET_MESSAGE_TYPE_MESH_PATH_ACK 263 + +/** + * Avoid path timeouts + */ +#define GNUNET_MESSAGE_TYPE_MESH_PATH_KEEPALIVE 264 + +/** + * Request the destuction of a path + */ +#define GNUNET_MESSAGE_TYPE_MESH_PATH_DESTROY 265 + +/** + * Request the destruction of a whole tunnel + */ +#define GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY 266 + +/** + * We need flow control + */ +#define GNUNET_MESSAGE_TYPE_MESH_SPEED_NOTIFY 270 + +/** + * Connect to the mesh service, specifying subscriptions + */ +#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT 272 + +/** + * Ask the mesh service to create a new tunnel + */ +#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE 273 + +/** + * Ask the mesh service to destroy a tunnel + */ +#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY 274 + +/** + * Ask the mesh service to add a peer to an existing tunnel + */ +#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD 275 + +/** + * Ask the mesh service to remove a peer from a tunnel + */ +#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL 276 + +/** + * Ask the mesh service to add a peer offering a service to an existing tunnel + */ +#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE 277 + +/** + * 640kb should be enough for everybody + */ +#define GNUNET_MESSAGE_TYPE_MESH_RESERVE_END 288 + + + +/******************************************************************************* + * CHAT message types START + ******************************************************************************/ + +/** + * Message sent from client to join a chat room. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST 300 + +/** + * Message sent to client to indicate joining of another room member. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION 301 + +/** + * Message sent to client to indicate leaving of another room member. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION 302 + +/** + * Notification sent by service to client indicating that we've received a chat + * message. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION 303 + +/** + * Request sent by client to transmit a chat message to another room members. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST 304 + +/** + * Receipt sent from a message receiver to the service to confirm delivery of + * a chat message. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT 305 + +/** + * Notification sent from the service to the original sender + * to acknowledge delivery of a chat message. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION 306 + +/** + * P2P message sent to indicate joining of another room member. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION 307 + +/** + * P2P message sent to indicate leaving of another room member. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION 308 + +/** + * P2P message sent to a newly connected peer to request its known clients in + * order to synchronize room members. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST 309 + +/** + * Notification sent from one peer to another to indicate that we have received + * a chat message. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION 310 + +/** + * P2P receipt confirming delivery of a chat message. + */ +#define GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT 311 + + +/******************************************************************************* + * NSE (network size estimation) message types + ******************************************************************************/ + +/** + * client->service message indicating start + */ +#define GNUNET_MESSAGE_TYPE_NSE_START 321 + +/** + * P2P message sent from nearest peer + */ +#define GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD 322 + +/** + * service->client message indicating + */ +#define GNUNET_MESSAGE_TYPE_NSE_ESTIMATE 323 + + +/******************************************************************************* + * PEERINFO message types + ******************************************************************************/ + +/** + * Request update and listing of a peer. + */ +#define GNUNET_MESSAGE_TYPE_PEERINFO_GET 330 + +/** + * Request update and listing of all peers. + */ +#define GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL 331 + +/** + * Information about one of the peers. + */ +#define GNUNET_MESSAGE_TYPE_PEERINFO_INFO 332 + +/** + * End of information about other peers. + */ +#define GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END 333 + +/** + * Start notifying this client about all changes to + * the known peers until it disconnects. + */ +#define GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY 334 + +/******************************************************************************* + * ATS message types + ******************************************************************************/ + +/** + * Type of the 'struct ClientStartMessage' sent by clients to ATS to + * identify the type of the client. + */ +#define GNUNET_MESSAGE_TYPE_ATS_START 340 + +/** + * Type of the 'struct RequestAddressMessage' sent by clients to ATS + * to request an address to help connect. + */ +#define GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS 341 + +/** + * Type of the 'struct RequestAddressMessage' sent by clients to ATS + * to request an address to help connect. + */ +#define GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL 342 + +/** + * Type of the 'struct AddressUpdateMessage' sent by clients to ATS + * to inform ATS about performance changes. + */ +#define GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE 343 + +/** + * Type of the 'struct AddressDestroyedMessage' sent by clients to ATS + * to inform ATS about an address being unavailable. + */ +#define GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED 344 + +/** + * Type of the 'struct AddressSuggestionMessage' sent by ATS to clients + * to suggest switching to a different address. + */ +#define GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION 345 + +/** + * Type of the 'struct PeerInformationMessage' sent by ATS to clients + * to inform about QoS for a particular connection. + */ +#define GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION 346 + +/** + * Type of the 'struct ReservationRequestMessage' sent by clients to ATS + * to ask for inbound bandwidth reservations. + */ +#define GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST 347 + +/** + * Type of the 'struct ReservationResultMessage' sent by ATS to clients + * in response to a reservation request. + */ +#define GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT 348 + +/** + * Type of the 'struct ChangePreferenceMessage' sent by clients to ATS + * to ask for allocation preference changes. + */ +#define GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE 349 + +/** + * Type of the 'struct SessionReleaseMessage' sent by ATS to client + * to confirm that a session ID was destroyed. + */ +#define GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE 350 + +/** + * Type of the 'struct AddressUseMessage' sent by ATS to client + * to confirm that an address is used or not used anymore + */ +#define GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE 351 + + + + +/******************************************************************************* + * TRANSPORT message types + ******************************************************************************/ + +/** + * Message from the core saying that the transport + * server should start giving it messages. This + * should automatically trigger the transmission of + * a HELLO message. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_START 360 + +/** + * Message from TRANSPORT notifying about a + * client that connected to us. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT 361 + +/** + * Message from TRANSPORT notifying about a + * client that disconnected from us. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT 362 + +/** + * Request to TRANSPORT to transmit a message. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_SEND 363 + +/** + * Confirmation from TRANSPORT that message for transmission has been + * queued (and that the next message to this peer can now be passed to + * the service). Note that this confirmation does NOT imply that the + * message was fully transmitted. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK 364 + +/** + * Message from TRANSPORT notifying about a + * message that was received. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_RECV 365 + +/** + * Message telling transport to limit its receive rate. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA 366 + +/** + * Request to look addresses of peers in server. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING 367 + +/** + * Response to the address lookup request. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY 368 + +/** + * Register a client that wants to do blacklisting. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT 369 + +/** + * Query to a blacklisting client (is this peer blacklisted)? + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY 370 + +/** + * Reply from blacklisting client (answer to blacklist query). + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY 371 + +/** + * Transport PING message + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_PING 372 + +/** + * Transport PONG message + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_PONG 373 + +/** + * Message for transport service from a client asking that a + * connection be initiated with another peer. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT 374 + +/** + * Transport CONNECT message exchanged between transport services to + * indicate that a session should be marked as 'connected'. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT 375 + +/** + * Transport CONNECT_ACK message exchanged between transport services to + * indicate that a CONNECT message was accepted + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK 376 + +/** + * Transport CONNECT_ACK message exchanged between transport services to + * indicate that a CONNECT message was accepted + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK 377 + +/** + * Transport DISCONNECT message exchanged between transport services to + * indicate that a connection should be dropped. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT 378 + +/** + * Request to monitor addresses used by a peer or all peers. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE 380 + +/** + * Message send by a peer to notify the other to keep the session alive + * and measure latency in a regular interval + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE 381 + +/** + * Response to a GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE message to + * measure latency in a regular interval + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE 382 + + +/** + * Request to iterate over all known addresses. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE 383 + +/** + * Message send by a peer to notify the other to keep the session alive. + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON 384 + +/******************************************************************************* + * STREAM LIRBRARY MESSAGES + ******************************************************************************/ + +/** + * Message containing data exchanged between stream end-points over mesh. + */ +#define GNUNET_MESSAGE_TYPE_STREAM_DATA 400 + +/** + * ACK message + */ +#define GNUNET_MESSAGE_TYPE_STREAM_ACK 401 + +/** + * Handshake hello message + */ +#define GNUNET_MESSAGE_TYPE_STREAM_HELLO 402 + +/** + * Handshake hello acknowledgement message + */ +#define GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK 403 + +/** + * Reset message + */ +#define GNUNET_MESSAGE_TYPE_STREAM_RESET 404 + +/** + * Transmit close message (data transmission no longer possible after this + * message) + */ +#define GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE 405 + +/** + * Transmit close acknowledgement message + */ +#define GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK 406 + +/** + * Receive close message (data is no loger read by the receiver after this + * message) + */ +#define GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE 407 + +/** + * Receive close acknowledgement message + */ +#define GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK 408 + +/** + * Stream close message (data is no longer sent or read after this message) + */ +#define GNUNET_MESSAGE_TYPE_STREAM_CLOSE 409 + +/** + * Close acknowledgement message + */ +#define GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK 410 + +/******************************************************************************* + * FS-PUBLISH-HELPER IPC Messages + ******************************************************************************/ + +/** + * Progress information from the helper: found a file + */ +#define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE 420 + +/** + * Progress information from the helper: found a directory + */ +#define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY 421 + +/** + * Error signal from the helper. + */ +#define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR 422 + +/** + * Signal that helper skipped a file. + */ +#define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE 423 + +/** + * Signal that helper is done scanning the directory tree. + */ +#define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE 424 + +/** + * Extracted meta data from the helper. + */ +#define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA 425 + +/** + * Signal that helper is done. + */ +#define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED 426 + +/******************************************************************************* + * NAMESTORE message types + ******************************************************************************/ + +/** + * Request update and listing of a peer. + */ +#define GNUNET_MESSAGE_TYPE_NAMESTORE_START 430 + +/** + * Next available: 440 + */ + +/******************************************************************************* + * TODO: we need a way to register message types centrally (via some webpage). + * For now: unofficial extensions should start at 48k, internal extensions + * define here should leave some room (4-10 additional messages to the previous + * extension). + ******************************************************************************/ + +/** + * Type used to match 'all' message types. + */ +#define GNUNET_MESSAGE_TYPE_ALL 65535 + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_PROTOCOLS_H */ +#endif +/* end of gnunet_protocols.h */ diff --git a/src/include/gnunet_pseudonym_lib.h b/src/include/gnunet_pseudonym_lib.h new file mode 100644 index 0000000..bde98ef --- /dev/null +++ b/src/include/gnunet_pseudonym_lib.h @@ -0,0 +1,140 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_pseudonym_lib.h + * @brief functions related to pseudonyms + * @author Christian Grothoff + */ + +#ifndef GNUNET_PSEUDONYM_LIB_H +#define GNUNET_PSEUDONYM_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_container_lib.h" + +/** + * Iterator over all known pseudonyms. + * + * @param cls closure + * @param pseudonym hash code of public key of pseudonym + * @param md meta data known about the pseudonym + * @param rating the local rating of the pseudonym + * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort + */ +typedef int (*GNUNET_PSEUDONYM_Iterator) (void *cls, + const GNUNET_HashCode * pseudonym, + const struct GNUNET_CONTAINER_MetaData + * md, int rating); + +/** + * Change the ranking of a pseudonym. + * + * @param cfg overall configuration + * @param nsid id of the pseudonym + * @param delta by how much should the rating be changed? + * @return new rating of the namespace + */ +int +GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * nsid, int delta); + +/** + * Add a pseudonym to the set of known pseudonyms. + * For all pseudonym advertisements that we discover + * FS should automatically call this function. + * + * @param cfg overall configuration + * @param id the pseudonym identifier + * @param meta metadata for the pseudonym + */ +void +GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * id, + const struct GNUNET_CONTAINER_MetaData *meta); + + +/** + * List all known pseudonyms. + * + * @param cfg overall configuration + * @param iterator function to call for each pseudonym + * @param closure closure for iterator + * @return number of pseudonyms found + */ +int +GNUNET_PSEUDONYM_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_PSEUDONYM_Iterator iterator, void *closure); + +/** + * Register callback to be invoked whenever we discover + * a new pseudonym. + */ +int +GNUNET_PSEUDONYM_discovery_callback_register (const struct + GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_PSEUDONYM_Iterator + iterator, void *closure); + +/** + * Unregister namespace discovery callback. + */ +int +GNUNET_PSEUDONYM_discovery_callback_unregister (GNUNET_PSEUDONYM_Iterator + iterator, void *closure); + +/** + * Return the unique, human readable name for the given pseudonym. + * + * @return NULL on failure (should never happen) + */ +char * +GNUNET_PSEUDONYM_id_to_name (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * pseudo); + +/** + * Get the pseudonym ID belonging to the given human readable name. + * + * @return GNUNET_OK on success + */ +int +GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *hname, GNUNET_HashCode * psid); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_PSEUDONYM_LIB_H */ +#endif +/* end of gnunet_pseudonym_lib.h */ diff --git a/src/include/gnunet_resolver_service.h b/src/include/gnunet_resolver_service.h new file mode 100644 index 0000000..498400d --- /dev/null +++ b/src/include/gnunet_resolver_service.h @@ -0,0 +1,169 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_resolver_service.h + * @brief functions related to doing DNS lookups + * @author Christian Grothoff + */ + +#ifndef GNUNET_RESOLVER_SERVICE_H +#define GNUNET_RESOLVER_SERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_configuration_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + + +/** + * Function called by the resolver for each address obtained from DNS. + * + * @param cls closure + * @param addr one of the addresses of the host, NULL for the last address + * @param addrlen length of the address + */ +typedef void (*GNUNET_RESOLVER_AddressCallback) (void *cls, + const struct sockaddr * addr, + socklen_t addrlen); + + +/** + * Handle to a request given to the resolver. Can be used to cancel + * the request prior to the timeout or successful execution. + */ +struct GNUNET_RESOLVER_RequestHandle; + +/** + * Create the connection to the resolver service. + * + * @param cfg configuration to use + */ +void +GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Destroy the connection to the resolver service. + */ +void +GNUNET_RESOLVER_disconnect (void); + + +/** + * Convert a string to one or more IP addresses. + * + * @param hostname the hostname to resolve + * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" + * @param callback function to call with addresses + * @param callback_cls closure for callback + * @param timeout how long to try resolving + * @return handle that can be used to cancel the request, NULL on error + */ +struct GNUNET_RESOLVER_RequestHandle * +GNUNET_RESOLVER_ip_get (const char *hostname, int af, + struct GNUNET_TIME_Relative timeout, + GNUNET_RESOLVER_AddressCallback callback, + void *callback_cls); + + +/** + * Resolve our hostname to an IP address. + * + * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" + * @param callback function to call with addresses + * @param cls closure for callback + * @param timeout how long to try resolving + * @return handle that can be used to cancel the request, NULL on error + */ +struct GNUNET_RESOLVER_RequestHandle * +GNUNET_RESOLVER_hostname_resolve (int af, + struct GNUNET_TIME_Relative timeout, + GNUNET_RESOLVER_AddressCallback callback, + void *cls); + + +/** + * Function called by the resolver for each hostname obtained from DNS. + * + * @param cls closure + * @param hostname one of the names for the host, NULL + * on the last call to the callback + */ +typedef void (*GNUNET_RESOLVER_HostnameCallback) (void *cls, + const char *hostname); + +/** + * Get local fully qualified domain name + * + * @return local hostname, caller must free + */ +char * +GNUNET_RESOLVER_local_fqdn_get (void); + + +/** + * Perform a reverse DNS lookup. + * + * @param sa host address + * @param salen length of host address + * @param do_resolve use GNUNET_NO to return numeric hostname + * @param timeout how long to try resolving + * @param callback function to call with hostnames + * @param cls closure for callback + * @return handle that can be used to cancel the request, NULL on error + */ +struct GNUNET_RESOLVER_RequestHandle * +GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa, socklen_t salen, + int do_resolve, + struct GNUNET_TIME_Relative timeout, + GNUNET_RESOLVER_HostnameCallback callback, + void *cls); + + +/** + * Cancel a request that is still pending with the resolver. + * Note that a client MUST NOT cancel a request that has + * been completed (i.e, the callback has been called to + * signal timeout or the final result). + * + * @param rh handle of request to cancel + */ +void +GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_RESOLVER_SERVICE_H */ +#endif +/* end of gnunet_resolver_service.h */ diff --git a/src/include/gnunet_scheduler_lib.h b/src/include/gnunet_scheduler_lib.h new file mode 100644 index 0000000..e16ccc5 --- /dev/null +++ b/src/include/gnunet_scheduler_lib.h @@ -0,0 +1,555 @@ +/* + This file is part of GNUnet + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_scheduler_lib.h + * @brief API to schedule computations using continuation passing style + * @author Christian Grothoff + */ + +#ifndef GNUNET_SCHEDULER_LIB_H +#define GNUNET_SCHEDULER_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * Opaque reference to a task. + */ +typedef unsigned long long GNUNET_SCHEDULER_TaskIdentifier; + + +/** + * Constant used to indicate that the scheduled + * task has no others as prerequisites. + */ +#define GNUNET_SCHEDULER_NO_TASK ((GNUNET_SCHEDULER_TaskIdentifier) 0) + +/** + * Reasons why the schedule may have triggered + * the task now. + */ +enum GNUNET_SCHEDULER_Reason +{ + /** + * This is the very first task run during startup. + */ + GNUNET_SCHEDULER_REASON_STARTUP = 0, + + /** + * We are shutting down and are running all shutdown-related tasks + * (regardless of timeout, etc.). + */ + GNUNET_SCHEDULER_REASON_SHUTDOWN = 1, + + /** + * The specified timeout has expired. + * (also set if the delay given was 0). + */ + GNUNET_SCHEDULER_REASON_TIMEOUT = 2, + + /** + * The reading socket is ready. + */ + GNUNET_SCHEDULER_REASON_READ_READY = 4, + + /** + * The writing socket is ready. + */ + GNUNET_SCHEDULER_REASON_WRITE_READY = 8, + + /** + * The prerequisite task is done. + */ + GNUNET_SCHEDULER_REASON_PREREQ_DONE = 16 +}; + + +/** + * Valid task priorities. Use these, do not + * pass random integers! + */ +enum GNUNET_SCHEDULER_Priority +{ + /** + * Run with the same priority as the current job. + */ + GNUNET_SCHEDULER_PRIORITY_KEEP = 0, + + /** + * Run when otherwise idle. + */ + GNUNET_SCHEDULER_PRIORITY_IDLE = 1, + + /** + * Run as background job (higher than idle, + * lower than default). + */ + GNUNET_SCHEDULER_PRIORITY_BACKGROUND = 2, + + /** + * Run with the default priority (normal + * P2P operations). Any task that is scheduled + * without an explicit priority being specified + * will run with this priority. + */ + GNUNET_SCHEDULER_PRIORITY_DEFAULT = 3, + + /** + * Run with high priority (important requests). + * Higher than DEFAULT. + */ + GNUNET_SCHEDULER_PRIORITY_HIGH = 4, + + /** + * Run with priority for interactive tasks. + * Higher than "HIGH". + */ + GNUNET_SCHEDULER_PRIORITY_UI = 5, + + /** + * Run with priority for urgent tasks. Use + * for things like aborts and shutdowns that + * need to preempt "UI"-level tasks. + * Higher than "UI". + */ + GNUNET_SCHEDULER_PRIORITY_URGENT = 6, + + /** + * This is an internal priority level that is only used for tasks + * that are being triggered due to shutdown (they have automatically + * highest priority). User code must not use this priority level + * directly. Tasks run with this priority level that internally + * schedule other tasks will see their original priority level + * be inherited (unless otherwise specified). + */ + GNUNET_SCHEDULER_PRIORITY_SHUTDOWN = 7, + + /** + * Number of priorities (must be the last priority). + * This priority must not be used by clients. + */ + GNUNET_SCHEDULER_PRIORITY_COUNT = 8 +}; + +#include "gnunet_time_lib.h" +#include "gnunet_network_lib.h" + + +/** + * Context information passed to each scheduler task. + */ +struct GNUNET_SCHEDULER_TaskContext +{ + /** + * Reason why the task is run now + */ + enum GNUNET_SCHEDULER_Reason reason; + + /** + * Set of file descriptors ready for reading; + * note that additional bits may be set + * that were not in the original request + */ + const struct GNUNET_NETWORK_FDSet *read_ready; + + /** + * Set of file descriptors ready for writing; + * note that additional bits may be set + * that were not in the original request. + */ + const struct GNUNET_NETWORK_FDSet *write_ready; + +}; + + +/** + * Signature of the main function of a task. + * + * @param cls closure + * @param tc context information (why was this task triggered now) + */ +typedef void (*GNUNET_SCHEDULER_Task) (void *cls, + const struct GNUNET_SCHEDULER_TaskContext + * tc); + + +/** + * Signature of the select function used by the scheduler. + * GNUNET_NETWORK_socket_select matches it. + * + * @param cls closure + * @param rfds set of sockets to be checked for readability + * @param wfds set of sockets to be checked for writability + * @param efds set of sockets to be checked for exceptions + * @param timeout relative value when to return + * @return number of selected sockets, GNUNET_SYSERR on error + */ +typedef int (*GNUNET_SCHEDULER_select) (void *cls, + struct GNUNET_NETWORK_FDSet * rfds, + struct GNUNET_NETWORK_FDSet * wfds, + struct GNUNET_NETWORK_FDSet * efds, + struct GNUNET_TIME_Relative timeout); +/** + * Initialize and run scheduler. This function will return when all + * tasks have completed. On systems with signals, receiving a SIGTERM + * (and other similar signals) will cause "GNUNET_SCHEDULER_shutdown" + * to be run after the active task is complete. As a result, SIGTERM + * causes all active tasks to be scheduled with reason + * "GNUNET_SCHEDULER_REASON_SHUTDOWN". (However, tasks added + * afterwards will execute normally!). Note that any particular + * signal will only shut down one scheduler; applications should + * always only create a single scheduler. + * + * @param task task to run first (and immediately) + * @param task_cls closure of task + */ +void +GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls); + + +/** + * Request the shutdown of a scheduler. Marks all currently + * pending tasks as ready because of shutdown. This will + * cause all tasks to run (as soon as possible, respecting + * priorities and prerequisite tasks). Note that tasks + * scheduled AFTER this call may still be delayed arbitrarily. + */ +void +GNUNET_SCHEDULER_shutdown (); + + +/** + * Get information about the current load of this scheduler. Use this + * function to determine if an elective task should be added or simply + * dropped (if the decision should be made based on the number of + * tasks ready to run). + * + * * @param p priority-level to query, use KEEP to query the level + * of the current task, use COUNT to get the sum over + * all priority levels + * @return number of tasks pending right now + */ +unsigned int +GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p); + + +/** + * Obtain the reason code for why the current task was + * started. Will return the same value as + * the GNUNET_SCHEDULER_TaskContext's reason field. + * + * * @return reason(s) why the current task is run + */ +enum GNUNET_SCHEDULER_Reason +GNUNET_SCHEDULER_get_reason (void); + + +/** + * Cancel the task with the specified identifier. + * The task must not yet have run. + * + * * @param task id of the task to cancel + * @return the closure of the callback of the cancelled task + */ +void * +GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_TaskIdentifier task); + + +/** + * Continue the current execution with the given function. This is + * similar to the other "add" functions except that there is no delay + * and the reason code can be specified. + * + * * @param task main function of the task + * @param task_cls closure of task + * @param reason reason for task invocation + */ +void +GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls, + enum GNUNET_SCHEDULER_Reason reason); + + +/** + * Continue the current execution with the given function. This is + * similar to the other "add" functions except that there is no delay + * and the reason code can be specified. + * + * @param task main function of the task + * @param task_cls closure for 'main' + * @param reason reason for task invocation + * @param priority priority to use for the task + */ +void +GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, void *task_cls, + enum GNUNET_SCHEDULER_Reason reason, + enum GNUNET_SCHEDULER_Priority priority); + + +/** + * Schedule a new task to be run after the specified prerequisite task + * has completed. It will be run with DEFAULT priority. + * + * * @param prerequisite_task run this task after the task with the given + * task identifier completes (and any of our other + * conditions, such as delay, read or write-readiness + * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency + * on completion of other tasks (this will cause the task to run as + * soon as possible). + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, + GNUNET_SCHEDULER_Task task, void *task_cls); + + +/** + * Schedule a new task to be run with a specified priority. + * + * * @param prio how important is the new task? + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio, + GNUNET_SCHEDULER_Task task, void *task_cls); + + +/** + * Schedule a new task to be run as soon as possible. The task + * will be run with the DEFAULT priority. + * + * * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task, void *task_cls); + + +/** + * Schedule a new task to be run as soon as possible with the + * (transitive) ignore-shutdown flag either explicitly set or + * explicitly enabled. This task (and all tasks created from it, + * other than by another call to this function) will either count or + * not count for the 'lifeness' of the process. This API is only + * useful in a few special cases. + * + * @param lifeness GNUNET_YES if the task counts for lifeness, GNUNET_NO if not. + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness, + GNUNET_SCHEDULER_Task task, + void *task_cls); + + +/** + * Schedule a new task to be run with a specified delay. The task + * will be scheduled for execution once the delay has expired. It + * will be run with the DEFAULT priority. + * + * * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, + GNUNET_SCHEDULER_Task task, void *task_cls); + + +/** + * Schedule a new task to be run with a specified delay. The task + * will be scheduled for execution once the delay has expired. + * + * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param priority priority to use for the task + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay, + enum GNUNET_SCHEDULER_Priority priority, + GNUNET_SCHEDULER_Task task, void *task_cls); + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for reading. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. It will be run with the DEFAULT priority. + * + * * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param rfd read file-descriptor + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, + struct GNUNET_NETWORK_Handle *rfd, + GNUNET_SCHEDULER_Task task, void *task_cls); + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for writing. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. It will be run with the DEFAULT priority. + * + * * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param wfd write file-descriptor + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, + struct GNUNET_NETWORK_Handle *wfd, + GNUNET_SCHEDULER_Task task, void *task_cls); + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for reading. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. It will be run with the DEFAULT priority. + * + * * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param rfd read file-descriptor + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, + const struct GNUNET_DISK_FileHandle *rfd, + GNUNET_SCHEDULER_Task task, void *task_cls); + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for writing. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. It will be run with the DEFAULT priority. + * + * * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param wfd write file-descriptor + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, + const struct GNUNET_DISK_FileHandle *wfd, + GNUNET_SCHEDULER_Task task, void *task_cls); + + +/** + * Schedule a new task to be run with a specified delay or when any of + * the specified file descriptor sets is ready. The delay can be used + * as a timeout on the socket(s) being ready. The task will be + * scheduled for execution once either the delay has expired or any of + * the socket operations is ready. This is the most general + * function of the "add" family. Note that the "prerequisite_task" + * must be satisfied in addition to any of the other conditions. In + * other words, the task will be started when + * + * (prerequisite-run) + * && (delay-ready + * || any-rs-ready + * || any-ws-ready + * || shutdown-active) + * + * + * * @param prio how important is this task? + * @param prerequisite_task run this task after the task with the given + * task identifier completes (and any of our other + * conditions, such as delay, read or write-readiness + * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency + * on completion of other tasks. + * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", + * which means that the task will only be run after we receive SIGTERM + * @param rs set of file descriptors we want to read (can be NULL) + * @param ws set of file descriptors we want to write (can be NULL) + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, + GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, + struct GNUNET_TIME_Relative delay, + const struct GNUNET_NETWORK_FDSet *rs, + const struct GNUNET_NETWORK_FDSet *ws, + GNUNET_SCHEDULER_Task task, void *task_cls); + +/** + * Sets the select function to use in the scheduler (scheduler_select). + * + * @param new_select new select function to use (NULL to reset to default) + * @param new_select_cls closure for 'new_select' + */ +void +GNUNET_SCHEDULER_set_select (GNUNET_SCHEDULER_select new_select, + void *new_select_cls); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/gnunet_server_lib.h b/src/include/gnunet_server_lib.h new file mode 100644 index 0000000..7fb8ae7 --- /dev/null +++ b/src/include/gnunet_server_lib.h @@ -0,0 +1,715 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_server_lib.h + * @brief library for building GNUnet network servers + * + * @author Christian Grothoff + */ + +#ifndef GNUNET_SERVER_LIB_H +#define GNUNET_SERVER_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" + + +/** + * Largest supported message. + */ +#define GNUNET_SERVER_MAX_MESSAGE_SIZE 65536 + +/** + * Smallest supported message. + */ +#define GNUNET_SERVER_MIN_BUFFER_SIZE sizeof (struct GNUNET_MessageHeader) + +/** + * @brief handle for a server + */ +struct GNUNET_SERVER_Handle; + + +/** + * @brief opaque handle for a client of the server + */ +struct GNUNET_SERVER_Client; + + +/** + * Functions with this signature are called whenever a message is + * received. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +typedef void (*GNUNET_SERVER_MessageCallback) (void *cls, + struct GNUNET_SERVER_Client * + client, + const struct GNUNET_MessageHeader + * message); + + + +/** + * Message handler. Each struct specifies how to handle on particular + * type of message received. + */ +struct GNUNET_SERVER_MessageHandler +{ + /** + * Function to call for messages of "type". + */ + GNUNET_SERVER_MessageCallback callback; + + /** + * Closure argument for "callback". + */ + void *callback_cls; + + /** + * Type of the message this handler covers. + */ + uint16_t type; + + /** + * Expected size of messages of this type. Use 0 for + * variable-size. If non-zero, messages of the given + * type will be discarded (and the connection closed) + * if they do not have the right size. + */ + uint16_t expected_size; + +}; + + +/** + * Create a new server. + * + * @param access function for access control + * @param access_cls closure for access + * @param lsocks NULL-terminated array of listen sockets + * @param idle_timeout after how long should we timeout idle connections? + * @param require_found if YES, connections sending messages of unknown type + * will be closed + * @return handle for the new server, NULL on error + * (typically, "port" already in use) + */ +struct GNUNET_SERVER_Handle * +GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access, + void *access_cls, + struct GNUNET_NETWORK_Handle **lsocks, + struct GNUNET_TIME_Relative idle_timeout, + int require_found); + +/** + * Create a new server. + * + * @param access function for access control + * @param access_cls closure for access + * @param serverAddr address toes listen on (including port), NULL terminated array + * @param socklen lengths of respective serverAddr + * @param idle_timeout after how long should we timeout idle connections? + * @param require_found if YES, connections sending messages of unknown type + * will be closed + * @return handle for the new server, NULL on error + * (typically, "port" already in use) + */ +struct GNUNET_SERVER_Handle * +GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access, void *access_cls, + struct sockaddr *const *serverAddr, + const socklen_t * socklen, + struct GNUNET_TIME_Relative idle_timeout, + int require_found); + + +/** + * Free resources held by this server. + * + * @param s server to destroy + */ +void +GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s); + + +/** + * Add additional handlers to an existing server. + * + * @param server the server to add handlers to + * @param handlers array of message handlers for + * incoming messages; the last entry must + * have "NULL" for the "callback"; multiple + * entries for the same type are allowed, + * they will be called in order of occurence. + * These handlers can be removed later; + * the handlers array must exist until removed + * (or server is destroyed). + */ +void +GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server, + const struct GNUNET_SERVER_MessageHandler + *handlers); + + +/** + * Notify us when the server has enough space to transmit + * a message of the given size to the given client. + * + * @param client client to transmit message to + * @param size requested amount of buffer space + * @param timeout after how long should we give up (and call + * notify with buf NULL and size 0)? + * @param callback function to call when space is available + * @param callback_cls closure for callback + * @return non-NULL if the notify callback was queued; can be used + * to cancel the request using + * GNUNET_CONNECTION_notify_transmit_ready_cancel. + * NULL if we are already going to notify someone else (busy) + */ +struct GNUNET_CONNECTION_TransmitHandle * +GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client, + size_t size, + struct GNUNET_TIME_Relative timeout, + GNUNET_CONNECTION_TransmitReadyNotify + callback, void *callback_cls); + + +/** + * Set the persistent flag on this client, used to setup client connection + * to only be killed when the service it's connected to is actually dead. + * + * @param client the client to set the persistent flag on + */ +void +GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client); + +/** + * Resume receiving from this client, we are done processing the + * current request. This function must be called from within each + * GNUNET_SERVER_MessageCallback (or its respective continuations). + * + * @param client client we were processing a message of + * @param success GNUNET_OK to keep the connection open and + * continue to receive + * GNUNET_NO to close the connection (normal behavior) + * GNUNET_SYSERR to close the connection (signal + * serious error) + */ +void +GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success); + + +/** + * Change the timeout for a particular client. Decreasing the timeout + * may not go into effect immediately (only after the previous timeout + * times out or activity happens on the socket). + * + * @param client the client to update + * @param timeout new timeout for activities on the socket + */ +void +GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client, + struct GNUNET_TIME_Relative timeout); + + +/** + * Set if a client should finish a pending write when disconnecting. + */ +void +GNUNET_SERVER_client_set_finish_pending_write (struct GNUNET_SERVER_Client *client, + int finish); + + +/** + * Disable the warning the server issues if a message is not acknowledged + * in a timely fashion. Use this call if a client is intentionally delayed + * for a while. Only applies to the current message. + * + * @param client client for which to disable the warning + */ +void +GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client + *client); + + +/** + * Inject a message into the server, pretend it came + * from the specified client. Delivery of the message + * will happen instantly (if a handler is installed; + * otherwise the call does nothing). + * + * @param server the server receiving the message + * @param sender the "pretended" sender of the message + * can be NULL! + * @param message message to transmit + * @return GNUNET_OK if the message was OK and the + * connection can stay open + * GNUNET_SYSERR if the connection to the + * client should be shut down + */ +int +GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server, + struct GNUNET_SERVER_Client *sender, + const struct GNUNET_MessageHeader *message); + + +/** + * Add a TCP socket-based connection to the set of handles managed by + * this server. Use this function for outgoing (P2P) connections that + * we initiated (and where this server should process incoming + * messages). + * + * @param server the server to use + * @param connection the connection to manage (client must + * stop using this connection from now on) + * @return the client handle (client should call + * "client_drop" on the return value eventually) + */ +struct GNUNET_SERVER_Client * +GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server, + struct GNUNET_CONNECTION_Handle *connection); + + +/** + * Notify the server that the given client handle should + * be kept (keeps the connection up if possible, increments + * the internal reference counter). + * + * @param client the client to keep + */ +void +GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client); + + +/** + * Notify the server that the given client handle is no + * longer required. Decrements the reference counter. If + * that counter reaches zero an inactive connection maybe + * closed. + * + * @param client the client to drop + */ +void +GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client); + + +/** + * Obtain the network address of the other party. + * + * @param client the client to get the address for + * @param addr where to store the address + * @param addrlen where to store the length of the address + * @return GNUNET_OK on success + */ +int +GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client, + void **addr, size_t * addrlen); + + +/** + * Functions with this signature are called whenever a client + * is disconnected on the network level. + * + * @param cls closure + * @param client identification of the client; NULL + * for the last call when the server is destroyed + */ +typedef void (*GNUNET_SERVER_DisconnectCallback) (void *cls, + struct GNUNET_SERVER_Client * + client); + + +/** + * Ask the server to notify us whenever a client disconnects. + * This function is called whenever the actual network connection + * is closed; the reference count may be zero or larger than zero + * at this point. If the server is destroyed before this + * notification is explicitly cancelled, the 'callback' will + * once be called with a 'client' argument of NULL to indicate + * that the server itself is now gone (and that the callback + * won't be called anymore and also can no longer be cancelled). + * + * @param server the server manageing the clients + * @param callback function to call on disconnect + * @param callback_cls closure for callback + */ +void +GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server, + GNUNET_SERVER_DisconnectCallback callback, + void *callback_cls); + + +/** + * Ask the server to stop notifying us whenever a client disconnects. + * + * @param server the server manageing the clients + * @param callback function to call on disconnect + * @param callback_cls closure for callback + */ +void +GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, + GNUNET_SERVER_DisconnectCallback + callback, void *callback_cls); + + +/** + * Ask the server to disconnect from the given client. + * This is the same as returning GNUNET_SYSERR from a message + * handler, except that it allows dropping of a client even + * when not handling a message from that client. + * + * @param client the client to disconnect from + */ +void +GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client); + + +/** + * Configure this server's connections to continue handling client + * requests as usual even after we get a shutdown signal. The change + * only applies to clients that connect to the server from the outside + * using TCP after this call. Clients managed previously or those + * added using GNUNET_SERVER_connect_socket and + * GNUNET_SERVER_connect_callback are not affected by this option. + * + * @param h server handle + * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default + */ +void +GNUNET_SERVER_ignore_shutdown (struct GNUNET_SERVER_Handle *h, int do_ignore); + + + +/** + * Disable the "CORK" feature for communication with the given client, + * forcing the OS to immediately flush the buffer on transmission + * instead of potentially buffering multiple messages. + * + * @param client handle to the client + * @return GNUNET_OK on success + */ +int +GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client); + + +/** + * The tansmit context is the key datastructure for a conveniance API + * used for transmission of complex results to the client followed + * ONLY by signaling receive_done with success or error + */ +struct GNUNET_SERVER_TransmitContext; + + +/** + * Create a new transmission context for the + * given client. + * + * @param client client to create the context for. + * @return NULL on error + */ +struct GNUNET_SERVER_TransmitContext * +GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client); + + +/** + * Append a message to the transmission context. + * All messages in the context will be sent by + * the transmit_context_run method. + * + * @param tc context to use + * @param data what to append to the result message + * @param length length of data + * @param type type of the message + */ +void +GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext + *tc, const void *data, + size_t length, uint16_t type); + + +/** + * Append a message to the transmission context. + * All messages in the context will be sent by + * the transmit_context_run method. + * + * @param tc context to use + * @param msg message to append + */ +void +GNUNET_SERVER_transmit_context_append_message (struct + GNUNET_SERVER_TransmitContext + *tc, + const struct GNUNET_MessageHeader + *msg); + + +/** + * Execute a transmission context. If there is an error in the + * transmission, the receive_done method will be called with an error + * code (GNUNET_SYSERR), otherwise with GNUNET_OK. + * + * @param tc transmission context to use + * @param timeout when to time out and abort the transmission + */ +void +GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc, + struct GNUNET_TIME_Relative timeout); + + +/** + * Destroy a transmission context. This function must not be called + * after 'GNUNET_SERVER_transmit_context_run'. + * + * @param tc transmission context to destroy + * @param success code to give to 'GNUNET_SERVER_receive_done' for + * the client: GNUNET_OK to keep the connection open and + * continue to receive + * GNUNET_NO to close the connection (normal behavior) + * GNUNET_SYSERR to close the connection (signal + * serious error) + */ +void +GNUNET_SERVER_transmit_context_destroy (struct GNUNET_SERVER_TransmitContext + *tc, int success); + + +/** + * The notification context is the key datastructure for a conveniance + * API used for transmission of notifications to the client until the + * client disconnects (or the notification context is destroyed, in + * which case we disconnect these clients). Essentially, all + * (notification) messages are queued up until the client is able to + * read them. + */ +struct GNUNET_SERVER_NotificationContext; + + +/** + * Create a new notification context. + * + * @param server server for which this function creates the context + * @param queue_length maximum number of messages to keep in + * the notification queue; optional messages are dropped + * if the queue gets longer than this number of messages + * @return handle to the notification context + */ +struct GNUNET_SERVER_NotificationContext * +GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server, + unsigned int queue_length); + + +/** + * Destroy the context, force disconnect for all clients. + * + * @param nc context to destroy. + */ +void +GNUNET_SERVER_notification_context_destroy (struct + GNUNET_SERVER_NotificationContext + *nc); + + +/** + * Add a client to the notification context. + * + * @param nc context to modify + * @param client client to add + */ +void +GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext + *nc, + struct GNUNET_SERVER_Client *client); + + +/** + * Send a message to a particular client; must have + * already been added to the notification context. + * + * @param nc context to modify + * @param client client to transmit to + * @param msg message to send + * @param can_drop can this message be dropped due to queue length limitations + */ +void +GNUNET_SERVER_notification_context_unicast (struct + GNUNET_SERVER_NotificationContext + *nc, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader + *msg, int can_drop); + + +/** + * Send a message to all clients of this context. + * + * @param nc context to modify + * @param msg message to send + * @param can_drop can this message be dropped due to queue length limitations + */ +void +GNUNET_SERVER_notification_context_broadcast (struct + GNUNET_SERVER_NotificationContext + *nc, + const struct GNUNET_MessageHeader + *msg, int can_drop); + + + +/** + * Handle to a message stream tokenizer. + */ +struct GNUNET_SERVER_MessageStreamTokenizer; + +/** + * Functions with this signature are called whenever a + * complete message is received by the tokenizer. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +typedef void (*GNUNET_SERVER_MessageTokenizerCallback) (void *cls, void *client, + const struct + GNUNET_MessageHeader * + message); + + +/** + * Create a message stream tokenizer. + * + * @param cb function to call on completed messages + * @param cb_cls closure for cb + * @return handle to tokenizer + */ +struct GNUNET_SERVER_MessageStreamTokenizer * +GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb, + void *cb_cls); + + +/** + * Add incoming data to the receive buffer and call the + * callback for all complete messages. + * + * @param mst tokenizer to use + * @param client_identity ID of client for which this is a buffer, + * can be NULL (will be passed back to 'cb') + * @param buf input data to add + * @param size number of bytes in buf + * @param purge should any excess bytes in the buffer be discarded + * (i.e. for packet-based services like UDP) + * @param one_shot only call callback once, keep rest of message in buffer + * @return GNUNET_OK if we are done processing (need more data) + * GNUNET_NO if one_shot was set and we have another message ready + * GNUNET_SYSERR if the data stream is corrupt + */ +int +GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst, + void *client_identity, const char *buf, size_t size, + int purge, int one_shot); + + +/** + * Destroys a tokenizer. + * + * @param mst tokenizer to destroy + */ +void +GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst); + + +/** + * Signature of a function to create a custom tokenizer. + * + * @param cls closure from 'GNUNET_SERVER_set_callbacks' + * @param client handle to client the tokenzier will be used for + * @return handle to custom tokenizer ('mst') + */ +typedef void* (*GNUNET_SERVER_MstCreateCallback) (void *cls, + struct GNUNET_SERVER_Client *client); + +/** + * Signature of a function to destroy a custom tokenizer. + * + * @param cls closure from 'GNUNET_SERVER_set_callbacks' + * @param mst custom tokenizer handle + */ +typedef void (*GNUNET_SERVER_MstDestroyCallback) (void *cls, void *mst); + +/** + * Signature of a function to destroy a custom tokenizer. + * + * @param cls closure from 'GNUNET_SERVER_set_callbacks' + * @param mst custom tokenizer handle + * @param client_identity ID of client for which this is a buffer, + * can be NULL (will be passed back to 'cb') + * @param buf input data to add + * @param size number of bytes in buf + * @param purge should any excess bytes in the buffer be discarded + * (i.e. for packet-based services like UDP) + * @param one_shot only call callback once, keep rest of message in buffer + * @return GNUNET_OK if we are done processing (need more data) + * GNUNET_NO if one_shot was set and we have another message ready + * GNUNET_SYSERR if the data stream is corrupt + */ +typedef int (*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst, + struct GNUNET_SERVER_Client *client, + const char *buf, size_t size, + int purge, int one_shot); + + +/** + * Change functions used by the server to tokenize the message stream. + * (very rarely used). + * + * @param server server to modify + * @param create new tokenizer initialization function + * @param destroy new tokenizer destruction function + * @param receive new tokenizer receive function + * @param cls closure for 'create', 'receive', 'destroy' + */ +void +GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server, + GNUNET_SERVER_MstCreateCallback create, + GNUNET_SERVER_MstDestroyCallback destroy, + GNUNET_SERVER_MstReceiveCallback receive, + void *cls); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_SERVER_LIB_H */ +#endif +/* end of gnunet_server_lib.h */ diff --git a/src/include/gnunet_service_lib.h b/src/include/gnunet_service_lib.h new file mode 100644 index 0000000..1641e0f --- /dev/null +++ b/src/include/gnunet_service_lib.h @@ -0,0 +1,164 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_service_lib.h + * @brief functions related to starting services + * @author Christian Grothoff + */ + +#ifndef GNUNET_SERVICE_LIB_H +#define GNUNET_SERVICE_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_configuration_lib.h" +#include "gnunet_server_lib.h" + + +/** + * Get the list of addresses that a server for the given service + * should bind to. + * + * @param serviceName name of the service + * @param cfg configuration (which specifies the addresses) + * @param addrs set (call by reference) to an array of pointers to the + * addresses the server should bind to and listen on; the + * array will be NULL-terminated (on success) + * @param addr_lens set (call by reference) to an array of the lengths + * of the respective 'struct sockaddr' struct in the 'addrs' + * array (on success) + * @return number of addresses found on success, + * GNUNET_SYSERR if the configuration + * did not specify reasonable finding information or + * if it specified a hostname that could not be resolved; + * GNUNET_NO if the number of addresses configured is + * zero (in this case, '*addrs' and '*addr_lens' will be + * set to NULL). + */ +int +GNUNET_SERVICE_get_server_addresses (const char *serviceName, + const struct GNUNET_CONFIGURATION_Handle + *cfg, struct sockaddr ***addrs, + socklen_t ** addr_lens); + + +/** + * Function called by the service's run + * method to run service-specific setup code. + * + * @param cls closure + * @param server the initialized server + * @param cfg configuration to use + */ +typedef void (*GNUNET_SERVICE_Main) (void *cls, + struct GNUNET_SERVER_Handle * server, + const struct GNUNET_CONFIGURATION_Handle * + cfg); + + +/** + * Options for the service (bitmask). + */ +enum GNUNET_SERVICE_Options +{ + /** + * Use defaults. + */ + GNUNET_SERVICE_OPTION_NONE = 0, + + /** + * Do not trigger server shutdown on signals, allow for the user + * to terminate the server explicitly when needed. + */ + GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN = 1 +}; + + +/** + * Run a standard GNUnet service startup sequence (initialize loggers + * and configuration, parse options). + * + * @param argc number of command line arguments + * @param argv command line arguments + * @param serviceName our service name + * @param opt service options + * @param task main task of the service + * @param task_cls closure for task + * @return GNUNET_SYSERR on error, GNUNET_OK + * if we shutdown nicely + */ +int +GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName, + enum GNUNET_SERVICE_Options opt, GNUNET_SERVICE_Main task, + void *task_cls); + + +struct GNUNET_SERVICE_Context; + +/** + * Run a service startup sequence within an existing + * initialized system. + * + * @param serviceName our service name + * @param cfg configuration to use + * @return NULL on error, service handle + */ +struct GNUNET_SERVICE_Context * +GNUNET_SERVICE_start (const char *serviceName, + const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Obtain the server used by a service. Note that the server must NOT + * be destroyed by the caller. + * + * @param ctx the service context returned from the start function + * @return handle to the server for this service, NULL if there is none + */ +struct GNUNET_SERVER_Handle * +GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx); + + +/** + * Stop a service that was started with "GNUNET_SERVICE_start". + * + * @param sctx the service context returned from the start function + */ +void +GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_SERVICE_LIB_H */ +#endif +/* end of gnunet_service_lib.h */ diff --git a/src/include/gnunet_signal_lib.h b/src/include/gnunet_signal_lib.h new file mode 100644 index 0000000..1597c76 --- /dev/null +++ b/src/include/gnunet_signal_lib.h @@ -0,0 +1,84 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_signal_lib.h + * @brief functions related to signals + * @author Christian Grothoff + */ + +#ifndef GNUNET_SIGNAL_LIB_H +#define GNUNET_SIGNAL_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * Context created when a signal handler is installed; + * can be used to restore it to the previous state later. + */ +struct GNUNET_SIGNAL_Context; + +/** + * A signal handler. Since different OSes have different signatures + * for their handlers, the API only gives the most restrictive + * signature -- no arguments, no return value. Note that this will + * work even if the OS expects a function with arguments. However, + * the implementation must guarantee that this handler is not called + * for signals other than the one that it has been registered for. + */ +typedef void (*GNUNET_SIGNAL_Handler) (void); + +/** + * Install a signal handler that will be run if the + * given signal is received. + * + * @param signal the number of the signal + * @param handler the function to call + * @return context that can be used to restore, NULL on error + */ +struct GNUNET_SIGNAL_Context * +GNUNET_SIGNAL_handler_install (int signal, GNUNET_SIGNAL_Handler handler); + +/** + * Uninstall a previously installed signal hander. + * + * @param ctx context that was returned when the + * signal handler was installed + */ +void +GNUNET_SIGNAL_handler_uninstall (struct GNUNET_SIGNAL_Context *ctx); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_SIGNAL_LIB_H */ +#endif +/* end of gnunet_signal_lib.h */ diff --git a/src/include/gnunet_signatures.h b/src/include/gnunet_signatures.h new file mode 100644 index 0000000..580282d --- /dev/null +++ b/src/include/gnunet_signatures.h @@ -0,0 +1,127 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_signatures.h + * @brief constants for network signatures + * @author Christian Grothoff + */ + +#ifndef GNUNET_SIGNATURES_H +#define GNUNET_SIGNATURES_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * Test signature, not valid for anything other than writing + * a test. (Note that the signature verification code will + * accept this value). + */ +#define GNUNET_SIGNATURE_PURPOSE_TEST 0 + +/** + * Signature for confirming that this peer uses a particular address. + */ +#define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN 1 + +/** + * Signature for confirming that this peer intends to disconnect. + */ +#define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT 2 + +/** + * Purpose is to set a session key. + */ +#define GNUNET_SIGNATURE_PURPOSE_SET_KEY 3 + +/** + * Signature for a namespace/pseudonym advertisement (by + * the namespace owner). + */ +#define GNUNET_SIGNATURE_PURPOSE_NAMESPACE_ADVERTISEMENT 4 + +/** + * Signature by which a peer affirms that it is + * providing a certain bit of content (used + * in LOCation URIs). + */ +#define GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT 5 + +/** + * Signature in a KBlock of the FS module. + */ +#define GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK 6 + +/** + * Signature of content URI placed into a namespace. + */ +#define GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK 7 + +/** + * Signature of advertisment for a namespace. + */ +#define GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK 8 + +/** + * Keyword-based signature of advertisment for a namespace. + */ +#define GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG 9 + +/** + * + */ +#define GNUNET_SIGNATURE_PURPOSE_RESOLVER_RESPONSE 10 + +/** + * Signature of an GNUNET_DNS_Record + */ +#define GNUNET_SIGNATURE_PURPOSE_DNS_RECORD 11 + +/** + * Signature of a chat message. + */ +#define GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE 12 + +/** + * Signature of confirmation receipt for a chat message. + */ +#define GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT 13 + +/** + * Signature of a network size estimate message. + */ +#define GNUNET_SIGNATURE_PURPOSE_NSE_SEND 14 + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_SIGNATURES_H */ +#endif +/* end of gnunet_signatures.h */ diff --git a/src/include/gnunet_statistics_service.h b/src/include/gnunet_statistics_service.h new file mode 100644 index 0000000..bfd65f8 --- /dev/null +++ b/src/include/gnunet_statistics_service.h @@ -0,0 +1,205 @@ +/* + This file is part of GNUnet + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_statistics_service.h + * @brief API to create, modify and access statistics about + * the operation of GNUnet; all statistical values + * must be of type "unsigned long long". + * @author Christian Grothoff + */ + +#ifndef GNUNET_STATISTICS_SERVICE_H +#define GNUNET_STATISTICS_SERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_scheduler_lib.h" + +/** + * Version of the statistics API. + */ +#define GNUNET_STATISTICS_VERSION 0x00000000 + +/** + * Opaque handle for the statistics service. + */ +struct GNUNET_STATISTICS_Handle; + +/** + * Callback function to process statistic values. + * + * @param cls closure + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +typedef int (*GNUNET_STATISTICS_Iterator) (void *cls, const char *subsystem, + const char *name, uint64_t value, + int is_persistent); + +/** + * Get handle for the statistics service. + * + * @param subsystem name of subsystem using the service + * @param cfg services configuration in use + * @return handle to use + */ +struct GNUNET_STATISTICS_Handle * +GNUNET_STATISTICS_create (const char *subsystem, + const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Destroy a handle (free all state associated with + * it). + * + * @param h statistics handle to destroy + * @param sync_first set to GNUNET_YES if pending SET requests should + * be completed + */ +void +GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first); + + +/** + * Watch statistics from the peer (be notified whenever they change). + * + * @param handle identification of the statistics service + * @param subsystem limit to the specified subsystem, never NULL + * @param name name of the statistic value, never NULL + * @param proc function to call on each value + * @param proc_cls closure for proc + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_STATISTICS_watch (struct GNUNET_STATISTICS_Handle *handle, + const char *subsystem, const char *name, + GNUNET_STATISTICS_Iterator proc, void *proc_cls); + + +/** + * Stop watching statistics from the peer. + * + * @param handle identification of the statistics service + * @param subsystem limit to the specified subsystem, never NULL + * @param name name of the statistic value, never NULL + * @param proc function to call on each value + * @param proc_cls closure for proc + * @return GNUNET_OK on success, GNUNET_SYSERR on error (no such watch) + */ +int +GNUNET_STATISTICS_watch_cancel (struct GNUNET_STATISTICS_Handle *handle, + const char *subsystem, const char *name, + GNUNET_STATISTICS_Iterator proc, void *proc_cls); + + +/** + * Continuation called by the "get_all" and "get" functions. + * + * @param cls closure + * @param success GNUNET_OK if statistics were + * successfully obtained, GNUNET_SYSERR if not. + */ +typedef void (*GNUNET_STATISTICS_Callback) (void *cls, int success); + + +/** + * Handle that can be used to cancel a statistics 'get' operation. + */ +struct GNUNET_STATISTICS_GetHandle; + +/** + * Get statistic from the peer. + * + * @param handle identification of the statistics service + * @param subsystem limit to the specified subsystem, NULL for our subsystem + * @param name name of the statistic value, NULL for all values + * @param timeout after how long should we give up (and call + * notify with buf NULL and size 0)? + * @param cont continuation to call when done (can be NULL) + * @param proc function to call on each value + * @param cls closure for proc and cont + * @return NULL on error + */ +struct GNUNET_STATISTICS_GetHandle * +GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle, + const char *subsystem, const char *name, + struct GNUNET_TIME_Relative timeout, + GNUNET_STATISTICS_Callback cont, + GNUNET_STATISTICS_Iterator proc, void *cls); + + +/** + * Cancel a 'get' request. Must be called before the 'cont' + * function is called. + * + * @param gh handle of the request to cancel + */ +void +GNUNET_STATISTICS_get_cancel (struct GNUNET_STATISTICS_GetHandle *gh); + + +/** + * Set statistic value for the peer. Will always use our + * subsystem (the argument used when "handle" was created). + * + * @param handle identification of the statistics service + * @param name name of the statistic value + * @param value new value to set + * @param make_persistent should the value be kept across restarts? + */ +void +GNUNET_STATISTICS_set (struct GNUNET_STATISTICS_Handle *handle, + const char *name, uint64_t value, int make_persistent); + +/** + * Set statistic value for the peer. Will always use our + * subsystem (the argument used when "handle" was created). + * + * @param handle identification of the statistics service + * @param name name of the statistic value + * @param delta change in value (added to existing value) + * @param make_persistent should the value be kept across restarts? + */ +void +GNUNET_STATISTICS_update (struct GNUNET_STATISTICS_Handle *handle, + const char *name, int64_t delta, int make_persistent); + + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/gnunet_stream_lib.h b/src/include/gnunet_stream_lib.h new file mode 100644 index 0000000..930cc1d --- /dev/null +++ b/src/include/gnunet_stream_lib.h @@ -0,0 +1,297 @@ +/* + This file is part of GNUnet. + (C) 2011, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_stream_lib.h + * @brief stream handling using mesh API + * @author Sree Harsha Totakura + */ + +#ifndef GNUNET_STREAM_LIB_H +#define GNUNET_STREAM_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 +} +#endif +#endif + +#include "gnunet_util_lib.h" +#include "gnunet_mesh_service.h" + +/** + * Stream status + */ +enum GNUNET_STREAM_Status + { + /** + * All previous read/write operations are successfully done + */ + GNUNET_STREAM_OK = 0, + + /** + * A timeout occured while reading/writing the stream + */ + GNUNET_STREAM_TIMEOUT = 1, + + /** + * Other side has shutdown the socket for this type of operation + * (reading/writing) + */ + GNUNET_STREAM_SHUTDOWN = 2, + + /** + * A serious error occured while operating on this stream + */ + GNUNET_STREAM_SYSERR = 3 + }; + +/** + * Opaque handler for stream + */ +struct GNUNET_STREAM_Socket; + +/** + * Functions of this type will be called when a stream is established + * + * @param cls the closure from GNUNET_STREAM_open + * @param socket socket to use to communicate with the other side (read/write) + */ +typedef void (*GNUNET_STREAM_OpenCallback) (void *cls, + struct GNUNET_STREAM_Socket *socket); + + +/** + * Options for the stream. + */ +enum GNUNET_STREAM_Option + { + /** + * End of the option list. + */ + GNUNET_STREAM_OPTION_END = 0, + + /** + * Option to set the initial retransmission timeout (when do we retransmit + * a packet that did not yield an acknowledgement for the first time?). + * Repeated retransmissions will then use an exponential back-off. + * Takes a 'struct GNUNET_TIME_Relative' as the only argument. A value + * of '0' means to use the round-trip time (plus a tiny grace period); + * this is also the default. + */ + GNUNET_STREAM_OPTION_INITIAL_RETRANSMIT_TIMEOUT + }; + + +/** + * Tries to open a stream to the target peer + * + * @param cfg configuration to use + * @param target the target peer to which the stream has to be opened + * @param app_port the application port number which uniquely identifies this + * stream + * @param open_cb this function will be called after stream has be established + * @param open_cb_cls the closure for open_cb + * @param ... options to the stream, terminated by GNUNET_STREAM_OPTION_END + * @return if successful it returns the stream socket; NULL if stream cannot be + * opened + */ +struct GNUNET_STREAM_Socket * +GNUNET_STREAM_open (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PeerIdentity *target, + GNUNET_MESH_ApplicationType app_port, + GNUNET_STREAM_OpenCallback open_cb, + void *open_cb_cls, + ...); + + +/** + * Shutdown the stream for reading or writing (man 2 shutdown). + * + * @param socket the stream socket + * @param how SHUT_RD, SHUT_WR or SHUT_RDWR + */ +void +GNUNET_STREAM_shutdown (struct GNUNET_STREAM_Socket *socket, + int how); + + +/** + * Closes the stream + * + * @param socket the stream socket + */ +void +GNUNET_STREAM_close (struct GNUNET_STREAM_Socket *socket); + + +/** + * Functions of this type are called upon new stream connection from other peers + * + * @param cls the closure from GNUNET_STREAM_listen + * @param socket the socket representing the stream + * @param initiator the identity of the peer who wants to establish a stream + * with us + * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the + * stream (the socket will be invalid after the call) + */ +typedef int (*GNUNET_STREAM_ListenCallback) (void *cls, + struct GNUNET_STREAM_Socket *socket, + const struct + GNUNET_PeerIdentity *initiator); + + +/** + * A socket for listening. + */ +struct GNUNET_STREAM_ListenSocket; + +/** + * Listens for stream connections for a specific application ports + * + * @param cfg the configuration to use + * @param app_port the application port for which new streams will be accepted + * @param listen_cb this function will be called when a peer tries to establish + * a stream with us + * @param listen_cb_cls closure for listen_cb + * @return listen socket, NULL for any error + */ +struct GNUNET_STREAM_ListenSocket * +GNUNET_STREAM_listen (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_MESH_ApplicationType app_port, + GNUNET_STREAM_ListenCallback listen_cb, + void *listen_cb_cls); + + +/** + * Closes the listen socket + * + * @param socket the listen socket + */ +void +GNUNET_STREAM_listen_close (struct GNUNET_STREAM_ListenSocket *socket); + + +/** + * Functions of this signature are called whenever writing operations + * on a stream are executed + * + * @param cls the closure from GNUNET_STREAM_write + * @param status the status of the stream at the time this function is called + * @param size the number of bytes written + */ +typedef void (*GNUNET_STREAM_CompletionContinuation) (void *cls, + enum GNUNET_STREAM_Status + status, + size_t size); + + +/** + * Handle to cancel IO write operations. + */ +struct GNUNET_STREAM_IOWriteHandle; + + +/** + * Handle to cancel IO read operations. + */ +struct GNUNET_STREAM_IOReadHandle; + +/** + * Tries to write the given data to the stream + * + * @param socket the socket representing a stream + * @param data the data buffer from where the data is written into the stream + * @param size the number of bytes to be written from the data buffer + * @param timeout the timeout period + * @param write_cont the function to call upon writing some bytes into the stream + * @param write_cont_cls the closure + * @return handle to cancel the operation; NULL if a previous write is pending + */ +struct GNUNET_STREAM_IOWriteHandle * +GNUNET_STREAM_write (struct GNUNET_STREAM_Socket *socket, + const void *data, + size_t size, + struct GNUNET_TIME_Relative timeout, + GNUNET_STREAM_CompletionContinuation write_cont, + void *write_cont_cls); + + +/** + * Functions of this signature are called whenever data is available from the + * stream. + * + * @param cls the closure from GNUNET_STREAM_read + * @param status the status of the stream at the time this function is called + * @param data traffic from the other side + * @param size the number of bytes available in data read + * @return number of bytes of processed from 'data' (any data remaining should be + * given to the next time the read processor is called). + */ +typedef size_t (*GNUNET_STREAM_DataProcessor) (void *cls, + enum GNUNET_STREAM_Status status, + const void *data, + size_t size); + + +/** + * Tries to read data from the stream + * + * @param socket the socket representing a stream + * @param timeout the timeout period + * @param proc function to call with data (once only) + * @param proc_cls the closure for proc + * @return handle to cancel the operation + */ +struct GNUNET_STREAM_IOReadHandle * +GNUNET_STREAM_read (struct GNUNET_STREAM_Socket *socket, + struct GNUNET_TIME_Relative timeout, + GNUNET_STREAM_DataProcessor proc, + void *proc_cls); + + +/** + * Cancel pending write operation. + * + * @param ioh handle to operation to cancel + */ +void +GNUNET_STREAM_io_write_cancel (struct GNUNET_STREAM_IOWriteHandle *ioh); + + +/** + * Cancel pending read operation. + * + * @param ioh handle to operation to cancel + */ +void +GNUNET_STREAM_io_read_cancel (struct GNUNET_STREAM_IOReadHandle *ioh); + + +#if 0 +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif /* STREAM_PROTOCOL_H */ diff --git a/src/include/gnunet_strings_lib.h b/src/include/gnunet_strings_lib.h new file mode 100644 index 0000000..8101a81 --- /dev/null +++ b/src/include/gnunet_strings_lib.h @@ -0,0 +1,226 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_strings_lib.h + * @brief strings and string handling functions (including malloc + * and string tokenizing) + * + * @author Christian Grothoff + * @author Krista Bennett + * @author Gerd Knorr + * @author Ioana Patrascu + * @author Tzvetan Horozov + */ + +#ifndef GNUNET_STRINGS_LIB_H +#define GNUNET_STRINGS_LIB_H + +/* we need size_t, and since it can be both unsigned int + or unsigned long long, this IS platform dependent; + but "stdlib.h" should be portable 'enough' to be + unconditionally available... */ +#include + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_time_lib.h" + + +/** + * Convert a given fancy human-readable size to bytes. + * + * @param fancy_size human readable string (i.e. 1 MB) + * @param size set to the size in bytes + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, + unsigned long long *size); + + +/** + * Convert a given fancy human-readable time to our internal + * representation. + * + * @param fancy_size human readable string (i.e. 1 minute) + * @param rtime set to the relative time + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_size, + struct GNUNET_TIME_Relative *rtime); + + +/** + * Convert a given filesize into a fancy human-readable format. + * + * @param size number of bytes + * @return fancy representation of the size (possibly rounded) for humans + */ +char * +GNUNET_STRINGS_byte_size_fancy (unsigned long long size); + + +/** + * Convert the len characters long character sequence + * given in input that is in the given input charset + * to a string in given output charset. + * @return the converted string (0-terminated), + * if conversion fails, a copy of the orignal + * string is returned. + */ +char * +GNUNET_STRINGS_conv (const char *input, size_t len, + const char *input_charset, const char *output_charset); + +/** + * Convert the len characters long character sequence + * given in input that is in the given charset + * to UTF-8. + * + * @param input the input string (not necessarily 0-terminated) + * @param len the number of bytes in the input + * @param charset character set to convert from + * @return the converted string (0-terminated) + */ +char * +GNUNET_STRINGS_to_utf8 (const char *input, size_t len, const char *charset); + +/** + * Convert the len bytes-long UTF-8 string + * given in input to the given charset. + + * @return the converted string (0-terminated), + * if conversion fails, a copy of the orignal + * string is returned. + */ +char * +GNUNET_STRINGS_from_utf8 (const char *input, size_t len, const char *charset); + + +/** + * Complete filename (a la shell) from abbrevition. + * + * @param fil the name of the file, may contain ~/ or + * be relative to the current directory + * @return the full file name, + * NULL is returned on error + */ +char * +GNUNET_STRINGS_filename_expand (const char *fil); + + +/** + * Fill a buffer of the given size with + * count 0-terminated strings (given as varargs). + * If "buffer" is NULL, only compute the amount of + * space required (sum of "strlen(arg)+1"). + * + * Unlike using "snprintf" with "%s", this function + * will add 0-terminators after each string. The + * "GNUNET_string_buffer_tokenize" function can be + * used to parse the buffer back into individual + * strings. + * + * @param buffer the buffer to fill with strings, can + * be NULL in which case only the necessary + * amount of space will be calculated + * @param size number of bytes available in buffer + * @param count number of strings that follow + * @param ... count 0-terminated strings to copy to buffer + * @return number of bytes written to the buffer + * (or number of bytes that would have been written) + */ +size_t +GNUNET_STRINGS_buffer_fill (char *buffer, size_t size, unsigned int count, ...); + + +/** + * Given a buffer of a given size, find "count" + * 0-terminated strings in the buffer and assign + * the count (varargs) of type "const char**" to the + * locations of the respective strings in the + * buffer. + * + * @param buffer the buffer to parse + * @param size size of the buffer + * @param count number of strings to locate + * @param ... pointers to where to store the strings + * @return offset of the character after the last 0-termination + * in the buffer, or 0 on error. + */ +unsigned int +GNUNET_STRINGS_buffer_tokenize (const char *buffer, size_t size, + unsigned int count, ...); + + + +/** + * "man ctime_r", except for GNUnet time; also, unlike ctime, the + * return value does not include the newline character. + * + * @param t the absolute time to convert + * @return timestamp in human-readable form + */ +char * +GNUNET_STRINGS_absolute_time_to_string (struct GNUNET_TIME_Absolute t); + + +/** + * Give relative time in human-readable fancy format. + * + * @param delta time in milli seconds + * @return string in human-readable form + */ +char * +GNUNET_STRINGS_relative_time_to_string (struct GNUNET_TIME_Relative delta); + +/** + * "man basename" + * Returns a pointer to a part of filename (allocates nothing)! + * + * @param filename filename to extract basename from + * @return short (base) name of the file (that is, everything following the + * last directory separator in filename. If filename ends with a + * directory separator, the result will be a zero-length string. + * If filename has no directory separators, the result is filename + * itself. + */ +const char * +GNUNET_STRINGS_get_short_name (const char *filename); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_UTIL_STRING_H */ +#endif +/* end of gnunet_util_string.h */ diff --git a/src/include/gnunet_testing_lib.h b/src/include/gnunet_testing_lib.h new file mode 100644 index 0000000..03b8376 --- /dev/null +++ b/src/include/gnunet_testing_lib.h @@ -0,0 +1,1231 @@ +/* + This file is part of GNUnet + (C) 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_testing_lib.h + * @brief convenience API for writing testcases for GNUnet + * Many testcases need to start and stop gnunetd, + * and this library is supposed to make that easier + * for TESTCASES. Normal programs should always + * use functions from gnunet_{util,arm}_lib.h. This API is + * ONLY for writing testcases! + * @author Christian Grothoff + */ + +#ifndef GNUNET_TESTING_LIB_H +#define GNUNET_TESTING_LIB_H + +#include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#define HOSTKEYFILESIZE 914 + +/** + * Handle for a GNUnet daemon (technically a set of + * daemons; the handle is really for the master ARM + * daemon) started by the testing library. + */ +struct GNUNET_TESTING_Daemon; + +/** + * Linked list of hostnames and ports to use for starting daemons. + */ +struct GNUNET_TESTING_Host +{ + /** + * Pointer to next item in the list. + */ + struct GNUNET_TESTING_Host *next; + + /** + * Hostname to connect to. + */ + char *hostname; + + /** + * Username to use when connecting (may be null). + */ + char *username; + + /** + * Port to use for SSH connection (used for ssh + * connection forwarding, 0 to let ssh decide) + */ + uint16_t port; +}; + +/** + * Prototype of a function that will be called whenever + * a daemon was started by the testing library. + * + * @param cls closure + * @param id identifier for the daemon, NULL on error + * @param d handle for the daemon + * @param emsg error message (NULL on success) + */ +typedef void (*GNUNET_TESTING_NotifyHostkeyCreated) (void *cls, + const struct + GNUNET_PeerIdentity * id, + struct + GNUNET_TESTING_Daemon * d, + const char *emsg); + +/** + * Prototype of a function that will be called whenever + * a daemon was started by the testing library. + * + * @param cls closure + * @param id identifier for the daemon, NULL on error + * @param cfg configuration used by this daemon + * @param d handle for the daemon + * @param emsg error message (NULL on success) + */ +typedef void (*GNUNET_TESTING_NotifyDaemonRunning) (void *cls, + const struct + GNUNET_PeerIdentity * id, + const struct + GNUNET_CONFIGURATION_Handle + * cfg, + struct GNUNET_TESTING_Daemon + * d, const char *emsg); + +/** + * Handle to an entire testbed of GNUnet peers. + */ +struct GNUNET_TESTING_Testbed; + +/** + * Phases of starting GNUnet on a system. + */ +enum GNUNET_TESTING_StartPhase +{ + /** + * Copy the configuration file to the target system. + */ + SP_COPYING, + + /** + * Configuration file has been copied, generate hostkey. + */ + SP_COPIED, + + /** + * Create the hostkey for the peer. + */ + SP_HOSTKEY_CREATE, + + /** + * Hostkey generated, wait for topology to be finished. + */ + SP_HOSTKEY_CREATED, + + /** + * Topology has been created, now start ARM. + */ + SP_TOPOLOGY_SETUP, + + /** + * ARM has been started, check that it has properly daemonized and + * then try to connect to the CORE service (which should be + * auto-started by ARM). + */ + SP_START_ARMING, + + /** + * We're waiting for CORE to start. + */ + SP_START_CORE, + + /** + * CORE is up, now make sure we get the HELLO for this peer. + */ + SP_GET_HELLO, + + /** + * Core has notified us that we've established a connection to the service. + * The main FSM halts here and waits to be moved to UPDATE or CLEANUP. + */ + SP_START_DONE, + + /** + * We've been asked to terminate the instance and are now waiting for + * the remote command to stop the gnunet-arm process and delete temporary + * files. + */ + SP_SHUTDOWN_START, + + /** + * We should shutdown a *single* service via gnunet-arm. Call the dead_cb + * upon notification from gnunet-arm that the service has been stopped. + */ + SP_SERVICE_SHUTDOWN_START, + + /** + * We should start a *single* service via gnunet-arm. Call the daemon cb + * upon notification from gnunet-arm that the service has been started. + */ + SP_SERVICE_START, + + /** + * We've received a configuration update and are currently waiting for + * the copy process for the update to complete. Once it is, we will + * return to "SP_START_DONE" (and rely on ARM to restart all affected + * services). + */ + SP_CONFIG_UPDATE +}; + +/** + * Prototype of a function that will be called when a + * particular operation was completed the testing library. + * + * @param cls closure + * @param emsg NULL on success + */ +typedef void (*GNUNET_TESTING_NotifyCompletion) (void *cls, const char *emsg); + +/** + * Prototype of a function that will be called with the + * number of connections created for a particular topology. + * + * @param cls closure + * @param num_connections the number of connections created + */ +typedef void (*GNUNET_TESTING_NotifyConnections) (void *cls, + unsigned int num_connections); + +/** + * Handle for a GNUnet daemon (technically a set of + * daemons; the handle is really for the master ARM + * daemon) started by the testing library. + */ +struct GNUNET_TESTING_Daemon +{ + /** + * Our configuration. + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * At what time to give up starting the peer + */ + struct GNUNET_TIME_Absolute max_timeout; + + /** + * Host to run GNUnet on. + */ + char *hostname; + + /** + * Port to use for ssh, NULL to let system choose default. + */ + char *ssh_port_str; + + /** + * Result of GNUNET_i2s of this peer, + * for printing + */ + char *shortname; + + /** + * Username we are using. + */ + char *username; + + /** + * Name of the configuration file + */ + char *cfgfile; + + /** + * Callback to inform initiator that the peer's + * hostkey has been created. + */ + GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback; + + /** + * Closure for hostkey creation callback. + */ + void *hostkey_cls; + + /** + * Function to call when the peer is running. + */ + GNUNET_TESTING_NotifyDaemonRunning cb; + + /** + * Closure for cb. + */ + void *cb_cls; + + /** + * Arguments from "daemon_stop" call. + */ + GNUNET_TESTING_NotifyCompletion dead_cb; + + /** + * Closure for 'dead_cb'. + */ + void *dead_cb_cls; + + /** + * Arguments from "daemon_stop" call. + */ + GNUNET_TESTING_NotifyCompletion update_cb; + + /** + * Closure for 'update_cb'. + */ + void *update_cb_cls; + + /** + * PID of the process that we started last. + */ + struct GNUNET_OS_Process *proc; + + /** + * Handle to the server. + */ + struct GNUNET_CORE_Handle *server; + + /** + * Handle to the transport service of this peer + */ + struct GNUNET_TRANSPORT_Handle *th; + + /** + * Handle for getting HELLOs from transport + */ + struct GNUNET_TRANSPORT_GetHelloHandle *ghh; + + /** + * HELLO message for this peer + */ + struct GNUNET_HELLO_Message *hello; + + /** + * Handle to a pipe for reading the hostkey. + */ + struct GNUNET_DISK_PipeHandle *pipe_stdout; + + /** + * Currently, a single char * pointing to a service + * that has been churned off. + * + * FIXME: make this a linked list of services that have been churned off!!! + */ + char *churned_services; + + /** + * ID of the current task. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Identity of this peer (once started). + */ + struct GNUNET_PeerIdentity id; + + /** + * Flag to indicate that we've already been asked + * to terminate (but could not because some action + * was still pending). + */ + int dead; + + /** + * GNUNET_YES if the hostkey has been created + * for this peer, GNUNET_NO otherwise. + */ + int have_hostkey; + + /** + * In which phase are we during the start of + * this process? + */ + enum GNUNET_TESTING_StartPhase phase; + + /** + * Current position in 'hostkeybuf' (for reading from gnunet-peerinfo) + */ + unsigned int hostkeybufpos; + + /** + * Set to GNUNET_YES once the peer is up. + */ + int running; + + /** + * Used to tell shutdown not to remove configuration for the peer + * (if it's going to be restarted later) + */ + int churn; + + /** + * Output from gnunet-peerinfo is read into this buffer. + */ + char hostkeybuf[105]; + +}; + + +/** + * Handle to a group of GNUnet peers. + */ +struct GNUNET_TESTING_PeerGroup; + + +/** + * Prototype of a function that will be called whenever + * two daemons are connected by the testing library. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param first_cfg config for the first daemon + * @param second_cfg config for the second daemon + * @param first_daemon handle for the first daemon + * @param second_daemon handle for the second daemon + * @param emsg error message (NULL on success) + */ +typedef void (*GNUNET_TESTING_NotifyConnection) (void *cls, + const struct + GNUNET_PeerIdentity * first, + const struct + GNUNET_PeerIdentity * second, + uint32_t distance, + const struct + GNUNET_CONFIGURATION_Handle * + first_cfg, + const struct + GNUNET_CONFIGURATION_Handle * + second_cfg, + struct GNUNET_TESTING_Daemon * + first_daemon, + struct GNUNET_TESTING_Daemon * + second_daemon, + const char *emsg); + + +/** + * Prototype of a callback function indicating that two peers + * are currently connected. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param emsg error message (NULL on success) + */ +typedef void (*GNUNET_TESTING_NotifyTopology) (void *cls, + const struct GNUNET_PeerIdentity + * first, + const struct GNUNET_PeerIdentity + * second, const char *emsg); + + +/** + * Starts a GNUnet daemon. GNUnet must be installed on the target + * system and available in the PATH. The machine must furthermore be + * reachable via "ssh" (unless the hostname is "NULL") without the + * need to enter a password. + * + * @param cfg configuration to use + * @param timeout how long to wait starting up peers + * @param pretend GNUNET_YES to set up files but not start peer GNUNET_NO + * to really start the peer (default) + * @param hostname name of the machine where to run GNUnet + * (use NULL for localhost). + * @param ssh_username ssh username to use when connecting to hostname + * @param sshport port to pass to ssh process when connecting to hostname + * @param hostkey pointer to a hostkey to be written to disk (instead of being generated) + * @param hostkey_callback function to call once the hostkey has been + * generated for this peer, but it hasn't yet been started + * (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start) + * @param hostkey_cls closure for hostkey callback + * @param cb function to call once peer is up, or failed to start + * @param cb_cls closure for cb + * @return handle to the daemon (actual start will be completed asynchronously) + */ +struct GNUNET_TESTING_Daemon * +GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TIME_Relative timeout, int pretend, + const char *hostname, const char *ssh_username, + uint16_t sshport, const char *hostkey, + GNUNET_TESTING_NotifyHostkeyCreated + hostkey_callback, void *hostkey_cls, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls); + +/** + * Continues GNUnet daemon startup when user wanted to be notified + * once a hostkey was generated (for creating friends files, blacklists, + * etc.). + * + * @param daemon the daemon to finish starting + */ +void +GNUNET_TESTING_daemon_continue_startup (struct GNUNET_TESTING_Daemon *daemon); + + +/** + * Check whether the given daemon is running. + * + * @param daemon the daemon to check + * @return GNUNET_YES if the daemon is up, GNUNET_NO if the + * daemon is down, GNUNET_SYSERR on error. + */ +int +GNUNET_TESTING_test_daemon_running (struct GNUNET_TESTING_Daemon *daemon); + + +/** + * Obtain the peer identity of the peer with the given configuration + * handle. This function reads the private key of the peer, obtains + * the public key and hashes it. + * + * @param cfg configuration of the peer + * @param pid where to store the peer identity + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_TESTING_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_PeerIdentity *pid); + + +/** + * Restart (stop and start) a GNUnet daemon. + * + * @param d the daemon that should be restarted + * @param cb function called once the daemon is (re)started + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls); + + +/** + * Start a peer that has previously been stopped using the daemon_stop + * call (and files weren't deleted and the allow restart flag) + * + * @param daemon the daemon to start (has been previously stopped) + * @param timeout how long to wait for restart + * @param cb the callback for notification when the peer is running + * @param cb_cls closure for the callback + */ +void +GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls); + + +/** + * Starts a GNUnet daemon's service. + * + * @param d the daemon for which the service should be started + * @param service the name of the service to start + * @param timeout how long to wait for process for startup + * @param cb function called once gnunet-arm returns + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_start_service (struct GNUNET_TESTING_Daemon *d, + const char *service, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls); + + +/** + * Starts a GNUnet daemon's service which has been previously turned off. + * + * @param d the daemon for which the service should be started + * @param service the name of the service to start + * @param timeout how long to wait for process for startup + * @param cb function called once gnunet-arm returns + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_start_stopped_service (struct GNUNET_TESTING_Daemon *d, + char *service, + struct GNUNET_TIME_Relative + timeout, + GNUNET_TESTING_NotifyDaemonRunning + cb, void *cb_cls); + + +/** + * Get a certain testing daemon handle. + * + * @param pg handle to the set of running peers + * @param position the number of the peer to return + */ +struct GNUNET_TESTING_Daemon * +GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, + unsigned int position); + + +/** + * Get a daemon by peer identity, so callers can + * retrieve the daemon without knowing it's offset. + * + * @param pg the peer group to retrieve the daemon from + * @param peer_id the peer identity of the daemon to retrieve + * + * @return the daemon on success, or NULL if no such peer identity is found + */ +struct GNUNET_TESTING_Daemon * +GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg, + const struct GNUNET_PeerIdentity *peer_id); + + +/** + * Stops a GNUnet daemon. + * + * @param d the daemon that should be stopped + * @param timeout how long to wait for process for shutdown to complete + * @param cb function called once the daemon was stopped + * @param cb_cls closure for cb + * @param delete_files GNUNET_YES to remove files, GNUNET_NO + * to leave them (i.e. for restarting at a later time, + * or logfile inspection once finished) + * @param allow_restart GNUNET_YES to restart peer later (using this API) + * GNUNET_NO to kill off and clean up for good + */ +void +GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls, + int delete_files, int allow_restart); + + + +/** + * Create a new configuration using the given configuration + * as a template; however, each PORT in the existing cfg + * must be renumbered by incrementing "*port". If we run + * out of "*port" numbers, return NULL. + * + * @param cfg template configuration + * @param off the current peer offset + * @param port port numbers to use, update to reflect + * port numbers that were used + * @param upnum number to make unix domain socket names unique + * @param hostname hostname of the controlling host, to allow control connections from + * @param fdnum number used to offset the unix domain socket for grouped processes + * (such as statistics or peerinfo, which can be shared among others) + * + * @return new configuration, NULL on error + */ +struct GNUNET_CONFIGURATION_Handle * +GNUNET_TESTING_create_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t off, + uint16_t * port, uint32_t * upnum, const char *hostname, + uint32_t * fdnum); + +/** + * Changes the configuration of a GNUnet daemon. + * + * @param d the daemon that should be modified + * @param cfg the new configuration for the daemon + * @param cb function called once the configuration was changed + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d, + struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_TESTING_NotifyCompletion cb, + void *cb_cls); + + +/** + * Stops a single service of a GNUnet daemon. Used like daemon_stop, + * only doesn't stop the entire peer in any case. If the service + * is not currently running, this call is likely to fail after + * timeout! + * + * @param d the daemon that should be stopped + * @param service the name of the service to stop + * @param timeout how long to wait for process for shutdown to complete + * @param cb function called once the service was stopped + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_stop_service (struct GNUNET_TESTING_Daemon *d, + const char *service, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, + void *cb_cls); + + +/** + * Read a testing hosts file based on a configuration. + * Returns a DLL of hosts (caller must free!) on success + * or NULL on failure. + * + * @param cfg a configuration with a testing section + * + * @return DLL of hosts on success, NULL on failure + */ +struct GNUNET_TESTING_Host * +GNUNET_TESTING_hosts_load (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Start count gnunet instances with the same set of transports and + * applications. The port numbers (any option called "PORT") will be + * adjusted to ensure that no two peers running on the same system + * have the same port(s) in their respective configurations. + * + * @param cfg configuration template to use + * @param total number of daemons to start + * @param max_concurrent_connections for testing, how many peers can +* we connect to simultaneously + * @param max_concurrent_ssh when starting with ssh, how many ssh + * connections will we allow at once (based on remote hosts allowed!) + * @param timeout total time allowed for peers to start + * @param hostkey_callback function to call on each peers hostkey generation + * if NULL, peers will be started by this call, if non-null, + * GNUNET_TESTING_daemons_continue_startup must be called after + * successful hostkey generation + * @param hostkey_cls closure for hostkey callback + * @param cb function to call on each daemon that was started + * @param cb_cls closure for cb + * @param connect_callback function to call each time two hosts are connected + * @param connect_callback_cls closure for connect_callback + * @param hostnames linked list of host structs to use to start peers on + * (NULL to run on localhost only) + * + * @return NULL on error, otherwise handle to control peer group + */ +struct GNUNET_TESTING_PeerGroup * +GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int total, + unsigned int max_concurrent_connections, + unsigned int max_concurrent_ssh, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyHostkeyCreated + hostkey_callback, void *hostkey_cls, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls, + GNUNET_TESTING_NotifyConnection connect_callback, + void *connect_callback_cls, + const struct GNUNET_TESTING_Host *hostnames); + + +/** + * Function which continues a peer group starting up + * after successfully generating hostkeys for each peer. + * + * @param pg the peer group to continue starting + */ +void +GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg); + + +/** + * Handle for an active request to connect two peers. + */ +struct GNUNET_TESTING_ConnectContext; + + +/** + * Establish a connection between two GNUnet daemons. The daemons + * must both be running and not be stopped until either the + * 'cb' callback is called OR the connection request has been + * explicitly cancelled. + * + * @param d1 handle for the first daemon + * @param d2 handle for the second daemon + * @param timeout how long is the connection attempt + * allowed to take? + * @param max_connect_attempts how many times should we try to reconnect + * (within timeout) + * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume + * the HELLO has already been exchanged + * @param cb function to call at the end + * @param cb_cls closure for cb + * @return handle to cancel the request, NULL on error + */ +struct GNUNET_TESTING_ConnectContext * +GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, + struct GNUNET_TESTING_Daemon *d2, + struct GNUNET_TIME_Relative timeout, + unsigned int max_connect_attempts, + int send_hello, + GNUNET_TESTING_NotifyConnection cb, + void *cb_cls); + + + +/** + * Cancel an attempt to connect two daemons. + * + * @param cc connect context + */ +void +GNUNET_TESTING_daemons_connect_cancel (struct GNUNET_TESTING_ConnectContext + *cc); + + + +/** + * Restart all peers in the given group. + * + * @param pg the handle to the peer group + * @param callback function to call on completion (or failure) + * @param callback_cls closure for the callback function + */ +void +GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_NotifyCompletion callback, + void *callback_cls); + + +/** + * Shutdown all peers started in the given group. + * + * @param pg handle to the peer group + * @param timeout how long to wait for shutdown + * @param cb callback to notify upon success or failure + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls); + + +/** + * Count the number of running peers. + * + * @param pg handle for the peer group + * + * @return the number of currently running peers in the peer group + */ +unsigned int +GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg); + + +/** + * Simulate churn by stopping some peers (and possibly + * re-starting others if churn is called multiple times). This + * function can only be used to create leave-join churn (peers "never" + * leave for good). First "voff" random peers that are currently + * online will be taken offline; then "von" random peers that are then + * offline will be put back online. No notifications will be + * generated for any of these operations except for the callback upon + * completion. Note that the implementation is at liberty to keep + * the ARM service itself (but none of the other services or daemons) + * running even though the "peer" is being varied offline. + * + * @param pg handle for the peer group + * @param service the service to churn on/off, NULL for all + * @param voff number of peers that should go offline + * @param von number of peers that should come back online; + * must be zero on first call (since "testbed_start" + * always starts all of the peers) + * @param timeout how long to wait for operations to finish before + * giving up + * @param cb function to call at the end + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg, + char *service, unsigned int voff, + unsigned int von, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls); + + +/** + * Start a given service for each of the peers in the peer group. + * + * @param pg handle for the peer group + * @param service the service to start + * @param timeout how long to wait for operations to finish before + * giving up + * @param cb function to call once finished + * @param cb_cls closure for cb + * + */ +void +GNUNET_TESTING_daemons_start_service (struct GNUNET_TESTING_PeerGroup *pg, + char *service, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, + void *cb_cls); + + +/** + * Callback function to process statistic values. + * + * @param cls closure + * @param peer the peer the statistics belong to + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +typedef int (*GNUNET_TESTING_STATISTICS_Iterator) (void *cls, + const struct + GNUNET_PeerIdentity * peer, + const char *subsystem, + const char *name, + uint64_t value, + int is_persistent); + + +/** + * Iterate over all (running) peers in the peer group, retrieve + * all statistics from each. + * + * @param pg the peergroup to iterate statistics of + * @param cont continuation to call once call is completed(?) + * @param proc processing function for each statistic retrieved + * @param cls closure to pass to proc + */ +void +GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_STATISTICS_Callback cont, + GNUNET_TESTING_STATISTICS_Iterator proc, + void *cls); + + +/** + * Topologies supported for testbeds. + */ +enum GNUNET_TESTING_Topology +{ + /** + * A clique (everyone connected to everyone else). + */ + GNUNET_TESTING_TOPOLOGY_CLIQUE, + + /** + * Small-world network (2d torus plus random links). + */ + GNUNET_TESTING_TOPOLOGY_SMALL_WORLD, + + /** + * Small-world network (ring plus random links). + */ + GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING, + + /** + * Ring topology. + */ + GNUNET_TESTING_TOPOLOGY_RING, + + /** + * 2-d torus. + */ + GNUNET_TESTING_TOPOLOGY_2D_TORUS, + + /** + * Random graph. + */ + GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI, + + /** + * Certain percentage of peers are unable to communicate directly + * replicating NAT conditions + */ + GNUNET_TESTING_TOPOLOGY_INTERNAT, + + /** + * Scale free topology. + */ + GNUNET_TESTING_TOPOLOGY_SCALE_FREE, + + /** + * Straight line topology. + */ + GNUNET_TESTING_TOPOLOGY_LINE, + + /** + * All peers are disconnected. + */ + GNUNET_TESTING_TOPOLOGY_NONE, + + /** + * Read a topology from a given file. + */ + GNUNET_TESTING_TOPOLOGY_FROM_FILE +}; + +/** + * Options for connecting a topology. + */ +enum GNUNET_TESTING_TopologyOption +{ + /** + * Try to connect all peers specified in the topology. + */ + GNUNET_TESTING_TOPOLOGY_OPTION_ALL, + + /** + * Choose a random subset of connections to create. + */ + GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM, + + /** + * Create at least X connections for each peer. + */ + GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM, + + /** + * Using a depth first search, create one connection + * per peer. If any are missed (graph disconnected) + * start over at those peers until all have at least one + * connection. + */ + GNUNET_TESTING_TOPOLOGY_OPTION_DFS, + + /** + * Find the N closest peers to each allowed peer in the + * topology and make sure a connection to those peers + * exists in the connect topology. + */ + GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST, + + /** + * No options specified. + */ + GNUNET_TESTING_TOPOLOGY_OPTION_NONE +}; + + +/** + * Get a topology from a string input. + * + * @param topology where to write the retrieved topology + * @param topology_string The string to attempt to + * get a configuration value from + * @return GNUNET_YES if topology string matched a + * known topology, GNUNET_NO if not + */ +int +GNUNET_TESTING_topology_get (enum GNUNET_TESTING_Topology *topology, + const char *topology_string); + + +/** + * Get connect topology option from string input. + * + * @param topology_option where to write the retrieved topology + * @param topology_string The string to attempt to + * get a configuration value from + * @return GNUNET_YES if topology string matched a + * known topology, GNUNET_NO if not + */ +int +GNUNET_TESTING_topology_option_get (enum GNUNET_TESTING_TopologyOption + *topology_option, + const char *topology_string); + + +/** + * Takes a peer group and creates a topology based on the + * one specified. Creates a topology means generates friend + * files for the peers so they can only connect to those allowed + * by the topology. This will only have an effect once peers + * are started if the FRIENDS_ONLY option is set in the base + * config. + * + * Also takes an optional restrict topology which + * disallows direct connections UNLESS they are specified in + * the restricted topology. + * + * A simple example; if the topology option is set to LINE + * peers can ONLY connect in a LINE. However, if the topology + * option is set to 2D-torus and the restrict option is set to + * line with restrict_transports equal to "tcp udp", then peers + * may connect in a 2D-torus, but will be restricted to tcp and + * udp connections only in a LINE. Generally it only makes + * sense to do this if restrict_topology is a subset of topology. + * + * For testing peer discovery, etc. it is generally better to + * leave restrict_topology as GNUNET_TESTING_TOPOLOGY_NONE and + * then use the connect_topology function to restrict the initial + * connection set. + * + * @param pg the peer group struct representing the running peers + * @param topology which topology to connect the peers in + * @param restrict_topology allow only direct connections in this topology, + * based on those listed in restrict_transports, set to + * GNUNET_TESTING_TOPOLOGY_NONE for no restrictions + * @param restrict_transports space delimited list of transports to blacklist + * to create restricted topology, NULL for none + * + * @return the maximum number of connections were all allowed peers + * connected to each other + */ +unsigned int +GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg, + enum GNUNET_TESTING_Topology topology, + enum GNUNET_TESTING_Topology restrict_topology, + const char *restrict_transports); + + +/** + * Iterate over all (running) peers in the peer group, retrieve + * all connections that each currently has. + * + * @param pg the peer group we are concerned with + * @param cb callback for topology information + * @param cls closure for callback + */ +void +GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_NotifyTopology cb, void *cls); + + +/** + * Stop the connection process temporarily. + * + * @param pg the peer group to stop connecting + */ +void +GNUNET_TESTING_stop_connections (struct GNUNET_TESTING_PeerGroup *pg); + + +/** + * Resume the connection process. + * + * @param pg the peer group to resume connecting + */ +void +GNUNET_TESTING_resume_connections (struct GNUNET_TESTING_PeerGroup *pg); + + +/** + * There are many ways to connect peers that are supported by this function. + * To connect peers in the same topology that was created via the + * GNUNET_TESTING_create_topology, the topology variable must be set to + * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified, + * a new instance of that topology will be generated and attempted to be + * connected. This could result in some connections being impossible, + * because some topologies are non-deterministic. + * + * @param pg the peer group struct representing the running peers + * @param topology which topology to connect the peers in + * @param options options for connecting the topology + * @param option_modifier modifier for options that take a parameter + * @param connect_timeout how long to wait before giving up on connecting + * two peers + * @param connect_attempts how many times to attempt to connect two peers + * over the connect_timeout duration + * @param notify_callback notification to be called once all connections completed + * @param notify_cls closure for notification callback + * + * @return the number of connections that will be attempted, GNUNET_SYSERR on error + */ +int +GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg, + enum GNUNET_TESTING_Topology topology, + enum GNUNET_TESTING_TopologyOption options, + double option_modifier, + struct GNUNET_TIME_Relative connect_timeout, + unsigned int connect_attempts, + GNUNET_TESTING_NotifyCompletion + notify_callback, void *notify_cls); + + +/** + * Start or stop an individual peer from the given group. + * + * @param pg handle to the peer group + * @param offset which peer to start or stop + * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it + * @param timeout how long to wait for shutdown + * @param cb function to call at the end + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, + unsigned int offset, int desired_status, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls); + + +/** + * Start a peer group with a given number of peers. Notify + * on completion of peer startup and connection based on given + * topological constraints. Optionally notify on each + * established connection. + * + * @param cfg configuration template to use + * @param total number of daemons to start + * @param timeout total time allowed for peers to start + * @param connect_cb function to call each time two daemons are connected + * @param peergroup_cb function to call once all peers are up and connected + * @param peergroup_cls closure for peergroup callbacks + * @param hostnames linked list of host structs to use to start peers on + * (NULL to run on localhost only) + * + * @return NULL on error, otherwise handle to control peer group + */ +struct GNUNET_TESTING_PeerGroup * +GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int total, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyConnection connect_cb, + GNUNET_TESTING_NotifyCompletion peergroup_cb, + void *peergroup_cls, + const struct GNUNET_TESTING_Host *hostnames); + + +/** + * Print current topology to a graphviz readable file. + * + * @param pg a currently running peergroup to print to file + * @param output_filename the file to write the topology to + * @param notify_cb callback to call upon completion or failure + * @param notify_cb_cls closure for notify_cb + * + */ +void +GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg, + const char *output_filename, + GNUNET_TESTING_NotifyCompletion + notify_cb, void *notify_cb_cls); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/gnunet_time_lib.h b/src/include/gnunet_time_lib.h new file mode 100644 index 0000000..7090c33 --- /dev/null +++ b/src/include/gnunet_time_lib.h @@ -0,0 +1,429 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_time_lib.h + * @brief functions related to time + * + * @author Christian Grothoff + */ + +#ifndef GNUNET_TIME_LIB_H +#define GNUNET_TIME_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" + +/** + * Time for absolute times used by GNUnet, in milliseconds. + */ +struct GNUNET_TIME_Absolute +{ + /** + * The actual value. + */ + uint64_t abs_value; +}; + +/** + * Time for relative time used by GNUnet, in milliseconds. + * Always positive, so we can only refer to future time. + */ +struct GNUNET_TIME_Relative +{ + /** + * The actual value. + */ + uint64_t rel_value; +}; + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Time for relative time used by GNUnet, in milliseconds and in network byte order. + */ +struct GNUNET_TIME_RelativeNBO +{ + /** + * The actual value (in network byte order). + */ + uint64_t rel_value__ GNUNET_PACKED; +}; + + +/** + * Time for absolute time used by GNUnet, in milliseconds and in network byte order. + */ +struct GNUNET_TIME_AbsoluteNBO +{ + /** + * The actual value (in network byte order). + */ + uint64_t abs_value__ GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Relative time zero. + */ +#define GNUNET_TIME_UNIT_ZERO GNUNET_TIME_relative_get_zero() + +/** + * Absolute time zero. + */ +#define GNUNET_TIME_UNIT_ZERO_ABS GNUNET_TIME_absolute_get_zero() + +/** + * One millisecond, our basic time unit. + */ +#define GNUNET_TIME_UNIT_MILLISECONDS GNUNET_TIME_relative_get_unit() + +/** + * One second. + */ +#define GNUNET_TIME_UNIT_SECONDS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 1000) + +/** + * One minute. + */ +#define GNUNET_TIME_UNIT_MINUTES GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * One hour. + */ +#define GNUNET_TIME_UNIT_HOURS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 60) + +/** + * One day. + */ +#define GNUNET_TIME_UNIT_DAYS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_HOURS, 24) + +/** + * One week. + */ +#define GNUNET_TIME_UNIT_WEEKS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_DAYS, 7) + +/** + * One month (30 days). + */ +#define GNUNET_TIME_UNIT_MONTHS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_DAYS, 30) + +/** + * One year (365 days). + */ +#define GNUNET_TIME_UNIT_YEARS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_DAYS, 365) + +/** + * Constant used to specify "forever". This constant + * will be treated specially in all time operations. + */ +#define GNUNET_TIME_UNIT_FOREVER_REL GNUNET_TIME_relative_get_forever () + +/** + * Constant used to specify "forever". This constant + * will be treated specially in all time operations. + */ +#define GNUNET_TIME_UNIT_FOREVER_ABS GNUNET_TIME_absolute_get_forever () + +/** + * Return relative time of 0ms. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_get_zero (void); + +/** + * Return absolute time of 0ms. + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_get_zero (void); + +/** + * Return relative time of 1ms. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_get_unit (void); + +/** + * Return "forever". + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_get_forever (void); + +/** + * Return "forever". + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_get_forever (void); + +/** + * Get the current time. + * + * @return the current time + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_get (void); + +/** + * Convert relative time to an absolute time in the + * future. + * + * @param rel relative time to convert + * @return timestamp that is "rel" in the future, or FOREVER if rel==FOREVER (or if we would overflow) + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel); + +/** + * Return the minimum of two relative time values. + * + * @param t1 first timestamp + * @param t2 other timestamp + * @return timestamp that is smaller + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_min (struct GNUNET_TIME_Relative t1, + struct GNUNET_TIME_Relative t2); + + +/** + * Return the maximum of two relative time values. + * + * @param t1 first timestamp + * @param t2 other timestamp + * @return timestamp that is larger + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_max (struct GNUNET_TIME_Relative t1, + struct GNUNET_TIME_Relative t2); + +/** + * Return the minimum of two absolute time values. + * + * @param t1 first timestamp + * @param t2 other timestamp + * @return timestamp that is smaller + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_min (struct GNUNET_TIME_Absolute t1, + struct GNUNET_TIME_Absolute t2); + +/** + * Return the maximum of two absolute time values. + * + * @param t1 first timestamp + * @param t2 other timestamp + * @return timestamp that is smaller + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_max (struct GNUNET_TIME_Absolute t1, + struct GNUNET_TIME_Absolute t2); + +/** + * Given a timestamp in the future, how much time + * remains until then? + * + * @param future some absolute time, typically in the future + * @return future - now, or 0 if now >= future, or FOREVER if future==FOREVER. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_absolute_get_remaining (struct GNUNET_TIME_Absolute future); + + +/** + * Calculate the estimate time of arrival/completion + * for an operation. + * + * @param start when did the operation start? + * @param finished how much has been done? + * @param total how much must be done overall (same unit as for "finished") + * @return remaining duration for the operation, + * assuming it continues at the same speed + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_calculate_eta (struct GNUNET_TIME_Absolute start, uint64_t finished, + uint64_t total); + + +/** + * Compute the time difference between the given start and end times. + * Use this function instead of actual subtraction to ensure that + * "FOREVER" and overflows are handeled correctly. + * + * @param start some absolute time + * @param end some absolute time (typically larger or equal to start) + * @return 0 if start >= end; FOREVER if end==FOREVER; otherwise end - start + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_absolute_get_difference (struct GNUNET_TIME_Absolute start, + struct GNUNET_TIME_Absolute end); + +/** + * Get the duration of an operation as the + * difference of the current time and the given start time "hence". + * + * @param whence some absolute time, typically in the past + * @return aborts if hence==FOREVER, 0 if hence > now, otherwise now-hence. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_absolute_get_duration (struct GNUNET_TIME_Absolute whence); + + +/** + * Add a given relative duration to the + * given start time. + * + * @param start some absolute time + * @param duration some relative time to add + * @return FOREVER if either argument is FOREVER or on overflow; start+duration otherwise + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_add (struct GNUNET_TIME_Absolute start, + struct GNUNET_TIME_Relative duration); + + +/** + * Subtract a given relative duration from the + * given start time. + * + * @param start some absolute time + * @param duration some relative time to subtract + * @return ZERO if start <= duration, or FOREVER if start time is FOREVER; start-duration otherwise + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_subtract (struct GNUNET_TIME_Absolute start, + struct GNUNET_TIME_Relative duration); + +/** + * Multiply relative time by a given factor. + * + * @param rel some duration + * @param factor integer to multiply with + * @return FOREVER if rel=FOREVER or on overflow; otherwise rel*factor + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel, + unsigned int factor); + +/** + * Divide relative time by a given factor. + * + * @param rel some duration + * @param factor integer to divide by + * @return FOREVER if rel=FOREVER or factor==0; otherwise rel/factor + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_divide (struct GNUNET_TIME_Relative rel, + unsigned int factor); + +/** + * Add relative times together. + * + * @param a1 some relative time + * @param a2 some other relative time + * @return FOREVER if either argument is FOREVER or on overflow; a1+a2 otherwise + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_add (struct GNUNET_TIME_Relative a1, + struct GNUNET_TIME_Relative a2); + +/** + * Subtract relative timestamp from the other. + * + * @param a1 first timestamp + * @param a2 second timestamp + * @return ZERO if a2>=a1 (including both FOREVER), FOREVER if a1 is FOREVER, a1-a2 otherwise + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_subtract (struct GNUNET_TIME_Relative a1, + struct GNUNET_TIME_Relative a2); + + +/** + * Convert relative time to network byte order. + * + * @param a time to convert + * @return converted time value + */ +struct GNUNET_TIME_RelativeNBO +GNUNET_TIME_relative_hton (struct GNUNET_TIME_Relative a); + +/** + * Convert relative time from network byte order. + * + * @param a time to convert + * @return converted time value + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_ntoh (struct GNUNET_TIME_RelativeNBO a); + +/** + * Convert relative time to network byte order. + * + * @param a time to convert + * @return converted time value + */ +struct GNUNET_TIME_AbsoluteNBO +GNUNET_TIME_absolute_hton (struct GNUNET_TIME_Absolute a); + +/** + * Convert relative time from network byte order. + * + * @param a time to convert + * @return converted time value + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_ntoh (struct GNUNET_TIME_AbsoluteNBO a); + +/** + * Convert a relative time to a string. + * NOT reentrant! + * + * @param time the time to print + * + * @return string form of the time (as milliseconds) + */ +const char * +GNUNET_TIME_relative_to_string (struct GNUNET_TIME_Relative time); + +/** + * Set the timestamp offset for this instance. + * + * @param offset the offset to skew the locale time by + */ +void +GNUNET_TIME_set_offset (long long offset); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_TIME_LIB_H */ +#endif +/* end of gnunet_time_lib.h */ diff --git a/src/include/gnunet_transport_plugin.h b/src/include/gnunet_transport_plugin.h new file mode 100644 index 0000000..9b39a41 --- /dev/null +++ b/src/include/gnunet_transport_plugin.h @@ -0,0 +1,487 @@ +/* + This file is part of GNUnet + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_transport_plugin.h + * @brief API for the transport services. This header + * specifies the struct that is given to the plugin's entry + * method and the other struct that must be returned. + * Note that the destructors of transport plugins will + * be given the value returned by the constructor + * and is expected to return a NULL pointer. + * @author Christian Grothoff + */ +#ifndef PLUGIN_TRANSPORT_H +#define PLUGIN_TRANSPORT_H + +#include "gnunet_configuration_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" + +/** + * Opaque pointer that plugins can use to distinguish specific + * connections to a given peer. Typically used by stateful plugins to + * allow the service to refer to specific streams instead of a more + * general notion of "some connection" to the given peer. This is + * useful since sometimes (i.e. for inbound TCP connections) a + * connection may not have an address that can be used for meaningful + * distinction between sessions to the same peer. + */ +struct Session; + +/** + * Every 'struct Session' must begin with this header. + */ +struct SessionHeader +{ + + /** + * Cached signature for PONG generation for the session. Do not use + * in the plugin! + */ + struct GNUNET_CRYPTO_RsaSignature pong_signature; + + /** + * Expiration time for signature. Do not use in the plugin! + */ + struct GNUNET_TIME_Absolute pong_sig_expires; + +}; + +/** + * Function that will be called whenever the plugin internally + * cleans up a session pointer and hence the service needs to + * discard all of those sessions as well. Plugins that do not + * use sessions can simply omit calling this function and always + * use NULL wherever a session pointer is needed. This function + * should be called BEFORE a potential "TransmitContinuation" + * from the "TransmitFunction". + * + * @param cls closure + * @param peer which peer was the session for + * @param session which session is being destoyed + */ +typedef void (*GNUNET_TRANSPORT_SessionEnd) (void *cls, + const struct GNUNET_PeerIdentity * + peer, struct Session * session); + + +/** + * Function called by the transport for each received message. + * This function should also be called with "NULL" for the + * message to signal that the other peer disconnected. + * + * @param cls closure + * @param peer (claimed) identity of the other peer + * @param message the message, NULL if we only care about + * learning about the delay until we should receive again + * @param session identifier used for this session (NULL for plugins + * that do not offer bi-directional communication to the sender + * using the same "connection") + * @param sender_address binary address of the sender (if we established the + * connection or are otherwise sure of it; should be NULL + * for inbound TCP/UDP connections since it it not clear + * that we could establish ourselves a connection to that + * IP address and get the same system) + * @param sender_address_len number of bytes in sender_address + * @return how long the plugin should wait until receiving more data + * (plugins that do not support this, can ignore the return value) + */ +typedef struct + GNUNET_TIME_Relative (*GNUNET_TRANSPORT_PluginReceiveCallback) (void *cls, + const struct + GNUNET_PeerIdentity + * peer, + const struct + GNUNET_MessageHeader + * message, + const struct + GNUNET_ATS_Information + * ats, + uint32_t + ats_count, + struct + Session * + session, + const char + *sender_address, + uint16_t + sender_address_len); + + +/** + * Function that will be called to figure if an address is an loopback, + * LAN, WAN etc. address + * + * @param cls closure + * @param addr binary address + * @param addrlen length of the address + * @return ATS Information containing the network type + */ +typedef const struct GNUNET_ATS_Information +(*GNUNET_TRANSPORT_AddressToType) (void *cls, + const struct sockaddr *addr, + size_t addrlen); + +/** + * Function that will be called for each address the transport + * is aware that it might be reachable under. + * + * @param cls closure + * @param add_remove should the address added (YES) or removed (NO) from the + * set of valid addresses? + * @param addr one of the addresses of the host + * the specific address format depends on the transport + * @param addrlen length of the address + */ +typedef void (*GNUNET_TRANSPORT_AddressNotification) (void *cls, int add_remove, + const void *addr, + size_t addrlen); + + +/** + * Function that will be called whenever the plugin receives data over + * the network and wants to determine how long it should wait until + * the next time it reads from the given peer. Note that some plugins + * (such as UDP) may not be able to wait (for a particular peer), so + * the waiting part is optional. Plugins that can wait should call + * this function, sleep the given amount of time, and call it again + * (with zero bytes read) UNTIL it returns zero and only then read. + * + * @param cls closure + * @param peer which peer did we read data from + * @param amount_recved number of bytes read (can be zero) + * @return how long to wait until reading more from this peer + * (to enforce inbound quotas) + */ +typedef struct GNUNET_TIME_Relative (*GNUNET_TRANSPORT_TrafficReport) (void + *cls, + const + struct + GNUNET_PeerIdentity + * peer, + size_t + amount_recved); + + +/** + * Function that returns a HELLO message. + */ +typedef const struct GNUNET_MessageHeader + *(*GNUNET_TRANSPORT_GetHelloCallback) (void); + + +/** + * The transport service will pass a pointer to a struct + * of this type as the first and only argument to the + * entry point of each transport plugin. + */ +struct GNUNET_TRANSPORT_PluginEnvironment +{ + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Identity of this peer. + */ + const struct GNUNET_PeerIdentity *my_identity; + + /** + * Closure for the various callbacks. + */ + void *cls; + + /** + * Handle for reporting statistics. + */ + struct GNUNET_STATISTICS_Handle *stats; + + /** + * Function that should be called by the transport plugin + * whenever a message is received. + */ + GNUNET_TRANSPORT_PluginReceiveCallback receive; + + + /** + * Function that returns our HELLO. + */ + GNUNET_TRANSPORT_GetHelloCallback get_our_hello; + + /** + * Function that must be called by each plugin to notify the + * transport service about the addresses under which the transport + * provided by the plugin can be reached. + */ + GNUNET_TRANSPORT_AddressNotification notify_address; + + /** + * Function that must be called by the plugin when a non-NULL + * session handle stops being valid (is destroyed). + */ + GNUNET_TRANSPORT_SessionEnd session_end; + + /** + * Function that will be called to figure if an address is an loopback, + * LAN, WAN etc. address + */ + GNUNET_TRANSPORT_AddressToType get_address_type; + + + /** + * What is the maximum number of connections that this transport + * should allow? Transports that do not have sessions (such as + * UDP) can ignore this value. + */ + uint32_t max_connections; + +}; + + +/** + * Function called by the GNUNET_TRANSPORT_TransmitFunction + * upon "completion". In the case that a peer disconnects, + * this function must be called for each pending request + * (with a 'failure' indication) AFTER notifying the service + * about the disconnect event (so that the service won't try + * to transmit more messages, believing the connection still + * exists...). + * + * @param cls closure + * @param target who was the recipient of the message? + * @param result GNUNET_OK on success + * GNUNET_SYSERR if the target disconnected; + * disconnect will ALSO be signalled using + * the ReceiveCallback. + */ +typedef void (*GNUNET_TRANSPORT_TransmitContinuation) (void *cls, + const struct + GNUNET_PeerIdentity * + target, int result); + +/** + * The new send function with just the session and no address + * + * Function that can be used by the transport service to transmit + * a message using the plugin. Note that in the case of a + * peer disconnecting, the continuation MUST be called + * prior to the disconnect notification itself. This function + * will be called with this peer's HELLO message to initiate + * a fresh connection to another peer. + * + * @param cls closure + * @param session which session must be used + * @param msgbuf the message to transmit + * @param msgbuf_size number of bytes in 'msgbuf' + * @param priority how important is the message (most plugins will + * ignore message priority and just FIFO) + * @param timeout how long to wait at most for the transmission (does not + * require plugins to discard the message after the timeout, + * just advisory for the desired delay; most plugins will ignore + * this as well) + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...); can be NULL + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV) + */ +typedef ssize_t (*GNUNET_TRANSPORT_TransmitFunction) (void *cls, + struct Session *session, + const char *msgbuf, size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative to, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls); + + +/** + * Function that can be called to force a disconnect from the + * specified neighbour. This should also cancel all previously + * scheduled transmissions. Obviously the transmission may have been + * partially completed already, which is OK. The plugin is supposed + * to close the connection (if applicable) and no longer call the + * transmit continuation(s). + * + * Finally, plugin MUST NOT call the services's receive function to + * notify the service that the connection to the specified target was + * closed after a getting this call. + * + * @param cls closure + * @param target peer for which the last transmission is + * to be cancelled + */ +typedef void (*GNUNET_TRANSPORT_DisconnectFunction) (void *cls, + const struct + GNUNET_PeerIdentity * + target); + + +/** + * Function called by the pretty printer for the resolved address for + * each human-readable address obtained. + * + * @param cls closure + * @param hostname one of the names for the host, NULL + * on the last call to the callback + */ +typedef void (*GNUNET_TRANSPORT_AddressStringCallback) (void *cls, + const char *address); + + +/** + * Convert the transports address to a nice, human-readable + * format. + * + * @param cls closure + * @param name name of the transport that generated the address + * @param addr one of the addresses of the host, NULL for the last address + * the specific address format depends on the transport + * @param addrlen length of the address + * @param numeric should (IP) addresses be displayed in numeric form? + * @param timeout after how long should we give up? + * @param asc function to call on each string + * @param asc_cls closure for asc + */ +typedef void (*GNUNET_TRANSPORT_AddressPrettyPrinter) (void *cls, + const char *type, + const void *addr, + size_t addrlen, + int numeric, + struct + GNUNET_TIME_Relative + timeout, + GNUNET_TRANSPORT_AddressStringCallback + asc, void *asc_cls); + + +/** + * Another peer has suggested an address for this peer and transport + * plugin. Check that this could be a valid address. This function + * is not expected to 'validate' the address in the sense of trying to + * connect to it but simply to see if the binary format is technically + * legal for establishing a connection to this peer (and make sure that + * the address really corresponds to our network connection/settings + * and not some potential man-in-the-middle). + * + * @param addr pointer to the address + * @param addrlen length of addr + * @return GNUNET_OK if this is a plausible address for this peer + * and transport, GNUNET_SYSERR if not + */ +typedef int (*GNUNET_TRANSPORT_CheckAddress) (void *cls, const void *addr, + size_t addrlen); + +/** + * Create a new session to transmit data to the target + * This session will used to send data to this peer and the plugin will + * notify us by calling the env->session_end function + * + * @param cls the plugin + * @param target the neighbour id + * @param addr pointer to the address + * @param addrlen length of addr + * @return the session if the address is valid, NULL otherwise + */ +typedef struct Session * (*GNUNET_TRANSPORT_CreateSession) (void *cls, + const struct GNUNET_HELLO_Address *address); + + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure + * @param addr binary address + * @param addr_len length of the address + * @return string representing the same address + */ +typedef const char *(*GNUNET_TRANSPORT_AddressToString) (void *cls, + const void *addr, + size_t addrlen); + + +/** + * Each plugin is required to return a pointer to a struct of this + * type as the return value from its entry point. + */ +struct GNUNET_TRANSPORT_PluginFunctions +{ + + /** + * Closure for all of the callbacks. + */ + void *cls; + + /** + * Function that the transport service will use to transmit data to + * another peer. May be NULL for plugins that only support + * receiving data. After this call, the plugin call the specified + * continuation with success or error before notifying us about the + * target having disconnected. + */ + GNUNET_TRANSPORT_TransmitFunction send; + + /** + * Function that can be used to force the plugin to disconnect from + * the given peer and cancel all previous transmissions (and their + * continuations). + */ + GNUNET_TRANSPORT_DisconnectFunction disconnect; + + /** + * Function to pretty-print addresses. NOTE: this function is not + * yet used by transport-service, but will be used in the future + * once the transport-API has been completed. + */ + GNUNET_TRANSPORT_AddressPrettyPrinter address_pretty_printer; + + /** + * Function that will be called to check if a binary address + * for this plugin is well-formed and corresponds to an + * address for THIS peer (as per our configuration). Naturally, + * if absolutely necessary, plugins can be a bit conservative in + * their answer, but in general plugins should make sure that the + * address does not redirect traffic to a 3rd party that might + * try to man-in-the-middle our traffic. + */ + GNUNET_TRANSPORT_CheckAddress check_address; + + /** + * Function that will be called to convert a binary address + * to a string (numeric conversion only). + */ + GNUNET_TRANSPORT_AddressToString address_to_string; + + /** + * Function that will be called tell the plugin to create a session + * object + */ + GNUNET_TRANSPORT_CreateSession get_session; +}; + + +#endif diff --git a/src/include/gnunet_transport_service.h b/src/include/gnunet_transport_service.h new file mode 100644 index 0000000..5c939a0 --- /dev/null +++ b/src/include/gnunet_transport_service.h @@ -0,0 +1,413 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_transport_service.h + * @brief low-level P2P IO + * @author Christian Grothoff + */ + +#ifndef GNUNET_TRANSPORT_SERVICE_H +#define GNUNET_TRANSPORT_SERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_util_lib.h" +#include "gnunet_ats_service.h" + +/** + * Version number of the transport API. + */ +#define GNUNET_TRANSPORT_VERSION 0x00000000 + + +/** + * Function called by the transport for each received message. + * + * @param cls closure + * @param peer (claimed) identity of the other peer + * @param message the message + * @param ats performance data + * @param ats_count number of entries in ats + */ +typedef void (*GNUNET_TRANSPORT_ReceiveCallback) (void *cls, + const struct + GNUNET_PeerIdentity * peer, + const struct + GNUNET_MessageHeader * + message, + const struct + GNUNET_ATS_Information * ats, + uint32_t ats_count); + + +/** + * Opaque handle to the service. + */ +struct GNUNET_TRANSPORT_Handle; + + +/** + * Function called to notify transport users that another + * peer connected to us. + * + * @param cls closure + * @param peer the peer that connected + * @param ats performance data + * @param ats_count number of entries in ats (excluding 0-termination) + */ +typedef void (*GNUNET_TRANSPORT_NotifyConnect) (void *cls, + const struct GNUNET_PeerIdentity + * peer, + const struct + GNUNET_ATS_Information * ats, + uint32_t ats_count); + +/** + * Function called to notify transport users that another + * peer disconnected from us. + * + * @param cls closure + * @param peer the peer that disconnected + */ +typedef void (*GNUNET_TRANSPORT_NotifyDisconnect) (void *cls, + const struct + GNUNET_PeerIdentity * peer); + + +/** + * Function to call with a textual representation of an address. + * This function will be called several times with different possible + * textual representations, and a last time with NULL to signal the end + * of the iteration. + * + * @param cls closure + * @param address NULL on error or end of iteration, + * otherwise 0-terminated printable UTF-8 string + */ +typedef void (*GNUNET_TRANSPORT_AddressToStringCallback) (void *cls, + const char *address); + + +/** + * Function to call with a binary format of an address + * + * @param cls closure + * @param peer peer this update is about (never NULL) + * @param address address, NULL for disconnect notification in monitor mode + */ +typedef void (*GNUNET_TRANSPORT_PeerIterateCallback) (void *cls, + const struct + GNUNET_PeerIdentity * + peer, + const struct + GNUNET_HELLO_Address * + address); + + +/** + * Connect to the transport service. Note that the connection may + * complete (or fail) asynchronously. + * + * @param cfg configuration to use + * @param self our own identity (API should check that it matches + * the identity found by transport), or NULL (no check) + * @param cls closure for the callbacks + * @param rec receive function to call + * @param nc function to call on connect events + * @param nd function to call on disconnect events + * @return NULL on error + */ +struct GNUNET_TRANSPORT_Handle * +GNUNET_TRANSPORT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PeerIdentity *self, void *cls, + GNUNET_TRANSPORT_ReceiveCallback rec, + GNUNET_TRANSPORT_NotifyConnect nc, + GNUNET_TRANSPORT_NotifyDisconnect nd); + + +/** + * Disconnect from the transport service. + * + * @param handle handle returned from connect + */ +void +GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle); + + +/** + * Ask the transport service to establish a connection to + * the given peer. + * + * @param handle connection to transport service + * @param target who we should try to connect to + */ +void +GNUNET_TRANSPORT_try_connect (struct GNUNET_TRANSPORT_Handle *handle, + const struct GNUNET_PeerIdentity *target); + + +/** + * Opaque handle for a transmission-ready request. + */ +struct GNUNET_TRANSPORT_TransmitHandle; + + +/** + * Check if we could queue a message of the given size for + * transmission. The transport service will take both its internal + * buffers and bandwidth limits imposed by the other peer into + * consideration when answering this query. + * + * @param handle connection to transport service + * @param target who should receive the message + * @param size how big is the message we want to transmit? + * @param priority how important is the message? @deprecated - remove? + * @param timeout after how long should we give up (and call + * notify with buf NULL and size 0)? + * @param notify function to call when we are ready to + * send such a message + * @param notify_cls closure for notify + * @return NULL if someone else is already waiting to be notified + * non-NULL if the notify callback was queued (can be used to cancel + * using GNUNET_TRANSPORT_notify_transmit_ready_cancel) + */ +struct GNUNET_TRANSPORT_TransmitHandle * +GNUNET_TRANSPORT_notify_transmit_ready (struct GNUNET_TRANSPORT_Handle *handle, + const struct GNUNET_PeerIdentity + *target, size_t size, uint32_t priority, + struct GNUNET_TIME_Relative timeout, + GNUNET_CONNECTION_TransmitReadyNotify + notify, void *notify_cls); + + +/** + * Cancel the specified transmission-ready notification. + * + * @param th handle of the transmission notification request to cancel + */ +void +GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct + GNUNET_TRANSPORT_TransmitHandle + *th); + + + +/** + * Function called whenever there is an update to the + * HELLO of this peer. + * + * @param cls closure + * @param hello our updated HELLO + */ +typedef void (*GNUNET_TRANSPORT_HelloUpdateCallback) (void *cls, + const struct + GNUNET_MessageHeader * + hello); + + +/** + * Handle to cancel a 'GNUNET_TRANSPORT_get_hello' operation. + */ +struct GNUNET_TRANSPORT_GetHelloHandle; + + +/** + * Obtain updates on changes to the HELLO message for this peer. + * + * @param handle connection to transport service + * @param rec function to call with the HELLO + * @param rec_cls closure for rec + * @return handle to cancel the operation + */ +struct GNUNET_TRANSPORT_GetHelloHandle * +GNUNET_TRANSPORT_get_hello (struct GNUNET_TRANSPORT_Handle *handle, + GNUNET_TRANSPORT_HelloUpdateCallback rec, + void *rec_cls); + + +/** + * Stop receiving updates about changes to our HELLO message. + * + * @param ghh handle returned from 'GNUNET_TRANSPORT_get_hello') + */ +void +GNUNET_TRANSPORT_get_hello_cancel (struct GNUNET_TRANSPORT_GetHelloHandle *ghh); + + +/** + * Offer the transport service the HELLO of another peer. Note that + * the transport service may just ignore this message if the HELLO is + * malformed or useless due to our local configuration. + * + * @param handle connection to transport service + * @param hello the hello message + * @param cont continuation to call when HELLO has been sent + * @param cls closure for continuation + */ +void +GNUNET_TRANSPORT_offer_hello (struct GNUNET_TRANSPORT_Handle *handle, + const struct GNUNET_MessageHeader *hello, + GNUNET_SCHEDULER_Task cont, void *cls); + + +/** + * Handle to cancel a pending address lookup. + */ +struct GNUNET_TRANSPORT_AddressToStringContext; + + +/** + * Convert a binary address into a human readable address. + * + * @param cfg configuration to use + * @param address address to convert (binary format) + * @param numeric should (IP) addresses be displayed in numeric form + * (otherwise do reverse DNS lookup) + * @param timeout how long is the lookup allowed to take at most + * @param aluc function to call with the results + * @param aluc_cls closure for aluc + * @return handle to cancel the operation, NULL on error + */ +struct GNUNET_TRANSPORT_AddressToStringContext * +GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle + *cfg, + const struct GNUNET_HELLO_Address *address, + int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressToStringCallback + aluc, void *aluc_cls); + + +/** + * Cancel request for address conversion. + * + * @param alc handle for the request to cancel + */ +void +GNUNET_TRANSPORT_address_to_string_cancel (struct + GNUNET_TRANSPORT_AddressToStringContext + *alc); + + +/** + * Return all the known addresses for a specific peer or all peers. + * Returns continously all address if one_shot is set to GNUNET_NO + * + * CHANGE: Returns the address(es) that we are currently using for this + * peer. Upon completion, the 'AddressLookUpCallback' is called one more + * time with 'NULL' for the address and the peer. After this, the operation must no + * longer be explicitly cancelled. + * + * @param cfg configuration to use + * @param peer peer identity to look up the addresses of, CHANGE: allow NULL for all (connected) peers + * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL), + * GNUNET_NO to monitor the set of addresses used (continuously, must be explicitly canceled, NOT implemented yet!) + * @param timeout how long is the lookup allowed to take at most + * @param peer_address_callback function to call with the results + * @param peer_address_callback_cls closure for peer_address_callback + */ +struct GNUNET_TRANSPORT_PeerIterateContext * +GNUNET_TRANSPORT_peer_get_active_addresses (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PeerIdentity + *peer, int one_shot, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_PeerIterateCallback + peer_address_callback, + void *peer_address_callback_cls); + + +/** + * Cancel request for peer lookup. + * + * @param alc handle for the request to cancel + */ +void +GNUNET_TRANSPORT_peer_get_active_addresses_cancel (struct + GNUNET_TRANSPORT_PeerIterateContext + *alc); + + +/** + * Handle for blacklisting peers. + */ +struct GNUNET_TRANSPORT_Blacklist; + + +/** + * Function that decides if a connection is acceptable or not. + * + * @param cls closure + * @param pid peer to approve or disapproave + * @return GNUNET_OK if the connection is allowed, GNUNET_SYSERR if not + */ +typedef int (*GNUNET_TRANSPORT_BlacklistCallback) (void *cls, + const struct + GNUNET_PeerIdentity * pid); + + +/** + * Install a blacklist callback. The service will be queried for all + * existing connections as well as any fresh connections to check if + * they are permitted. If the blacklisting callback is unregistered, + * all hosts that were denied in the past will automatically be + * whitelisted again. Cancelling the blacklist handle is also the + * only way to re-enable connections from peers that were previously + * blacklisted. + * + * @param cfg configuration to use + * @param cb callback to invoke to check if connections are allowed + * @param cb_cls closure for cb + * @return NULL on error, otherwise handle for cancellation + */ +struct GNUNET_TRANSPORT_Blacklist * +GNUNET_TRANSPORT_blacklist (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_TRANSPORT_BlacklistCallback cb, + void *cb_cls); + + +/** + * Abort the blacklist. Note that this function is the only way for + * removing a peer from the blacklist. + * + * @param br handle of the request that is to be cancelled + */ +void +GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_Blacklist *br); + + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_TRANSPORT_SERVICE_H */ +#endif +/* end of gnunet_transport_service.h */ diff --git a/src/include/gnunet_tun_lib.h b/src/include/gnunet_tun_lib.h new file mode 100644 index 0000000..dac11d6 --- /dev/null +++ b/src/include/gnunet_tun_lib.h @@ -0,0 +1,420 @@ +/* + This file is part of GNUnet. + (C) 2010, 2011, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/gnunet_tun_lib.h + * @brief standard TCP/IP network structs and IP checksum calculations for TUN interaction + * @author Philipp Toelke + * @author Christian Grothoff + */ +#ifndef GNUNET_TUN_LIB_H +#define GNUNET_TUN_LIB_H + +#include "gnunet_util_lib.h" + + +/* see http://www.iana.org/assignments/ethernet-numbers */ +#ifndef ETH_P_IPV4 +/** + * Number for IPv4 + */ +#define ETH_P_IPV4 0x0800 +#endif + +#ifndef ETH_P_IPV6 +/** + * Number for IPv6 + */ +#define ETH_P_IPV6 0x86DD +#endif + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Header from Linux TUN interface. + */ +struct GNUNET_TUN_Layer2PacketHeader +{ + /** + * Some flags (unused). + */ + uint16_t flags GNUNET_PACKED; + + /** + * Here we get an ETH_P_-number. + */ + uint16_t proto GNUNET_PACKED; +}; + + +/** + * Standard IPv4 header. + */ +struct GNUNET_TUN_IPv4Header +{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int header_length:4 GNUNET_PACKED; + unsigned int version:4 GNUNET_PACKED; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int version:4 GNUNET_PACKED; + unsigned int header_length:4 GNUNET_PACKED; +#else + #error byteorder undefined +#endif + uint8_t diff_serv; + + /** + * Length of the packet, including this header. + */ + uint16_t total_length GNUNET_PACKED; + + /** + * Unique random ID for matching up fragments. + */ + uint16_t identification GNUNET_PACKED; + + unsigned int flags:3 GNUNET_PACKED; + + unsigned int fragmentation_offset:13 GNUNET_PACKED; + + /** + * How many more hops can this packet be forwarded? + */ + uint8_t ttl; + + /** + * L4-protocol, for example, IPPROTO_UDP or IPPROTO_TCP. + */ + uint8_t protocol; + + /** + * Checksum. + */ + uint16_t checksum GNUNET_PACKED; + + /** + * Origin of the packet. + */ + struct in_addr source_address GNUNET_PACKED; + + /** + * Destination of the packet. + */ + struct in_addr destination_address GNUNET_PACKED; +}; + + +/** + * Standard IPv6 header. + */ +struct GNUNET_TUN_IPv6Header +{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int traffic_class_h:4 GNUNET_PACKED; + unsigned int version:4 GNUNET_PACKED; + unsigned int traffic_class_l:4 GNUNET_PACKED; + unsigned int flow_label:20 GNUNET_PACKED; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int version:4 GNUNET_PACKED; + unsigned int traffic_class:8 GNUNET_PACKED; + unsigned int flow_label:20 GNUNET_PACKED; +#else + #error byteorder undefined +#endif + /** + * Length of the payload, excluding this header. + */ + uint16_t payload_length GNUNET_PACKED; + + /** + * For example, IPPROTO_UDP or IPPROTO_TCP. + */ + uint8_t next_header; + + /** + * How many more hops can this packet be forwarded? + */ + uint8_t hop_limit; + + /** + * Origin of the packet. + */ + struct in6_addr source_address GNUNET_PACKED; + + /** + * Destination of the packet. + */ + struct in6_addr destination_address GNUNET_PACKED; +}; + + +/** + * TCP packet header. + */ +struct GNUNET_TUN_TcpHeader +{ + uint16_t source_port GNUNET_PACKED; + uint16_t destination_port GNUNET_PACKED; + + /** + * Sequence number. + */ + uint32_t seq GNUNET_PACKED; + + /** + * Acknowledgement number. + */ + uint32_t ack GNUNET_PACKED; +#if __BYTE_ORDER == __LITTLE_ENDIAN + /** + * Reserved. Must be zero. + */ + unsigned int reserved : 4 GNUNET_PACKED; + /** + * Number of 32-bit words in TCP header. + */ + unsigned int off : 4 GNUNET_PACKED; +#elif __BYTE_ORDER == __BIG_ENDIAN + /** + * Number of 32-bit words in TCP header. + */ + unsigned int off : 4 GNUNET_PACKED; + /** + * Reserved. Must be zero. + */ + unsigned int reserved : 4 GNUNET_PACKED; +#else + #error byteorder undefined +#endif + + /** + * Flags (SYN, FIN, ACK, etc.) + */ + uint8_t flags; + + /** + * Window size. + */ + uint16_t window_size GNUNET_PACKED; + + /** + * Checksum. + */ + uint16_t crc GNUNET_PACKED; + + /** + * Urgent pointer. + */ + uint16_t urgent_pointer GNUNET_PACKED; +}; + + +/** + * UDP packet header. + */ +struct GNUNET_TUN_UdpHeader +{ + uint16_t source_port GNUNET_PACKED; + uint16_t destination_port GNUNET_PACKED; + uint16_t len GNUNET_PACKED; + uint16_t crc GNUNET_PACKED; +}; + + +/** + * DNS header. + */ +struct GNUNET_TUN_DnsHeader +{ + uint16_t id GNUNET_PACKED; + uint16_t flags GNUNET_PACKED; + uint16_t qdcount GNUNET_PACKED; + uint16_t ancount GNUNET_PACKED; + uint16_t nscount GNUNET_PACKED; + uint16_t arcount GNUNET_PACKED; +}; + +#define GNUNET_TUN_ICMPTYPE_ECHO_REPLY 0 +#define GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE 3 +#define GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH 4 +#define GNUNET_TUN_ICMPTYPE_REDIRECT_MESSAGE 5 +#define GNUNET_TUN_ICMPTYPE_ECHO_REQUEST 8 +#define GNUNET_TUN_ICMPTYPE_ROUTER_ADVERTISEMENT 9 +#define GNUNET_TUN_ICMPTYPE_ROUTER_SOLICITATION 10 +#define GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED 11 + +#define GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE 1 +#define GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG 2 +#define GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED 3 +#define GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM 4 +#define GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST 128 +#define GNUNET_TUN_ICMPTYPE6_ECHO_REPLY 129 + + +/** + * ICMP header. + */ +struct GNUNET_TUN_IcmpHeader { + uint8_t type; + uint8_t code; + uint16_t crc GNUNET_PACKED; + + union { + /** + * ICMP Echo (request/reply) + */ + struct { + uint16_t identifier GNUNET_PACKED; + uint16_t sequence_number GNUNET_PACKED; + } echo; + + /** + * ICMP Destination Unreachable (RFC 1191) + */ + struct ih_pmtu { + uint16_t empty GNUNET_PACKED; + uint16_t next_hop_mtu GNUNET_PACKED; + /* followed by original IP header + first 8 bytes of original IP datagram */ + } destination_unreachable; + + /** + * ICMP Redirect + */ + struct in_addr redirect_gateway_address GNUNET_PACKED; + + /** + * MTU for packets that are too big (IPv6). + */ + uint32_t packet_too_big_mtu GNUNET_PACKED; + + } quench; + +}; + + +GNUNET_NETWORK_STRUCT_END + + +/** + * Initialize an IPv4 header. + * + * @param ip header to initialize + * @param protocol protocol to use (i.e. IPPROTO_UDP) + * @param payload_length number of bytes of payload that follow (excluding IPv4 header) + * @param src source IP address to use + * @param dst destination IP address to use + */ +void +GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip, + uint8_t protocol, + uint16_t payload_length, + const struct in_addr *src, + const struct in_addr *dst); + + +/** + * Initialize an IPv6 header. + * + * @param ip header to initialize + * @param protocol protocol to use (i.e. IPPROTO_UDP) + * @param payload_length number of bytes of payload that follow (excluding IPv4 header) + * @param src source IP address to use + * @param dst destination IP address to use + */ +void +GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip, + uint8_t protocol, + uint16_t payload_length, + const struct in6_addr *src, + const struct in6_addr *dst); + +/** + * Calculate IPv4 TCP checksum. + * + * @param ip ipv4 header fully initialized + * @param tcp TCP header (initialized except for CRC) + * @param payload the TCP payload + * @param payload_length number of bytes of TCP payload + */ +void +GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, + struct GNUNET_TUN_TcpHeader *tcp, + const void *payload, + uint16_t payload_length); + +/** + * Calculate IPv6 TCP checksum. + * + * @param ip ipv6 header fully initialized + * @param tcp TCP header (initialized except for CRC) + * @param payload the TCP payload + * @param payload_length number of bytes of TCP payload + */ +void +GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, + struct GNUNET_TUN_TcpHeader *tcp, + const void *payload, + uint16_t payload_length); + +/** + * Calculate IPv4 UDP checksum. + * + * @param ip ipv4 header fully initialized + * @param udp UDP header (initialized except for CRC) + * @param payload the UDP payload + * @param payload_length number of bytes of UDP payload + */ +void +GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, + struct GNUNET_TUN_UdpHeader *udp, + const void *payload, + uint16_t payload_length); + + +/** + * Calculate IPv6 UDP checksum. + * + * @param ip ipv6 header fully initialized + * @param udp UDP header (initialized except for CRC) + * @param payload the UDP payload + * @param payload_length number of bytes of UDP payload + */ +void +GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, + struct GNUNET_TUN_UdpHeader *udp, + const void *payload, + uint16_t payload_length); + + +/** + * Calculate ICMP checksum. + * + * @param icmp IMCP header (initialized except for CRC) + * @param payload the ICMP payload + * @param payload_length number of bytes of ICMP payload + */ +void +GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp, + const void *payload, + uint16_t payload_length); + + +#endif diff --git a/src/include/gnunet_util_lib.h b/src/include/gnunet_util_lib.h new file mode 100644 index 0000000..5f01cde --- /dev/null +++ b/src/include/gnunet_util_lib.h @@ -0,0 +1,71 @@ +/* + This file is part of GNUnet + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_util_lib.h + * @brief convenience header including all headers of subsystems in + * gnunet_util library + * @author Christian Grothoff + */ + +#ifndef GNUNET_UTIL_LIB_H +#define GNUNET_UTIL_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include "gnunet_bandwidth_lib.h" +#include "gnunet_bio_lib.h" +#include "gnunet_client_lib.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_connection_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_disk_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_helper_lib.h" +#include "gnunet_network_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_peer_lib.h" +#include "gnunet_plugin_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_pseudonym_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_service_lib.h" +#include "gnunet_signal_lib.h" +#include "gnunet_strings_lib.h" +#include "gnunet_time_lib.h" + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/gnunet_vpn_service.h b/src/include/gnunet_vpn_service.h new file mode 100644 index 0000000..ecf6cf5 --- /dev/null +++ b/src/include/gnunet_vpn_service.h @@ -0,0 +1,162 @@ +/* + This file is part of GNUnet + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_vpn_service.h + * @brief API to access the VPN service. + * @author Christian Grothoff + */ +#ifndef GNUNET_VPN_SERVICE_H +#define GNUNET_VPN_SERVICE_H + +#include "gnunet_util_lib.h" + + +/** + * Opaque VPN handle + */ +struct GNUNET_VPN_Handle; + +/** + * Opaque redirection request handle. + */ +struct GNUNET_VPN_RedirectionRequest; + + +/** + * Callback invoked from the VPN service once a redirection is + * available. Provides the IP address that can now be used to + * reach the requested destination. + * + * @param cls closure + * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error; + * will match 'result_af' from the request + * @param address IP address (struct in_addr or struct in_addr6, depending on 'af') + * that the VPN allocated for the redirection; + * traffic to this IP will now be redirected to the + * specified target peer; NULL on error + */ +typedef void (*GNUNET_VPN_AllocationCallback)(void *cls, + int af, + const void *address); + + +/** + * Cancel redirection request with the service. + * + * @param rr request to cancel + */ +void +GNUNET_VPN_cancel_request (struct GNUNET_VPN_RedirectionRequest *rr); + + +/** + * Tell the VPN that a forwarding to a particular peer offering a + * particular service is requested. The VPN is to reserve a + * particular IP for the redirection and return it. The VPN will + * begin the redirection as soon as possible and maintain it as long + * as it is actively used and keeping it is feasible. Given resource + * limitations, the longest inactive mappings will be destroyed. + * + * @param vh VPN handle + * @param result_af desired address family for the returned allocation + * can also be AF_UNSPEC + * @param protocol protocol, IPPROTO_UDP or IPPROTO_TCP + * @param peer target peer for the redirection + * @param serv service descriptor to give to the peer + * @param nac GNUNET_YES to notify via callback only after completion of + * the MESH-level connection, + * GNUNET_NO to notify as soon as the IP has been reserved + * @param expiration_time at what time should the redirection expire? + * (this should not impact connections that are active at that time) + * @param cb function to call with the IP + * @param cb_cls closure for cb + * @return handle to cancel the request (means the callback won't be + * invoked anymore; the mapping may or may not be established + * anyway) + */ +struct GNUNET_VPN_RedirectionRequest * +GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *vh, + int result_af, + uint8_t protocol, + const struct GNUNET_PeerIdentity *peer, + const GNUNET_HashCode *serv, + int nac, + struct GNUNET_TIME_Absolute expiration_time, + GNUNET_VPN_AllocationCallback cb, + void *cb_cls); + + +/** + * Tell the VPN that forwarding to the Internet via some exit node is + * requested. Note that both UDP and TCP traffic will be forwarded, + * but possibly to different exit nodes. The VPN is to reserve a + * particular IP for the redirection and return it. The VPN will + * begin the redirection as soon as possible and maintain it as long + * as it is actively used and keeping it is feasible. Given resource + * limitations, the longest inactive mappings will be destroyed. + * + * @param vh VPN handle + * @param result_af desired address family for the returned allocation, + * can also be AF_UNSPEC + * @param addr_af address family for 'addr', AF_INET or AF_INET6 + * @param addr destination IP address on the Internet; destination + * port is to be taken from the VPN packet itself + * @param nac GNUNET_YES to notify via callback only after completion of + * the MESH-level connection, + * GNUNET_NO to notify as soon as the IP has been reserved + * @param expiration_time at what time should the redirection expire? + * (this should not impact connections that are active at that time) + * @param cb function to call with the IP + * @param cb_cls closure for cb + * @return handle to cancel the request (means the callback won't be + * invoked anymore; the mapping may or may not be established + * anyway) + */ +struct GNUNET_VPN_RedirectionRequest * +GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *vh, + int result_af, + int addr_af, + const void *addr, + int nac, + struct GNUNET_TIME_Absolute expiration_time, + GNUNET_VPN_AllocationCallback cb, + void *cb_cls); + + +/** + * Connect to the VPN service + * + * @param cfg configuration to use + * @return VPN handle + */ +struct GNUNET_VPN_Handle * +GNUNET_VPN_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Disconnect from the VPN service. + * + * @param vh VPN handle + */ +void +GNUNET_VPN_disconnect (struct GNUNET_VPN_Handle *vh); + +#endif diff --git a/src/include/platform.h b/src/include/platform.h new file mode 100644 index 0000000..7383e48 --- /dev/null +++ b/src/include/platform.h @@ -0,0 +1,258 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/platform.h + * @brief plaform specifics + * + * @author Nils Durner + * + * This file should never be included by installed + * header files (thos starting with "gnunet_"). + */ + +#ifndef PLATFORM_H +#define PLATFORM_H + +#ifndef HAVE_USED_CONFIG_H +#define HAVE_USED_CONFIG_H +#if HAVE_CONFIG_H +#include "gnunet_config.h" +#endif +#endif + +#ifdef WINDOWS +#define BREAKPOINT asm("int $3;"); +#define GNUNET_SIGCHLD 17 +#else +#define BREAKPOINT +#define GNUNET_SIGCHLD SIGCHLD +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#define ALLOW_EXTRA_CHECKS GNUNET_NO + +/** + * For strptime (glibc2 needs this). + */ +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE +#endif + +#ifndef _REENTRANT +#define _REENTRANT +#endif + +/* configuration options */ + +#define VERBOSE_STATS 0 + +#ifdef CYGWIN +#include +#endif + +#ifdef _MSC_VER +#ifndef FD_SETSIZE +#define FD_SETSIZE 1024 +#endif +#include +#include +#else +#ifndef MINGW +#include +#include +#include +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_NETINET_IN_SYSTM_H +#include +#endif +#include /* superset of previous */ +#include +#include +#include +#include +#include +#include +#else +#include "winproc.h" +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WINDOWS +#include /* for alloca(), on other OSes it's in stdlib.h */ +#endif +#ifndef _MSC_VER +#include /* KLB_FIX */ +#endif +#include +#include +#ifndef _MSC_VER +#include /* KLB_FIX */ +#endif +#include +#include +#if HAVE_SYS_PARAM_H +#include +#endif +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#ifdef SOMEBSD +#include +#endif +#ifdef GNUNET_freeBSD +#include +#endif +#ifdef DARWIN +#include +#include +#include +#endif +#ifdef LINUX +#include +#endif +#ifdef SOLARIS +#include +#include +#include +#include +#endif +#if HAVE_UCRED_H +#include +#endif +#ifdef CYGWIN +#include +#include +#endif +#if HAVE_IFADDRS_H +#include +#endif +#include +#include + +#if HAVE_VFORK_H +#include +#endif + +#include +#if HAVE_SYS_RESOURCE_H +#include +#endif + +#if HAVE_ENDIAN_H +#include +#endif +#if HAVE_SYS_ENDIAN_H +#include +#endif + +#include "plibc.h" + +#include +#ifndef FRAMEWORK_BUILD +#include "gettext.h" +/** + * GNU gettext support macro. + */ +#define _(String) dgettext("gnunet",String) +#define LIBEXTRACTOR_GETTEXT_DOMAIN "libextractor" +#else +#include "libintlemu.h" +#define _(String) dgettext("org.gnunet.gnunet",String) +#define LIBEXTRACTOR_GETTEXT_DOMAIN "org.gnunet.libextractor" +#endif + +#ifdef CYGWIN +#define SIOCGIFCONF _IOW('s', 100, struct ifconf) /* get if list */ +#define SIOCGIFFLAGS _IOW('s', 101, struct ifreq) /* Get if flags */ +#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */ +#endif + +#ifndef MINGW +#include +#endif + +#ifdef FREEBSD +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#endif + +#ifdef DARWIN +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN + /* not available on darwin, override configure */ +#undef HAVE_STAT64 +#undef HAVE_MREMAP +#endif + + +#if !HAVE_ATOLL +long long +atoll (const char *nptr); +#endif + +#if ENABLE_NLS +#include "langinfo.h" +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t)(-1)) +#endif + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + +#if defined(__sparc__) +#define MAKE_UNALIGNED(val) ({ __typeof__((val)) __tmp; memmove(&__tmp, &(val), sizeof((val))); __tmp; }) +#else +#define MAKE_UNALIGNED(val) val +#endif + +#if WINDOWS +#define FDTYPE HANDLE +#define SOCKTYPE SOCKET +#else +#define FDTYPE int +#define SOCKTYPE int +#endif + +#endif diff --git a/src/include/plibc.h b/src/include/plibc.h new file mode 100644 index 0000000..70cbd9e --- /dev/null +++ b/src/include/plibc.h @@ -0,0 +1,864 @@ +/* + This file is part of PlibC. + (C) 2005, 2006, 2007, 2008, 2009, 2010 Nils Durner (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** + * @file include/plibc.h + * @brief PlibC header + * @attention This file is usually not installed under Unix, + * so ship it with your application + * @version $Revision$ + */ + +#ifndef _PLIBC_H_ +#define _PLIBC_H_ + +#ifndef SIGALRM + #define SIGALRM 14 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef Q_OS_WIN32 + #define WINDOWS 1 +#endif + +#define HAVE_PLIBC_FD 0 + +#ifdef WINDOWS + +#if ENABLE_NLS + #include "langinfo.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN + +/* Conflicts with our definitions */ +#define __G_WIN32_H__ + +/* Convert LARGE_INTEGER to double */ +#define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 + \ + (double)((x).LowPart)) +#ifndef __MINGW64__ +struct stat64 +{ + _dev_t st_dev; + _ino_t st_ino; + _mode_t st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; +}; +#endif +typedef unsigned int sa_family_t; + +struct sockaddr_un { + short sun_family; /*AF_UNIX*/ + char sun_path[108]; /*path name */ +}; + +#ifndef pid_t + #define pid_t DWORD +#endif + +#ifndef error_t + #define error_t int +#endif + +#ifndef WEXITSTATUS + #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) +#endif + +#ifndef MSG_DONTWAIT + #define MSG_DONTWAIT 0 +#endif + +enum +{ + _SC_PAGESIZE = 30, + _SC_PAGE_SIZE = 30 +}; + +/* Thanks to the Cygwin project */ +#define ENOCSI 43 /* No CSI structure available */ +#define EL2HLT 44 /* Level 2 halted */ +#ifndef EDEADLK + #define EDEADLK 45 /* Deadlock condition */ +#endif +#ifndef ENOLCK + #define ENOLCK 46 /* No record locks available */ +#endif +#define EBADE 50 /* Invalid exchange */ +#define EBADR 51 /* Invalid request descriptor */ +#define EXFULL 52 /* Exchange full */ +#define ENOANO 53 /* No anode */ +#define EBADRQC 54 /* Invalid request code */ +#define EBADSLT 55 /* Invalid slot */ +#ifndef EDEADLOCK + #define EDEADLOCK EDEADLK /* File locking deadlock error */ +#endif +#define EBFONT 57 /* Bad font file fmt */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data (for no delay io) */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* The object is remote */ +#define ENOLINK 67 /* The link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 74 /* Multihop attempted */ +#define ELBIN 75 /* Inode is remote (not really error) */ +#define EDOTDOT 76 /* Cross mount point (not really error) */ +#define EBADMSG 77 /* Trying to read unreadable message */ +#define ENOTUNIQ 80 /* Given log. name not unique */ +#define EBADFD 81 /* f.d. invalid for this operation */ +#define EREMCHG 82 /* Remote address changed */ +#define ELIBACC 83 /* Can't access a needed shared lib */ +#define ELIBBAD 84 /* Accessing a corrupted shared lib */ +#define ELIBSCN 85 /* .lib section in a.out corrupted */ +#define ELIBMAX 86 /* Attempting to link in too many libs */ +#define ELIBEXEC 87 /* Attempting to exec a shared library */ +#ifndef ENOSYS + #define ENOSYS 88 /* Function not implemented */ +#endif +#define ENMFILE 89 /* No more files */ +#ifndef ENOTEMPTY + #define ENOTEMPTY 90 /* Directory not empty */ +#endif +#ifndef ENAMETOOLONG + #define ENAMETOOLONG 91 /* File or path name too long */ +#endif +#define ELOOP 92 /* Too many symbolic links */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ +#define EPROTOTYPE 107 /* Protocol wrong type for socket */ +#define ENOTSOCK 108 /* Socket operation on non-socket */ +#define ENOPROTOOPT 109 /* Protocol not available */ +#define ESHUTDOWN 110 /* Can't send after socket shutdown */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EADDRINUSE 112 /* Address already in use */ +#define ECONNABORTED 113 /* Connection aborted */ +#define ENETUNREACH 114 /* Network is unreachable */ +#define ENETDOWN 115 /* Network interface is not configured */ +#ifndef ETIMEDOUT + #define ETIMEDOUT 116 /* Connection timed out */ +#endif +#define EHOSTDOWN 117 /* Host is down */ +#define EHOSTUNREACH 118 /* Host is unreachable */ +#define EINPROGRESS 119 /* Connection already in progress */ +#define EALREADY 120 /* Socket already connected */ +#define EDESTADDRREQ 121 /* Destination address required */ +#define EMSGSIZE 122 /* Message too long */ +#define EPROTONOSUPPORT 123 /* Unknown protocol */ +#define ESOCKTNOSUPPORT 124 /* Socket type not supported */ +#define EADDRNOTAVAIL 125 /* Address not available */ +#define ENETRESET 126 /* Connection aborted by network */ +#define EISCONN 127 /* Socket is already connected */ +#define ENOTCONN 128 /* Socket is not connected */ +#define ETOOMANYREFS 129 /* Too many references: cannot splice */ +#define EPROCLIM 130 /* Too many processes */ +#define EUSERS 131 /* Too many users */ +#define EDQUOT 132 /* Disk quota exceeded */ +#define ESTALE 133 /* Unknown error */ +#ifndef ENOTSUP + #define ENOTSUP 134 /* Not supported */ +#endif +#define ENOMEDIUM 135 /* No medium (in tape drive) */ +#define ENOSHARE 136 /* No such host or network path */ +#define ECASECLASH 137 /* Filename exists with different case */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EOVERFLOW 139 /* Value too large for defined data type */ + +#undef HOST_NOT_FOUND +#define HOST_NOT_FOUND 1 +#undef TRY_AGAIN +#define TRY_AGAIN 2 +#undef NO_RECOVERY +#define NO_RECOVERY 3 +#undef NO_ADDRESS +#define NO_ADDRESS 4 + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +#define MAP_SHARED 0x1 +#define MAP_PRIVATE 0x2 /* unsupported */ +#define MAP_FIXED 0x10 +#define MAP_ANONYMOUS 0x20 /* unsupported */ +#define MAP_FAILED ((void *)-1) + +#define MS_ASYNC 1 /* sync memory asynchronously */ +#define MS_INVALIDATE 2 /* invalidate the caches */ +#define MS_SYNC 4 /* synchronous memory sync */ + +struct statfs +{ + long f_type; /* type of filesystem (see below) */ + long f_bsize; /* optimal transfer block size */ + long f_blocks; /* total data blocks in file system */ + long f_bfree; /* free blocks in fs */ + long f_bavail; /* free blocks avail to non-superuser */ + long f_files; /* total file nodes in file system */ + long f_ffree; /* free file nodes in fs */ + long f_fsid; /* file system id */ + long f_namelen; /* maximum length of filenames */ + long f_spare[6]; /* spare for later */ +}; + +extern const struct in6_addr in6addr_any; /* :: */ +extern const struct in6_addr in6addr_loopback; /* ::1 */ + +/* Taken from the Wine project + /wine/include/winternl.h */ +enum SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation = 0, + Unknown1, + SystemPerformanceInformation = 2, + SystemTimeOfDayInformation = 3, /* was SystemTimeInformation */ + Unknown4, + SystemProcessInformation = 5, + Unknown6, + Unknown7, + SystemProcessorPerformanceInformation = 8, + Unknown9, + Unknown10, + SystemDriverInformation, + Unknown12, + Unknown13, + Unknown14, + Unknown15, + SystemHandleList, + Unknown17, + Unknown18, + Unknown19, + Unknown20, + SystemCacheInformation, + Unknown22, + SystemInterruptInformation = 23, + SystemExceptionInformation = 33, + SystemRegistryQuotaInformation = 37, + SystemLookasideInformation = 45 +}; + +typedef struct +{ + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER Reserved1[2]; + ULONG Reserved2; +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + +#define sleep(secs) (Sleep(secs * 1000)) + +/*********************** statfs *****************************/ +/* fake block size */ +#define FAKED_BLOCK_SIZE 512 + +/* linux-compatible values for fs type */ +#define MSDOS_SUPER_MAGIC 0x4d44 +#define NTFS_SUPER_MAGIC 0x5346544E + +/*********************** End of statfs ***********************/ + +#define SHUT_RDWR SD_BOTH + +/* Operations for flock() */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* or'd with one of the above to prevent + blocking */ +#define LOCK_UN 8 /* remove lock */ + +/* Not supported under MinGW */ +#define S_IRGRP 0 +#define S_IWGRP 0 +#define S_IROTH 0 +#define S_IXGRP 0 +#define S_IWOTH 0 +#define S_IXOTH 0 +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 +#define S_IRWXG 0 +#define S_IRWXO 0 + +#define SHUT_WR SD_SEND +#define SHUT_RD SD_RECEIVE +#define SHUT_RDWR SD_BOTH + +#define SIGKILL 9 +#define SIGTERM 15 + +#define SetErrnoFromWinError(e) _SetErrnoFromWinError(e, __FILE__, __LINE__) + +BOOL _plibc_CreateShortcut(const char *pszSrc, const char *pszDest); +BOOL _plibc_DereferenceShortcut(char *pszShortcut); +char *plibc_ChooseDir(char *pszTitle, unsigned long ulFlags); +char *plibc_ChooseFile(char *pszTitle, unsigned long ulFlags); + +long QueryRegistry(HKEY hMainKey, const char *pszKey, const char *pszSubKey, + char *pszBuffer, long *pdLength); +long QueryRegistryW(HKEY hMainKey, const wchar_t *pszKey, const wchar_t *pszSubKey, + wchar_t *pszBuffer, long *pdLength); + +BOOL __win_IsHandleMarkedAsBlocking(int hHandle); +void __win_SetHandleBlockingMode(int s, BOOL bBlocking); +void __win_DiscardHandleBlockingMode(int s); +int _win_isSocketValid(int s); +int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows); +int plibc_conv_to_win_pathw(const wchar_t *pszUnix, wchar_t *pwszWindows); + +int plibc_conv_to_win_pathwconv(const char *pszUnix, wchar_t *pwszWindows); +int plibc_conv_to_win_pathwconv_ex(const char *pszUnix, wchar_t *pszWindows, int derefLinks); + +unsigned plibc_get_handle_count(); + +typedef void (*TPanicProc) (int, char *); +void plibc_set_panic_proc(TPanicProc proc); + +int flock(int fd, int operation); +int fsync(int fildes); +int inet_pton(int af, const char *src, void *dst); +int inet_pton4(const char *src, u_char *dst, int pton); +#if USE_IPV6 +int inet_pton6(const char *src, u_char *dst); +#endif +int truncate(const char *fname, int distance); +int statfs(const char *path, struct statfs *buf); +const char *hstrerror(int err); +int mkstemp(char *tmplate); +char *strptime (const char *buf, const char *format, struct tm *tm); +const char *inet_ntop(int af, const void *src, char *dst, size_t size); +struct tm *gmtime_r(const time_t *clock, struct tm *result); + +int plibc_init(char *pszOrg, char *pszApp); +void plibc_shutdown(); +int plibc_initialized(); + +void _SetErrnoFromWinError(long lWinError, char *pszCaller, int iLine); +void SetErrnoFromWinsockError(long lWinError); +void SetHErrnoFromWinError(long lWinError); +void SetErrnoFromHRESULT(HRESULT hRes); +int GetErrnoFromWinsockError(long lWinError); +FILE *_win_fopen(const char *filename, const char *mode); +int _win_fclose(FILE *); +DIR *_win_opendir(const char *dirname); +struct dirent *_win_readdir(DIR *dirp); +int _win_closedir(DIR *dirp); +int _win_open(const char *filename, int oflag, ...); +#ifdef ENABLE_NLS +char *_win_bindtextdomain(const char *domainname, const char *dirname); +#endif +int _win_chdir(const char *path); +int _win_close(int fd); +int _win_creat(const char *path, mode_t mode); +char *_win_ctime(const time_t *clock); +char *_win_ctime_r(const time_t *clock, char *buf); +int _win_fstat(int handle, struct stat *buffer); +int _win_ftruncate(int fildes, off_t length); +void _win_gettimeofday(struct timeval *tp, void *tzp); +int _win_kill(pid_t pid, int sig); +int _win_pipe(int *phandles); +int _win_rmdir(const char *path); +int _win_access( const char *path, int mode ); +int _win_chmod(const char *filename, int pmode); +char *realpath(const char *file_name, char *resolved_name); +long _win_random(void); +void _win_srandom(unsigned int seed); +int _win_remove(const char *path); +int _win_rename(const char *oldname, const char *newname); +int _win_stat(const char *path, struct stat *buffer); +int _win_stat64(const char *path, struct stat64 *buffer); +long _win_sysconf(int name); +int _win_unlink(const char *filename); +int _win_write(int fildes, const void *buf, size_t nbyte); +int _win_read(int fildes, void *buf, size_t nbyte); +size_t _win_fwrite(const void *buffer, size_t size, size_t count, FILE *stream); +size_t _win_fread( void *buffer, size_t size, size_t count, FILE *stream ); +int _win_symlink(const char *path1, const char *path2); +void *_win_mmap(void *start, size_t len, int access, int flags, int fd, + unsigned long long offset); +int _win_msync(void *start, size_t length, int flags); +int _win_munmap(void *start, size_t length); +int _win_lstat(const char *path, struct stat *buf); +int _win_lstat64(const char *path, struct stat64 *buf); +int _win_readlink(const char *path, char *buf, size_t bufsize); +int _win_accept(int s, struct sockaddr *addr, int *addrlen); + +int _win_printf(const char *format,...); +int _win_wprintf(const wchar_t *format, ...); + +int _win_fprintf(FILE *f,const char *format,...); +int _win_fwprintf(FILE *f,const wchar_t *format, ...); + +int _win_vprintf(const char *format, va_list ap); +int _win_vfwprintf(FILE *stream, const wchar_t *format, va_list arg_ptr); + +int _win_vfprintf(FILE *stream, const char *format, va_list arg_ptr); +int _win_vwprintf(const wchar_t *format, va_list ap); + +int _win_vsprintf(char *dest,const char *format, va_list arg_ptr); +int _win_vswprintf(wchar_t *dest, const wchar_t *format, va_list arg_ptr); + +int _win_vsnprintf(char* str, size_t size, const char *format, va_list arg_ptr); +int _win_vsnwprintf(wchar_t* wstr, size_t size, const wchar_t *format, va_list arg_ptr); + +int _win_snprintf(char *str,size_t size,const char *format,...); +int _win_snwprintf(wchar_t *str, size_t size, const wchar_t *format, ...); + +int _win_sprintf(char *dest,const char *format,...); +int _win_swprintf(wchar_t *dest, const wchar_t *format, ...); + +int _win_vsscanf(const char* str, const char* format, va_list arg_ptr); +int _win_vswscanf(const wchar_t* wstr, const wchar_t* format, va_list arg_ptr); + +int _win_sscanf(const char *str, const char *format, ...); +int _win_swscanf(const wchar_t *wstr, const wchar_t *format, ...); + +int _win_vfscanf(FILE *stream, const char *format, va_list arg_ptr); +int _win_vfwscanf(FILE *stream, const wchar_t *format, va_list arg_ptr); + +int _win_vscanf(const char *format, va_list arg_ptr); +int _win_vwscanf(const wchar_t *format, va_list arg_ptr); + +int _win_scanf(const char *format, ...); +int _win_wscanf(const wchar_t *format, ...); + +int _win_fscanf(FILE *stream, const char *format, ...); +int _win_fwscanf(FILE *stream, const wchar_t *format, ...); + + +pid_t _win_waitpid(pid_t pid, int *stat_loc, int options); +int _win_bind(int s, const struct sockaddr *name, int namelen); +int _win_connect(int s,const struct sockaddr *name, int namelen); +int _win_getpeername(int s, struct sockaddr *name, + int *namelen); +int _win_getsockname(int s, struct sockaddr *name, + int *namelen); +int _win_getsockopt(int s, int level, int optname, char *optval, + int *optlen); +int _win_listen(int s, int backlog); +int _win_recv(int s, char *buf, int len, int flags); +int _win_recvfrom(int s, void *buf, int len, int flags, + struct sockaddr *from, int *fromlen); +int _win_select(int max_fd, fd_set * rfds, fd_set * wfds, fd_set * efds, + const struct timeval *tv); +int _win_send(int s, const char *buf, int len, int flags); +int _win_sendto(int s, const char *buf, int len, int flags, + const struct sockaddr *to, int tolen); +int _win_setsockopt(int s, int level, int optname, const void *optval, + int optlen); +int _win_shutdown(int s, int how); +int _win_socket(int af, int type, int protocol); +struct hostent *_win_gethostbyaddr(const char *addr, int len, int type); +struct hostent *_win_gethostbyname(const char *name); +struct hostent *gethostbyname2(const char *name, int af); +char *_win_strerror(int errnum); +int IsWinNT(); +char *index(const char *s, int c); + +#if !HAVE_STRNDUP +char *strndup (const char *s, size_t n); +#endif +#if !HAVE_STRNLEN +size_t strnlen (const char *str, size_t maxlen); +#endif +char *stpcpy(char *dest, const char *src); +char *strcasestr(const char *haystack_start, const char *needle_start); +#ifndef __MINGW64__ +#define strcasecmp(a, b) stricmp(a, b) +#define wcscasecmp(a, b) wcsicmp(a, b) +#define strncasecmp(a, b, c) strnicmp(a, b, c) +#define wcsncasecmp(a, b, c) wcsnicmp(a, b, c) +#endif +#endif /* WINDOWS */ + +#ifndef WINDOWS + #define DIR_SEPARATOR '/' + #define DIR_SEPARATOR_STR "/" + #define PATH_SEPARATOR ':' + #define PATH_SEPARATOR_STR ":" + #define NEWLINE "\n" + +#ifdef ENABLE_NLS + #define BINDTEXTDOMAIN(d, n) bindtextdomain(d, n) +#endif + #define CREAT(p, m) creat(p, m) + #define PLIBC_CTIME(c) ctime(c) + #define CTIME_R(c, b) ctime_r(c, b) + #undef FOPEN + #define FOPEN(f, m) fopen(f, m) + #define FCLOSE(f) fclose(f) + #define FTRUNCATE(f, l) ftruncate(f, l) + #define OPENDIR(d) opendir(d) + #define CLOSEDIR(d) closedir(d) + #define READDIR(d) readdir(d) + #define OPEN open + #define CHDIR(d) chdir(d) + #define CLOSE(f) close(f) + #define LSEEK(f, o, w) lseek(f, o, w) + #define RMDIR(f) rmdir(f) + #define ACCESS(p, m) access(p, m) + #define CHMOD(f, p) chmod(f, p) + #define FSTAT(h, b) fstat(h, b) + #define PLIBC_KILL(p, s) kill(p, s) + #define PIPE(h) pipe(h) + #define REMOVE(p) remove(p) + #define RENAME(o, n) rename(o, n) + #define STAT(p, b) stat(p, b) + #define STAT64(p, b) stat64(p, b) + #define SYSCONF(n) sysconf(n) + #define UNLINK(f) unlink(f) + #define WRITE(f, b, n) write(f, b, n) + #define READ(f, b, n) read(f, b, n) + #define GN_FREAD(b, s, c, f) fread(b, s, c, f) + #define GN_FWRITE(b, s, c, f) fwrite(b, s, c, f) + #define SYMLINK(a, b) symlink(a, b) + #define MMAP(s, l, p, f, d, o) mmap(s, l, p, f, d, o) + #define MKFIFO(p, m) mkfifo(p, m) + #define MSYNC(s, l, f) msync(s, l, f) + #define MUNMAP(s, l) munmap(s, l) + #define STRERROR(i) strerror(i) + #define RANDOM() random() + #define SRANDOM(s) srandom(s) + #define READLINK(p, b, s) readlink(p, b, s) + #define LSTAT(p, b) lstat(p, b) + #define LSTAT64(p, b) lstat64(p, b) + #define PRINTF printf + #define FPRINTF fprintf + #define VPRINTF(f, a) vprintf(f, a) + #define VFPRINTF(s, f, a) vfprintf(s, f, a) + #define VSPRINTF(d, f, a) vsprintf(d, f, a) + #define VSNPRINTF(str, size, fmt, a) vsnprintf(str, size, fmt, a) + #define _REAL_SNPRINTF snprintf + #define SPRINTF sprintf + #define VSSCANF(s, f, a) vsscanf(s, f, a) + #define SSCANF sscanf + #define VFSCANF(s, f, a) vfscanf(s, f, a) + #define VSCANF(f, a) vscanf(f, a) + #define SCANF scanf + #define FSCANF fscanf + #define WAITPID(p, s, o) waitpid(p, s, o) + #define ACCEPT(s, a, l) accept(s, a, l) + #define BIND(s, n, l) bind(s, n, l) + #define CONNECT(s, n, l) connect(s, n, l) + #define GETPEERNAME(s, n, l) getpeername(s, n, l) + #define GETSOCKNAME(s, n, l) getsockname(s, n, l) + #define GETSOCKOPT(s, l, o, v, p) getsockopt(s, l, o, v, p) + #define LISTEN(s, b) listen(s, b) + #define RECV(s, b, l, f) recv(s, b, l, f) + #define RECVFROM(s, b, l, f, r, o) recvfrom(s, b, l, f, r, o) + #define SELECT(n, r, w, e, t) select(n, r, w, e, t) + #define SEND(s, b, l, f) send(s, b, l, f) + #define SENDTO(s, b, l, f, o, n) sendto(s, b, l, f, o, n) + #define SETSOCKOPT(s, l, o, v, n) setsockopt(s, l, o, v, n) + #define SHUTDOWN(s, h) shutdown(s, h) + #define SOCKET(a, t, p) socket(a, t, p) + #define GETHOSTBYADDR(a, l, t) gethostbyname(a, l, t) + #define GETHOSTBYNAME(n) gethostbyname(n) + #define GETTIMEOFDAY(t, n) gettimeofday(t, n) + #define INSQUE(e, p) insque(e, p) + #define REMQUE(e) remque(e) + #define HSEARCH(i, a) hsearch(i, a) + #define HCREATE(n) hcreate(n) + #define HDESTROY() hdestroy() + #define HSEARCH_R(i, a, r, h) hsearch_r(i, a, r, h) + #define HCREATE_R(n, h) hcreate_r(n, h) + #define HDESTROY_R(h) hdestroy_r(h) + #define TSEARCH(k, r, c) tsearch(k, r, c) + #define TFIND(k, r, c) tfind(k, r, c) + #define TDELETE(k, r, c) tdelete(k, r, c) + #define TWALK(r, a) twalk(r, a) + #define TDESTROY(r, f) tdestroy(r, f) + #define LFIND(k, b, n, s, c) lfind(k, b, n, s, c) + #define LSEARCH(k, b, n, s, c) lsearch(k, b, n, s, c) +#else + #define DIR_SEPARATOR '\\' + #define DIR_SEPARATOR_STR "\\" + #define PATH_SEPARATOR ';' + #define PATH_SEPARATOR_STR ";" + #define NEWLINE "\r\n" + +#ifdef ENABLE_NLS + #define BINDTEXTDOMAIN(d, n) _win_bindtextdomain(d, n) +#endif + #define CREAT(p, m) _win_creat(p, m) + #define PLIBC_CTIME(c) _win_ctime(c) + #define CTIME_R(c, b) _win_ctime_r(c, b) + #define FOPEN(f, m) _win_fopen(f, m) + #define FCLOSE(f) _win_fclose(f) + #define FTRUNCATE(f, l) _win_ftruncate(f, l) + #define OPENDIR(d) _win_opendir(d) + #define CLOSEDIR(d) _win_closedir(d) + #define READDIR(d) _win_readdir(d) + #define OPEN _win_open + #define CHDIR(d) _win_chdir(d) + #define CLOSE(f) _win_close(f) + #define PLIBC_KILL(p, s) _win_kill(p, s) + #define LSEEK(f, o, w) _win_lseek(f, o, w) + #define FSTAT(h, b) _win_fstat(h, b) + #define RMDIR(f) _win_rmdir(f) + #define ACCESS(p, m) _win_access(p, m) + #define CHMOD(f, p) _win_chmod(f, p) + #define PIPE(h) _win_pipe(h) + #define RANDOM() _win_random() + #define SRANDOM(s) _win_srandom(s) + #define REMOVE(p) _win_remove(p) + #define RENAME(o, n) _win_rename(o, n) + #define STAT(p, b) _win_stat(p, b) + #define STAT64(p, b) _win_stat64(p, b) + #define SYSCONF(n) _win_sysconf(n) + #define UNLINK(f) _win_unlink(f) + #define WRITE(f, b, n) _win_write(f, b, n) + #define READ(f, b, n) _win_read(f, b, n) + #define GN_FREAD(b, s, c, f) _win_fread(b, s, c, f) + #define GN_FWRITE(b, s, c, f) _win_fwrite(b, s, c, f) + #define SYMLINK(a, b) _win_symlink(a, b) + #define MMAP(s, l, p, f, d, o) _win_mmap(s, l, p, f, d, o) + #define MKFIFO(p, m) _win_mkfifo(p, m) + #define MSYNC(s, l, f) _win_msync(s, l, f) + #define MUNMAP(s, l) _win_munmap(s, l) + #define STRERROR(i) _win_strerror(i) + #define READLINK(p, b, s) _win_readlink(p, b, s) + #define LSTAT(p, b) _win_lstat(p, b) + #define LSTAT64(p, b) _win_lstat64(p, b) + #define PRINTF(f, ...) _win_printf(f , __VA_ARGS__) + #define FPRINTF(fil, fmt, ...) _win_fprintf(fil, fmt, __VA_ARGS__) + #define VPRINTF(f, a) _win_vprintf(f, a) + #define VFPRINTF(s, f, a) _win_vfprintf(s, f, a) + #define VSPRINTF(d, f, a) _win_vsprintf(d, f, a) + #define VSNPRINTF(str, size, fmt, a) _win_vsnprintf(str, size, fmt, a) + #define _REAL_SNPRINTF(str, size, fmt, ...) _win_snprintf(str, size, fmt, __VA_ARGS__) + #define SPRINTF(d, f, ...) _win_sprintf(d, f, __VA_ARGS__) + #define VSSCANF(s, f, a) _win_vsscanf(s, f, a) + #define SSCANF(s, f, ...) _win_sscanf(s, f, __VA_ARGS__) + #define VFSCANF(s, f, a) _win_vfscanf(s, f, a) + #define VSCANF(f, a) _win_vscanf(f, a) + #define SCANF(f, ...) _win_scanf(f, __VA_ARGS__) + #define FSCANF(s, f, ...) _win_fscanf(s, f, __VA_ARGS__) + #define WAITPID(p, s, o) _win_waitpid(p, s, o) + #define ACCEPT(s, a, l) _win_accept(s, a, l) + #define BIND(s, n, l) _win_bind(s, n, l) + #define CONNECT(s, n, l) _win_connect(s, n, l) + #define GETPEERNAME(s, n, l) _win_getpeername(s, n, l) + #define GETSOCKNAME(s, n, l) _win_getsockname(s, n, l) + #define GETSOCKOPT(s, l, o, v, p) _win_getsockopt(s, l, o, v, p) + #define LISTEN(s, b) _win_listen(s, b) + #define RECV(s, b, l, f) _win_recv(s, b, l, f) + #define RECVFROM(s, b, l, f, r, o) _win_recvfrom(s, b, l, f, r, o) + #define SELECT(n, r, w, e, t) _win_select(n, r, w, e, t) + #define SEND(s, b, l, f) _win_send(s, b, l, f) + #define SENDTO(s, b, l, f, o, n) _win_sendto(s, b, l, f, o, n) + #define SETSOCKOPT(s, l, o, v, n) _win_setsockopt(s, l, o, v, n) + #define SHUTDOWN(s, h) _win_shutdown(s, h) + #define SOCKET(a, t, p) _win_socket(a, t, p) + #define GETHOSTBYADDR(a, l, t) _win_gethostbyname(a, l, t) + #define GETHOSTBYNAME(n) _win_gethostbyname(n) + #define GETTIMEOFDAY(t, n) _win_gettimeofday(t, n) + #define INSQUE(e, p) _win_insque(e, p) + #define REMQUE(e) _win_remque(e) + #define HSEARCH(i, a) _win_hsearch(i, a) + #define HCREATE(n) _win_hcreate(n) + #define HDESTROY() _win_hdestroy() + #define HSEARCH_R(i, a, r, h) _win_hsearch_r(i, a, r, h) + #define HCREATE_R(n, h) _win_hcreate_r(n, h) + #define HDESTROY_R(h) _win_hdestroy_r(h) + #define TSEARCH(k, r, c) _win_tsearch(k, r, c) + #define TFIND(k, r, c) _win_tfind(k, r, c) + #define TDELETE(k, r, c) _win_tdelete(k, r, c) + #define TWALK(r, a) _win_twalk(r, a) + #define TDESTROY(r, f) _win_tdestroy(r, f) + #define LFIND(k, b, n, s, c) _win_lfind(k, b, n, s, c) + #define LSEARCH(k, b, n, s, c) _win_lsearch(k, b, n, s, c) +#endif + +/* search.h */ + +/* Prototype structure for a linked-list data structure. + This is the type used by the `insque' and `remque' functions. */ + +struct PLIBC_SEARCH_QELEM + { + struct qelem *q_forw; + struct qelem *q_back; + char q_data[1]; + }; + + +/* Insert ELEM into a doubly-linked list, after PREV. */ +void _win_insque (void *__elem, void *__prev); + +/* Unlink ELEM from the doubly-linked list that it is in. */ +void _win_remque (void *__elem); + + +/* For use with hsearch(3). */ +typedef int (*PLIBC_SEARCH__compar_fn_t) (__const void *, __const void *); + +typedef PLIBC_SEARCH__compar_fn_t _win_comparison_fn_t; + +/* Action which shall be performed in the call the hsearch. */ +typedef enum + { + PLIBC_SEARCH_FIND, + PLIBC_SEARCH_ENTER + } +PLIBC_SEARCH_ACTION; + +typedef struct PLIBC_SEARCH_entry + { + char *key; + void *data; + } +PLIBC_SEARCH_ENTRY; + +/* The reentrant version has no static variables to maintain the state. + Instead the interface of all functions is extended to take an argument + which describes the current status. */ +typedef struct _PLIBC_SEARCH_ENTRY +{ + unsigned int used; + PLIBC_SEARCH_ENTRY entry; +} +_PLIBC_SEARCH_ENTRY; + + +/* Family of hash table handling functions. The functions also + have reentrant counterparts ending with _r. The non-reentrant + functions all work on a signle internal hashing table. */ + +/* Search for entry matching ITEM.key in internal hash table. If + ACTION is `FIND' return found entry or signal error by returning + NULL. If ACTION is `ENTER' replace existing data (if any) with + ITEM.data. */ +PLIBC_SEARCH_ENTRY *_win_hsearch (PLIBC_SEARCH_ENTRY __item, PLIBC_SEARCH_ACTION __action); + +/* Create a new hashing table which will at most contain NEL elements. */ +int _win_hcreate (size_t __nel); + +/* Destroy current internal hashing table. */ +void _win_hdestroy (void); + +/* Data type for reentrant functions. */ +struct PLIBC_SEARCH_hsearch_data + { + struct _PLIBC_SEARCH_ENTRY *table; + unsigned int size; + unsigned int filled; + }; + +/* Reentrant versions which can handle multiple hashing tables at the + same time. */ +int _win_hsearch_r (PLIBC_SEARCH_ENTRY __item, PLIBC_SEARCH_ACTION __action, PLIBC_SEARCH_ENTRY **__retval, + struct PLIBC_SEARCH_hsearch_data *__htab); +int _win_hcreate_r (size_t __nel, struct PLIBC_SEARCH_hsearch_data *__htab); +void _win_hdestroy_r (struct PLIBC_SEARCH_hsearch_data *__htab); + + +/* The tsearch routines are very interesting. They make many + assumptions about the compiler. It assumes that the first field + in node must be the "key" field, which points to the datum. + Everything depends on that. */ +/* For tsearch */ +typedef enum +{ + PLIBC_SEARCH_preorder, + PLIBC_SEARCH_postorder, + PLIBC_SEARCH_endorder, + PLIBC_SEARCH_leaf +} +PLIBC_SEARCH_VISIT; + +/* Search for an entry matching the given KEY in the tree pointed to + by *ROOTP and insert a new element if not found. */ +void *_win_tsearch (__const void *__key, void **__rootp, + PLIBC_SEARCH__compar_fn_t __compar); + +/* Search for an entry matching the given KEY in the tree pointed to + by *ROOTP. If no matching entry is available return NULL. */ +void *_win_tfind (__const void *__key, void *__const *__rootp, + PLIBC_SEARCH__compar_fn_t __compar); + +/* Remove the element matching KEY from the tree pointed to by *ROOTP. */ +void *_win_tdelete (__const void *__restrict __key, + void **__restrict __rootp, + PLIBC_SEARCH__compar_fn_t __compar); + +typedef void (*PLIBC_SEARCH__action_fn_t) (__const void *__nodep, PLIBC_SEARCH_VISIT __value, + int __level); + +/* Walk through the whole tree and call the ACTION callback for every node + or leaf. */ +void _win_twalk (__const void *__root, PLIBC_SEARCH__action_fn_t __action); + +/* Callback type for function to free a tree node. If the keys are atomic + data this function should do nothing. */ +typedef void (*PLIBC_SEARCH__free_fn_t) (void *__nodep); + +/* Destroy the whole tree, call FREEFCT for each node or leaf. */ +void _win_tdestroy (void *__root, PLIBC_SEARCH__free_fn_t __freefct); + + +/* Perform linear search for KEY by comparing by COMPAR in an array + [BASE,BASE+NMEMB*SIZE). */ +void *_win_lfind (__const void *__key, __const void *__base, + size_t *__nmemb, size_t __size, PLIBC_SEARCH__compar_fn_t __compar); + +/* Perform linear search for KEY by comparing by COMPAR function in + array [BASE,BASE+NMEMB*SIZE) and insert entry if not found. */ +void *_win_lsearch (__const void *__key, void *__base, + size_t *__nmemb, size_t __size, PLIBC_SEARCH__compar_fn_t __compar); + + +#ifdef __cplusplus +} +#endif + + +#endif //_PLIBC_H_ + +/* end of plibc.h */ diff --git a/src/include/winproc.h b/src/include/winproc.h new file mode 100644 index 0000000..3670a74 --- /dev/null +++ b/src/include/winproc.h @@ -0,0 +1,234 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file include/winproc.h + * @brief Definitions for MS Windows + * @author Nils Durner + */ + +#ifndef _WINPROC_H +#define _WINPROC_H + +#include +#include +#include +#include +#include +#include +#include +#ifndef FD_SETSIZE +#define FD_SETSIZE 1024 +#endif +#include +#include +#include +#include +#include +#include +#include +#include /* #define BYTE_ORDER */ +#include +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef MAX_NAME_LENGTH +#define MAX_NAME_LENGTH 25 +#endif + + typedef DWORD WINAPI (*TNtQuerySystemInformation) (int, PVOID, ULONG, PULONG); + typedef DWORD WINAPI (*TGetIfEntry) (PMIB_IFROW pIfRow); + typedef DWORD WINAPI (*TGetIpAddrTable) (PMIB_IPADDRTABLE pIpAddrTable, + PULONG pdwSize, BOOL bOrder); + typedef DWORD WINAPI (*TGetIfTable) (PMIB_IFTABLE pIfTable, PULONG pdwSize, + BOOL bOrder); + typedef DWORD WINAPI (*TGetBestInterfaceEx) (struct sockaddr *, PDWORD); + /* TODO: Explicitly import -A variants (i.e. TCreateHardLinkA) or -W + * variants (TCreateHardLinkW), etc. + */ + typedef DWORD WINAPI (*TCreateHardLink) (LPCTSTR lpFileName, + LPCTSTR lpExistingFileName, + LPSECURITY_ATTRIBUTES + lpSecurityAttributes); + typedef SC_HANDLE WINAPI (*TOpenSCManager) (LPCTSTR lpMachineName, + LPCTSTR lpDatabaseName, + DWORD dwDesiredAccess); + typedef SC_HANDLE WINAPI (*TCreateService) (SC_HANDLE hSCManager, + LPCTSTR lpServiceName, + LPCTSTR lpDisplayName, + DWORD dwDesiredAccess, + DWORD dwServiceType, + DWORD dwStartType, + DWORD dwErrorControl, + LPCTSTR lpBinaryPathName, + LPCTSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, + LPCTSTR lpDependencies, + LPCTSTR lpServiceStartName, + LPCTSTR lpPassword); + typedef BOOL WINAPI (*TCloseServiceHandle) (SC_HANDLE hSCObject); + typedef BOOL WINAPI (*TDeleteService) (SC_HANDLE hService); + typedef SERVICE_STATUS_HANDLE WINAPI (*TRegisterServiceCtrlHandler) (LPCTSTR + lpServiceName, + LPHANDLER_FUNCTION + lpHandlerProc); + typedef BOOL WINAPI (*TSetServiceStatus) (SERVICE_STATUS_HANDLE + hServiceStatus, + LPSERVICE_STATUS lpServiceStatus); + typedef BOOL WINAPI (*TStartServiceCtrlDispatcher) (const + LPSERVICE_TABLE_ENTRY + lpServiceTable); + typedef BOOL WINAPI (*TControlService) (SC_HANDLE hService, DWORD dwControl, + LPSERVICE_STATUS lpServiceStatus); + typedef SC_HANDLE WINAPI (*TOpenService) (SC_HANDLE hSCManager, + LPCTSTR lpServiceName, + DWORD dwDesiredAccess); + typedef DWORD WINAPI (*TGetAdaptersInfo) (PIP_ADAPTER_INFO pAdapterInfo, + PULONG pOutBufLen); + typedef NET_API_STATUS WINAPI (*TNetUserAdd) (LPCWSTR, DWORD, PBYTE, PDWORD); + typedef NET_API_STATUS WINAPI (*TNetUserSetInfo) (LPCWSTR servername, + LPCWSTR username, + DWORD level, LPBYTE buf, + LPDWORD parm_err); + typedef NTSTATUS NTAPI (*TLsaOpenPolicy) (PLSA_UNICODE_STRING, + PLSA_OBJECT_ATTRIBUTES, ACCESS_MASK, + PLSA_HANDLE); + typedef NTSTATUS NTAPI (*TLsaAddAccountRights) (LSA_HANDLE, PSID, + PLSA_UNICODE_STRING, ULONG); + typedef NTSTATUS NTAPI (*TLsaRemoveAccountRights) (LSA_HANDLE, PSID, BOOLEAN, + PLSA_UNICODE_STRING, + ULONG); + typedef NTSTATUS NTAPI (*TLsaClose) (LSA_HANDLE); + typedef BOOL WINAPI (*TLookupAccountName) (LPCTSTR lpSystemName, + LPCTSTR lpAccountName, PSID Sid, + LPDWORD cbSid, + LPTSTR ReferencedDomainName, + LPDWORD cchReferencedDomainName, + PSID_NAME_USE peUse); + + typedef BOOL WINAPI (*TGetFileSecurity) (LPCTSTR lpFileName, + SECURITY_INFORMATION + RequestedInformation, + PSECURITY_DESCRIPTOR + pSecurityDescriptor, DWORD nLength, + LPDWORD lpnLengthNeeded); + typedef BOOL WINAPI (*TInitializeSecurityDescriptor) (PSECURITY_DESCRIPTOR + pSecurityDescriptor, + DWORD dwRevision); + typedef BOOL WINAPI (*TGetSecurityDescriptorDacl) (PSECURITY_DESCRIPTOR + pSecurityDescriptor, + LPBOOL lpbDaclPresent, + PACL * pDacl, + LPBOOL lpbDaclDefaulted); + typedef BOOL WINAPI (*TGetAclInformation) (PACL pAcl, LPVOID pAclInformation, + DWORD nAclInformationLength, + ACL_INFORMATION_CLASS + dwAclInformationClass); + typedef BOOL WINAPI (*TInitializeAcl) (PACL pAcl, DWORD nAclLength, + DWORD dwAclRevision); + typedef BOOL WINAPI (*TGetAce) (PACL pAcl, DWORD dwAceIndex, LPVOID * pAce); + typedef BOOL WINAPI (*TEqualSid) (PSID pSid1, PSID pSid2); + typedef BOOL WINAPI (*TAddAce) (PACL pAcl, DWORD dwAceRevision, + DWORD dwStartingAceIndex, LPVOID pAceList, + DWORD nAceListLength); + typedef BOOL WINAPI (*TAddAccessAllowedAce) (PACL pAcl, DWORD dwAceRevision, + DWORD AccessMask, PSID pSid); + typedef BOOL WINAPI (*TSetNamedSecurityInfo) (LPTSTR pObjectName, + SE_OBJECT_TYPE ObjectType, + SECURITY_INFORMATION + SecurityInfo, PSID psidOwner, + PSID psidGroup, PACL pDacl, + PACL pSacl); + + extern TGetBestInterfaceEx GNGetBestInterfaceEx; + extern TNtQuerySystemInformation GNNtQuerySystemInformation; + extern TGetIfEntry GNGetIfEntry; + extern TGetIpAddrTable GNGetIpAddrTable; + extern TGetIfTable GNGetIfTable; + extern TCreateHardLink GNCreateHardLink; + extern TOpenSCManager GNOpenSCManager; + extern TCreateService GNCreateService; + extern TCloseServiceHandle GNCloseServiceHandle; + extern TDeleteService GNDeleteService; + extern TRegisterServiceCtrlHandler GNRegisterServiceCtrlHandler; + extern TSetServiceStatus GNSetServiceStatus; + extern TStartServiceCtrlDispatcher GNStartServiceCtrlDispatcher; + extern TControlService GNControlService; + extern TOpenService GNOpenService; + extern TGetAdaptersInfo GNGetAdaptersInfo; + extern TNetUserAdd GNNetUserAdd; + extern TNetUserSetInfo GNNetUserSetInfo; + extern TLsaOpenPolicy GNLsaOpenPolicy; + extern TLsaAddAccountRights GNLsaAddAccountRights; + extern TLsaRemoveAccountRights GNLsaRemoveAccountRights; + extern TLsaClose GNLsaClose; + extern TLookupAccountName GNLookupAccountName; + extern TGetFileSecurity GNGetFileSecurity; + extern TInitializeSecurityDescriptor GNInitializeSecurityDescriptor; + extern TGetSecurityDescriptorDacl GNGetSecurityDescriptorDacl; + extern TGetAclInformation GNGetAclInformation; + extern TInitializeAcl GNInitializeAcl; + extern TGetAce GNGetAce; + extern TEqualSid GNEqualSid; + extern TAddAce GNAddAce; + extern TAddAccessAllowedAce GNAddAccessAllowedAce; + extern TSetNamedSecurityInfo GNSetNamedSecurityInfo; + + + BOOL CreateShortcut (const char *pszSrc, const char *pszDest); + BOOL DereferenceShortcut (char *pszShortcut); + long QueryRegistry (HKEY hMainKey, const char *pszKey, const char *pszSubKey, + char *pszBuffer, long *pdLength); + int ListNICs (void (*callback) (void *, const char *, int), void *cls); + BOOL AddPathAccessRights (char *lpszFileName, char *lpszAccountName, + DWORD dwAccessMask); + char *winErrorStr (const char *prefix, int dwErr); + void EnumNICs (PMIB_IFTABLE * pIfTable, PMIB_IPADDRTABLE * pAddrTable); + +#define ENUMNICS3_MASK_OK 0x01 +#define ENUMNICS3_BCAST_OK 0x02 + + struct EnumNICs3_results + { + unsigned char flags; + int is_default; + char pretty_name[1001]; + size_t addr_size; + SOCKADDR_STORAGE address; + SOCKADDR_STORAGE mask; + SOCKADDR_STORAGE broadcast; + }; + + int EnumNICs3 (struct EnumNICs3_results **, int *EnumNICs3_results_count); + void EnumNICs3_free (struct EnumNICs3_results *); + int GNInitWinEnv (); + void GNShutdownWinEnv (); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/integration-tests/Makefile.am b/src/integration-tests/Makefile.am new file mode 100644 index 0000000..d948b3d --- /dev/null +++ b/src/integration-tests/Makefile.am @@ -0,0 +1,113 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +bin_PROGRAMS = + +check_PROGRAMS = + +noinst_SCRIPTS = \ + gnunet_testing.py \ + gnunet_pyexpect.py + +if HAVE_PYTHON_PEXPECT +check_SCRIPTS = \ + test_integration_bootstrap_and_connect.py \ + test_integration_bootstrap_and_connect_and_disconnect.py \ + test_integration_bootstrap_and_connect_and_disconnect_nat.py \ + test_integration_restart.py \ + test_integration_clique.py \ + test_integration_clique_nat.py +endif +# test_integration_disconnect.py + + +if ENABLE_TEST_RUN +TESTS = \ + $(check_SCRIPTS) +endif + +do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' + +%.py: %.py.in Makefile + $(do_subst) < $(srcdir)/$< > $@ + chmod +x $@ + +gnunet_testing.py: gnunet_testing.py.in Makefile + $(do_subst) < $(srcdir)/gnunet_testing.py.in > gnunet_testing.py + chmod +x gnunet_testing.py + +gnunet_pyexpect.py: gnunet_pyexpect.py.in Makefile + $(do_subst) < $(srcdir)/gnunet_pyexpect.py.in > gnunet_pyexpect.py + chmod +x gnunet_pyexpect.py + +test_integration_bootstrap_and_connect.py: test_integration_bootstrap_and_connect.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect.py.in > test_integration_bootstrap_and_connect.py + chmod +x test_integration_bootstrap_and_connect.py + +test_integration_bootstrap_and_connect_and_disconnect.py: test_integration_bootstrap_and_connect_and_disconnect.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect_and_disconnect.py.in > test_integration_bootstrap_and_connect_and_disconnect.py + chmod +x test_integration_bootstrap_and_connect_and_disconnect.py + +test_integration_bootstrap_and_connect_and_disconnect_nat.py: test_integration_bootstrap_and_connect_and_disconnect_nat.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect_and_disconnect_nat.py.in > test_integration_bootstrap_and_connect_and_disconnect_nat.py + chmod +x test_integration_bootstrap_and_connect_and_disconnect_nat.py + + +test_integration_disconnect.py: test_integration_disconnect.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_disconnect.py.in > test_integration_disconnect.py + chmod +x test_integration_disconnect.py + +#test_integration_disconnect_nat.py: test_integration_disconnect_nat.py.in Makefile +# $(do_subst) < $(srcdir)/test_integration_disconnect_nat.py.in > test_integration_disconnect_nat.py +# chmod +x test_integration_disconnect_nat.py + +test_integration_restart.py: test_integration_restart.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_restart.py.in > test_integration_restart.py + chmod +x test_integration_restart.py + +test_integration_clique.py: test_integration_clique.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_clique.py.in > test_integration_clique.py + chmod +x test_integration_clique.py + +test_integration_clique_nat.py: test_integration_clique_nat.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_clique_nat.py.in > test_integration_clique_nat.py + chmod +x test_integration_clique_nat.py + + +EXTRA_DIST = \ + gnunet_testing.py.in \ + gnunet_pyexpect.py.in \ + test_integration_bootstrap_and_connect.py.in \ + test_integration_bootstrap_and_connect_and_disconnect.py.in \ + test_integration_bootstrap_and_connect_and_disconnect_nat.py.in \ + test_integration_disconnect.py.in \ + test_integration_restart.py.in \ + test_integration_clique.py.in \ + test_integration_clique_nat.py.in \ + confs/c_bootstrap_server.conf \ + confs/c_nat_client.conf \ + confs/c_no_nat_client_2.conf \ + confs/c_no_nat_client.conf \ + hostkeys/0000-hostkey \ + hostkeys/0001-hostkey \ + hostkeys/0002-hostkey \ + hostkeys/0003-hostkey \ + hostkeys/0004-hostkey \ + hostkeys/0005-hostkey \ + hostkeys/0006-hostkey \ + hostkeys/0007-hostkey \ + hostkeys/0008-hostkey \ + hostkeys/0009-hostkey +# test_integration_disconnect_nat.py + +CLEANFILES = \ + $(check_SCRIPTS) \ + gnunet_testing.py diff --git a/src/integration-tests/Makefile.in b/src/integration-tests/Makefile.in new file mode 100644 index 0000000..20b13d6 --- /dev/null +++ b/src/integration-tests/Makefile.in @@ -0,0 +1,715 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = +check_PROGRAMS = +subdir = src/integration-tests +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +SCRIPTS = $(noinst_SCRIPTS) +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +noinst_SCRIPTS = \ + gnunet_testing.py \ + gnunet_pyexpect.py + +@HAVE_PYTHON_PEXPECT_TRUE@check_SCRIPTS = \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_integration_bootstrap_and_connect.py \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_integration_bootstrap_and_connect_and_disconnect.py \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_integration_bootstrap_and_connect_and_disconnect_nat.py \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_integration_restart.py \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_integration_clique.py \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_integration_clique_nat.py + +# test_integration_disconnect.py +@ENABLE_TEST_RUN_TRUE@TESTS = \ +@ENABLE_TEST_RUN_TRUE@ $(check_SCRIPTS) + +do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' +EXTRA_DIST = \ + gnunet_testing.py.in \ + gnunet_pyexpect.py.in \ + test_integration_bootstrap_and_connect.py.in \ + test_integration_bootstrap_and_connect_and_disconnect.py.in \ + test_integration_bootstrap_and_connect_and_disconnect_nat.py.in \ + test_integration_disconnect.py.in \ + test_integration_restart.py.in \ + test_integration_clique.py.in \ + test_integration_clique_nat.py.in \ + confs/c_bootstrap_server.conf \ + confs/c_nat_client.conf \ + confs/c_no_nat_client_2.conf \ + confs/c_no_nat_client.conf \ + hostkeys/0000-hostkey \ + hostkeys/0001-hostkey \ + hostkeys/0002-hostkey \ + hostkeys/0003-hostkey \ + hostkeys/0004-hostkey \ + hostkeys/0005-hostkey \ + hostkeys/0006-hostkey \ + hostkeys/0007-hostkey \ + hostkeys/0008-hostkey \ + hostkeys/0009-hostkey + +# test_integration_disconnect_nat.py +CLEANFILES = \ + $(check_SCRIPTS) \ + gnunet_testing.py + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/integration-tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/integration-tests/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) $(SCRIPTS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: check-am install-am install-strip + +.PHONY: all all-am check check-TESTS check-am clean clean-binPROGRAMS \ + clean-checkPROGRAMS clean-generic clean-libtool distclean \ + distclean-generic distclean-libtool distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-binPROGRAMS + + +%.py: %.py.in Makefile + $(do_subst) < $(srcdir)/$< > $@ + chmod +x $@ + +gnunet_testing.py: gnunet_testing.py.in Makefile + $(do_subst) < $(srcdir)/gnunet_testing.py.in > gnunet_testing.py + chmod +x gnunet_testing.py + +gnunet_pyexpect.py: gnunet_pyexpect.py.in Makefile + $(do_subst) < $(srcdir)/gnunet_pyexpect.py.in > gnunet_pyexpect.py + chmod +x gnunet_pyexpect.py + +test_integration_bootstrap_and_connect.py: test_integration_bootstrap_and_connect.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect.py.in > test_integration_bootstrap_and_connect.py + chmod +x test_integration_bootstrap_and_connect.py + +test_integration_bootstrap_and_connect_and_disconnect.py: test_integration_bootstrap_and_connect_and_disconnect.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect_and_disconnect.py.in > test_integration_bootstrap_and_connect_and_disconnect.py + chmod +x test_integration_bootstrap_and_connect_and_disconnect.py + +test_integration_bootstrap_and_connect_and_disconnect_nat.py: test_integration_bootstrap_and_connect_and_disconnect_nat.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect_and_disconnect_nat.py.in > test_integration_bootstrap_and_connect_and_disconnect_nat.py + chmod +x test_integration_bootstrap_and_connect_and_disconnect_nat.py + +test_integration_disconnect.py: test_integration_disconnect.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_disconnect.py.in > test_integration_disconnect.py + chmod +x test_integration_disconnect.py + +#test_integration_disconnect_nat.py: test_integration_disconnect_nat.py.in Makefile +# $(do_subst) < $(srcdir)/test_integration_disconnect_nat.py.in > test_integration_disconnect_nat.py +# chmod +x test_integration_disconnect_nat.py + +test_integration_restart.py: test_integration_restart.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_restart.py.in > test_integration_restart.py + chmod +x test_integration_restart.py + +test_integration_clique.py: test_integration_clique.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_clique.py.in > test_integration_clique.py + chmod +x test_integration_clique.py + +test_integration_clique_nat.py: test_integration_clique_nat.py.in Makefile + $(do_subst) < $(srcdir)/test_integration_clique_nat.py.in > test_integration_clique_nat.py + chmod +x test_integration_clique_nat.py + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/integration-tests/confs/c_bootstrap_server.conf b/src/integration-tests/confs/c_bootstrap_server.conf new file mode 100644 index 0000000..0b919f9 --- /dev/null +++ b/src/integration-tests/confs/c_bootstrap_server.conf @@ -0,0 +1,355 @@ +[PATHS] +SERVICEHOME = /tmp/c_bootstrap_server/ +DEFAULTCONFIG = confs/c_bootstrap_server.conf + +[gnunetd] +#HOSTKEY = $SERVICEHOME/.hostkey +HOSTKEY = hostkeys/0000-hostkey + +[vpn] +AUTOSTART = YES +PORT = 0 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dns +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-vpn-15 + +[resolver] +AUTOSTART = YES +PORT = 20017 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-resolver +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-resolver-14 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = NO + +[mesh] +AUTOSTART = YES +PORT = 20016 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-mesh +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-mesh-13 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[nse] +AUTOSTART = YES +PORT = 20015 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-nse +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-nse-12 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +PROOFFILE = $SERVICEHOME/.nse-proof +HISTOGRAM = $SERVICEHOME/nse-history.log +WORKDELAY = 5 ms +INTERVAL = 1 h +WORKBITS = 26 + +[topology] +MINIMUM-FRIENDS = 0 +FRIENDS-ONLY = NO +AUTOCONNECT = YES +TARGET-CONNECTION-COUNT = 16 +FRIENDS = $SERVICEHOME/friends +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-topology + +[datastore] +AUTOSTART = YES +UNIXPATH = /tmp/test-service-datastore-11 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +PORT = 20014 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-datastore +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +QUOTA = 100 MB +BLOOMFILTER = $SERVICEHOME/fs/bloomfilter +DATABASE = sqlite + +[datastore-sqlite] +FILENAME = $SERVICEHOME/datastore/sqlite.db + +[datastore-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[datastore-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf + +[peerinfo] +AUTOSTART = YES +PORT = 20013 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-peerinfo +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-peerinfo-10 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +HOSTS = $SERVICEHOME/data/hosts/ + +[client] +HOME = $SERVICEHOME + +[TESTING] +WEAKRANDOM = YES +CONNECT_TIMEOUT = 30 s +CONNECT_ATTEMPTS = 3 +MAX_OUTSTANDING_CONNECTIONS = 50 +DELETE_FILES = YES + +[ats] +AUTOSTART = YES +PORT = 20012 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-ats +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-ats-9 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +WAN_QUOTA_IN = 65536 +WAN_QUOTA_OUT = 65536 +DUMP_MLP = NO +DUMP_SOLUTION = NO +DUMP_OVERWRITE = NO +DUMP_MIN_PEERS = 0 +DUMP_MIN_ADDRS = 0 +ATS_MIN_INTERVAL = 15000 +ATS_EXEC_INTERVAL = 30000 + +[transport] +AUTOSTART = YES +PORT = 20011 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-transport +NEIGHBOUR_LIMIT = 50 +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +PLUGINS = tcp +UNIXPATH = /tmp/test-service-transport-8 +BLACKLIST_FILE = $SERVICEHOME/blacklist +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[transport-tcp] +USE_LOCALADDR = YES +PORT = 20010 +ADVERTISED_PORT = 20010 +MAX_CONNECTIONS = 128 +TIMEOUT = 5 s + +[transport-udp] +USE_LOCALADDR = YES +PORT = 20009 +BROADCAST = YES +BROADCAST_INTERVAL = 30000 +MAX_BPS = 1000000 + +[transport-http] +PORT = 20008 +MAX_CONNECTIONS = 128 + +[transport-https] +PORT = 20007 +CRYPTO_INIT = NORMAL +KEY_FILE = https.key +CERT_FILE = https.cert +MAX_CONNECTIONS = 128 + +[transport-wlan] +INTERFACE = mon0 +TESTMODE = 0 + +[datacache-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf + +[datacache-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[template] +AUTOSTART = NO +PORT = 20006 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-template +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-template-7 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[fs] +AUTOSTART = YES +INDEXDB = $SERVICEHOME/idxinfo.lst +TRUST = $SERVICEHOME/data/credit/ +IDENTITY_DIR = $SERVICEHOME/identities/ +STATE_DIR = $SERVICEHOME/persistence/ +UPDATE_DIR = $SERVICEHOME/updates/ +PORT = 20005 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-fs +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DELAY = YES +CONTENT_CACHING = YES +CONTENT_PUSHING = YES +UNIXPATH = /tmp/test-service-fs-6 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +MAX_PENDING_REQUESTS = 65536 +MIN_MIGRATION_DELAY = 100 ms +EXPECTED_NEIGHBOUR_COUNT = 128 + +[vpn] +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-vpn +IPV6ADDR = 1234::1 +IPV6PREFIX = 32 +IPV4ADDR = 10.11.10.1 +IPV4MASK = 255.255.0.0 +VIRTDNS = 10.11.10.2 +VIRTDNS6 = 1234::17 +IFNAME = vpn-gnunet + +[exit] +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-exit +IPV6ADDR = 1234:1::1 +IPV6PREFIX = 32 +IPV4ADDR = 10.10.1.1 +IPV4MASK = 255.255.0.0 +IFNAME = exit-gnunet +ENABLE_UDP = NO +ENABLE_TCP = NO + +[dns] +AUTOSTART = YES +PORT = 0 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dns +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-dns-5 +PROVIDE_EXIT = NO + +[arm] +PORT = 20004 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-arm +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DEFAULTSERVICES = topology hostlist fs +UNIXPATH = /tmp/test-service-arm-4 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[hostlist] +HTTPPORT = 8080 +HOME = $SERVICEHOME +HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-hostlist +OPTIONS = -p +#SERVERS = http://v9.gnunet.org:58080/ +HTTP-PROXY = + +[core] +AUTOSTART = YES +PORT = 20003 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-core +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-core-3 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[nat] +EXTERNAL_ADDRESS = 127.0.0.1 +INTERNAL_ADDRESS = 127.0.0.1 +BINDTO = 127.0.0.1 +BEHIND_NAT = NO +PUNCHED_NAT = NO +ENABLE_UPNP = NO +USE_LOCALADDR = YES +USE_HOSTNAME = NO +ENABLE_ICMP_CLIENT = NO +ENABLE_ICMP_SERVER = NO +DISABLEV6 = YES +RETURN_LOCAL_ADDRESSES = NO +HOSTNAME_DNS_FREQUENCY = 1200000 +IFC_SCAN_FREQUENCY = 3000000 +DYNDNS_FREQUENCY = 140000 + +[gnunet-nat-server] +HOSTNAME = gnunet.org +PORT = 20002 + +[statistics] +AUTOSTART = YES +PORT = 20001 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-statistics +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-statistics-2 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES + +[dht] +AUTOSTART = YES +PORT = 20000 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dht +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +BUCKET_SIZE = 4 +UNIXPATH = /tmp/test-service-dht-1 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[dhtcache] +DATABASE = sqlite +QUOTA = 1 MB + diff --git a/src/integration-tests/confs/c_nat_client.conf b/src/integration-tests/confs/c_nat_client.conf new file mode 100644 index 0000000..59fa0f7 --- /dev/null +++ b/src/integration-tests/confs/c_nat_client.conf @@ -0,0 +1,354 @@ +[PATHS] +SERVICEHOME = /tmp/c_nat_client +DEFAULTCONFIG = confs/c_nat_client.conf + +[gnunetd] +HOSTKEY = hostkeys/0002-hostkey + +[client] +HOME = $SERVICEHOME + +[vpn] +AUTOSTART = YES +PORT = 0 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dns +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-vpn-57 + + +[resolver] +AUTOSTART = YES +PORT = 20071 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-resolver +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-resolver-56 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = NO + +[mesh] +AUTOSTART = YES +PORT = 20070 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-mesh +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-mesh-55 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[nse] +AUTOSTART = YES +PORT = 20069 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-nse +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-nse-54 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +PROOFFILE = $SERVICEHOME/.nse-proof +HISTOGRAM = $SERVICEHOME/nse-history.log +WORKDELAY = 5 ms +INTERVAL = 1 h +WORKBITS = 26 + +[topology] +MINIMUM-FRIENDS = 0 +FRIENDS-ONLY = NO +AUTOCONNECT = YES +TARGET-CONNECTION-COUNT = 16 +FRIENDS = $SERVICEHOME/friends +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-topology + +[datastore] +AUTOSTART = YES +UNIXPATH = /tmp/test-service-datastore-53 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +PORT = 20068 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-datastore +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +QUOTA = 100 MB +BLOOMFILTER = $SERVICEHOME/fs/bloomfilter +DATABASE = sqlite + +[datastore-sqlite] +FILENAME = $SERVICEHOME/datastore/sqlite.db + +[datastore-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[datastore-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf + +[peerinfo] +AUTOSTART = YES +PORT = 20067 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-peerinfo +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-peerinfo-52 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +HOSTS = $SERVICEHOME/data/hosts/ + +[TESTING] +WEAKRANDOM = NO +CONNECT_TIMEOUT = 30 s +CONNECT_ATTEMPTS = 3 +MAX_OUTSTANDING_CONNECTIONS = 50 +DELETE_FILES = YES + +[ats] +AUTOSTART = YES +PORT = 20066 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-ats +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-ats-51 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +WAN_QUOTA_IN = 65536 +WAN_QUOTA_OUT = 65536 +DUMP_MLP = NO +DUMP_SOLUTION = NO +DUMP_OVERWRITE = NO +DUMP_MIN_PEERS = 0 +DUMP_MIN_ADDRS = 0 +ATS_MIN_INTERVAL = 15000 +ATS_EXEC_INTERVAL = 30000 + +[transport] +AUTOSTART = YES +PORT = 20065 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-transport +NEIGHBOUR_LIMIT = 50 +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +PLUGINS = tcp +UNIXPATH = /tmp/test-service-transport-50 +BLACKLIST_FILE = $SERVICEHOME/blacklist +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[transport-tcp] +PORT = 0 +ADVERTISED_PORT = 20064 +MAX_CONNECTIONS = 128 +TIMEOUT = 5 s +USE_LOCALADDR = YES + +[transport-udp] +PORT = 0 +BROADCAST = YES +BROADCAST_INTERVAL = 30000 +MAX_BPS = 1000000 +USE_LOCALADDR = YES + +[transport-http] +PORT = 0 +MAX_CONNECTIONS = 128 + +[transport-https] +PORT = 0 +CRYPTO_INIT = NORMAL +KEY_FILE = https.key +CERT_FILE = https.cert +MAX_CONNECTIONS = 128 + +[transport-wlan] +INTERFACE = mon0 +TESTMODE = 0 + +[datacache-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf + +[datacache-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[template] +AUTOSTART = NO +PORT = 20060 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-template +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-template-49 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[fs] +AUTOSTART = YES +INDEXDB = $SERVICEHOME/idxinfo.lst +TRUST = $SERVICEHOME/data/credit/ +IDENTITY_DIR = $SERVICEHOME/identities/ +STATE_DIR = $SERVICEHOME/persistence/ +UPDATE_DIR = $SERVICEHOME/updates/ +PORT = 20059 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-fs +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DELAY = YES +CONTENT_CACHING = YES +CONTENT_PUSHING = YES +UNIXPATH = /tmp/test-service-fs-48 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +MAX_PENDING_REQUESTS = 65536 +MIN_MIGRATION_DELAY = 100 ms +EXPECTED_NEIGHBOUR_COUNT = 128 + +[vpn] +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-vpn +IPV6ADDR = 1234::1 +IPV6PREFIX = 32 +IPV4ADDR = 10.11.10.1 +IPV4MASK = 255.255.0.0 +VIRTDNS = 10.11.10.2 +VIRTDNS6 = 1234::17 +IFNAME = vpn-gnunet + +[exit] +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-exit +IPV6ADDR = 1234:1::1 +IPV6PREFIX = 32 +IPV4ADDR = 10.10.1.1 +IPV4MASK = 255.255.0.0 +IFNAME = exit-gnunet +ENABLE_UDP = NO +ENABLE_TCP = NO + +[dns] +AUTOSTART = YES +PORT = 0 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dns +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-dns-47 +PROVIDE_EXIT = NO + +[arm] +PORT = 20058 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-arm +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DEFAULTSERVICES = topology hostlist fs +UNIXPATH = /tmp/test-service-arm-46 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[hostlist] +HTTPPORT = 8080 +HOME = $SERVICEHOME +HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-hostlist +OPTIONS = -b +SERVERS = http://localhost:8080/ +HTTP-PROXY = + +[core] +AUTOSTART = YES +PORT = 20057 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-core +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-core-45 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[nat] +BEHIND_NAT = YES +PUNCHED_NAT = NO +ENABLE_UPNP = NO +USE_LOCALADDR = YES +USE_HOSTNAME = NO +ENABLE_ICMP_CLIENT = NO +ENABLE_ICMP_SERVER = NO +DISABLEV6 = YES +RETURN_LOCAL_ADDRESSES = NO +HOSTNAME_DNS_FREQUENCY = 1200000 +IFC_SCAN_FREQUENCY = 3000000 +DYNDNS_FREQUENCY = 140000 +EXTERNAL_ADDRESS = 127.0.0.1 +INTERNAL_ADDRESS = 127.0.0.1 +BINDTO = 127.0.0.1 + +[gnunet-nat-server] +HOSTNAME = gnunet.org +PORT = 20056 + +[statistics] +AUTOSTART = YES +PORT = 20055 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-statistics +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-statistics-44 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES + +[dht] +AUTOSTART = YES +PORT = 20054 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dht +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +BUCKET_SIZE = 4 +UNIXPATH = /tmp/test-service-dht-43 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[dhtcache] +DATABASE = sqlite +QUOTA = 1 MB \ No newline at end of file diff --git a/src/integration-tests/confs/c_no_nat_client.conf b/src/integration-tests/confs/c_no_nat_client.conf new file mode 100644 index 0000000..4ec077c --- /dev/null +++ b/src/integration-tests/confs/c_no_nat_client.conf @@ -0,0 +1,356 @@ +[PATHS] +SERVICEHOME = /tmp/c_no_nat_client/ +DEFAULTCONFIG = confs/c_no_nat_client.conf + +[gnunetd] +#HOSTKEY = $SERVICEHOME/.hostkey +HOSTKEY = hostkeys/0001-hostkey + +[vpn] +AUTOSTART = YES +PORT = 0 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dns +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-vpn-29 + +[resolver] +AUTOSTART = YES +PORT = 20035 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-resolver +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-resolver-28 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = NO + +[mesh] +AUTOSTART = YES +PORT = 20034 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-mesh +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-mesh-27 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[nse] +AUTOSTART = YES +PORT = 20033 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-nse +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-nse-26 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +PROOFFILE = $SERVICEHOME/.nse-proof +HISTOGRAM = $SERVICEHOME/nse-history.log +WORKDELAY = 5 ms +INTERVAL = 1 h +WORKBITS = 26 + +[topology] +MINIMUM-FRIENDS = 0 +FRIENDS-ONLY = NO +AUTOCONNECT = YES +TARGET-CONNECTION-COUNT = 16 +FRIENDS = $SERVICEHOME/friends +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-topology + +[datastore] +AUTOSTART = YES +UNIXPATH = /tmp/test-service-datastore-25 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +PORT = 20032 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-datastore +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +QUOTA = 100 MB +BLOOMFILTER = $SERVICEHOME/fs/bloomfilter +DATABASE = sqlite + +[datastore-sqlite] +FILENAME = $SERVICEHOME/datastore/sqlite.db + +[datastore-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[datastore-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf + +[peerinfo] +AUTOSTART = YES +PORT = 20031 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-peerinfo +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-peerinfo-24 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +HOSTS = $SERVICEHOME/data/hosts/ + +[client] +HOME = $SERVICEHOME + +[TESTING] +WEAKRANDOM = NO +CONNECT_TIMEOUT = 30 s +CONNECT_ATTEMPTS = 3 +MAX_OUTSTANDING_CONNECTIONS = 50 +DELETE_FILES = YES + +[ats] +AUTOSTART = YES +PORT = 20030 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-ats +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-ats-23 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +WAN_QUOTA_IN = 65536 +WAN_QUOTA_OUT = 65536 +DUMP_MLP = NO +DUMP_SOLUTION = NO +DUMP_OVERWRITE = NO +DUMP_MIN_PEERS = 0 +DUMP_MIN_ADDRS = 0 +ATS_MIN_INTERVAL = 15000 +ATS_EXEC_INTERVAL = 30000 + +[transport] +#DEBUG = YES +AUTOSTART = YES +PORT = 20029 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-transport +NEIGHBOUR_LIMIT = 50 +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +PLUGINS = tcp +UNIXPATH = /tmp/test-service-transport-22 +BLACKLIST_FILE = $SERVICEHOME/blacklist +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[transport-tcp] +USE_LOCALADDR = YES +PORT = 20028 +ADVERTISED_PORT = 20028 +MAX_CONNECTIONS = 128 +TIMEOUT = 5 s + +[transport-udp] +USE_LOCALADDR = YES +PORT = 20027 +BROADCAST = YES +BROADCAST_INTERVAL = 30000 +MAX_BPS = 1000000 + +[transport-http] +PORT = 20026 +MAX_CONNECTIONS = 128 + +[transport-https] +PORT = 20025 +CRYPTO_INIT = NORMAL +KEY_FILE = https.key +CERT_FILE = https.cert +MAX_CONNECTIONS = 128 + +[transport-wlan] +INTERFACE = mon0 +TESTMODE = 0 + +[datacache-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf + +[datacache-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[template] +AUTOSTART = NO +PORT = 20024 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-template +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-template-21 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[fs] +AUTOSTART = YES +INDEXDB = $SERVICEHOME/idxinfo.lst +TRUST = $SERVICEHOME/data/credit/ +IDENTITY_DIR = $SERVICEHOME/identities/ +STATE_DIR = $SERVICEHOME/persistence/ +UPDATE_DIR = $SERVICEHOME/updates/ +PORT = 20023 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-fs +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DELAY = YES +CONTENT_CACHING = YES +CONTENT_PUSHING = YES +UNIXPATH = /tmp/test-service-fs-20 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +MAX_PENDING_REQUESTS = 65536 +MIN_MIGRATION_DELAY = 100 ms +EXPECTED_NEIGHBOUR_COUNT = 128 + +[vpn] +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-vpn +IPV6ADDR = 1234::1 +IPV6PREFIX = 32 +IPV4ADDR = 10.11.10.1 +IPV4MASK = 255.255.0.0 +VIRTDNS = 10.11.10.2 +VIRTDNS6 = 1234::17 +IFNAME = vpn-gnunet + +[exit] +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-exit +IPV6ADDR = 1234:1::1 +IPV6PREFIX = 32 +IPV4ADDR = 10.10.1.1 +IPV4MASK = 255.255.0.0 +IFNAME = exit-gnunet +ENABLE_UDP = NO +ENABLE_TCP = NO + +[dns] +AUTOSTART = YES +PORT = 0 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dns +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-dns-19 +PROVIDE_EXIT = NO + +[arm] +PORT = 20022 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-arm +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DEFAULTSERVICES = topology hostlist fs +UNIXPATH = /tmp/test-service-arm-18 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[hostlist] +HTTPPORT = 8080 +HOME = $SERVICEHOME +HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-hostlist +OPTIONS = -b +SERVERS = http://localhost:8080/ +HTTP-PROXY = + +[core] +AUTOSTART = YES +PORT = 20021 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-core +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-core-17 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[nat] +EXTERNAL_ADDRESS = 127.0.0.1 +INTERNAL_ADDRESS = 127.0.0.1 +BINDTO = 127.0.0.1 +BEHIND_NAT = NO +PUNCHED_NAT = NO +ENABLE_UPNP = NO +USE_LOCALADDR = YES +USE_HOSTNAME = NO +ENABLE_ICMP_CLIENT = NO +ENABLE_ICMP_SERVER = NO +DISABLEV6 = YES +RETURN_LOCAL_ADDRESSES = NO +HOSTNAME_DNS_FREQUENCY = 1200000 +IFC_SCAN_FREQUENCY = 3000000 +DYNDNS_FREQUENCY = 140000 + +[gnunet-nat-server] +HOSTNAME = gnunet.org +PORT = 20020 + +[statistics] +AUTOSTART = YES +PORT = 20019 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-statistics +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-statistics-16 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES + +[dht] +AUTOSTART = YES +PORT = 20018 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dht +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +BUCKET_SIZE = 4 +UNIXPATH = /tmp/test-service-dht-15 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[dhtcache] +DATABASE = sqlite +QUOTA = 1 MB + diff --git a/src/integration-tests/confs/c_no_nat_client_2.conf b/src/integration-tests/confs/c_no_nat_client_2.conf new file mode 100644 index 0000000..bd675d7 --- /dev/null +++ b/src/integration-tests/confs/c_no_nat_client_2.conf @@ -0,0 +1,344 @@ +[PATHS] +SERVICEHOME = /tmp/c_no_nat_client_2/ +DEFAULTCONFIG = confs/c_no_nat_client_2.conf + +[gnunetd] +#HOSTKEY = $SERVICEHOME/.hostkey +HOSTKEY = hostkeys/0002-hostkey + +[resolver] +AUTOSTART = YES +PORT = 20053 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-resolver +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-resolver-42 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = NO + +[mesh] +AUTOSTART = YES +PORT = 20052 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-mesh +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-mesh-41 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[nse] +AUTOSTART = YES +PORT = 20051 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-nse +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-nse-40 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +PROOFFILE = $SERVICEHOME/.nse-proof +HISTOGRAM = $SERVICEHOME/nse-history.log +WORKDELAY = 5 ms +INTERVAL = 1 h +WORKBITS = 26 + +[topology] +MINIMUM-FRIENDS = 0 +FRIENDS-ONLY = NO +AUTOCONNECT = YES +TARGET-CONNECTION-COUNT = 16 +FRIENDS = $SERVICEHOME/friends +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-topology + +[datastore] +AUTOSTART = YES +UNIXPATH = /tmp/test-service-datastore-39 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +PORT = 20050 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-datastore +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +QUOTA = 100 MB +BLOOMFILTER = $SERVICEHOME/fs/bloomfilter +DATABASE = sqlite + +[datastore-sqlite] +FILENAME = $SERVICEHOME/datastore/sqlite.db + +[datastore-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[datastore-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf + +[peerinfo] +AUTOSTART = YES +PORT = 20049 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-peerinfo +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-peerinfo-38 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +HOSTS = $SERVICEHOME/data/hosts/ + +[client] +HOME = $SERVICEHOME + +[TESTING] +WEAKRANDOM = NO +CONNECT_TIMEOUT = 30 s +CONNECT_ATTEMPTS = 3 +MAX_OUTSTANDING_CONNECTIONS = 50 +DELETE_FILES = YES + +[ats] +AUTOSTART = YES +PORT = 20048 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-ats +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-ats-37 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +WAN_QUOTA_IN = 65536 +WAN_QUOTA_OUT = 65536 +DUMP_MLP = NO +DUMP_SOLUTION = NO +DUMP_OVERWRITE = NO +DUMP_MIN_PEERS = 0 +DUMP_MIN_ADDRS = 0 +ATS_MIN_INTERVAL = 15000 +ATS_EXEC_INTERVAL = 30000 + +[transport] +AUTOSTART = YES +PORT = 20047 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-transport +NEIGHBOUR_LIMIT = 50 +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +PLUGINS = tcp +UNIXPATH = /tmp/test-service-transport-36 +BLACKLIST_FILE = $SERVICEHOME/blacklist +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[transport-tcp] +PORT = 20046 +ADVERTISED_PORT = 20046 +MAX_CONNECTIONS = 128 +TIMEOUT = 5 s +USE_LOCALADDR = YES + +[transport-udp] +PORT = 20045 +BROADCAST = YES +BROADCAST_INTERVAL = 30000 +MAX_BPS = 1000000 +USE_LOCALADDR = YES + +[transport-http] +PORT = 20044 +MAX_CONNECTIONS = 128 + +[transport-https] +PORT = 20043 +CRYPTO_INIT = NORMAL +KEY_FILE = https.key +CERT_FILE = https.cert +MAX_CONNECTIONS = 128 + +[transport-wlan] +INTERFACE = mon0 +TESTMODE = 0 + +[datacache-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf + +[datacache-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[template] +AUTOSTART = NO +PORT = 20042 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-template +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-template-35 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[fs] +AUTOSTART = YES +INDEXDB = $SERVICEHOME/idxinfo.lst +TRUST = $SERVICEHOME/data/credit/ +IDENTITY_DIR = $SERVICEHOME/identities/ +STATE_DIR = $SERVICEHOME/persistence/ +UPDATE_DIR = $SERVICEHOME/updates/ +PORT = 20041 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-fs +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DELAY = YES +CONTENT_CACHING = YES +CONTENT_PUSHING = YES +UNIXPATH = /tmp/test-service-fs-34 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +MAX_PENDING_REQUESTS = 65536 +MIN_MIGRATION_DELAY = 100 ms +EXPECTED_NEIGHBOUR_COUNT = 128 + +[vpn] +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-vpn +IPV6ADDR = 1234::1 +IPV6PREFIX = 32 +IPV4ADDR = 10.11.10.1 +IPV4MASK = 255.255.0.0 +VIRTDNS = 10.11.10.2 +VIRTDNS6 = 1234::17 +IFNAME = vpn-gnunet + +[exit] +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-exit +IPV6ADDR = 1234:1::1 +IPV6PREFIX = 32 +IPV4ADDR = 10.10.1.1 +IPV4MASK = 255.255.0.0 +IFNAME = exit-gnunet +ENABLE_UDP = NO +ENABLE_TCP = NO + +[dns] +AUTOSTART = YES +PORT = 0 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dns +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-dns-33 +PROVIDE_EXIT = NO + +[arm] +PORT = 20040 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-arm +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DEFAULTSERVICES = topology hostlist fs +UNIXPATH = /tmp/test-service-arm-32 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[hostlist] +HTTPPORT = 8080 +HOME = $SERVICEHOME +HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-hostlist +OPTIONS = -b +SERVERS = http://localhost:8080/ +HTTP-PROXY = + +[core] +AUTOSTART = YES +PORT = 20039 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-core +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-core-31 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[nat] +BEHIND_NAT = NO +PUNCHED_NAT = NO +ENABLE_UPNP = NO +USE_LOCALADDR = YES +USE_HOSTNAME = NO +ENABLE_ICMP_CLIENT = NO +ENABLE_ICMP_SERVER = NO +DISABLEV6 = YES +RETURN_LOCAL_ADDRESSES = NO +HOSTNAME_DNS_FREQUENCY = 1200000 +IFC_SCAN_FREQUENCY = 3000000 +DYNDNS_FREQUENCY = 140000 +EXTERNAL_ADDRESS = 127.0.0.1 +INTERNAL_ADDRESS = 127.0.0.1 +BINDTO = 127.0.0.1 + +[gnunet-nat-server] +HOSTNAME = gnunet.org +PORT = 20038 + +[statistics] +AUTOSTART = YES +PORT = 20037 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-statistics +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-service-statistics-30 +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES + +[dht] +AUTOSTART = YES +PORT = 20036 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-dht +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +BUCKET_SIZE = 4 +UNIXPATH = /tmp/test-service-dht-29 +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +[dhtcache] +DATABASE = sqlite +QUOTA = 1 MB + diff --git a/src/integration-tests/gnunet_pyexpect.py.in b/src/integration-tests/gnunet_pyexpect.py.in new file mode 100644 index 0000000..9e5c83f --- /dev/null +++ b/src/integration-tests/gnunet_pyexpect.py.in @@ -0,0 +1,83 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Testcase for gnunet-peerinfo +from __future__ import print_function +import os +import re +import subprocess +import sys +import shutil +import time + +class pexpect (object): + def __init__ (self): + super (pexpect, self).__init__ () + + def spawn (self, stdin, arglist, *pargs, **kwargs): + env = kwargs.pop ('env', None) + if env is None: + env = os.environ.copy () + # This messes up some testcases, disable log redirection + env.pop ('GNUNET_FORCE_LOGFILE', None) + self.proc = subprocess.Popen (arglist, *pargs, env=env, **kwargs) + if self.proc is None: + print ("Failed to spawn a process {0}".format (arglist)) + sys.exit (1) + if stdin is not None: + self.stdo, self.stde = self.proc.communicate (stdin) + else: + self.stdo, self.stde = self.proc.communicate () + return self.proc + + def expect (self, s, r, flags=0): + stream = self.stdo if s == 'stdout' else self.stde + if isinstance (r, str): + if r == "EOF": + if len (stream) == 0: + return True + else: + print ("Failed to find `{1}' in {0}, which is `{2}' ({3})".format (s, r, stream, len (stream))) + sys.exit (2) + raise ValueError ("Argument `r' should be an instance of re.RegexObject or a special string, but is `{0}'".format (r)) + m = r.search (stream, flags) + if not m: + print ("Failed to find `{1}' in {0}, which is is `{2}'".format (s, r.pattern, stream)) + sys.exit (2) + stream = stream[m.end ():] + if s == 'stdout': + self.stdo = stream + else: + self.stde = stream + return m + + def read (self, s, size=-1): + stream = self.stdo if s == 'stdout' else self.stde + result = "" + if size < 0: + result = stream + new_stream = "" + else: + result = stream[0:size] + new_stream = stream[size:] + if s == 'stdout': + self.stdo = new_stream + else: + self.stde = new_stream + return result diff --git a/src/integration-tests/gnunet_testing.py.in b/src/integration-tests/gnunet_testing.py.in new file mode 100644 index 0000000..79cbfe9 --- /dev/null +++ b/src/integration-tests/gnunet_testing.py.in @@ -0,0 +1,232 @@ +#!/usr/bin/python +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Functions for integration testing +import os +import subprocess +import sys +import shutil +import time +from gnunet_pyexpect import pexpect + +class Check: + def __init__(self, test): + self.fulfilled = False + self.conditions = list() + self.test = test + def add (self, condition): + self.conditions.append(condition) + def run (self): + fulfilled = True + pos = 0 + neg = 0 + for c in self.conditions: + if (False == c.check ()): + fulfilled = False + neg += 1 + else: + pos += 1 + self.test.p (str(pos) +' out of '+ str (pos+neg) + ' conditions fulfilled') + return fulfilled + def run_blocking (self, timeout, pos_cont, neg_cont): + execs = 0; + res = False + while ((False == res) and (execs < timeout)): + res = self.run() + time.sleep(1) + execs += 1 + if (res == False): + neg_cont (self) + else: + pos_cont (self) + def evaluate (self, failed_only): + pos = 0 + neg = 0 + for c in self.conditions: + if (False == c.evaluate (failed_only)): + neg += 1 + else: + pos += 1 + print (str(pos) +' out of '+ str (pos+neg) + ' conditions fulfilled') + return self.fulfilled + +class Condition: + def __init__(self): + self.fulfilled = False + self.type = 'generic' + def __init__(self, type): + self.fulfilled = False + self.type = type + def check(self): + return False; + def evaluate (self, failed_only): + if ((self.fulfilled == False) and (failed_only == True)): + print str(self.type) + 'condition for was ' + str(self.fulfilled) + elif (failed_only == False): + print str(self.type) + 'condition for was ' + str(self.fulfilled) + return self.fulfilled + +class FileExistCondition (Condition): + def __init__(self, file): + self.fulfilled = False + self.type = 'file' + self.file = file + def check(self): + if (self.fulfilled == False): + res = os.path.isfile(self.file) + if (res == True): + self.fulfilled = True + return True + else: + return False + else: + return True + def evaluate (self, failed_only): + if ((self.fulfilled == False) and (failed_only == True)): + print str(self.type) + 'condition for file '+self.file+' was ' + str(self.fulfilled) + elif (failed_only == False): + print str(self.type) + 'condition for file '+self.file+' was ' + str(self.fulfilled) + return self.fulfilled + +class StatisticsCondition (Condition): + def __init__(self, peer, subsystem, name, value): + self.fulfilled = False + self.type = 'statistics' + self.peer = peer; + self.subsystem = subsystem; + self.name = name; + self.value = value; + self.result = -1; + def check(self): + if (self.fulfilled == False): + self.result = self.peer.get_statistics_value (self.subsystem, self.name); + if (str(self.result) == str(self.value)): + self.fulfilled = True + return True + else: + return False + else: + return True + def evaluate (self, failed_only): + if (self.result == -1): + res = 'NaN' + else: + res = str(self.result) + if (self.fulfilled == False): + fail = " FAIL!" + op = " != " + else: + fail = "" + op = " == " + if ((self.fulfilled == False) and (failed_only == True)): + print self.peer.id[:4] + " " +self.peer.cfg + " " + str(self.type) + ' condition in subsystem "' + self.subsystem.ljust(12) +'" : "' + self.name.ljust(30) +'" : (expected/real value) ' + str(self.value) + op + res + fail + elif (failed_only == False): + print self.peer.id[:4] + " " +self.peer.cfg + " " + str(self.type) + ' condition in subsystem "' + self.subsystem.ljust(12) +'" : "' + self.name.ljust(30) +'" : (expected/real value) ' + str(self.value) + op + res + fail + return self.fulfilled + +class Test: + def __init__(self, testname, verbose): + self.peers = list() + self.verbose = verbose; + self.name = testname; + srcdir = "../.." + gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") + if gnunet_pyexpect_dir not in sys.path: + sys.path.append (gnunet_pyexpect_dir) + self.gnunetarm = '' + self.gnunetstatistics = '' + if os.name == 'posix': + self.gnunetarm = 'gnunet-arm' + self.gnunetstatistics = 'gnunet-statistics' + self.gnunetpeerinfo = 'gnunet-peerinfo' + elif os.name == 'nt': + self.gnunetarm = 'gnunet-arm.exe' + self.gnunetstatistics = 'gnunet-statistics.exe' + self.gnunetpeerinfo = 'gnunet-peerinfo.exe' + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), testname), True) + else: + shutil.rmtree ("/tmp/" + testname, True) + def add_peer (self, peer): + self.peers.append(peer) + def p (self, msg): + if (self.verbose == True): + print msg + +class Peer: + def __init__(self, test, cfg_file): + if (False == os.path.isfile(cfg_file)): + print ("Peer cfg " + cfg_file + ": FILE NOT FOUND") + self.id = "" + self.test = test + self.started = False + self.cfg = cfg_file + def __del__(self): + if (self.started == True): + print 'ERROR! Peer using cfg ' + self.cfg + ' was not stopped' + ret = self.stop () + if (False == ret): + print 'ERROR! Peer using cfg ' + self.cfg + ' could not be stopped' + self.started = False + return ret + else: + return False + def start (self): + self.test.p ("Starting peer using cfg " + self.cfg) + try: + server = subprocess.Popen ([self.test.gnunetarm, '-sq', '-c', self.cfg]) + server.communicate () + except OSError: + print "Can not start peer" + self.started = False + return False + self.started = True; + test = '' + try: + server = pexpect () + server.spawn (None, [self.test.gnunetpeerinfo, '-c', self.cfg ,'-s'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + test = server.read("stdout", 1024) + except OSError: + print "Can not get peer identity" + test = (test.split('`')[1]) + self.id = test.split('\'')[0] + return True + def stop (self): + if (self.started == False): + return False + self.test.p ("Stopping peer using cfg " + self.cfg) + try: + server = subprocess.Popen ([self.test.gnunetarm, '-eq', '-c', self.cfg]) + server.communicate () + except OSError: + print "Can not stop peer" + return False + self.started = False + return True; + def get_statistics_value (self, subsystem, name): + server = pexpect () + server.spawn (None, [self.test.gnunetstatistics, '-c', self.cfg ,'-q','-n', name, '-s', subsystem ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + #server.expect ("stdout", re.compile (r"")) + test = server.read("stdout", 10240) + tests = test.partition('\n')[0] + if (tests.isdigit() == True): + return tests + else: + return -1 + \ No newline at end of file diff --git a/src/integration-tests/hostkeys/0000-hostkey b/src/integration-tests/hostkeys/0000-hostkey new file mode 100644 index 0000000..c3c2123 Binary files /dev/null and b/src/integration-tests/hostkeys/0000-hostkey differ diff --git a/src/integration-tests/hostkeys/0001-hostkey b/src/integration-tests/hostkeys/0001-hostkey new file mode 100644 index 0000000..871fc90 Binary files /dev/null and b/src/integration-tests/hostkeys/0001-hostkey differ diff --git a/src/integration-tests/hostkeys/0002-hostkey b/src/integration-tests/hostkeys/0002-hostkey new file mode 100644 index 0000000..2ffb55f Binary files /dev/null and b/src/integration-tests/hostkeys/0002-hostkey differ diff --git a/src/integration-tests/hostkeys/0003-hostkey b/src/integration-tests/hostkeys/0003-hostkey new file mode 100644 index 0000000..13bc889 Binary files /dev/null and b/src/integration-tests/hostkeys/0003-hostkey differ diff --git a/src/integration-tests/hostkeys/0004-hostkey b/src/integration-tests/hostkeys/0004-hostkey new file mode 100644 index 0000000..a15a073 Binary files /dev/null and b/src/integration-tests/hostkeys/0004-hostkey differ diff --git a/src/integration-tests/hostkeys/0005-hostkey b/src/integration-tests/hostkeys/0005-hostkey new file mode 100644 index 0000000..4bcfffe Binary files /dev/null and b/src/integration-tests/hostkeys/0005-hostkey differ diff --git a/src/integration-tests/hostkeys/0006-hostkey b/src/integration-tests/hostkeys/0006-hostkey new file mode 100644 index 0000000..c595d91 Binary files /dev/null and b/src/integration-tests/hostkeys/0006-hostkey differ diff --git a/src/integration-tests/hostkeys/0007-hostkey b/src/integration-tests/hostkeys/0007-hostkey new file mode 100644 index 0000000..f7e9dbc Binary files /dev/null and b/src/integration-tests/hostkeys/0007-hostkey differ diff --git a/src/integration-tests/hostkeys/0008-hostkey b/src/integration-tests/hostkeys/0008-hostkey new file mode 100644 index 0000000..559a69c Binary files /dev/null and b/src/integration-tests/hostkeys/0008-hostkey differ diff --git a/src/integration-tests/hostkeys/0009-hostkey b/src/integration-tests/hostkeys/0009-hostkey new file mode 100644 index 0000000..7d8ce5e Binary files /dev/null and b/src/integration-tests/hostkeys/0009-hostkey differ diff --git a/src/integration-tests/test_integration_bootstrap_and_connect.py.in b/src/integration-tests/test_integration_bootstrap_and_connect.py.in new file mode 100755 index 0000000..32995d2 --- /dev/null +++ b/src/integration-tests/test_integration_bootstrap_and_connect.py.in @@ -0,0 +1,135 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# +import sys +import os +import subprocess +import re +import shutil +import time +import pexpect +from gnunet_testing import Peer +from gnunet_testing import Test +from gnunet_testing import Check +from gnunet_testing import Condition +from gnunet_testing import * + + +# +# This test tests if a fresh peer bootstraps from a hostlist server and then +# successfully connects to the server +# +# Conditions for successful exit: +# Both peers have 1 connected peer in transport, core, topology, fs + +# +# This test tests if a fresh peer bootstraps from a hostlist server and then +# successfully connects to the server +# +# Conditions for successful exit: +# Both peers have 1 connected peer in transport, core, topology, fs + +#definitions + +testname = "test_integration_bootstrap_and_connect" +verbose = True +check_timeout = 30 + + +def cleanup (): + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) + else: + shutil.rmtree ("/tmp/c_bootstrap_server/", True) + shutil.rmtree ("/tmp/c_no_nat_client/", True) + +def success_cont (check): + global success + success = True; + +def fail_cont (check): + global success + success = False; + check.evaluate(True) + +def check (): + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) + + + check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (server, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) + + check.run_blocking (check_timeout, success_cont, fail_cont) + +# +# Test execution +# + +def run (): + global success + global test + global server + global client + + success = False + test = Test ('test_integration_bootstrap_and_connect.py', verbose) + + server = Peer(test, './confs/c_bootstrap_server.conf'); + client = Peer(test, './confs/c_no_nat_client.conf'); + + assert (True == server.start()); + assert (True == client.start()); + + if ((client.started == True) and (server.started == True)): + test.p ('Peers started, running check') + time.sleep(5) + check () + server.stop () + client.stop () + + cleanup () + + if (success == False): + print ('Test failed') + return False + else: + return True + +try: + run () +except (KeyboardInterrupt, SystemExit): + print 'Test interrupted' + server.stop () + client.stop () + cleanup () +if (success == False): + sys.exit(1) +else: + sys.exit(0) + \ No newline at end of file diff --git a/src/integration-tests/test_integration_bootstrap_and_connect_and_disconnect.py.in b/src/integration-tests/test_integration_bootstrap_and_connect_and_disconnect.py.in new file mode 100755 index 0000000..b426182 --- /dev/null +++ b/src/integration-tests/test_integration_bootstrap_and_connect_and_disconnect.py.in @@ -0,0 +1,147 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# +import sys +import os +import subprocess +import re +import shutil +import time +import pexpect +from gnunet_testing import Peer +from gnunet_testing import Test +from gnunet_testing import Check +from gnunet_testing import Condition +from gnunet_testing import * + + +# +# This test tests if a fresh peer bootstraps from a hostlist server and then +# successfully connects to the server +# +# Conditions for successful exit: +# Both peers have 1 connected peer in transport, core, topology, fs + +# +# This test tests if a fresh peer bootstraps from a hostlist server and then +# successfully connects to the server +# +# Conditions for successful exit: +# Both peers have 1 connected peer in transport, core, topology, fs + +#definitions + +testname = "test_integration_bootstrap_and_connect" +verbose = True +check_timeout = 30 + + +def cleanup (): + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) + else: + shutil.rmtree ("/tmp/c_bootstrap_server/", True) + shutil.rmtree ("/tmp/c_no_nat_client/", True) + +def success_server_stop_cont (check): + global success + success = True; + +def success_cont (check): + server.stop() + + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',0)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',0)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',0)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',0)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',0)) + + check.run_blocking (check_timeout, success_server_stop_cont, fail_cont) + +def fail_cont (check): + global success + success = False; + check.evaluate(True) + +def check (): + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) + + + check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (server, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) + + check.run_blocking (check_timeout, success_cont, fail_cont) + +# +# Test execution +# + +def run (): + global success + global test + global server + global client + + success = False + test = Test ('test_integration_bootstrap_and_connect.py', verbose) + + server = Peer(test, './confs/c_bootstrap_server.conf'); + client = Peer(test, './confs/c_no_nat_client.conf'); + + assert (True == server.start()); + assert (True == client.start()); + + if ((client.started == True) and (server.started == True)): + test.p ('Peers started, running check') + time.sleep(5) + check () + server.stop () + client.stop () + + cleanup () + + if (success == False): + print ('Test failed') + return False + else: + return True + +try: + run () +except (KeyboardInterrupt, SystemExit): + print 'Test interrupted' + server.stop () + client.stop () + cleanup () +if (success == False): + sys.exit(1) +else: + sys.exit(0) + \ No newline at end of file diff --git a/src/integration-tests/test_integration_bootstrap_and_connect_and_disconnect_nat.py.in b/src/integration-tests/test_integration_bootstrap_and_connect_and_disconnect_nat.py.in new file mode 100755 index 0000000..f055e79 --- /dev/null +++ b/src/integration-tests/test_integration_bootstrap_and_connect_and_disconnect_nat.py.in @@ -0,0 +1,147 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# +import sys +import os +import subprocess +import re +import shutil +import time +import pexpect +from gnunet_testing import Peer +from gnunet_testing import Test +from gnunet_testing import Check +from gnunet_testing import Condition +from gnunet_testing import * + + +# +# This test tests if a fresh peer bootstraps from a hostlist server and then +# successfully connects to the server +# +# Conditions for successful exit: +# Both peers have 1 connected peer in transport, core, topology, fs + +# +# This test tests if a fresh peer bootstraps from a hostlist server and then +# successfully connects to the server +# +# Conditions for successful exit: +# Both peers have 1 connected peer in transport, core, topology, fs + +#definitions + +testname = "test_integration_bootstrap_and_connect" +verbose = True +check_timeout = 30 + + +def cleanup (): + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) + else: + shutil.rmtree ("/tmp/c_bootstrap_server/", True) + shutil.rmtree ("/tmp/c_no_nat_client/", True) + +def success_server_stop_cont (check): + global success + success = True; + +def success_cont (check): + server.stop() + + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',0)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',0)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',0)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',0)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',0)) + + check.run_blocking (check_timeout, success_server_stop_cont, fail_cont) + +def fail_cont (check): + global success + success = False; + check.evaluate(True) + +def check (): + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) + + + check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (server, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) + + check.run_blocking (check_timeout, success_cont, fail_cont) + +# +# Test execution +# + +def run (): + global success + global test + global server + global client + + success = False + test = Test ('test_integration_bootstrap_and_connect.py', verbose) + + server = Peer(test, './confs/c_bootstrap_server.conf'); + client = Peer(test, './confs/c_nat_client.conf'); + + assert (True == server.start()); + assert (True == client.start()); + + if ((client.started == True) and (server.started == True)): + test.p ('Peers started, running check') + time.sleep(5) + check () + server.stop () + client.stop () + + cleanup () + + if (success == False): + print ('Test failed') + return False + else: + return True + +try: + run () +except (KeyboardInterrupt, SystemExit): + print 'Test interrupted' + server.stop () + client.stop () + cleanup () +if (success == False): + sys.exit(1) +else: + sys.exit(0) + \ No newline at end of file diff --git a/src/integration-tests/test_integration_clique.py.in b/src/integration-tests/test_integration_clique.py.in new file mode 100755 index 0000000..49a2c59 --- /dev/null +++ b/src/integration-tests/test_integration_clique.py.in @@ -0,0 +1,197 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# +# +# This test starts 3 peers and expects bootstrap and a connected clique +# +# Conditions for successful exit: +# Both peers have 1 connected peer in transport, core, topology, fs + +import sys +import os +import subprocess +import re +import shutil +import time +import pexpect +from gnunet_testing import Peer +from gnunet_testing import Test +from gnunet_testing import Check +from gnunet_testing import Condition +from gnunet_testing import * + + +#definitions + +testname = "test_integration_clique" +verbose = True +check_timeout = 30 + + +def cleanup (): + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client_2"), True) + else: + shutil.rmtree ("/tmp/c_bootstrap_server/", True) + shutil.rmtree ("/tmp/c_no_nat_client/", True) + shutil.rmtree ("/tmp/c_no_nat_client_2/", True) + + +def success_cont (check): + global success + success = True; + +def fail_cont (check): + global success + success= False; + check.evaluate(True) + + +def check_disconnect_client (): + test.p ('Shutting down bootstrap client') + client.stop () + check = Check (test) + + check.add (StatisticsCondition (client2, 'transport', '# peers connected',0)) + check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',0)) + check.add (StatisticsCondition (client2, 'core', '# entries in session map',0)) + check.add (StatisticsCondition (client2, 'topology', '# peers connected',0)) + check.add (StatisticsCondition (client2, 'fs', '# peers connected',0)) + + check.run_blocking (check_timeout, success_cont, fail_cont) + + +def success_disconnect_server_cont (check): + check_disconnect_client () + + +def fail_disconnect_server_cont (check): + global success + success= False; + check.evaluate(True) + + +def check_disconnect_server (): + test.p ('Shutting down bootstrap server') + server.stop () + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) + + check.add (StatisticsCondition (client2, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (client2, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (client2, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (client2, 'fs', '# peers connected',1)) + + check.run_blocking (check_timeout, success_disconnect_server_cont, fail_disconnect_server_cont) + + +def success_connect_cont (check): + check_disconnect_server () + + +def fail_connect_cont (check): + global success + success= False; + check.evaluate(True) + + +def check_connect (): + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',2)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',2)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',2)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',2)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',2)) + + check.add (StatisticsCondition (client2, 'transport', '# peers connected',2)) + check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',2)) + check.add (StatisticsCondition (client2, 'core', '# entries in session map',2)) + check.add (StatisticsCondition (client2, 'topology', '# peers connected',2)) + check.add (StatisticsCondition (client2, 'fs', '# peers connected',2)) + + check.add (StatisticsCondition (server, 'transport', '# peers connected',2)) + check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',2)) + check.add (StatisticsCondition (server, 'core', '# entries in session map',2)) + check.add (StatisticsCondition (server, 'topology', '# peers connected',2)) + check.add (StatisticsCondition (server, 'fs', '# peers connected',2)) + + check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) + +# +# Test execution +# +def run (): + global success + global test + global server + global client + global client2 + + success = False + + test = Test ('test_integration_disconnect', verbose) + + server = Peer(test, './confs/c_bootstrap_server.conf'); + server.start(); + + client = Peer(test, './confs/c_no_nat_client.conf'); + client.start(); + + client2 = Peer(test, './confs/c_no_nat_client_2.conf'); + client2.start(); + + if ((client.started == True) and (client2.started == True) and (server.started == True)): + test.p ('Peers started, running check') + check_connect () + + server.stop () + client.stop () + client2.stop () + + cleanup () + + if (success == False): + print ('Test failed') + return False + else: + return True + + +try: + run () +except (KeyboardInterrupt, SystemExit): + print 'Test interrupted' + server.stop () + client.stop () + client2.stop () + cleanup () +if (success == False): + sys.exit(1) +else: + sys.exit(0) + + diff --git a/src/integration-tests/test_integration_clique_nat.py.in b/src/integration-tests/test_integration_clique_nat.py.in new file mode 100755 index 0000000..e8f7719 --- /dev/null +++ b/src/integration-tests/test_integration_clique_nat.py.in @@ -0,0 +1,197 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# +# +# This test starts 3 peers (1 bootstrap server, 1 not nat'ed peer, 1 nat'ed peer) +# and expects bootstrap and a connected clique +# +# Conditions for successful exit: +# Both peers have 1 connected peer in transport, core, topology, fs + +import sys +import os +import subprocess +import re +import shutil +import time +import pexpect +from gnunet_testing import Peer +from gnunet_testing import Test +from gnunet_testing import Check +from gnunet_testing import Condition +from gnunet_testing import * + + +#definitions +testname = "test_integration_clique_nat" +verbose = True +check_timeout = 30 + + +def cleanup (): + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_bootstrap_server"), True) + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_nat_client"), True) + else: + shutil.rmtree ("/tmp/c_bootstrap_server/", True) + shutil.rmtree ("/tmp/c_no_nat_client/", True) + shutil.rmtree ("/tmp/c_nat_client/", True) + + +def success_cont (check): + global success + success = True; + +def fail_cont (check): + global success + success= False; + check.evaluate(True) + + +def check_disconnect_client (): + test.p ('Shutting down bootstrap client') + client.stop () + check = Check (test) + + check.add (StatisticsCondition (client2, 'transport', '# peers connected',0)) + check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',0)) + check.add (StatisticsCondition (client2, 'core', '# entries in session map',0)) + check.add (StatisticsCondition (client2, 'topology', '# peers connected',0)) + check.add (StatisticsCondition (client2, 'fs', '# peers connected',0)) + + check.run_blocking (check_timeout, success_cont, fail_cont) + + +def success_disconnect_server_cont (check): + check_disconnect_client () + + +def fail_disconnect_server_cont (check): + global success + success= False; + check.evaluate(False) + + +def check_disconnect_server (): + test.p ('Shutting down bootstrap server') + server.stop () + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) + + check.add (StatisticsCondition (client2, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (client2, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (client2, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (client2, 'fs', '# peers connected',1)) + + check.run_blocking (check_timeout, success_disconnect_server_cont, fail_disconnect_server_cont) + + +def success_connect_cont (check): + check_disconnect_server () + + +def fail_connect_cont (check): + global success + success= False; + check.evaluate(False) + + +def check_connect (): + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',2)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',2)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',2)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',2)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',2)) + + check.add (StatisticsCondition (client2, 'transport', '# peers connected',2)) + check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',2)) + check.add (StatisticsCondition (client2, 'core', '# entries in session map',2)) + check.add (StatisticsCondition (client2, 'topology', '# peers connected',2)) + check.add (StatisticsCondition (client2, 'fs', '# peers connected',2)) + + check.add (StatisticsCondition (server, 'transport', '# peers connected',2)) + check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',2)) + check.add (StatisticsCondition (server, 'core', '# entries in session map',2)) + check.add (StatisticsCondition (server, 'topology', '# peers connected',2)) + check.add (StatisticsCondition (server, 'fs', '# peers connected',2)) + + check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) + +# +# Test execution +# +def run (): + global success + global test + global server + global client + global client2 + + success = False + + test = Test ('test_integration_disconnect', verbose) + + server = Peer(test, './confs/c_bootstrap_server.conf'); + server.start(); + + client = Peer(test, './confs/c_no_nat_client.conf'); + client.start(); + + client2 = Peer(test, './confs/c_nat_client.conf'); + client2.start(); + + if ((client.started == True) and (client2.started == True) and (server.started == True)): + test.p ('Peers started, running check') + check_connect () + + server.stop () + client.stop () + client2.stop () + + cleanup () + + if (success == False): + print ('Test failed') + return False + else: + return True + + +try: + run () +except (KeyboardInterrupt, SystemExit): + print 'Test interrupted' + server.stop () + client.stop () + client2.stop () + cleanup () +if (success == False): + sys.exit(1) +else: + sys.exit(0) + + diff --git a/src/integration-tests/test_integration_disconnect.py.in b/src/integration-tests/test_integration_disconnect.py.in new file mode 100755 index 0000000..5e137cf --- /dev/null +++ b/src/integration-tests/test_integration_disconnect.py.in @@ -0,0 +1,156 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# +import sys +import os +import subprocess +import re +import shutil +import time +import pexpect +from gnunet_testing import Peer +from gnunet_testing import Test +from gnunet_testing import Check +from gnunet_testing import Condition +from gnunet_testing import * + + +# +# This test tests if a fresh peer bootstraps from a hostlist server and then +# successfully connects to the server. When both peers are connected +# in transport, core, topology, fs, the server is shutdown +# +# Conditions for successful exit: +# Both peers have 0 connected peer in transport, core, topology, fs + +#definitions + +testname = "test_integration_disconnect" +verbose = True +check_timeout = 30 + + +def cleanup (): + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_bootstrap_server"), True) + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) + else: + shutil.rmtree ("/tmp/c_bootstrap_server/", True) + shutil.rmtree ("/tmp/c_no_nat_client/", True) + + +def success_disconnect_cont (check): + global success + success = True; + + +def fail_disconnect_cont (check): + global success + success = False; + check.evaluate(True) + + +def check_disconnect (): + test.p ('Shutting down bootstrap server') + server.stop () + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',0)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',0)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',0)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',0)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',0)) + check.run_blocking (check_timeout, success_disconnect_cont, fail_disconnect_cont) + + +def success_connect_cont (check): + check_disconnect () + + +def fail_connect_cont (check): + global success + success= False; + check.evaluate(True) + + +def check_connect (): + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) + + check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (server, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) + + check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) + +# +# Test execution +# + +def run (): + global success + global test + global server + global client + + success = False + + test = Test ('test_integration_disconnect', verbose) + + server = Peer(test, './confs/c_bootstrap_server.conf'); + server.start(); + + client = Peer(test, './confs/c_no_nat_client.conf'); + client.start(); + + + if ((client.started == True) and (server.started == True)): + test.p ('Peers started, running check') + check_connect () + + server.stop () + client.stop () + + cleanup () + + if (success == False): + print ('Test failed') + return True + else: + return False + + +try: + run () +except (KeyboardInterrupt, SystemExit): + print 'Test interrupted' + server.stop () + client.stop () + cleanup () +if (success == False): + sys.exit(1) +else: + sys.exit(0) + \ No newline at end of file diff --git a/src/integration-tests/test_integration_restart.py.in b/src/integration-tests/test_integration_restart.py.in new file mode 100755 index 0000000..e2a72e7 --- /dev/null +++ b/src/integration-tests/test_integration_restart.py.in @@ -0,0 +1,171 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# +import sys +import os +import subprocess +import re +import shutil +import time +import pexpect +from gnunet_testing import Peer +from gnunet_testing import Test +from gnunet_testing import Check +from gnunet_testing import Condition +from gnunet_testing import * + + +# +# This test tests if a fresh peer bootstraps from a hostlist server and then +# successfully connects to the server. When both peers are connected +# in transport, core, topology, fs, botth peers are shutdown and restarted +# +# Conditions for successful exit: +# Both peers have 1 connected peer in transport, core, topology, fs after restart + +#definitions + + +testname = "test_integration_restart" +verbose = False +check_timeout = 30 + + +def cleanup (): + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) + else: + shutil.rmtree ("/tmp/c_bootstrap_server/", True) + shutil.rmtree ("/tmp/c_no_nat_client/", True) + + +def success_restart_cont (check): + global success + test.p ('Shutting down client & server') + server.stop () + client.stop () + success = True; + + +def fail_restart_cont (check): + global success + success = False; + check.evaluate(True) + + +def success_connect_cont (check): + test.p ('Shutting down client & server for restart') + server.stop () + client.stop () + + time.sleep(5) + + test.p ('Restarting client & server') + server.start () + client.start () + + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) + + check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (server, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) + + check.run_blocking (check_timeout, success_restart_cont, fail_restart_cont) + + +def fail_connect_cont (check): + global success + success= False; + check.evaluate(True) + + +def check_connect (): + check = Check (test) + check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (client, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) + + check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) + check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) + check.add (StatisticsCondition (server, 'core', '# entries in session map',1)) + check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) + check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) + + check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) + +# +# Test execution +# + +def run (): + global success + global test + global server + global client + + success = False + + test = Test ('test_integration_disconnect', verbose) + + server = Peer(test, './confs/c_bootstrap_server.conf'); + server.start(); + + client = Peer(test, './confs/c_no_nat_client.conf'); + client.start(); + + + if ((client.started == True) and (server.started == True)): + test.p ('Peers started, running check') + check_connect () + + server.stop () + client.stop () + + cleanup () + + if (success == False): + print ('Test failed') + return True + else: + return False + + +try: + run () +except (KeyboardInterrupt, SystemExit): + print 'Test interrupted' + server.stop () + client.stop () + cleanup () +if (success == False): + sys.exit(1) +else: + sys.exit(0) + \ No newline at end of file diff --git a/src/mesh/Makefile.am b/src/mesh/Makefile.am new file mode 100644 index 0000000..e9c0109 --- /dev/null +++ b/src/mesh/Makefile.am @@ -0,0 +1,142 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + mesh.conf + +AM_CLFAGS = -g + +bin_PROGRAMS = \ + gnunet-service-mesh + +lib_LTLIBRARIES = \ + libgnunetmesh.la + +gnunet_service_mesh_SOURCES = \ + gnunet-service-mesh.c \ + mesh_tunnel_tree.c mesh_tunnel_tree.h +gnunet_service_mesh_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la\ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/util/libgnunetutil.la + gnunet_service_mesh_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la\ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunetmesh_la_SOURCES = \ + mesh_api.c mesh.h mesh_protocol.h +libgnunetmesh_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(XLIB) +libgnunetmesh_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +check_PROGRAMS = \ + test_mesh_api \ + test_mesh_tree_api \ + test_mesh_local_1 \ + test_mesh_local_2 \ + test_mesh_2dtorus \ + test_mesh_small_unicast \ + test_mesh_small_multicast \ + test_mesh_small_speed \ + test_mesh_small_speed_ack + +test_mesh_api_SOURCES = \ + test_mesh_api.c +test_mesh_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la +test_mesh_api_DEPENDENCIES = \ + libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_mesh_tree_api_SOURCES = \ + test_mesh_tree_api.c +test_mesh_tree_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/dht/libgnunetdht.la +test_mesh_tree_api_DEPENDENCIES = \ + libgnunetmesh.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_mesh_local_1_SOURCES = \ + test_mesh_local_1.c +test_mesh_local_1_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la +test_mesh_local_1_DEPENDENCIES = \ + libgnunetmesh.la + +test_mesh_local_2_SOURCES = \ + test_mesh_local_2.c +test_mesh_local_2_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la +test_mesh_local_2_DEPENDENCIES = \ + libgnunetmesh.la + +test_mesh_2dtorus_SOURCES = \ + test_mesh_2dtorus.c +test_mesh_2dtorus_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_mesh_small_unicast_SOURCES = \ + test_mesh_small.c +test_mesh_small_unicast_LDADD = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_mesh_small_unicast_DEPENDENCIES = \ + libgnunetmesh.la + +test_mesh_small_multicast_SOURCES = \ + test_mesh_small.c +test_mesh_small_multicast_LDADD = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_mesh_small_multicast_DEPENDENCIES = \ + libgnunetmesh.la + +test_mesh_small_speed_SOURCES = \ + test_mesh_small.c +test_mesh_small_speed_LDADD = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_mesh_small_speed_DEPENDENCIES = \ + libgnunetmesh.la + +test_mesh_small_speed_ack_SOURCES = \ + test_mesh_small.c +test_mesh_small_speed_ack_LDADD = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_mesh_small_speed_ack_DEPENDENCIES = \ + libgnunetmesh.la + +if ENABLE_TEST_RUN +TESTS = test_mesh_api test_mesh_tree_api test_mesh_local_1 test_mesh_local_2 \ + test_mesh_2dtorus test_mesh_small_unicast test_mesh_small_multicast +endif + +EXTRA_DIST = \ + test_mesh.conf \ + test_mesh_2dtorus.conf \ + test_mesh_small.conf \ + test_mesh_path.conf diff --git a/src/mesh/Makefile.in b/src/mesh/Makefile.in new file mode 100644 index 0000000..337d6ab --- /dev/null +++ b/src/mesh/Makefile.in @@ -0,0 +1,1052 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-mesh$(EXEEXT) +check_PROGRAMS = test_mesh_api$(EXEEXT) test_mesh_tree_api$(EXEEXT) \ + test_mesh_local_1$(EXEEXT) test_mesh_local_2$(EXEEXT) \ + test_mesh_2dtorus$(EXEEXT) test_mesh_small_unicast$(EXEEXT) \ + test_mesh_small_multicast$(EXEEXT) \ + test_mesh_small_speed$(EXEEXT) \ + test_mesh_small_speed_ack$(EXEEXT) +@ENABLE_TEST_RUN_TRUE@TESTS = test_mesh_api$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_mesh_tree_api$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_mesh_local_1$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_mesh_local_2$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_mesh_2dtorus$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_mesh_small_unicast$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_mesh_small_multicast$(EXEEXT) +subdir = src/mesh +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/mesh.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = mesh.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunetmesh_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunetmesh_la_OBJECTS = mesh_api.lo +libgnunetmesh_la_OBJECTS = $(am_libgnunetmesh_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetmesh_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetmesh_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_service_mesh_OBJECTS = gnunet-service-mesh.$(OBJEXT) \ + mesh_tunnel_tree.$(OBJEXT) +gnunet_service_mesh_OBJECTS = $(am_gnunet_service_mesh_OBJECTS) +am_test_mesh_2dtorus_OBJECTS = test_mesh_2dtorus.$(OBJEXT) +test_mesh_2dtorus_OBJECTS = $(am_test_mesh_2dtorus_OBJECTS) +test_mesh_2dtorus_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la +am_test_mesh_api_OBJECTS = test_mesh_api.$(OBJEXT) +test_mesh_api_OBJECTS = $(am_test_mesh_api_OBJECTS) +am_test_mesh_local_1_OBJECTS = test_mesh_local_1.$(OBJEXT) +test_mesh_local_1_OBJECTS = $(am_test_mesh_local_1_OBJECTS) +am_test_mesh_local_2_OBJECTS = test_mesh_local_2.$(OBJEXT) +test_mesh_local_2_OBJECTS = $(am_test_mesh_local_2_OBJECTS) +am_test_mesh_small_multicast_OBJECTS = test_mesh_small.$(OBJEXT) +test_mesh_small_multicast_OBJECTS = \ + $(am_test_mesh_small_multicast_OBJECTS) +am_test_mesh_small_speed_OBJECTS = test_mesh_small.$(OBJEXT) +test_mesh_small_speed_OBJECTS = $(am_test_mesh_small_speed_OBJECTS) +am_test_mesh_small_speed_ack_OBJECTS = test_mesh_small.$(OBJEXT) +test_mesh_small_speed_ack_OBJECTS = \ + $(am_test_mesh_small_speed_ack_OBJECTS) +am_test_mesh_small_unicast_OBJECTS = test_mesh_small.$(OBJEXT) +test_mesh_small_unicast_OBJECTS = \ + $(am_test_mesh_small_unicast_OBJECTS) +am_test_mesh_tree_api_OBJECTS = test_mesh_tree_api.$(OBJEXT) +test_mesh_tree_api_OBJECTS = $(am_test_mesh_tree_api_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetmesh_la_SOURCES) $(gnunet_service_mesh_SOURCES) \ + $(test_mesh_2dtorus_SOURCES) $(test_mesh_api_SOURCES) \ + $(test_mesh_local_1_SOURCES) $(test_mesh_local_2_SOURCES) \ + $(test_mesh_small_multicast_SOURCES) \ + $(test_mesh_small_speed_SOURCES) \ + $(test_mesh_small_speed_ack_SOURCES) \ + $(test_mesh_small_unicast_SOURCES) \ + $(test_mesh_tree_api_SOURCES) +DIST_SOURCES = $(libgnunetmesh_la_SOURCES) \ + $(gnunet_service_mesh_SOURCES) $(test_mesh_2dtorus_SOURCES) \ + $(test_mesh_api_SOURCES) $(test_mesh_local_1_SOURCES) \ + $(test_mesh_local_2_SOURCES) \ + $(test_mesh_small_multicast_SOURCES) \ + $(test_mesh_small_speed_SOURCES) \ + $(test_mesh_small_speed_ack_SOURCES) \ + $(test_mesh_small_unicast_SOURCES) \ + $(test_mesh_tree_api_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + mesh.conf + +AM_CLFAGS = -g +lib_LTLIBRARIES = \ + libgnunetmesh.la + +gnunet_service_mesh_SOURCES = \ + gnunet-service-mesh.c \ + mesh_tunnel_tree.c mesh_tunnel_tree.h + +gnunet_service_mesh_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la\ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_service_mesh_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la\ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunetmesh_la_SOURCES = \ + mesh_api.c mesh.h mesh_protocol.h + +libgnunetmesh_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(XLIB) + +libgnunetmesh_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +test_mesh_api_SOURCES = \ + test_mesh_api.c + +test_mesh_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la + +test_mesh_api_DEPENDENCIES = \ + libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_mesh_tree_api_SOURCES = \ + test_mesh_tree_api.c + +test_mesh_tree_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_mesh_tree_api_DEPENDENCIES = \ + libgnunetmesh.la \ + $(top_builddir)/src/dht/libgnunetdht.la + +test_mesh_local_1_SOURCES = \ + test_mesh_local_1.c + +test_mesh_local_1_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la + +test_mesh_local_1_DEPENDENCIES = \ + libgnunetmesh.la + +test_mesh_local_2_SOURCES = \ + test_mesh_local_2.c + +test_mesh_local_2_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la + +test_mesh_local_2_DEPENDENCIES = \ + libgnunetmesh.la + +test_mesh_2dtorus_SOURCES = \ + test_mesh_2dtorus.c + +test_mesh_2dtorus_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_mesh_small_unicast_SOURCES = \ + test_mesh_small.c + +test_mesh_small_unicast_LDADD = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_mesh_small_unicast_DEPENDENCIES = \ + libgnunetmesh.la + +test_mesh_small_multicast_SOURCES = \ + test_mesh_small.c + +test_mesh_small_multicast_LDADD = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_mesh_small_multicast_DEPENDENCIES = \ + libgnunetmesh.la + +test_mesh_small_speed_SOURCES = \ + test_mesh_small.c + +test_mesh_small_speed_LDADD = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_mesh_small_speed_DEPENDENCIES = \ + libgnunetmesh.la + +test_mesh_small_speed_ack_SOURCES = \ + test_mesh_small.c + +test_mesh_small_speed_ack_LDADD = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_mesh_small_speed_ack_DEPENDENCIES = \ + libgnunetmesh.la + +EXTRA_DIST = \ + test_mesh.conf \ + test_mesh_2dtorus.conf \ + test_mesh_small.conf \ + test_mesh_path.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/mesh/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/mesh/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +mesh.conf: $(top_builddir)/config.status $(srcdir)/mesh.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetmesh.la: $(libgnunetmesh_la_OBJECTS) $(libgnunetmesh_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetmesh_la_LINK) -rpath $(libdir) $(libgnunetmesh_la_OBJECTS) $(libgnunetmesh_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-service-mesh$(EXEEXT): $(gnunet_service_mesh_OBJECTS) $(gnunet_service_mesh_DEPENDENCIES) + @rm -f gnunet-service-mesh$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_mesh_OBJECTS) $(gnunet_service_mesh_LDADD) $(LIBS) +test_mesh_2dtorus$(EXEEXT): $(test_mesh_2dtorus_OBJECTS) $(test_mesh_2dtorus_DEPENDENCIES) + @rm -f test_mesh_2dtorus$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_mesh_2dtorus_OBJECTS) $(test_mesh_2dtorus_LDADD) $(LIBS) +test_mesh_api$(EXEEXT): $(test_mesh_api_OBJECTS) $(test_mesh_api_DEPENDENCIES) + @rm -f test_mesh_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_mesh_api_OBJECTS) $(test_mesh_api_LDADD) $(LIBS) +test_mesh_local_1$(EXEEXT): $(test_mesh_local_1_OBJECTS) $(test_mesh_local_1_DEPENDENCIES) + @rm -f test_mesh_local_1$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_mesh_local_1_OBJECTS) $(test_mesh_local_1_LDADD) $(LIBS) +test_mesh_local_2$(EXEEXT): $(test_mesh_local_2_OBJECTS) $(test_mesh_local_2_DEPENDENCIES) + @rm -f test_mesh_local_2$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_mesh_local_2_OBJECTS) $(test_mesh_local_2_LDADD) $(LIBS) +test_mesh_small_multicast$(EXEEXT): $(test_mesh_small_multicast_OBJECTS) $(test_mesh_small_multicast_DEPENDENCIES) + @rm -f test_mesh_small_multicast$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_mesh_small_multicast_OBJECTS) $(test_mesh_small_multicast_LDADD) $(LIBS) +test_mesh_small_speed$(EXEEXT): $(test_mesh_small_speed_OBJECTS) $(test_mesh_small_speed_DEPENDENCIES) + @rm -f test_mesh_small_speed$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_mesh_small_speed_OBJECTS) $(test_mesh_small_speed_LDADD) $(LIBS) +test_mesh_small_speed_ack$(EXEEXT): $(test_mesh_small_speed_ack_OBJECTS) $(test_mesh_small_speed_ack_DEPENDENCIES) + @rm -f test_mesh_small_speed_ack$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_mesh_small_speed_ack_OBJECTS) $(test_mesh_small_speed_ack_LDADD) $(LIBS) +test_mesh_small_unicast$(EXEEXT): $(test_mesh_small_unicast_OBJECTS) $(test_mesh_small_unicast_DEPENDENCIES) + @rm -f test_mesh_small_unicast$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_mesh_small_unicast_OBJECTS) $(test_mesh_small_unicast_LDADD) $(LIBS) +test_mesh_tree_api$(EXEEXT): $(test_mesh_tree_api_OBJECTS) $(test_mesh_tree_api_DEPENDENCIES) + @rm -f test_mesh_tree_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_mesh_tree_api_OBJECTS) $(test_mesh_tree_api_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-mesh.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mesh_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mesh_tunnel_tree.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_2dtorus.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_local_1.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_local_2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_small.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_tree_api.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/mesh/gnunet-service-mesh.c b/src/mesh/gnunet-service-mesh.c new file mode 100644 index 0000000..80848f2 --- /dev/null +++ b/src/mesh/gnunet-service-mesh.c @@ -0,0 +1,4877 @@ +/* + This file is part of GNUnet. + (C) 2001 - 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file mesh/gnunet-service-mesh.c + * @brief GNUnet MESH service + * @author Bartlomiej Polot + * + * STRUCTURE: + * - DATA STRUCTURES + * - GLOBAL VARIABLES + * - GENERAL HELPERS + * - PERIODIC FUNCTIONS + * - MESH NETWORK HANDLER HELPERS + * - MESH NETWORK HANDLES + * - MESH LOCAL HANDLER HELPERS + * - MESH LOCAL HANDLES + * - MAIN FUNCTIONS (main & run) + * + * TODO: + * - error reporting (CREATE/CHANGE/ADD/DEL?) -- new message! + * - partial disconnect reporting -- same as error reporting? + * - add vs create? change vs. keep-alive? same msg or different ones? -- thinking... + * - speed requirement specification (change?) in mesh API -- API call + * - add ping message + * - relay corking down to core + * - set ttl relative to tree depth + * TODO END + */ + +#include "platform.h" +#include "mesh.h" +#include "mesh_protocol.h" +#include "gnunet_dht_service.h" +#include "mesh_tunnel_tree.h" + +/* TODO: move into configuration file */ +#define REFRESH_PATH_TIME GNUNET_TIME_relative_multiply(\ + GNUNET_TIME_UNIT_SECONDS,\ + 300) +#define APP_ANNOUNCE_TIME GNUNET_TIME_relative_multiply(\ + GNUNET_TIME_UNIT_SECONDS,\ + 5) + +#define ID_ANNOUNCE_TIME GNUNET_TIME_relative_multiply(\ + GNUNET_TIME_UNIT_SECONDS,\ + 5) + +#define UNACKNOWLEDGED_WAIT GNUNET_TIME_relative_multiply(\ + GNUNET_TIME_UNIT_SECONDS,\ + 2) +#define DEFAULT_TTL 64 + +/* TODO END */ + +#define MESH_DEBUG_DHT GNUNET_YES +#define MESH_DEBUG_CONNECTION GNUNET_NO + +#if MESH_DEBUG_CONNECTION +#define DEBUG_CONN(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) +#else +#define DEBUG_CONN(...) +#endif + +#if MESH_DEBUG_DHT +#define DEBUG_DHT(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) +#else +#define DEBUG_DHT(...) +#endif + +/******************************************************************************/ +/************************ DATA STRUCTURES ****************************/ +/******************************************************************************/ + +/** FWD declaration */ +struct MeshPeerInfo; + + +/** + * Struct representing a piece of data being sent to other peers + */ +struct MeshData +{ + /** Tunnel it belongs to. */ + struct MeshTunnel *t; + + /** In case of a multicast, task to allow a client to send more data if + * some neighbor is too slow. */ + GNUNET_SCHEDULER_TaskIdentifier *task; + + /** How many remaining neighbors we need to send this to. */ + unsigned int *reference_counter; + + /** Size of the data. */ + size_t data_len; + + /** Data itself */ + void *data; +}; + + +/** + * Struct containing all info possibly needed to build a package when called + * back by core. + */ +struct MeshTransmissionDescriptor +{ + /** ID of the tunnel this packet travels in */ + struct MESH_TunnelID *origin; + + /** Who was this message being sent to */ + struct MeshPeerInfo *peer; + + /** Ultimate destination of the packet */ + GNUNET_PEER_Id destination; + + /** Which handler was used to request the transmission */ + unsigned int handler_n; + + /** Data descriptor */ + struct MeshData* mesh_data; +}; + + +/** + * Struct containing all information regarding a given peer + */ +struct MeshPeerInfo +{ + /** + * ID of the peer + */ + GNUNET_PEER_Id id; + + /** + * Last time we heard from this peer + */ + struct GNUNET_TIME_Absolute last_contact; + + /** + * Number of attempts to reconnect so far + */ + int n_reconnect_attempts; + + /** + * Paths to reach the peer, ordered by ascending hop count + */ + struct MeshPeerPath *path_head; + + /** + * Paths to reach the peer, ordered by ascending hop count + */ + struct MeshPeerPath *path_tail; + + /** + * Handle to stop the DHT search for a path to this peer + */ + struct GNUNET_DHT_GetHandle *dhtget; + + /** + * Closure given to the DHT GET + */ + struct MeshPathInfo *dhtgetcls; + + /** + * Handles to stop queued transmissions for this peer + */ + struct GNUNET_CORE_TransmitHandle *core_transmit[CORE_QUEUE_SIZE]; + + /** + * Pointer to info stuctures used as cls for queued transmissions + */ + void *infos[CORE_QUEUE_SIZE]; + + /** + * Type of message being in each transmission + */ + uint16_t types[CORE_QUEUE_SIZE]; + + /** + * Array of tunnels this peer participates in + * (most probably a small amount, therefore not a hashmap) + * When the path to the peer changes, notify these tunnels to let them + * re-adjust their path trees. + */ + struct MeshTunnel **tunnels; + + /** + * Number of tunnels this peers participates in + */ + unsigned int ntunnels; +}; + + +/** + * Data scheduled to transmit (to local client or remote peer) + */ +struct MeshQueue +{ + /** + * Double linked list + */ + struct MeshQueue *next; + struct MeshQueue *prev; + + /** + * Target of the data (NULL if target is client) + */ + struct MeshPeerInfo *peer; + + /** + * Client to send the data to (NULL if target is peer) + */ + struct MeshClient *client; + + /** + * Size of the message to transmit + */ + unsigned int size; + + /** + * How old is the data? + */ + struct GNUNET_TIME_Absolute timestamp; + + /** + * Data itself + */ + struct GNUNET_MessageHeader *data; +}; + +/** + * Globally unique tunnel identification (owner + number) + * DO NOT USE OVER THE NETWORK + */ +struct MESH_TunnelID +{ + /** + * Node that owns the tunnel + */ + GNUNET_PEER_Id oid; + + /** + * Tunnel number to differentiate all the tunnels owned by the node oid + * ( tid < GNUNET_MESH_LOCAL_TUNNEL_ID_CLI ) + */ + MESH_TunnelNumber tid; +}; + + +struct MeshClient; /* FWD declaration */ + +/** + * Struct containing all information regarding a tunnel + * For an intermediate node the improtant info used will be: + * - id Tunnel unique identification + * - paths[0] To know where to send it next + * - metainfo: ready, speeds, accounting + */ +struct MeshTunnel +{ + /** + * Tunnel ID + */ + struct MESH_TunnelID id; + + /** + * Local tunnel number ( >= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI or 0 ) + */ + MESH_TunnelNumber local_tid; + + /** + * Local tunnel number for local destination clients (incoming number) + * ( >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV or 0). All clients share the same + * number. + */ + MESH_TunnelNumber local_tid_dest; + + /** + * ID of the last multicast packet seen/sent. + */ + uint32_t mid; + + /** + * Last time the tunnel was used + */ + struct GNUNET_TIME_Absolute timestamp; + + /** + * Peers in the tunnel, indexed by PeerIdentity -> (MeshPeerInfo) + * containing peers added by id or by type, not intermediate peers. + */ + struct GNUNET_CONTAINER_MultiHashMap *peers; + + /** + * Number of peers that are connected and potentially ready to receive data + */ + unsigned int peers_ready; + + /** + * Number of peers that have been added to the tunnel + */ + unsigned int peers_total; + + /** + * Client owner of the tunnel, if any + */ + struct MeshClient *owner; + + /** + * Clients that have been informed about the tunnel, if any + */ + struct MeshClient **clients; + + /** + * Number of elements in clients + */ + unsigned int nclients; + + /** + * Clients that have requested to leave the tunnel + */ + struct MeshClient **ignore; + + /** + * Number of elements in clients + */ + unsigned int nignore; + + /** + * Messages ready to transmit + */ + struct MeshQueue *queue_head; + struct MeshQueue *queue_tail; + + /** + * Tunnel paths + */ + struct MeshTunnelTree *tree; + + /** + * Application type we are looking for in this tunnel + */ + GNUNET_MESH_ApplicationType type; + + /** + * Used to search peers offering a service + */ + struct GNUNET_DHT_GetHandle *dht_get_type; + + /** + * Task to keep the used paths alive + */ + GNUNET_SCHEDULER_TaskIdentifier path_refresh_task; + + /** + * Task to destroy the tunnel after timeout + * + * FIXME: merge the two? a tunnel will have either + * a path refresh OR a timeout, never both! + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; +}; + + +/** + * Info needed to work with tunnel paths and peers + */ +struct MeshPathInfo +{ + /** + * Tunnel + */ + struct MeshTunnel *t; + + /** + * Neighbouring peer to whom we send the packet to + */ + struct MeshPeerInfo *peer; + + /** + * Path itself + */ + struct MeshPeerPath *path; + + /** + * Position in peer's transmit queue + */ + unsigned int pos; +}; + + +/** + * Struct containing information about a client of the service + */ +struct MeshClient +{ + /** + * Linked list next + */ + struct MeshClient *next; + + /** + * Linked list prev + */ + struct MeshClient *prev; + + /** + * Tunnels that belong to this client, indexed by local id + */ + struct GNUNET_CONTAINER_MultiHashMap *own_tunnels; + + /** + * Tunnels this client has accepted, indexed by incoming local id + */ + struct GNUNET_CONTAINER_MultiHashMap *incoming_tunnels; + + /** + * Tunnels this client has rejected, indexed by incoming local id + */ + struct GNUNET_CONTAINER_MultiHashMap *ignore_tunnels; + /** + * Handle to communicate with the client + */ + struct GNUNET_SERVER_Client *handle; + + /** + * Applications that this client has claimed to provide + */ + struct GNUNET_CONTAINER_MultiHashMap *apps; + + /** + * Messages that this client has declared interest in + */ + struct GNUNET_CONTAINER_MultiHashMap *types; + + /** + * Whether the client is active or shutting down (don't send confirmations + * to a client that is shutting down. + */ + int shutting_down; + + /** + * ID of the client, mainly for debug messages + */ + unsigned int id; + +}; + + + +/******************************************************************************/ +/************************ DEBUG FUNCTIONS ****************************/ +/******************************************************************************/ + +#if MESH_DEBUG +/** + * GNUNET_SCHEDULER_Task for printing a message after some operation is done + * @param cls string to print + * @param tc task context + */ +static void +mesh_debug (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *s = cls; + + if (NULL != tc && GNUNET_SCHEDULER_REASON_SHUTDOWN == tc->reason) + { + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s\n", s); +} +#endif + +/******************************************************************************/ +/*********************** GLOBAL VARIABLES ****************************/ +/******************************************************************************/ + +/** + * All the clients + */ +static struct MeshClient *clients; +static struct MeshClient *clients_tail; + +/** + * Tunnels known, indexed by MESH_TunnelID (MeshTunnel) + */ +static struct GNUNET_CONTAINER_MultiHashMap *tunnels; + +/** + * Tunnels incoming, indexed by MESH_TunnelNumber + * (which is greater than GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) + */ +static struct GNUNET_CONTAINER_MultiHashMap *incoming_tunnels; + +/** + * Peers known, indexed by PeerIdentity (MeshPeerInfo) + */ +static struct GNUNET_CONTAINER_MultiHashMap *peers; + +/** + * Handle to communicate with core + */ +static struct GNUNET_CORE_Handle *core_handle; + +/** + * Handle to communicate with transport + */ +// static struct GNUNET_TRANSPORT_Handle *transport_handle; + +/** + * Handle to use DHT + */ +static struct GNUNET_DHT_Handle *dht_handle; + +/** + * Handle to server + */ +static struct GNUNET_SERVER_Handle *server_handle; + +/** + * Notification context, to send messages to local clients + */ +static struct GNUNET_SERVER_NotificationContext *nc; + +/** + * Local peer own ID (memory efficient handle) + */ +static GNUNET_PEER_Id myid; + +/** + * Local peer own ID (full value) + */ +static struct GNUNET_PeerIdentity my_full_id; + +/** + * Own private key + */ +static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; + +/** + * Own public key. + */ +static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; + +/** + * Tunnel ID for the next created tunnel (global tunnel number) + */ +static MESH_TunnelNumber next_tid; + +/** + * Tunnel ID for the next incoming tunnel (local tunnel number) + */ +static MESH_TunnelNumber next_local_tid; + +/** + * All application types provided by this peer + */ +static struct GNUNET_CONTAINER_MultiHashMap *applications; + +/** + * All message types clients of this peer are interested in + */ +static struct GNUNET_CONTAINER_MultiHashMap *types; + +/** + * Task to periodically announce provided applications + */ +GNUNET_SCHEDULER_TaskIdentifier announce_applications_task; + +/** + * Task to periodically announce itself in the network + */ +GNUNET_SCHEDULER_TaskIdentifier announce_id_task; + +/** + * Next ID to assign to a client + */ +unsigned int next_client_id; + + + +/******************************************************************************/ +/************************ ITERATORS ****************************/ +/******************************************************************************/ + +/* FIXME move iterators here */ + + +/******************************************************************************/ +/************************ PERIODIC FUNCTIONS ****************************/ +/******************************************************************************/ + +/** + * Announce iterator over for each application provided by the peer + * + * @param cls closure + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +announce_application (void *cls, const GNUNET_HashCode * key, void *value) +{ + /* FIXME are hashes in multihash map equal on all aquitectures? */ + GNUNET_DHT_put (dht_handle, key, 10U, + GNUNET_DHT_RO_RECORD_ROUTE | + GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, GNUNET_BLOCK_TYPE_TEST, + sizeof (struct GNUNET_PeerIdentity), + (const char *) &my_full_id, +#if MESH_DEBUG + GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_REL, + &mesh_debug, "DHT_put for app completed"); +#else + GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), + APP_ANNOUNCE_TIME), + APP_ANNOUNCE_TIME, NULL, NULL); +#endif + return GNUNET_OK; +} + + +/** + * Periodically announce what applications are provided by local clients + * + * @param cls closure + * @param tc task context + */ +static void +announce_applications (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + { + announce_applications_task = GNUNET_SCHEDULER_NO_TASK; + return; + } + + DEBUG_DHT ("Starting PUT for apps\n"); + + GNUNET_CONTAINER_multihashmap_iterate (applications, &announce_application, + NULL); + announce_applications_task = + GNUNET_SCHEDULER_add_delayed (APP_ANNOUNCE_TIME, &announce_applications, + cls); + DEBUG_DHT ("Finished PUT for apps\n"); + + return; +} + + +/** + * Periodically announce self id in the DHT + * + * @param cls closure + * @param tc task context + */ +static void +announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + { + announce_id_task = GNUNET_SCHEDULER_NO_TASK; + return; + } + /* TODO + * - Set data expiration in function of X + * - Adapt X to churn + */ + DEBUG_DHT ("DHT_put for ID %s started.\n", GNUNET_i2s (&my_full_id)); + + GNUNET_DHT_put (dht_handle, /* DHT handle */ + &my_full_id.hashPubKey, /* Key to use */ + 10U, /* Replication level */ + GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */ + GNUNET_BLOCK_TYPE_TEST, /* Block type */ + sizeof (my_full_id), /* Size of the data */ + (char *) &my_full_id, /* Data itself */ + GNUNET_TIME_absolute_get_forever (), /* Data expiration */ + GNUNET_TIME_UNIT_FOREVER_REL, /* Retry time */ +#if MESH_DEBUG_DHT + &mesh_debug, "DHT_put for id completed"); +#else + NULL, /* Continuation */ + NULL); /* Continuation closure */ +#endif + announce_id_task = + GNUNET_SCHEDULER_add_delayed (ID_ANNOUNCE_TIME, &announce_id, cls); +} + + +/** + * Function to process paths received for a new peer addition. The recorded + * paths form the initial tunnel, which can be optimized later. + * Called on each result obtained for the DHT search. + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +static void +dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data); + + +/******************************************************************************/ +/****************** GENERAL HELPER FUNCTIONS ************************/ +/******************************************************************************/ + +/** + * Search for a tunnel by global ID using full PeerIdentities + * + * @param oid owner of the tunnel + * @param tid global tunnel number + * + * @return tunnel handler, NULL if doesn't exist + */ +static struct MeshTunnel * +tunnel_get (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid); + + +/** + * Delete an active client from the tunnel. + * + * @param t Tunnel. + * @param c Client. + */ +static void +tunnel_delete_active_client (struct MeshTunnel *t, const struct MeshClient *c); + +/** + * Notify a tunnel that a connection has broken that affects at least + * some of its peers. + * + * @param t Tunnel affected. + * @param p1 Peer that got disconnected from p2. + * @param p2 Peer that got disconnected from p1. + * + * @return Short ID of the peer disconnected (either p1 or p2). + * 0 if the tunnel remained unaffected. + */ +static GNUNET_PEER_Id +tunnel_notify_connection_broken (struct MeshTunnel *t, GNUNET_PEER_Id p1, + GNUNET_PEER_Id p2); + + +/** + * Check if client has registered with the service and has not disconnected + * + * @param client the client to check + * + * @return non-NULL if client exists in the global DLL + */ +static struct MeshClient * +client_get (struct GNUNET_SERVER_Client *client) +{ + struct MeshClient *c; + + c = clients; + while (NULL != c) + { + if (c->handle == client) + return c; + c = c->next; + } + return NULL; +} + + +/** + * Checks if a given client has subscribed to certain message type + * + * @param message_type Type of message to check + * @param c Client to check + * + * @return GNUNET_YES or GNUNET_NO, depending on subscription status + * + * TODO inline? + */ +static int +client_is_subscribed (uint16_t message_type, struct MeshClient *c) +{ + GNUNET_HashCode hc; + + GNUNET_CRYPTO_hash (&message_type, sizeof (uint16_t), &hc); + return GNUNET_CONTAINER_multihashmap_contains (c->types, &hc); +} + + +/** + * Allow a client to send more data after transmitting a multicast message + * which some neighbor has not yet accepted altough a reasonable time has + * passed. + * + * @param cls Closure (DataDescriptor containing the task identifier) + * @param tc Task Context + * + * FIXME reference counter cshould be just int + */ +static void +client_allow_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct MeshData *mdata = cls; + + if (GNUNET_SCHEDULER_REASON_SHUTDOWN == tc->reason) + return; + GNUNET_assert (NULL != mdata->reference_counter); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CLIENT ALLOW SEND DESPITE %u COPIES PENDING\n", + *(mdata->reference_counter)); + *(mdata->task) = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SERVER_receive_done (mdata->t->owner->handle, GNUNET_OK); +} + + +/** + * Check whether client wants traffic from a tunnel. + * + * @param c Client to check. + * @param t Tunnel to be found. + * + * @return GNUNET_YES if client knows tunnel. + * + * TODO look in client hashmap + */ +static int +client_wants_tunnel (struct MeshClient *c, struct MeshTunnel *t) +{ + unsigned int i; + + for (i = 0; i < t->nclients; i++) + if (t->clients[i] == c) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Check whether client has been informed about a tunnel. + * + * @param c Client to check. + * @param t Tunnel to be found. + * + * @return GNUNET_YES if client knows tunnel. + * + * TODO look in client hashmap + */ +static int +client_knows_tunnel (struct MeshClient *c, struct MeshTunnel *t) +{ + unsigned int i; + + for (i = 0; i < t->nignore; i++) + if (t->ignore[i] == c) + return GNUNET_YES; + return client_wants_tunnel(c, t); +} + + +/** + * Marks a client as uninterested in traffic from the tunnel, updating both + * client and tunnel to reflect this. + * + * @param c Client that doesn't want traffic anymore. + * @param t Tunnel which should be ignored. + * + * FIXME when to delete an incoming tunnel? + */ +static void +client_ignore_tunnel (struct MeshClient *c, struct MeshTunnel *t) +{ + GNUNET_HashCode hash; + + GNUNET_CRYPTO_hash(&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels, + &hash, t)); + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_put (c->ignore_tunnels, &hash, t, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); + tunnel_delete_active_client (t, c); + GNUNET_array_append (t->ignore, t->nignore, c); +} + + +/** + * Deletes a tunnel from a client (either owner or destination). To be used on + * tunnel destroy, otherwise, use client_ignore_tunnel. + * + * @param c Client whose tunnel to delete. + * @param t Tunnel which should be deleted. + */ +static void +client_delete_tunnel (struct MeshClient *c, struct MeshTunnel *t) +{ + GNUNET_HashCode hash; + + if (c == t->owner) + { + GNUNET_CRYPTO_hash(&t->local_tid, sizeof (MESH_TunnelNumber), &hash); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (c->own_tunnels, + &hash, + t)); + } + else + { + GNUNET_CRYPTO_hash(&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); + // FIXME XOR? + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels, + &hash, + t) || + GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (c->ignore_tunnels, + &hash, + t)); + } + +} + + +/** + * Send the message to all clients that have subscribed to its type + * + * @param msg Pointer to the message itself + * @param payload Pointer to the payload of the message. + * @return number of clients this message was sent to + */ +static unsigned int +send_subscribed_clients (const struct GNUNET_MessageHeader *msg, + const struct GNUNET_MessageHeader *payload) +{ + struct GNUNET_PeerIdentity *oid; + struct MeshClient *c; + struct MeshTunnel *t; + MESH_TunnelNumber *tid; + unsigned int count; + uint16_t type; + char cbuf[htons (msg->size)]; + + type = ntohs (payload->type); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending to clients...\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "message of type %u\n", type); + + memcpy (cbuf, msg, sizeof (cbuf)); + switch (htons (msg->type)) + { + struct GNUNET_MESH_Unicast *uc; + struct GNUNET_MESH_Multicast *mc; + struct GNUNET_MESH_ToOrigin *to; + + case GNUNET_MESSAGE_TYPE_MESH_UNICAST: + uc = (struct GNUNET_MESH_Unicast *) cbuf; + tid = &uc->tid; + oid = &uc->oid; + break; + case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: + mc = (struct GNUNET_MESH_Multicast *) cbuf; + tid = &mc->tid; + oid = &mc->oid; + break; + case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: + to = (struct GNUNET_MESH_ToOrigin *) cbuf; + tid = &to->tid; + oid = &to->oid; + break; + default: + GNUNET_break (0); + return 0; + } + t = tunnel_get (oid, ntohl (*tid)); + if (NULL == t) + { + GNUNET_break (0); + return 0; + } + + for (count = 0, c = clients; c != NULL; c = c->next) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " client %u\n", c->id); + if (client_is_subscribed (type, c)) + { + if (htons (msg->type) == GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN) + { + if (c != t->owner) + continue; + *tid = htonl (t->local_tid); + } + else + { + if (GNUNET_NO == client_knows_tunnel (c, t)) + { + /* This client doesn't know the tunnel */ + struct GNUNET_MESH_TunnelNotification tmsg; + GNUNET_HashCode hash; + + tmsg.header.size = htons (sizeof (tmsg)); + tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE); + GNUNET_PEER_resolve (t->id.oid, &tmsg.peer); + tmsg.tunnel_id = htonl (t->local_tid_dest); + GNUNET_SERVER_notification_context_unicast (nc, c->handle, + &tmsg.header, GNUNET_NO); + GNUNET_array_append (t->clients, t->nclients, c); + GNUNET_CRYPTO_hash (&t->local_tid_dest, sizeof (MESH_TunnelNumber), + &hash); + GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put ( + c->incoming_tunnels, &hash, t, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); + } + *tid = htonl (t->local_tid_dest); + } + + /* Check if the client wants to get traffic from the tunnel */ + if (GNUNET_NO == client_wants_tunnel(c, t)) + continue; + count++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " sending\n"); + GNUNET_SERVER_notification_context_unicast (nc, c->handle, + (struct GNUNET_MessageHeader + *) cbuf, GNUNET_YES); + } + } + return count; +} + + +/** + * Notify the client that owns the tunnel that a peer has connected to it + * (the requested path to it has been confirmed). + * + * @param t Tunnel whose owner to notify + * @param id Short id of the peer that has connected + */ +static void +send_client_peer_connected (const struct MeshTunnel *t, const GNUNET_PEER_Id id) +{ + struct GNUNET_MESH_PeerControl pc; + + pc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD); + pc.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); + pc.tunnel_id = htonl (t->local_tid); + GNUNET_PEER_resolve (id, &pc.peer); + GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle, &pc.header, + GNUNET_NO); +} + + +/** + * Notify all clients (not depending on registration status) that the incoming + * tunnel is no longer valid. + * + * @param t Tunnel that was destroyed. + */ +static void +send_clients_tunnel_destroy (struct MeshTunnel *t) +{ + struct GNUNET_MESH_TunnelMessage msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); + msg.tunnel_id = htonl (t->local_tid_dest); + GNUNET_SERVER_notification_context_broadcast (nc, &msg.header, GNUNET_NO); +} + + +/** + * Notify clients of tunnel disconnections, if needed. + * In case the origin disconnects, the destination clients get a tunnel destroy + * notification. If the last destination disconnects (only one remaining client + * in tunnel), the origin gets a (local ID) peer disconnected. + * Note that the function must be called BEFORE removing the client from + * the tunnel. + * + * @param t Tunnel that was destroyed. + * @param c Client that disconnected. + */ +static void +send_client_tunnel_disconnect (struct MeshTunnel *t, struct MeshClient *c) +{ + unsigned int i; + + if (c == t->owner) + { + struct GNUNET_MESH_TunnelMessage msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); + msg.tunnel_id = htonl (t->local_tid_dest); + for (i = 0; i < t->nclients; i++) + GNUNET_SERVER_notification_context_unicast (nc, t->clients[i]->handle, + &msg.header, GNUNET_NO); + } + // FIXME when to disconnect an incoming tunnel? + else if (1 == t->nclients && NULL != t->owner) + { + struct GNUNET_MESH_PeerControl msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL); + msg.tunnel_id = htonl (t->local_tid); + msg.peer = my_full_id; + GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle, + &msg.header, GNUNET_NO); + } +} + + +/** + * Function called to notify a client about the socket + * being ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +send_core_create_path (void *cls, size_t size, void *buf); + + +/** + * Function called to notify a client about the socket + * being ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure (data itself) + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * + * @return number of bytes written to buf + */ +static size_t +send_core_data_multicast (void *cls, size_t size, void *buf); + + +/** + * Decrements the reference counter and frees all resources if needed + * + * @param mesh_data Data Descriptor used in a multicast message. + * Freed no longer needed (last message). + */ +static void +data_descriptor_decrement_multicast (struct MeshData *mesh_data) +{ + /* Make sure it's a multicast packet */ + GNUNET_assert (NULL != mesh_data->reference_counter); + + if (0 == --(*(mesh_data->reference_counter))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last copy!\n"); + if (NULL != mesh_data->task) + { + if (GNUNET_SCHEDULER_NO_TASK != *(mesh_data->task)) + { + GNUNET_SCHEDULER_cancel (*(mesh_data->task)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " notifying client...\n"); + GNUNET_SERVER_receive_done (mesh_data->t->owner->handle, GNUNET_OK); + } + GNUNET_free (mesh_data->task); + } + GNUNET_free (mesh_data->reference_counter); + GNUNET_free (mesh_data->data); + GNUNET_free (mesh_data); + } +} + + +/** + * Cancel a core transmission that was already requested and free all resources + * associated to the request. + * + * @param peer PeeInfo of the peer whose transmission is cancelled. + * @param i Position of the transmission to be cancelled. + */ +static void +peer_info_cancel_transmission (struct MeshPeerInfo *peer, unsigned int i) +{ + if (NULL != peer->core_transmit[i]) + { + struct MeshTransmissionDescriptor *dd; + struct MeshPathInfo *path_info; + +#if MESH_DEBUG + { + struct GNUNET_PeerIdentity id; + + GNUNET_PEER_resolve (peer->id, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " Cancelling data transmission at %s [%u]\n", + GNUNET_i2s (&id), i); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " message type %u\n", + peer->types[i]); + } +#endif + /* TODO: notify that tranmission has failed */ + switch (peer->types[i]) + { + case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: + case GNUNET_MESSAGE_TYPE_MESH_UNICAST: + case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " type payload\n"); + dd = peer->infos[i]; + data_descriptor_decrement_multicast (dd->mesh_data); + break; + case GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " type create path\n"); + path_info = peer->infos[i]; + path_destroy (path_info->path); + break; + default: + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " type unknown!\n"); + } + GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit[i]); + peer->core_transmit[i] = NULL; + GNUNET_free (peer->infos[i]); + } +} + + +/** + * Get a unused CORE slot to transmit a message to a peer. If all the slots + * are used, cancel one and return it's position. + * + * @param peer PeerInfo of the neighbor we want to transmit to. + * + * @return The index of an available slot to transmit to the neighbor. + */ +static unsigned int +peer_info_transmit_slot (struct MeshPeerInfo *peer) +{ + unsigned int i; + + for (i = 0; peer->core_transmit[i]; i++) + { + if (i == (CORE_QUEUE_SIZE - 1)) + { + /* All positions are taken! Overwriting! */ + GNUNET_break (0); + peer_info_cancel_transmission (peer, 0); + return 0; + } + } + return i; +} + + +/** + * Retrieve the MeshPeerInfo stucture associated with the peer, create one + * and insert it in the appropiate structures if the peer is not known yet. + * + * @param peer Full identity of the peer. + * + * @return Existing or newly created peer info. + */ +static struct MeshPeerInfo * +peer_info_get (const struct GNUNET_PeerIdentity *peer) +{ + struct MeshPeerInfo *peer_info; + + peer_info = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); + if (NULL == peer_info) + { + peer_info = + (struct MeshPeerInfo *) GNUNET_malloc (sizeof (struct MeshPeerInfo)); + GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey, peer_info, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + peer_info->id = GNUNET_PEER_intern (peer); + } + + return peer_info; +} + + +/** + * Retrieve the MeshPeerInfo stucture associated with the peer, create one + * and insert it in the appropiate structures if the peer is not known yet. + * + * @param peer Short identity of the peer. + * + * @return Existing or newly created peer info. + */ +static struct MeshPeerInfo * +peer_info_get_short (const GNUNET_PEER_Id peer) +{ + struct GNUNET_PeerIdentity id; + + GNUNET_PEER_resolve (peer, &id); + return peer_info_get (&id); +} + + +/** + * Iterator to remove the tunnel from the list of tunnels a peer participates + * in. + * + * @param cls Closure (tunnel info) + * @param key GNUNET_PeerIdentity of the peer (unused) + * @param value PeerInfo of the peer + * + * @return always GNUNET_YES, to keep iterating + */ +static int +peer_info_delete_tunnel (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct MeshTunnel *t = cls; + struct MeshPeerInfo *peer = value; + unsigned int i; + + for (i = 0; i < peer->ntunnels; i++) + { + if (0 == + memcmp (&peer->tunnels[i]->id, &t->id, sizeof (struct MESH_TunnelID))) + { + peer->ntunnels--; + peer->tunnels[i] = peer->tunnels[peer->ntunnels]; + peer->tunnels = GNUNET_realloc (peer->tunnels, peer->ntunnels); + return GNUNET_YES; + } + } + return GNUNET_YES; +} + + +/** + * Core callback to write a + * + * @param cls Closure (MeshTransmissionDescriptor with data in "data" member). + * @param size Number of bytes available in buf. + * @param buf Where the to write the message. + * + * @return number of bytes written to buf + */ +static size_t +send_core_data_raw (void *cls, size_t size, void *buf) +{ + struct MeshTransmissionDescriptor *info = cls; + struct GNUNET_MessageHeader *msg; + size_t total_size; + + GNUNET_assert (NULL != info); + GNUNET_assert (NULL != info->mesh_data); + msg = (struct GNUNET_MessageHeader *) info->mesh_data->data; + total_size = ntohs (msg->size); + + if (total_size > size) + { + struct GNUNET_PeerIdentity id; + + GNUNET_PEER_resolve (info->peer->id, &id); + info->peer->core_transmit[info->handler_n] = + GNUNET_CORE_notify_transmit_ready (core_handle, 0, 100, + GNUNET_TIME_UNIT_FOREVER_REL, &id, + size, &send_core_data_raw, info); + return 0; + } + info->peer->core_transmit[info->handler_n] = NULL; + memcpy (buf, msg, total_size); + GNUNET_free (info->mesh_data); + GNUNET_free (info); + return total_size; +} + + +/** + * Sends an already built message to a peer, properly registrating + * all used resources. + * + * @param message Message to send. Fucntion makes a copy of it. + * @param peer Short ID of the neighbor whom to send the message. + * + * FIXME tunnel? + */ +static void +send_message (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer) +{ + struct MeshTransmissionDescriptor *info; + struct MeshPeerInfo *neighbor; + struct MeshPeerPath *p; + unsigned int i; + size_t size; + +// GNUNET_TRANSPORT_try_connect(); + + size = ntohs (message->size); + info = GNUNET_malloc (sizeof (struct MeshTransmissionDescriptor)); + info->mesh_data = GNUNET_malloc (sizeof (struct MeshData)); + info->mesh_data->data = GNUNET_malloc (size); + memcpy (info->mesh_data->data, message, size); + info->mesh_data->data_len = size; + neighbor = peer_info_get (peer); + for (p = neighbor->path_head; NULL != p; p = p->next) + { + if (2 == p->length) + { + break; + } + } + if (NULL == p) + { + GNUNET_break (0); + GNUNET_free (info->mesh_data->data); + GNUNET_free (info->mesh_data); + GNUNET_free (info); + return; + } + i = peer_info_transmit_slot (neighbor); + info->handler_n = i; + info->peer = neighbor; + neighbor->types[i] = GNUNET_MESSAGE_TYPE_MESH_UNICAST; + neighbor->infos[i] = info; + neighbor->core_transmit[i] = + GNUNET_CORE_notify_transmit_ready (core_handle, 0, 100, + GNUNET_TIME_UNIT_FOREVER_REL, peer, + size, &send_core_data_raw, info); + +} + + +/** + * Sends a CREATE PATH message for a path to a peer, properly registrating + * all used resources. + * + * @param peer PeerInfo of the final peer for whom this path is being created. + * @param p Path itself. + * @param t Tunnel for which the path is created. + */ +static void +send_create_path (struct MeshPeerInfo *peer, struct MeshPeerPath *p, + struct MeshTunnel *t) +{ + struct GNUNET_PeerIdentity id; + struct MeshPathInfo *path_info; + struct MeshPeerInfo *neighbor; + unsigned int i; + + if (NULL == p) + { + p = tree_get_path_to_peer (t->tree, peer->id); + if (NULL == p) + { + GNUNET_break (0); + return; + } + } + for (i = 0; i < p->length; i++) + { + if (p->peers[i] == myid) + break; + } + if (i >= p->length - 1) + { + path_destroy (p); + GNUNET_break (0); + return; + } + GNUNET_PEER_resolve (p->peers[i + 1], &id); + + path_info = GNUNET_malloc (sizeof (struct MeshPathInfo)); + path_info->path = p; + path_info->t = t; + neighbor = peer_info_get (&id); + path_info->peer = neighbor; + path_info->pos = peer_info_transmit_slot (neighbor); + neighbor->types[path_info->pos] = GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE; + neighbor->infos[path_info->pos] = path_info; + neighbor->core_transmit[path_info->pos] = + GNUNET_CORE_notify_transmit_ready (core_handle, /* handle */ + 0, /* cork */ + 0, /* priority */ + GNUNET_TIME_UNIT_FOREVER_REL, /* timeout */ + &id, /* target */ + sizeof (struct GNUNET_MESH_ManipulatePath) + + (p->length * sizeof (struct GNUNET_PeerIdentity)), /*size */ + &send_core_create_path, /* callback */ + path_info); /* cls */ +} + + +/** + * Sends a DESTROY PATH message to free resources for a path in a tunnel + * + * @param t Tunnel whose path to destroy. + * @param destination Short ID of the peer to whom the path to destroy. + */ +static void +send_destroy_path (struct MeshTunnel *t, GNUNET_PEER_Id destination) +{ + struct MeshPeerPath *p; + size_t size; + + p = tree_get_path_to_peer (t->tree, destination); + if (NULL == p) + { + GNUNET_break (0); + return; + } + size = sizeof (struct GNUNET_MESH_ManipulatePath); + size += p->length * sizeof (struct GNUNET_PeerIdentity); + { + struct GNUNET_MESH_ManipulatePath *msg; + struct GNUNET_PeerIdentity *pi; + char cbuf[size]; + unsigned int i; + + msg = (struct GNUNET_MESH_ManipulatePath *) cbuf; + msg->header.size = htons (size); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_DESTROY); + msg->tid = htonl (t->id.tid); + pi = (struct GNUNET_PeerIdentity *) &msg[1]; + for (i = 0; i < p->length; i++) + { + GNUNET_PEER_resolve (p->peers[i], &pi[i]); + } + send_message (&msg->header, tree_get_first_hop (t->tree, destination)); + } + path_destroy (p); +} + + +/** + * Try to establish a new connection to this peer. + * Use the best path for the given tunnel. + * If the peer doesn't have any path to it yet, try to get one. + * If the peer already has some path, send a CREATE PATH towards it. + * + * @param peer PeerInfo of the peer. + * @param t Tunnel for which to create the path, if possible. + */ +static void +peer_info_connect (struct MeshPeerInfo *peer, struct MeshTunnel *t) +{ + struct MeshPeerPath *p; + struct MeshPathInfo *path_info; + + if (NULL != peer->path_head) + { + p = tree_get_path_to_peer (t->tree, peer->id); + if (NULL == p) + { + GNUNET_break (0); + return; + } + + // FIXME always send create path to self + if (p->length > 1) + { + send_create_path (peer, p, t); + } + else + { + GNUNET_HashCode hash; + + path_destroy (p); + send_client_peer_connected (t, myid); + t->local_tid_dest = next_local_tid++; + GNUNET_CRYPTO_hash (&t->local_tid_dest, sizeof (MESH_TunnelNumber), + &hash); + if (GNUNET_OK != + GNUNET_CONTAINER_multihashmap_put (incoming_tunnels, &hash, t, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + GNUNET_break (0); + return; + } + } + } + else if (NULL == peer->dhtget) + { + struct GNUNET_PeerIdentity id; + + GNUNET_PEER_resolve (peer->id, &id); + path_info = GNUNET_malloc (sizeof (struct MeshPathInfo)); + path_info->peer = peer; + path_info->t = t; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " Starting DHT GET for peer %s\n", GNUNET_i2s (&id)); + peer->dhtgetcls = path_info; + peer->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */ + GNUNET_TIME_UNIT_FOREVER_REL, /* timeout */ + GNUNET_BLOCK_TYPE_TEST, /* type */ + &id.hashPubKey, /* key to search */ + 10U, /* replication level */ + GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, /* xquery */ + 0, /* xquery bits */ + &dht_get_id_handler, path_info); + } + /* Otherwise, there is no path but the DHT get is already started. */ +} + + +/** + * Task to delay the connection of a peer + * + * @param cls Closure (path info with tunnel and peer to connect). + * Will be free'd on exection. + * @param tc TaskContext + */ +static void +peer_info_connect_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct MeshPathInfo *path_info = cls; + + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + { + GNUNET_free (cls); + return; + } + peer_info_connect (path_info->peer, path_info->t); + GNUNET_free (cls); +} + + +/** + * Destroy the peer_info and free any allocated resources linked to it + * + * @param pi The peer_info to destroy. + * + * @return GNUNET_OK on success + */ +static int +peer_info_destroy (struct MeshPeerInfo *pi) +{ + struct GNUNET_PeerIdentity id; + struct MeshPeerPath *p; + struct MeshPeerPath *nextp; + unsigned int i; + + GNUNET_PEER_resolve (pi->id, &id); + GNUNET_PEER_change_rc (pi->id, -1); + + if (GNUNET_YES != + GNUNET_CONTAINER_multihashmap_remove (peers, &id.hashPubKey, pi)) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "removing peer %s, not in hashmap\n", GNUNET_i2s (&id)); + } + if (NULL != pi->dhtget) + { + GNUNET_DHT_get_stop (pi->dhtget); + GNUNET_free (pi->dhtgetcls); + } + for (i = 0; i < CORE_QUEUE_SIZE; i++) + { + peer_info_cancel_transmission (pi, i); + } + p = pi->path_head; + while (NULL != p) + { + nextp = p->next; + GNUNET_CONTAINER_DLL_remove (pi->path_head, pi->path_tail, p); + path_destroy (p); + p = nextp; + } + GNUNET_free (pi); + return GNUNET_OK; +} + + +/** + * Remove all paths that rely on a direct connection between p1 and p2 + * from the peer itself and notify all tunnels about it. + * + * @param peer PeerInfo of affected peer. + * @param p1 GNUNET_PEER_Id of one peer. + * @param p2 GNUNET_PEER_Id of another peer that was connected to the first and + * no longer is. + * + * TODO: optimize (see below) + */ +static void +peer_info_remove_path (struct MeshPeerInfo *peer, GNUNET_PEER_Id p1, + GNUNET_PEER_Id p2) +{ + struct MeshPeerPath *p; + struct MeshPeerPath *aux; + struct MeshPeerInfo *peer_d; + GNUNET_PEER_Id d; + unsigned int destroyed; + unsigned int best; + unsigned int cost; + unsigned int i; + + destroyed = 0; + p = peer->path_head; + while (NULL != p) + { + aux = p->next; + for (i = 0; i < (p->length - 1); i++) + { + if ((p->peers[i] == p1 && p->peers[i + 1] == p2) || + (p->peers[i] == p2 && p->peers[i + 1] == p1)) + { + GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p); + path_destroy (p); + destroyed++; + break; + } + } + p = aux; + } + if (0 == destroyed) + return; + + for (i = 0; i < peer->ntunnels; i++) + { + d = tunnel_notify_connection_broken (peer->tunnels[i], p1, p2); + if (0 == d) + continue; + /* TODO + * Problem: one or more peers have been deleted from the tunnel tree. + * We don't know who they are to try to add them again. + * We need to try to find a new path for each of the disconnected peers. + * Some of them might already have a path to reach them that does not + * involve p1 and p2. Adding all anew might render in a better tree than + * the trivial immediate fix. + * + * Trivial immiediate fix: try to reconnect to the disconnected node. All + * its children will be reachable trough him. + */ + peer_d = peer_info_get_short (d); + best = UINT_MAX; + aux = NULL; + for (p = peer_d->path_head; NULL != p; p = p->next) + { + if ((cost = tree_get_path_cost (peer->tunnels[i]->tree, p)) < best) + { + best = cost; + aux = p; + } + } + if (NULL != aux) + { + /* No callback, as peer will be already disconnected and a connection + * scheduled by tunnel_notify_connection_broken. + */ + tree_add_path (peer->tunnels[i]->tree, aux, NULL, NULL); + } + else + { + peer_info_connect (peer_d, peer->tunnels[i]); + } + } +} + + +/** + * Add the path to the peer and update the path used to reach it in case this + * is the shortest. + * + * @param peer_info Destination peer to add the path to. + * @param path New path to add. Last peer must be the peer in arg 1. + * Path will be either used of freed if already known. + * @param trusted Do we trust that this path is real? + */ +void +peer_info_add_path (struct MeshPeerInfo *peer_info, struct MeshPeerPath *path, + int trusted) +{ + struct MeshPeerPath *aux; + unsigned int l; + unsigned int l2; + + if ((NULL == peer_info) || (NULL == path)) + { + GNUNET_break (0); + path_destroy (path); + return; + } + if (path->peers[path->length - 1] != peer_info->id) + { + GNUNET_break (0); + path_destroy (path); + return; + } + if (path->length <= 2 && GNUNET_NO == trusted) + { + /* Only allow CORE to tell us about direct paths */ + path_destroy (path); + return; + } + GNUNET_assert (peer_info->id == path->peers[path->length - 1]); + for (l = 1; l < path->length; l++) + { + if (path->peers[l] == myid) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shortening path by %u\n", l); + for (l2 = 0; l2 < path->length - l; l2++) + { + path->peers[l2] = path->peers[l + l2]; + } + path->length -= l; + l = 1; + path->peers = + GNUNET_realloc (path->peers, path->length * sizeof (GNUNET_PEER_Id)); + } + } +#if MESH_DEBUG + { + struct GNUNET_PeerIdentity id; + + GNUNET_PEER_resolve (peer_info->id, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "adding path [%u] to peer %s\n", + path->length, GNUNET_i2s (&id)); + } +#endif + l = path_get_length (path); + if (0 == l) + { + GNUNET_free (path); + return; + } + + GNUNET_assert (peer_info->id == path->peers[path->length - 1]); + for (aux = peer_info->path_head; aux != NULL; aux = aux->next) + { + l2 = path_get_length (aux); + if (l2 > l) + { + GNUNET_CONTAINER_DLL_insert_before (peer_info->path_head, + peer_info->path_tail, aux, path); + return; + } + else + { + if (l2 == l && memcmp (path->peers, aux->peers, l) == 0) + { + path_destroy (path); + return; + } + } + } + GNUNET_CONTAINER_DLL_insert_tail (peer_info->path_head, peer_info->path_tail, + path); + return; +} + + +/** + * Add the path to the origin peer and update the path used to reach it in case + * this is the shortest. + * The path is given in peer_info -> destination, therefore we turn the path + * upside down first. + * + * @param peer_info Peer to add the path to, being the origin of the path. + * @param path New path to add after being inversed. + * @param trusted Do we trust that this path is real? + */ +static void +peer_info_add_path_to_origin (struct MeshPeerInfo *peer_info, + struct MeshPeerPath *path, int trusted) +{ + path_invert (path); + peer_info_add_path (peer_info, path, trusted); +} + + +/** + * Build a PeerPath from the paths returned from the DHT, reversing the paths + * to obtain a local peer -> destination path and interning the peer ids. + * + * @return Newly allocated and created path + */ +static struct MeshPeerPath * +path_build_from_dht (const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length) +{ + struct MeshPeerPath *p; + GNUNET_PEER_Id id; + int i; + + p = path_new (1); + p->peers[0] = myid; + GNUNET_PEER_change_rc (myid, 1); + i = get_path_length; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", i); + for (i--; i >= 0; i--) + { + id = GNUNET_PEER_intern (&get_path[i]); + if (p->length > 0 && id == p->peers[p->length - 1]) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n"); + GNUNET_PEER_change_rc (id, -1); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Adding from GET: %s.\n", + GNUNET_i2s (&get_path[i])); + p->length++; + p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length); + p->peers[p->length - 1] = id; + } + } + i = put_path_length; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " PUT has %d hops.\n", i); + for (i--; i >= 0; i--) + { + id = GNUNET_PEER_intern (&put_path[i]); + if (id == myid) + { + /* PUT path went through us, so discard the path up until now and start + * from here to get a much shorter (and loop-free) path. + */ + path_destroy (p); + p = path_new (0); + } + if (p->length > 0 && id == p->peers[p->length - 1]) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n"); + GNUNET_PEER_change_rc (id, -1); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Adding from PUT: %s.\n", + GNUNET_i2s (&put_path[i])); + p->length++; + p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length); + p->peers[p->length - 1] = id; + } + } +#if MESH_DEBUG + if (get_path_length > 0) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (first of GET: %s)\n", + GNUNET_i2s (&get_path[0])); + if (put_path_length > 0) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (first of PUT: %s)\n", + GNUNET_i2s (&put_path[0])); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " In total: %d hops\n", + p->length); + for (i = 0; i < p->length; i++) + { + struct GNUNET_PeerIdentity peer_id; + + GNUNET_PEER_resolve (p->peers[i], &peer_id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", p->peers[i], + GNUNET_i2s (&peer_id)); + } +#endif + return p; +} + + +/** + * Adds a path to the peer_infos of all the peers in the path + * + * @param p Path to process. + * @param confirmed Whether we know if the path works or not. FIXME use + */ +static void +path_add_to_peers (struct MeshPeerPath *p, int confirmed) +{ + unsigned int i; + + /* TODO: invert and add */ + for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ; + for (i++; i < p->length; i++) + { + struct MeshPeerInfo *aux; + struct MeshPeerPath *copy; + + aux = peer_info_get_short (p->peers[i]); + copy = path_duplicate (p); + copy->length = i + 1; + peer_info_add_path (aux, copy, GNUNET_NO); + } +} + + +/** + * Send keepalive packets for a peer + * + * @param cls Closure (tunnel for which to send the keepalive). + * @param tc Notification context. + * + * TODO: implement explicit multicast keepalive? + */ +static void +path_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Search for a tunnel among the incoming tunnels + * + * @param tid the local id of the tunnel + * + * @return tunnel handler, NULL if doesn't exist + */ +static struct MeshTunnel * +tunnel_get_incoming (MESH_TunnelNumber tid) +{ + GNUNET_HashCode hash; + + GNUNET_assert (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV); + GNUNET_CRYPTO_hash (&tid, sizeof (MESH_TunnelNumber), &hash); + return GNUNET_CONTAINER_multihashmap_get (incoming_tunnels, &hash); +} + + +/** + * Search for a tunnel among the tunnels for a client + * + * @param c the client whose tunnels to search in + * @param tid the local id of the tunnel + * + * @return tunnel handler, NULL if doesn't exist + */ +static struct MeshTunnel * +tunnel_get_by_local_id (struct MeshClient *c, MESH_TunnelNumber tid) +{ + if (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) + { + return tunnel_get_incoming (tid); + } + else + { + GNUNET_HashCode hash; + + GNUNET_CRYPTO_hash (&tid, sizeof (MESH_TunnelNumber), &hash); + return GNUNET_CONTAINER_multihashmap_get (c->own_tunnels, &hash); + } +} + + +/** + * Search for a tunnel by global ID using PEER_ID + * + * @param pi owner of the tunnel + * @param tid global tunnel number + * + * @return tunnel handler, NULL if doesn't exist + */ +static struct MeshTunnel * +tunnel_get_by_pi (GNUNET_PEER_Id pi, MESH_TunnelNumber tid) +{ + struct MESH_TunnelID id; + GNUNET_HashCode hash; + + id.oid = pi; + id.tid = tid; + + GNUNET_CRYPTO_hash (&id, sizeof (struct MESH_TunnelID), &hash); + return GNUNET_CONTAINER_multihashmap_get (tunnels, &hash); +} + + +/** + * Search for a tunnel by global ID using full PeerIdentities + * + * @param oid owner of the tunnel + * @param tid global tunnel number + * + * @return tunnel handler, NULL if doesn't exist + */ +static struct MeshTunnel * +tunnel_get (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid) +{ + return tunnel_get_by_pi (GNUNET_PEER_search (oid), tid); +} + + +/** + * Delete an active client from the tunnel. + * + * @param t Tunnel. + * @param c Client. + */ +static void +tunnel_delete_active_client (struct MeshTunnel *t, const struct MeshClient *c) +{ + unsigned int i; + + for (i = 0; i < t->nclients; i++) + { + if (t->clients[i] == c) + { + t->clients[i] = t->clients[t->nclients - 1]; + GNUNET_array_grow (t->clients, t->nclients, t->nclients - 1); + break; + } + } +} + + +/** + * Delete an ignored client from the tunnel. + * + * @param t Tunnel. + * @param c Client. + */ +static void +tunnel_delete_ignored_client (struct MeshTunnel *t, const struct MeshClient *c) +{ + unsigned int i; + + for (i = 0; i < t->nignore; i++) + { + if (t->ignore[i] == c) + { + t->ignore[i] = t->ignore[t->nignore - 1]; + GNUNET_array_grow (t->ignore, t->nignore, t->nignore - 1); + break; + } + } +} + + +/** + * Delete a client from the tunnel. It should be only done on + * client disconnection, otherwise use client_ignore_tunnel. + * + * @param t Tunnel. + * @param c Client. + */ +static void +tunnel_delete_client (struct MeshTunnel *t, const struct MeshClient *c) +{ + tunnel_delete_ignored_client (t, c); + tunnel_delete_active_client (t, c); +} + + +/** + * Callback used to notify a client owner of a tunnel that a peer has + * disconnected, most likely because of a path change. + * + * @param cls Closure (tunnel this notification is about). + * @param peer_id Short ID of disconnected peer. + */ +void +notify_peer_disconnected (void *cls, GNUNET_PEER_Id peer_id) +{ + struct MeshTunnel *t = cls; + struct MeshPeerInfo *peer; + struct MeshPathInfo *path_info; + + if (NULL != t->owner && NULL != nc) + { + struct GNUNET_MESH_PeerControl msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL); + msg.tunnel_id = htonl (t->local_tid); + GNUNET_PEER_resolve (peer_id, &msg.peer); + GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle, + &msg.header, GNUNET_NO); + } + peer = peer_info_get_short (peer_id); + path_info = GNUNET_malloc (sizeof (struct MeshPathInfo)); + path_info->peer = peer; + path_info->t = t; + GNUNET_SCHEDULER_add_now (&peer_info_connect_task, path_info); +} + + +/** + * Add a peer to a tunnel, accomodating paths accordingly and initializing all + * needed rescources. + * If peer already exists, reevaluate shortest path and change if different. + * + * @param t Tunnel we want to add a new peer to + * @param peer PeerInfo of the peer being added + * + */ +static void +tunnel_add_peer (struct MeshTunnel *t, struct MeshPeerInfo *peer) +{ + struct GNUNET_PeerIdentity id; + struct MeshPeerPath *best_p; + struct MeshPeerPath *p; + unsigned int best_cost; + unsigned int cost; + + GNUNET_PEER_resolve (peer->id, &id); + if (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (t->peers, &id.hashPubKey)) + { + t->peers_total++; + GNUNET_array_append (peer->tunnels, peer->ntunnels, t); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (t->peers, &id.hashPubKey, + peer, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); + } + + if (NULL != (p = peer->path_head)) + { + best_p = p; + best_cost = tree_get_path_cost (t->tree, p); + while (NULL != p) + { + if ((cost = tree_get_path_cost (t->tree, p)) < best_cost) + { + best_cost = cost; + best_p = p; + } + p = p->next; + } + tree_add_path (t->tree, best_p, ¬ify_peer_disconnected, t); + if (GNUNET_SCHEDULER_NO_TASK == t->path_refresh_task) + t->path_refresh_task = + GNUNET_SCHEDULER_add_delayed (REFRESH_PATH_TIME, &path_refresh, t); + } + else + { + /* Start a DHT get */ + peer_info_connect (peer, t); + } +} + +/** + * Add a path to a tunnel which we don't own, just to remember the next hop. + * If destination node was already in the tunnel, the first hop information + * will be replaced with the new path. + * + * @param t Tunnel we want to add a new peer to + * @param p Path to add + * @param own_pos Position of local node in path. + * + */ +static void +tunnel_add_path (struct MeshTunnel *t, struct MeshPeerPath *p, + unsigned int own_pos) +{ + struct GNUNET_PeerIdentity id; + + GNUNET_assert (0 != own_pos); + tree_add_path (t->tree, p, NULL, NULL); + if (own_pos < p->length - 1) + { + GNUNET_PEER_resolve (p->peers[own_pos + 1], &id); + tree_update_first_hops (t->tree, myid, &id); + } +} + + +/** + * Notifies a tunnel that a connection has broken that affects at least + * some of its peers. Sends a notification towards the root of the tree. + * In case the peer is the owner of the tree, notifies the client that owns + * the tunnel and tries to reconnect. + * + * @param t Tunnel affected. + * @param p1 Peer that got disconnected from p2. + * @param p2 Peer that got disconnected from p1. + * + * @return Short ID of the peer disconnected (either p1 or p2). + * 0 if the tunnel remained unaffected. + */ +static GNUNET_PEER_Id +tunnel_notify_connection_broken (struct MeshTunnel *t, GNUNET_PEER_Id p1, + GNUNET_PEER_Id p2) +{ + GNUNET_PEER_Id pid; + + pid = + tree_notify_connection_broken (t->tree, p1, p2, ¬ify_peer_disconnected, + t); + if (myid != p1 && myid != p2) + { + return pid; + } + if (pid != myid) + { + if (tree_get_predecessor (t->tree) != 0) + { + /* We are the peer still connected, notify owner of the disconnection. */ + struct GNUNET_MESH_PathBroken msg; + struct GNUNET_PeerIdentity neighbor; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_BROKEN); + GNUNET_PEER_resolve (t->id.oid, &msg.oid); + msg.tid = htonl (t->id.tid); + msg.peer1 = my_full_id; + GNUNET_PEER_resolve (pid, &msg.peer2); + GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &neighbor); + send_message (&msg.header, &neighbor); + } + } + return pid; +} + + +/** + * Send a multicast packet to a neighbor. + * + * @param cls Closure (Info about the multicast packet) + * @param neighbor_id Short ID of the neighbor to send the packet to. + */ +static void +tunnel_send_multicast_iterator (void *cls, GNUNET_PEER_Id neighbor_id) +{ + struct MeshData *mdata = cls; + struct MeshTransmissionDescriptor *info; + struct GNUNET_PeerIdentity neighbor; + unsigned int i; + + info = GNUNET_malloc (sizeof (struct MeshTransmissionDescriptor)); + + info->mesh_data = mdata; + (*(mdata->reference_counter)) ++; + info->destination = neighbor_id; + GNUNET_PEER_resolve (neighbor_id, &neighbor); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " sending to %s...\n", + GNUNET_i2s (&neighbor)); + info->peer = peer_info_get (&neighbor); + GNUNET_assert (NULL != info->peer); + i = peer_info_transmit_slot (info->peer); + info->handler_n = i; + info->peer->infos[i] = info; + info->peer->types[i] = GNUNET_MESSAGE_TYPE_MESH_MULTICAST; + info->peer->core_transmit[i] = + GNUNET_CORE_notify_transmit_ready (core_handle, 0, 0, + GNUNET_TIME_UNIT_FOREVER_REL, + &neighbor, info->mesh_data->data_len, + &send_core_data_multicast, info); +} + +/** + * Send a message in a tunnel in multicast, sending a copy to each child node + * down the local one in the tunnel tree. + * + * @param t Tunnel in which to send the data. + * @param msg Message to be sent. + * @param internal Has the service generated this message? + */ +static void +tunnel_send_multicast (struct MeshTunnel *t, + const struct GNUNET_MessageHeader *msg, + int internal) +{ + struct MeshData *mdata; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " sending a multicast packet...\n"); + mdata = GNUNET_malloc (sizeof (struct MeshData)); + mdata->data_len = ntohs (msg->size); + mdata->reference_counter = GNUNET_malloc (sizeof (unsigned int)); + mdata->t = t; + mdata->data = GNUNET_malloc (mdata->data_len); + memcpy (mdata->data, msg, mdata->data_len); + if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_MESH_MULTICAST) + { + struct GNUNET_MESH_Multicast *mcast; + + mcast = (struct GNUNET_MESH_Multicast *) mdata->data; + mcast->ttl = htonl (ntohl (mcast->ttl) - 1); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " data packet, ttl: %u\n", + ntohl (mcast->ttl)); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " not a data packet, no ttl\n"); + } + if (NULL != t->owner && GNUNET_YES != t->owner->shutting_down + && GNUNET_NO == internal) + { + mdata->task = GNUNET_malloc (sizeof (GNUNET_SCHEDULER_TaskIdentifier)); + (*(mdata->task)) = + GNUNET_SCHEDULER_add_delayed (UNACKNOWLEDGED_WAIT, &client_allow_send, + mdata); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "timeout task %u\n", + *(mdata->task)); + } + + tree_iterate_children (t->tree, &tunnel_send_multicast_iterator, mdata); + if (*(mdata->reference_counter) == 0) + { + GNUNET_free (mdata->data); + GNUNET_free (mdata->reference_counter); + if (NULL != mdata->task) + { + GNUNET_SCHEDULER_cancel(*(mdata->task)); + GNUNET_free (mdata->task); + GNUNET_SERVER_receive_done(t->owner->handle, GNUNET_OK); + } + // FIXME change order? + GNUNET_free (mdata); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " sending a multicast packet done\n"); + return; +} + + +/** + * Send a message to all peers in this tunnel that the tunnel is no longer + * valid. + * + * @param t The tunnel whose peers to notify. + */ +static void +tunnel_send_destroy (struct MeshTunnel *t) +{ + struct GNUNET_MESH_TunnelDestroy msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY); + GNUNET_PEER_resolve (t->id.oid, &msg.oid); + msg.tid = htonl (t->id.tid); + tunnel_send_multicast (t, &msg.header, GNUNET_NO); +} + + + +/** + * Destroy the tunnel and free any allocated resources linked to it. + * + * @param t the tunnel to destroy + * + * @return GNUNET_OK on success + */ +static int +tunnel_destroy (struct MeshTunnel *t) +{ + struct MeshClient *c; + struct MeshQueue *q; + struct MeshQueue *qn; + GNUNET_HashCode hash; + unsigned int i; + int r; + + if (NULL == t) + return GNUNET_OK; + + r = GNUNET_OK; + c = t->owner; +#if MESH_DEBUG + { + struct GNUNET_PeerIdentity id; + + GNUNET_PEER_resolve (t->id.oid, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s [%x]\n", + GNUNET_i2s (&id), t->id.tid); + if (NULL != c) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); + } +#endif + + GNUNET_CRYPTO_hash (&t->id, sizeof (struct MESH_TunnelID), &hash); + if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (tunnels, &hash, t)) + { + r = GNUNET_SYSERR; + } + + GNUNET_CRYPTO_hash (&t->local_tid, sizeof (MESH_TunnelNumber), &hash); + if (NULL != c && + GNUNET_YES != + GNUNET_CONTAINER_multihashmap_remove (c->own_tunnels, &hash, t)) + { + r = GNUNET_SYSERR; + } + GNUNET_CRYPTO_hash (&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); + for (i = 0; i < t->nclients; i++) + { + c = t->clients[i]; + if (GNUNET_YES != + GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels, &hash, t)) + { + r = GNUNET_SYSERR; + } + } + for (i = 0; i < t->nignore; i++) + { + c = t->ignore[i]; + if (GNUNET_YES != + GNUNET_CONTAINER_multihashmap_remove (c->ignore_tunnels, &hash, t)) + { + r = GNUNET_SYSERR; + } + } + if (t->nclients > 0) + { + if (GNUNET_YES != + GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels, &hash, t)) + { + r = GNUNET_SYSERR; + } + GNUNET_free (t->clients); + } + if (NULL != t->peers) + { + GNUNET_CONTAINER_multihashmap_iterate (t->peers, &peer_info_delete_tunnel, + t); + GNUNET_CONTAINER_multihashmap_destroy (t->peers); + } + q = t->queue_head; + while (NULL != q) + { + if (NULL != q->data) + GNUNET_free (q->data); + qn = q->next; + GNUNET_free (q); + q = qn; + /* TODO cancel core transmit ready in case it was active */ + } + tree_destroy (t->tree); + if (NULL != t->dht_get_type) + GNUNET_DHT_get_stop (t->dht_get_type); + if (GNUNET_SCHEDULER_NO_TASK != t->timeout_task) + GNUNET_SCHEDULER_cancel (t->timeout_task); + if (GNUNET_SCHEDULER_NO_TASK != t->path_refresh_task) + GNUNET_SCHEDULER_cancel (t->path_refresh_task); + GNUNET_free (t); + return r; +} + + +/** + * Removes an explicit path from a tunnel, freeing all intermediate nodes + * that are no longer needed, as well as nodes of no longer reachable peers. + * The tunnel itself is also destoyed if results in a remote empty tunnel. + * + * @param t Tunnel from which to remove the path. + * @param peer Short id of the peer which should be removed. + */ +static void +tunnel_delete_peer (struct MeshTunnel *t, GNUNET_PEER_Id peer) +{ + if (GNUNET_NO == tree_del_peer (t->tree, peer, NULL, NULL)) + tunnel_destroy (t); +} + + +/** + * tunnel_destroy_iterator: iterator for deleting each tunnel that belongs to a + * client when the client disconnects. If the client is not the owner, the + * owner will get notified if no more clients are in the tunnel and the client + * get removed from the tunnel's list. + * + * @param cls closure (client that is disconnecting) + * @param key the hash of the local tunnel id (used to access the hashmap) + * @param value the value stored at the key (tunnel to destroy) + * + * @return GNUNET_OK on success + */ +static int +tunnel_destroy_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct MeshTunnel *t = value; + struct MeshClient *c = cls; + int r; + + send_client_tunnel_disconnect(t, c); + if (c != t->owner) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client %u is destination, keeping the tunnel alive.\n", c->id); + tunnel_delete_client(t, c); + client_delete_tunnel(c, t); + return GNUNET_OK; + } + tunnel_send_destroy(t); + r = tunnel_destroy (t); + return r; +} + + +/** + * Timeout function, destroys tunnel if called + * + * @param cls Closure (tunnel to destroy). + * @param tc TaskContext + */ +static void +tunnel_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct MeshTunnel *t = cls; + + if (GNUNET_SCHEDULER_REASON_SHUTDOWN == tc->reason) + return; + t->timeout_task = GNUNET_SCHEDULER_NO_TASK; + tunnel_destroy (t); +} + +/** + * Resets the tunnel timeout. Starts it if no timeout was running. + * + * @param t Tunnel whose timeout to reset. + */ +static void +tunnel_reset_timeout (struct MeshTunnel *t) +{ + if (GNUNET_SCHEDULER_NO_TASK != t->timeout_task) + GNUNET_SCHEDULER_cancel (t->timeout_task); + t->timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (REFRESH_PATH_TIME, 4), &tunnel_timeout, t); +} + + +/******************************************************************************/ +/**************** MESH NETWORK HANDLER HELPERS ***********************/ +/******************************************************************************/ + +/** + * Function called to notify a client about the socket + * being ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +send_core_create_path (void *cls, size_t size, void *buf) +{ + struct MeshPathInfo *info = cls; + struct GNUNET_MESH_ManipulatePath *msg; + struct GNUNET_PeerIdentity *peer_ptr; + struct MeshPeerInfo *peer = info->peer; + struct MeshTunnel *t = info->t; + struct MeshPeerPath *p = info->path; + size_t size_needed; + int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATE PATH sending...\n"); + size_needed = + sizeof (struct GNUNET_MESH_ManipulatePath) + + p->length * sizeof (struct GNUNET_PeerIdentity); + + if (size < size_needed || NULL == buf) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "create path retransmit!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " buf: %p\n", buf); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " size: (%u/%u)\n", size, + size_needed); + info->peer->core_transmit[info->pos] = + GNUNET_CORE_notify_transmit_ready (core_handle, 0, 0, + GNUNET_TIME_UNIT_FOREVER_REL, + tree_get_first_hop (t->tree, + peer->id), + size_needed, &send_core_create_path, + info); + return 0; + } + info->peer->core_transmit[info->pos] = NULL; +#if MESH_DEBUG + { + struct GNUNET_PeerIdentity id; + + GNUNET_PEER_resolve (peer->id, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " setting core_transmit %s [%u] to NULL\n", + GNUNET_i2s (&id), info->pos); + } +#endif + msg = (struct GNUNET_MESH_ManipulatePath *) buf; + msg->header.size = htons (size_needed); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE); + msg->tid = ntohl (t->id.tid); + + peer_ptr = (struct GNUNET_PeerIdentity *) &msg[1]; + for (i = 0; i < p->length; i++) + { + GNUNET_PEER_resolve (p->peers[i], peer_ptr++); + } + + path_destroy (p); + GNUNET_free (info); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CREATE PATH (%u bytes long) sent!\n", size_needed); + return size_needed; +} + + +/** + * Function called to notify a client about the socket + * being ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure (data itself) + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * + * @return number of bytes written to buf + */ +static size_t +send_core_data_multicast (void *cls, size_t size, void *buf) +{ + struct MeshTransmissionDescriptor *info = cls; + size_t total_size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Multicast callback.\n"); + GNUNET_assert (NULL != info); + GNUNET_assert (NULL != info->peer); + total_size = info->mesh_data->data_len; + GNUNET_assert (total_size < GNUNET_SERVER_MAX_MESSAGE_SIZE); + + if (total_size > size) + { + /* Retry */ + struct GNUNET_PeerIdentity id; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Multicast: retransmitting... (%u/%u)\n", size, + total_size); + GNUNET_PEER_resolve (info->peer->id, &id); + info->peer->core_transmit[info->handler_n] = + GNUNET_CORE_notify_transmit_ready (core_handle, 0, 0, + GNUNET_TIME_UNIT_FOREVER_REL, &id, + total_size, + &send_core_data_multicast, info); + return 0; + } + info->peer->core_transmit[info->handler_n] = NULL; + info->peer->infos[info->handler_n] = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " copying data...\n"); + memcpy (buf, info->mesh_data->data, total_size); +#if MESH_DEBUG + { + struct GNUNET_MESH_Multicast *mc; + struct GNUNET_MessageHeader *mh; + + mh = buf; + if (ntohs (mh->type) == GNUNET_MESSAGE_TYPE_MESH_MULTICAST) + { + mc = (struct GNUNET_MESH_Multicast *) mh; + mh = (struct GNUNET_MessageHeader *) &mc[1]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " multicast, payload type %u\n", ntohs (mh->type)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " multicast, payload size %u\n", ntohs (mh->size)); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " type %u\n", + ntohs (mh->type)); + } + } +#endif + data_descriptor_decrement_multicast (info->mesh_data); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "freeing info...\n"); + GNUNET_free (info); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "return %u\n", total_size); + return total_size; +} + + +/** + * Function called to notify a client about the socket + * being ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure (MeshTransmissionDescriptor) + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +send_core_path_ack (void *cls, size_t size, void *buf) +{ + struct MeshTransmissionDescriptor *info = cls; + struct GNUNET_MESH_PathACK *msg = buf; + + GNUNET_assert (NULL != info); + if (info->peer) + { + info->peer->core_transmit[info->handler_n] = NULL; + } + if (sizeof (struct GNUNET_MESH_PathACK) > size) + { + GNUNET_break (0); + return 0; + } + msg->header.size = htons (sizeof (struct GNUNET_MESH_PathACK)); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_ACK); + GNUNET_PEER_resolve (info->origin->oid, &msg->oid); + msg->tid = htonl (info->origin->tid); + msg->peer_id = my_full_id; + GNUNET_free (info); + /* TODO add signature */ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH ACK sent!\n"); + return sizeof (struct GNUNET_MESH_PathACK); +} + + +/******************************************************************************/ +/******************** MESH NETWORK HANDLERS **************************/ +/******************************************************************************/ + + +/** + * Core handler for path creation + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + unsigned int own_pos; + uint16_t size; + uint16_t i; + MESH_TunnelNumber tid; + struct GNUNET_MESH_ManipulatePath *msg; + struct GNUNET_PeerIdentity *pi; + GNUNET_HashCode hash; + struct MeshPeerPath *path; + struct MeshPeerInfo *dest_peer_info; + struct MeshPeerInfo *orig_peer_info; + struct MeshTunnel *t; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received a path create msg [%s]\n", + GNUNET_i2s (&my_full_id)); + size = ntohs (message->size); + if (size < sizeof (struct GNUNET_MESH_ManipulatePath)) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + + size -= sizeof (struct GNUNET_MESH_ManipulatePath); + if (size % sizeof (struct GNUNET_PeerIdentity)) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + size /= sizeof (struct GNUNET_PeerIdentity); + if (size < 2) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size); + msg = (struct GNUNET_MESH_ManipulatePath *) message; + + tid = ntohl (msg->tid); + pi = (struct GNUNET_PeerIdentity *) &msg[1]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " path is for tunnel %s [%X].\n", GNUNET_i2s (pi), tid); + t = tunnel_get (pi, tid); + if (NULL == t) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating tunnel\n"); + t = GNUNET_malloc (sizeof (struct MeshTunnel)); + t->id.oid = GNUNET_PEER_intern (pi); + t->id.tid = tid; + while (NULL != tunnel_get_incoming (next_local_tid)) + next_local_tid = (next_local_tid + 1) | GNUNET_MESH_LOCAL_TUNNEL_ID_SERV; + t->local_tid_dest = next_local_tid++; + next_local_tid = next_local_tid | GNUNET_MESH_LOCAL_TUNNEL_ID_SERV; + t->tree = tree_new (t->id.oid); + + GNUNET_CRYPTO_hash (&t->id, sizeof (struct MESH_TunnelID), &hash); + if (GNUNET_OK != + GNUNET_CONTAINER_multihashmap_put (tunnels, &hash, t, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + tunnel_destroy (t); + GNUNET_break (0); + return GNUNET_OK; + } + tunnel_reset_timeout (t); + GNUNET_CRYPTO_hash (&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); + if (GNUNET_OK != + GNUNET_CONTAINER_multihashmap_put (incoming_tunnels, &hash, t, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + tunnel_destroy (t); + GNUNET_break (0); + return GNUNET_OK; + } + } + dest_peer_info = + GNUNET_CONTAINER_multihashmap_get (peers, &pi[size - 1].hashPubKey); + if (NULL == dest_peer_info) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " Creating PeerInfo for destination.\n"); + dest_peer_info = GNUNET_malloc (sizeof (struct MeshPeerInfo)); + dest_peer_info->id = GNUNET_PEER_intern (&pi[size - 1]); + GNUNET_CONTAINER_multihashmap_put (peers, &pi[size - 1].hashPubKey, + dest_peer_info, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + } + orig_peer_info = GNUNET_CONTAINER_multihashmap_get (peers, &pi->hashPubKey); + if (NULL == orig_peer_info) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " Creating PeerInfo for origin.\n"); + orig_peer_info = GNUNET_malloc (sizeof (struct MeshPeerInfo)); + orig_peer_info->id = GNUNET_PEER_intern (pi); + GNUNET_CONTAINER_multihashmap_put (peers, &pi->hashPubKey, orig_peer_info, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n"); + path = path_new (size); + own_pos = 0; + for (i = 0; i < size; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ... adding %s\n", + GNUNET_i2s (&pi[i])); + path->peers[i] = GNUNET_PEER_intern (&pi[i]); + if (path->peers[i] == myid) + own_pos = i; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos); + if (own_pos == 0) + { + /* cannot be self, must be 'not found' */ + /* create path: self not found in path through self */ + GNUNET_break_op (0); + path_destroy (path); + /* FIXME error. destroy tunnel? leave for timeout? */ + return 0; + } + path_add_to_peers (path, GNUNET_NO); + tunnel_add_path (t, path, own_pos); + if (own_pos == size - 1) + { + /* It is for us! Send ack. */ + struct MeshTransmissionDescriptor *info; + unsigned int j; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n"); + peer_info_add_path_to_origin (orig_peer_info, path, GNUNET_NO); + if (NULL == t->peers) + { + /* New tunnel! Notify clients on data. */ + t->peers = GNUNET_CONTAINER_multihashmap_create (4); + } + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (t->peers, + &my_full_id.hashPubKey, + peer_info_get + (&my_full_id), + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); + /* FIXME use send_message */ + info = GNUNET_malloc (sizeof (struct MeshTransmissionDescriptor)); + info->origin = &t->id; + info->peer = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); + GNUNET_assert (NULL != info->peer); + j = peer_info_transmit_slot (info->peer); + info->handler_n = j; + info->peer->types[j] = GNUNET_MESSAGE_TYPE_MESH_PATH_ACK; + info->peer->infos[j] = info; + info->peer->core_transmit[j] = + GNUNET_CORE_notify_transmit_ready (core_handle, 0, 100, + GNUNET_TIME_UNIT_FOREVER_REL, peer, + sizeof (struct GNUNET_MESH_PathACK), + &send_core_path_ack, info); + } + else + { + struct MeshPeerPath *path2; + + /* It's for somebody else! Retransmit. */ + path2 = path_duplicate (path); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Retransmitting.\n"); + peer_info_add_path (dest_peer_info, path2, GNUNET_NO); + path2 = path_duplicate (path); + peer_info_add_path_to_origin (orig_peer_info, path2, GNUNET_NO); + send_create_path (dest_peer_info, path, t); + } + return GNUNET_OK; +} + + +/** + * Core handler for path destruction + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_mesh_path_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_MESH_ManipulatePath *msg; + struct GNUNET_PeerIdentity *pi; + struct MeshPeerPath *path; + struct MeshTunnel *t; + unsigned int own_pos; + unsigned int i; + size_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received a PATH DESTROY msg from %s\n", GNUNET_i2s (peer)); + size = ntohs (message->size); + if (size < sizeof (struct GNUNET_MESH_ManipulatePath)) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + + size -= sizeof (struct GNUNET_MESH_ManipulatePath); + if (size % sizeof (struct GNUNET_PeerIdentity)) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + size /= sizeof (struct GNUNET_PeerIdentity); + if (size < 2) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size); + + msg = (struct GNUNET_MESH_ManipulatePath *) message; + pi = (struct GNUNET_PeerIdentity *) &msg[1]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " path is for tunnel %s [%X].\n", GNUNET_i2s (pi), + msg->tid); + t = tunnel_get (pi, ntohl (msg->tid)); + if (NULL == t) + { + /* TODO notify back: we don't know this tunnel */ + GNUNET_break_op (0); + return GNUNET_OK; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n"); + path = path_new (size); + own_pos = 0; + for (i = 0; i < size; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ... adding %s\n", + GNUNET_i2s (&pi[i])); + path->peers[i] = GNUNET_PEER_intern (&pi[i]); + if (path->peers[i] == myid) + own_pos = i; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos); + if (own_pos < path->length - 1) + send_message (message, &pi[own_pos + 1]); + else + send_client_tunnel_disconnect(t, NULL); + + tunnel_delete_peer (t, path->peers[path->length - 1]); + path_destroy (path); + return GNUNET_OK; +} + + +/** + * Core handler for notifications of broken paths + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_mesh_path_broken (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_MESH_PathBroken *msg; + struct MeshTunnel *t; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received a PATH BROKEN msg from %s\n", GNUNET_i2s (peer)); + msg = (struct GNUNET_MESH_PathBroken *) message; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", + GNUNET_i2s (&msg->peer1)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", + GNUNET_i2s (&msg->peer2)); + t = tunnel_get (&msg->oid, ntohl (msg->tid)); + if (NULL == t) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + tunnel_notify_connection_broken (t, GNUNET_PEER_search (&msg->peer1), + GNUNET_PEER_search (&msg->peer2)); + return GNUNET_OK; + +} + + +/** + * Core handler for tunnel destruction + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_mesh_tunnel_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_MESH_TunnelDestroy *msg; + struct MeshTunnel *t; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got a TUNNEL DESTROY packet from %s\n", GNUNET_i2s (peer)); + msg = (struct GNUNET_MESH_TunnelDestroy *) message; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for tunnel %s [%u]\n", + GNUNET_i2s (&msg->oid), ntohl (msg->tid)); + t = tunnel_get (&msg->oid, ntohl (msg->tid)); + if (NULL == t) + { + /* Probably already got the message from another path, + * destroyed the tunnel and retransmitted to children. + * Safe to ignore. + */ + return GNUNET_OK; + } + if (t->id.oid == myid) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + if (t->local_tid_dest >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) + { + /* Tunnel was incoming, notify clients */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "INCOMING TUNNEL %X %X\n", + t->local_tid, t->local_tid_dest); + send_clients_tunnel_destroy (t); + } + tunnel_send_destroy (t); + tunnel_destroy (t); + return GNUNET_OK; +} + + +/** + * Core handler for mesh network traffic going from the origin to a peer + * + * @param cls closure + * @param peer peer identity this notification is about + * @param message message + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_mesh_data_unicast (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_MESH_Unicast *msg; + struct MeshTunnel *t; + GNUNET_PEER_Id pid; + size_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a unicast packet from %s\n", + GNUNET_i2s (peer)); + size = ntohs (message->size); + if (size < + sizeof (struct GNUNET_MESH_Unicast) + + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + return GNUNET_OK; + } + msg = (struct GNUNET_MESH_Unicast *) message; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " of type %u\n", + ntohs (msg[1].header.type)); + t = tunnel_get (&msg->oid, ntohl (msg->tid)); + if (NULL == t) + { + /* TODO notify back: we don't know this tunnel */ + GNUNET_break_op (0); + return GNUNET_OK; + } + tunnel_reset_timeout (t); + pid = GNUNET_PEER_search (&msg->destination); + if (pid == myid) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " it's for us! sending to clients...\n"); + send_subscribed_clients (message, (struct GNUNET_MessageHeader *) &msg[1]); + return GNUNET_OK; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " not for us, retransmitting...\n"); + send_message (message, tree_get_first_hop (t->tree, pid)); + return GNUNET_OK; +} + + +/** + * Core handler for mesh network traffic going from the origin to all peers + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + * + * TODO: Check who we got this from, to validate route. + */ +static int +handle_mesh_data_multicast (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_MESH_Multicast *msg; + struct MeshTunnel *t; + size_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a multicast packet from %s\n", + GNUNET_i2s (peer)); + size = ntohs (message->size); + if (sizeof (struct GNUNET_MESH_Multicast) + + sizeof (struct GNUNET_MessageHeader) > size) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + msg = (struct GNUNET_MESH_Multicast *) message; + t = tunnel_get (&msg->oid, ntohl (msg->tid)); + + if (NULL == t) + { + /* TODO notify that we dont know that tunnel */ + GNUNET_break_op (0); + return GNUNET_OK; + } + if (t->mid == ntohl (msg->mid)) + { + /* FIXME: already seen this packet, log dropping */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + " Already seen mid %u, DROPPING!\n", t->mid); + return GNUNET_OK; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " mid %u not seen yet, forwarding\n", ntohl (msg->mid)); + } + t->mid = ntohl (msg->mid); + tunnel_reset_timeout (t); + + /* Transmit to locally interested clients */ + if (NULL != t->peers && + GNUNET_CONTAINER_multihashmap_contains (t->peers, &my_full_id.hashPubKey)) + { + send_subscribed_clients (message, &msg[1].header); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ttl: %u\n", ntohl (msg->ttl)); + if (ntohl (msg->ttl) == 0) + { + /* FIXME: ttl is 0, log dropping */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n"); + return GNUNET_OK; + } + tunnel_send_multicast (t, message, GNUNET_NO); + return GNUNET_OK; +} + + +/** + * Core handler for mesh network traffic toward the owner of a tunnel + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_mesh_data_to_orig (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_MESH_ToOrigin *msg; + struct GNUNET_PeerIdentity id; + struct MeshPeerInfo *peer_info; + struct MeshTunnel *t; + size_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a ToOrigin packet from %s\n", + GNUNET_i2s (peer)); + size = ntohs (message->size); + if (size < sizeof (struct GNUNET_MESH_ToOrigin) + /* Payload must be */ + sizeof (struct GNUNET_MessageHeader)) /* at least a header */ + { + GNUNET_break_op (0); + return GNUNET_OK; + } + msg = (struct GNUNET_MESH_ToOrigin *) message; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " of type %u\n", + ntohs (msg[1].header.type)); + t = tunnel_get (&msg->oid, ntohl (msg->tid)); + + if (NULL == t) + { + /* TODO notify that we dont know this tunnel (whom)? */ + GNUNET_break_op (0); + return GNUNET_OK; + } + + if (t->id.oid == myid) + { + char cbuf[size]; + struct GNUNET_MESH_ToOrigin *copy; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " it's for us! sending to clients...\n"); + if (NULL == t->owner) + { + /* got data packet for ownerless tunnel */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " no clients!\n"); + GNUNET_break_op (0); + return GNUNET_OK; + } + /* TODO signature verification */ + memcpy (cbuf, message, size); + copy = (struct GNUNET_MESH_ToOrigin *) cbuf; + copy->tid = htonl (t->local_tid); + GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle, + ©->header, GNUNET_YES); + return GNUNET_OK; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " not for us, retransmitting...\n"); + + peer_info = peer_info_get (&msg->oid); + if (NULL == peer_info) + { + /* unknown origin of tunnel */ + GNUNET_break (0); + return GNUNET_OK; + } + GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &id); + send_message (message, &id); + + return GNUNET_OK; +} + + +/** + * Core handler for path ACKs + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_MESH_PathACK *msg; + struct GNUNET_PeerIdentity id; + struct MeshPeerInfo *peer_info; + struct MeshPeerPath *p; + struct MeshTunnel *t; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a path ACK msg [%s]\n", + GNUNET_i2s (&my_full_id)); + msg = (struct GNUNET_MESH_PathACK *) message; + t = tunnel_get (&msg->oid, msg->tid); + if (NULL == t) + { + /* TODO notify that we don't know the tunnel */ + return GNUNET_OK; + } + + peer_info = peer_info_get (&msg->peer_id); + + /* Add paths to peers? */ + p = tree_get_path_to_peer (t->tree, peer_info->id); + if (NULL != p) + { + path_add_to_peers (p, GNUNET_YES); + path_destroy (p); + } + else + { + GNUNET_break (0); + } + + /* Message for us? */ + if (0 == memcmp (&msg->oid, &my_full_id, sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n"); + if (NULL == t->owner) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + if (NULL != t->dht_get_type) + { + GNUNET_DHT_get_stop (t->dht_get_type); + t->dht_get_type = NULL; + } + if (tree_get_status (t->tree, peer_info->id) != MESH_PEER_READY) + { + tree_set_status (t->tree, peer_info->id, MESH_PEER_READY); + send_client_peer_connected (t, peer_info->id); + } + return GNUNET_OK; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " not for us, retransmitting...\n"); + GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &id); + peer_info = peer_info_get (&msg->oid); + if (NULL == peer_info) + { + /* If we know the tunnel, we should DEFINITELY know the peer */ + GNUNET_break (0); + return GNUNET_OK; + } + send_message (message, &id); + return GNUNET_OK; +} + + +/** + * Functions to handle messages from core + */ +static struct GNUNET_CORE_MessageHandler core_handlers[] = { + {&handle_mesh_path_create, GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE, 0}, + {&handle_mesh_path_destroy, GNUNET_MESSAGE_TYPE_MESH_PATH_DESTROY, 0}, + {&handle_mesh_path_broken, GNUNET_MESSAGE_TYPE_MESH_PATH_BROKEN, + sizeof (struct GNUNET_MESH_PathBroken)}, + {&handle_mesh_tunnel_destroy, GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY, 0}, + {&handle_mesh_data_unicast, GNUNET_MESSAGE_TYPE_MESH_UNICAST, 0}, + {&handle_mesh_data_multicast, GNUNET_MESSAGE_TYPE_MESH_MULTICAST, 0}, + {&handle_mesh_data_to_orig, GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN, 0}, + {&handle_mesh_path_ack, GNUNET_MESSAGE_TYPE_MESH_PATH_ACK, + sizeof (struct GNUNET_MESH_PathACK)}, + {NULL, 0, 0} +}; + + + +/******************************************************************************/ +/**************** MESH LOCAL HANDLER HELPERS ***********************/ +/******************************************************************************/ + +/** + * deregister_app: iterator for removing each application registered by a client + * + * @param cls closure + * @param key the hash of the application id (used to access the hashmap) + * @param value the value stored at the key (client) + * + * @return GNUNET_OK on success + */ +static int +deregister_app (void *cls, const GNUNET_HashCode * key, void *value) +{ + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (applications, key, + value)); + return GNUNET_OK; +} + +#if LATER +/** + * notify_client_connection_failure: notify a client that the connection to the + * requested remote peer is not possible (for instance, no route found) + * Function called when the socket is ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +notify_client_connection_failure (void *cls, size_t size, void *buf) +{ + int size_needed; + struct MeshPeerInfo *peer_info; + struct GNUNET_MESH_PeerControl *msg; + struct GNUNET_PeerIdentity id; + + if (0 == size && NULL == buf) + { + // TODO retry? cancel? + return 0; + } + + size_needed = sizeof (struct GNUNET_MESH_PeerControl); + peer_info = (struct MeshPeerInfo *) cls; + msg = (struct GNUNET_MESH_PeerControl *) buf; + msg->header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DISCONNECTED); +// msg->tunnel_id = htonl(peer_info->t->tid); + GNUNET_PEER_resolve (peer_info->id, &id); + memcpy (&msg->peer, &id, sizeof (struct GNUNET_PeerIdentity)); + + return size_needed; +} +#endif + + +/** + * Send keepalive packets for a peer + * + * @param cls Closure (tunnel for which to send the keepalive). + * @param tc Notification context. + * + * TODO: implement explicit multicast keepalive? + */ +static void +path_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct MeshTunnel *t = cls; + struct GNUNET_MessageHeader *payload; + struct GNUNET_MESH_Multicast *msg; + size_t size = + sizeof (struct GNUNET_MESH_Multicast) + + sizeof (struct GNUNET_MessageHeader); + char cbuf[size]; + + if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + { + return; + } + t->path_refresh_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "sending keepalive for tunnel %d\n", t->id.tid); + + msg = (struct GNUNET_MESH_Multicast *) cbuf; + msg->header.size = htons (size); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST); + msg->oid = my_full_id; + msg->tid = htonl (t->id.tid); + msg->ttl = htonl (DEFAULT_TTL); + msg->mid = htonl (t->mid + 1); + t->mid++; + payload = (struct GNUNET_MessageHeader *) &msg[1]; + payload->size = htons (sizeof (struct GNUNET_MessageHeader)); + payload->type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_KEEPALIVE); + tunnel_send_multicast (t, &msg->header, GNUNET_YES); + + t->path_refresh_task = + GNUNET_SCHEDULER_add_delayed (REFRESH_PATH_TIME, &path_refresh, t); + return; +} + + +/** + * Function to process paths received for a new peer addition. The recorded + * paths form the initial tunnel, which can be optimized later. + * Called on each result obtained for the DHT search. + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param get_path path of the get request + * @param get_path_length lenght of get_path + * @param put_path path of the put request + * @param put_path_length length of the put_path + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + * + * TODO: re-issue the request after certain time? cancel after X results? + */ +static void +dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + struct MeshPathInfo *path_info = cls; + struct MeshPeerPath *p; + struct GNUNET_PeerIdentity pi; + int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got results from DHT!\n"); + GNUNET_PEER_resolve (path_info->peer->id, &pi); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for %s\n", GNUNET_i2s (&pi)); + + p = path_build_from_dht (get_path, get_path_length, put_path, + put_path_length); + path_add_to_peers (p, GNUNET_NO); + path_destroy(p); + for (i = 0; i < path_info->peer->ntunnels; i++) + { + tunnel_add_peer (path_info->peer->tunnels[i], path_info->peer); + peer_info_connect (path_info->peer, path_info->t); + } + + return; +} + + +/** + * Function to process paths received for a new peer addition. The recorded + * paths form the initial tunnel, which can be optimized later. + * Called on each result obtained for the DHT search. + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param get_path path of the get request + * @param get_path_length lenght of get_path + * @param put_path path of the put request + * @param put_path_length length of the put_path + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +static void +dht_get_type_handler (void *cls, struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + const struct GNUNET_PeerIdentity *pi = data; + struct MeshTunnel *t = cls; + struct MeshPeerInfo *peer_info; + struct MeshPeerPath *p; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got type DHT result!\n"); + if (size != sizeof (struct GNUNET_PeerIdentity)) + { + GNUNET_break_op (0); + return; + } + GNUNET_assert (NULL != t->owner); + peer_info = peer_info_get (pi); + (void) GNUNET_CONTAINER_multihashmap_put (t->peers, &pi->hashPubKey, + peer_info, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + + p = path_build_from_dht (get_path, get_path_length, put_path, + put_path_length); + path_add_to_peers (p, GNUNET_NO); + path_destroy(p); + tunnel_add_peer (t, peer_info); + peer_info_connect (peer_info, t); +} + + +/******************************************************************************/ +/********************* MESH LOCAL HANDLES **************************/ +/******************************************************************************/ + + +/** + * Handler for client disconnection + * + * @param cls closure + * @param client identification of the client; NULL + * for the last call when the server is destroyed + */ +static void +handle_local_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct MeshClient *c; + struct MeshClient *next; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client disconnected\n"); + if (client == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (SERVER DOWN)\n"); + return; + } + c = clients; + while (NULL != c) + { + if (c->handle != client) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ... searching\n"); + c = c->next; + continue; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u)\n", + c->id); + GNUNET_SERVER_client_drop (c->handle); + c->shutting_down = GNUNET_YES; + GNUNET_assert (NULL != c->own_tunnels); + GNUNET_assert (NULL != c->incoming_tunnels); + GNUNET_CONTAINER_multihashmap_iterate (c->own_tunnels, + &tunnel_destroy_iterator, c); + GNUNET_CONTAINER_multihashmap_iterate (c->incoming_tunnels, + &tunnel_destroy_iterator, c); + GNUNET_CONTAINER_multihashmap_iterate (c->ignore_tunnels, + &tunnel_destroy_iterator, c); + GNUNET_CONTAINER_multihashmap_destroy (c->own_tunnels); + GNUNET_CONTAINER_multihashmap_destroy (c->incoming_tunnels); + GNUNET_CONTAINER_multihashmap_destroy (c->ignore_tunnels); + + /* deregister clients applications */ + if (NULL != c->apps) + { + GNUNET_CONTAINER_multihashmap_iterate (c->apps, &deregister_app, NULL); + GNUNET_CONTAINER_multihashmap_destroy (c->apps); + } + if (0 == GNUNET_CONTAINER_multihashmap_size (applications) && + GNUNET_SCHEDULER_NO_TASK != announce_applications_task) + { + GNUNET_SCHEDULER_cancel (announce_applications_task); + announce_applications_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != c->types) + GNUNET_CONTAINER_multihashmap_destroy (c->types); + next = c->next; + GNUNET_CONTAINER_DLL_remove (clients, clients_tail, c); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " CLIENT FREE at %p\n", c); + GNUNET_free (c); + c = next; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " done!\n"); + return; +} + + +/** + * Handler for new clients + * + * @param cls closure + * @param client identification of the client + * @param message the actual message, which includes messages the client wants + */ +static void +handle_local_new_client (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_MESH_ClientConnect *cc_msg; + struct MeshClient *c; + GNUNET_MESH_ApplicationType *a; + unsigned int size; + uint16_t ntypes; + uint16_t *t; + uint16_t napps; + uint16_t i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new client connected\n"); + /* Check data sanity */ + size = ntohs (message->size) - sizeof (struct GNUNET_MESH_ClientConnect); + cc_msg = (struct GNUNET_MESH_ClientConnect *) message; + ntypes = ntohs (cc_msg->types); + napps = ntohs (cc_msg->applications); + if (size != + ntypes * sizeof (uint16_t) + napps * sizeof (GNUNET_MESH_ApplicationType)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Create new client structure */ + c = GNUNET_malloc (sizeof (struct MeshClient)); + c->id = next_client_id++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " CLIENT NEW %u\n", c->id); + c->handle = client; + GNUNET_SERVER_client_keep (client); + a = (GNUNET_MESH_ApplicationType *) &cc_msg[1]; + if (napps > 0) + { + GNUNET_MESH_ApplicationType at; + GNUNET_HashCode hc; + + c->apps = GNUNET_CONTAINER_multihashmap_create (napps); + for (i = 0; i < napps; i++) + { + at = ntohl (a[i]); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " app type: %u\n", at); + GNUNET_CRYPTO_hash (&at, sizeof (at), &hc); + /* store in clients hashmap */ + GNUNET_CONTAINER_multihashmap_put (c->apps, &hc, c, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + /* store in global hashmap, for announcements */ + GNUNET_CONTAINER_multihashmap_put (applications, &hc, c, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + } + if (GNUNET_SCHEDULER_NO_TASK == announce_applications_task) + announce_applications_task = + GNUNET_SCHEDULER_add_now (&announce_applications, NULL); + + } + if (ntypes > 0) + { + uint16_t u16; + GNUNET_HashCode hc; + + t = (uint16_t *) & a[napps]; + c->types = GNUNET_CONTAINER_multihashmap_create (ntypes); + for (i = 0; i < ntypes; i++) + { + u16 = ntohs (t[i]); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " msg type: %u\n", u16); + GNUNET_CRYPTO_hash (&u16, sizeof (u16), &hc); + + /* store in clients hashmap */ + GNUNET_CONTAINER_multihashmap_put (c->types, &hc, c, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + /* store in global hashmap */ + GNUNET_CONTAINER_multihashmap_put (types, &hc, c, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + } + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " client has %u+%u subscriptions\n", napps, ntypes); + + GNUNET_CONTAINER_DLL_insert (clients, clients_tail, c); + c->own_tunnels = GNUNET_CONTAINER_multihashmap_create (32); + c->incoming_tunnels = GNUNET_CONTAINER_multihashmap_create (32); + c->ignore_tunnels = GNUNET_CONTAINER_multihashmap_create (32); + GNUNET_SERVER_notification_context_add (nc, client); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new client processed\n"); +} + + +/** + * Handler for requests of new tunnels + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_local_tunnel_create (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_MESH_TunnelMessage *t_msg; + struct MeshTunnel *t; + struct MeshClient *c; + GNUNET_HashCode hash; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new tunnel requested\n"); + + /* Sanity check for client registration */ + if (NULL == (c = client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); + + /* Message sanity check */ + if (sizeof (struct GNUNET_MESH_TunnelMessage) != ntohs (message->size)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + t_msg = (struct GNUNET_MESH_TunnelMessage *) message; + /* Sanity check for tunnel numbering */ + if (0 == (ntohl (t_msg->tunnel_id) & GNUNET_MESH_LOCAL_TUNNEL_ID_CLI)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + /* Sanity check for duplicate tunnel IDs */ + if (NULL != tunnel_get_by_local_id (c, ntohl (t_msg->tunnel_id))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + t = GNUNET_malloc (sizeof (struct MeshTunnel)); + while (NULL != tunnel_get_by_pi (myid, next_tid)) + next_tid = (next_tid + 1) & ~GNUNET_MESH_LOCAL_TUNNEL_ID_CLI; + t->id.tid = next_tid++; + next_tid = next_tid & ~GNUNET_MESH_LOCAL_TUNNEL_ID_CLI; + t->id.oid = myid; + t->local_tid = ntohl (t_msg->tunnel_id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATED TUNNEL %s [%x] (%x)\n", + GNUNET_i2s (&my_full_id), t->id.tid, t->local_tid); + t->owner = c; + t->peers = GNUNET_CONTAINER_multihashmap_create (32); + + GNUNET_CRYPTO_hash (&t->local_tid, sizeof (MESH_TunnelNumber), &hash); + if (GNUNET_OK != + GNUNET_CONTAINER_multihashmap_put (c->own_tunnels, &hash, t, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + GNUNET_CRYPTO_hash (&t->id, sizeof (struct MESH_TunnelID), &hash); + if (GNUNET_OK != + GNUNET_CONTAINER_multihashmap_put (tunnels, &hash, t, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + t->tree = tree_new (myid); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new tunnel created\n"); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; +} + + +/** + * Handler for requests of deleting tunnels + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_local_tunnel_destroy (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_MESH_TunnelMessage *tunnel_msg; + struct MeshClient *c; + struct MeshTunnel *t; + MESH_TunnelNumber tid; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got a DESTROY TUNNEL from client!\n"); + + /* Sanity check for client registration */ + if (NULL == (c = client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + /* Message sanity check */ + if (sizeof (struct GNUNET_MESH_TunnelMessage) != ntohs (message->size)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); + tunnel_msg = (struct GNUNET_MESH_TunnelMessage *) message; + + /* Retrieve tunnel */ + tid = ntohl (tunnel_msg->tunnel_id); + t = tunnel_get_by_local_id(c, tid); + if (NULL == t) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " tunnel %X not found\n", tid); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + send_client_tunnel_disconnect(t, c); + if (c != t->owner) + { + client_ignore_tunnel (c, t); +#if 0 + // TODO: when to destroy incoming tunnel? + if (t->nclients == 0) + { + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels, + &hash, t)); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (t->peers, + &my_full_id.hashPubKey, + t)); + } +#endif + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + client_delete_tunnel(c, t); + + /* Don't try to ACK the client about the tunnel_destroy multicast packet */ + t->owner = NULL; + tunnel_send_destroy (t); + tunnel_destroy (t); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; +} + + +/** + * Handler for connection requests to new peers + * + * @param cls closure + * @param client identification of the client + * @param message the actual message (PeerControl) + */ +static void +handle_local_connect_add (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_MESH_PeerControl *peer_msg; + struct MeshPeerInfo *peer_info; + struct MeshClient *c; + struct MeshTunnel *t; + MESH_TunnelNumber tid; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got connection request\n"); + /* Sanity check for client registration */ + if (NULL == (c = client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + peer_msg = (struct GNUNET_MESH_PeerControl *) message; + /* Sanity check for message size */ + if (sizeof (struct GNUNET_MESH_PeerControl) != ntohs (peer_msg->header.size)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Tunnel exists? */ + tid = ntohl (peer_msg->tunnel_id); + t = tunnel_get_by_local_id (c, tid); + if (NULL == t) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Does client own tunnel? */ + if (t->owner->handle != client) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for %s\n", + GNUNET_i2s (&peer_msg->peer)); + peer_info = peer_info_get (&peer_msg->peer); + + tunnel_add_peer (t, peer_info); + peer_info_connect (peer_info, t); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; +} + + +/** + * Handler for disconnection requests of peers in a tunnel + * + * @param cls closure + * @param client identification of the client + * @param message the actual message (PeerControl) + */ +static void +handle_local_connect_del (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_MESH_PeerControl *peer_msg; + struct MeshPeerInfo *peer_info; + struct MeshClient *c; + struct MeshTunnel *t; + MESH_TunnelNumber tid; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a PEER DEL request\n"); + /* Sanity check for client registration */ + if (NULL == (c = client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + peer_msg = (struct GNUNET_MESH_PeerControl *) message; + /* Sanity check for message size */ + if (sizeof (struct GNUNET_MESH_PeerControl) != ntohs (peer_msg->header.size)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Tunnel exists? */ + tid = ntohl (peer_msg->tunnel_id); + t = tunnel_get_by_local_id (c, tid); + if (NULL == t) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " on tunnel %X\n", t->id.tid); + + /* Does client own tunnel? */ + if (t->owner->handle != client) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for peer %s\n", + GNUNET_i2s (&peer_msg->peer)); + /* Is the peer in the tunnel? */ + peer_info = + GNUNET_CONTAINER_multihashmap_get (t->peers, &peer_msg->peer.hashPubKey); + if (NULL == peer_info) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Ok, delete peer from tunnel */ + GNUNET_CONTAINER_multihashmap_remove_all (t->peers, + &peer_msg->peer.hashPubKey); + + send_destroy_path (t, peer_info->id); + tunnel_delete_peer (t, peer_info->id); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; +} + + +/** + * Handler for connection requests to new peers by type + * + * @param cls closure + * @param client identification of the client + * @param message the actual message (ConnectPeerByType) + */ +static void +handle_local_connect_by_type (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_MESH_ConnectPeerByType *connect_msg; + struct MeshClient *c; + struct MeshTunnel *t; + GNUNET_HashCode hash; + MESH_TunnelNumber tid; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got connect by type request\n"); + /* Sanity check for client registration */ + if (NULL == (c = client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + connect_msg = (struct GNUNET_MESH_ConnectPeerByType *) message; + /* Sanity check for message size */ + if (sizeof (struct GNUNET_MESH_ConnectPeerByType) != + ntohs (connect_msg->header.size)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Tunnel exists? */ + tid = ntohl (connect_msg->tunnel_id); + t = tunnel_get_by_local_id (c, tid); + if (NULL == t) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Does client own tunnel? */ + if (t->owner->handle != client) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Do WE have the service? */ + t->type = ntohl (connect_msg->type); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " type requested: %u\n", t->type); + GNUNET_CRYPTO_hash (&t->type, sizeof (GNUNET_MESH_ApplicationType), &hash); + if (GNUNET_CONTAINER_multihashmap_contains (applications, &hash) == + GNUNET_YES) + { + /* Yes! Fast forward, add ourselves to the tunnel and send the + * good news to the client, and alert the destination client of + * an incoming tunnel. + * + * FIXME send a path create to self, avoid code duplication + */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " available locally\n"); + GNUNET_CONTAINER_multihashmap_put (t->peers, &my_full_id.hashPubKey, + peer_info_get (&my_full_id), + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " notifying client\n"); + send_client_peer_connected (t, myid); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Done\n"); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + + t->local_tid_dest = next_local_tid++; + GNUNET_CRYPTO_hash (&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); + GNUNET_CONTAINER_multihashmap_put (incoming_tunnels, &hash, t, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); + + return; + } + /* Ok, lets find a peer offering the service */ + if (NULL != t->dht_get_type) + { + GNUNET_DHT_get_stop (t->dht_get_type); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " looking in DHT for %s\n", + GNUNET_h2s (&hash)); + t->dht_get_type = + GNUNET_DHT_get_start (dht_handle, GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_BLOCK_TYPE_TEST, &hash, 10U, + GNUNET_DHT_RO_RECORD_ROUTE | + GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, 0, + &dht_get_type_handler, t); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; +} + + +/** + * Handler for client traffic directed to one peer + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_local_unicast (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct MeshClient *c; + struct MeshTunnel *t; + struct MeshPeerInfo *pi; + struct GNUNET_MESH_Unicast *data_msg; + MESH_TunnelNumber tid; + size_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got a unicast request from a client!\n"); + + /* Sanity check for client registration */ + if (NULL == (c = client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + data_msg = (struct GNUNET_MESH_Unicast *) message; + /* Sanity check for message size */ + size = ntohs (message->size); + if (sizeof (struct GNUNET_MESH_Unicast) + + sizeof (struct GNUNET_MessageHeader) > size) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Tunnel exists? */ + tid = ntohl (data_msg->tid); + t = tunnel_get_by_local_id (c, tid); + if (NULL == t) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Is it a local tunnel? Then, does client own the tunnel? */ + if (t->owner->handle != client) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + pi = GNUNET_CONTAINER_multihashmap_get (t->peers, + &data_msg->destination.hashPubKey); + /* Is the selected peer in the tunnel? */ + if (NULL == pi) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Ok, everything is correct, send the message + * (pretend we got it from a mesh peer) + */ + { + char buf[ntohs (message->size)]; + struct GNUNET_MESH_Unicast *copy; + + /* Work around const limitation */ + copy = (struct GNUNET_MESH_Unicast *) buf; + memcpy (buf, data_msg, size); + copy->oid = my_full_id; + copy->tid = htonl (t->id.tid); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " calling generic handler...\n"); + handle_mesh_data_unicast (NULL, &my_full_id, ©->header, NULL, 0); + } + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; +} + + +/** + * Handler for client traffic directed to the origin + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_local_to_origin (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_MESH_ToOrigin *data_msg; + struct GNUNET_PeerIdentity id; + struct MeshClient *c; + struct MeshTunnel *t; + MESH_TunnelNumber tid; + size_t size; + + /* Sanity check for client registration */ + if (NULL == (c = client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + data_msg = (struct GNUNET_MESH_ToOrigin *) message; + /* Sanity check for message size */ + size = ntohs (message->size); + if (sizeof (struct GNUNET_MESH_ToOrigin) + + sizeof (struct GNUNET_MessageHeader) > size) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Tunnel exists? */ + tid = ntohl (data_msg->tid); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got a ToOrigin request from a client! Tunnel %X\n", tid); + if (tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + t = tunnel_get_by_local_id (c, tid); + if (NULL == t) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* It should be sent by someone who has this as incoming tunnel. */ + if (-1 == client_knows_tunnel (c, t)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_PEER_resolve (t->id.oid, &id); + + /* Ok, everything is correct, send the message + * (pretend we got it from a mesh peer) + */ + { + char buf[ntohs (message->size)]; + struct GNUNET_MESH_ToOrigin *copy; + + /* Work around const limitation */ + copy = (struct GNUNET_MESH_ToOrigin *) buf; + memcpy (buf, data_msg, size); + copy->oid = id; + copy->tid = htonl (t->id.tid); + copy->sender = my_full_id; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " calling generic handler...\n"); + handle_mesh_data_to_orig (NULL, &my_full_id, ©->header, NULL, 0); + } + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; +} + + +/** + * Handler for client traffic directed to all peers in a tunnel + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_local_multicast (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct MeshClient *c; + struct MeshTunnel *t; + struct GNUNET_MESH_Multicast *data_msg; + MESH_TunnelNumber tid; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got a multicast request from a client!\n"); + + /* Sanity check for client registration */ + if (NULL == (c = client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + data_msg = (struct GNUNET_MESH_Multicast *) message; + /* Sanity check for message size */ + if (sizeof (struct GNUNET_MESH_Multicast) + + sizeof (struct GNUNET_MessageHeader) > ntohs (data_msg->header.size)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Tunnel exists? */ + tid = ntohl (data_msg->tid); + t = tunnel_get_by_local_id (c, tid); + if (NULL == t) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Does client own tunnel? */ + if (t->owner->handle != client) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + { + char buf[ntohs (message->size)]; + struct GNUNET_MESH_Multicast *copy; + + copy = (struct GNUNET_MESH_Multicast *) buf; + memcpy (buf, message, ntohs (message->size)); + copy->oid = my_full_id; + copy->tid = htonl (t->id.tid); + copy->ttl = htonl (DEFAULT_TTL); + copy->mid = htonl (t->mid + 1); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " calling generic handler...\n"); + handle_mesh_data_multicast (client, &my_full_id, ©->header, NULL, 0); + } + + /* receive done gets called when last copy is sent to a neighbor */ + return; +} + +/** + * Functions to handle messages from clients + */ +static struct GNUNET_SERVER_MessageHandler client_handlers[] = { + {&handle_local_new_client, NULL, + GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT, 0}, + {&handle_local_tunnel_create, NULL, + GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE, + sizeof (struct GNUNET_MESH_TunnelMessage)}, + {&handle_local_tunnel_destroy, NULL, + GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY, + sizeof (struct GNUNET_MESH_TunnelMessage)}, + {&handle_local_connect_add, NULL, + GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD, + sizeof (struct GNUNET_MESH_PeerControl)}, + {&handle_local_connect_del, NULL, + GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL, + sizeof (struct GNUNET_MESH_PeerControl)}, + {&handle_local_connect_by_type, NULL, + GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE, + sizeof (struct GNUNET_MESH_ConnectPeerByType)}, + {&handle_local_unicast, NULL, + GNUNET_MESSAGE_TYPE_MESH_UNICAST, 0}, + {&handle_local_to_origin, NULL, + GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN, 0}, + {&handle_local_multicast, NULL, + GNUNET_MESSAGE_TYPE_MESH_MULTICAST, 0}, + {NULL, NULL, 0, 0} +}; + + +/** + * To be called on core init/fail. + * + * @param cls service closure + * @param server handle to the server for this service + * @param identity the public identity of this peer + */ +static void +core_init (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *identity) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core init\n"); + core_handle = server; + if (0 != memcmp (identity, &my_full_id, sizeof (my_full_id)) || + NULL == server) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n")); + GNUNET_SCHEDULER_shutdown (); + } + return; +} + +/** + * Method called whenever a given peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data for the connection + * @param atsi_count number of records in 'atsi' + */ +static void +core_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct MeshPeerInfo *peer_info; + struct MeshPeerPath *path; + + DEBUG_CONN ("Peer connected\n"); + DEBUG_CONN (" %s\n", GNUNET_i2s (&my_full_id)); + peer_info = peer_info_get (peer); + if (myid == peer_info->id) + { + DEBUG_CONN (" (self)\n"); + return; + } + else + { + DEBUG_CONN (" %s\n", GNUNET_i2s (peer)); + } + path = path_new (2); + path->peers[0] = myid; + path->peers[1] = peer_info->id; + GNUNET_PEER_change_rc (myid, 1); + GNUNET_PEER_change_rc (peer_info->id, 1); + peer_info_add_path (peer_info, path, GNUNET_YES); + return; +} + +/** + * Method called whenever a peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct MeshPeerInfo *pi; + unsigned int i; + + DEBUG_CONN ("Peer disconnected\n"); + pi = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); + if (NULL == pi) + { + GNUNET_break (0); + return; + } + for (i = 0; i < CORE_QUEUE_SIZE; i++) + { + /* TODO: notify that the transmission failed */ + peer_info_cancel_transmission (pi, i); + } + peer_info_remove_path (pi, pi->id, myid); + if (myid == pi->id) + { + DEBUG_CONN (" (self)\n"); + } + return; +} + + +/******************************************************************************/ +/************************ MAIN FUNCTIONS ****************************/ +/******************************************************************************/ + +/** + * Iterator over tunnel hash map entries to destroy the tunnel during shutdown. + * + * @param cls closure + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to iterate, + * GNUNET_NO if not. + */ +static int +shutdown_tunnel (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct MeshTunnel *t = value; + + tunnel_destroy (t); + return GNUNET_YES; +} + +/** + * Iterator over peer hash map entries to destroy the tunnel during shutdown. + * + * @param cls closure + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to iterate, + * GNUNET_NO if not. + */ +static int +shutdown_peer (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct MeshPeerInfo *p = value; + + peer_info_destroy (p); + return GNUNET_YES; +} + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n"); + + if (core_handle != NULL) + { + GNUNET_CORE_disconnect (core_handle); + core_handle = NULL; + } + GNUNET_CONTAINER_multihashmap_iterate (tunnels, &shutdown_tunnel, NULL); + GNUNET_CONTAINER_multihashmap_iterate (peers, &shutdown_peer, NULL); + if (dht_handle != NULL) + { + GNUNET_DHT_disconnect (dht_handle); + dht_handle = NULL; + } + if (nc != NULL) + { + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != announce_id_task) + { + GNUNET_SCHEDULER_cancel (announce_id_task); + announce_id_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n"); +} + +/** + * Process mesh requests. + * + * @param cls closure + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + struct MeshPeerInfo *peer; + struct MeshPeerPath *p; + char *keyfile; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n"); + server_handle = server; + core_handle = GNUNET_CORE_connect (c, /* Main configuration */ + CORE_QUEUE_SIZE, /* queue size */ + NULL, /* Closure passed to MESH functions */ + &core_init, /* Call core_init once connected */ + &core_connect, /* Handle connects */ + &core_disconnect, /* remove peers on disconnects */ + NULL, /* Don't notify about all incoming messages */ + GNUNET_NO, /* For header only in notification */ + NULL, /* Don't notify about all outbound messages */ + GNUNET_NO, /* For header-only out notification */ + core_handlers); /* Register these handlers */ + + if (core_handle == NULL) + { + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY", + &keyfile)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Mesh service is lacking key configuration settings. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_free (keyfile); + if (my_private_key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Mesh service could not access hostkey. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); + GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), + &my_full_id.hashPubKey); + myid = GNUNET_PEER_intern (&my_full_id); + +// // transport_handle = GNUNET_TRANSPORT_connect(c, +// // &my_full_id, +// // NULL, +// // NULL, +// // NULL, +// // NULL); + + dht_handle = GNUNET_DHT_connect (c, 64); + if (dht_handle == NULL) + { + GNUNET_break (0); + } + + next_tid = 0; + next_local_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_SERV; + + tunnels = GNUNET_CONTAINER_multihashmap_create (32); + incoming_tunnels = GNUNET_CONTAINER_multihashmap_create (32); + peers = GNUNET_CONTAINER_multihashmap_create (32); + applications = GNUNET_CONTAINER_multihashmap_create (32); + types = GNUNET_CONTAINER_multihashmap_create (32); + + GNUNET_SERVER_add_handlers (server_handle, client_handlers); + nc = GNUNET_SERVER_notification_context_create (server_handle, + LOCAL_QUEUE_SIZE); + GNUNET_SERVER_disconnect_notify (server_handle, + &handle_local_client_disconnect, NULL); + + + clients = NULL; + clients_tail = NULL; + next_client_id = 0; + + announce_applications_task = GNUNET_SCHEDULER_NO_TASK; + announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, cls); + + /* Create a peer_info for the local peer */ + peer = peer_info_get (&my_full_id); + p = path_new (1); + p->peers[0] = myid; + GNUNET_PEER_change_rc (myid, 1); + peer_info_add_path (peer, p, GNUNET_YES); + + /* Scheduled the task to clean up when shutdown is called */ + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "end of run()\n"); +} + +/** + * The main function for the mesh service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + int ret; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "main()\n"); + ret = + (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "mesh", GNUNET_SERVICE_OPTION_NONE, &run, + NULL)) ? 0 : 1; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "main() END\n"); + + return ret; +} diff --git a/src/mesh/mesh.conf.in b/src/mesh/mesh.conf.in new file mode 100644 index 0000000..83a8938 --- /dev/null +++ b/src/mesh/mesh.conf.in @@ -0,0 +1,13 @@ +[mesh] +AUTOSTART = YES +@UNIXONLY@ PORT = 2096 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-mesh +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-mesh.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + diff --git a/src/mesh/mesh.h b/src/mesh/mesh.h new file mode 100644 index 0000000..d8fc404 --- /dev/null +++ b/src/mesh/mesh.h @@ -0,0 +1,263 @@ +/* + This file is part of GNUnet. + (C) 2001 - 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Bartlomiej Polot + * @file mesh/mesh.h + */ + +#ifndef MESH_H_ +#define MESH_H_ +#include + +#define MESH_DEBUG GNUNET_YES + + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_util_lib.h" +#include "gnunet_peer_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_protocols.h" +#include + +/******************************************************************************/ +/******************** MESH LOCAL MESSAGES *************************/ +/******************************************************************************/ +/* Any API call should be documented in the folowing table under API CALL. + * Also, any message type should be documented in the following table, with the + * associated event. + * + * API CALL (GNUNET_MESH_*) MESSAGE USED + * ------------------------ ------------ + * connect GNUNET_MESH_ClientConnect + * disconnect None (network level disconnect) + * + * tunnel_create GNUNET_MESH_TunnelMessage + * tunnel_destroy GNUNET_MESH_TunnelMessage + * + * peer_request_connect_add GNUNET_MESH_PeerControl + * peer_request_connect_del GNUNET_MESH_PeerControl + * peer_request_connect_by_type GNUNET_MESH_ConnectPeerByType + * + * notify_transmit_ready *GNUNET_MESH_TransmitReady?* + * notify_transmit_ready_cancel None (clear of internal data structures) + * + * + * + * EVENT MESSAGE USED + * ----- ------------ + * data GNUNET_MESH_Data OR + * GNUNET_MESH_DataBroadcast + * new incoming tunnel GNUNET_MESH_PeerControl + * peer connects to a tunnel GNUNET_MESH_PeerControl + * peer disconnects from a tunnel GNUNET_MESH_PeerControl + */ + +/******************************************************************************/ +/************************** CONSTANTS ******************************/ +/******************************************************************************/ + +#define GNUNET_MESH_LOCAL_TUNNEL_ID_CLI 0x80000000 +#define GNUNET_MESH_LOCAL_TUNNEL_ID_SERV 0xB0000000 + +#define CORE_QUEUE_SIZE 10 +#define LOCAL_QUEUE_SIZE 100 + +/******************************************************************************/ +/************************** MESSAGES ******************************/ +/******************************************************************************/ + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message for a client to register to the service + */ +struct GNUNET_MESH_ClientConnect +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT + * + * Size: sizeof(struct GNUNET_MESH_ClientConnect) + + * sizeof(MESH_ApplicationType) * applications + + * sizeof(uint16_t) * types + */ + struct GNUNET_MessageHeader header; + uint16_t applications GNUNET_PACKED; + uint16_t types GNUNET_PACKED; + /* uint16_t list_apps[applications] */ + /* uint16_t list_types[types] */ +}; + + +/** + * Type for tunnel numbering. + * - Local tunnel numbers given by the service (incoming) are >= 0xB0000000 + * - Local tunnel numbers given by the client (created) are >= 0x80000000 + * - Global tunnel numbers are < 0x80000000 + */ +typedef uint32_t MESH_TunnelNumber; + +/** + * Message for a client to create and destroy tunnels. + */ +struct GNUNET_MESH_TunnelMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_[CREATE|DESTROY] + * + * Size: sizeof(struct GNUNET_MESH_TunnelMessage) + */ + struct GNUNET_MessageHeader header; + + /** + * ID of a tunnel controlled by this client. + */ + MESH_TunnelNumber tunnel_id GNUNET_PACKED; +}; + + +/** + * Message for the service to let a client know about created tunnels. + */ +struct GNUNET_MESH_TunnelNotification +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE + * + * Size: sizeof(struct GNUNET_MESH_TunnelMessage) + */ + struct GNUNET_MessageHeader header; + + /** + * ID of a tunnel controlled by this client. + */ + MESH_TunnelNumber tunnel_id GNUNET_PACKED; + + /** + * Peer at the other end, if any + */ + struct GNUNET_PeerIdentity peer; +}; + +/** + * Message for: + * - request adding and deleting peers from a tunnel + * - notify the client that peers have connected: + * -- requested + * -- unrequested (new incoming tunnels) + * - notify the client that peers have disconnected + */ +struct GNUNET_MESH_PeerControl +{ + + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_[ADD|DEL] + * (client to service, client created tunnel) + * GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_[CONNECTED|DISCONNECTED] + * (service to client) + * + * Size: sizeof(struct GNUNET_MESH_PeerControl) + */ + struct GNUNET_MessageHeader header; + + /** + * ID of a tunnel controlled by this client. + */ + MESH_TunnelNumber tunnel_id GNUNET_PACKED; + + /** + * Peer to connect/disconnect. + */ + struct GNUNET_PeerIdentity peer; +}; + + +/** + * Message for connecting to peers offering a certain service. + */ +struct GNUNET_MESH_ConnectPeerByType +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_BY_TYPE | + * GNUNET_MESSAGE_TYPE_MESH_LOCAL_DISCONNECT_PEER_BY_TYPE + */ + struct GNUNET_MessageHeader header; + + /** + * ID of a tunnel controlled by this client. + */ + MESH_TunnelNumber tunnel_id GNUNET_PACKED; + + /** + * Type specification + */ + GNUNET_MESH_ApplicationType type GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + +/******************************************************************************/ +/************************ ENUMERATIONS ****************************/ +/******************************************************************************/ + +/** + * All the states a peer participating in a tunnel can be in. + */ +enum MeshPeerState +{ + /** + * Uninitialized status, should never appear in operation. + */ + MESH_PEER_INVALID, + + /** + * Peer is the root and owner of the tree + */ + MESH_PEER_ROOT, + + /** + * Peer only retransmits traffic, is not a final destination + */ + MESH_PEER_RELAY, + + /** + * Path to the peer not known yet + */ + MESH_PEER_SEARCHING, + + /** + * Request sent, not yet answered. + */ + MESH_PEER_WAITING, + + /** + * Peer connected and ready to accept data + */ + MESH_PEER_READY, + + /** + * Peer connected previosly but not responding + */ + MESH_PEER_RECONNECTING +}; + + + +#endif diff --git a/src/mesh/mesh_api.c b/src/mesh/mesh_api.c new file mode 100644 index 0000000..7b9aa06 --- /dev/null +++ b/src/mesh/mesh_api.c @@ -0,0 +1,1713 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file mesh/mesh_api.c + * @brief mesh api: client implementation of mesh service + * @author Bartlomiej Polot + * + * STRUCTURE: + * - CONSTANTS + * - DATA STRUCTURES + * - AUXILIARY FUNCTIONS + * - RECEIVE HANDLERS + * - SEND FUNCTIONS + * - API CALL DEFINITIONS + */ +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_client_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_peer_lib.h" +#include "gnunet_mesh_service.h" +#include "mesh.h" +#include "mesh_protocol.h" + +#define MESH_API_DEBUG GNUNET_YES + +#if MESH_API_DEBUG +#define LOG(kind,...) GNUNET_log_from (kind, "mesh-api",__VA_ARGS__) +#else +#define LOG(kind,...) +#endif + +/******************************************************************************/ +/************************ DATA STRUCTURES ****************************/ +/******************************************************************************/ + +/** + * Transmission queue to the service + */ +struct GNUNET_MESH_TransmitHandle +{ + + /** + * Double Linked list + */ + struct GNUNET_MESH_TransmitHandle *next; + + /** + * Double Linked list + */ + struct GNUNET_MESH_TransmitHandle *prev; + + /** + * Tunnel this message is sent on / for (may be NULL for control messages). + */ + struct GNUNET_MESH_Tunnel *tunnel; + + /** + * Callback to obtain the message to transmit, or NULL if we + * got the message in 'data'. Notice that messages built + * by 'notify' need to be encapsulated with information about + * the 'target'. + */ + GNUNET_CONNECTION_TransmitReadyNotify notify; + + /** + * Closure for 'notify' + */ + void *notify_cls; + + /** + * How long is this message valid. Once the timeout has been + * reached, the message must no longer be sent. If this + * is a message with a 'notify' callback set, the 'notify' + * function should be called with 'buf' NULL and size 0. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * Priority of the message. The queue is sorted by priority, + * control messages have the maximum priority (UINT32_MAX). + */ + uint32_t priority; + + /** + * Target of the message, 0 for multicast. This field + * is only valid if 'notify' is non-NULL. + */ + GNUNET_PEER_Id target; + + /** + * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL. + */ + size_t size; +}; + + +/** + * Opaque handle to the service. + */ +struct GNUNET_MESH_Handle +{ + + /** + * Handle to the server connection, to send messages later + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Set of handlers used for processing incoming messages in the tunnels + */ + const struct GNUNET_MESH_MessageHandler *message_handlers; + + /** + * Set of applications that should be claimed to be offered at this node. + * Note that this is just informative, the appropiate handlers must be + * registered independently and the mapping is up to the developer of the + * client application. + */ + const GNUNET_MESH_ApplicationType *applications; + + /** + * Double linked list of the tunnels this client is connected to. + */ + struct GNUNET_MESH_Tunnel *tunnels_head; + struct GNUNET_MESH_Tunnel *tunnels_tail; + + /** + * Callback for inbound tunnel creation + */ + GNUNET_MESH_InboundTunnelNotificationHandler *new_tunnel; + + /** + * Callback for inbound tunnel disconnection + */ + GNUNET_MESH_TunnelEndHandler *cleaner; + + /** + * Handle to cancel pending transmissions in case of disconnection + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Closure for all the handlers given by the client + */ + void *cls; + + /** + * Messages to send to the service + */ + struct GNUNET_MESH_TransmitHandle *th_head; + struct GNUNET_MESH_TransmitHandle *th_tail; + + /** + * tid of the next tunnel to create (to avoid reusing IDs often) + */ + MESH_TunnelNumber next_tid; + unsigned int n_handlers; + unsigned int n_applications; + unsigned int max_queue_size; + + /** + * Have we started the task to receive messages from the service + * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message. + */ + int in_receive; + + /** + * Number of packets queued + */ + unsigned int npackets; + + /** + * Configuration given by the client, in case of reconnection + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Time to the next reconnect in case one reconnect fails + */ + struct GNUNET_TIME_Relative reconnect_time; + + /** + * Task for trying to reconnect. + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; +}; + + +/** + * Description of a peer + */ +struct GNUNET_MESH_Peer +{ + /** + * ID of the peer in short form + */ + GNUNET_PEER_Id id; + + /** + * Tunnel this peer belongs to + */ + struct GNUNET_MESH_Tunnel *t; + + /** + * Flag indicating whether service has informed about its connection + */ + int connected; + +}; + + +/** + * Opaque handle to a tunnel. + */ +struct GNUNET_MESH_Tunnel +{ + + /** + * DLL + */ + struct GNUNET_MESH_Tunnel *next; + struct GNUNET_MESH_Tunnel *prev; + + /** + * Callback to execute when peers connect to the tunnel + */ + GNUNET_MESH_PeerConnectHandler connect_handler; + + /** + * Callback to execute when peers disconnect from the tunnel + */ + GNUNET_MESH_PeerDisconnectHandler disconnect_handler; + + /** + * Closure for the connect/disconnect handlers + */ + void *cls; + + /** + * Handle to the mesh this tunnel belongs to + */ + struct GNUNET_MESH_Handle *mesh; + + /** + * Local ID of the tunnel + */ + MESH_TunnelNumber tid; + + /** + * Owner of the tunnel. 0 if the tunnel is the local client. + */ + GNUNET_PEER_Id owner; + + /** + * All peers added to the tunnel + */ + struct GNUNET_MESH_Peer **peers; + + /** + * List of application types that have been requested for this tunnel + */ + GNUNET_MESH_ApplicationType *apps; + + /** + * Any data the caller wants to put in here + */ + void *ctx; + + /** + * Number of peers added to the tunnel + */ + unsigned int npeers; + + /** + * Number of packets queued in this tunnel + */ + unsigned int npackets; + + /** + * Number of applications requested this tunnel + */ + unsigned int napps; + +}; + + +/******************************************************************************/ +/*********************** AUXILIARY FUNCTIONS *************************/ +/******************************************************************************/ + +/** + * Get the tunnel handler for the tunnel specified by id from the given handle + * @param h Mesh handle + * @param tid ID of the wanted tunnel + * @return handle to the required tunnel or NULL if not found + */ +static struct GNUNET_MESH_Tunnel * +retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid) +{ + struct GNUNET_MESH_Tunnel *t; + + t = h->tunnels_head; + while (t != NULL) + { + if (t->tid == tid) + return t; + t = t->next; + } + return NULL; +} + + +/** + * Create a new tunnel and insert it in the tunnel list of the mesh handle + * @param h Mesh handle + * @param tid desired tid of the tunnel, 0 to assign one automatically + * @return handle to the created tunnel + */ +static struct GNUNET_MESH_Tunnel * +create_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid) +{ + struct GNUNET_MESH_Tunnel *t; + + t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel)); + GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t); + t->mesh = h; + if (0 == tid) + { + t->tid = h->next_tid; + while (NULL != retrieve_tunnel (h, h->next_tid)) + { + h->next_tid++; + h->next_tid &= ~GNUNET_MESH_LOCAL_TUNNEL_ID_SERV; + h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI; + } + } + else + { + t->tid = tid; + } + return t; +} + + +/** + * Destroy the specified tunnel. + * - Destroys all peers, calling the disconnect callback on each if needed + * - Cancels all outgoing traffic for that tunnel, calling respective notifys + * - Calls cleaner if tunnel was inbound + * - Frees all memory used + * + * @param t Pointer to the tunnel. + * @param call_cleaner Whether to call the cleaner handler. + * + * @return Handle to the required tunnel or NULL if not found. + */ +static void +destroy_tunnel (struct GNUNET_MESH_Tunnel *t, int call_cleaner) +{ + struct GNUNET_MESH_Handle *h; + struct GNUNET_PeerIdentity pi; + struct GNUNET_MESH_TransmitHandle *th; + struct GNUNET_MESH_TransmitHandle *next; + unsigned int i; + + if (NULL == t) + { + GNUNET_break (0); + return; + } + h = t->mesh; + + /* disconnect all peers */ + GNUNET_CONTAINER_DLL_remove (h->tunnels_head, h->tunnels_tail, t); + for (i = 0; i < t->npeers; i++) + { + if ( (NULL != t->disconnect_handler) && t->peers[i]->connected) + { + GNUNET_PEER_resolve (t->peers[i]->id, &pi); + t->disconnect_handler (t->cls, &pi); + } + GNUNET_PEER_change_rc (t->peers[i]->id, -1); + GNUNET_free (t->peers[i]); + } + + /* signal tunnel destruction */ + if ( (NULL != h->cleaner) && (0 != t->owner) && (GNUNET_YES == call_cleaner) ) + h->cleaner (h->cls, t, t->ctx); + + /* check that clients did not leave messages behind in the queue */ + for (th = h->th_head; NULL != th; th = next) + { + next = th->next; + if (th->tunnel != t) + continue; + /* Clients should have aborted their requests already. + * Management traffic should be ok, as clients can't cancel that */ + GNUNET_break (NULL == th->notify); + GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); + + /* clean up request */ + if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task) + GNUNET_SCHEDULER_cancel (th->timeout_task); + GNUNET_free (th); + } + + /* if there are no more pending requests with mesh service, cancel active request */ + /* Note: this should be unnecessary... */ + if ( (NULL == h->th_head) && (NULL != h->th)) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } + + + if (t->npeers > 0) + GNUNET_free (t->peers); + if (0 != t->owner) + GNUNET_PEER_change_rc (t->owner, -1); + if (0 != t->napps && t->apps) + GNUNET_free (t->apps); + GNUNET_free (t); + return; +} + + +/** + * Get the peer descriptor for the peer with id from the given tunnel + * @param t Tunnel handle + * @param id Short form ID of the wanted peer + * @return handle to the requested peer or NULL if not found + */ +static struct GNUNET_MESH_Peer * +retrieve_peer (struct GNUNET_MESH_Tunnel *t, GNUNET_PEER_Id id) +{ + unsigned int i; + + for (i = 0; i < t->npeers; i++) + if (t->peers[i]->id == id) + return t->peers[i]; + return NULL; +} + + +/** + * Add a peer into a tunnel + * @param t Tunnel handle + * @param pi Full ID of the new peer + * @return handle to the newly created peer + */ +static struct GNUNET_MESH_Peer * +add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t, + const struct GNUNET_PeerIdentity *pi) +{ + struct GNUNET_MESH_Peer *p; + GNUNET_PEER_Id id; + + if (0 != t->owner) + { + GNUNET_break (0); + return NULL; + } + id = GNUNET_PEER_intern (pi); + + p = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer)); + p->id = id; + p->t = t; + GNUNET_array_append (t->peers, t->npeers, p); + return p; +} + + +/** + * Remove a peer from a tunnel + * @param p Peer handle + */ +static void +remove_peer_from_tunnel (struct GNUNET_MESH_Peer *p) +{ + unsigned int i; + + for (i = 0; i < p->t->npeers; i++) + { + if (p->t->peers[i] == p) + break; + } + if (i == p->t->npeers) + { + GNUNET_break (0); + return; + } + p->t->peers[i] = p->t->peers[p->t->npeers - 1]; + GNUNET_array_grow (p->t->peers, p->t->npeers, p->t->npeers - 1); +} + + +/** + * Notify client that the transmission has timed out + * @param cls closure + * @param tc task context + */ +static void +timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_MESH_TransmitHandle *th = cls; + struct GNUNET_MESH_Handle *mesh; + + mesh = th->tunnel->mesh; + GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th); + if (th->notify != NULL) + th->notify (th->notify_cls, 0, NULL); + GNUNET_free (th); + if ((NULL == mesh->th_head) && (NULL != mesh->th)) + { + /* queue empty, no point in asking for transmission */ + GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th); + mesh->th = NULL; + } +} + + +/** + * Add a transmit handle to the transmission queue by priority and set the + * timeout if needed. + * + * @param h mesh handle with the queue head and tail + * @param th handle to the packet to be transmitted + */ +static void +add_to_queue (struct GNUNET_MESH_Handle *h, + struct GNUNET_MESH_TransmitHandle *th) +{ + struct GNUNET_MESH_TransmitHandle *p; + + p = h->th_head; + while ((NULL != p) && (th->priority <= p->priority)) + p = p->next; + if (NULL == p) + p = h->th_tail; + else + p = p->prev; + GNUNET_CONTAINER_DLL_insert_after (h->th_head, h->th_tail, p, th); + if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value) + return; + th->timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (th->timeout), &timeout_transmission, th); +} + + +/** + * Auxiliary function to send an already constructed packet to the service. + * Takes care of creating a new queue element, copying the message and + * calling the tmt_rdy function if necessary. + * + * @param h mesh handle + * @param msg message to transmit + * @param tunnel tunnel this send is related to (NULL if N/A) + */ +static void +send_packet (struct GNUNET_MESH_Handle *h, + const struct GNUNET_MessageHeader *msg, + struct GNUNET_MESH_Tunnel *tunnel); + + +/** + * Reconnect callback: tries to reconnect again after a failer previous + * reconnecttion + * @param cls closure (mesh handle) + * @param tc task context + */ +static void +reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Send a connect packet to the service with the applications and types + * requested by the user. + * + * @param h The mesh handle. + * + */ +static void +send_connect (struct GNUNET_MESH_Handle *h) +{ + size_t size; + + size = sizeof (struct GNUNET_MESH_ClientConnect); + size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType); + size += h->n_handlers * sizeof (uint16_t); + { + char buf[size]; + struct GNUNET_MESH_ClientConnect *msg; + GNUNET_MESH_ApplicationType *apps; + uint16_t napps; + uint16_t *types; + uint16_t ntypes; + + /* build connection packet */ + msg = (struct GNUNET_MESH_ClientConnect *) buf; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT); + msg->header.size = htons (size); + apps = (GNUNET_MESH_ApplicationType *) &msg[1]; + for (napps = 0; napps < h->n_applications; napps++) + { + apps[napps] = htonl (h->applications[napps]); + LOG (GNUNET_ERROR_TYPE_DEBUG, " app %u\n", h->applications[napps]); + } + types = (uint16_t *) & apps[napps]; + for (ntypes = 0; ntypes < h->n_handlers; ntypes++) + types[ntypes] = htons (h->message_handlers[ntypes].type); + msg->applications = htons (napps); + msg->types = htons (ntypes); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending %lu bytes long message %d types and %d apps\n", + ntohs (msg->header.size), ntypes, napps); + send_packet (h, &msg->header, NULL); + } +} + + +/** + * Reconnect to the service, retransmit all infomation to try to restore the + * original state. + * + * @param h handle to the mesh + * + * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...) + */ +static int +do_reconnect (struct GNUNET_MESH_Handle *h) +{ + struct GNUNET_MESH_Tunnel *t; + unsigned int i; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "******* RECONNECT *******\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); + + h->in_receive = GNUNET_NO; + /* disconnect */ + if (NULL != h->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } + if (NULL != h->client) + { + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + } + + /* connect again */ + h->client = GNUNET_CLIENT_connect ("mesh", h->cfg); + if (h->client == NULL) + { + h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, + &reconnect_cbk, h); + h->reconnect_time = + GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, + GNUNET_TIME_relative_multiply + (h->reconnect_time, 2)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " Next retry in %sms\n", + GNUNET_TIME_relative_to_string (h->reconnect_time)); + GNUNET_break (0); + return GNUNET_NO; + } + else + { + h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; + } + send_connect (h); + /* Rebuild all tunnels */ + for (t = h->tunnels_head; NULL != t; t = t->next) + { + struct GNUNET_MESH_TunnelMessage tmsg; + struct GNUNET_MESH_PeerControl pmsg; + + if (t->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) + { + /* Tunnel was created by service (incoming tunnel) */ + /* TODO: Notify service of missing tunnel, to request + * creator to recreate path (find a path to him via DHT?) + */ + continue; + } + tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE); + tmsg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); + tmsg.tunnel_id = htonl (t->tid); + send_packet (h, &tmsg.header, t); + + pmsg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); + pmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD); + pmsg.tunnel_id = htonl (t->tid); + + /* Reconnect all peers */ + for (i = 0; i < t->npeers; i++) + { + GNUNET_PEER_resolve (t->peers[i]->id, &pmsg.peer); + if (NULL != t->disconnect_handler && t->peers[i]->connected) + t->disconnect_handler (t->cls, &pmsg.peer); + /* If the tunnel was "by type", dont connect individual peers */ + if (0 == t->napps) + send_packet (t->mesh, &pmsg.header, t); + } + /* Reconnect all types, if any */ + for (i = 0; i < t->napps; i++) + { + struct GNUNET_MESH_ConnectPeerByType msg; + + msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE); + msg.tunnel_id = htonl (t->tid); + msg.type = htonl (t->apps[i]); + send_packet (t->mesh, &msg.header, t); + } + } + return GNUNET_YES; +} + +/** + * Reconnect callback: tries to reconnect again after a failer previous + * reconnecttion + * @param cls closure (mesh handle) + * @param tc task context + */ +static void +reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_MESH_Handle *h = cls; + + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + do_reconnect (h); +} + + +/** + * Reconnect to the service, retransmit all infomation to try to restore the + * original state. + * + * @param h handle to the mesh + * + * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...) + */ +static void +reconnect (struct GNUNET_MESH_Handle *h) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "Requested RECONNECT\n"); + if (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task) + h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, + &reconnect_cbk, h); +} + + +/******************************************************************************/ +/*********************** RECEIVE HANDLERS ****************************/ +/******************************************************************************/ + +/** + * Process the new tunnel notification and add it to the tunnels in the handle + * + * @param h The mesh handle + * @param msg A message with the details of the new incoming tunnel + */ +static void +process_tunnel_created (struct GNUNET_MESH_Handle *h, + const struct GNUNET_MESH_TunnelNotification *msg) +{ + struct GNUNET_MESH_Tunnel *t; + MESH_TunnelNumber tid; + + tid = ntohl (msg->tunnel_id); + if (tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) + { + GNUNET_break (0); + return; + } + t = create_tunnel (h, tid); + t->owner = GNUNET_PEER_intern (&msg->peer); + t->npeers = 1; + t->peers = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer *)); + t->peers[0] = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer)); + t->peers[0]->t = t; + t->peers[0]->connected = 1; + t->peers[0]->id = t->owner; + GNUNET_PEER_change_rc (t->owner, 1); + t->mesh = h; + t->tid = tid; + if (NULL != h->new_tunnel) + { + struct GNUNET_ATS_Information atsi; + + atsi.type = 0; + atsi.value = 0; + t->ctx = h->new_tunnel (h->cls, t, &msg->peer, &atsi); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "new incoming tunnel %X\n", t->tid); + return; +} + + +/** + * Process the tunnel destroy notification and free associated resources + * + * @param h The mesh handle + * @param msg A message with the details of the tunnel being destroyed + */ +static void +process_tunnel_destroy (struct GNUNET_MESH_Handle *h, + const struct GNUNET_MESH_TunnelMessage *msg) +{ + struct GNUNET_MESH_Tunnel *t; + MESH_TunnelNumber tid; + + tid = ntohl (msg->tunnel_id); + t = retrieve_tunnel (h, tid); + + if (NULL == t) + { + return; + } + if (0 == t->owner) + { + GNUNET_break (0); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel %u destroyed\n", t->tid); + destroy_tunnel (t, GNUNET_YES); + return; +} + + +/** + * Process the new peer event and notify the upper level of it + * + * @param h The mesh handle + * @param msg A message with the details of the peer event + */ +static void +process_peer_event (struct GNUNET_MESH_Handle *h, + const struct GNUNET_MESH_PeerControl *msg) +{ + struct GNUNET_MESH_Tunnel *t; + struct GNUNET_MESH_Peer *p; + struct GNUNET_ATS_Information atsi; + GNUNET_PEER_Id id; + uint16_t size; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "processig peer event\n"); + size = ntohs (msg->header.size); + if (size != sizeof (struct GNUNET_MESH_PeerControl)) + { + GNUNET_break (0); + return; + } + t = retrieve_tunnel (h, ntohl (msg->tunnel_id)); + if (NULL == t) + { + GNUNET_break (0); + return; + } + id = GNUNET_PEER_search (&msg->peer); + if ((p = retrieve_peer (t, id)) == NULL) + p = add_peer_to_tunnel (t, &msg->peer); + if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == ntohs (msg->header.type)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "adding peer\n"); + if (NULL != t->connect_handler) + { + atsi.type = 0; + atsi.value = 0; + t->connect_handler (t->cls, &msg->peer, &atsi); + } + p->connected = 1; + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "removing peer\n"); + if (NULL != t->disconnect_handler && p->connected) + { + t->disconnect_handler (t->cls, &msg->peer); + } + remove_peer_from_tunnel (p); + GNUNET_free (p); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "processing peer event END\n"); +} + + +/** + * Process the incoming data packets + * + * @param h The mesh handle + * @param message A message encapsulating the data + * + * @return GNUNET_YES if everything went fine + * GNUNET_NO if client closed connection (h no longer valid) + */ +static int +process_incoming_data (struct GNUNET_MESH_Handle *h, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_MessageHeader *payload; + const struct GNUNET_MESH_MessageHandler *handler; + const struct GNUNET_PeerIdentity *peer; + struct GNUNET_MESH_Unicast *ucast; + struct GNUNET_MESH_Multicast *mcast; + struct GNUNET_MESH_ToOrigin *to_orig; + struct GNUNET_MESH_Tunnel *t; + unsigned int i; + uint16_t type; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a data message!\n"); + type = ntohs (message->type); + switch (type) + { + case GNUNET_MESSAGE_TYPE_MESH_UNICAST: + ucast = (struct GNUNET_MESH_Unicast *) message; + + t = retrieve_tunnel (h, ntohl (ucast->tid)); + payload = (struct GNUNET_MessageHeader *) &ucast[1]; + peer = &ucast->oid; + LOG (GNUNET_ERROR_TYPE_DEBUG, " ucast on tunnel %s [%x]\n", + GNUNET_i2s (peer), ntohl (ucast->tid)); + break; + case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: + mcast = (struct GNUNET_MESH_Multicast *) message; + t = retrieve_tunnel (h, ntohl (mcast->tid)); + payload = (struct GNUNET_MessageHeader *) &mcast[1]; + peer = &mcast->oid; + LOG (GNUNET_ERROR_TYPE_DEBUG, " mcast on tunnel %s [%x]\n", + GNUNET_i2s (peer), ntohl (mcast->tid)); + break; + case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: + to_orig = (struct GNUNET_MESH_ToOrigin *) message; + t = retrieve_tunnel (h, ntohl (to_orig->tid)); + payload = (struct GNUNET_MessageHeader *) &to_orig[1]; + peer = &to_orig->sender; + LOG (GNUNET_ERROR_TYPE_DEBUG, " torig on tunnel %s [%x]\n", + GNUNET_i2s (peer), ntohl (to_orig->tid)); + break; + default: + GNUNET_break (0); + return GNUNET_YES; + } + if (NULL == t) + { + GNUNET_break (0); + return GNUNET_YES; + } + type = ntohs (payload->type); + for (i = 0; i < h->n_handlers; i++) + { + handler = &h->message_handlers[i]; + if (handler->type == type) + { + struct GNUNET_ATS_Information atsi; + + atsi.type = 0; + atsi.value = 0; + if (GNUNET_OK != + handler->callback (h->cls, t, &t->ctx, peer, payload, &atsi)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH: callback caused disconnection\n"); + GNUNET_MESH_disconnect (h); + return GNUNET_NO; + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "MESH: callback completed successfully\n"); + + } + } + } + return GNUNET_YES; +} + + +/** + * Function to process all messages received from the service + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +msg_received (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_MESH_Handle *h = cls; + + if (msg == NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NULL msg\n"); + reconnect (h); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "received a message type %hu from MESH\n", + ntohs (msg->type)); + switch (ntohs (msg->type)) + { + /* Notify of a new incoming tunnel */ + case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE: + process_tunnel_created (h, (struct GNUNET_MESH_TunnelNotification *) msg); + break; + /* Notify of a tunnel disconnection */ + case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY: + process_tunnel_destroy (h, (struct GNUNET_MESH_TunnelMessage *) msg); + break; + /* Notify of a new peer or a peer disconnect in the tunnel */ + case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD: + case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL: + process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg); + break; + /* Notify of a new data packet in the tunnel */ + case GNUNET_MESSAGE_TYPE_MESH_UNICAST: + case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: + case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: + if (GNUNET_NO == process_incoming_data (h, msg)) + return; + break; + /* We shouldn't get any other packages, log and ignore */ + default: + LOG (GNUNET_ERROR_TYPE_WARNING, + "MESH: unsolicited message form service (type %d)\n", + ntohs (msg->type)); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n"); + GNUNET_CLIENT_receive (h->client, &msg_received, h, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/******************************************************************************/ +/************************ SEND FUNCTIONS ****************************/ +/******************************************************************************/ + +/** + * Function called to send a message to the service. + * "buf" will be NULL and "size" zero if the socket was closed for writing in + * the meantime. + * + * @param cls closure, the mesh handle + * @param size number of bytes available in buf + * @param buf where the callee should write the connect message + * @return number of bytes written to buf + */ +static size_t +send_callback (void *cls, size_t size, void *buf) +{ + struct GNUNET_MESH_Handle *h = cls; + struct GNUNET_MESH_TransmitHandle *th; + char *cbuf = buf; + size_t tsize; + size_t psize; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() Buffer %u\n", size); + h->th = NULL; + if ((0 == size) || (NULL == buf)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NULL callback\n"); + reconnect (h); + return 0; + } + tsize = 0; + while ((NULL != (th = h->th_head)) && (size >= th->size)) + { + if (NULL != th->notify) + { + if (th->tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) + { + /* traffic to origin */ + struct GNUNET_MESH_ToOrigin to; + struct GNUNET_MessageHeader *mh; + + GNUNET_assert (size >= th->size); + mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (to)]; + psize = th->notify (th->notify_cls, size - sizeof (to), mh); + LOG (GNUNET_ERROR_TYPE_DEBUG, " to origin, type %u\n", + ntohs (mh->type)); + if (psize > 0) + { + psize += sizeof (to); + GNUNET_assert (size >= psize); + to.header.size = htons (psize); + to.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN); + to.tid = htonl (th->tunnel->tid); + memset (&to.oid, 0, sizeof (struct GNUNET_PeerIdentity)); + memset (&to.sender, 0, sizeof (struct GNUNET_PeerIdentity)); + memcpy (cbuf, &to, sizeof (to)); + } + } + else if (th->target == 0) + { + /* multicast */ + struct GNUNET_MESH_Multicast mc; + struct GNUNET_MessageHeader *mh; + + GNUNET_assert (size >= th->size); + mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (mc)]; + psize = th->notify (th->notify_cls, size - sizeof (mc), mh); + LOG (GNUNET_ERROR_TYPE_DEBUG, " multicast, type %u\n", + ntohs (mh->type)); + if (psize > 0) + { + psize += sizeof (mc); + GNUNET_assert (size >= psize); + mc.header.size = htons (psize); + mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST); + mc.tid = htonl (th->tunnel->tid); + mc.mid = 0; + mc.ttl = 0; + memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); + memcpy (cbuf, &mc, sizeof (mc)); + } + } + else + { + /* unicast */ + struct GNUNET_MESH_Unicast uc; + struct GNUNET_MessageHeader *mh; + + GNUNET_assert (size >= th->size); + mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (uc)]; + psize = th->notify (th->notify_cls, size - sizeof (uc), mh); + LOG (GNUNET_ERROR_TYPE_DEBUG, " unicast, type %u\n", + ntohs (mh->type)); + if (psize > 0) + { + psize += sizeof (uc); + GNUNET_assert (size >= psize); + uc.header.size = htons (psize); + uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST); + uc.tid = htonl (th->tunnel->tid); + memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); + GNUNET_PEER_resolve (th->target, &uc.destination); + memcpy (cbuf, &uc, sizeof (uc)); + } + } + } + else + { + memcpy (cbuf, &th[1], th->size); + psize = th->size; + } + if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (th->timeout_task); + if (NULL != th->notify) + { + th->tunnel->mesh->npackets--; + th->tunnel->npackets--; + } + GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); + GNUNET_free (th); + cbuf += psize; + size -= psize; + tsize += psize; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " total size: %u\n", tsize); + if (NULL != (th = h->th_head)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " next size: %u\n", th->size); + if (NULL == h->th) + h->th = + GNUNET_CLIENT_notify_transmit_ready (h->client, th->size, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &send_callback, h); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() END\n"); + if (GNUNET_NO == h->in_receive) + { + h->in_receive = GNUNET_YES; + GNUNET_CLIENT_receive (h->client, &msg_received, h, + GNUNET_TIME_UNIT_FOREVER_REL); + } + return tsize; +} + + +/** + * Auxiliary function to send an already constructed packet to the service. + * Takes care of creating a new queue element, copying the message and + * calling the tmt_rdy function if necessary. + * + * @param h mesh handle + * @param msg message to transmit + * @param tunnel tunnel this send is related to (NULL if N/A) + */ +static void +send_packet (struct GNUNET_MESH_Handle *h, + const struct GNUNET_MessageHeader *msg, + struct GNUNET_MESH_Tunnel *tunnel) +{ + struct GNUNET_MESH_TransmitHandle *th; + size_t msize; + + msize = ntohs (msg->size); + th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize); + th->priority = UINT32_MAX; + th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; + th->size = msize; + th->tunnel = tunnel; + memcpy (&th[1], msg, msize); + add_to_queue (h, th); + if (NULL != h->th) + return; + h->th = + GNUNET_CLIENT_notify_transmit_ready (h->client, msize, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &send_callback, h); +} + + +/******************************************************************************/ +/********************** API CALL DEFINITIONS *************************/ +/******************************************************************************/ + +/** + * Connect to the mesh service. + * + * @param cfg configuration to use + * @param queue_size size of the data message queue, shared among all tunnels + * (each tunnel is guaranteed to accept at least one message, + * no matter what is the status of other tunnels) + * @param cls closure for the various callbacks that follow + * (including handlers in the handlers array) + * @param new_tunnel function called when an *inbound* tunnel is created + * @param cleaner function called when an *inbound* tunnel is destroyed by the + * remote peer, it is *not* called if GNUNET_MESH_tunnel_destroy + * is called on the tunnel + * @param handlers callbacks for messages we care about, NULL-terminated + * note that the mesh is allowed to drop notifications about + * inbound messages if the client does not process them fast + * enough (for this notification type, a bounded queue is used) + * @param stypes list of the applications that this client claims to provide + * @return handle to the mesh service NULL on error + * (in this case, init is never called) + */ +struct GNUNET_MESH_Handle * +GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int queue_size, void *cls, + GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel, + GNUNET_MESH_TunnelEndHandler cleaner, + const struct GNUNET_MESH_MessageHandler *handlers, + const GNUNET_MESH_ApplicationType *stypes) +{ + struct GNUNET_MESH_Handle *h; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect()\n"); + h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle)); + h->cfg = cfg; + h->max_queue_size = queue_size; + h->new_tunnel = new_tunnel; + h->cleaner = cleaner; + h->client = GNUNET_CLIENT_connect ("mesh", cfg); + if (h->client == NULL) + { + GNUNET_break (0); + GNUNET_free (h); + return NULL; + } + h->cls = cls; + /* FIXME memdup? */ + h->applications = stypes; + h->message_handlers = handlers; + h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_CLI; + h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + + /* count handlers and apps, calculate size */ + for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ; + for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ; + send_connect (h); + LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect() END\n"); + return h; +} + + +/** + * Disconnect from the mesh service. All tunnels will be destroyed. All tunnel + * disconnect callbacks will be called on any still connected peers, notifying + * about their disconnection. The registered inbound tunnel cleaner will be + * called should any inbound tunnels still exist. + * + * @param handle connection to mesh to disconnect + */ +void +GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle) +{ + struct GNUNET_MESH_Tunnel *t; + struct GNUNET_MESH_Tunnel *aux; + struct GNUNET_MESH_TransmitHandle *th; + + t = handle->tunnels_head; + while (NULL != t) + { + aux = t->next; + if (t->tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel %X not destroyed\n", t->tid); + } + destroy_tunnel (t, GNUNET_YES); + t = aux; + } + while ( (th = handle->th_head) != NULL) + { + struct GNUNET_MessageHeader *msg; + + /* Make sure it is an allowed packet (everything else should have been + * already canceled). + */ + GNUNET_break (UINT32_MAX == th->priority); + GNUNET_break (NULL == th->notify); + msg = (struct GNUNET_MessageHeader *) &th[1]; + switch (ntohs(msg->type)) + { + case GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT: + case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY: + break; + default: + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, "unexpected msg %u\n", + ntohs(msg->type)); + } + + GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th); + GNUNET_free (th); + } + + if (NULL != handle->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); + handle->th = NULL; + } + if (NULL != handle->client) + { + GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO); + handle->client = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task) + { + GNUNET_SCHEDULER_cancel(handle->reconnect_task); + handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (handle); +} + + +/** + * Create a new tunnel (we're initiator and will be allowed to add/remove peers + * and to broadcast). + * + * @param h mesh handle + * @param tunnel_ctx client's tunnel context to associate with the tunnel + * @param connect_handler function to call when peers are actually connected + * @param disconnect_handler function to call when peers are disconnected + * @param handler_cls closure for connect/disconnect handlers + */ +struct GNUNET_MESH_Tunnel * +GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx, + GNUNET_MESH_PeerConnectHandler connect_handler, + GNUNET_MESH_PeerDisconnectHandler disconnect_handler, + void *handler_cls) +{ + struct GNUNET_MESH_Tunnel *t; + struct GNUNET_MESH_TunnelMessage msg; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating new tunnel\n"); + t = create_tunnel (h, 0); + t->connect_handler = connect_handler; + t->disconnect_handler = disconnect_handler; + t->cls = handler_cls; + t->ctx = tunnel_ctx; + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE); + msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); + msg.tunnel_id = htonl (t->tid); + send_packet (h, &msg.header, t); + return t; +} + + +/** + * Destroy an existing tunnel. The existing callback for the tunnel will NOT + * be called. + * + * @param tunnel tunnel handle + */ +void +GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tunnel) +{ + struct GNUNET_MESH_Handle *h; + struct GNUNET_MESH_TunnelMessage msg; + struct GNUNET_MESH_TransmitHandle *th; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying tunnel\n"); + h = tunnel->mesh; + + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); + msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); + msg.tunnel_id = htonl (tunnel->tid); + th = h->th_head; + while (th != NULL) + { + struct GNUNET_MESH_TransmitHandle *aux; + if (th->tunnel == tunnel) + { + aux = th->next; + /* FIXME call the handler? */ + if (NULL != th->notify) + th->notify (th->notify_cls, 0, NULL); + GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); + GNUNET_free (th); + th = aux; + } + else + th = th->next; + } + + destroy_tunnel (tunnel, GNUNET_NO); + send_packet (h, &msg.header, tunnel); +} + + +/** + * Request that a peer should be added to the tunnel. The existing + * connect handler will be called ONCE with either success or failure. + * This function should NOT be called again with the same peer before the + * connect handler is called. + * + * @param tunnel handle to existing tunnel + * @param peer peer to add + */ +void +GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *peer) +{ + struct GNUNET_MESH_PeerControl msg; + GNUNET_PEER_Id peer_id; + unsigned int i; + + peer_id = GNUNET_PEER_intern (peer); + for (i = 0; i < tunnel->npeers; i++) + { + if (tunnel->peers[i]->id == peer_id) + { + /* Peer already exists in tunnel */ + GNUNET_PEER_change_rc (peer_id, -1); + GNUNET_break (0); + return; + } + } + if (NULL == add_peer_to_tunnel (tunnel, peer)) + return; + + msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD); + msg.tunnel_id = htonl (tunnel->tid); + msg.peer = *peer; + send_packet (tunnel->mesh, &msg.header, tunnel); + + return; +} + + +/** + * Request that a peer should be removed from the tunnel. The existing + * disconnect handler will be called ONCE if we were connected. + * + * @param tunnel handle to existing tunnel + * @param peer peer to remove + */ +void +GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *peer) +{ + struct GNUNET_MESH_PeerControl msg; + GNUNET_PEER_Id peer_id; + unsigned int i; + + peer_id = GNUNET_PEER_search (peer); + if (0 == peer_id) + { + GNUNET_break (0); + return; + } + for (i = 0; i < tunnel->npeers; i++) + if (tunnel->peers[i]->id == peer_id) + break; + if (i == tunnel->npeers) + { + GNUNET_break (0); + return; + } + if (NULL != tunnel->disconnect_handler && tunnel->peers[i]->connected == 1) + tunnel->disconnect_handler (tunnel->cls, peer); + GNUNET_PEER_change_rc (peer_id, -1); + GNUNET_free (tunnel->peers[i]); + tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1]; + GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1); + + msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL); + msg.tunnel_id = htonl (tunnel->tid); + memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity)); + send_packet (tunnel->mesh, &msg.header, tunnel); +} + + +/** + * Request that the mesh should try to connect to a peer supporting the given + * message type. + * + * @param tunnel handle to existing tunnel + * @param app_type application type that must be supported by the peer (MESH + * should discover peer in proximity handling this type) + */ +void +GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel, + GNUNET_MESH_ApplicationType app_type) +{ + struct GNUNET_MESH_ConnectPeerByType msg; + + GNUNET_array_append (tunnel->apps, tunnel->napps, app_type); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "* CONNECT BY TYPE *\n"); + msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE); + msg.tunnel_id = htonl (tunnel->tid); + msg.type = htonl (app_type); + send_packet (tunnel->mesh, &msg.header, tunnel); +} + + +/** + * Ask the mesh to call "notify" once it is ready to transmit the + * given number of bytes to the specified "target". If we are not yet + * connected to the specified peer, a call to this function will cause + * us to try to establish a connection. + * + * @param tunnel tunnel to use for transmission + * @param cork is corking allowed for this transmission? + * @param priority how important is the message? + * @param maxdelay how long can the message wait? + * @param target destination for the message, + * NULL for multicast to all tunnel targets + * @param notify_size how many bytes of buffer space does notify want? + * @param notify function to call when buffer space is available; + * will be called with NULL on timeout or if the overall queue + * for this peer is larger than queue_size and this is currently + * the message with the lowest priority + * @param notify_cls closure for notify + * @return non-NULL if the notify callback was queued, + * NULL if we can not even queue the request (insufficient + * memory); if NULL is returned, "notify" will NOT be called. + */ +struct GNUNET_MESH_TransmitHandle * +GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork, + uint32_t priority, + struct GNUNET_TIME_Relative maxdelay, + const struct GNUNET_PeerIdentity *target, + size_t notify_size, + GNUNET_CONNECTION_TransmitReadyNotify notify, + void *notify_cls) +{ + struct GNUNET_MESH_TransmitHandle *th; + struct GNUNET_MESH_TransmitHandle *least_priority_th; + uint32_t least_priority; + size_t overhead; + + GNUNET_assert (NULL != tunnel); + LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh notify transmit ready called\n"); + if (NULL != target) + LOG (GNUNET_ERROR_TYPE_DEBUG, " target %s\n", GNUNET_i2s (target)); + else + LOG (GNUNET_ERROR_TYPE_DEBUG, " target multicast\n"); + GNUNET_assert (NULL != notify); + if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size && + tunnel->npackets > 0) + { + /* queue full */ + if (0 == priority) + return NULL; + th = tunnel->mesh->th_tail; + least_priority = priority; + least_priority_th = NULL; + while (NULL != th) + { + if (th->priority < least_priority && th->tunnel->npackets > 1) + { + least_priority_th = th; + least_priority = th->priority; + } + th = th->prev; + } + if (NULL == least_priority_th) + return NULL; + /* Can't be a control message */ + GNUNET_assert (NULL != least_priority_th->notify); + least_priority_th->notify (notify_cls, 0, NULL); + least_priority_th->tunnel->npackets--; + tunnel->mesh->npackets--; + GNUNET_CONTAINER_DLL_remove (tunnel->mesh->th_head, tunnel->mesh->th_tail, + least_priority_th); + if (GNUNET_SCHEDULER_NO_TASK != least_priority_th->timeout_task) + GNUNET_SCHEDULER_cancel (least_priority_th->timeout_task); + GNUNET_free (least_priority_th); + } + tunnel->npackets++; + tunnel->mesh->npackets++; + th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle)); + th->tunnel = tunnel; + th->priority = priority; + th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay); + th->target = GNUNET_PEER_intern (target); + if (tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) + overhead = sizeof (struct GNUNET_MESH_ToOrigin); + else if (NULL == target) + overhead = sizeof (struct GNUNET_MESH_Multicast); + else + overhead = sizeof (struct GNUNET_MESH_Unicast); + th->size = notify_size + overhead; + th->notify = notify; + th->notify_cls = notify_cls; + add_to_queue (tunnel->mesh, th); + if (NULL != tunnel->mesh->th) + return th; + tunnel->mesh->th = + GNUNET_CLIENT_notify_transmit_ready (tunnel->mesh->client, th->size, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &send_callback, + tunnel->mesh); + return th; +} + + +/** + * Cancel the specified transmission-ready notification. + * + * @param th handle that was returned by "notify_transmit_ready". + */ +void +GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th) +{ + struct GNUNET_MESH_Handle *mesh; + + mesh = th->tunnel->mesh; + if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (th->timeout_task); + GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th); + GNUNET_free (th); + if ((NULL == mesh->th_head) && (NULL != mesh->th)) + { + /* queue empty, no point in asking for transmission */ + GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th); + mesh->th = NULL; + } +} + + +/** + * Transition API for tunnel ctx management + */ +void +GNUNET_MESH_tunnel_set_data (struct GNUNET_MESH_Tunnel *tunnel, void *data) +{ + tunnel->ctx = data; +} + +/** + * Transition API for tunnel ctx management + */ +void * +GNUNET_MESH_tunnel_get_data (struct GNUNET_MESH_Tunnel *tunnel) +{ + return tunnel->ctx; +} + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif diff --git a/src/mesh/mesh_protocol.h b/src/mesh/mesh_protocol.h new file mode 100644 index 0000000..885f1f3 --- /dev/null +++ b/src/mesh/mesh_protocol.h @@ -0,0 +1,292 @@ +/* + This file is part of GNUnet. + (C) 2001 - 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Bartlomiej Polot + * @file mesh/mesh_protocol.h + */ + +#ifndef MESH_PROTOCOL_H_ +#define MESH_PROTOCOL_H_ + +#ifdef __cplusplus +extern "C" +{ +#if 0 + /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/******************************************************************************/ +/******************** MESH NETWORK MESSAGES **************************/ +/******************************************************************************/ + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message for mesh path management + */ +struct GNUNET_MESH_ManipulatePath +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_PATH_[CREATE|CHANGE|ADD|DEL] + * + * Size: sizeof(struct GNUNET_MESH_ManipulatePath) + + * path_length * sizeof (struct GNUNET_PeerIdentity) + */ + struct GNUNET_MessageHeader header; + + /** + * Global id of the tunnel this path belongs to, + * unique in conjunction with the origin. + */ + uint32_t tid GNUNET_PACKED; + + /** + * path_length structs defining the *whole* path from the origin [0] to the + * final destination [path_length-1]. + */ + /* struct GNUNET_PeerIdentity peers[path_length]; */ +}; + +/** + * Message for mesh data traffic to all tunnel targets. + */ +struct GNUNET_MESH_Multicast +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_MULTICAST + */ + struct GNUNET_MessageHeader header; + + /** + * TID of the tunnel + */ + uint32_t tid GNUNET_PACKED; + + /** + * Number of hops to live + */ + uint32_t ttl GNUNET_PACKED; + + /** + * Unique ID of the packet + */ + uint32_t mid GNUNET_PACKED; + + /** + * OID of the tunnel + */ + struct GNUNET_PeerIdentity oid; + + /** + * Payload follows + */ +}; + + +/** + * Message for mesh data traffic to a particular destination from origin. + */ +struct GNUNET_MESH_Unicast +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_UNICAST + */ + struct GNUNET_MessageHeader header; + + /** + * TID of the tunnel + */ + uint32_t tid GNUNET_PACKED; + + /** + * OID of the tunnel + */ + struct GNUNET_PeerIdentity oid; + + /** + * Destination. + */ + struct GNUNET_PeerIdentity destination; + + /** + * Payload follows + */ +}; + + +/** + * Message for mesh data traffic from a tunnel participant to origin. + */ +struct GNUNET_MESH_ToOrigin +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN + */ + struct GNUNET_MessageHeader header; + + /** + * TID of the tunnel + */ + uint32_t tid GNUNET_PACKED; + + /** + * OID of the tunnel + */ + struct GNUNET_PeerIdentity oid; + + /** + * Sender of the message. + */ + struct GNUNET_PeerIdentity sender; + + /** + * Payload follows + */ +}; + + +/** + * Message for ack'ing a path + */ +struct GNUNET_MESH_PathACK +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_PATH_ACK + */ + struct GNUNET_MessageHeader header; + + /** + * TID of the tunnel + */ + uint32_t tid GNUNET_PACKED; + + /** + * OID of the tunnel + */ + struct GNUNET_PeerIdentity oid; + + /** + * ID of the endpoint + */ + struct GNUNET_PeerIdentity peer_id; + + /* TODO: signature */ +}; + + +/** + * Message for notifying a disconnection in a path + */ +struct GNUNET_MESH_PathBroken +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_PATH_BROKEN + */ + struct GNUNET_MessageHeader header; + + /** + * TID of the tunnel + */ + uint32_t tid GNUNET_PACKED; + + /** + * OID of the tunnel + */ + struct GNUNET_PeerIdentity oid; + + /** + * ID of the endpoint + */ + struct GNUNET_PeerIdentity peer1; + + /** + * ID of the endpoint + */ + struct GNUNET_PeerIdentity peer2; + + /* TODO: signature */ +}; + + +/** + * Message to destroy a tunnel + */ +struct GNUNET_MESH_TunnelDestroy +{ + /** + * Type: GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY + */ + struct GNUNET_MessageHeader header; + + /** + * TID of the tunnel + */ + uint32_t tid GNUNET_PACKED; + + /** + * OID of the tunnel + */ + struct GNUNET_PeerIdentity oid; + + /* TODO: signature */ +}; + + +/** + * Message for mesh flow control + */ +struct GNUNET_MESH_SpeedNotify +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DATA_SPEED_NOTIFY + */ + struct GNUNET_MessageHeader header; + + /** + * TID of the tunnel + */ + uint32_t tid GNUNET_PACKED; + + /** + * OID of the tunnel + */ + struct GNUNET_PeerIdentity oid; + + /** + * Slowest link down the path (above minimum speed requirement). + */ + uint32_t speed_min; + +}; +GNUNET_NETWORK_STRUCT_END + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef MES_PROTOCOL_H */ +#endif +/* end of mesh_protocol.h */ diff --git a/src/mesh/mesh_tunnel_tree.c b/src/mesh/mesh_tunnel_tree.c new file mode 100644 index 0000000..445b710 --- /dev/null +++ b/src/mesh/mesh_tunnel_tree.c @@ -0,0 +1,1075 @@ +/* + This file is part of GNUnet. + (C) 2001 - 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file mesh/mesh_tunnel_tree.c + * @brief Tunnel tree handling functions + * @author Bartlomiej Polot + */ + +#include "mesh.h" +#include "mesh_tunnel_tree.h" + +#define MESH_TREE_DEBUG GNUNET_YES + + +/** + * Node of path tree for a tunnel + */ +struct MeshTunnelTreeNode +{ + /** + * Peer this node describes + */ + GNUNET_PEER_Id peer; + + /** + * Parent node in the tree + */ + struct MeshTunnelTreeNode *parent; + + /** + * DLL of siblings + */ + struct MeshTunnelTreeNode *next; + + /** + * DLL of siblings + */ + struct MeshTunnelTreeNode *prev; + + /** + * DLL of children + */ + struct MeshTunnelTreeNode *children_head; + + /** + * DLL of children + */ + struct MeshTunnelTreeNode *children_tail; + + /** + * Status of the peer in the tunnel + */ + enum MeshPeerState status; +}; + + +/** + * Tree to reach all peers in the tunnel + */ +struct MeshTunnelTree +{ + /** + * Root node of peer tree + */ + struct MeshTunnelTreeNode *root; + + /** + * Node that represents our position in the tree (for non local tunnels) + */ + struct MeshTunnelTreeNode *me; + + /** + * DLL of disconneted nodes + */ + struct MeshTunnelTreeNode *disconnected_head; + + /** + * DLL of disconneted nodes + */ + struct MeshTunnelTreeNode *disconnected_tail; + + /** + * Cache of all peers and the first hop to them. + * Indexed by PeerIdentity, contains a pointer to the PeerIdentity + * of 1st hop. + */ + struct GNUNET_CONTAINER_MultiHashMap *first_hops; + +}; + + +/** + * Create a new path + * + * @param length How many hops will the path have. + * + * @return A newly allocated path with a peer array of the specified length. + */ +struct MeshPeerPath * +path_new (unsigned int length) +{ + struct MeshPeerPath *p; + + p = GNUNET_malloc (sizeof (struct MeshPeerPath)); + if (length > 0) + { + p->length = length; + p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id)); + } + return p; +} + + +/** + * Invert the path + * + * @param path the path to invert + */ +void +path_invert (struct MeshPeerPath *path) +{ + GNUNET_PEER_Id aux; + unsigned int i; + + for (i = 0; i < path->length / 2; i++) + { + aux = path->peers[i]; + path->peers[i] = path->peers[path->length - i - 1]; + path->peers[path->length - i - 1] = aux; + } +} + + +/** + * Duplicate a path, incrementing short peer's rc. + * + * @param path The path to duplicate. + */ +struct MeshPeerPath * +path_duplicate (struct MeshPeerPath *path) +{ + struct MeshPeerPath *aux; + unsigned int i; + + aux = path_new (path->length); + memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id)); + for (i = 0; i < path->length; i++) + GNUNET_PEER_change_rc (path->peers[i], 1); + return aux; +} + + +/** + * Recusively update the info about what is the first hop to reach the node + * + * @param tree Tree this nodes belongs to. + * @param parent The node form which to start updating. + * @param hop If known, ID of the first hop. + * If not known, NULL to find out and pass on children. + */ +static void +tree_node_update_first_hops (struct MeshTunnelTree *tree, + struct MeshTunnelTreeNode *parent, + struct GNUNET_PeerIdentity *hop); + + +/** + * Get the length of a path. + * + * @param path The path to measure, with the local peer at any point of it. + * + * @return Number of hops to reach destination. + * UINT_MAX in case the peer is not in the path. + */ +unsigned int +path_get_length (struct MeshPeerPath *path) +{ + if (NULL == path) + return UINT_MAX; + return path->length; +} + + +/** + * Destroy the path and free any allocated resources linked to it + * + * @param p the path to destroy + * + * @return GNUNET_OK on success + */ +int +path_destroy (struct MeshPeerPath *p) +{ + if (NULL == p) + return GNUNET_OK; + GNUNET_PEER_decrement_rcs (p->peers, p->length); + GNUNET_free_non_null (p->peers); + GNUNET_free (p); + return GNUNET_OK; +} + + + +/** + * Allocates and initializes a new node. + * Sets ID and parent of the new node and inserts it in the DLL of the parent + * + * @param parent Node that will be the parent from the new node, NULL for root + * @param peer Short Id of the new node + * + * @return Newly allocated node + */ +static struct MeshTunnelTreeNode * +tree_node_new (struct MeshTunnelTreeNode *parent, GNUNET_PEER_Id peer) +{ + struct MeshTunnelTreeNode *node; + + node = GNUNET_malloc (sizeof (struct MeshTunnelTreeNode)); + node->peer = peer; + GNUNET_PEER_change_rc (peer, 1); + node->parent = parent; + if (NULL != parent) + GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, + node); + + return node; +} + + +/** + * Recursively find the given peer. + * + * @param parent Node where to start looking. + * @param peer_id Short ID of the peer to find. + * + * @return Pointer to the node of the peer. NULL if not found. + */ +static struct MeshTunnelTreeNode * +tree_node_find_peer (struct MeshTunnelTreeNode *parent, GNUNET_PEER_Id peer_id) +{ + struct MeshTunnelTreeNode *n; + struct MeshTunnelTreeNode *r; + + if (parent->peer == peer_id) + return parent; + for (n = parent->children_head; NULL != n; n = n->next) + { + r = tree_node_find_peer (n, peer_id); + if (NULL != r) + return r; + } + return NULL; +} + + +/** + * Recusively update the info about what is the first hop to reach the node + * + * @param tree Tree this nodes belongs to. + * @param parent ID from node form which to start updating. + * @param hop If known, ID of the first hop. + * If not known, NULL to find out and pass on children. + */ +static void +tree_node_update_first_hops (struct MeshTunnelTree *tree, + struct MeshTunnelTreeNode *parent, + struct GNUNET_PeerIdentity *hop) +{ + struct GNUNET_PeerIdentity pi; + struct GNUNET_PeerIdentity *copy; + struct GNUNET_PeerIdentity id; + struct MeshTunnelTreeNode *n; + +#if MESH_TREE_DEBUG + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Finding first hop for %s.\n", + GNUNET_i2s (&id)); +#endif + if (NULL == hop) + { + struct MeshTunnelTreeNode *aux; + struct MeshTunnelTreeNode *old; + + aux = old = parent; + while (aux != tree->me) + { +#if MESH_TREE_DEBUG + GNUNET_PEER_resolve (aux->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: ... checking %s.\n", + GNUNET_i2s (&id)); +#endif + old = aux; + aux = aux->parent; + GNUNET_assert (NULL != aux); + } +#if MESH_TREE_DEBUG + GNUNET_PEER_resolve (old->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: It's %s!\n", + GNUNET_i2s (&id)); +#endif + hop = π + GNUNET_PEER_resolve (old->peer, hop); + } + GNUNET_PEER_resolve (parent->peer, &id); + copy = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey); + if (NULL == copy) + copy = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); + *copy = *hop; + + (void) GNUNET_CONTAINER_multihashmap_put (tree->first_hops, &id.hashPubKey, + copy, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + + for (n = parent->children_head; NULL != n; n = n->next) + { + tree_node_update_first_hops (tree, n, hop); + } +} + + +static void +tree_node_debug (struct MeshTunnelTreeNode *n, uint16_t level) +{ + struct MeshTunnelTreeNode *c; + struct GNUNET_PeerIdentity id;; + uint16_t i; + + for (i = 0; i < level; i++) + FPRINTF (stderr, "%s", " "); + if (n->status == MESH_PEER_READY) + FPRINTF (stderr, "%s", "#"); + if (n->status == MESH_PEER_SEARCHING) + FPRINTF (stderr, "%s", "+"); + if (n->status == MESH_PEER_RELAY) + FPRINTF (stderr, "%s", "-"); + if (n->status == MESH_PEER_RECONNECTING) + FPRINTF (stderr, "%s", "*"); + + GNUNET_PEER_resolve (n->peer, &id); + FPRINTF (stderr, "%s, [%u, %p] ", GNUNET_i2s (&id), n->peer, n); + if (NULL != n->parent) + { + GNUNET_PEER_resolve (n->parent->peer, &id); + FPRINTF (stderr, "(-> %s [%u])\n", GNUNET_i2s (&id), n->parent->peer); + } + else + FPRINTF (stderr, "%s", "(root)\n"); + for (c = n->children_head; NULL != c; c = c->next) + tree_node_debug (c, level + 1); +} + + +/** + * Destroys and frees the node and all children + * + * @param parent Parent node to be destroyed + */ +static void +tree_node_destroy (struct MeshTunnelTreeNode *parent) +{ + struct MeshTunnelTreeNode *n; + struct MeshTunnelTreeNode *next; + +#if MESH_TREE_DEBUG + struct GNUNET_PeerIdentity id; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying node %u\n", + parent->peer); + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: (%s)\n", GNUNET_i2s (&id)); +#endif + n = parent->children_head; + while (NULL != n) + { + next = n->next; + tree_node_destroy (n); + n = next; + } + GNUNET_PEER_change_rc (parent->peer, -1); + if (NULL != parent->parent) + GNUNET_CONTAINER_DLL_remove (parent->parent->children_head, + parent->parent->children_tail, parent); + GNUNET_free (parent); +} + + + +/** + * Create a new tree. + * + * @param peer A short peer id of the root of the tree. + * + * @return A newly allocated and initialized tunnel tree. + */ +struct MeshTunnelTree * +tree_new (GNUNET_PEER_Id peer) +{ + struct MeshTunnelTree *tree; + + tree = GNUNET_malloc (sizeof (struct MeshTunnelTree)); + tree->first_hops = GNUNET_CONTAINER_multihashmap_create (32); + tree->root = tree_node_new (NULL, peer); + tree->root->status = MESH_PEER_ROOT; + + if (1 == peer) + { + tree->me = tree->root; + } + + return tree; +} + + +/** + * Set the status of a node. + * + * @param tree Tree. + * @param peer A short peer id of the node. + * @param status New status to set. + */ +void +tree_set_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer, + enum MeshPeerState status) +{ + struct MeshTunnelTreeNode *n; + + n = tree_find_peer (tree, peer); + if (NULL == n) + return; + n->status = status; +} + + +/** + * Get the status of a node. + * + * @param tree Tree whose node's status we want to now. + * @param peer A short peer id of the node. + * + * @return Status of the peer. + */ +enum MeshPeerState +tree_get_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer) +{ + struct MeshTunnelTreeNode *n; + + n = tree_find_peer (tree, peer); + if (NULL == n) + return MESH_PEER_INVALID; + return n->status; +} + + +/** + * Get the id of the predecessor of the local node. + * + * @param tree Tree whose local id we want to now. + * + * @return Short peer id of local peer. + */ +GNUNET_PEER_Id +tree_get_predecessor (struct MeshTunnelTree *tree) +{ + if (NULL != tree->me && NULL != tree->me->parent) + return tree->me->parent->peer; + else + return (GNUNET_PEER_Id) 0; +} + + +/** + * Find the first peer whom to send a packet to go down this path + * + * @param t The tunnel tree to use + * @param peer The peerinfo of the peer we are trying to reach + * + * @return peerinfo of the peer who is the first hop in the tunnel + * NULL on error + */ +struct GNUNET_PeerIdentity * +tree_get_first_hop (struct MeshTunnelTree *t, GNUNET_PEER_Id peer) +{ + struct GNUNET_PeerIdentity id; + struct GNUNET_PeerIdentity *r; + + GNUNET_PEER_resolve (peer, &id); + r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); + if (NULL == r) + { + struct MeshTunnelTreeNode *n; + + n = tree_find_peer (t, peer); + if (NULL != t->me && NULL != n) + { + tree_node_update_first_hops (t, n, NULL); + r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); + GNUNET_assert (NULL != r); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Tree structure inconsistent! me: %p, n: %p", t->me, n); + GNUNET_break (0); + } + } + + return r; +} + + +/** + * Find the given peer in the tree. + * + * @param tree Tree where to look for the peer. + * @param peer_id Short ID of the peer to find. + * + * @return Pointer to the node of the peer. NULL if not found. + */ +struct MeshTunnelTreeNode * +tree_find_peer (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer_id) +{ + return tree_node_find_peer (tree->root, peer_id); +} + + +/** + * Recusively mark peer and children as disconnected, notify client + * + * @param tree Tree this node belongs to + * @param parent Node to be clean, potentially with children + * @param cb Callback to use to notify about disconnected peers. + * @param cbcls Closure for cb. + */ +static void +tree_mark_peers_disconnected (struct MeshTunnelTree *tree, + struct MeshTunnelTreeNode *parent, + MeshTreeCallback cb, void *cbcls) +{ + struct GNUNET_PeerIdentity *pi; + struct GNUNET_PeerIdentity id; + struct MeshTunnelTreeNode *n; + + for (n = parent->children_head; NULL != n; n = n->next) + { + tree_mark_peers_disconnected (tree, n, cb, cbcls); + } + if (MESH_PEER_READY == parent->status) + { + if (NULL != cb) + cb (cbcls, parent->peer); + parent->status = MESH_PEER_RECONNECTING; + } + + /* Remove and free info about first hop */ + GNUNET_PEER_resolve (parent->peer, &id); + pi = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey); + GNUNET_CONTAINER_multihashmap_remove_all (tree->first_hops, &id.hashPubKey); + if (NULL != pi) + GNUNET_free (pi); +} + + +/** + * Iterate over all children of the local node. + * + * @param tree Tree to use. Must have "me" set. + * @param cb Callback to call over each child. + * @param cls Closure. + */ +void +tree_iterate_children (struct MeshTunnelTree *tree, MeshTreeCallback cb, + void *cls) +{ + struct MeshTunnelTreeNode *n; + + if (NULL == tree->me) + { + GNUNET_break (0); + return; + } + for (n = tree->me->children_head; NULL != n; n = n->next) + { + cb (cls, n->peer); + } +} + + +/** + * Recusively update the info about what is the first hop to reach the node + * + * @param tree Tree this nodes belongs to. + * @param parent_id Short ID from node form which to start updating. + * @param hop If known, ID of the first hop. + * If not known, NULL to find out and pass on children. + */ +void +tree_update_first_hops (struct MeshTunnelTree *tree, GNUNET_PEER_Id parent_id, + struct GNUNET_PeerIdentity *hop) +{ + tree_node_update_first_hops (tree, tree_find_peer (tree, parent_id), hop); +} + + +/** + * Delete the current path to the peer, including all now unused relays. + * The destination peer is NOT destroyed, it is returned in order to either set + * a new path to it or destroy it explicitly, taking care of it's child nodes. + * + * @param t Tunnel tree where to delete the path from. + * @param peer_id Short ID of the destination peer whose path we want to remove. + * @param cb Callback to use to notify about disconnected peers. + * @param cbcls Closure for cb. + * + * @return pointer to the pathless node. + * NULL when not found + */ +struct MeshTunnelTreeNode * +tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id, + MeshTreeCallback cb, void *cbcls) +{ + struct MeshTunnelTreeNode *parent; + struct MeshTunnelTreeNode *node; + struct MeshTunnelTreeNode *n; + +#if MESH_TREE_DEBUG + struct GNUNET_PeerIdentity id; + + GNUNET_PEER_resolve (peer_id, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting path to %s.\n", + GNUNET_i2s (&id)); +#endif + if (peer_id == t->root->peer) + return NULL; + + for (n = t->disconnected_head; NULL != n; n = n->next) + { + if (n->peer == peer_id) + { + /* Was already pathless, waiting for reconnection */ + GNUNET_CONTAINER_DLL_remove (t->disconnected_head, t->disconnected_tail, + n); + return n; + } + } + n = tree_find_peer (t, peer_id); + if (NULL == n) + return NULL; + node = n; + + parent = n->parent; + GNUNET_CONTAINER_DLL_remove (parent->children_head, parent->children_tail, n); + n->parent = NULL; + + while (MESH_PEER_RELAY == parent->status && NULL == parent->children_head) + { +#if MESH_TREE_DEBUG + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting node %s.\n", + GNUNET_i2s (&id)); +#endif + n = parent->parent; + tree_node_destroy (parent); + parent = n; + } +#if MESH_TREE_DEBUG + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Not deleted peer %s.\n", + GNUNET_i2s (&id)); +#endif + + tree_mark_peers_disconnected (t, node, cb, cbcls); + + return node; +} + + +/** + * Return a newly allocated individual path to reach a peer from the local peer, + * according to the path tree of some tunnel. + * + * @param t Tunnel from which to read the path tree. + * @param peer Short ID of the destination peer to whom we want a path. + * + * @return A newly allocated individual path to reach the destination peer. + * Path must be destroyed afterwards. + */ +struct MeshPeerPath * +tree_get_path_to_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer) +{ + struct MeshTunnelTreeNode *n; + struct MeshPeerPath *p; + + n = tree_find_peer (t, peer); + if (NULL == n) + { + GNUNET_break (0); + return NULL; + } + p = path_new (0); + + /* Building the path (inverted!) */ + while (n->peer != 1) + { + GNUNET_array_append (p->peers, p->length, n->peer); + GNUNET_PEER_change_rc (n->peer, 1); + n = n->parent; + if (NULL == n) + { + GNUNET_break (0); + path_destroy (p); + return NULL; + } + } + GNUNET_array_append (p->peers, p->length, 1); + GNUNET_PEER_change_rc (1, 1); + + path_invert (p); + + return p; +} + + + +/** + * Integrate a stand alone path into the tunnel tree. + * If the peer toward which the new path is already in the tree, the peer + * and its children will be maked as disconnected and the callback + * will be called on each one of them. They will be maked as online only after + * receiving a PATH ACK for the new path for each one of them, so the caller + * should take care of sending a new CREATE PATH message for each disconnected + * peer. + * + * @param t Tunnel where to add the new path. + * @param p Path to be integrated. + * @param cb Callback to use to notify about peers temporarily disconnecting. + * @param cbcls Closure for cb. + * + * @return GNUNET_OK in case of success. + * GNUNET_SYSERR in case of error. + * + * TODO: optimize + * - go backwards on path looking for each peer in the present tree + * - do not disconnect peers until new path is created & connected + */ +int +tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, + MeshTreeCallback cb, void *cbcls) +{ + struct MeshTunnelTreeNode *parent; + struct MeshTunnelTreeNode *oldnode; + struct MeshTunnelTreeNode *n; + struct MeshTunnelTreeNode *c; + struct GNUNET_PeerIdentity id; + int me; + unsigned int i; + +#if MESH_TREE_DEBUG + GNUNET_PEER_resolve (p->peers[p->length - 1], &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "tree: Adding path [%u] towards peer %s.\n", p->length, + GNUNET_i2s (&id)); +#endif + + GNUNET_assert (0 != p->length); + parent = n = t->root; + if (n->peer != p->peers[0]) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (1 == p->length) + return GNUNET_OK; + oldnode = tree_del_path (t, p->peers[p->length - 1], cb, cbcls); + /* Look for the first node that is not already present in the tree + * + * Assuming that the tree is somewhat balanced, O(log n * log N). + * - Length of the path is expected to be log N (size of whole network). + * - Each level of the tree is expected to have log n children (size of tree). + */ + me = t->root->peer == 1 ? 0 : -1; + for (i = 1; i < p->length; i++) + { +#if MESH_TREE_DEBUG + GNUNET_PEER_resolve (p->peers[i], &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Looking for peer %s.\n", + GNUNET_i2s (&id)); +#endif + parent = n; + if (p->peers[i] == 1) + me = i; + for (c = n->children_head; NULL != c; c = c->next) + { + if (c->peer == p->peers[i]) + { +#if MESH_TREE_DEBUG + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "tree: Found in children of %s.\n", GNUNET_i2s (&id)); +#endif + n = c; + break; + } + } + /* If we couldn't find a child equal to path[i], we have reached the end + * of the common path. */ + if (parent == n) + break; + } +#if MESH_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: All childen visited.\n"); +#endif + /* Add the rest of the path as a branch from parent. */ + while (i < p->length) + { +#if MESH_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %u to %u.\n", + p->peers[i], parent->peer); + GNUNET_PEER_resolve (p->peers[i], &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %s.\n", + GNUNET_i2s (&id)); + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: to %s.\n", + GNUNET_i2s (&id)); +#endif + + if (i == p->length - 1 && NULL != oldnode) + { +#if MESH_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "tree: Putting old node into place.\n"); +#endif + oldnode->parent = parent; + GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, + oldnode); + tree_node_update_first_hops (t, oldnode, NULL); + n = oldnode; + } + else + { +#if MESH_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Creating new node.\n"); +#endif + n = tree_node_new (parent, p->peers[i]); + n->status = MESH_PEER_RELAY; + if (n->peer == 1) + { + t->me = n; + me = i; + } + } + i++; + parent = n; + } + n->status = MESH_PEER_SEARCHING; + + GNUNET_break (-1 != me); + + /* Add info about first hop into hashmap. */ + if (-1 != me && me < p->length - 1) + { +#if MESH_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MESH: finding first hop (own pos %d/%u)\n", me, + p->length - 1); +#endif + GNUNET_PEER_resolve (p->peers[me + 1], &id); + tree_update_first_hops (t, p->peers[me + 1], &id); + } +#if MESH_TREE_DEBUG + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MESH: was last in path, not updating first hops (%d/%u)\n", + me, p->length - 1); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: New node added.\n"); +#endif + if (NULL == t->me) + t->me = tree_find_peer (t, 1); + return GNUNET_OK; +} + + +/** + * Notifies a tree that a connection it might be using is broken. + * Marks all peers down the paths as disconnected and notifies the client. + * + * @param t Tree to use. + * @param p1 Short id of one of the peers (order unimportant) + * @param p2 Short id of one of the peers (order unimportant) + * @param cb Function to call for every peer that is marked as disconnected. + * @param cbcls Closure for cb. + * + * @return Short ID of the first disconnected peer in the tree. + */ +GNUNET_PEER_Id +tree_notify_connection_broken (struct MeshTunnelTree *t, GNUNET_PEER_Id p1, + GNUNET_PEER_Id p2, MeshTreeCallback cb, + void *cbcls) +{ + struct MeshTunnelTreeNode *n; + struct MeshTunnelTreeNode *c; + + n = tree_find_peer (t, p1); + if (NULL == n) + return 0; + if (NULL != n->parent && n->parent->peer == p2) + { + tree_mark_peers_disconnected (t, n, cb, cbcls); + GNUNET_CONTAINER_DLL_remove (n->parent->children_head, + n->parent->children_tail, n); + GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail, n); + return p1; + } + for (c = n->children_head; NULL != c; c = c->next) + { + if (c->peer == p2) + { + tree_mark_peers_disconnected (t, c, cb, cbcls); + GNUNET_CONTAINER_DLL_remove (n->children_head, n->children_tail, c); + GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail, + c); + return p2; + } + } + return 0; +} + + +/** + * Deletes a peer from a tunnel, liberating all unused resources on the path to + * it. It shouldn't have children, if it has they will be destroyed as well. + * If the tree is not local and no longer has any paths, the root node will be + * destroyed and marked as NULL. + * + * @param t Tunnel tree to use. + * @param peer Short ID of the peer to remove from the tunnel tree. + * @param cb Callback to notify client of disconnected peers. + * @param cbcls Closure for cb. + * + * @return GNUNET_OK or GNUNET_SYSERR + */ +int +tree_del_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer, + MeshTreeCallback cb, void *cbcls) +{ + struct MeshTunnelTreeNode *n; + + n = tree_del_path (t, peer, cb, cbcls); + if (NULL == n) + { + GNUNET_break (0); + return GNUNET_YES; + } + GNUNET_break_op (NULL == n->children_head); + tree_node_destroy (n); + if (NULL == t->root->children_head && t->me != t->root) + { + tree_node_destroy (t->root); + t->root = NULL; + return GNUNET_NO; + } + return GNUNET_YES; +} + + + +/** + * Get the cost of the path relative to the already built tunnel tree. + * + * @param t The tunnel tree to which compare. + * @param path The individual path to reach a peer. It has to start at the + * root of the tree to be comparable. + * + * @return Number of hops to reach destination, UINT_MAX in case the peer is not + * in the path. + * + * TODO: adapt to allow any start / root combination + * TODO: take in account state of the nodes + */ +unsigned int +tree_get_path_cost (struct MeshTunnelTree *t, struct MeshPeerPath *path) +{ + struct MeshTunnelTreeNode *n; + struct MeshTunnelTreeNode *p; + unsigned int i; + unsigned int l; + + l = path_get_length (path); + p = t->root; + if (t->root->peer != path->peers[0]) + { + GNUNET_break (0); + return UINT_MAX; + } + for (i = 1; i < l; i++) + { + for (n = p->children_head; NULL != n; n = n->next) + { + if (path->peers[i] == n->peer) + { + break; + } + } + if (NULL == n) + return l - i; + p = n; + } + return l - i; +} + + +/** + * Print the tree on stderr + * + * @param t The tree + */ +void +tree_debug (struct MeshTunnelTree *t) +{ + tree_node_debug (t->root, 0); +} + + +/** + * Iterator over hash map peer entries and frees all data in it. + * Used prior to destroying a hashmap. Makes you miss anonymous functions in C. + * + * @param cls closure + * @param key current key code (will no longer contain valid data!!) + * @param value value in the hash map (treated as void *) + * @return GNUNET_YES if we should continue to iterate, GNUNET_NO if not. + */ +static int +iterate_free (void *cls, const GNUNET_HashCode * key, void *value) +{ + GNUNET_free (value); + return GNUNET_YES; +} + + +/** + * Destroy the whole tree and free all used memory and Peer_Ids + * + * @param t Tree to be destroyed + */ +void +tree_destroy (struct MeshTunnelTree *t) +{ +#if MESH_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying tree\n"); +#endif + tree_node_destroy (t->root); + GNUNET_CONTAINER_multihashmap_iterate (t->first_hops, &iterate_free, NULL); + GNUNET_CONTAINER_multihashmap_destroy (t->first_hops); + GNUNET_free (t); +} diff --git a/src/mesh/mesh_tunnel_tree.h b/src/mesh/mesh_tunnel_tree.h new file mode 100644 index 0000000..84fd0ac --- /dev/null +++ b/src/mesh/mesh_tunnel_tree.h @@ -0,0 +1,345 @@ +/* + This file is part of GNUnet. + (C) 2001 - 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file mesh/mesh_tunnel_tree.h + * @brief Tunnel tree handling functions + * @author Bartlomiej Polot + */ + +#include "mesh.h" + +/******************************************************************************/ +/************************ DATA STRUCTURES ****************************/ +/******************************************************************************/ + +/** + * Information regarding a possible path to reach a single peer + */ +struct MeshPeerPath +{ + + /** + * Linked list + */ + struct MeshPeerPath *next; + struct MeshPeerPath *prev; + + /** + * List of all the peers that form the path from origin to target. + */ + GNUNET_PEER_Id *peers; + + /** + * Number of peers (hops) in the path + */ + unsigned int length; + +}; + + +/** + * Node of path tree for a tunnel + */ +struct MeshTunnelTreeNode; + + +/** + * Tree to reach all peers in the tunnel + */ +struct MeshTunnelTree; + + +/******************************************************************************/ +/************************* FUNCTIONS *****************************/ +/******************************************************************************/ + +/** + * Create a new path. + * + * @param length How many hops will the path have. + * + * @return A newly allocated path with a peer array of the specified length. + */ +struct MeshPeerPath * +path_new (unsigned int length); + + +/** + * Invert the path. + * + * @param path The path to invert. + */ +void +path_invert (struct MeshPeerPath *path); + + +/** + * Duplicate a path, incrementing short peer's rc. + * + * @param path The path to duplicate. + */ +struct MeshPeerPath * +path_duplicate (struct MeshPeerPath *path); + + +/** + * Get the length of a path. + * + * @param path The path to measure, with the local peer at any point of it. + * + * @return Number of hops to reach destination. + * UINT_MAX in case the peer is not in the path. + */ +unsigned int +path_get_length (struct MeshPeerPath *path); + + +/** + * Destroy the path and free any allocated resources linked to it + * + * @param p the path to destroy + * + * @return GNUNET_OK on success + */ +int +path_destroy (struct MeshPeerPath *p); + + +/******************************************************************************/ + +/** + * Method called whenever a node has been marked as disconnected. + * + * @param cls Closure. + * @param peer_id short ID of peer that is no longer reachable. + */ +typedef void (*MeshTreeCallback) (void *cls, GNUNET_PEER_Id peer_id); + + +/** + * Create a new tunnel tree associated to a tunnel + * + * @param peer A short peer id of the root of the tree + * + * @return A newly allocated and initialized tunnel tree + */ +struct MeshTunnelTree * +tree_new (GNUNET_PEER_Id peer); + + +/** + * Set the status of a node. + * + * @param tree Tree. + * @param peer A short peer id of the node. + * @param status New status to set. + */ +void +tree_set_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer, + enum MeshPeerState status); + + +/** + * Get the status of a node. + * + * @param tree Tree whose local id we want to now. + * @param peer A short peer id of the node. + * + * @return Short peer id of local peer. + */ +enum MeshPeerState +tree_get_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer); + + +/** + * Get the id of the predecessor of the local node. + * + * @param tree Tree whose local id we want to now. + * + * @return Short peer id of local peer. + */ +GNUNET_PEER_Id +tree_get_predecessor (struct MeshTunnelTree *tree); + + +/** + * Find the first peer whom to send a packet to go down this path + * + * @param t The tunnel tree to use + * @param peer The peerinfo of the peer we are trying to reach + * + * @return peerinfo of the peer who is the first hop in the tunnel + * NULL on error + */ +struct GNUNET_PeerIdentity * +tree_get_first_hop (struct MeshTunnelTree *t, GNUNET_PEER_Id peer); + + +/** + * Find the given peer in the tree. + * + * @param tree Tree where to look for the peer. + * @param peer_id Peer to find. + * + * @return Pointer to the node of the peer. NULL if not found. + */ +struct MeshTunnelTreeNode * +tree_find_peer (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer_id); + + +/** + * Iterate over all children of the local node. + * + * @param tree Tree to use. Must have "me" set. + * @param cb Callback to call over each child. + * @param cls Closure. + */ +void +tree_iterate_children (struct MeshTunnelTree *tree, MeshTreeCallback cb, + void *cls); + + +/** + * Recusively update the info about what is the first hop to reach the node + * + * @param tree Tree this nodes belongs to. + * @param parent_id Short ID from node form which to start updating. + * @param hop If known, ID of the first hop. + * If not known, NULL to find out and pass on children. + */ +void +tree_update_first_hops (struct MeshTunnelTree *tree, GNUNET_PEER_Id parent_id, + struct GNUNET_PeerIdentity *hop); + +/** + * Delete the current path to the peer, including all now unused relays. + * The destination peer is NOT destroyed, it is returned in order to either set + * a new path to it or destroy it explicitly, taking care of it's child nodes. + * + * @param t Tunnel tree where to delete the path from. + * @param peer_id Short ID of the destination peer whose path we want to remove. + * @param cb Callback to use to notify about which peers are going to be + * disconnected. + * @param cbcls Closure for cb. + * + * @return pointer to the pathless node. + * NULL when not found + */ +struct MeshTunnelTreeNode * +tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id, + MeshTreeCallback cb, void *cbcls); + + +/** + * Return a newly allocated individual path to reach a peer from the local peer, + * according to the path tree of some tunnel. + * + * @param t Tunnel from which to read the path tree + * @param peer Destination peer to whom we want a path + * + * @return A newly allocated individual path to reach the destination peer. + * Path must be destroyed afterwards. + */ +struct MeshPeerPath * +tree_get_path_to_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer); + + +/** + * Integrate a stand alone path into the tunnel tree. + * + * @param t Tunnel where to add the new path. + * @param p Path to be integrated. + * @param cb Callback to use to notify about peers temporarily disconnecting. + * @param cbcls Closure for cb. + * + * @return GNUNET_OK in case of success. + * GNUNET_SYSERR in case of error. + */ +int +tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, + MeshTreeCallback cb, void *cbcls); + + +/** + * Notifies a tree that a connection it might be using is broken. + * Marks all peers down the paths as disconnected and notifies the client. + * + * @param t Tree to use. + * @param p1 Short id of one of the peers (order unimportant) + * @param p2 Short id of one of the peers (order unimportant) + * @param cb Function to call for every peer that is marked as disconnected. + * @param cbcls Closure for cb. + * + * @return Short ID of the first disconnected peer in the tree. + */ +GNUNET_PEER_Id +tree_notify_connection_broken (struct MeshTunnelTree *t, GNUNET_PEER_Id p1, + GNUNET_PEER_Id p2, MeshTreeCallback cb, + void *cbcls); + + +/** + * Deletes a peer from a tunnel, liberating all unused resources on the path to + * it. It shouldn't have children, if it has they will be destroyed as well. + * If the tree is not local and no longer has any paths, the root node will be + * destroyed and marked as NULL. + * + * @param t Tunnel tree to use. + * @param peer Short ID of the peer to remove from the tunnel tree. + * @param cb Callback to notify client of disconnected peers. + * @param cbcls Closure for cb. + * + * @return GNUNET_YES if the tunnel still has nodes + */ +int +tree_del_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer, + MeshTreeCallback cb, void *cbcls); + + +/** + * Get the cost of the path relative to the already built tunnel tree + * + * @param t The tunnel tree to which compare + * @param path The individual path to reach a peer + * + * @return Number of hops to reach destination, UINT_MAX in case the peer is not + * in the path + */ +unsigned int +tree_get_path_cost (struct MeshTunnelTree *t, struct MeshPeerPath *path); + + +/** + * Print the tree on stderr + * + * @param t The tree + */ +void +tree_debug (struct MeshTunnelTree *t); + + +/** + * Destroy the whole tree and free all used memory and Peer_Ids + * + * @param t Tree to be destroyed + */ +void +tree_destroy (struct MeshTunnelTree *t); diff --git a/src/mesh/test_mesh.conf b/src/mesh/test_mesh.conf new file mode 100644 index 0000000..3d955f0 --- /dev/null +++ b/src/mesh/test_mesh.conf @@ -0,0 +1,69 @@ +[fs] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO + +[mesh] +DEBUG = YES +AUTOSTART = YES +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 10511 +# PREFIX = valgrind --leak-check=full +# PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 2100 + +[block] +plugins = dht test + +[dhtcache] +QUOTA = 1 MB +DATABASE = sqlite + +[transport] +PLUGINS = tcp +DEBUG = NO +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +NEIGHBOUR_LIMIT = 50 +PORT = 12365 + +[ats] +WAN_QUOTA_OUT = 3932160 +WAN_QUOTA_IN = 3932160 + +[core] +PORT = 12092 + +[arm] +DEFAULTSERVICES = core +PORT = 12366 +DEBUG = NO + +[transport-tcp] +TIMEOUT = 300 s +PORT = 12368 + +[TESTING] +WEAKRANDOM = YES + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[PATHS] +DEFAULTCONFIG = test_mesh.conf +SERVICEHOME = /tmp/test-mesh/ + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO diff --git a/src/mesh/test_mesh_2dtorus.c b/src/mesh/test_mesh_2dtorus.c new file mode 100644 index 0000000..9946fe2 --- /dev/null +++ b/src/mesh/test_mesh_2dtorus.c @@ -0,0 +1,370 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file mesh/test_mesh_2dtorus.c + * + * @brief Test for creating a 2dtorus. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_YES +#define REMOVE_DIR GNUNET_YES + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) + +/** + * Time to wait for stuff that should be rather fast + */ +#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + + +/** + * How many events have happened + */ +static int ok; + +/** + * Be verbose + */ +static int verbose; + +/** + * Total number of peers in the test. + */ +static unsigned long long num_peers; + +/** + * Global configuration file + */ +static struct GNUNET_CONFIGURATION_Handle *testing_cfg; + +/** + * Total number of currently running peers. + */ +static unsigned long long peers_running; + +/** + * Total number of successful connections in the whole network. + */ +static unsigned int total_connections; + +/** + * Total number of counted topo connections + */ +static unsigned int topo_connections; + +/** + * Total number of failed connections in the whole network. + */ +static unsigned int failed_connections; + +/** + * The currently running peer group. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Task called to disconnect peers + */ +static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +/** + * Task called to shutdown test. + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; + + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "test: Shutdown of peers failed! (%s)\n", emsg); + ok--; + } +#if VERBOSE + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: All peers successfully shut down!\n"); + } +#endif + GNUNET_CONFIGURATION_destroy (testing_cfg); +} + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n"); +#endif + + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +static void +disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: disconnecting peers\n"); + + if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) + { + GNUNET_SCHEDULER_cancel (shutdown_handle); + shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + } +} + + +/** + * Prototype of a callback function indicating that two peers + * are currently connected. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param emsg error message (NULL on success) + */ +void +topo_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, const char *emsg) +{ + topo_connections++; + if (NULL != emsg) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: Error by topo %u: %s\n", + topo_connections, emsg); + } + else + { + if (first == NULL || second == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u NULL\n", + topo_connections); + if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); + } + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u ok\n", + topo_connections); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (first)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (second)); + } +} + + +/** + * peergroup_ready: start test when all peers are connected + * @param cls closure + * @param emsg error message + */ +static void +peergroup_ready (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n", + emsg); + ok--; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "************************************************************\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Peer Group started successfully!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Have %u connections\n", + total_connections); +#endif + + peers_running = GNUNET_TESTING_daemons_running (pg); + if (0 < failed_connections) + { + ok = GNUNET_SYSERR; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: %u connections have FAILED!\n", + failed_connections); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); + + } + else + { + GNUNET_TESTING_get_topology (pg, &topo_cb, NULL); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_peers, NULL); + ok = GNUNET_OK; + } + +} + + +/** + * Function that will be called whenever two daemons are connected by + * the testing library. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param first_cfg config for the first daemon + * @param second_cfg config for the second daemon + * @param first_daemon handle for the first daemon + * @param second_daemon handle for the second daemon + * @param emsg error message (NULL on success) + */ +static void +connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; + } + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Problem with new connection (%s)\n", emsg); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (first)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (second)); + } + +} + + +/** + * run: load configuration options and schedule test to run (start peergroup) + * @param cls closure + * @param args argv + * @param cfgfile configuration file name (can be NULL) + * @param cfg configuration handle + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_TESTING_Host *hosts; + + ok = GNUNET_NO; + total_connections = 0; + failed_connections = 0; + testing_cfg = GNUNET_CONFIGURATION_dup (cfg); + + GNUNET_log_setup ("test_mesh_2dtorus", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", "YES"); +#endif + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", + "num_peers", &num_peers)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option TESTING:NUM_PEERS is required!\n"); + return; + } + + hosts = GNUNET_TESTING_hosts_load (testing_cfg); + + pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, + &connect_cb, &peergroup_ready, NULL, + hosts); + GNUNET_assert (pg != NULL); + shutdown_handle = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (), + &shutdown_task, NULL); +} + + +/** + * test_mesh_2dtorus command line options + */ +static struct GNUNET_GETOPT_CommandLineOption options[] = { + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END +}; + + +/** + * Main: start test + */ +int +main (int argc, char *argv[]) +{ + char *const argv2[] = { + argv[0], + "-c", + "test_mesh_2dtorus.conf", +#if VERBOSE + "-L", + "DEBUG", +#endif + NULL + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Start\n"); + + + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test_mesh_2dtorus", gettext_noop ("Test mesh 2d torus."), + options, &run, NULL); +#if REMOVE_DIR + GNUNET_DISK_directory_remove ("/tmp/test_mesh_2dtorus"); +#endif + if (GNUNET_OK != ok) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n"); + return 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n"); + return 0; +} + +/* end of test_mesh_2dtorus.c */ diff --git a/src/mesh/test_mesh_2dtorus.conf b/src/mesh/test_mesh_2dtorus.conf new file mode 100644 index 0000000..9a2227b --- /dev/null +++ b/src/mesh/test_mesh_2dtorus.conf @@ -0,0 +1,87 @@ +[PATHS] +SERVICEHOME = /tmp/test_mesh_small/ +DEFAULTCONFIG = test_mesh_small.conf + +[arm] +PORT = 10010 +DEFAULTSERVICES = core dht mesh +#DEBUG = YES + +[statistics] +AUTOSTART = YES +PORT = 10000 + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 10001 + +[nse] +WORKBITS = 0 + +[dns] +AUTOSTART = NO +PORT = 10011 + +[transport] +PORT = 10002 +AUTOSTART = YES + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +AUTOSTART = YES +PORT = 10003 + +[peerinfo] +AUTOSTART = YES +PORT = 10004 + +[mesh] +PORT = 10005 +DEBUG=YES +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +# PREFIX = valgrind --leak-check=full +# PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args + +[testing] +NUM_PEERS = 16 +WEAKRANDOM = YES +TOPOLOGY = 2D_TORUS +CONNECT_TOPOLOGY = 2D_TORUS +#TOPOLOGY_FILE = small.dat +CONNECT_TOPOLOGY = 2D_TORUS +#CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM +#CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 +#PERCENTAGE = 3 +#PROBABILITY = .1 +F2F = NO +CONNECT_TIMEOUT = 600 s +CONNECT_ATTEMPTS = 2 +DEBUG = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat +MAX_CONCURRENT_SSH = 10 +USE_PROGRESSBARS = YES +PEERGROUP_TIMEOUT = 2400 s +TOPOLOGY_OUTPUT_FILE = mesh_topo_initial +MAX_OUTSTANDING_CONNECTIONS = 75 +#SINGLE_PEERINFO_PER_HOST = YES +#NUM_PEERINFO_PER_HOST = 10 +#SINGLE_STATISTICS_PER_HOST = YES +#NUM_STATISTICS_PER_HOST = 10 +DELETE_FILES = YES diff --git a/src/mesh/test_mesh_api.c b/src/mesh/test_mesh_api.c new file mode 100644 index 0000000..fbc1fba --- /dev/null +++ b/src/mesh/test_mesh_api.c @@ -0,0 +1,192 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file mesh/test_mesh_api.c + * @brief test mesh api: dummy test of callbacks + * @author Bartlomiej Polot + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_mesh_service.h" + +#define VERBOSE 1 +#define VERBOSE_ARM 0 + +static struct GNUNET_OS_Process *arm_pid; +static struct GNUNET_MESH_Handle *mesh; +static struct GNUNET_MESH_Tunnel *t; +static int result; +static GNUNET_SCHEDULER_TaskIdentifier abort_task; +static GNUNET_SCHEDULER_TaskIdentifier test_task; + +/** + * Function is called whenever a message is received. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx place to store local state associated with the tunnel + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi) +{ + return GNUNET_OK; +} + +static struct GNUNET_MESH_MessageHandler handlers[] = { {&callback, 1, 0}, +{NULL, 0, 0} +}; + + +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != t) + { + GNUNET_MESH_tunnel_destroy (t); + } + if (0 != abort_task) + { + GNUNET_SCHEDULER_cancel (abort_task); + } + if (NULL != mesh) + { + GNUNET_MESH_disconnect (mesh); + } + if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + } + GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (arm_pid)); + GNUNET_OS_process_close (arm_pid); +} + +static void +do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (0 != test_task) + { + GNUNET_SCHEDULER_cancel (test_task); + } + result = GNUNET_SYSERR; + abort_task = 0; + do_shutdown (cls, tc); +} + +static void +test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + static const GNUNET_MESH_ApplicationType app[] = + { 1, 2, 3, 4, 5, 6, 7, 8, 0 }; + + test_task = (GNUNET_SCHEDULER_TaskIdentifier) 0; + mesh = GNUNET_MESH_connect (cfg, 10, NULL, NULL, NULL, handlers, app); + if (NULL == mesh) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: Couldn't connect to mesh :(\n"); + return; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: YAY! CONNECTED TO MESH :D\n"); + } + + t = GNUNET_MESH_tunnel_create (mesh, NULL, NULL, NULL, NULL); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), &do_shutdown, + NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_log_setup ("test_mesh_api", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + arm_pid = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE_ARM + "-L", "DEBUG", +#endif + "-c", "test_mesh.conf", NULL); + + abort_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort, + NULL); + + test_task = GNUNET_SCHEDULER_add_now (&test, (void *) cfg); + +} + + +int +main (int argc, char *argv[]) +{ + int ret; + + char *const argv2[] = { "test-mesh-api", + "-c", "test_mesh.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + ret = + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test-mesh-api", "nohelp", options, &run, NULL); + + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", + ret); + return 1; + } + if (GNUNET_SYSERR == result) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); + return 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test ok\n"); + return 0; +} diff --git a/src/mesh/test_mesh_local_1.c b/src/mesh/test_mesh_local_1.c new file mode 100644 index 0000000..73e2bdc --- /dev/null +++ b/src/mesh/test_mesh_local_1.c @@ -0,0 +1,357 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file mesh/test_mesh_local.c + * @brief test mesh local: test of tunnels with just one peer + * @author Bartlomiej Polot + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_mesh_service.h" + +#define VERBOSE 1 +#define VERBOSE_ARM 0 + +static struct GNUNET_OS_Process *arm_pid; +static struct GNUNET_MESH_Handle *mesh_peer_1; +static struct GNUNET_MESH_Handle *mesh_peer_2; +static struct GNUNET_MESH_Tunnel *t; +static unsigned int one = 1; +static unsigned int two = 2; + +static int result; +static GNUNET_SCHEDULER_TaskIdentifier abort_task; +static GNUNET_SCHEDULER_TaskIdentifier test_task; +static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + + +/** + * Shutdown nicely + */ +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n"); + if (0 != abort_task) + { + GNUNET_SCHEDULER_cancel (abort_task); + } + if (NULL != t) + { + GNUNET_MESH_tunnel_destroy(t); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: D1\n"); + if (NULL != mesh_peer_1) + { + GNUNET_MESH_disconnect (mesh_peer_1); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: D2\n"); + if (NULL != mesh_peer_2) + { + GNUNET_MESH_disconnect (mesh_peer_2); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: arm\n"); + if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n"); + GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (arm_pid)); + GNUNET_OS_process_close (arm_pid); +} + + +/** + * Something went wrong and timed out. Kill everything and set error flag + */ +static void +do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n"); + if (0 != test_task) + { + GNUNET_SCHEDULER_cancel (test_task); + } + result = GNUNET_SYSERR; + abort_task = 0; + if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) + { + GNUNET_SCHEDULER_cancel (shutdown_task); + shutdown_task = GNUNET_SCHEDULER_NO_TASK; + } + do_shutdown (cls, tc); +} + + +/** + * Function is called whenever a message is received. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx place to store local state associated with the tunnel + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Data callback\n"); + if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) + GNUNET_SCHEDULER_cancel (shutdown_task); + shutdown_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 2), &do_shutdown, + NULL); + return GNUNET_OK; +} + + +/** + * Method called whenever another peer has added us to a tunnel + * the other peer initiated. + * + * @param cls closure + * @param tunnel new handle to the tunnel + * @param initiator peer that started the tunnel + * @param atsi performance information for the tunnel + * @return initial tunnel context for the tunnel (can be NULL -- that's not an error) + */ +static void * +inbound_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *initiator, + const struct GNUNET_ATS_Information *atsi) +{ + unsigned int id = *(unsigned int *) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: received incoming tunnel\n"); + if (id != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "test: received incoming tunnel on peer 2\n"); + result = GNUNET_SYSERR; + } + return NULL; +} + + +/** + * Function called whenever an inbound tunnel is destroyed. Should clean up + * any associated state. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end (henceforth invalid) + * @param tunnel_ctx place where local state associated + * with the tunnel is stored + */ +static void +inbound_end (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, + void *tunnel_ctx) +{ + unsigned int id = *(unsigned int *) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: incoming tunnel closed\n"); + if (id != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "test: received closing tunnel on peer 2\n"); + result = GNUNET_SYSERR; + } +} + + +/** + * Method called whenever a peer has connected to the tunnel. + * + * @param cls closure + * @param peer peer identity the tunnel stopped working with + */ +static void +peer_conected (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer connected\n"); + if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) + GNUNET_SCHEDULER_cancel(shutdown_task); + shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &do_shutdown, NULL); +} + + +/** + * Method called whenever a peer has connected to the tunnel. + * + * @param cls closure + * @param peer peer identity the tunnel was created to, NULL on timeout + * @param atsi performance data for the connection + */ +static void +peer_disconnected (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer disconnected\n"); +} + + +/** + * Handler array for traffic received on peer1 + */ +static struct GNUNET_MESH_MessageHandler handlers1[] = { + {&data_callback, 1, 0}, + {NULL, 0, 0} +}; + + +/** + * Handler array for traffic received on peer2 (none expected) + */ +static struct GNUNET_MESH_MessageHandler handlers2[] = { {NULL, 0, 0} }; + + +/** + * Start looking for a peer by type + */ +static void +do_find (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: CONNECT BY TYPE\n"); + GNUNET_MESH_peer_request_connect_by_type (t, 1); +} + + +/** + * Main test function + */ +static void +test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + static const GNUNET_MESH_ApplicationType app1[] = { 1, 0 }; + static const GNUNET_MESH_ApplicationType app2[] = { 0 }; + + test_task = GNUNET_SCHEDULER_NO_TASK; + mesh_peer_1 = GNUNET_MESH_connect (cfg, /* configuration */ + 10, /* queue size */ + (void *) &one, /* cls */ + &inbound_tunnel, /* inbound new hndlr */ + &inbound_end, /* inbound end hndlr */ + handlers1, /* traffic handlers */ + app1); /* apps offered */ + + mesh_peer_2 = GNUNET_MESH_connect (cfg, /* configuration */ + 10, /* queue size */ + (void *) &two, /* cls */ + &inbound_tunnel, /* inbound new hndlr */ + &inbound_end, /* inbound end hndlr */ + handlers2, /* traffic handlers */ + app2); /* apps offered */ + if (NULL == mesh_peer_1 || NULL == mesh_peer_2) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: Couldn't connect to mesh :(\n"); + return; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: YAY! CONNECTED TO MESH :D\n"); + } + + t = GNUNET_MESH_tunnel_create (mesh_peer_2, NULL, &peer_conected, + &peer_disconnected, (void *) &two); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_find, NULL); +} + + +/** + * Initialize framework and start test + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_log_setup ("test_mesh_local", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + arm_pid = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE_ARM + "-L", "DEBUG", +#endif + "-c", "test_mesh.conf", NULL); + + abort_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort, + NULL); + + test_task = GNUNET_SCHEDULER_add_now (&test, (void *) cfg); + +} + + +/** + * Main + */ +int +main (int argc, char *argv[]) +{ + int ret; + + char *const argv2[] = { "test-mesh-local", + "-c", "test_mesh.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + result = GNUNET_OK; + ret = + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test-mesh-local", "nohelp", options, &run, NULL); + + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", + ret); + return 1; + } + if (GNUNET_SYSERR == result) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); + return 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test ok\n"); + return 0; +} diff --git a/src/mesh/test_mesh_local_2.c b/src/mesh/test_mesh_local_2.c new file mode 100644 index 0000000..b185f1b --- /dev/null +++ b/src/mesh/test_mesh_local_2.c @@ -0,0 +1,349 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file mesh/test_mesh_local.c + * @brief test mesh local: test of tunnels with just one peer + * @author Bartlomiej Polot + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_mesh_service.h" + +#define VERBOSE 1 +#define VERBOSE_ARM 0 + +static struct GNUNET_OS_Process *arm_pid; +static struct GNUNET_MESH_Handle *mesh_peer_1; +static struct GNUNET_MESH_Handle *mesh_peer_2; +static struct GNUNET_MESH_Tunnel *t; +static unsigned int one = 1; +static unsigned int two = 2; + +static int result; +static GNUNET_SCHEDULER_TaskIdentifier abort_task; +static GNUNET_SCHEDULER_TaskIdentifier test_task; + + +/** + * Shutdown nicely + */ +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n"); + if (0 != abort_task) + { + GNUNET_SCHEDULER_cancel (abort_task); + } + if (NULL != t) + { + GNUNET_MESH_tunnel_destroy(t); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: D1\n"); + if (NULL != mesh_peer_1) + { + GNUNET_MESH_disconnect (mesh_peer_1); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: D2\n"); + if (NULL != mesh_peer_2) + { + GNUNET_MESH_disconnect (mesh_peer_2); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: arm\n"); + if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n"); + GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (arm_pid)); + GNUNET_OS_process_close (arm_pid); +} + + +/** + * Something went wrong and timed out. Kill everything and set error flag + */ +static void +do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n"); + if (0 != test_task) + { + GNUNET_SCHEDULER_cancel (test_task); + } + result = GNUNET_SYSERR; + abort_task = 0; + do_shutdown (cls, tc); +} + + +/** + * Function is called whenever a message is received. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx place to store local state associated with the tunnel + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Data callback\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 2), &do_shutdown, + NULL); + return GNUNET_OK; +} + + +/** + * Method called whenever another peer has added us to a tunnel + * the other peer initiated. + * + * @param cls closure + * @param tunnel new handle to the tunnel + * @param initiator peer that started the tunnel + * @param atsi performance information for the tunnel + * @return initial tunnel context for the tunnel (can be NULL -- that's not an error) + */ +static void * +inbound_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *initiator, + const struct GNUNET_ATS_Information *atsi) +{ + unsigned int id = *(unsigned int *) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: received incoming tunnel\n"); + if (id != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "test: received incoming tunnel on peer 2\n"); + result = GNUNET_SYSERR; + } + return NULL; +} + + +/** + * Function called whenever an inbound tunnel is destroyed. Should clean up + * any associated state. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end (henceforth invalid) + * @param tunnel_ctx place where local state associated + * with the tunnel is stored + */ +static void +inbound_end (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, + void *tunnel_ctx) +{ + unsigned int id = *(unsigned int *) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: incoming tunnel closed\n"); + if (id != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "test: received closing tunnel on peer 2\n"); + result = GNUNET_SYSERR; + } +} + + +/** + * Method called whenever a peer has disconnected from the tunnel. + * + * @param cls closure + * @param peer peer identity the tunnel stopped working with + */ +static void +peer_conected (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer connected\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, NULL); +} + + +/** + * Method called whenever a peer has connected to the tunnel. + * + * @param cls closure + * @param peer peer identity the tunnel was created to, NULL on timeout + * @param atsi performance data for the connection + */ +static void +peer_disconnected (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer disconnected\n"); +} + + +/** + * Handler array for traffic received on peer1 + */ +static struct GNUNET_MESH_MessageHandler handlers1[] = { + {&data_callback, 1, 0}, + {NULL, 0, 0} +}; + + +/** + * Handler array for traffic received on peer2 (none expected) + */ +static struct GNUNET_MESH_MessageHandler handlers2[] = { {NULL, 0, 0} }; + + +/** + * Start looking for a peer by type + */ +static void +do_connect_peer_1 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + static const GNUNET_MESH_ApplicationType app1[] = { 1, 0 }; + + test_task = GNUNET_SCHEDULER_NO_TASK; + mesh_peer_1 = GNUNET_MESH_connect (cfg, /* configuration */ + 10, /* queue size */ + (void *) &one, /* cls */ + &inbound_tunnel, /* inbound new hndlr */ + &inbound_end, /* inbound end hndlr */ + handlers1, /* traffic handlers */ + app1); /* apps offered */ +} + + +/** + * Main test function + */ +static void +test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + static const GNUNET_MESH_ApplicationType app2[] = { 0 }; + + test_task = GNUNET_SCHEDULER_NO_TASK; + + mesh_peer_2 = GNUNET_MESH_connect (cfg, /* configuration */ + 10, /* queue size */ + (void *) &two, /* cls */ + &inbound_tunnel, /* inbound new hndlr */ + &inbound_end, /* inbound end hndlr */ + handlers2, /* traffic handlers */ + app2); /* apps offered */ + if (NULL == mesh_peer_2) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: Couldn't connect to mesh :(\n"); + return; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: YAY! CONNECTED TO MESH :D\n"); + } + + t = GNUNET_MESH_tunnel_create (mesh_peer_2, NULL, &peer_conected, + &peer_disconnected, (void *) &two); + GNUNET_MESH_peer_request_connect_by_type (t, 1); + test_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + &do_connect_peer_1, cfg); +} + + +/** + * Initialize framework and start test + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_log_setup ("test_mesh_local", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + arm_pid = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE_ARM + "-L", "DEBUG", +#endif + "-c", "test_mesh.conf", NULL); + + abort_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort, + NULL); + + test_task = GNUNET_SCHEDULER_add_now (&test, (void *) cfg); + +} + + +/** + * Main + */ +int +main (int argc, char *argv[]) +{ + int ret; + + char *const argv2[] = { "test-mesh-local", + "-c", "test_mesh.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + ret = + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test-mesh-local", "nohelp", options, &run, NULL); + + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", + ret); + return 1; + } + if (GNUNET_SYSERR == result) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); + return 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test ok\n"); + return 0; +} diff --git a/src/mesh/test_mesh_path.conf b/src/mesh/test_mesh_path.conf new file mode 100644 index 0000000..3d955f0 --- /dev/null +++ b/src/mesh/test_mesh_path.conf @@ -0,0 +1,69 @@ +[fs] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO + +[mesh] +DEBUG = YES +AUTOSTART = YES +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 10511 +# PREFIX = valgrind --leak-check=full +# PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 2100 + +[block] +plugins = dht test + +[dhtcache] +QUOTA = 1 MB +DATABASE = sqlite + +[transport] +PLUGINS = tcp +DEBUG = NO +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +NEIGHBOUR_LIMIT = 50 +PORT = 12365 + +[ats] +WAN_QUOTA_OUT = 3932160 +WAN_QUOTA_IN = 3932160 + +[core] +PORT = 12092 + +[arm] +DEFAULTSERVICES = core +PORT = 12366 +DEBUG = NO + +[transport-tcp] +TIMEOUT = 300 s +PORT = 12368 + +[TESTING] +WEAKRANDOM = YES + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[PATHS] +DEFAULTCONFIG = test_mesh.conf +SERVICEHOME = /tmp/test-mesh/ + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO diff --git a/src/mesh/test_mesh_small.c b/src/mesh/test_mesh_small.c new file mode 100644 index 0000000..b06e324 --- /dev/null +++ b/src/mesh/test_mesh_small.c @@ -0,0 +1,1020 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file mesh/test_mesh_small.c + * + * @brief Test for the mesh service: retransmission of traffic. + */ +#include +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_mesh_service.h" +#include + + +#define VERBOSE GNUNET_YES +#define REMOVE_DIR GNUNET_YES + +struct MeshPeer +{ + struct MeshPeer *prev; + + struct MeshPeer *next; + + struct GNUNET_TESTING_Daemon *daemon; + + struct GNUNET_MESH_Handle *mesh_handle; +}; + + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) + +/** + * Time to wait for stuff that should be rather fast + */ +#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +/** + * DIFFERENT TESTS TO RUN + */ +#define SETUP 0 +#define UNICAST 1 +#define MULTICAST 2 +#define SPEED 3 +#define SPEED_ACK 4 + +/** + * Which test are we running? + */ +static int test; + +/** + * How many events have happened + */ +static int ok; + +static int peers_in_tunnel; + +static int peers_responded; + +static int data_sent; + +static int data_received; + +static int data_ack; + +/** + * Be verbose + */ +static int verbose; + +/** + * Total number of peers in the test. + */ +static unsigned long long num_peers; + +/** + * Global configuration file + */ +static struct GNUNET_CONFIGURATION_Handle *testing_cfg; + +/** + * Total number of currently running peers. + */ +static unsigned long long peers_running; + +/** + * Total number of connections in the whole network. + */ +static unsigned int total_connections; + +/** + * The currently running peer group. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * File to report results to. + */ +static struct GNUNET_DISK_FileHandle *output_file; + +/** + * File to log connection info, statistics to. + */ +static struct GNUNET_DISK_FileHandle *data_file; + +/** + * How many data points to capture before triggering next round? + */ +static struct GNUNET_TIME_Relative wait_time; + +/** + * Task called to disconnect peers. + */ +static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +/** + * Task To perform tests + */ +static GNUNET_SCHEDULER_TaskIdentifier test_task; + +/** + * Task called to shutdown test. + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; + +static char *topology_file; + +static struct GNUNET_TESTING_Daemon *d1; + +static GNUNET_PEER_Id pid1; + +static struct GNUNET_TESTING_Daemon *d2; + +static struct GNUNET_TESTING_Daemon *d3; + +static struct GNUNET_MESH_Handle *h1; + +static struct GNUNET_MESH_Handle *h2; + +static struct GNUNET_MESH_Handle *h3; + +static struct GNUNET_MESH_Tunnel *t; + +static struct GNUNET_MESH_Tunnel *incoming_t; + +static struct GNUNET_MESH_Tunnel *incoming_t2; + +static struct GNUNET_TIME_Absolute start_time; + +static struct GNUNET_TIME_Absolute end_time; + +static struct GNUNET_TIME_Relative total_time; + + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Shutdown of peers failed!\n"); +#endif + ok--; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All peers successfully shut down!\n"); +#endif + } + GNUNET_CONFIGURATION_destroy (testing_cfg); +} + + +/** + * Shut down peergroup, clean up. + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Ending test.\n"); +#endif + + if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (NULL != h1) + { + GNUNET_MESH_disconnect (h1); + h1 = NULL; + } + if (NULL != h2) + { + GNUNET_MESH_disconnect (h2); + h2 = NULL; + } + if (test == MULTICAST && NULL != h3) + { + GNUNET_MESH_disconnect (h3); + h3 = NULL; + } + + if (data_file != NULL) + GNUNET_DISK_file_close (data_file); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +/** + * Disconnect from mesh services af all peers, call shutdown. + */ +static void +disconnect_mesh_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "disconnecting mesh service of peers\n"); + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + if (NULL != t) + { + GNUNET_MESH_tunnel_destroy(t); + t = NULL; + } + if (NULL != incoming_t) + { + GNUNET_MESH_tunnel_destroy(incoming_t); + incoming_t = NULL; + } + if (NULL != incoming_t2) + { + GNUNET_MESH_tunnel_destroy(incoming_t2); + incoming_t2 = NULL; + } + GNUNET_MESH_disconnect (h1); + GNUNET_MESH_disconnect (h2); + h1 = h2 = NULL; + if (test == MULTICAST) + { + GNUNET_MESH_disconnect (h3); + h3 = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) + { + GNUNET_SCHEDULER_cancel (shutdown_handle); + shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + } +} + +size_t +tmt_rdy (void *cls, size_t size, void *buf); + +static void +data_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_MESH_TransmitHandle *th; + if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) + return; + th = GNUNET_MESH_notify_transmit_ready (t, GNUNET_NO, 0, + GNUNET_TIME_UNIT_FOREVER_REL, &d2->id, + sizeof (struct GNUNET_MessageHeader), + &tmt_rdy, (void *) 1L); + if (NULL == th) + { + unsigned long i = (unsigned long) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Retransmission\n"); + if (0 == i) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " in 1 ms\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, + &data_task, (void *)1UL); + } + else + { + i++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "in %u ms\n", i); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply( + GNUNET_TIME_UNIT_MILLISECONDS, + i), + &data_task, (void *)i); + } + } +} + +/** + * Transmit ready callback + * + * @param cls Closure. + * @param size Size of the buffer we have. + * @param buf Buffer to copy data to. + */ +size_t +tmt_rdy (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg = buf; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " tmt_rdy called\n"); + if (size < sizeof (struct GNUNET_MessageHeader) || NULL == buf) + return 0; + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + msg->type = htons ((long) cls); + if (test == SPEED) + { + data_sent++; + if (data_sent < 1000) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " Scheduling %d packet\n", data_sent); + GNUNET_SCHEDULER_add_now(&data_task, NULL); + } + } + return sizeof (struct GNUNET_MessageHeader); +} + + +/** + * Function is called whenever a message is received. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx place to store local state associated with the tunnel + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi) +{ + long client = (long) cls; + + switch (client) + { + case 1L: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Origin client got a response!\n"); + ok++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); + peers_responded++; + data_ack++; + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, + NULL); + } + if (test == MULTICAST && peers_responded < 2) + return GNUNET_OK; + if (test == SPEED_ACK) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + " received ack %u\n", data_ack); + GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO, 0, + GNUNET_TIME_UNIT_FOREVER_REL, sender, + sizeof (struct GNUNET_MessageHeader), + &tmt_rdy, (void *) 1L); + if (data_ack < 1000) + return GNUNET_OK; + end_time = GNUNET_TIME_absolute_get(); + total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time); + FPRINTF (stderr, "\nTest time %llu ms\n", + (unsigned long long) total_time.rel_value); + FPRINTF (stderr, "Test bandwidth: %f kb/s\n", + 4000.0 / total_time.rel_value); + FPRINTF (stderr, "Test throughput: %f packets/s\n", + 1000000.0 / total_time.rel_value); + GAUGER ("MESH", "Tunnel 5 peers", 1000000.0 / total_time.rel_value, + "packets/s"); + } + GNUNET_assert (tunnel == t); + GNUNET_MESH_tunnel_destroy (t); + t = NULL; + break; + case 2L: + case 3L: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Destination client %u got a message.\n", + client); + ok++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); + if (SPEED != test) + { + GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO, 0, + GNUNET_TIME_UNIT_FOREVER_REL, sender, + sizeof (struct GNUNET_MessageHeader), + &tmt_rdy, (void *) 1L); + } + else + { + data_received++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + " received data %u\n", data_received); + if (data_received < 1000) + return GNUNET_OK; + } + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, + NULL); + } + break; + default: + break; + } + return GNUNET_OK; +} + + +/** + * Handlers, for diverse services + */ +static struct GNUNET_MESH_MessageHandler handlers[] = { + {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)}, + {NULL, 0, 0} +}; + + +/** + * Method called whenever another peer has added us to a tunnel + * the other peer initiated. + * + * @param cls closure + * @param tunnel new handle to the tunnel + * @param initiator peer that started the tunnel + * @param atsi performance information for the tunnel + * @return initial tunnel context for the tunnel + * (can be NULL -- that's not an error) + */ +static void * +incoming_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *initiator, + const struct GNUNET_ATS_Information *atsi) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Incoming tunnel from %s to peer %d\n", + GNUNET_i2s (initiator), (long) cls); + ok++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); + if ((long) cls == 2L) + incoming_t = tunnel; + else if ((long) cls == 3L) + incoming_t2 = tunnel; + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Incoming tunnel for unknown client %lu\n", (long) cls); + } + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL); + } + return NULL; +} + +/** + * Function called whenever an inbound tunnel is destroyed. Should clean up + * any associated state. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end (henceforth invalid) + * @param tunnel_ctx place where local state associated + * with the tunnel is stored + */ +static void +tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, + void *tunnel_ctx) +{ + long i = (long) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Incoming tunnel disconnected at peer %d\n", + i); + if (2L == i) + { + ok++; + incoming_t = NULL; + } + else if (3L == i) + { + ok++; + incoming_t2 = NULL; + } + else + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Unknown peer! %d\n", i); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); + peers_in_tunnel--; + if (peers_in_tunnel > 0) + return; + + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers, NULL); + } + + return; +} + + +/** + * Method called whenever a tunnel falls apart. + * + * @param cls closure + * @param peer peer identity the tunnel stopped working with + */ +static void +dh (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "peer %s disconnected\n", + GNUNET_i2s (peer)); + return; +} + + +/** + * Method called whenever a peer connects to a tunnel. + * + * @param cls closure + * @param peer peer identity the tunnel was created to, NULL on timeout + * @param atsi performance data for the connection + */ +static void +ch (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi) +{ + struct GNUNET_PeerIdentity *dest; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "peer %s connected\n", GNUNET_i2s (peer)); + + if (0 == memcmp (&d2->id, peer, sizeof (d2->id)) && (long) cls == 1L) + { + ok++; + } + if (test == MULTICAST && 0 == memcmp (&d3->id, peer, sizeof (d3->id)) && + (long) cls == 1L) + { + ok++; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); + switch (test) + { + case UNICAST: + case SPEED: + case SPEED_ACK: + dest = &d2->id; + break; + case MULTICAST: + peers_in_tunnel++; + if (peers_in_tunnel < 2) + return; + dest = NULL; + break; + default: + return; + } + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending data...\n"); + peers_responded = 0; + data_ack = 0; + data_received = 0; + data_sent = 0; + start_time = GNUNET_TIME_absolute_get(); + GNUNET_MESH_notify_transmit_ready (t, GNUNET_NO, 0, + GNUNET_TIME_UNIT_FOREVER_REL, dest, + sizeof (struct GNUNET_MessageHeader), + &tmt_rdy, (void *) 1L); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Disconnect already run?\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Aborting...\n"); + } + return; +} + + +static void +do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\n"); + if (test == MULTICAST) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "add peer 3\n"); + GNUNET_MESH_peer_request_connect_add (t, &d3->id); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "add peer 2\n"); + GNUNET_MESH_peer_request_connect_add (t, &d2->id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "schedule timeout in 90s\n"); + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL); + } +} + + +/** + * connect_mesh_service: connect to the mesh service of one of the peers + * + */ +static void +connect_mesh_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_MESH_ApplicationType app; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connect_mesh_service\n"); + + d2 = GNUNET_TESTING_daemon_get (pg, 4); + if (test == MULTICAST) + { + d3 = GNUNET_TESTING_daemon_get (pg, 3); + } + app = (GNUNET_MESH_ApplicationType) 0; + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connecting to mesh service of peer %s\n", + GNUNET_i2s (&d1->id)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connecting to mesh service of peer %s\n", + GNUNET_i2s (&d2->id)); + if (test == MULTICAST) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connecting to mesh service of peer %s\n", + GNUNET_i2s (&d3->id)); + } +#endif + h1 = GNUNET_MESH_connect (d1->cfg, 5, (void *) 1L, NULL, &tunnel_cleaner, + handlers, &app); + h2 = GNUNET_MESH_connect (d2->cfg, 5, (void *) 2L, &incoming_tunnel, + &tunnel_cleaner, handlers, &app); + if (test == MULTICAST) + { + h3 = GNUNET_MESH_connect (d3->cfg, 5, (void *) 3L, &incoming_tunnel, + &tunnel_cleaner, handlers, &app); + } + t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 1L); + peers_in_tunnel = 0; + test_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), &do_test, + NULL); +} + + + +/** + * peergroup_ready: start test when all peers are connected + * @param cls closure + * @param emsg error message + */ +static void +peergroup_ready (void *cls, const char *emsg) +{ + char *buf; + int buf_len; + unsigned int i; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Error from testing: `%s'\n", emsg); + ok--; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "************************************************************\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer Group started successfully!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Have %u connections\n", + total_connections); +#endif + + if (data_file != NULL) + { + buf = NULL; + buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections); + if (buf_len > 0) + GNUNET_DISK_file_write (data_file, buf, buf_len); + GNUNET_free (buf); + } + peers_running = GNUNET_TESTING_daemons_running (pg); + for (i = 0; i < num_peers; i++) + { + GNUNET_PEER_Id peer_id; + + d1 = GNUNET_TESTING_daemon_get (pg, i); + peer_id = GNUNET_PEER_intern (&d1->id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", + peer_id, GNUNET_i2s (&d1->id)); + } + d1 = GNUNET_TESTING_daemon_get (pg, 0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer looking: %s\n", + GNUNET_i2s (&d1->id)); + pid1 = GNUNET_PEER_intern (&d1->id); + + GNUNET_SCHEDULER_add_now (&connect_mesh_service, NULL); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_mesh_peers, NULL); + +} + + +/** + * Function that will be called whenever two daemons are connected by + * the testing library. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param first_cfg config for the first daemon + * @param second_cfg config for the second daemon + * @param first_daemon handle for the first daemon + * @param second_daemon handle for the second daemon + * @param emsg error message (NULL on success) + */ +static void +connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Problem with new connection (%s)\n", + emsg); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (%s)\n", GNUNET_i2s (first)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (%s)\n", GNUNET_i2s (second)); + } + +} + + +/** + * run: load configuration options and schedule test to run (start peergroup) + * @param cls closure + * @param args argv + * @param cfgfile configuration file name (can be NULL) + * @param cfg configuration handle + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *temp_str; + struct GNUNET_TESTING_Host *hosts; + char *data_filename; + + ok = 0; + testing_cfg = GNUNET_CONFIGURATION_dup (cfg); + + GNUNET_log_setup ("test_mesh_small", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", "YES"); +#endif + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", + "num_peers", &num_peers)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option TESTING:NUM_PEERS is required!\n"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (testing_cfg, "test_mesh_small", + "WAIT_TIME", &wait_time)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option test_mesh_small:wait_time is required!\n"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing", + "topology_output_file", + &topology_file)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option test_mesh_small:topology_output_file is required!\n"); + return; + } + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_mesh_small", + "data_output_file", + &data_filename)) + { + data_file = + GNUNET_DISK_file_open (data_filename, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (data_file == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", + data_filename); + GNUNET_free (data_filename); + } + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "test_mesh_small", + "output_file", &temp_str)) + { + output_file = + GNUNET_DISK_file_open (temp_str, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (output_file == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", + temp_str); + } + GNUNET_free_non_null (temp_str); + + hosts = GNUNET_TESTING_hosts_load (testing_cfg); + + pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, + &connect_cb, &peergroup_ready, NULL, + hosts); + GNUNET_assert (pg != NULL); + shutdown_handle = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (), + &shutdown_task, NULL); +} + + + +/** + * test_mesh_small command line options + */ +static struct GNUNET_GETOPT_CommandLineOption options[] = { + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END +}; + + +/** + * Main: start test + */ +int +main (int argc, char *argv[]) +{ + char * argv2[] = { + argv[0], + "-c", + "test_mesh_small.conf", +#if VERBOSE + "-L", + "DEBUG", +#endif + NULL + }; + int argc2 = (sizeof (argv2) / sizeof (char *)) - 1; + + /* Each peer is supposed to generate the following callbacks: + * 1 incoming tunnel (@dest) + * 1 connected peer (@orig) + * 1 received data packet (@dest) + * 1 received data packet (@orig) + * 1 received tunnel destroy (@dest) + * _________________________________ + * 5 x ok expected per peer + */ + int ok_goal; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n"); + if (strstr (argv[0], "test_mesh_small_unicast") != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNICAST\n"); + test = UNICAST; + ok_goal = 5; + } + else if (strstr (argv[0], "test_mesh_small_multicast") != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MULTICAST\n"); + test = MULTICAST; + ok_goal = 10; + } + else if (strstr (argv[0], "test_mesh_small_speed_ack") != NULL) + { + /* Each peer is supposed to generate the following callbacks: + * 1 incoming tunnel (@dest) + * 1 connected peer (@orig) + * 1000 received data packet (@dest) + * 1000 received data packet (@orig) + * 1 received tunnel destroy (@dest) + * _________________________________ + * 5 x ok expected per peer + */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n"); + test = SPEED_ACK; + ok_goal = 2003; + argv2 [3] = NULL; // remove -L DEBUG +#if VERBOSE + argc2 -= 2; +#endif + } + else if (strstr (argv[0], "test_mesh_small_speed") != NULL) + { + /* Each peer is supposed to generate the following callbacks: + * 1 incoming tunnel (@dest) + * 1 connected peer (@orig) + * 1000 received data packet (@dest) + * 1 received tunnel destroy (@dest) + * _________________________________ + * 5 x ok expected per peer + */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n"); + test = SPEED; + ok_goal = 1003; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n"); + test = SETUP; + ok_goal = 0; + } + + GNUNET_PROGRAM_run (argc2, argv2, + "test_mesh_small", + gettext_noop ("Test mesh in a small network."), options, + &run, NULL); +#if REMOVE_DIR + GNUNET_DISK_directory_remove ("/tmp/test_mesh_small"); +#endif + if (ok_goal > ok) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "FAILED! (%d/%d)\n", ok, ok_goal); + return 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n"); + return 0; +} + +/* end of test_mesh_small.c */ diff --git a/src/mesh/test_mesh_small.conf b/src/mesh/test_mesh_small.conf new file mode 100644 index 0000000..005c490 --- /dev/null +++ b/src/mesh/test_mesh_small.conf @@ -0,0 +1,95 @@ +[PATHS] +SERVICEHOME = /tmp/test_mesh_small/ +DEFAULTCONFIG = test_mesh_small.conf + +[arm] +PORT = 10010 +DEFAULTSERVICES = core dht mesh +#DEBUG = YES + +[statistics] +AUTOSTART = YES +PORT = 10000 + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 10001 + +[nse] +WORKBITS = 0 +INTERVAL = 60 s +WORKDELAY = 500 ms + +[dns] +AUTOSTART = NO +PORT = 10011 + +[transport] +PORT = 10002 +AUTOSTART = YES + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +AUTOSTART = YES +PORT = 10003 + +[peerinfo] +AUTOSTART = YES +PORT = 10004 + +[mesh] +PORT = 10005 +DEBUG = YES +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +# PREFIX = valgrind --leak-check=full --suppressions=valgrind-mesh.supp +# PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args + +[testing] +NUM_PEERS = 5 +WEAKRANDOM = YES +TOPOLOGY = NONE +CONNECT_TOPOLOGY = LINE +BLACKLIST_TOPOLOGY = LINE +BLACKLIST_TRANSPORTS = tcp udp http unix +#TOPOLOGY_FILE = small.dat +#CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM +#CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 +#PERCENTAGE = 3 +#PROBABILITY = .1 +F2F = NO +CONNECT_TIMEOUT = 660 s +CONNECT_ATTEMPTS = 2 +DEBUG = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat +MAX_CONCURRENT_SSH = 10 +USE_PROGRESSBARS = YES +PEERGROUP_TIMEOUT = 2400 s +TOPOLOGY_OUTPUT_FILE = mesh_topo_initial +MAX_OUTSTANDING_CONNECTIONS = 75 +#SINGLE_PEERINFO_PER_HOST = YES +#NUM_PEERINFO_PER_HOST = 10 +#SINGLE_STATISTICS_PER_HOST = YES +#NUM_STATISTICS_PER_HOST = 10 +DELETE_FILES = YES + +[test_mesh_small] +WAIT_TIME = 300 s +CONNECTION_LIMIT = 16 +#DATA_OUTPUT_FILE=data_output diff --git a/src/mesh/test_mesh_tree_api.c b/src/mesh/test_mesh_tree_api.c new file mode 100644 index 0000000..1d43135 --- /dev/null +++ b/src/mesh/test_mesh_tree_api.c @@ -0,0 +1,378 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file mesh/test_mesh_tree_api.c + * @brief test mesh tree api: test of tree & path management api + * @author Bartlomiej Polot + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_util_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_mesh_service.h" +#include "mesh.h" +#ifndef MESH_TUNNEL_TREE_C +#include "mesh_tunnel_tree.c" +#define MESH_TUNNEL_TREE_C +#endif + +#define VERBOSE 1 + +int failed; +int cb_call; +struct GNUNET_PeerIdentity *pi[10]; +struct MeshTunnelTree *tree; + +static void +cb (void *cls, GNUNET_PEER_Id peer_id) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: CB: Disconnected %u\n", peer_id); + if (0 == cb_call) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: and it shouldn't!\n"); + failed++; + } + cb_call--; +} + + +/** + * Check if a node has all expected properties. + * + * @param peer_id Short ID of the peer to test. + * @param status Expected status of the peer. + * @param children Expected number of children of the peer. + * @param first_hop Short ID of the expected first hop towards the peer. + */ +static void +test_assert (GNUNET_PEER_Id peer_id, enum MeshPeerState status, + unsigned int children, GNUNET_PEER_Id first_hop) +{ + struct MeshTunnelTreeNode *n; + struct MeshTunnelTreeNode *c; + unsigned int i; + int pre_failed; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Checking peer %u\n", peer_id); + pre_failed = failed; + n = tree_find_peer (tree, peer_id); + if (n->peer != peer_id) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Retrieved peer has wrong ID! (Got %u, expected %u)\n", n->peer, + peer_id); + failed++; + } + if (n->status != status) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Retrieved peer has wrong status! (Got %u, expected %u)\n", + n->status, status); + failed++; + } + for (c = n->children_head, i = 0; NULL != c; c = c->next, i++) ; + if (i != children) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Retrieved peer wrong has number of children! (Got %u, expected %u)\n", + i, children); + failed++; + } + if (0 != first_hop && + GNUNET_PEER_search (tree_get_first_hop (tree, peer_id)) != first_hop) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Wrong first hop! (Got %u, expected %u)\n", + GNUNET_PEER_search (tree_get_first_hop (tree, peer_id)), + first_hop); + failed++; + } + if (pre_failed != failed) + { + struct GNUNET_PeerIdentity id; + + GNUNET_PEER_resolve (peer_id, &id); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "*** Peer %s (%u) has failed %d checks!\n", GNUNET_i2s (&id), + peer_id, failed - pre_failed); + } +} + + +static void +finish (void) +{ + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Finishing...\n"); + for (i = 0; i < 10; i++) + { + GNUNET_free (pi[i]); + } +} + +/** + * Convert an integer int to a peer identity + */ +static struct GNUNET_PeerIdentity * +get_pi (uint32_t id) +{ + struct GNUNET_PeerIdentity *pi; + + pi = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); + pi->hashPubKey.bits[0] = id + 1; + return pi; +} + + +int +main (int argc, char *argv[]) +{ + struct MeshTunnelTreeNode *node; + struct MeshPeerPath *path; + struct MeshPeerPath *path1; + unsigned int i; + + failed = 0; + cb_call = 0; + GNUNET_log_setup ("test_mesh_api_tree", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + for (i = 0; i < 10; i++) + { + pi[i] = get_pi (i); + GNUNET_break (i + 1 == GNUNET_PEER_intern (pi[i])); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer %u: %s\n", i + 1, + GNUNET_h2s (&pi[i]->hashPubKey)); + } + tree = tree_new (1); + tree->me = tree->root; + path = path_new (5); + path->peers[0] = 1; + path->peers[1] = 2; + path->peers[2] = 3; + path->peers[3] = 4; + path->length = 4; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding first path: 1 2 3 4\n"); + tree_add_path (tree, path, &cb, NULL); + tree_debug (tree); + path1 = tree_get_path_to_peer (tree, 4); + if (NULL == path1 || path->length != path1->length || + memcmp (path->peers, path1->peers, path->length) != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retrieved path != original\n"); + failed++; + } + path_destroy (path1); + test_assert (4, MESH_PEER_SEARCHING, 0, 2); + test_assert (3, MESH_PEER_RELAY, 1, 0); + test_assert (2, MESH_PEER_RELAY, 1, 0); + test_assert (1, MESH_PEER_ROOT, 1, 0); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding second path: 1 2 3\n"); + path->length--; + tree_add_path (tree, path, &cb, NULL); + tree_debug (tree); + + test_assert (4, MESH_PEER_SEARCHING, 0, 2); + test_assert (3, MESH_PEER_SEARCHING, 1, 2); + test_assert (2, MESH_PEER_RELAY, 1, 0); + test_assert (1, MESH_PEER_ROOT, 1, 0); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding third path 1 2 3 5\n"); + path->length++; + path->peers[3] = 5; + tree_add_path (tree, path, &cb, NULL); + tree_debug (tree); + + test_assert (5, MESH_PEER_SEARCHING, 0, 2); + test_assert (4, MESH_PEER_SEARCHING, 0, 2); + test_assert (3, MESH_PEER_SEARCHING, 2, 2); + test_assert (2, MESH_PEER_RELAY, 1, 0); + test_assert (1, MESH_PEER_ROOT, 1, 0); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Calculating costs...\n"); + for (i = 1; i < 5; i++) + { + path->length = i; + if (tree_get_path_cost (tree, path) != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: length %u cost failed!\n", + i); + failed++; + } + } + path->length++; + path->peers[4] = 6; + if (tree_get_path_cost (tree, path) != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: length %u cost failed!\n", i); + failed++; + } + path->peers[3] = 7; + if (tree_get_path_cost (tree, path) != 2) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: length %u cost failed!\n", i); + failed++; + } + path->length--; + if (tree_get_path_cost (tree, path) != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: length %u cost failed!\n", i); + failed++; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Deleting third path (5)\n"); + tree_set_status (tree, 5, MESH_PEER_READY); + cb_call = 1; + node = tree_del_path (tree, 5, &cb, NULL); + tree_debug (tree); + if (cb_call != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%u callbacks missed!\n", cb_call); + failed++; + } + if (node->peer != 5) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retrieved peer != original\n"); + failed++; + } + + test_assert (4, MESH_PEER_SEARCHING, 0, 2); + test_assert (3, MESH_PEER_SEARCHING, 1, 2); + test_assert (2, MESH_PEER_RELAY, 1, 0); + test_assert (1, MESH_PEER_ROOT, 1, 0); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Destroying node copy...\n"); + GNUNET_free (node); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Adding new shorter first path...\n"); + path->length = 2; + path->peers[1] = 4; + cb_call = 1; + tree_find_peer (tree, 4)->status = MESH_PEER_READY; + tree_add_path (tree, path, &cb, NULL); + tree_debug (tree); + if (cb_call != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%u callbacks missed!\n", cb_call); + failed++; + } + + test_assert (4, MESH_PEER_SEARCHING, 0, 4); + test_assert (3, MESH_PEER_SEARCHING, 0, 2); + test_assert (2, MESH_PEER_RELAY, 1, 0); + test_assert (1, MESH_PEER_ROOT, 2, 0); + + GNUNET_free (path->peers); + GNUNET_free (path); + tree_destroy (tree); + + /****************************************************************************/ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test:\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Testing relay trees\n"); + for (i = 0; i < 10; i++) + { + GNUNET_break (i + 1 == GNUNET_PEER_intern (pi[i])); + } + tree = tree_new (2); + path = path_new (8); + path->peers[0] = 2; + path->peers[1] = 1; + path->peers[2] = 3; + path->length = 3; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding first path: 2 1 3\n"); + tree_add_path (tree, path, &cb, NULL); + tree_debug (tree); + + test_assert (3, MESH_PEER_SEARCHING, 0, 3); + test_assert (1, MESH_PEER_RELAY, 1, 0); + test_assert (2, MESH_PEER_ROOT, 1, 0); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding long path: 2 1 4 5 3\n"); + path->peers[2] = 4; + path->peers[3] = 5; + path->peers[4] = 3; + path->length = 5; + tree_add_path (tree, path, &cb, NULL); + tree_debug (tree); + + test_assert (3, MESH_PEER_SEARCHING, 0, 4); + test_assert (5, MESH_PEER_RELAY, 1, 4); + test_assert (4, MESH_PEER_RELAY, 1, 4); + test_assert (1, MESH_PEER_RELAY, 1, 0); + test_assert (2, MESH_PEER_ROOT, 1, 0); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Even longer path: 2 6 1 7 8 4 5 3\n"); + path->peers[0] = 2; + path->peers[1] = 6; + path->peers[2] = 1; + path->peers[3] = 7; + path->peers[4] = 8; + path->peers[5] = 4; + path->peers[6] = 5; + path->peers[7] = 3; + path->length = 8; + tree_add_path (tree, path, &cb, NULL); + tree_debug (tree); + + test_assert (3, MESH_PEER_SEARCHING, 0, 7); + test_assert (5, MESH_PEER_RELAY, 1, 7); + test_assert (4, MESH_PEER_RELAY, 1, 7); + test_assert (8, MESH_PEER_RELAY, 1, 7); + test_assert (7, MESH_PEER_RELAY, 1, 7); + test_assert (1, MESH_PEER_RELAY, 1, 0); + test_assert (6, MESH_PEER_RELAY, 1, 0); + test_assert (2, MESH_PEER_ROOT, 1, 0); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding first path: 2 1 3\n"); + path->peers[1] = 1; + path->peers[2] = 3; + path->length = 3; + tree_add_path (tree, path, &cb, NULL); + tree_debug (tree); + + test_assert (3, MESH_PEER_SEARCHING, 0, 3); + test_assert (1, MESH_PEER_RELAY, 1, 0); + test_assert (2, MESH_PEER_ROOT, 1, 0); + + GNUNET_free (path->peers); + GNUNET_free (path); + tree_destroy (tree); + finish (); + if (failed > 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%u tests failed\n", failed); + return 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: OK\n"); + + return 0; +} diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am new file mode 100644 index 0000000..47517b9 --- /dev/null +++ b/src/namestore/Makefile.am @@ -0,0 +1,105 @@ +INCLUDES = -I$(top_srcdir)/src/include + +plugindir = $(libdir)/gnunet + +pkgcfgdir= $(pkgnamedir)/config.d/ + +pkgcfg_NAME = \ + namestore.conf + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIBS = -lgcov +endif + +if HAVE_SQLITE +SQLITE_TESTS = \ + test_plugin_namestore_sqlite +endif + + +check_PROGRAMS = \ + $(SQLITE_TESTS) \ + test_namestore_api \ + test_namestore_api_zone_iteration \ + test_namestore_record_serialization + +if HAVE_EXPERIMENTAL + check_PROGRAMS +endif + +lib_LTLIBRARIES = \ + libgnunetnamestore.la + +libgnunetnamestore_la_SOURCES = \ + namestore_api.c namestore.h +libgnunetnamestore_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +libgnunetnamestore_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +bin_PROGRAMS = \ + gnunet-service-namestore + +gnunet_service_namestore_SOURCES = \ + gnunet-service-namestore.c \ + namestore_common.c +gnunet_service_namestore_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +if HAVE_SQLITE + SQLITE_PLUGIN = libgnunet_plugin_namestore_sqlite.la +endif + +plugin_LTLIBRARIES = \ + $(SQLITE_PLUGIN) + +libgnunet_plugin_namestore_sqlite_la_SOURCES = \ + plugin_namestore_sqlite.c +libgnunet_plugin_namestore_sqlite_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 +libgnunet_plugin_namestore_sqlite_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + +test_namestore_api_SOURCES = \ + test_namestore_api.c \ + namestore_common.c +test_namestore_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la + +test_namestore_api_zone_iteration_SOURCES = \ + test_namestore_api_zone_iteration.c \ + namestore_common.c +test_namestore_api_zone_iteration_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la + +test_namestore_record_serialization_SOURCES = \ + test_namestore_record_serialization.c \ + namestore_common.c +test_namestore_record_serialization_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la + +EXTRA_DIST = \ + test_namestore_api.conf \ + test_plugin_namestore_sqlite.conf\ + hostkey + + +test_plugin_namestore_sqlite_SOURCES = \ + test_plugin_namestore.c +test_plugin_namestore_sqlite_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la diff --git a/src/namestore/Makefile.in b/src/namestore/Makefile.in new file mode 100644 index 0000000..2ed2a46 --- /dev/null +++ b/src/namestore/Makefile.in @@ -0,0 +1,918 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +check_PROGRAMS = $(am__EXEEXT_1) test_namestore_api$(EXEEXT) \ + test_namestore_api_zone_iteration$(EXEEXT) \ + test_namestore_record_serialization$(EXEEXT) +bin_PROGRAMS = gnunet-service-namestore$(EXEEXT) +subdir = src/namestore +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/namestore.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = namestore.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(bindir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunet_plugin_namestore_sqlite_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunet_plugin_namestore_sqlite_la_OBJECTS = \ + plugin_namestore_sqlite.lo +libgnunet_plugin_namestore_sqlite_la_OBJECTS = \ + $(am_libgnunet_plugin_namestore_sqlite_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_namestore_sqlite_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_namestore_sqlite_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +@HAVE_SQLITE_TRUE@am_libgnunet_plugin_namestore_sqlite_la_rpath = \ +@HAVE_SQLITE_TRUE@ -rpath $(plugindir) +libgnunetnamestore_la_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunetnamestore_la_OBJECTS = namestore_api.lo +libgnunetnamestore_la_OBJECTS = $(am_libgnunetnamestore_la_OBJECTS) +libgnunetnamestore_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetnamestore_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@HAVE_SQLITE_TRUE@am__EXEEXT_1 = \ +@HAVE_SQLITE_TRUE@ test_plugin_namestore_sqlite$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_service_namestore_OBJECTS = \ + gnunet-service-namestore.$(OBJEXT) namestore_common.$(OBJEXT) +gnunet_service_namestore_OBJECTS = \ + $(am_gnunet_service_namestore_OBJECTS) +gnunet_service_namestore_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_test_namestore_api_OBJECTS = test_namestore_api.$(OBJEXT) \ + namestore_common.$(OBJEXT) +test_namestore_api_OBJECTS = $(am_test_namestore_api_OBJECTS) +test_namestore_api_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la +am_test_namestore_api_zone_iteration_OBJECTS = \ + test_namestore_api_zone_iteration.$(OBJEXT) \ + namestore_common.$(OBJEXT) +test_namestore_api_zone_iteration_OBJECTS = \ + $(am_test_namestore_api_zone_iteration_OBJECTS) +test_namestore_api_zone_iteration_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la +am_test_namestore_record_serialization_OBJECTS = \ + test_namestore_record_serialization.$(OBJEXT) \ + namestore_common.$(OBJEXT) +test_namestore_record_serialization_OBJECTS = \ + $(am_test_namestore_record_serialization_OBJECTS) +test_namestore_record_serialization_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la +am_test_plugin_namestore_sqlite_OBJECTS = \ + test_plugin_namestore.$(OBJEXT) +test_plugin_namestore_sqlite_OBJECTS = \ + $(am_test_plugin_namestore_sqlite_OBJECTS) +test_plugin_namestore_sqlite_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunet_plugin_namestore_sqlite_la_SOURCES) \ + $(libgnunetnamestore_la_SOURCES) \ + $(gnunet_service_namestore_SOURCES) \ + $(test_namestore_api_SOURCES) \ + $(test_namestore_api_zone_iteration_SOURCES) \ + $(test_namestore_record_serialization_SOURCES) \ + $(test_plugin_namestore_sqlite_SOURCES) +DIST_SOURCES = $(libgnunet_plugin_namestore_sqlite_la_SOURCES) \ + $(libgnunetnamestore_la_SOURCES) \ + $(gnunet_service_namestore_SOURCES) \ + $(test_namestore_api_SOURCES) \ + $(test_namestore_api_zone_iteration_SOURCES) \ + $(test_namestore_record_serialization_SOURCES) \ + $(test_plugin_namestore_sqlite_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +plugindir = $(libdir)/gnunet +pkgcfgdir = $(pkgnamedir)/config.d/ +pkgcfg_NAME = \ + namestore.conf + +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIBS = -lgcov +@HAVE_SQLITE_TRUE@SQLITE_TESTS = \ +@HAVE_SQLITE_TRUE@ test_plugin_namestore_sqlite + +lib_LTLIBRARIES = \ + libgnunetnamestore.la + +libgnunetnamestore_la_SOURCES = \ + namestore_api.c namestore.h + +libgnunetnamestore_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +libgnunetnamestore_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +gnunet_service_namestore_SOURCES = \ + gnunet-service-namestore.c \ + namestore_common.c + +gnunet_service_namestore_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +@HAVE_SQLITE_TRUE@SQLITE_PLUGIN = libgnunet_plugin_namestore_sqlite.la +plugin_LTLIBRARIES = \ + $(SQLITE_PLUGIN) + +libgnunet_plugin_namestore_sqlite_la_SOURCES = \ + plugin_namestore_sqlite.c + +libgnunet_plugin_namestore_sqlite_la_LIBADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 + +libgnunet_plugin_namestore_sqlite_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +test_namestore_api_SOURCES = \ + test_namestore_api.c \ + namestore_common.c + +test_namestore_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la + +test_namestore_api_zone_iteration_SOURCES = \ + test_namestore_api_zone_iteration.c \ + namestore_common.c + +test_namestore_api_zone_iteration_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la + +test_namestore_record_serialization_SOURCES = \ + test_namestore_record_serialization.c \ + namestore_common.c + +test_namestore_record_serialization_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la + +EXTRA_DIST = \ + test_namestore_api.conf \ + test_plugin_namestore_sqlite.conf\ + hostkey + +test_plugin_namestore_sqlite_SOURCES = \ + test_plugin_namestore.c + +test_plugin_namestore_sqlite_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/namestore/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/namestore/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +namestore.conf: $(top_builddir)/config.status $(srcdir)/namestore.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_namestore_sqlite.la: $(libgnunet_plugin_namestore_sqlite_la_OBJECTS) $(libgnunet_plugin_namestore_sqlite_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_namestore_sqlite_la_LINK) $(am_libgnunet_plugin_namestore_sqlite_la_rpath) $(libgnunet_plugin_namestore_sqlite_la_OBJECTS) $(libgnunet_plugin_namestore_sqlite_la_LIBADD) $(LIBS) +libgnunetnamestore.la: $(libgnunetnamestore_la_OBJECTS) $(libgnunetnamestore_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetnamestore_la_LINK) -rpath $(libdir) $(libgnunetnamestore_la_OBJECTS) $(libgnunetnamestore_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-service-namestore$(EXEEXT): $(gnunet_service_namestore_OBJECTS) $(gnunet_service_namestore_DEPENDENCIES) + @rm -f gnunet-service-namestore$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_namestore_OBJECTS) $(gnunet_service_namestore_LDADD) $(LIBS) +test_namestore_api$(EXEEXT): $(test_namestore_api_OBJECTS) $(test_namestore_api_DEPENDENCIES) + @rm -f test_namestore_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_namestore_api_OBJECTS) $(test_namestore_api_LDADD) $(LIBS) +test_namestore_api_zone_iteration$(EXEEXT): $(test_namestore_api_zone_iteration_OBJECTS) $(test_namestore_api_zone_iteration_DEPENDENCIES) + @rm -f test_namestore_api_zone_iteration$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_namestore_api_zone_iteration_OBJECTS) $(test_namestore_api_zone_iteration_LDADD) $(LIBS) +test_namestore_record_serialization$(EXEEXT): $(test_namestore_record_serialization_OBJECTS) $(test_namestore_record_serialization_DEPENDENCIES) + @rm -f test_namestore_record_serialization$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_namestore_record_serialization_OBJECTS) $(test_namestore_record_serialization_LDADD) $(LIBS) +test_plugin_namestore_sqlite$(EXEEXT): $(test_plugin_namestore_sqlite_OBJECTS) $(test_plugin_namestore_sqlite_DEPENDENCIES) + @rm -f test_plugin_namestore_sqlite$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_plugin_namestore_sqlite_OBJECTS) $(test_plugin_namestore_sqlite_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-namestore.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namestore_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namestore_common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_namestore_sqlite.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_zone_iteration.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_record_serialization.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_plugin_namestore.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-pluginLTLIBRARIES install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pluginLTLIBRARIES + + +@HAVE_EXPERIMENTAL_TRUE@ check_PROGRAMS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c new file mode 100644 index 0000000..92eb218 --- /dev/null +++ b/src/namestore/gnunet-service-namestore.c @@ -0,0 +1,845 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file namestore/gnunet-service-namestore.c + * @brief namestore for the GNUnet naming system + * @author Matthias Wachs + */ +#include "platform.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_service_lib.h" +#include "gnunet_namestore_service.h" +#include "gnunet_namestore_plugin.h" +#include "namestore.h" + + + +/** + * A namestore operation. + */ +struct GNUNET_NAMESTORE_ZoneIteration +{ + struct GNUNET_NAMESTORE_ZoneIteration *next; + struct GNUNET_NAMESTORE_ZoneIteration *prev; + + struct GNUNET_NAMESTORE_Client * client; + + GNUNET_HashCode zone; + + uint64_t op_id; + uint32_t offset; + +}; + + +/** + * A namestore client + */ +struct GNUNET_NAMESTORE_Client +{ + struct GNUNET_NAMESTORE_Client *next; + struct GNUNET_NAMESTORE_Client *prev; + + struct GNUNET_SERVER_Client * client; + + struct GNUNET_NAMESTORE_ZoneIteration *op_head; + struct GNUNET_NAMESTORE_ZoneIteration *op_tail; +}; + + + +/** + * Configuration handle. + */ +const struct GNUNET_CONFIGURATION_Handle *GSN_cfg; + +static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database; + +/** + * Our notification context. + */ +static struct GNUNET_SERVER_NotificationContext *snc; + +static char *db_lib_name; + +static struct GNUNET_NAMESTORE_Client *client_head; +static struct GNUNET_NAMESTORE_Client *client_tail; + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n"); + + struct GNUNET_NAMESTORE_ZoneIteration * no; + struct GNUNET_NAMESTORE_ZoneIteration * tmp; + struct GNUNET_NAMESTORE_Client * nc; + struct GNUNET_NAMESTORE_Client * next; + + for (nc = client_head; nc != NULL; nc = next) + { + next = nc->next; + for (no = nc->op_head; no != NULL; no = tmp) + { + GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no); + tmp = no->next; + GNUNET_free (no); + } + + GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc); + GNUNET_free (nc); + + } + + GNUNET_SERVER_notification_context_destroy (snc); + snc = NULL; + + GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database)); + GNUNET_free (db_lib_name); +} + +static struct GNUNET_NAMESTORE_Client * +client_lookup (struct GNUNET_SERVER_Client *client) +{ + struct GNUNET_NAMESTORE_Client * nc; + + GNUNET_assert (NULL != client); + + for (nc = client_head; nc != NULL; nc = nc->next) + { + if (client == nc->client) + break; + } + return nc; +} + + +/** + * Called whenever a client is disconnected. Frees our + * resources associated with that client. + * + * @param cls closure + * @param client identification of the client + */ +static void +client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct GNUNET_NAMESTORE_ZoneIteration * no; + struct GNUNET_NAMESTORE_Client * nc; + if (NULL == client) + return; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected \n", client); + + nc = client_lookup (client); + + if ((NULL == client) || (NULL == nc)) + return; + + for (no = nc->op_head; no != NULL; no = no->next) + { + GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no); + GNUNET_free (no); + } + + GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc); + GNUNET_free (nc); +} + +static void handle_start (void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client); + + struct GNUNET_NAMESTORE_Client * nc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Client)); + nc->client = client; + GNUNET_SERVER_notification_context_add (snc, client); + GNUNET_CONTAINER_DLL_insert(client_head, client_tail, nc); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + +struct LookupNameContext +{ + struct GNUNET_NAMESTORE_Client *nc; + uint32_t id; + uint32_t record_type; +}; + + + + +static void +handle_lookup_name_it (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + /* send response */ + struct LookupNameContext *lnc = cls; + struct LookupNameResponseMessage *lnr_msg; + + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key_tmp; + struct GNUNET_NAMESTORE_RecordData * rd_tmp; + char *name_tmp; + struct GNUNET_CRYPTO_RsaSignature *signature_tmp; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "NAMESTORE_LOOKUP_NAME_RESPONSE"); + + size_t r_size = 0; + + size_t name_len = 0; + if (NULL != name) + name_len = strlen(name) + 1; + + int copied_elements = 0; + int contains_signature = 0; + int c; + + /* count records to copy */ + if (rd_count != 0) + { + if (lnc->record_type != 0) + { + /* special record type needed */ + for (c = 0; c < rd_count; c ++) + if (rd[c].record_type == lnc->record_type) + copied_elements++; /* found matching record */ + } + else + copied_elements = rd_count; + } + + if ((copied_elements == rd_count) && (signature != NULL)) + contains_signature = GNUNET_YES; + + r_size = sizeof (struct LookupNameResponseMessage) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + name_len + + copied_elements * sizeof (struct GNUNET_NAMESTORE_RecordData) + + contains_signature * sizeof (struct GNUNET_CRYPTO_RsaSignature); + + lnr_msg = GNUNET_malloc (r_size); + + lnr_msg->header.type = ntohs (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE); + lnr_msg->header.size = ntohs (r_size); + lnr_msg->op_id = htonl (lnc->id); + lnr_msg->rc_count = htonl (copied_elements); + lnr_msg->name_len = htons (name_len); + lnr_msg->expire = GNUNET_TIME_absolute_hton(expire); + lnr_msg->contains_sig = htons (contains_signature); + + + zone_key_tmp = (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *) &lnr_msg[1]; + name_tmp = (char *) &zone_key_tmp[1]; + rd_tmp = (struct GNUNET_NAMESTORE_RecordData *) &name_tmp[name_len]; + signature_tmp = (struct GNUNET_CRYPTO_RsaSignature *) &rd_tmp[copied_elements]; + + if (zone_key != NULL) + memcpy (zone_key_tmp, zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + else + { + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded dummy; + memset (&dummy, '0', sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + memcpy (zone_key_tmp, &dummy, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + } + memcpy (name_tmp, name, name_len); + /* copy records */ + copied_elements = 0; + if (rd_count != 0) + { + if (lnc->record_type != 0) + { + /* special record type needed */ + for (c = 0; c < rd_count; c ++) + if (rd[c].record_type == lnc->record_type) + { + /* found matching record */ + memcpy (&rd_tmp[copied_elements], &rd[c], rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData)); + copied_elements++; + } + } + else + memcpy (rd_tmp, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData)); + } + + if (GNUNET_YES == contains_signature) + memcpy (signature_tmp, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature)); + GNUNET_SERVER_notification_context_unicast (snc, lnc->nc->client, (const struct GNUNET_MessageHeader *) lnr_msg, GNUNET_NO); + + GNUNET_free (lnr_msg); +} + +static void handle_lookup_name (void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_LOOKUP_NAME"); + struct LookupNameContext lnc; + struct GNUNET_NAMESTORE_Client *nc; + GNUNET_HashCode name_hash; + size_t name_len; + char * name; + uint32_t id = 0; + uint32_t type = 0; + + + if (ntohs (message->size) < sizeof (struct LookupNameMessage)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + nc = client_lookup(client); + if (nc == NULL) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + struct LookupNameMessage * ln_msg = (struct LookupNameMessage *) message; + id = ntohl (ln_msg->op_id); + name_len = ntohl (ln_msg->name_len); + type = ntohl (ln_msg->record_type); + + if ((name_len == 0) || (name_len > 256)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + name = GNUNET_malloc (name_len); + memcpy (name, &ln_msg[1], name_len); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking up record for name `%s'\n", name); + GNUNET_CRYPTO_hash(name, name_len-1, &name_hash); + GNUNET_free (name); + + /* do the actual lookup */ + lnc.id = id; + lnc.nc = nc; + lnc.record_type = type; + GSN_database->iterate_records(GSN_database->cls, &ln_msg->zone, &ln_msg->zone, 0, &handle_lookup_name_it, &lnc); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + +static void handle_record_put (void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_PUT"); + struct GNUNET_NAMESTORE_Client *nc; + struct GNUNET_TIME_Absolute expire; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key; + struct GNUNET_NAMESTORE_RecordData *rd; + struct GNUNET_CRYPTO_RsaSignature *signature; + struct RecordPutResponseMessage rpr_msg; + size_t name_len; + size_t msg_size; + size_t msg_size_exp; + char * name; + char * rd_ser; + uint32_t id = 0; + uint32_t rd_ser_len; + uint32_t rd_count; + int res = GNUNET_SYSERR; + + if (ntohs (message->size) < sizeof (struct RecordPutMessage)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + nc = client_lookup (client); + if (nc == NULL) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + struct RecordPutMessage * rp_msg = (struct RecordPutMessage *) message; + id = ntohl (rp_msg->op_id); + name_len = ntohs (rp_msg->name_len); + rd_ser_len = ntohs(rp_msg->rd_len); + msg_size = ntohs (message->size); + msg_size_exp = sizeof (struct RecordPutMessage) + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + name_len + rd_ser_len; + + if (msg_size != msg_size_exp) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Expected message %u size but message size is %u \n", msg_size_exp, msg_size); + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + + if ((name_len == 0) || (name_len > 256)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + zone_key = (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *) &rp_msg[1]; + name = (char *) &zone_key[1]; + expire = GNUNET_TIME_absolute_ntoh(rp_msg->expire); + signature = (struct GNUNET_CRYPTO_RsaSignature *) &rp_msg->signature; + rd_ser = &name[name_len]; + rd_count = GNUNET_NAMESTORE_records_deserialize(&rd, rd_ser, rd_ser_len); + + /* Database operation */ + res = GSN_database->put_records(GSN_database->cls, + zone_key, + expire, + name, + rd_count, rd, + signature); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting record for name `%s': %s\n", + name, (res == GNUNET_OK) ? "OK" : "FAIL"); + + /* Send response */ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "RECORD_PUT_RESPONSE"); + rpr_msg.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE); + rpr_msg.op_id = rp_msg->op_id; + rpr_msg.header.size = htons (sizeof (struct RecordPutResponseMessage)); + if (GNUNET_OK == res) + rpr_msg.op_result = htons (GNUNET_OK); + else + rpr_msg.op_result = htons (GNUNET_NO); + GNUNET_SERVER_notification_context_unicast (snc, nc->client, (const struct GNUNET_MessageHeader *) &rpr_msg, GNUNET_NO); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +static void handle_record_create (void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_CREATE"); + struct GNUNET_NAMESTORE_Client *nc; + struct RecordCreateResponseMessage rcr_msg; + size_t name_len; + size_t msg_size; + size_t msg_size_exp; + uint32_t id = 0; + + int res = GNUNET_SYSERR; + + if (ntohs (message->size) < sizeof (struct RecordCreateMessage)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + nc = client_lookup(client); + if (nc == NULL) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + struct RecordCreateMessage * rp_msg = (struct RecordCreateMessage *) message; + id = ntohl (rp_msg->op_id); + name_len = ntohs (rp_msg->name_len); + msg_size = ntohs (message->size); + msg_size_exp = sizeof (struct RecordCreateMessage) + name_len + sizeof (struct GNUNET_NAMESTORE_RecordData); + + if (msg_size != msg_size_exp) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Expected message %u size but message size is %u \n", msg_size_exp, msg_size); + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + + if ((name_len == 0) || (name_len > 256)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + /* DO WORK HERE */ + + /* Send response */ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "RECORD_CREATE_RESPONSE"); + rcr_msg.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE); + rcr_msg.op_id = rp_msg->op_id; + rcr_msg.header.size = htons (sizeof (struct RecordCreateResponseMessage)); + if (GNUNET_OK == res) + rcr_msg.op_result = htons (GNUNET_OK); + else + rcr_msg.op_result = htons (GNUNET_NO); + GNUNET_SERVER_notification_context_unicast (snc, nc->client, (const struct GNUNET_MessageHeader *) &rcr_msg, GNUNET_NO); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + +static void handle_record_remove (void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_REMOVE"); + struct GNUNET_NAMESTORE_Client *nc; + struct RecordRemoveResponseMessage rrr_msg; + size_t name_len; + size_t msg_size; + size_t msg_size_exp; + uint32_t id = 0; + + int res = GNUNET_SYSERR; + + if (ntohs (message->size) < sizeof (struct RecordRemoveMessage)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + nc = client_lookup(client); + if (nc == NULL) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + struct RecordRemoveMessage * rp_msg = (struct RecordRemoveMessage *) message; + id = ntohl (rp_msg->op_id); + name_len = ntohs (rp_msg->name_len); + msg_size = ntohs (message->size); + msg_size_exp = sizeof (struct RecordRemoveMessage) + name_len + sizeof (struct GNUNET_NAMESTORE_RecordData); + + if (msg_size != msg_size_exp) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Expected message %u size but message size is %u \n", msg_size_exp, msg_size); + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + + if ((name_len == 0) || (name_len > 256)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + /* DO WORK HERE */ + + /* Send response */ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "RECORD_REMOVE_RESPONSE"); + rrr_msg.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE); + rrr_msg.op_id = rp_msg->op_id; + rrr_msg.header.size = htons (sizeof (struct RecordRemoveResponseMessage)); + if (GNUNET_OK == res) + rrr_msg.op_result = htons (GNUNET_OK); + else + rrr_msg.op_result = htons (GNUNET_NO); + GNUNET_SERVER_notification_context_unicast (snc, nc->client, (const struct GNUNET_MessageHeader *) &rrr_msg, GNUNET_NO); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + +struct ZoneIterationProcResult +{ + int have_zone_key; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded zone_key; + + int have_signature; + struct GNUNET_CRYPTO_RsaSignature signature; + struct GNUNET_TIME_Absolute expire; + + int have_name; + char name[256]; + + unsigned int rd_count; + char *rd_ser; +}; + + +void zone_iteration_proc (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct ZoneIterationProcResult *zipr = cls; + size_t len; + if (zone_key != NULL) + { + zipr->zone_key = *zone_key; + zipr->have_zone_key = GNUNET_YES; + } + else + zipr->have_zone_key = GNUNET_NO; + + zipr->expire = expire; + + if (name != NULL) + { + memcpy (zipr->name, name, strlen(name) + 1); + zipr->have_name = GNUNET_YES; + } + else + zipr->have_name = GNUNET_NO; + + zipr->rd_count = rd_count; + + if (signature != NULL) + { + zipr->signature = *signature; + zipr->have_signature = GNUNET_YES; + } + else + zipr->have_signature = GNUNET_NO; + + if ((rd_count > 0) && (rd != NULL)) + { + len = GNUNET_NAMESTORE_records_serialize (&zipr->rd_ser, rd_count, rd); + } +} + +static void handle_iteration_start (void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_START"); + + struct ZoneIterationStartMessage * zis_msg = (struct ZoneIterationStartMessage *) message; + struct GNUNET_NAMESTORE_Client *nc; + struct GNUNET_NAMESTORE_ZoneIteration *zi; + struct ZoneIterationResponseMessage zir_msg; + struct ZoneIterationProcResult zipr; + int res; + + nc = client_lookup(client); + if (nc == NULL) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + zi = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIteration)); + zi->op_id = ntohl (zis_msg->op_id); + zi->offset = 0; + zi->client = nc; + zi->zone = zis_msg->zone; + + GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi); + + res = GSN_database->iterate_records (GSN_database->cls, &zis_msg->zone, NULL, zi->offset , &zone_iteration_proc, &zipr); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "ZONE_ITERATION_RESPONSE"); + zir_msg.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE); + zir_msg.op_id = htonl(zi->op_id); + zir_msg.header.size = htons (sizeof (struct ZoneIterationResponseMessage)); + + GNUNET_SERVER_notification_context_unicast (snc, zi->client->client, (const struct GNUNET_MessageHeader *) &zir_msg, GNUNET_NO); + + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + +static void handle_iteration_stop (void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_STOP"); + + struct GNUNET_NAMESTORE_Client *nc; + struct GNUNET_NAMESTORE_ZoneIteration *zi; + struct ZoneIterationStopMessage * zis_msg = (struct ZoneIterationStopMessage *) message; + uint32_t id; + + nc = client_lookup(client); + if (nc == NULL) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + id = ntohl (zis_msg->op_id); + for (zi = nc->op_head; zi != NULL; zi = zi->next) + { + if (zi->op_id == id) + break; + } + if (zi == NULL) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + GNUNET_CONTAINER_DLL_remove(nc->op_head, nc->op_tail, zi); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopped zone iteration for zone `%s'\n", GNUNET_h2s (&zi->zone)); + GNUNET_free (zi); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + +static void handle_iteration_next (void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_NEXT"); + + struct GNUNET_NAMESTORE_Client *nc; + struct GNUNET_NAMESTORE_ZoneIteration *zi; + struct ZoneIterationStopMessage * zis_msg = (struct ZoneIterationStopMessage *) message; + uint32_t id; + int res; + + nc = client_lookup(client); + if (nc == NULL) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + id = ntohl (zis_msg->op_id); + for (zi = nc->op_head; zi != NULL; zi = zi->next) + { + if (zi->op_id == id) + break; + } + if (zi == NULL) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + zi->offset++; + res = GSN_database->iterate_records (GSN_database->cls, &zi->zone, NULL, zi->offset , &zone_iteration_proc, zi); +} + + + +/** + * Process template requests. + * + * @param cls closure + * @param server the initialized server + * @param cfg configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char * database; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n"); + + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_start, NULL, + GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)}, + {&handle_lookup_name, NULL, + GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, 0}, + {&handle_record_put, NULL, + GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT, 0}, + {&handle_record_create, NULL, + GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE, 0}, + {&handle_record_remove, NULL, + GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE, 0}, + {&handle_iteration_start, NULL, + GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage)}, + {&handle_iteration_stop, NULL, + GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, sizeof (struct ZoneIterationStopMessage)}, + {&handle_iteration_next, NULL, + GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, 0}, + {NULL, NULL, 0, 0} + }; + + GSN_cfg = cfg; + + /* Loading database plugin */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database", + &database)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n"); + + GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database); + GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg); + if (GSN_database == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load database backend `%s'\n", + db_lib_name); + GNUNET_free (database); + + /* Configuring server handles */ + GNUNET_SERVER_add_handlers (server, handlers); + snc = GNUNET_SERVER_notification_context_create (server, 16); + GNUNET_SERVER_disconnect_notify (server, + &client_disconnect_notification, + NULL); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, + NULL); + +} + + +/** + * The main function for the template service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "namestore", + GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-service-namestore.c */ diff --git a/src/namestore/hostkey b/src/namestore/hostkey new file mode 100644 index 0000000..eac1d1e Binary files /dev/null and b/src/namestore/hostkey differ diff --git a/src/namestore/namestore.conf.in b/src/namestore/namestore.conf.in new file mode 100644 index 0000000..c9b9984 --- /dev/null +++ b/src/namestore/namestore.conf.in @@ -0,0 +1,30 @@ +[namestore] +AUTOSTART = YES +UNIXPATH = /tmp/gnunet-service-namestore.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +@UNIXONLY@ PORT = 2099 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-namestore +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DATABASE = sqlite + +[namestore-sqlite] +FILENAME = $SERVICEHOME/namestore/sqlite.db + +[namestore-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[namestore-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf +# USER = gnunet +# PASSWORD = +# HOST = localhost +# PORT = 3306 + + + diff --git a/src/namestore/namestore.h b/src/namestore/namestore.h new file mode 100644 index 0000000..22fc860 --- /dev/null +++ b/src/namestore/namestore.h @@ -0,0 +1,424 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file namestore/namestore.h + * @brief common internal definitions for namestore service + * @author Matthias Wachs + */ +#ifndef NAMESTORE_H +#define NAMESTORE_H + +/* + * Collect message types here, move to protocols later + */ +#define GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME 431 +#define GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE 432 +#define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT 433 +#define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE 434 +#define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE 435 +#define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE 436 +#define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE 437 +#define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE 438 + +#define GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START 439 +#define GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE 440 +#define GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT 441 +#define GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP 442 + +size_t +GNUNET_NAMESTORE_records_serialize (char ** dest, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd); + +int +GNUNET_NAMESTORE_records_deserialize ( struct GNUNET_NAMESTORE_RecordData **dest, char *src, size_t len); + +/** + * A GNS record serialized for network transmission. + * layout is [struct GNUNET_NAMESTORE_NetworkRecord][char[data_size] data] + */ +struct GNUNET_NAMESTORE_NetworkRecord +{ + /** + * Expiration time for the DNS record. + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /** + * Number of bytes in 'data'. + */ + uint32_t data_size; + + /** + * Type of the GNS/DNS record. + */ + uint32_t record_type; + + /** + * Flags for the record. + */ + uint32_t flags; +}; + + + +GNUNET_NETWORK_STRUCT_BEGIN +/** + * Connect to namestore service + */ +struct StartMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_START + */ + struct GNUNET_MessageHeader header; + +}; +GNUNET_NETWORK_STRUCT_END + + +GNUNET_NETWORK_STRUCT_BEGIN +/** + * Generic namestore message with op id + */ +struct GenericMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_* + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * Connect to namestore service + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct LookupNameMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; + + /* The zone */ + GNUNET_HashCode zone; + + /* Requested record type */ + uint32_t record_type; + + /* Requested record type */ + uint32_t name_len; +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * Lookup response + * Memory layout: + * [struct LookupNameResponseMessage][struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded][char *name][rc_count * struct GNUNET_NAMESTORE_RecordData][struct GNUNET_CRYPTO_RsaSignature] + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct LookupNameResponseMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; + + struct GNUNET_TIME_AbsoluteNBO expire; + + uint16_t name_len; + + uint16_t contains_sig; + + /* Requested record type */ + uint32_t rc_count; +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * Put a record to the namestore + * Memory layout: + * [struct RecordPutMessage][struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded][char *name][rc_count * struct GNUNET_NAMESTORE_RecordData] + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct RecordPutMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_RECORD_PUT + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; + + /* Contenct starts here */ + + /* name length */ + uint16_t name_len; + + /* Length of serialized rd data */ + uint16_t rd_len; + + struct GNUNET_TIME_AbsoluteNBO expire; + + struct GNUNET_CRYPTO_RsaSignature signature; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Put a record to the namestore response + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct RecordPutResponseMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; + + /* Contenct starts here */ + + /** + * name length: GNUNET_NO (0) on error, GNUNET_OK (1) on success + */ + uint16_t op_result; +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * Put a record to the namestore + * Memory layout: + * [struct RecordPutMessage][struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded][char *name][rc_count * struct GNUNET_NAMESTORE_RecordData] + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct RecordCreateMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; + + /* Contenct starts here */ + + /* name length */ + uint16_t name_len; + + struct GNUNET_CRYPTO_RsaSignature signature; +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * Create a record to the namestore response + * Memory layout: + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct RecordCreateResponseMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; + + /* Contenct starts here */ + + /** + * name length: GNUNET_NO (0) on error, GNUNET_OK (1) on success + */ + uint16_t op_result; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Remove a record from the namestore + * Memory layout: + * [struct RecordRemoveMessage][char *name][struct GNUNET_NAMESTORE_RecordData] + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct RecordRemoveMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; + + /* Contenct starts here */ + + /* name length */ + uint16_t name_len; + + struct GNUNET_CRYPTO_RsaSignature signature; +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * Remove a record from the namestore response + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct RecordRemoveResponseMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; + + /* Contenct starts here */ + + /** + * name length: GNUNET_NO (0) on error, GNUNET_OK (1) on success + */ + uint16_t op_result; +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * Start a zone iteration for the given zone + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct ZoneIterationStartMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; + + /* Contenct starts here */ + + uint16_t must_have_flags; + uint16_t must_not_have_flags; + + GNUNET_HashCode zone; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Ask for next result of zone iteration for the given operation + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct ZoneIterationNextMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * Stop zone iteration for the given operation + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct ZoneIterationStopMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Ask for next result of zone iteration for the given operation + */ +GNUNET_NETWORK_STRUCT_BEGIN +struct ZoneIterationResponseMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE + */ + struct GNUNET_MessageHeader header; + + /** + * Operation ID in NBO + */ + uint32_t op_id; +}; +GNUNET_NETWORK_STRUCT_END + + +/* end of namestore.h */ +#endif diff --git a/src/namestore/namestore_api.c b/src/namestore/namestore_api.c new file mode 100644 index 0000000..1d41399 --- /dev/null +++ b/src/namestore/namestore_api.c @@ -0,0 +1,1194 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file namestore/namestore_api.c + * @brief API to access the NAMESTORE service + * @author Martin Schanzenbach + * @author Matthias Wachs + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_namestore_service.h" +#include "namestore.h" +#define DEBUG_GNS_API GNUNET_EXTRA_LOGGING + +#define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) + +/** + * A QueueEntry. + */ +struct GNUNET_NAMESTORE_QueueEntry +{ + struct GNUNET_NAMESTORE_QueueEntry *next; + struct GNUNET_NAMESTORE_QueueEntry *prev; + + struct GNUNET_NAMESTORE_Handle *nsh; + + uint32_t op_id; + + GNUNET_NAMESTORE_ContinuationWithStatus cont; + void *cont_cls; + + GNUNET_NAMESTORE_RecordProcessor proc; + void *proc_cls; + + char *data; /*stub data pointer*/ +}; + + +/** + * Zone iterator + */ +struct GNUNET_NAMESTORE_ZoneIterator +{ + struct GNUNET_NAMESTORE_ZoneIterator *next; + struct GNUNET_NAMESTORE_ZoneIterator *prev; + + uint32_t op_id; + + struct GNUNET_NAMESTORE_Handle *h; + GNUNET_NAMESTORE_RecordProcessor proc; + void* proc_cls; + GNUNET_HashCode zone; + uint32_t no_flags; + uint32_t flags; +}; + + +/** + * Message in linked list we should send to the service. The + * actual binary message follows this struct. + */ +struct PendingMessage +{ + + /** + * Kept in a DLL. + */ + struct PendingMessage *next; + + /** + * Kept in a DLL. + */ + struct PendingMessage *prev; + + /** + * Size of the message. + */ + size_t size; + + /** + * Is this the 'START' message? + */ + int is_init; +}; + + +/** + * Connection to the NAMESTORE service. + */ +struct GNUNET_NAMESTORE_Handle +{ + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Socket (if available). + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Currently pending transmission request (or NULL). + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Reconnect task + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * Pending messages to send to the service + */ + + struct PendingMessage * pending_head; + struct PendingMessage * pending_tail; + + /** + * Should we reconnect to service due to some serious error? + */ + int reconnect; + + + /** + * Pending namestore queue entries + */ + struct GNUNET_NAMESTORE_QueueEntry * op_head; + struct GNUNET_NAMESTORE_QueueEntry * op_tail; + + uint32_t op_id; + + /** + * Pending namestore zone iterator entries + */ + struct GNUNET_NAMESTORE_ZoneIterator * z_head; + struct GNUNET_NAMESTORE_ZoneIterator * z_tail; +}; + +struct GNUNET_NAMESTORE_SimpleRecord +{ + /** + * DLL + */ + struct GNUNET_NAMESTORE_SimpleRecord *next; + + /** + * DLL + */ + struct GNUNET_NAMESTORE_SimpleRecord *prev; + + const char *name; + const GNUNET_HashCode *zone; + uint32_t record_type; + struct GNUNET_TIME_Absolute expiration; + enum GNUNET_NAMESTORE_RecordFlags flags; + size_t data_size; + const void *data; +}; + + +/** + * Disconnect from service and then reconnect. + * + * @param h our handle + */ +static void +force_reconnect (struct GNUNET_NAMESTORE_Handle *h); + +static void +handle_lookup_name_response (struct GNUNET_NAMESTORE_QueueEntry *qe, + struct LookupNameResponseMessage * msg, + size_t size) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", + "LOOKUP_NAME_RESPONSE"); + + struct GNUNET_NAMESTORE_Handle *h = qe->nsh; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key; + char *name; + struct GNUNET_NAMESTORE_RecordData *rd = NULL; + struct GNUNET_CRYPTO_RsaSignature *signature = NULL; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded dummy; + struct GNUNET_TIME_Absolute expire; + unsigned int rd_count = 0; + size_t msg_len = 0; + size_t name_len = 0; + int contains_sig = GNUNET_NO; + + rd_count = ntohl (msg->rc_count); + msg_len = ntohs (msg->header.size); + name_len = ntohs (msg->name_len); + contains_sig = ntohs (msg->contains_sig); + expire = GNUNET_TIME_absolute_ntoh(msg->expire); + + if (msg_len != sizeof (struct LookupNameResponseMessage) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + name_len + + rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData) + + contains_sig * sizeof (struct GNUNET_CRYPTO_RsaSignature)) + { + GNUNET_break_op (0); + return; + } + + zone_key = (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *) &msg[1]; + name = (char *) &zone_key[1]; + rd = (struct GNUNET_NAMESTORE_RecordData *) &name[name_len]; + + /* reset values if values not contained */ + if (contains_sig == GNUNET_NO) + signature = NULL; + else + signature = (struct GNUNET_CRYPTO_RsaSignature *) &rd[rd_count]; + if (rd_count == 0) + rd = NULL; + if (name_len == 0) + name = NULL; + + memset (&dummy, '0', sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + if (0 == memcmp (zone_key, &dummy, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) + zone_key = NULL; + + if (qe->proc != NULL) + { + qe->proc (qe->proc_cls, zone_key, expire, name, rd_count, rd, signature); + } + /* Operation done, remove */ + GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); + GNUNET_free (qe); +} + + +static void +handle_record_put_response (struct GNUNET_NAMESTORE_QueueEntry *qe, + struct RecordPutResponseMessage* msg, + size_t size) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", + "RECORD_PUT_RESPONSE"); + + struct GNUNET_NAMESTORE_Handle *h = qe->nsh; + int res = GNUNET_OK; + + if (ntohs (msg->op_result) == GNUNET_OK) + { + res = GNUNET_OK; + if (qe->cont != NULL) + { + qe->cont (qe->cont_cls, res, _("Namestore added record successfully")); + } + + } + else if (ntohs (msg->op_result) == GNUNET_NO) + { + res = GNUNET_SYSERR; + if (qe->cont != NULL) + { + qe->cont (qe->cont_cls, res, _("Namestore failed to add record")); + } + } + else + { + GNUNET_break_op (0); + return; + } + + /* Operation done, remove */ + GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); + + GNUNET_free (qe); +} + + +static void +handle_record_create_response (struct GNUNET_NAMESTORE_QueueEntry *qe, + struct RecordCreateResponseMessage* msg, + size_t size) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", + "RECORD_CREATE_RESPONSE"); + + struct GNUNET_NAMESTORE_Handle *h = qe->nsh; + int res = GNUNET_OK; + + if (ntohs (msg->op_result) == GNUNET_OK) + { + res = GNUNET_OK; + if (qe->cont != NULL) + { + qe->cont (qe->cont_cls, res, _("Namestore added record successfully")); + } + + } + else if (ntohs (msg->op_result) == GNUNET_NO) + { + res = GNUNET_SYSERR; + if (qe->cont != NULL) + { + qe->cont (qe->cont_cls, res, _("Namestore failed to add record")); + } + } + else + { + GNUNET_break_op (0); + return; + } + + /* Operation done, remove */ + GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); + + GNUNET_free (qe); +} + + +static void +manage_record_operations (struct GNUNET_NAMESTORE_QueueEntry *qe, + const struct GNUNET_MessageHeader *msg, + int type, size_t size) +{ + + /* handle different message type */ + switch (type) { + case GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE: + if (size < sizeof (struct LookupNameResponseMessage)) + { + GNUNET_break_op (0); + break; + } + handle_lookup_name_response (qe, (struct LookupNameResponseMessage *) msg, size); + break; + case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE: + if (size != sizeof (struct RecordPutResponseMessage)) + { + GNUNET_break_op (0); + break; + } + handle_record_put_response (qe, (struct RecordPutResponseMessage *) msg, size); + break; + case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE: + if (size != sizeof (struct RecordCreateResponseMessage)) + { + GNUNET_break_op (0); + break; + } + handle_record_create_response (qe, (struct RecordCreateResponseMessage *) msg, size); + break; + default: + GNUNET_break_op (0); + break; + } +} + +static void +handle_zone_iteration_response (struct GNUNET_NAMESTORE_ZoneIterator *ze, + struct ZoneIterationResponseMessage *msg, + size_t size) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", + "ZONE_ITERATION_RESPONSE"); + + + if (ze->proc != NULL) + { + // FIXME + ze->proc(ze->proc_cls, NULL, GNUNET_TIME_absolute_get_forever(), "dummy", 0, NULL, NULL); + } +} + + +static void +manage_zone_operations (struct GNUNET_NAMESTORE_ZoneIterator *ze, + const struct GNUNET_MessageHeader *msg, + int type, size_t size) +{ + + /* handle different message type */ + switch (type) { + case GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE: + if (size < sizeof (struct ZoneIterationResponseMessage)) + { + GNUNET_break_op (0); + break; + } + handle_zone_iteration_response (ze, (struct ZoneIterationResponseMessage *) msg, size); + break; + default: + GNUNET_break_op (0); + break; + } +} + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls the 'struct GNUNET_NAMESTORE_SchedulingHandle' + * @param msg message received, NULL on timeout or fatal error + */ +static void +process_namestore_message (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_NAMESTORE_Handle *h = cls; + struct GenericMessage * gm; + struct GNUNET_NAMESTORE_QueueEntry *qe; + struct GNUNET_NAMESTORE_ZoneIterator *ze; + uint16_t size; + uint16_t type; + uint32_t op_id = UINT32_MAX; + + if (NULL == msg) + { + force_reconnect (h); + return; + } + + size = ntohs (msg->size); + type = ntohs (msg->type); + + if (size < sizeof (struct GenericMessage)) + { + GNUNET_break_op (0); + GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, + GNUNET_TIME_UNIT_FOREVER_REL); + return; + } + + gm = (struct GenericMessage *) msg; + op_id = ntohl (gm->op_id); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message type %i size %i op %u\n", type, size, op_id); + + /* Find matching operation */ + if (op_id > h->op_id) + { + /* No matching pending operation found */ + GNUNET_break_op (0); + GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, + GNUNET_TIME_UNIT_FOREVER_REL); + return; + } + + /* Is it a record related operation ? */ + for (qe = h->op_head; qe != NULL; qe = qe->next) + { + if (qe->op_id == op_id) + break; + } + if (qe != NULL) + { + manage_record_operations (qe, msg, type, size); + } + + /* Is it a zone iteration operation ? */ + for (ze = h->z_head; ze != NULL; ze = ze->next) + { + if (ze->op_id == op_id) + break; + } + if (ze != NULL) + { + manage_zone_operations (ze, msg, type, size); + } + + GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, + GNUNET_TIME_UNIT_FOREVER_REL); + + if (GNUNET_YES == h->reconnect) + force_reconnect (h); + +} + + +/** + * Transmit messages from the message queue to the service + * (if there are any, and if we are not already trying). + * + * @param h handle to use + */ +static void +do_transmit (struct GNUNET_NAMESTORE_Handle *h); + + +/** + * We can now transmit a message to NAMESTORE. Do it. + * + * @param cls the 'struct GNUNET_NAMESTORE_Handle' + * @param size number of bytes we can transmit + * @param buf where to copy the messages + * @return number of bytes copied into buf + */ +static size_t +transmit_message_to_namestore (void *cls, size_t size, void *buf) +{ + struct GNUNET_NAMESTORE_Handle *h = cls; + struct PendingMessage *p; + size_t ret; + char *cbuf; + + h->th = NULL; + if ((size == 0) || (buf == NULL)) + { + force_reconnect (h); + return 0; + } + ret = 0; + cbuf = buf; + while ((NULL != (p = h->pending_head)) && (p->size <= size)) + { + memcpy (&cbuf[ret], &p[1], p->size); + ret += p->size; + size -= p->size; + GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p); + if (GNUNET_YES == p->is_init) + GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, + GNUNET_TIME_UNIT_FOREVER_REL); + GNUNET_free (p); + } + do_transmit (h); + return ret; +} + + +/** + * Transmit messages from the message queue to the service + * (if there are any, and if we are not already trying). + * + * @param h handle to use + */ +static void +do_transmit (struct GNUNET_NAMESTORE_Handle *h) +{ + struct PendingMessage *p; + + if (NULL != h->th) + return; + if (NULL == (p = h->pending_head)) + return; + if (NULL == h->client) + return; /* currently reconnecting */ + + h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, p->size, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, &transmit_message_to_namestore, + h); +} + + +/** + * Reconnect to namestore service. + * + * @param h the handle to the namestore service + */ +static void +reconnect (struct GNUNET_NAMESTORE_Handle *h) +{ + struct PendingMessage *p; + struct StartMessage *init; + + GNUNET_assert (NULL == h->client); + h->client = GNUNET_CLIENT_connect ("namestore", h->cfg); + GNUNET_assert (NULL != h->client); + + if ((NULL == (p = h->pending_head)) || (GNUNET_YES != p->is_init)) + { + p = GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct StartMessage)); + p->size = sizeof (struct StartMessage); + p->is_init = GNUNET_YES; + init = (struct StartMessage *) &p[1]; + init->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_START); + init->header.size = htons (sizeof (struct StartMessage)); + GNUNET_CONTAINER_DLL_insert (h->pending_head, h->pending_tail, p); + } + do_transmit (h); +} + +/** + * Re-establish the connection to the service. + * + * @param cls handle to use to re-connect. + * @param tc scheduler context + */ +static void +reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAMESTORE_Handle *h = cls; + + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + reconnect (h); +} + + +/** + * Disconnect from service and then reconnect. + * + * @param h our handle + */ +static void +force_reconnect (struct GNUNET_NAMESTORE_Handle *h) +{ + h->reconnect = GNUNET_NO; + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->client = NULL; + h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &reconnect_task, + h); +} + +static uint32_t +get_op_id (struct GNUNET_NAMESTORE_Handle *h) +{ + uint32_t op_id = h->op_id; + h->op_id ++; + return op_id; +} + +/** + * Initialize the connection with the NAMESTORE service. + * + * @param cfg configuration to use + * @return handle to the GNS service, or NULL on error + */ +struct GNUNET_NAMESTORE_Handle * +GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_NAMESTORE_Handle *h; + + h = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Handle)); + h->cfg = cfg; + h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h); + h->op_id = 0; + return h; +} + + +/** + * Disconnect from the namestore service (and free associated + * resources). + * + * @param h handle to the namestore + * @param drop set to GNUNET_YES to delete all data in namestore (!) + */ +void +GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h, int drop) +{ + struct PendingMessage *p; + struct GNUNET_NAMESTORE_QueueEntry *q; + struct GNUNET_NAMESTORE_ZoneIterator *z; + + GNUNET_assert (h != NULL); + + while (NULL != (p = h->pending_head)) + { + GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p); + GNUNET_free (p); + } + + while (NULL != (q = h->op_head)) + { + GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q); + GNUNET_free (q); + } + + while (NULL != (z = h->z_head)) + { + GNUNET_CONTAINER_DLL_remove (h->z_head, h->z_tail, z); + GNUNET_free (z); + } + + if (NULL != h->client) + { + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->client = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task) + { + GNUNET_SCHEDULER_cancel (h->reconnect_task); + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free(h); + h = NULL; +} + + +/** + * Store an item in the namestore. If the item is already present, + * the expiration time is updated to the max of the existing time and + * the new time. This API is used when we cache signatures from other + * authorities. + * + * @param h handle to the namestore + * @param zone_key public key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param expire when does the corresponding block in the DHT expire (until + * when should we never do a DHT lookup for the same name again)? + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature for all the records in the zone under the given name + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return handle to abort the request + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_record_put (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + const char *name, + struct GNUNET_TIME_Absolute expire, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_NAMESTORE_QueueEntry *qe; + struct PendingMessage *pe; + + /* pointer to elements */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key_tmp; + char * rd_tmp; + char * rd_ser; + char * name_tmp; + + size_t msg_size = 0; + size_t name_len = strlen(name) + 1; + size_t rd_ser_len = 0; + uint32_t id = 0; + + GNUNET_assert (NULL != h); + id = get_op_id(h); + qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); + qe->nsh = h; + qe->cont = cont; + qe->cont_cls = cont_cls; + qe->op_id = id; + GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); + + /* set msg_size*/ + rd_ser_len = GNUNET_NAMESTORE_records_serialize(&rd_ser, rd_count, rd); + + struct RecordPutMessage * msg; + msg_size = sizeof (struct RecordPutMessage) + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + name_len + rd_ser_len; + + /* create msg here */ + pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); + pe->size = msg_size; + pe->is_init = GNUNET_NO; + msg = (struct RecordPutMessage *) &pe[1]; + zone_key_tmp = (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *) &msg[1]; + name_tmp = (char *) &zone_key_tmp[1]; + rd_tmp = &name_tmp[name_len]; + + msg->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT); + msg->header.size = htons (msg_size); + msg->op_id = htonl (id); + memcpy (zone_key_tmp, zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + msg->signature = *signature; + msg->name_len = htons (name_len); + memcpy (name_tmp, name, name_len); + msg->expire = GNUNET_TIME_absolute_hton (expire); + msg->rd_len = htons (rd_ser_len); + + memcpy (rd_tmp, rd_ser, rd_ser_len); + GNUNET_free (rd_ser); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_PUT", name, msg_size); + + GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); + do_transmit(h); + + return qe; +} + + +/** + * Check if a signature is valid. This API is used by the GNS Block + * to validate signatures received from the network. + * + * @param public_key public key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature for all the records in the zone under the given name + * @return GNUNET_OK if the signature is valid + */ +int +GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + return GNUNET_SYSERR; +} + +/** + * Store an item in the namestore. If the item is already present, + * the expiration time is updated to the max of the existing time and + * the new time. This API is used by the authority of a zone. + * + * @param h handle to the namestore + * @param pkey private key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param rd record data to store + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return handle to abort the request + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_record_create (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, + const char *name, + const struct GNUNET_NAMESTORE_RecordData *rd, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_NAMESTORE_QueueEntry *qe; + struct PendingMessage *pe; + char * name_tmp; + char * rd_tmp; + char * rd_ser; + size_t rd_ser_len = 0; + size_t msg_size = 0; + size_t name_len = 0; + uint32_t id = 0; + + GNUNET_assert (NULL != h); + + id = get_op_id(h); + qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); + qe->nsh = h; + qe->cont = cont; + qe->cont_cls = cont_cls; + qe->op_id = id; + + /* set msg_size*/ + rd_ser_len = GNUNET_NAMESTORE_records_serialize(&rd_ser, 1, rd); + struct RecordCreateMessage * msg; + msg_size = sizeof (struct RecordCreateMessage) + name_len + rd_ser_len; + + /* create msg here */ + pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); + pe->size = msg_size; + pe->is_init = GNUNET_NO; + msg = (struct RecordCreateMessage *) &pe[1]; + + name_tmp = (char *) &msg[1]; + rd_tmp = &name_tmp[name_len]; + + msg->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE); + msg->header.size = htons (msg_size); + msg->op_id = htonl (id); + //msg->signature = *signature; + msg->name_len = htons (name_len); + memcpy (name_tmp, name, name_len); + memcpy (rd_tmp, rd_ser, rd_ser_len); + GNUNET_free (rd_ser); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_CREATE", name, msg_size); + + GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); + do_transmit(h); + return qe; +} + + +/** + * Explicitly remove some content from the database. The + * "cont"inuation will be called with status "GNUNET_OK" if content + * was removed, "GNUNET_NO" if no matching entry was found and + * "GNUNET_SYSERR" on all other types of errors. + * This API is used by the authority of a zone. + * + * @param h handle to the namestore + * @param pkey private key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param rd record data + * @param cont continuation to call when done + * @param cont_cls closure for cont + * @return handle to abort the request + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_record_remove (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, + const char *name, + const struct GNUNET_NAMESTORE_RecordData *rd, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_NAMESTORE_QueueEntry *qe; + struct PendingMessage *pe; + char * rd_tmp; + char * rd_ser; + char * name_tmp; + size_t rd_ser_len = 0; + size_t msg_size = 0; + size_t name_len = 0; + uint32_t id = 0; + + GNUNET_assert (NULL != h); + + id = get_op_id(h); + qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); + qe->nsh = h; + qe->cont = cont; + qe->cont_cls = cont_cls; + qe->op_id = id; + + /* set msg_size*/ + rd_ser_len = GNUNET_NAMESTORE_records_serialize(&rd_ser, 1, rd); + struct RecordRemoveMessage * msg; + msg_size = sizeof (struct RecordRemoveMessage) + name_len + rd_ser_len; + + /* create msg here */ + pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); + pe->size = msg_size; + pe->is_init = GNUNET_NO; + msg = (struct RecordRemoveMessage *) &pe[1]; + + name_tmp = (char *) &msg[1]; + rd_tmp = &name_tmp[name_len]; + + msg->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE); + msg->header.size = htons (msg_size); + msg->op_id = htonl (id); + //msg->signature = *signature; + msg->name_len = htons (name_len); + memcpy (name_tmp, name, name_len); + memcpy (rd_tmp, rd_ser, rd_ser_len); + GNUNET_free (rd_ser); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_REMOVE", name, msg_size); + + GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); + do_transmit(h); + return qe; +} + + +/** + * Get a result for a particular key from the namestore. The processor + * will only be called once. + * + * @param h handle to the namestore + * @param zone zone to look up a record from + * @param name name to look up + * @param record_type desired record type, 0 for all + * @param proc function to call on the matching records, or with + * NULL (rd_count == 0) if there are no matching records + * @param proc_cls closure for proc + * @return a handle that can be used to + * cancel + */ +struct GNUNET_NAMESTORE_QueueEntry * +GNUNET_NAMESTORE_lookup_record (struct GNUNET_NAMESTORE_Handle *h, + const GNUNET_HashCode *zone, + const char *name, + uint32_t record_type, + GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls) +{ + struct GNUNET_NAMESTORE_QueueEntry *qe; + struct PendingMessage *pe; + size_t msg_size = 0; + size_t name_len = 0; + uint32_t id = 0; + + GNUNET_assert (NULL != h); + GNUNET_assert (NULL != zone); + GNUNET_assert (NULL != name); + + name_len = strlen (name) + 1; + if ((name_len == 0) || (name_len > 256)) + { + GNUNET_break (0); + return NULL; + } + + id = get_op_id(h); + qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); + qe->nsh = h; + qe->proc = proc; + qe->proc_cls = proc_cls; + qe->op_id = id; + GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); + + /* set msg_size*/ + msg_size = sizeof (struct LookupNameMessage) + name_len; + pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); + + /* create msg here */ + struct LookupNameMessage * msg; + pe->size = msg_size; + pe->is_init = GNUNET_NO; + msg = (struct LookupNameMessage *) &pe[1]; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME); + msg->header.size = htons (msg_size); + msg->op_id = htonl (id); + msg->record_type = htonl (record_type); + msg->zone = *zone; + msg->name_len = htonl (name_len); + memcpy (&msg[1], name, name_len); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s'\n", "NAMESTORE_LOOKUP_NAME", name); + + /* transmit message */ + GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); + do_transmit(h); + + return qe; +} + + + +/** + * Starts a new zone iteration (used to periodically PUT all of our + * records into our DHT). This MUST lock the GNUNET_NAMESTORE_Handle + * for any other calls than GNUNET_NAMESTORE_zone_iterator_next and + * GNUNET_NAMESTORE_zone_iteration_stop. "proc" will be called once + * immediately, and then again after + * "GNUNET_NAMESTORE_zone_iterator_next" is invoked. + * + * @param h handle to the namestore + * @param zone zone to access, NULL for all zones + * @param must_have_flags flags that must be set for the record to be returned + * @param must_not_have_flags flags that must NOT be set for the record to be returned + * @param proc function to call on each name from the zone; it + * will be called repeatedly with a value (if available) + * and always once at the end with a name of NULL. + * @param proc_cls closure for proc + * @return an iterator handle to use for iteration + */ +struct GNUNET_NAMESTORE_ZoneIterator * +GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h, + const GNUNET_HashCode *zone, + enum GNUNET_NAMESTORE_RecordFlags must_have_flags, + enum GNUNET_NAMESTORE_RecordFlags must_not_have_flags, + GNUNET_NAMESTORE_RecordProcessor proc, + void *proc_cls) +{ + struct GNUNET_NAMESTORE_ZoneIterator *it; + struct PendingMessage *pe; + size_t msg_size = 0; + uint32_t id = 0; + + GNUNET_assert (NULL != h); + GNUNET_assert (NULL != zone); + + id = get_op_id(h); + it = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIterator)); + it->h = h; + it->proc = proc; + it->proc_cls = proc; + it->op_id = id; + it->zone = *zone; + GNUNET_CONTAINER_DLL_insert_tail(h->z_head, h->z_tail, it); + + /* set msg_size*/ + msg_size = sizeof (struct ZoneIterationStartMessage); + pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); + + /* create msg here */ + struct ZoneIterationStartMessage * msg; + pe->size = msg_size; + pe->is_init = GNUNET_NO; + msg = (struct ZoneIterationStartMessage *) &pe[1]; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START); + msg->header.size = htons (msg_size); + msg->op_id = htonl (id); + msg->zone = *zone; + msg->must_have_flags = ntohs (must_have_flags); + msg->must_not_have_flags = ntohs (must_not_have_flags); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for zone `%s'\n", "ZONE_ITERATION_START", GNUNET_h2s(zone)); + + /* transmit message */ + GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); + do_transmit(h); + + return it; +} + + +/** + * Calls the record processor specified in GNUNET_NAMESTORE_zone_iteration_start + * for the next record. + * + * @param it the iterator + */ +void +GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it) +{ + struct GNUNET_NAMESTORE_Handle *h; + struct PendingMessage *pe; + size_t msg_size = 0; + + GNUNET_assert (NULL != it); + h = it->h; + + /* set msg_size*/ + msg_size = sizeof (struct ZoneIterationNextMessage); + pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); + + /* create msg here */ + struct ZoneIterationNextMessage * msg; + pe->size = msg_size; + pe->is_init = GNUNET_NO; + msg = (struct ZoneIterationNextMessage *) &pe[1]; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT); + msg->header.size = htons (msg_size); + msg->op_id = htonl (it->op_id); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s'\n", "ZONE_ITERATION_NEXT", GNUNET_h2s(&it->zone)); + + /* transmit message */ + GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); + do_transmit(h); +} + + +/** + * Stops iteration and releases the namestore handle for further calls. + * + * @param it the iterator + */ +void +GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it) +{ + GNUNET_assert (NULL != it); + struct PendingMessage *pe; + size_t msg_size = 0; + struct GNUNET_NAMESTORE_Handle *h = it->h; + + /* set msg_size*/ + msg_size = sizeof (struct ZoneIterationStopMessage); + pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); + + /* create msg here */ + struct ZoneIterationStopMessage * msg; + pe->size = msg_size; + pe->is_init = GNUNET_NO; + msg = (struct ZoneIterationStopMessage *) &pe[1]; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP); + msg->header.size = htons (msg_size); + msg->op_id = htonl (it->op_id); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s'\n", "ZONE_ITERATION_STOP", GNUNET_h2s(&it->zone)); + + /* transmit message */ + GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); + do_transmit(h); +} + + +/** + * Cancel a namestore operation. The final callback from the + * operation must not have been done yet. + * + * @param qe operation to cancel + */ +void +GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe) +{ + struct GNUNET_NAMESTORE_Handle *h = qe->nsh; + + GNUNET_assert (qe != NULL); + + GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); + GNUNET_free(qe); + +} + +/* end of namestore_api.c */ diff --git a/src/namestore/namestore_common.c b/src/namestore/namestore_common.c new file mode 100644 index 0000000..37f0eab --- /dev/null +++ b/src/namestore/namestore_common.c @@ -0,0 +1,159 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file namestore/namestore_common.c + * @brief API to access the NAMESTORE service + * @author Martin Schanzenbach + * @author Matthias Wachs + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_namestore_service.h" +#include "namestore.h" +#define DEBUG_GNS_API GNUNET_EXTRA_LOGGING + +#define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) +/** + * Serialize an array of GNUNET_NAMESTORE_RecordData *rd to transmit over the + * network + * + * @param dest where to write the serialized data + * @param rd_count number of elements in array + * @param rd array + * + * @return number of bytes written to destination dest + */ +size_t +GNUNET_NAMESTORE_records_serialize (char ** dest, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + //size_t len = 0; + struct GNUNET_NAMESTORE_NetworkRecord * nr; + char * d = (*dest); + int c = 0; + int offset; + + + size_t total_len = rd_count * sizeof (struct GNUNET_NAMESTORE_NetworkRecord); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Struct size: %u\n", total_len); + + /* figure out total len required */ + for (c = 0; c < rd_count; c ++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data size record[%i] : %u\n", c, rd[c].data_size); + total_len += rd[c].data_size; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Serializing %i records with total length of %llu\n", rd_count, total_len); + + (*dest) = GNUNET_malloc (total_len); + d = (*dest); + + /* copy records */ + offset = 0; + + for (c = 0; c < rd_count; c ++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Serialized record [%i]: data_size %i\n", c,rd[c].data_size); + + nr = (struct GNUNET_NAMESTORE_NetworkRecord *) &d[offset]; + nr->data_size = htonl (rd[c].data_size); + nr->flags = htonl (rd[c].flags); + nr->record_type = htonl (rd[c].record_type); + nr->expiration = GNUNET_TIME_absolute_hton(rd[c].expiration); + + /*put data here */ + offset += sizeof (struct GNUNET_NAMESTORE_NetworkRecord); + memcpy (&d[offset], rd[c].data, rd[c].data_size); + offset += rd[c].data_size; + } + + GNUNET_assert (offset == total_len); + return total_len; +} + + +/** + * Deserialize an array of GNUNET_NAMESTORE_RecordData *rd after transmission + * over the network + * + * @param source where to read the data to deserialize + * @param rd_count number of elements in array + * @param rd array + * + * @return number of elements deserialized + */ +int +GNUNET_NAMESTORE_records_deserialize ( struct GNUNET_NAMESTORE_RecordData **dest, char *src, size_t len) +{ + struct GNUNET_NAMESTORE_NetworkRecord * nr; + struct GNUNET_NAMESTORE_RecordData *d = (*dest); + int elements; + size_t offset; + uint32_t data_size; + int c; + + offset = 0; + elements = 0; + while (offset < len) + { + nr = (struct GNUNET_NAMESTORE_NetworkRecord *) &src[offset]; + offset += sizeof (struct GNUNET_NAMESTORE_NetworkRecord); + + data_size = ntohl (nr->data_size); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Datasize record[%i]: %u\n", elements, data_size); + offset += data_size; + elements ++; + } + + GNUNET_assert (len == offset); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deserializing %i records with total length of %u\n", elements, len); + + (*dest) = GNUNET_malloc (elements * sizeof (struct GNUNET_NAMESTORE_RecordData)); + d = (*dest); + + offset = 0; + for (c = 0; c < elements; c++) + { + nr = (struct GNUNET_NAMESTORE_NetworkRecord *) &src[offset]; + d[c].expiration = GNUNET_TIME_absolute_ntoh(nr->expiration); + d[c].record_type = ntohl (nr->record_type); + d[c].flags = ntohl (nr->flags); + d[c].data_size = ntohl (nr->data_size); + d[c].data = GNUNET_malloc (d[c].data_size); + GNUNET_assert (d[c].data != NULL); + + offset += sizeof (struct GNUNET_NAMESTORE_NetworkRecord); + memcpy((char *) d[c].data, &src[offset], d[c].data_size); + + offset += d[c].data_size; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deserialized record[%i] /w data_size %i\n", c, d[c].data_size); + } + GNUNET_assert(offset == len); + + return elements; +} + +/* end of namestore_api.c */ diff --git a/src/namestore/plugin_namestore_sqlite.c b/src/namestore/plugin_namestore_sqlite.c new file mode 100644 index 0000000..c297216 --- /dev/null +++ b/src/namestore/plugin_namestore_sqlite.c @@ -0,0 +1,806 @@ + /* + * This file is part of GNUnet + * (C) 2009, 2011, 2012 Christian Grothoff (and other contributing authors) + * + * GNUnet is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 3, or (at your + * option) any later version. + * + * GNUnet is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNUnet; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * @file namestore/plugin_namestore_sqlite.c + * @brief sqlite-based namestore backend + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_namestore_plugin.h" +#include + +/** + * After how many ms "busy" should a DB operation fail for good? + * A low value makes sure that we are more responsive to requests + * (especially PUTs). A high value guarantees a higher success + * rate (SELECTs in iterate can take several seconds despite LIMIT=1). + * + * The default value of 1s should ensure that users do not experience + * huge latencies while at the same time allowing operations to succeed + * with reasonable probability. + */ +#define BUSY_TIMEOUT_MS 1000 + + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' on file 'filename' + * with the message given by strerror(errno). + */ +#define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "namestore-sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0) + +#define LOG(kind,...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__) + + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Database filename. + */ + char *fn; + + /** + * Native SQLite database handle. + */ + sqlite3 *dbh; + + /** + * Precompiled SQL for put record + */ + sqlite3_stmt *put_records; + + /** + * Precompiled SQL for remove record + */ + sqlite3_stmt *remove_records; + + /** + * Precompiled SQL for iterate over all records. + */ + sqlite3_stmt *iterate_all; + + /** + * Precompiled SQL for iterate records with same name. + */ + sqlite3_stmt *iterate_by_name; + + /** + * Precompiled SQL for iterate records with same zone. + */ + sqlite3_stmt *iterate_by_zone; + + /** + * Precompiled SQL for iterate records with same name and zone. + */ + sqlite3_stmt *iterate_records; + + /** + * Precompiled SQL for delete zone + */ + sqlite3_stmt *delete_zone; + +}; + + +/** + * Internal format of a record in the BLOB in the database. + */ +struct DbRecord +{ + + /** + * Expiration time for the DNS record. + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /** + * Number of bytes in 'data', network byte order. + */ + uint32_t data_size; + + /** + * Type of the GNS/DNS record, network byte order. + */ + uint32_t record_type; + + /** + * Flags for the record, network byte order. + */ + uint32_t flags; + +}; + + +/** + * @brief Prepare a SQL statement + * + * @param dbh handle to the database + * @param zSql SQL statement, UTF-8 encoded + * @param ppStmt set to the prepared statement + * @return 0 on success + */ +static int +sq_prepare (sqlite3 * dbh, const char *zSql, sqlite3_stmt ** ppStmt) +{ + char *dummy; + int result; + + result = + sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt, + (const char **) &dummy); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result); + return result; +} + + +/** + * Create our database indices. + * + * @param dbh handle to the database + */ +static void +create_indices (sqlite3 * dbh) +{ + /* create indices */ + if ( (SQLITE_OK != + sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_name_rv ON ns090records (zone_hash,record_name_hash,rvalue)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_rv ON ns090records (zone_hash,rvalue)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone ON ns090records (zone_hash)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_name_rv ON ns090records (record_name_hash,rvalue)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_rv ON ns090records (rvalue)", + NULL, NULL, NULL)) ) + LOG (GNUNET_ERROR_TYPE_ERROR, + "Failed to create indices: %s\n", sqlite3_errmsg (dbh)); +} + + +#if 0 +#define CHECK(a) GNUNET_break(a) +#define ENULL NULL +#else +#define ENULL &e +#define ENULL_DEFINED 1 +#define CHECK(a) if (! a) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); } +#endif + + +/** + * Initialize the database connections and associated + * data structures (create tables and indices + * as needed as well). + * + * @param plugin the plugin context (state for this module) + * @return GNUNET_OK on success + */ +static int +database_setup (struct Plugin *plugin) +{ + sqlite3_stmt *stmt; + char *afsdir; +#if ENULL_DEFINED + char *e; +#endif + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "namestore-sqlite", + "FILENAME", &afsdir)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _ ("Option `%s' in section `%s' missing in configuration!\n"), + "FILENAME", "namestore-sqlite"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != GNUNET_DISK_file_test (afsdir)) + { + if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) + { + GNUNET_break (0); + GNUNET_free (afsdir); + return GNUNET_SYSERR; + } + } +#ifdef ENABLE_NLS + plugin->fn = + GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), nl_langinfo (CODESET)); +#else + plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), "UTF-8"); /* good luck */ +#endif + GNUNET_free (afsdir); + + /* Open database and precompile statements */ + if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Unable to initialize SQLite: %s.\n"), + sqlite3_errmsg (plugin->dbh)); + return GNUNET_SYSERR; + } + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA synchronous=NORMAL", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL, + NULL, ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\"", NULL, + NULL, ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA count_changes=OFF", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, "PRAGMA page_size=4092", NULL, NULL, + ENULL)); + + CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS)); + + + /* Create tables */ + CHECK (SQLITE_OK == + sq_prepare (plugin->dbh, + "SELECT 1 FROM sqlite_master WHERE tbl_name = 'ns090records'", + &stmt)); + if ((sqlite3_step (stmt) == SQLITE_DONE) && + (sqlite3_exec + (plugin->dbh, + "CREATE TABLE ns090records (" + " zone_key BLOB NOT NULL DEFAULT ''," + " zone_hash BLOB NOT NULL DEFAULT ''," + " record_count INT NOT NULL DEFAULT 0," + " record_data BLOB NOT NULL DEFAULT ''," + " block_expiration_time INT8 NOT NULL DEFAULT 0," + " signature BLOB NOT NULL DEFAULT ''," + " record_name TEXT NOT NULL DEFAULT ''," + " record_name_hash BLOB NOT NULL DEFAULT ''," + " rvalue INT8 NOT NULL DEFAULT ''" + ")", + NULL, NULL, NULL) != SQLITE_OK)) + { + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec"); + sqlite3_finalize (stmt); + return GNUNET_SYSERR; + } + sqlite3_finalize (stmt); + + create_indices (plugin->dbh); + +#define ALL "zone_key, record_name, record_count, record_data, block_expiration_time, signature" + if ((sq_prepare + (plugin->dbh, + "INSERT INTO ns090records (" ALL ", zone_hash, record_name_hash, rvalue) VALUES " + "(?, ?, ?, ?, ?, ?, ?, ?, ?)", + &plugin->put_records) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "DELETE FROM ns090records WHERE zone_hash=? AND record_name_hash=?", + &plugin->remove_records) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "SELECT " ALL + " FROM ns090records WHERE zone_hash=? AND record_name_hash=? ORDER BY rvalue LIMIT 1 OFFSET ?", + &plugin->iterate_records) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "SELECT " ALL + " FROM ns090records WHERE zone_hash=? ORDER BY rvalue LIMIT 1 OFFSET ?", + &plugin->iterate_by_zone) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "SELECT " ALL + " FROM ns090records WHERE record_name_hash=? ORDER BY rvalue LIMIT 1 OFFSET ?", + &plugin->iterate_by_name) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "SELECT " ALL + " FROM ns090records ORDER BY rvalue LIMIT 1 OFFSET ?", + &plugin->iterate_all) != SQLITE_OK) || + (sq_prepare + (plugin->dbh, + "DELETE FROM ns090records WHERE zone_hash=?", + &plugin->delete_zone) != SQLITE_OK) ) + { + LOG_SQLITE (plugin,GNUNET_ERROR_TYPE_ERROR, "precompiling"); + return GNUNET_SYSERR; + } +#undef ALL + return GNUNET_OK; +} + + +/** + * Shutdown database connection and associate data + * structures. + * @param plugin the plugin context (state for this module) + */ +static void +database_shutdown (struct Plugin *plugin) +{ + int result; + sqlite3_stmt *stmt; + + if (NULL != plugin->put_records) + sqlite3_finalize (plugin->put_records); + if (NULL != plugin->remove_records) + sqlite3_finalize (plugin->remove_records); + if (NULL != plugin->iterate_records) + sqlite3_finalize (plugin->iterate_records); + if (NULL != plugin->iterate_records) + sqlite3_finalize (plugin->iterate_by_zone); + if (NULL != plugin->iterate_records) + sqlite3_finalize (plugin->iterate_by_name); + if (NULL != plugin->iterate_records) + sqlite3_finalize (plugin->iterate_all); + if (NULL != plugin->delete_zone) + sqlite3_finalize (plugin->delete_zone); + result = sqlite3_close (plugin->dbh); + if (result == SQLITE_BUSY) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Tried to close sqlite without finalizing all prepared statements.\n")); + stmt = sqlite3_next_stmt (plugin->dbh, NULL); + while (stmt != NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", + "Closing statement %p\n", stmt); + result = sqlite3_finalize (stmt); + if (result != SQLITE_OK) + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", + "Failed to close statement %p: %d\n", stmt, result); + stmt = sqlite3_next_stmt (plugin->dbh, NULL); + } + result = sqlite3_close (plugin->dbh); + } + if (SQLITE_OK != result) + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); + + GNUNET_free_non_null (plugin->fn); +} + + +/** + * Removes any existing record in the given zone with the same name. + * + * @param cls closure (internal context for the plugin) + * @param zone hash of the public key of the zone + * @param name name to remove (at most 255 characters long) + * @return GNUNET_OK on success + */ +static int +namestore_sqlite_remove_records (void *cls, + const GNUNET_HashCode *zone, + const char *name) +{ + struct Plugin *plugin = cls; + GNUNET_HashCode nh; + size_t name_len; + int n; + + name_len = strlen (name); + GNUNET_CRYPTO_hash (name, name_len, &nh); + + if ((SQLITE_OK != sqlite3_bind_blob (plugin->remove_records, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) || + (SQLITE_OK != sqlite3_bind_blob (plugin->remove_records, 2, &nh, sizeof (GNUNET_HashCode), SQLITE_STATIC))) + { + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (plugin->remove_records)) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_SYSERR; + } + n = sqlite3_step (plugin->remove_records); + if (SQLITE_OK != sqlite3_reset (plugin->remove_records)) + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + switch (n) + { + case SQLITE_DONE: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record removed\n"); + return GNUNET_OK; + case SQLITE_BUSY: + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_NO; + default: + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_SYSERR; + } +} + + +/** + * Store a record in the datastore. Removes any existing record in the + * same zone with the same name. + * + * @param cls closure (internal context for the plugin) + * @param zone_key public key of the zone + * @param expire when does the corresponding block in the DHT expire (until + * when should we never do a DHT lookup for the same name again)? + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature of the record block, NULL if signature is unavailable (i.e. + * because the user queried for a particular record type only) + * @return GNUNET_OK on success, else GNUNET_SYSERR + */ +static int +namestore_sqlite_put_records (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct Plugin *plugin = cls; + int n; + GNUNET_HashCode zone; + GNUNET_HashCode nh; + size_t name_len; + uint64_t rvalue; + size_t data_size; + size_t off; + unsigned int i; + + GNUNET_CRYPTO_hash (zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone); + (void) namestore_sqlite_remove_records (plugin, &zone, name); + name_len = strlen (name); + GNUNET_CRYPTO_hash (name, name_len, &nh); + rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); + data_size = rd_count * sizeof (struct DbRecord); + for (i=0;i 64 * 65536) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + { + char data[data_size]; + struct DbRecord *rec; + + rec = (struct DbRecord *) data; + off = rd_count * sizeof (struct DbRecord); + for (i=0;iput_records, 1, zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), SQLITE_STATIC)) || + (SQLITE_OK != sqlite3_bind_text (plugin->put_records, 2, name, -1, SQLITE_STATIC)) || + (SQLITE_OK != sqlite3_bind_int (plugin->put_records, 3, rd_count)) || + (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 4, data, data_size, SQLITE_STATIC)) || + (SQLITE_OK != sqlite3_bind_int64 (plugin->put_records, 5, expire.abs_value)) || + (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 6, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature), SQLITE_STATIC)) || + (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 7, &zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) || + (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 8, &nh, sizeof (GNUNET_HashCode), SQLITE_STATIC)) || + (SQLITE_OK != sqlite3_bind_int64 (plugin->put_records, 9, rvalue)) ) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (plugin->put_records)) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_SYSERR; + + } + n = sqlite3_step (plugin->put_records); + if (SQLITE_OK != sqlite3_reset (plugin->put_records)) + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + } + switch (n) + { + case SQLITE_DONE: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record stored\n"); + return GNUNET_OK; + case SQLITE_BUSY: + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_NO; + default: + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_SYSERR; + } +} + + +/** + * Iterate over the results for a particular key and zone in the + * datastore. Will return at most one result to the iterator. + * + * @param cls closure (internal context for the plugin) + * @param zone hash of public key of the zone, NULL to iterate over all zones + * @param name_hash hash of name, NULL to iterate over all records of the zone + * @param offset offset in the list of all matching records + * @param iter function to call with the result + * @param iter_cls closure for iter + * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error + */ +static int +namestore_sqlite_iterate_records (void *cls, + const GNUNET_HashCode *zone, + const GNUNET_HashCode *name_hash, + uint64_t offset, + GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) +{ + struct Plugin *plugin = cls; + sqlite3_stmt *stmt; + unsigned int boff; + int ret; + int sret; + + if (NULL == zone) + if (NULL == name_hash) + stmt = plugin->iterate_all; + else + stmt = plugin->iterate_by_name; + else + if (NULL == name_hash) + stmt = plugin->iterate_by_zone; + else + stmt = plugin->iterate_records; + + boff = 0; + if ( (NULL != zone) && + (SQLITE_OK != sqlite3_bind_blob (stmt, ++boff, + zone, sizeof (GNUNET_HashCode), + SQLITE_STATIC)) ) + { + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_SYSERR; + } + if ( (NULL != name_hash) && + (SQLITE_OK != sqlite3_bind_blob (stmt, ++boff, + name_hash, sizeof (GNUNET_HashCode), + SQLITE_STATIC)) ) + { + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_SYSERR; + } + + if (SQLITE_OK != sqlite3_bind_int64 (stmt, ++boff, + offset)) + { + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return GNUNET_SYSERR; + } + ret = GNUNET_NO; + if (SQLITE_ROW == (sret = sqlite3_step (stmt))) + { + unsigned int record_count; + size_t data_size; + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key; + const struct GNUNET_CRYPTO_RsaSignature *sig; + struct GNUNET_TIME_Absolute expiration; + const char *data; + const char *name; + + ret = GNUNET_YES; + zone_key = sqlite3_column_blob (stmt, 0); + name = (const char*) sqlite3_column_text (stmt, 1); + record_count = sqlite3_column_int (stmt, 2); + data_size = sqlite3_column_bytes (stmt, 3); + data = sqlite3_column_blob (stmt, 3); + expiration.abs_value = (uint64_t) sqlite3_column_int64 (stmt, 4); + sig = sqlite3_column_blob (stmt, 5); + + if ( (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) != sqlite3_column_bytes (stmt, 0)) || + (sizeof (struct GNUNET_CRYPTO_RsaSignature) != sqlite3_column_bytes (stmt, 5)) || + (sizeof (struct DbRecord) * record_count > data_size) ) + { + GNUNET_break (0); + ret = GNUNET_SYSERR; + } + else + { + const struct DbRecord *db = (const struct DbRecord*) data; + struct GNUNET_NAMESTORE_RecordData rd[record_count]; + unsigned int i; + size_t off; + + off = record_count * sizeof (struct DbRecord); + for (i=0;i data_size) + { + GNUNET_break (0); + ret = GNUNET_SYSERR; + record_count = i; + break; + } + rd[i].expiration = GNUNET_TIME_absolute_ntoh (db[i].expiration); + rd[i].data_size = ntohl (db[i].data_size); + rd[i].data = &data[off]; + rd[i].record_type = ntohl (db[i].record_type); + rd[i].flags = ntohl (db[i].flags); + off += rd[i].data_size; + } + iter (iter_cls, zone_key, expiration, name, + record_count, rd, sig); + } + } + else + { + if (SQLITE_DONE != sret) + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); + iter (iter_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL, 0, NULL, NULL); + } + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return ret; +} + + +/** + * Delete an entire zone (all records). Not used in normal operation. + * + * @param cls closure (internal context for the plugin) + * @param zone zone to delete + */ +static void +namestore_sqlite_delete_zone (void *cls, + const GNUNET_HashCode *zone) +{ + struct Plugin *plugin = cls; + sqlite3_stmt *stmt = plugin->delete_zone; + int n; + + if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, zone, sizeof (GNUNET_HashCode), SQLITE_STATIC)) + { + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + return; + } + n = sqlite3_step (stmt); + if (SQLITE_OK != sqlite3_reset (stmt)) + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_reset"); + switch (n) + { + case SQLITE_DONE: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Values deleted\n"); + break; + case SQLITE_BUSY: + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + break; + default: + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + break; + } +} + + +/** + * Entry point for the plugin. + * + * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" + * @return NULL on error, othrewise the plugin context + */ +void * +libgnunet_plugin_namestore_sqlite_init (void *cls) +{ + static struct Plugin plugin; + const struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct GNUNET_NAMESTORE_PluginFunctions *api; + + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.cfg = cfg; + if (GNUNET_OK != database_setup (&plugin)) + { + database_shutdown (&plugin); + return NULL; + } + api = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_PluginFunctions)); + api->cls = &plugin; + api->put_records = &namestore_sqlite_put_records; + api->remove_records = &namestore_sqlite_remove_records; + api->iterate_records = &namestore_sqlite_iterate_records; + api->delete_zone = &namestore_sqlite_delete_zone; + LOG (GNUNET_ERROR_TYPE_INFO, + _("Sqlite database running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_namestore_sqlite_done (void *cls) +{ + struct GNUNET_NAMESTORE_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "sqlite plugin is done\n"); + database_shutdown (plugin); + plugin->cfg = NULL; + GNUNET_free (api); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "sqlite plugin is finished\n"); + return NULL; +} + +/* end of plugin_namestore_sqlite.c */ diff --git a/src/namestore/test_namestore_api.c b/src/namestore/test_namestore_api.c new file mode 100644 index 0000000..ebd8be3 --- /dev/null +++ b/src/namestore/test_namestore_api.c @@ -0,0 +1,213 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file namestore/test_namestore_api.c + * @brief testcase for namestore_api.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_namestore_service.h" + +#define VERBOSE GNUNET_NO + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) + +static struct GNUNET_NAMESTORE_Handle * nsh; + +static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; +static struct GNUNET_OS_Process *arm; + +static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; +static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; +static GNUNET_HashCode zone; + +static int res; + +#define TEST_RECORD_TYPE 1234 +#define TEST_RECORD_DATALEN 123 +#define TEST_RECORD_DATA 'a' + + +static void +start_arm (const char *cfgname) +{ + arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", "-c", cfgname, +#if VERBOSE_PEERS + "-L", "DEBUG", +#else + "-L", "ERROR", +#endif + NULL); +} + +static void +stop_arm () +{ + if (NULL != arm) + { + if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + GNUNET_OS_process_wait (arm); + GNUNET_OS_process_close (arm); + arm = NULL; + } +} + +/** + * Re-establish the connection to the service. + * + * @param cls handle to use to re-connect. + * @param tc scheduler context + */ +static void +endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (nsh != NULL) + GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); + nsh = NULL; + + if (privkey != NULL) + GNUNET_CRYPTO_rsa_key_free (privkey); + privkey = NULL; + + if (NULL != arm) + stop_arm(); + + res = 1; +} + + +static void +end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (endbadly_task); + endbadly_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (privkey != NULL) + GNUNET_CRYPTO_rsa_key_free (privkey); + privkey = NULL; + + if (nsh != NULL) + GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); + nsh = NULL; + + + if (NULL != arm) + stop_arm(); + + res = 0; +} + + +void name_lookup_proc (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore lookup result %p `%s' %i %p %p\n", zone_key, name, rd_count, rd, signature); + res = 0; + GNUNET_SCHEDULER_add_now(&end, NULL); +} + +void put_cont (void *cls, int32_t success, const char *emsg) +{ + char * name = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name store added record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); + + GNUNET_NAMESTORE_lookup_record (nsh, &zone, name, 0, &name_lookup_proc, NULL); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,endbadly, NULL); + + privkey = GNUNET_CRYPTO_rsa_key_create_from_file("hostkey"); + GNUNET_assert (privkey != NULL); + GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); + + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &zone); + + + struct GNUNET_CRYPTO_RsaSignature signature; + struct GNUNET_NAMESTORE_RecordData rd; + + rd.expiration = GNUNET_TIME_absolute_get(); + rd.record_type = TEST_RECORD_TYPE; + rd.data_size = TEST_RECORD_DATALEN; + rd.data = GNUNET_malloc(TEST_RECORD_DATALEN); + memset ((char *) rd.data, 'a', TEST_RECORD_DATALEN); + char * name = "dummy.dummy.gnunet"; + + start_arm (cfgfile); + GNUNET_assert (arm != NULL); + + nsh = GNUNET_NAMESTORE_connect (cfg); + GNUNET_break (NULL != nsh); + + GNUNET_NAMESTORE_record_put (nsh, &pubkey, name, + GNUNET_TIME_absolute_get_forever(), + 1, &rd, &signature, put_cont, name); + + GNUNET_free ((void *)rd.data); + +} + +static int +check () +{ + static char *const argv[] = { "test-namestore-api", + "-c", + "test_namestore_api.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + res = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-namestore-api", + "nohelp", options, &run, &res); + return res; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + ret = check (); + + return ret; +} + +/* end of test_namestore_api.c */ diff --git a/src/namestore/test_namestore_api.conf b/src/namestore/test_namestore_api.conf new file mode 100644 index 0000000..1b83e8f --- /dev/null +++ b/src/namestore/test_namestore_api.conf @@ -0,0 +1,34 @@ +[arm] +PORT = 12000 +DEFAULTSERVICES = namestore +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[namestore] +#PREFIX = valgrind --leak-check=full +AUTOSTART = YES +UNIXPATH = /tmp/gnunet-service-namestore.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +# PORT = 2099 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-namestore +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DATABASE = sqlite + +[namestore-sqlite] +FILENAME = $SERVICEHOME/namestore/sqlite.db + +[namestore-postgres] +CONFIG = connect_timeout=10; dbname=gnunet + +[namestore-mysql] +DATABASE = gnunet +CONFIG = ~/.my.cnf +# USER = gnunet +# PASSWORD = +# HOST = localhost +# PORT = 3306 + diff --git a/src/namestore/test_namestore_api_zone_iteration.c b/src/namestore/test_namestore_api_zone_iteration.c new file mode 100644 index 0000000..c0ef8c8 --- /dev/null +++ b/src/namestore/test_namestore_api_zone_iteration.c @@ -0,0 +1,219 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file namestore/test_namestore_api_zone_iteration.c + * @brief testcase for namestore_api.c zone iteration functionality + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_namestore_service.h" + +#define VERBOSE GNUNET_NO + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) + +static struct GNUNET_NAMESTORE_Handle * nsh; + +static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; +static GNUNET_SCHEDULER_TaskIdentifier stopiteration_task; +static struct GNUNET_OS_Process *arm; + +static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; +static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; +static GNUNET_HashCode zone; + +static struct GNUNET_NAMESTORE_ZoneIterator *zi; +static int res; + +static void +start_arm (const char *cfgname) +{ + arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", "-c", cfgname, +#if VERBOSE_PEERS + "-L", "DEBUG", +#else + "-L", "ERROR", +#endif + NULL); +} + +static void +stop_arm () +{ + if (NULL != arm) + { + if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + GNUNET_OS_process_wait (arm); + GNUNET_OS_process_close (arm); + arm = NULL; + } +} + +/** + * Re-establish the connection to the service. + * + * @param cls handle to use to re-connect. + * @param tc scheduler context + */ +static void +endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (stopiteration_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (stopiteration_task); + stopiteration_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (nsh != NULL) + GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); + nsh = NULL; + + if (privkey != NULL) + GNUNET_CRYPTO_rsa_key_free (privkey); + privkey = NULL; + + if (NULL != arm) + stop_arm(); + + res = 1; +} + + +static void +end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (stopiteration_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (stopiteration_task); + stopiteration_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (endbadly_task); + endbadly_task = GNUNET_SCHEDULER_NO_TASK; + } + + + if (privkey != NULL) + GNUNET_CRYPTO_rsa_key_free (privkey); + privkey = NULL; + + if (nsh != NULL) + GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); + nsh = NULL; + + + if (NULL != arm) + stop_arm(); + + res = 0; +} + +static void +stop_iteration (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + stopiteration_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping iteration for zone `%s'\n", GNUNET_h2s (&zone)); + GNUNET_NAMESTORE_zone_iteration_stop (zi); + + GNUNET_SCHEDULER_add_now (&end, NULL); +} + +void zone_proc (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for zone `%s'\n", GNUNET_h2s (&zone)); + + stopiteration_task = GNUNET_SCHEDULER_add_now (&stop_iteration, NULL); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,&endbadly, NULL); + + privkey = GNUNET_CRYPTO_rsa_key_create_from_file("hostkey"); + GNUNET_assert (privkey != NULL); + GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); + + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &zone); + + start_arm (cfgfile); + GNUNET_assert (arm != NULL); + + nsh = GNUNET_NAMESTORE_connect (cfg); + GNUNET_break (NULL != nsh); + + zi = GNUNET_NAMESTORE_zone_iteration_start(nsh, + &zone, + GNUNET_NAMESTORE_RF_NONE, + GNUNET_NAMESTORE_RF_NONE, + zone_proc, + &zone); + if (zi == NULL) + { + GNUNET_break (0); + GNUNET_SCHEDULER_cancel (endbadly_task); + endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); + } +} + +static int +check () +{ + static char *const argv[] = { "test_namestore_api_zone_iteration", + "-c", + "test_namestore_api.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + res = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test_namestore_api_zone_iteration", + "nohelp", options, &run, &res); + return res; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + ret = check (); + + return ret; +} + +/* end of test_namestore_api_zone_iteration.c */ diff --git a/src/namestore/test_namestore_record_serialization.c b/src/namestore/test_namestore_record_serialization.c new file mode 100644 index 0000000..5ea345b --- /dev/null +++ b/src/namestore/test_namestore_record_serialization.c @@ -0,0 +1,157 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file namestore/test_namestore_record_serialization.c + * @brief testcase for test_namestore_record_serialization.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_namestore_service.h" +#include "namestore.h" + +#define VERBOSE GNUNET_NO + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) + +static int res; + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char * dest = NULL; + size_t len; + int c; + int elem = 0; + + int rd_count = 3; + size_t data_len; + struct GNUNET_NAMESTORE_RecordData src[rd_count]; + struct GNUNET_NAMESTORE_RecordData *dst = NULL; + + memset(src, '\0', rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData)); + + data_len = 0; + for (c = 0; c < rd_count; c++) + { + src[c].record_type = c+1; + src[c].data_size = data_len; + src[c].data = GNUNET_malloc (data_len); + + /* Setting data to data_len * record_type */ + memset ((char *) src[c].data, 'a', data_len); + data_len += 10; + } + res = 0; + + len = GNUNET_NAMESTORE_records_serialize (&dest, rd_count, src); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Serialized data len: %u\n",len); + + GNUNET_assert (dest != NULL); + + elem = GNUNET_NAMESTORE_records_deserialize(&dst, dest, len); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deserialized elements: %u\n",elem); + + GNUNET_assert (elem == rd_count); + GNUNET_assert (dst != NULL); + + for (c = 0; c < elem; c++) + { + if (src[c].data_size != dst[c].data_size) + { + GNUNET_break (0); + res = 1; + } + if (GNUNET_TIME_absolute_get_difference(src[c].expiration, dst[c].expiration).rel_value != GNUNET_TIME_relative_get_zero().rel_value) + { + GNUNET_break (0); + res = 1; + } + if (src[c].flags != dst[c].flags) + { + GNUNET_break (0); + res = 1; + } + if (src[c].record_type != dst[c].record_type) + { + GNUNET_break (0); + res = 1; + } + + size_t data_size = src[c].data_size; + char data[data_size]; + memset (data, 'a', data_size); + if (0 != memcmp (data, dst[c].data, data_size)) + { + GNUNET_break (0); + res = 1; + } + if (0 != memcmp (data, src[c].data, data_size)) + { + GNUNET_break (0); + res = 1; + } + if (0 != memcmp (src[c].data, dst[c].data, src[c].data_size)) + { + GNUNET_break (0); + res = 1; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Element [%i]: EQUAL\n", c); + /* clean up */ + GNUNET_free((char *) dst[c].data); + GNUNET_free((char *) src[c].data); + } + GNUNET_free (dest); + GNUNET_free (dst); +} + +static int +check () +{ + static char *const argv[] = { "test_namestore_record_serialization", + "-c", + "test_namestore_api.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + res = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test_namestore_record_serialization", + "nohelp", options, &run, &res); + return res; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + ret = check (); + + return ret; +} + +/* end of test_namestore_record_serialization.c */ diff --git a/src/namestore/test_plugin_namestore.c b/src/namestore/test_plugin_namestore.c new file mode 100644 index 0000000..0b0008f --- /dev/null +++ b/src/namestore/test_plugin_namestore.c @@ -0,0 +1,248 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* + * @file namestore/test_plugin_namestore.c + * @brief Test for the namestore plugins + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_namestore_plugin.h" + +#define VERBOSE GNUNET_NO + +#define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0) + +static int ok; + +/** + * Name of plugin under test. + */ +static const char *plugin_name; + + +/** + * Function called when the service shuts down. Unloads our namestore + * plugin. + * + * @param api api to unload + */ +static void +unload_plugin (struct GNUNET_NAMESTORE_PluginFunctions *api) +{ + char *libname; + + GNUNET_asprintf (&libname, "libgnunet_plugin_namestore_%s", plugin_name); + GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api)); + GNUNET_free (libname); +} + + +/** + * Load the namestore plugin. + * + * @param cfg configuration to pass + * @return NULL on error + */ +static struct GNUNET_NAMESTORE_PluginFunctions * +load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_NAMESTORE_PluginFunctions *ret; + char *libname; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' namestore plugin\n"), + plugin_name); + GNUNET_asprintf (&libname, "libgnunet_plugin_namestore_%s", plugin_name); + if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg))) + { + FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name); + return NULL; + } + GNUNET_free (libname); + return ret; +} + + +/** + * Function called by for each matching record. + * + * @param cls closure + * @param zone_key public key of the zone + * @param expire when does the corresponding block in the DHT expire (until + * when should we never do a DHT lookup for the same name again)? + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature of the record block, NULL if signature is unavailable (i.e. + * because the user queried for a particular record type only) + */ +static void +test_record (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + int *idp = cls; + int id = *idp; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded tzone_key; + char tname[64]; + unsigned int trd_count = 1 + (id % 1024); + struct GNUNET_CRYPTO_RsaSignature tsignature; + unsigned int i; + + GNUNET_snprintf (tname, sizeof (tname), + "a%u", (unsigned int ) id); + for (i=0;iiterate_records (nsp->cls, + NULL, NULL, 0, + &test_record, &id)); +} + + +static void +put_record (struct GNUNET_NAMESTORE_PluginFunctions *nsp, int id) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded zone_key; + struct GNUNET_TIME_Absolute expire; + char name[64]; + unsigned int rd_count = 1 + (id % 1024); + struct GNUNET_NAMESTORE_RecordData rd[rd_count]; + struct GNUNET_CRYPTO_RsaSignature signature; + unsigned int i; + + GNUNET_snprintf (name, sizeof (name), + "a%u", (unsigned int ) id); + expire = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); + for (i=0;iput_records (nsp->cls, + &zone_key, + expire, + name, + rd_count, + rd, + &signature)); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_NAMESTORE_PluginFunctions *nsp; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded zone_key; + GNUNET_HashCode zone; + + ok = 0; + nsp = load_plugin (cfg); + if (NULL == nsp) + { + FPRINTF (stderr, + "%s", + "Failed to initialize namestore. Database likely not setup, skipping test.\n"); + return; + } + put_record (nsp, 1); + get_record (nsp, 1); + + memset (&zone_key, 1, sizeof (zone_key)); + GNUNET_CRYPTO_hash (&zone_key, sizeof (zone_key), &zone); + nsp->delete_zone (nsp->cls, &zone); + unload_plugin (nsp); +} + + +int +main (int argc, char *argv[]) +{ + char *pos; + char cfg_name[128]; + + char *const xargv[] = { + "test-plugin-namestore", + "-c", + cfg_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-namestore-sqlite"); + GNUNET_log_setup ("test-plugin-namestore", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + /* determine name of plugin to use */ + plugin_name = argv[0]; + while (NULL != (pos = strstr (plugin_name, "_"))) + plugin_name = pos + 1; + if (NULL != (pos = strstr (plugin_name, "."))) + pos[0] = 0; + else + pos = (char *) plugin_name; + + GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_namestore_%s.conf", + plugin_name); + if (pos != plugin_name) + pos[0] = '.'; + GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, + "test-plugin-namestore", "nohelp", options, &run, NULL); + if (ok != 0) + FPRINTF (stderr, "Missed some testcases: %d\n", ok); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-namestore-sqlite"); + return ok; +} + +/* end of test_plugin_namestore.c */ diff --git a/src/namestore/test_plugin_namestore_sqlite.conf b/src/namestore/test_plugin_namestore_sqlite.conf new file mode 100644 index 0000000..57b170f --- /dev/null +++ b/src/namestore/test_plugin_namestore_sqlite.conf @@ -0,0 +1,2 @@ +[namestore-sqlite] +FILENAME = /tmp/gnunet-test-plugin-namestore-sqlite/sqlite.db diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am new file mode 100644 index 0000000..ed3a154 --- /dev/null +++ b/src/nat/Makefile.am @@ -0,0 +1,102 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols + NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client + NATSERVER = gnunet-helper-nat-server-windows.c + NATCLIENT = gnunet-helper-nat-client-windows.c +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +dist_pkgcfg_DATA = \ + nat.conf + + +if ENABLE_TEST_RUN + nattest = $(bindir)/gnunet-nat-server +endif + + +if LINUX +NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client +NATSERVER = gnunet-helper-nat-server.c +NATCLIENT = gnunet-helper-nat-client.c +install-exec-hook: + $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-nat-server $(bindir)/gnunet-helper-nat-client $(nattest) || true + $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-nat-server $(bindir)/gnunet-helper-nat-client $(nattest) || true +else +install-exec-hook: +endif + +bin_PROGRAMS = \ + gnunet-nat-server \ + $(NATBIN) + +gnunet_nat_server_SOURCES = \ + gnunet-nat-server.c nat.h +gnunet_nat_server_LDADD = \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +gnunet_nat_server_DEPENDENCIES = \ + libgnunetnat.la + +gnunet_helper_nat_server_SOURCES = \ + $(NATSERVER) + +gnunet_helper_nat_client_SOURCES = \ + $(NATCLIENT) + + + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + +lib_LTLIBRARIES = libgnunetnat.la + +libgnunetnat_la_SOURCES = \ + nat.c nat.h \ + nat_test.c \ + nat_mini.c + +libgnunetnat_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) @EXT_LIBS@ + +libgnunetnat_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +check_PROGRAMS = \ + test_nat \ + test_nat_mini \ + test_nat_test + +if ENABLE_TEST_RUN + TESTS = $(check_PROGRAMS) +endif + +test_nat_SOURCES = \ + test_nat.c +test_nat_LDADD = \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_nat_mini_SOURCES = \ + test_nat_mini.c +test_nat_mini_LDADD = \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + + +test_nat_test_SOURCES = \ + test_nat_test.c +test_nat_test_LDADD = \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + + +EXTRA_DIST = \ + test_nat_data.conf \ + test_nat_test_data.conf \ No newline at end of file diff --git a/src/nat/Makefile.in b/src/nat/Makefile.in new file mode 100644 index 0000000..00ef188 --- /dev/null +++ b/src/nat/Makefile.in @@ -0,0 +1,969 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-nat-server$(EXEEXT) $(am__EXEEXT_1) +check_PROGRAMS = test_nat$(EXEEXT) test_nat_mini$(EXEEXT) \ + test_nat_test$(EXEEXT) +subdir = src/nat +DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunetnat_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunetnat_la_OBJECTS = nat.lo nat_test.lo nat_mini.lo +libgnunetnat_la_OBJECTS = $(am_libgnunetnat_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetnat_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetnat_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +@LINUX_FALSE@@MINGW_TRUE@am__EXEEXT_1 = \ +@LINUX_FALSE@@MINGW_TRUE@ gnunet-helper-nat-server$(EXEEXT) \ +@LINUX_FALSE@@MINGW_TRUE@ gnunet-helper-nat-client$(EXEEXT) +@LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-nat-server$(EXEEXT) \ +@LINUX_TRUE@ gnunet-helper-nat-client$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) +am__gnunet_helper_nat_client_SOURCES_DIST = \ + gnunet-helper-nat-client.c gnunet-helper-nat-client-windows.c +@LINUX_FALSE@@MINGW_TRUE@am__objects_1 = gnunet-helper-nat-client-windows.$(OBJEXT) +@LINUX_TRUE@am__objects_1 = gnunet-helper-nat-client.$(OBJEXT) +am_gnunet_helper_nat_client_OBJECTS = $(am__objects_1) +gnunet_helper_nat_client_OBJECTS = \ + $(am_gnunet_helper_nat_client_OBJECTS) +gnunet_helper_nat_client_LDADD = $(LDADD) +am__gnunet_helper_nat_server_SOURCES_DIST = \ + gnunet-helper-nat-server.c gnunet-helper-nat-server-windows.c +@LINUX_FALSE@@MINGW_TRUE@am__objects_2 = gnunet-helper-nat-server-windows.$(OBJEXT) +@LINUX_TRUE@am__objects_2 = gnunet-helper-nat-server.$(OBJEXT) +am_gnunet_helper_nat_server_OBJECTS = $(am__objects_2) +gnunet_helper_nat_server_OBJECTS = \ + $(am_gnunet_helper_nat_server_OBJECTS) +gnunet_helper_nat_server_LDADD = $(LDADD) +am_gnunet_nat_server_OBJECTS = gnunet-nat-server.$(OBJEXT) +gnunet_nat_server_OBJECTS = $(am_gnunet_nat_server_OBJECTS) +am_test_nat_OBJECTS = test_nat.$(OBJEXT) +test_nat_OBJECTS = $(am_test_nat_OBJECTS) +test_nat_DEPENDENCIES = $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_nat_mini_OBJECTS = test_nat_mini.$(OBJEXT) +test_nat_mini_OBJECTS = $(am_test_nat_mini_OBJECTS) +test_nat_mini_DEPENDENCIES = $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_nat_test_OBJECTS = test_nat_test.$(OBJEXT) +test_nat_test_OBJECTS = $(am_test_nat_test_OBJECTS) +test_nat_test_DEPENDENCIES = $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetnat_la_SOURCES) \ + $(gnunet_helper_nat_client_SOURCES) \ + $(gnunet_helper_nat_server_SOURCES) \ + $(gnunet_nat_server_SOURCES) $(test_nat_SOURCES) \ + $(test_nat_mini_SOURCES) $(test_nat_test_SOURCES) +DIST_SOURCES = $(libgnunetnat_la_SOURCES) \ + $(am__gnunet_helper_nat_client_SOURCES_DIST) \ + $(am__gnunet_helper_nat_server_SOURCES_DIST) \ + $(gnunet_nat_server_SOURCES) $(test_nat_SOURCES) \ + $(test_nat_mini_SOURCES) $(test_nat_test_SOURCES) +DATA = $(dist_pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@LINUX_TRUE@NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client +@MINGW_TRUE@NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client +@LINUX_TRUE@NATSERVER = gnunet-helper-nat-server.c +@MINGW_TRUE@NATSERVER = gnunet-helper-nat-server-windows.c +@LINUX_TRUE@NATCLIENT = gnunet-helper-nat-client.c +@MINGW_TRUE@NATCLIENT = gnunet-helper-nat-client-windows.c +pkgcfgdir = $(pkgdatadir)/config.d/ +dist_pkgcfg_DATA = \ + nat.conf + +@ENABLE_TEST_RUN_TRUE@nattest = $(bindir)/gnunet-nat-server +gnunet_nat_server_SOURCES = \ + gnunet-nat-server.c nat.h + +gnunet_nat_server_LDADD = \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_nat_server_DEPENDENCIES = \ + libgnunetnat.la + +gnunet_helper_nat_server_SOURCES = \ + $(NATSERVER) + +gnunet_helper_nat_client_SOURCES = \ + $(NATCLIENT) + +@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage +lib_LTLIBRARIES = libgnunetnat.la +libgnunetnat_la_SOURCES = \ + nat.c nat.h \ + nat_test.c \ + nat_mini.c + +libgnunetnat_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) @EXT_LIBS@ + +libgnunetnat_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_nat_SOURCES = \ + test_nat.c + +test_nat_LDADD = \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_nat_mini_SOURCES = \ + test_nat_mini.c + +test_nat_mini_LDADD = \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_nat_test_SOURCES = \ + test_nat_test.c + +test_nat_test_LDADD = \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_nat_data.conf \ + test_nat_test_data.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/nat/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/nat/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetnat.la: $(libgnunetnat_la_OBJECTS) $(libgnunetnat_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetnat_la_LINK) -rpath $(libdir) $(libgnunetnat_la_OBJECTS) $(libgnunetnat_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-helper-nat-client$(EXEEXT): $(gnunet_helper_nat_client_OBJECTS) $(gnunet_helper_nat_client_DEPENDENCIES) + @rm -f gnunet-helper-nat-client$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_helper_nat_client_OBJECTS) $(gnunet_helper_nat_client_LDADD) $(LIBS) +gnunet-helper-nat-server$(EXEEXT): $(gnunet_helper_nat_server_OBJECTS) $(gnunet_helper_nat_server_DEPENDENCIES) + @rm -f gnunet-helper-nat-server$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_helper_nat_server_OBJECTS) $(gnunet_helper_nat_server_LDADD) $(LIBS) +gnunet-nat-server$(EXEEXT): $(gnunet_nat_server_OBJECTS) $(gnunet_nat_server_DEPENDENCIES) + @rm -f gnunet-nat-server$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_nat_server_OBJECTS) $(gnunet_nat_server_LDADD) $(LIBS) +test_nat$(EXEEXT): $(test_nat_OBJECTS) $(test_nat_DEPENDENCIES) + @rm -f test_nat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_nat_OBJECTS) $(test_nat_LDADD) $(LIBS) +test_nat_mini$(EXEEXT): $(test_nat_mini_OBJECTS) $(test_nat_mini_DEPENDENCIES) + @rm -f test_nat_mini$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_nat_mini_OBJECTS) $(test_nat_mini_LDADD) $(LIBS) +test_nat_test$(EXEEXT): $(test_nat_test_OBJECTS) $(test_nat_test_DEPENDENCIES) + @rm -f test_nat_test$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_nat_test_OBJECTS) $(test_nat_test_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-nat-client-windows.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-nat-client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-nat-server-windows.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-nat-server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-nat-server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nat_mini.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nat_test.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_nat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_nat_mini.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_nat_test.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-dist_pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA \ + uninstall-libLTLIBRARIES + +.MAKE: check-am install-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dist_pkgcfgDATA install-dvi \ + install-dvi-am install-exec install-exec-am install-exec-hook \ + install-html install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-dist_pkgcfgDATA uninstall-libLTLIBRARIES + +@LINUX_TRUE@install-exec-hook: +@LINUX_TRUE@ $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-nat-server $(bindir)/gnunet-helper-nat-client $(nattest) || true +@LINUX_TRUE@ $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-nat-server $(bindir)/gnunet-helper-nat-client $(nattest) || true +@LINUX_FALSE@install-exec-hook: + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/nat/gnunet-helper-nat-client-windows.c b/src/nat/gnunet-helper-nat-client-windows.c new file mode 100644 index 0000000..47fbc0b --- /dev/null +++ b/src/nat/gnunet-helper-nat-client-windows.c @@ -0,0 +1,507 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/nat/gnunet-helper-nat-client-windows.c + * @brief Tool to help bypass NATs using ICMP method; must run as + * administrator on W32 + * This code is forx W32. + * @author Nathan Evans + * + * This program will send ONE ICMP message using RAW sockets + * to the IP address specified as the second argument. Since + * it uses RAW sockets, it must be installed SUID or run as 'root'. + * In order to keep the security risk of the resulting SUID binary + * minimal, the program ONLY opens the RAW socket with root + * privileges, then drops them and only then starts to process + * command line arguments. The code also does not link against + * any shared libraries (except libc) and is strictly minimal + * (except for checking for errors). The following list of people + * have reviewed this code and considered it safe since the last + * modification (if you reviewed it, please have your name added + * to the list): + * + * - Christian Grothoff + * - Nathan Evans + */ +#define _GNU_SOURCE + +#define FD_SETSIZE 1024 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define ICMP_ECHO 8 +#define IPDEFTTL 64 +#define ICMP_TIME_EXCEEDED 11 + +/** + * Must match IP given in the server. + */ +#define DUMMY_IP "192.0.2.86" + +#define NAT_TRAV_PORT 22225 + +/** + * IPv4 header. + */ +struct ip_header +{ + + /** + * Version (4 bits) + Internet header length (4 bits) + */ + uint8_t vers_ihl; + + /** + * Type of service + */ + uint8_t tos; + + /** + * Total length + */ + uint16_t pkt_len; + + /** + * Identification + */ + uint16_t id; + + /** + * Flags (3 bits) + Fragment offset (13 bits) + */ + uint16_t flags_frag_offset; + + /** + * Time to live + */ + uint8_t ttl; + + /** + * Protocol + */ + uint8_t proto; + + /** + * Header checksum + */ + uint16_t checksum; + + /** + * Source address + */ + uint32_t src_ip; + + /** + * Destination address + */ + uint32_t dst_ip; +}; + + +/** + * Format of ICMP packet. + */ +struct icmp_ttl_exceeded_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t unused; + + /* followed by original payload */ +}; + +struct icmp_echo_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t reserved; +}; + +/** + * Beginning of UDP packet. + */ +struct udp_header +{ + uint16_t src_port; + + uint16_t dst_port; + + uint16_t length; + + uint16_t crc; +}; + + +/** + * Socket we use to send our ICMP packets. + */ +static SOCKET rawsock; + +/** + * Target "dummy" address. + */ +static struct in_addr dummy; + +/** + * Port we are listening on (communicated to the server). + */ +static uint16_t port; + + + +/** + * Convert IPv4 address from text to binary form. + * + * @param af address family + * @param cp the address to print + * @param buf where to write the address result + * @return 1 on success + */ +static int +inet_pton (int af, const char *cp, struct in_addr *buf) +{ + buf->s_addr = inet_addr (cp); + if (buf->s_addr == INADDR_NONE) + { + fprintf (stderr, "Error %d handling address %s", WSAGetLastError (), cp); + return 0; + } + return 1; +} + + +/** + * CRC-16 for IP/ICMP headers. + * + * @param data what to calculate the CRC over + * @param bytes number of bytes in data (must be multiple of 2) + * @return the CRC 16. + */ +static uint16_t +calc_checksum (const uint16_t * data, unsigned int bytes) +{ + uint32_t sum; + unsigned int i; + + sum = 0; + for (i = 0; i < bytes / 2; i++) + sum += data[i]; + sum = (sum & 0xffff) + (sum >> 16); + sum = htons (0xffff - sum); + return sum; +} + + +/** + * Send an ICMP message to the target. + * + * @param my_ip source address + * @param other target address + */ +static void +send_icmp_udp (const struct in_addr *my_ip, const struct in_addr *other) +{ + char packet[sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct udp_header)]; + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_pkt; + struct udp_header udp_pkt; + struct sockaddr_in dst; + size_t off; + int err; + + /* ip header: send to (known) ip address */ + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons (256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 128; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = other->s_addr; + ip_pkt.checksum = + htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + icmp_pkt.type = ICMP_TIME_EXCEEDED; + icmp_pkt.code = 0; + icmp_pkt.checksum = 0; + icmp_pkt.unused = 0; + memcpy (&packet[off], &icmp_pkt, sizeof (struct icmp_ttl_exceeded_header)); + off += sizeof (struct icmp_ttl_exceeded_header); + + /* ip header of the presumably 'lost' udp packet */ + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = + htons (sizeof (struct ip_header) + sizeof (struct udp_header)); + ip_pkt.id = htons (0); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 128; + ip_pkt.proto = IPPROTO_UDP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = other->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = + htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + /* build UDP header */ + udp_pkt.src_port = htons (NAT_TRAV_PORT); + udp_pkt.dst_port = htons (NAT_TRAV_PORT); + udp_pkt.length = htons (port); + udp_pkt.crc = 0; + memcpy (&packet[off], &udp_pkt, sizeof (struct udp_header)); + off += sizeof (struct udp_header); + + /* no go back to calculate ICMP packet checksum */ + icmp_pkt.checksum = + htons (calc_checksum + ((uint16_t *) & packet[off], + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct ip_header) + sizeof (struct udp_header))); + memcpy (&packet[sizeof (struct ip_header)], &icmp_pkt, + sizeof (struct icmp_ttl_exceeded_header)); + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; + dst.sin_addr = *other; + err = + sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst, + sizeof (dst)); + if (err < 0) + { + fprintf (stderr, "sendto failed: %s\n", strerror (errno)); + } + else if (sizeof (packet) != (size_t) err) + { + fprintf (stderr, "Error: partial send of ICMP message\n"); + } +} + + +/** + * Send an ICMP message to the target. + * + * @param my_ip source address + * @param other target address + */ +static void +send_icmp (const struct in_addr *my_ip, const struct in_addr *other) +{ + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_ttl; + struct icmp_echo_header icmp_echo; + struct sockaddr_in dst; + char packet[sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct icmp_echo_header)]; + size_t off; + int err; + + /* ip header: send to (known) ip address */ + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons (256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = IPDEFTTL; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = other->s_addr; + ip_pkt.checksum = + htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); + off += sizeof (ip_pkt); + + /* icmp reply: time exceeded */ + icmp_ttl.type = ICMP_TIME_EXCEEDED; + icmp_ttl.code = 0; + icmp_ttl.checksum = 0; + icmp_ttl.unused = 0; + memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header)); + off += sizeof (struct icmp_ttl_exceeded_header); + + /* ip header of the presumably 'lost' udp packet */ + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = + htons (sizeof (struct ip_header) + sizeof (struct icmp_echo_header)); + ip_pkt.id = htons (256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.src_ip = other->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = 0; + ip_pkt.checksum = + htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + icmp_echo.type = ICMP_ECHO; + icmp_echo.code = 0; + icmp_echo.reserved = htonl (port); + icmp_echo.checksum = 0; + icmp_echo.checksum = + htons (calc_checksum + ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header))); + memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header)); + + /* no go back to calculate ICMP packet checksum */ + off = sizeof (struct ip_header); + icmp_ttl.checksum = + htons (calc_checksum + ((uint16_t *) & packet[off], + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct ip_header) + sizeof (struct icmp_echo_header))); + memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header)); + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; + dst.sin_addr = *other; + + err = + sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst, + sizeof (dst)); + + if (err < 0) + { + fprintf (stderr, "sendto failed: %s\n", strerror (errno)); + } + else if (sizeof (packet) != (size_t) err) + { + fprintf (stderr, "Error: partial send of ICMP message\n"); + } +} + + +/** + * Create an ICMP raw socket. + * + * @return INVALID_SOCKET on error + */ +static SOCKET +make_raw_socket () +{ + DWORD bOptVal = TRUE; + int bOptLen = sizeof (bOptVal); + SOCKET ret; + + ret = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); + if (INVALID_SOCKET == ret) + { + fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno)); + return INVALID_SOCKET; + } + if (0 != + setsockopt (ret, SOL_SOCKET, SO_BROADCAST, (char *) &bOptVal, bOptLen)) + { + fprintf (stderr, "Error setting SO_BROADCAST to ON: %s\n", + strerror (errno)); + closesocket (rawsock); + return INVALID_SOCKET; + } + + if (0 != setsockopt (ret, IPPROTO_IP, IP_HDRINCL, (char *) &bOptVal, bOptLen)) + { + fprintf (stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror (errno)); + closesocket (rawsock); + return INVALID_SOCKET; + } + return ret; +} + + +int +main (int argc, char *const *argv) +{ + struct in_addr external; + struct in_addr target; + WSADATA wsaData; + + unsigned int p; + + if (argc != 4) + { + fprintf (stderr, + "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); + return 1; + } + if ((1 != inet_pton (AF_INET, argv[1], &external)) || + (1 != inet_pton (AF_INET, argv[2], &target))) + { + fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno)); + return 1; + } + if ((1 != sscanf (argv[3], "%u", &p)) || (0 == p) || (0xFFFF < p)) + { + fprintf (stderr, "Error parsing port value `%s'\n", argv[3]); + return 1; + } + port = (uint16_t) p; + + if (0 != WSAStartup (MAKEWORD (2, 1), &wsaData)) + { + fprintf (stderr, "Failed to find Winsock 2.1 or better.\n"); + return 2; + } + if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) + { + fprintf (stderr, "Internal error converting dummy IP to binary.\n"); + return 2; + } + if (-1 == (rawsock = make_raw_socket ())) + return 3; + send_icmp (&external, &target); + send_icmp_udp (&external, &target); + closesocket (rawsock); + WSACleanup (); + return 0; +} + +/* end of gnunet-helper-nat-client-windows.c */ diff --git a/src/nat/gnunet-helper-nat-client.c b/src/nat/gnunet-helper-nat-client.c new file mode 100644 index 0000000..73504ab --- /dev/null +++ b/src/nat/gnunet-helper-nat-client.c @@ -0,0 +1,498 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/nat/gnunet-helper-nat-client.c + * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) + * This code will work under GNU/Linux only. + * @author Christian Grothoff + * + * This program will send ONE ICMP message using RAW sockets + * to the IP address specified as the second argument. Since + * it uses RAW sockets, it must be installed SUID or run as 'root'. + * In order to keep the security risk of the resulting SUID binary + * minimal, the program ONLY opens the RAW socket with root + * privileges, then drops them and only then starts to process + * command line arguments. The code also does not link against + * any shared libraries (except libc) and is strictly minimal + * (except for checking for errors). The following list of people + * have reviewed this code and considered it safe since the last + * modification (if you reviewed it, please have your name added + * to the list): + * + * - Christian Grothoff + * - Nathan Evans + * - Benjamin Kuperman (22 Aug 2010) + */ +#if HAVE_CONFIG_H +/* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ +#include "gnunet_config.h" +#else +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Must match IP given in the server. + */ +#define DUMMY_IP "192.0.2.86" + +#define NAT_TRAV_PORT 22225 + +/** + * Must match packet ID used by gnunet-helper-nat-server.c + */ +#define PACKET_ID 256 + +/** + * IPv4 header. + */ +struct ip_header +{ + + /** + * Version (4 bits) + Internet header length (4 bits) + */ + uint8_t vers_ihl; + + /** + * Type of service + */ + uint8_t tos; + + /** + * Total length + */ + uint16_t pkt_len; + + /** + * Identification + */ + uint16_t id; + + /** + * Flags (3 bits) + Fragment offset (13 bits) + */ + uint16_t flags_frag_offset; + + /** + * Time to live + */ + uint8_t ttl; + + /** + * Protocol + */ + uint8_t proto; + + /** + * Header checksum + */ + uint16_t checksum; + + /** + * Source address + */ + uint32_t src_ip; + + /** + * Destination address + */ + uint32_t dst_ip; +}; + +/** + * Format of ICMP packet. + */ +struct icmp_ttl_exceeded_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t unused; + + /* followed by original payload */ +}; + +struct icmp_echo_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t reserved; +}; + +/** + * Beginning of UDP packet. + */ +struct udp_header +{ + uint16_t src_port; + + uint16_t dst_port; + + uint16_t length; + + uint16_t crc; +}; + +/** + * Socket we use to send our fake ICMP replies. + */ +static int rawsock; + +/** + * Target "dummy" address of the packet we pretend to respond to. + */ +static struct in_addr dummy; + +/** + * Our "source" port. + */ +static uint16_t port; + + +/** + * CRC-16 for IP/ICMP headers. + * + * @param data what to calculate the CRC over + * @param bytes number of bytes in data (must be multiple of 2) + * @return the CRC 16. + */ +static uint16_t +calc_checksum (const uint16_t * data, unsigned int bytes) +{ + uint32_t sum; + unsigned int i; + + sum = 0; + for (i = 0; i < bytes / 2; i++) + sum += data[i]; + sum = (sum & 0xffff) + (sum >> 16); + sum = htons (0xffff - sum); + return sum; +} + + +/** + * Send an ICMP message to the target. + * + * @param my_ip source address + * @param other target address + */ +static void +send_icmp_udp (const struct in_addr *my_ip, const struct in_addr *other) +{ + char packet[sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct udp_header)]; + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_pkt; + struct udp_header udp_pkt; + struct sockaddr_in dst; + size_t off; + int err; + + /* ip header: send to (known) ip address */ + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons (PACKET_ID); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 128; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = other->s_addr; + ip_pkt.checksum = + htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + icmp_pkt.type = ICMP_TIME_EXCEEDED; + icmp_pkt.code = 0; + icmp_pkt.checksum = 0; + icmp_pkt.unused = 0; + memcpy (&packet[off], &icmp_pkt, sizeof (struct icmp_ttl_exceeded_header)); + off += sizeof (struct icmp_ttl_exceeded_header); + + /* ip header of the presumably 'lost' udp packet */ + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = + htons (sizeof (struct ip_header) + sizeof (struct udp_header)); + ip_pkt.id = htons (0); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 128; + ip_pkt.proto = IPPROTO_UDP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = other->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = + htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + /* build UDP header */ + udp_pkt.src_port = htons (NAT_TRAV_PORT); + udp_pkt.dst_port = htons (NAT_TRAV_PORT); + udp_pkt.length = htons (port); + udp_pkt.crc = 0; + memcpy (&packet[off], &udp_pkt, sizeof (struct udp_header)); + off += sizeof (struct udp_header); + + /* set ICMP checksum */ + icmp_pkt.checksum = + htons (calc_checksum + ((uint16_t *) & packet[sizeof (struct ip_header)], + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct ip_header) + sizeof (struct udp_header))); + memcpy (&packet[sizeof (struct ip_header)], &icmp_pkt, + sizeof (struct icmp_ttl_exceeded_header)); + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + dst.sin_len = sizeof (struct sockaddr_in); +#endif + dst.sin_addr = *other; + err = + sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst, + sizeof (dst)); + if (err < 0) + { + fprintf (stderr, "sendto failed: %s\n", strerror (errno)); + } + else if (sizeof (packet) != (size_t) err) + { + fprintf (stderr, "Error: partial send of ICMP message\n"); + } +} + + +/** + * Send an ICMP message to the target. + * + * @param my_ip source address + * @param other target address + */ +static void +send_icmp (const struct in_addr *my_ip, const struct in_addr *other) +{ + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_ttl; + struct icmp_echo_header icmp_echo; + struct sockaddr_in dst; + char packet[sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct icmp_echo_header)]; + size_t off; + int err; + + /* ip header: send to (known) ip address */ + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons (PACKET_ID); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = IPDEFTTL; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = other->s_addr; + ip_pkt.checksum = + htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); + off = sizeof (ip_pkt); + + /* icmp reply: time exceeded */ + icmp_ttl.type = ICMP_TIME_EXCEEDED; + icmp_ttl.code = 0; + icmp_ttl.checksum = 0; + icmp_ttl.unused = 0; + memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header)); + off += sizeof (struct icmp_ttl_exceeded_header); + + /* ip header of the presumably 'lost' udp packet */ + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = + htons (sizeof (struct ip_header) + sizeof (struct icmp_echo_header)); + ip_pkt.id = htons (PACKET_ID); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.src_ip = other->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = 0; + ip_pkt.checksum = + htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + icmp_echo.type = ICMP_ECHO; + icmp_echo.code = 0; + icmp_echo.reserved = htonl (port); + icmp_echo.checksum = 0; + icmp_echo.checksum = + htons (calc_checksum + ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header))); + memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header)); + + /* no go back to calculate ICMP packet checksum */ + off = sizeof (struct ip_header); + icmp_ttl.checksum = + htons (calc_checksum + ((uint16_t *) & packet[off], + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct ip_header) + sizeof (struct icmp_echo_header))); + memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header)); + + /* prepare for transmission */ + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + dst.sin_len = sizeof (struct sockaddr_in); +#endif + dst.sin_addr = *other; + err = + sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst, + sizeof (dst)); + if (err < 0) + { + fprintf (stderr, "sendto failed: %s\n", strerror (errno)); + } + else if (sizeof (packet) != (size_t) err) + { + fprintf (stderr, "Error: partial send of ICMP message\n"); + } +} + + +int +main (int argc, char *const *argv) +{ + const int one = 1; + struct in_addr external; + struct in_addr target; + uid_t uid; + unsigned int p; + int raw_eno; + int global_ret; + + /* Create an ICMP raw socket for writing (only operation that requires root) */ + rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); + raw_eno = errno; /* for later error checking */ + + /* now drop root privileges */ + uid = getuid (); +#ifdef HAVE_SETRESUID + if (0 != setresuid (uid, uid, uid)) + { + fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); + global_ret = 1; + goto cleanup; + } +#else + if (0 != (setuid (uid) | seteuid (uid))) + { + fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); + global_ret = 2; + goto cleanup; + } +#endif + if (-1 == rawsock) + { + fprintf (stderr, "Error opening RAW socket: %s\n", strerror (raw_eno)); + global_ret = 3; + goto cleanup; + } + if (0 != + setsockopt (rawsock, SOL_SOCKET, SO_BROADCAST, (char *) &one, sizeof (one))) + { + fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); + global_ret = 4; + goto cleanup; + } + if (0 != + setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &one, sizeof (one))) + { + fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); + global_ret = 5; + goto cleanup; + } + + if (4 != argc) + { + fprintf (stderr, + "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); + global_ret = 6; + goto cleanup; + } + if ((1 != inet_pton (AF_INET, argv[1], &external)) || + (1 != inet_pton (AF_INET, argv[2], &target))) + { + fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno)); + global_ret = 7; + goto cleanup; + } + if ((1 != sscanf (argv[3], "%u", &p)) || (0 == p) || (0xFFFF < p)) + { + fprintf (stderr, "Error parsing port value `%s'\n", argv[3]); + global_ret = 8; + goto cleanup; + } + port = (uint16_t) p; + if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) + { + fprintf (stderr, "Internal error converting dummy IP to binary.\n"); + global_ret = 9; + goto cleanup; + } + send_icmp (&external, &target); + send_icmp_udp (&external, &target); + global_ret = 0; + cleanup: + if (-1 != rawsock) + (void) close (rawsock); + return global_ret; +} + +/* end of gnunet-helper-nat-client.c */ diff --git a/src/nat/gnunet-helper-nat-server-windows.c b/src/nat/gnunet-helper-nat-server-windows.c new file mode 100644 index 0000000..d970ffd --- /dev/null +++ b/src/nat/gnunet-helper-nat-server-windows.c @@ -0,0 +1,598 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/nat/gnunet-helper-nat-server-windows.c + * @brief Windows tool to help bypass NATs using ICMP method + * This code will work under W32 only + * @author Christian Grothoff + * + * This program will send ONE ICMP message every 500 ms RAW sockets + * to a DUMMY IP address and also listens for ICMP replies. Since + * it uses RAW sockets, it must be run as an administrative user. + * In order to keep the security risk of the resulting binary + * minimal, the program ONLY opens the two RAW sockets with administrative + * privileges, then drops them and only then starts to process + * command line arguments. The code also does not link against + * any shared libraries (except libc) and is strictly minimal + * (except for checking for errors). The following list of people + * have reviewed this code and considered it safe since the last + * modification (if you reviewed it, please have your name added + * to the list): + * + * - Nathan Evans + * - Christian Grothoff + */ +#define _GNU_SOURCE + +#define FD_SETSIZE 1024 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Should we print some debug output? + */ +#define VERBOSE 0 + +/** + * Must match IP given in the client. + */ +#define DUMMY_IP "192.0.2.86" + +/** + * Default Port + */ +#define NAT_TRAV_PORT 22225 + +/** + * Must match packet ID used by gnunet-helper-nat-client.c + */ +#define PACKET_ID 256 + +/** + * TTL to use for our outgoing messages. + */ +#define IPDEFTTL 64 + +#define ICMP_ECHO 8 + +#define ICMP_TIME_EXCEEDED 11 + +/** + * How often do we send our ICMP messages to receive replies? + */ +#define ICMP_SEND_FREQUENCY_MS 500 + +/** + * IPv4 header. + */ +struct ip_header +{ + + /** + * Version (4 bits) + Internet header length (4 bits) + */ + uint8_t vers_ihl; + + /** + * Type of service + */ + uint8_t tos; + + /** + * Total length + */ + uint16_t pkt_len; + + /** + * Identification + */ + uint16_t id; + + /** + * Flags (3 bits) + Fragment offset (13 bits) + */ + uint16_t flags_frag_offset; + + /** + * Time to live + */ + uint8_t ttl; + + /** + * Protocol + */ + uint8_t proto; + + /** + * Header checksum + */ + uint16_t checksum; + + /** + * Source address + */ + uint32_t src_ip; + + /** + * Destination address + */ + uint32_t dst_ip; +}; + +/** + * Format of ICMP packet. + */ +struct icmp_ttl_exceeded_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t unused; + + /* followed by original payload */ +}; + +struct icmp_echo_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t reserved; +}; + +/** + * Beginning of UDP packet. + */ +struct udp_header +{ + uint16_t src_port; + + uint16_t dst_port; + + uint16_t length; + + uint16_t crc; +}; + +/** + * Socket we use to receive "fake" ICMP replies. + */ +static SOCKET icmpsock; + +/** + * Socket we use to send our ICMP requests. + */ +static SOCKET rawsock; + +/** + * Socket we use to send our UDP requests. + */ +static SOCKET udpsock; + +/** + * Target "dummy" address. + */ +static struct in_addr dummy; + + +/** + * CRC-16 for IP/ICMP headers. + * + * @param data what to calculate the CRC over + * @param bytes number of bytes in data (must be multiple of 2) + * @return the CRC 16. + */ +static uint16_t +calc_checksum (const uint16_t * data, unsigned int bytes) +{ + uint32_t sum; + unsigned int i; + + sum = 0; + for (i = 0; i < bytes / 2; i++) + sum += data[i]; + sum = (sum & 0xffff) + (sum >> 16); + sum = htons (0xffff - sum); + return sum; +} + + +/** + * Convert IPv4 address from text to binary form. + * + * @param af address family + * @param cp the address to print + * @param buf where to write the address result + * @return 1 on success + */ +static int +inet_pton (int af, const char *cp, struct in_addr *buf) +{ + buf->s_addr = inet_addr (cp); + if (buf->s_addr == INADDR_NONE) + { + fprintf (stderr, "Error %d handling address %s", WSAGetLastError (), cp); + return 0; + } + return 1; +} + + +/** + * Send an ICMP message to the dummy IP. + * + * @param my_ip source address (our ip address) + */ +static void +send_icmp_echo (const struct in_addr *my_ip) +{ + char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)]; + struct icmp_echo_header icmp_echo; + struct ip_header ip_pkt; + struct sockaddr_in dst; + size_t off; + int err; + + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons (PACKET_ID); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = IPDEFTTL; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = + htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + icmp_echo.type = ICMP_ECHO; + icmp_echo.code = 0; + icmp_echo.reserved = 0; + icmp_echo.checksum = 0; + icmp_echo.checksum = + htons (calc_checksum + ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header))); + memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header)); + off += sizeof (struct icmp_echo_header); + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; + dst.sin_addr = dummy; + err = + sendto (rawsock, packet, off, 0, (struct sockaddr *) &dst, sizeof (dst)); + if (err < 0) + { +#if VERBOSE + fprintf (stderr, "sendto failed: %s\n", strerror (errno)); +#endif + } + else if (err != off) + { + fprintf (stderr, "Error: partial send of ICMP message\n"); + } +} + + +/** + * Send a UDP message to the dummy IP. + */ +static void +send_udp () +{ + struct sockaddr_in dst; + ssize_t err; + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; + dst.sin_addr = dummy; + dst.sin_port = htons (NAT_TRAV_PORT); + err = sendto (udpsock, NULL, 0, 0, (struct sockaddr *) &dst, sizeof (dst)); + if (err < 0) + { +#if VERBOSE + fprintf (stderr, "sendto failed: %s\n", strerror (errno)); +#endif + } + else if (0 != err) + { + fprintf (stderr, "Error: partial send of ICMP message\n"); + } +} + + +/** + * We've received an ICMP response. Process it. + */ +static void +process_icmp_response () +{ + char buf[65536]; + ssize_t have; + struct in_addr source_ip; + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_ttl; + struct icmp_echo_header icmp_echo; + struct udp_header udp_pkt; + size_t off; + uint16_t port; + DWORD ssize; + + have = read (icmpsock, buf, sizeof (buf)); + if (have == -1) + { + fprintf (stderr, "Error reading raw socket: %s\n", strerror (errno)); + return; + } +#if VERBOSE + fprintf (stderr, "Received message of %u bytes\n", (unsigned int) have); +#endif + if (have < + (ssize_t) (sizeof (struct ip_header) + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct ip_header))) + { + /* malformed */ + return; + } + off = 0; + memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header)); + off += sizeof (struct ip_header); + memcpy (&source_ip, &ip_pkt.src_ip, sizeof (source_ip)); + memcpy (&icmp_ttl, &buf[off], sizeof (struct icmp_ttl_exceeded_header)); + off += sizeof (struct icmp_ttl_exceeded_header); + if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code)) + { + /* different type than what we want */ + return; + } + /* skip 2nd IP header */ + memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + switch (ip_pkt.proto) + { + case IPPROTO_ICMP: + if (have != + (sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct icmp_echo_header))) + { + /* malformed */ + return; + } + /* grab ICMP ECHO content */ + memcpy (&icmp_echo, &buf[off], sizeof (struct icmp_echo_header)); + port = (uint16_t) ntohl (icmp_echo.reserved); + break; + case IPPROTO_UDP: + if (have != + (sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct udp_header))) + { + /* malformed */ + return; + } + /* grab UDP content */ + memcpy (&udp_pkt, &buf[off], sizeof (struct udp_header)); + port = ntohs (udp_pkt.length); + break; + default: + /* different type than what we want */ + return; + } + + ssize = sizeof (buf); + WSAAddressToString ((LPSOCKADDR) & source_ip, sizeof (source_ip), NULL, buf, + &ssize); + if (port == 0) + fprintf (stdout, "%s\n", buf); + else + fprintf (stdout, "%s:%u\n", buf, (unsigned int) port); + fflush (stdout); +} + + +/** + * Create an ICMP raw socket for reading. + * + * @return INVALID_SOCKET on error + */ +static SOCKET +make_icmp_socket () +{ + SOCKET ret; + + ret = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (INVALID_SOCKET == ret) + { + fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno)); + return INVALID_SOCKET; + } + return ret; +} + + +/** + * Create an ICMP raw socket for writing. + * + * @return INVALID_SOCKET on error + */ +static SOCKET +make_raw_socket () +{ + DWORD bOptVal = TRUE; + int bOptLen = sizeof (bOptVal); + + rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (INVALID_SOCKET == rawsock) + { + fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno)); + return INVALID_SOCKET; + } + + if (0 != + setsockopt (rawsock, SOL_SOCKET, SO_BROADCAST, (char *) &bOptVal, + bOptLen)) + { + fprintf (stderr, "Error setting SO_BROADCAST to ON: %s\n", + strerror (errno)); + closesocket (rawsock); + return INVALID_SOCKET; + } + if (0 != + setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &bOptVal, bOptLen)) + { + fprintf (stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror (errno)); + closesocket (rawsock); + return INVALID_SOCKET; + } + return rawsock; +} + + +/** + * Create a UDP socket for writing. + * + * @param my_ip source address (our ip address) + * @return INVALID_SOCKET on error + */ +static SOCKET +make_udp_socket (const struct in_addr *my_ip) +{ + SOCKET ret; + struct sockaddr_in addr; + + ret = socket (AF_INET, SOCK_DGRAM, 0); + if (INVALID_SOCKET == ret) + { + fprintf (stderr, "Error opening UDP socket: %s\n", strerror (errno)); + return INVALID_SOCKET; + } + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_addr = *my_ip; + addr.sin_port = htons (NAT_TRAV_PORT); + if (0 != bind (ret, (struct sockaddr *) &addr, sizeof (addr))) + { + fprintf (stderr, "Error binding UDP socket to port %u: %s\n", NAT_TRAV_PORT, + strerror (errno)); + /* likely problematic, but not certain, try to continue */ + } + return ret; +} + + +int +main (int argc, char *const *argv) +{ + struct in_addr external; + fd_set rs; + struct timeval tv; + WSADATA wsaData; + unsigned int alt; + + alt = 0; + if (2 != argc) + { + fprintf (stderr, + "This program must be started with our (internal NAT) IP as the only argument.\n"); + return 1; + } + if (1 != inet_pton (AF_INET, argv[1], &external)) + { + fprintf (stderr, "Error parsing IPv4 address: %s, error %s\n", argv[1], + strerror (errno)); + return 1; + } + if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) + { + fprintf (stderr, "Internal error converting dummy IP to binary.\n"); + return 2; + } + if (WSAStartup (MAKEWORD (2, 1), &wsaData) != 0) + { + fprintf (stderr, "Failed to find Winsock 2.1 or better.\n"); + return 2; + } + if (INVALID_SOCKET == (icmpsock = make_icmp_socket ())) + { + return 3; + } + if (INVALID_SOCKET == (make_raw_socket ())) + { + closesocket (icmpsock); + return 3; + } + if (INVALID_SOCKET == (udpsock = make_udp_socket (&external))) + { + closesocket (icmpsock); + closesocket (rawsock); + return 3; + } + while (1) + { + FD_ZERO (&rs); + FD_SET (icmpsock, &rs); + tv.tv_sec = 0; + tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; + if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv)) + { + if (errno == EINTR) + continue; + fprintf (stderr, "select failed: %s\n", strerror (errno)); + break; + } + if (FD_ISSET (icmpsock, &rs)) + process_icmp_response (); + if (0 == (++alt % 2)) + send_icmp_echo (&external); + else + send_udp (); + } + /* select failed (internal error or OS out of resources) */ + closesocket (icmpsock); + closesocket (rawsock); + closesocket (udpsock); + WSACleanup (); + return 4; +} + + +/* end of gnunet-helper-nat-server-windows.c */ diff --git a/src/nat/gnunet-helper-nat-server.c b/src/nat/gnunet-helper-nat-server.c new file mode 100644 index 0000000..d3c890b --- /dev/null +++ b/src/nat/gnunet-helper-nat-server.c @@ -0,0 +1,617 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/nat/gnunet-helper-nat-server.c + * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) + * This code will work under GNU/Linux only (or maybe BSDs, but never W32) + * @author Christian Grothoff + * + * This program will send ONE ICMP message every 500 ms RAW sockets + * to a DUMMY IP address and also listens for ICMP replies. Since + * it uses RAW sockets, it must be installed SUID or run as 'root'. + * In order to keep the security risk of the resulting SUID binary + * minimal, the program ONLY opens the two RAW sockets with root + * privileges, then drops them and only then starts to process + * command line arguments. The code also does not link against + * any shared libraries (except libc) and is strictly minimal + * (except for checking for errors). The following list of people + * have reviewed this code and considered it safe since the last + * modification (if you reviewed it, please have your name added + * to the list): + * + * - Christian Grothoff + * - Nathan Evans + * - Benjamin Kuperman (22 Aug 2010) + * - Jacob Appelbaum (19 Dec 2011) + */ +#if HAVE_CONFIG_H +/* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ +#include "gnunet_config.h" +#else +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Should we print some debug output? + */ +#define VERBOSE 0 + +/** + * Must match packet ID used by gnunet-helper-nat-client.c + */ +#define PACKET_ID 256 + +/** + * Must match IP given in the client. + */ +#define DUMMY_IP "192.0.2.86" + +/** + * Port for UDP + */ +#define NAT_TRAV_PORT 22225 + +/** + * How often do we send our ICMP messages to receive replies? + */ +#define ICMP_SEND_FREQUENCY_MS 500 + +/** + * IPv4 header. + */ +struct ip_header +{ + + /** + * Version (4 bits) + Internet header length (4 bits) + */ + uint8_t vers_ihl; + + /** + * Type of service + */ + uint8_t tos; + + /** + * Total length + */ + uint16_t pkt_len; + + /** + * Identification + */ + uint16_t id; + + /** + * Flags (3 bits) + Fragment offset (13 bits) + */ + uint16_t flags_frag_offset; + + /** + * Time to live + */ + uint8_t ttl; + + /** + * Protocol + */ + uint8_t proto; + + /** + * Header checksum + */ + uint16_t checksum; + + /** + * Source address + */ + uint32_t src_ip; + + /** + * Destination address + */ + uint32_t dst_ip; +}; + +/** + * Format of ICMP packet. + */ +struct icmp_ttl_exceeded_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t unused; + + /* followed by original payload */ +}; + +struct icmp_echo_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t reserved; +}; + + +/** + * Beginning of UDP packet. + */ +struct udp_header +{ + uint16_t src_port; + + uint16_t dst_port; + + uint16_t length; + + uint16_t crc; +}; + +/** + * Socket we use to receive "fake" ICMP replies. + */ +static int icmpsock; + +/** + * Socket we use to send our ICMP requests. + */ +static int rawsock; + +/** + * Socket we use to send our UDP requests. + */ +static int udpsock; + +/** + * Target "dummy" address. + */ +static struct in_addr dummy; + + +/** + * CRC-16 for IP/ICMP headers. + * + * @param data what to calculate the CRC over + * @param bytes number of bytes in data (must be multiple of 2) + * @return the CRC 16. + */ +static uint16_t +calc_checksum (const uint16_t * data, unsigned int bytes) +{ + uint32_t sum; + unsigned int i; + + sum = 0; + for (i = 0; i < bytes / 2; i++) + sum += data[i]; + sum = (sum & 0xffff) + (sum >> 16); + sum = htons (0xffff - sum); + return sum; +} + + +/** + * Send an ICMP message to the dummy IP. + * + * @param my_ip source address (our ip address) + */ +static void +send_icmp_echo (const struct in_addr *my_ip) +{ + char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)]; + struct icmp_echo_header icmp_echo; + struct ip_header ip_pkt; + struct sockaddr_in dst; + size_t off; + int err; + + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons (PACKET_ID); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = IPDEFTTL; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = + htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + icmp_echo.type = ICMP_ECHO; + icmp_echo.code = 0; + icmp_echo.checksum = 0; + icmp_echo.reserved = 0; + icmp_echo.checksum = + htons (calc_checksum + ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header))); + memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header)); + off += sizeof (struct icmp_echo_header); + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + dst.sin_len = sizeof (struct sockaddr_in); +#endif + dst.sin_addr = dummy; + err = + sendto (rawsock, packet, off, 0, (struct sockaddr *) &dst, sizeof (dst)); + if (err < 0) + { +#if VERBOSE + fprintf (stderr, "sendto failed: %s\n", strerror (errno)); +#endif + } + else if (sizeof (packet) != err) + { + fprintf (stderr, "Error: partial send of ICMP message\n"); + } +} + + +/** + * Send a UDP message to the dummy IP. + */ +static void +send_udp () +{ + struct sockaddr_in dst; + ssize_t err; + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + dst.sin_len = sizeof (struct sockaddr_in); +#endif + dst.sin_addr = dummy; + dst.sin_port = htons (NAT_TRAV_PORT); + err = sendto (udpsock, NULL, 0, 0, (struct sockaddr *) &dst, sizeof (dst)); + if (err < 0) + { +#if VERBOSE + fprintf (stderr, "sendto failed: %s\n", strerror (errno)); +#endif + } + else if (0 != err) + { + fprintf (stderr, "Error: partial send of ICMP message\n"); + } +} + + +/** + * We've received an ICMP response. Process it. + */ +static void +process_icmp_response () +{ + char buf[65536]; + ssize_t have; + struct in_addr source_ip; + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_ttl; + struct icmp_echo_header icmp_echo; + struct udp_header udp_pkt; + size_t off; + uint16_t port; + + have = read (icmpsock, buf, sizeof (buf)); + if (-1 == have) + { + fprintf (stderr, "Error reading raw socket: %s\n", strerror (errno)); + return; + } +#if VERBOSE + fprintf (stderr, "Received message of %u bytes\n", (unsigned int) have); +#endif + if (have < + (ssize_t) (sizeof (struct ip_header) + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct ip_header))) + { + /* malformed */ + return; + } + off = 0; + memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header)); + off += sizeof (struct ip_header); + memcpy (&icmp_ttl, &buf[off], sizeof (struct icmp_ttl_exceeded_header)); + off += sizeof (struct icmp_ttl_exceeded_header); + if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code)) + { + /* different type than what we want */ + return; + } + /* skip 2nd IP header */ + memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + switch (ip_pkt.proto) + { + case IPPROTO_ICMP: + if (have != + (sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct icmp_echo_header))) + { + /* malformed */ + return; + } + /* grab ICMP ECHO content */ + memcpy (&icmp_echo, &buf[off], sizeof (struct icmp_echo_header)); + port = (uint16_t) ntohl (icmp_echo.reserved); + break; + case IPPROTO_UDP: + if (have != + (sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct udp_header))) + { + /* malformed */ + return; + } + /* grab UDP content */ + memcpy (&udp_pkt, &buf[off], sizeof (struct udp_header)); + port = ntohs (udp_pkt.length); + break; + default: + /* different type than what we want */ + return; + } + + source_ip.s_addr = ip_pkt.src_ip; + if (port == 0) + fprintf (stdout, "%s\n", + inet_ntop (AF_INET, &source_ip, buf, sizeof (buf))); + else + fprintf (stdout, "%s:%u\n", + inet_ntop (AF_INET, &source_ip, buf, sizeof (buf)), + (unsigned int) port); + fflush (stdout); +} + + +/** + * Fully initialize the raw socket. + * + * @return -1 on error, 0 on success + */ +static int +setup_raw_socket () +{ + const int one = 1; + + if (-1 == + setsockopt (rawsock, SOL_SOCKET, SO_BROADCAST, (char *) &one, sizeof (one))) + { + fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); + return -1; + } + if (-1 == + setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &one, sizeof (one))) + { + fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); + return -1; + } + return 0; +} + + +/** + * Create a UDP socket for writing. + * + * @param my_ip source address (our ip address) + * @return -1 on error + */ +static int +make_udp_socket (const struct in_addr *my_ip) +{ + int ret; + struct sockaddr_in addr; + + ret = socket (AF_INET, SOCK_DGRAM, 0); + if (-1 == ret) + { + fprintf (stderr, "Error opening UDP socket: %s\n", strerror (errno)); + return -1; + } + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + addr.sin_len = sizeof (struct sockaddr_in); +#endif + addr.sin_addr = *my_ip; + addr.sin_port = htons (NAT_TRAV_PORT); + + if (0 != bind (ret, &addr, sizeof (addr))) + { + fprintf (stderr, "Error binding UDP socket to port %u: %s\n", NAT_TRAV_PORT, + strerror (errno)); + (void) close (ret); + return -1; + } + return ret; +} + + +int +main (int argc, char *const *argv) +{ + struct in_addr external; + fd_set rs; + struct timeval tv; + uid_t uid; + unsigned int alt; + int icmp_eno; + int raw_eno; + int global_ret; + + /* Create an ICMP raw socket for reading (we'll check errors later) */ + icmpsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); + icmp_eno = errno; + + /* Create an (ICMP) raw socket for writing (we'll check errors later) */ + rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); + raw_eno = errno; + udpsock = -1; + + /* drop root rights */ + uid = getuid (); +#ifdef HAVE_SETRESUID + if (0 != setresuid (uid, uid, uid)) + { + fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); + global_ret = 1; + goto error_exit; + } +#else + if (0 != (setuid (uid) | seteuid (uid))) + { + fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); + global_ret = 2; + goto error_exit; + } +#endif + + /* Now that we run without root rights, we can do error checking... */ + if (2 != argc) + { + fprintf (stderr, + "This program must be started with our (internal NAT) IP as the only argument.\n"); + global_ret = 3; + goto error_exit; + } + if (1 != inet_pton (AF_INET, argv[1], &external)) + { + fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno)); + global_ret = 4; + goto error_exit; + } + if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) + { + fprintf (stderr, "Internal error converting dummy IP to binary.\n"); + global_ret = 5; + goto error_exit; + } + + /* error checking icmpsock */ + if (-1 == icmpsock) + { + fprintf (stderr, "Error opening RAW socket: %s\n", strerror (icmp_eno)); + global_ret = 6; + goto error_exit; + } + if (icmpsock >= FD_SETSIZE) + { + /* this could happen if we were started with a large number of already-open + file descriptors... */ + fprintf (stderr, "Socket number too large (%d > %u)\n", icmpsock, + (unsigned int) FD_SETSIZE); + global_ret = 7; + goto error_exit; + } + + /* error checking rawsock */ + if (-1 == rawsock) + { + fprintf (stderr, "Error opening RAW socket: %s\n", strerror (raw_eno)); + global_ret = 8; + goto error_exit; + } + /* no need to check 'rawsock' against FD_SETSIZE as it is never used + with 'select' */ + + if (0 != setup_raw_socket ()) + { + global_ret = 9; + goto error_exit; + } + + if (-1 == (udpsock = make_udp_socket (&external))) + { + global_ret = 10; + goto error_exit; + } + + alt = 0; + while (1) + { + FD_ZERO (&rs); + FD_SET (icmpsock, &rs); + tv.tv_sec = 0; + tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; + if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv)) + { + if (errno == EINTR) + continue; + fprintf (stderr, "select failed: %s\n", strerror (errno)); + break; + } + if (1 == getppid ()) /* Check the parent process id, if 1 the parent has died, so we should die too */ + break; + if (FD_ISSET (icmpsock, &rs)) + process_icmp_response (); + if (0 == (++alt % 2)) + send_icmp_echo (&external); + else + send_udp (); + } + + /* select failed (internal error or OS out of resources) */ + global_ret = 11; +error_exit: + if (-1 != icmpsock) + (void) close (icmpsock); + if (-1 != rawsock) + (void) close (rawsock); + if (-1 != udpsock) + (void) close (udpsock); + return global_ret; +} + + +/* end of gnunet-helper-nat-server.c */ diff --git a/src/nat/gnunet-nat-server.c b/src/nat/gnunet-nat-server.c new file mode 100644 index 0000000..0336ecc --- /dev/null +++ b/src/nat/gnunet-nat-server.c @@ -0,0 +1,335 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/nat/gnunet-nat-server.c + * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_nat_lib.h" +#include "gnunet_protocols.h" +#include "nat.h" + + +/** + * Our server. + */ +static struct GNUNET_SERVER_Handle *server; + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + + +/** + * Try contacting the peer using autonomous + * NAT traveral method. + * + * @param dst_ipv4 IPv4 address to send the fake ICMP message + * @param dport destination port to include in ICMP message + * @param is_tcp mark for TCP (GNUNET_YES) or UDP (GNUNET_NO) + */ +static void +try_anat (uint32_t dst_ipv4, uint16_t dport, int is_tcp) +{ + struct GNUNET_NAT_Handle *h; + struct sockaddr_in sa; + +#if DEBUG_NAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking for connection reversal with %x and code %u\n", + (unsigned int) dst_ipv4, (unsigned int) dport); +#endif + h = GNUNET_NAT_register (cfg, is_tcp, dport, 0, NULL, NULL, NULL, NULL, NULL); + memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_addr.s_addr = dst_ipv4; + GNUNET_NAT_run_client (h, &sa); + GNUNET_NAT_unregister (h); +} + + +/** + * Closure for 'tcp_send'. + */ +struct TcpContext +{ + /** + * TCP socket. + */ + struct GNUNET_NETWORK_Handle *s; + + /** + * Data to transmit. + */ + uint16_t data; +}; + + +/** + * Task called by the scheduler once we can do the TCP send + * (or once we failed to connect...). + * + * @param cls the 'struct TcpContext' + * @param tc scheduler context + */ +static void +tcp_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TcpContext *ctx = cls; + + if ((NULL != tc->write_ready) && + (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s))) + { + if (-1 == + GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data))) + { +#if DEBUG_NAT + GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send"); +#endif + } + GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR); + } + GNUNET_NETWORK_socket_close (ctx->s); + GNUNET_free (ctx); +} + + +/** + * Try to send 'data' to the + * IP 'dst_ipv4' at port 'dport' via TCP. + * + * @param dst_ipv4 target IP + * @param dport target port + * @param data data to send + */ +static void +try_send_tcp (uint32_t dst_ipv4, uint16_t dport, uint16_t data) +{ + struct GNUNET_NETWORK_Handle *s; + struct sockaddr_in sa; + struct TcpContext *ctx; + + s = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); + if (NULL == s) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket"); + return; + } + memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_addr.s_addr = dst_ipv4; + sa.sin_port = htons (dport); +#if DEBUG_NAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TCP message to `%s'\n", + GNUNET_a2s ((struct sockaddr *) &sa, sizeof (sa))); +#endif + if ((GNUNET_OK != + GNUNET_NETWORK_socket_connect (s, (const struct sockaddr *) &sa, + sizeof (sa))) && (errno != EINPROGRESS)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect"); + GNUNET_NETWORK_socket_close (s); + return; + } + ctx = GNUNET_malloc (sizeof (struct TcpContext)); + ctx->s = s; + ctx->data = data; + GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS, s, &tcp_send, ctx); +} + + +/** + * Try to send 'data' to the + * IP 'dst_ipv4' at port 'dport' via UDP. + * + * @param dst_ipv4 target IP + * @param dport target port + * @param data data to send + */ +static void +try_send_udp (uint32_t dst_ipv4, uint16_t dport, uint16_t data) +{ + struct GNUNET_NETWORK_Handle *s; + struct sockaddr_in sa; + + s = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); + if (NULL == s) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket"); + return; + } + memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_addr.s_addr = dst_ipv4; + sa.sin_port = htons (dport); +#if DEBUG_NAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending UDP packet to `%s'\n", + GNUNET_a2s ((struct sockaddr *) &sa, sizeof (sa))); +#endif + if (-1 == + GNUNET_NETWORK_socket_sendto (s, &data, sizeof (data), + (const struct sockaddr *) &sa, sizeof (sa))) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto"); + GNUNET_NETWORK_socket_close (s); +} + + +/** + * We've received a request to probe a NAT + * traversal. Do it. + * + * @param cls unused + * @param client handle to client (we always close) + * @param msg message with details about what to test + */ +static void +test (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg) +{ + const struct GNUNET_NAT_TestMessage *tm; + uint16_t dport; + +#if DEBUG_NAT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received test request\n"); +#endif + tm = (const struct GNUNET_NAT_TestMessage *) msg; + dport = ntohs (tm->dport); + if (0 == dport) + try_anat (tm->dst_ipv4, ntohs (tm->data), (int) ntohl (tm->is_tcp)); + else if (GNUNET_YES == ntohl (tm->is_tcp)) + try_send_tcp (tm->dst_ipv4, dport, tm->data); + else + try_send_udp (tm->dst_ipv4, dport, tm->data); + GNUNET_SERVER_receive_done (client, GNUNET_NO); +} + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc scheduler context + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_SERVER_destroy (server); + server = NULL; +} + + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST, + sizeof (struct GNUNET_NAT_TestMessage)}, + {NULL, NULL, 0, 0} + }; + unsigned int port; + struct sockaddr_in in4; + struct sockaddr_in6 in6; + + socklen_t slen[] = { + sizeof (in4), + sizeof (in6), + 0 + }; + struct sockaddr *sa[] = { + (struct sockaddr *) &in4, + (struct sockaddr *) &in6, + NULL + }; + + cfg = c; + if ((args[0] == NULL) || (1 != SSCANF (args[0], "%u", &port)) || (0 == port) + || (65536 <= port)) + { + FPRINTF (stderr, + _ + ("Please pass valid port number as the first argument! (got `%s')\n"), + args[0]); + return; + } + memset (&in4, 0, sizeof (in4)); + memset (&in6, 0, sizeof (in6)); + in4.sin_family = AF_INET; + in4.sin_port = htons ((uint16_t) port); + in6.sin6_family = AF_INET6; + in6.sin6_port = htons ((uint16_t) port); +#if HAVE_SOCKADDR_IN_SIN_LEN + in4.sin_len = sizeof (in4); + in6.sin6_len = sizeof (in6); +#endif + server = + GNUNET_SERVER_create (NULL, NULL, (struct sockaddr * const *) sa, slen, + GNUNET_TIME_UNIT_SECONDS, GNUNET_YES); + GNUNET_SERVER_add_handlers (server, handlers); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); +} + + +/** + * Main function of gnunet-nat-server. + * + * @param argc number of command-line arguments + * @param argv command line + * @return 0 on success, -1 on error + */ +int +main (int argc, char *const argv[]) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, argv, "gnunet-nat-server [options] PORT", + _("GNUnet NAT traversal test helper daemon"), options, + &run, NULL)) + return 1; + return 0; +} + + +/* end of gnunet-nat-server.c */ diff --git a/src/nat/nat.c b/src/nat/nat.c new file mode 100644 index 0000000..5117f5d --- /dev/null +++ b/src/nat/nat.c @@ -0,0 +1,1411 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file nat/nat.c + * @brief Library handling UPnP and NAT-PMP port forwarding and + * external IP address retrieval + * @author Milan Bouchet-Valat + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_resolver_service.h" +#include "gnunet_nat_lib.h" +#include "nat.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) + +/** + * How often do we scan for changes in our IP address from our local + * interfaces? + */ +#define IFC_SCAN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +/** + * How often do we scan for changes in how our hostname resolves? + */ +#define HOSTNAME_DNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 20) + + +/** + * How often do we scan for changes in how our external (dyndns) hostname resolves? + */ +#define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7) + +/** + * How long until we give up trying to resolve our own hostname? + */ +#define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + + +/** + * Where did the given local address originate from? + * To be used for debugging as well as in the future + * to remove all addresses from a certain source when + * we reevaluate the source. + */ +enum LocalAddressSource +{ + /** + * Address was obtained by DNS resolution of the external hostname + * given in the configuration (i.e. hole-punched DynDNS setup). + */ + LAL_EXTERNAL_IP, + + /** + * Address was obtained by looking up our own hostname in DNS. + */ + LAL_HOSTNAME_DNS, + + /** + * Address was obtained by scanning our hosts's network interfaces + * and taking their address (no DNS involved). + */ + LAL_INTERFACE_ADDRESS, + + /** + * Addresses we were explicitly bound to. + */ + LAL_BINDTO_ADDRESS, + + /** + * Addresses from UPnP or PMP + */ + LAL_UPNP, + + /** + * End of the list. + */ + LAL_END +}; + + +/** + * List of local addresses that we currently deem valid. Actual + * struct is followed by the 'struct sockaddr'. Note that the code + * intentionally makes no attempt to ensure that a particular address + * is only listed once (especially since it may come from different + * sources, and the source is an "internal" construct). + */ +struct LocalAddressList +{ + /** + * This is a linked list. + */ + struct LocalAddressList *next; + + /** + * Previous entry. + */ + struct LocalAddressList *prev; + + /** + * Number of bytes of address that follow. + */ + socklen_t addrlen; + + /** + * Origin of the local address. + */ + enum LocalAddressSource source; +}; + + +/** + * Handle for miniupnp-based NAT traversal actions. + */ +struct MiniList +{ + + /** + * Doubly-linked list. + */ + struct MiniList *next; + + /** + * Doubly-linked list. + */ + struct MiniList *prev; + + /** + * Handle to mini-action. + */ + struct GNUNET_NAT_MiniHandle *mini; + + /** + * Local port number that was mapped. + */ + uint16_t port; + +}; + + +/** + * Handle for active NAT registrations. + */ +struct GNUNET_NAT_Handle +{ + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Function to call when we learn about a new address. + */ + GNUNET_NAT_AddressCallback address_callback; + + /** + * Function to call when we notice another peer asking for + * connection reversal. + */ + GNUNET_NAT_ReversalCallback reversal_callback; + + /** + * Closure for 'callback'. + */ + void *callback_cls; + + /** + * Handle for (DYN)DNS lookup of our external IP. + */ + struct GNUNET_RESOLVER_RequestHandle *ext_dns; + + /** + * Handle for request of hostname resolution, non-NULL if pending. + */ + struct GNUNET_RESOLVER_RequestHandle *hostname_dns; + + /** + * stdout pipe handle for the gnunet-helper-nat-server process + */ + struct GNUNET_DISK_PipeHandle *server_stdout; + + /** + * stdout file handle (for reading) for the gnunet-helper-nat-server process + */ + const struct GNUNET_DISK_FileHandle *server_stdout_handle; + + /** + * Linked list of currently valid addresses (head). + */ + struct LocalAddressList *lal_head; + + /** + * Linked list of currently valid addresses (tail). + */ + struct LocalAddressList *lal_tail; + + /** + * How long do we wait for restarting a crashed gnunet-helper-nat-server? + */ + struct GNUNET_TIME_Relative server_retry_delay; + + /** + * ID of select gnunet-helper-nat-server stdout read task + */ + GNUNET_SCHEDULER_TaskIdentifier server_read_task; + + /** + * ID of interface IP-scan task + */ + GNUNET_SCHEDULER_TaskIdentifier ifc_task; + + /** + * ID of hostname DNS lookup task + */ + GNUNET_SCHEDULER_TaskIdentifier hostname_task; + + /** + * ID of DynDNS lookup task + */ + GNUNET_SCHEDULER_TaskIdentifier dns_task; + + /** + * ID of task to add addresses from bind. + */ + GNUNET_SCHEDULER_TaskIdentifier bind_task; + + /** + * How often do we scan for changes in our IP address from our local + * interfaces? + */ + struct GNUNET_TIME_Relative ifc_scan_frequency; + + /** + * How often do we scan for changes in how our hostname resolves? + */ + struct GNUNET_TIME_Relative hostname_dns_frequency; + + /** + * How often do we scan for changes in how our external (dyndns) hostname resolves? + */ + struct GNUNET_TIME_Relative dyndns_frequency; + + /** + * The process id of the server process (if behind NAT) + */ + struct GNUNET_OS_Process *server_proc; + + /** + * LAN address as passed by the caller (array). + */ + struct sockaddr **local_addrs; + + /** + * Length of the 'local_addrs'. + */ + socklen_t *local_addrlens; + + /** + * List of handles for UPnP-traversal, one per local port (if + * not IPv6-only). + */ + struct MiniList *mini_head; + + /** + * List of handles for UPnP-traversal, one per local port (if + * not IPv6-only). + */ + struct MiniList *mini_tail; + + /** + * Number of entries in 'local_addrs' array. + */ + unsigned int num_local_addrs; + + /** + * Our external address (according to config, UPnP may disagree...), + * in dotted decimal notation, IPv4-only. Or NULL if not known. + */ + char *external_address; + + /** + * Presumably our internal address (according to config) + */ + char *internal_address; + + /** + * Is this transport configured to be behind a NAT? + */ + int behind_nat; + + /** + * Has the NAT been punched? (according to config) + */ + int nat_punched; + + /** + * Is this transport configured to allow connections to NAT'd peers? + */ + int enable_nat_client; + + /** + * Should we run the gnunet-helper-nat-server? + */ + int enable_nat_server; + + /** + * Are we allowed to try UPnP/PMP for NAT traversal? + */ + int enable_upnp; + + /** + * Should we use local addresses (loopback)? (according to config) + */ + int use_localaddresses; + + /** + * Should we return local addresses to clients + */ + int return_localaddress; + + /** + * Should we do a DNS lookup of our hostname to find out our own IP? + */ + int use_hostname; + + /** + * Is using IPv6 disabled? + */ + int disable_ipv6; + + /** + * Is this TCP or UDP? + */ + int is_tcp; + + /** + * Port we advertise to the outside. + */ + uint16_t adv_port; + +}; + + +/** + * Try to start the gnunet-helper-nat-server (if it is not + * already running). + * + * @param h handle to NAT + */ +static void +start_gnunet_nat_server (struct GNUNET_NAT_Handle *h); + + +/** + * Remove all addresses from the list of 'local' addresses + * that originated from the given source. + * + * @param h handle to NAT + * @param src source that identifies addresses to remove + */ +static void +remove_from_address_list_by_source (struct GNUNET_NAT_Handle *h, + enum LocalAddressSource src) +{ + struct LocalAddressList *pos; + struct LocalAddressList *next; + + next = h->lal_head; + while (NULL != (pos = next)) + { + next = pos->next; + if (pos->source != src) + continue; + GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, pos); + if (NULL != h->address_callback) + h->address_callback (h->callback_cls, GNUNET_NO, + (const struct sockaddr *) &pos[1], pos->addrlen); + GNUNET_free (pos); + } +} + + +/** + * Add the given address to the list of 'local' addresses, thereby + * making it a 'legal' address for this peer to have. + * + * @param h handle to NAT + * @param src where did the local address originate from? + * @param arg the address, some 'struct sockaddr' + * @param arg_size number of bytes in arg + */ +static void +add_to_address_list_as_is (struct GNUNET_NAT_Handle *h, + enum LocalAddressSource src, + const struct sockaddr *arg, socklen_t arg_size) +{ + struct LocalAddressList *lal; + + lal = GNUNET_malloc (sizeof (struct LocalAddressList) + arg_size); + memcpy (&lal[1], arg, arg_size); + lal->addrlen = arg_size; + lal->source = src; + GNUNET_CONTAINER_DLL_insert (h->lal_head, h->lal_tail, lal); +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address `%s' from source %d\n", + GNUNET_a2s (arg, arg_size), src); +#endif + if (NULL != h->address_callback) + h->address_callback (h->callback_cls, GNUNET_YES, arg, arg_size); +} + + +/** + * Add the given address to the list of 'local' addresses, thereby + * making it a 'legal' address for this peer to have. Set the + * port number in the process to the advertised port and possibly + * also to zero (if we have the gnunet-helper-nat-server). + * + * @param h handle to NAT + * @param src where did the local address originate from? + * @param arg the address, some 'struct sockaddr' + * @param arg_size number of bytes in arg + */ +static void +add_to_address_list (struct GNUNET_NAT_Handle *h, enum LocalAddressSource src, + const struct sockaddr *arg, socklen_t arg_size) +{ + struct sockaddr_in s4; + const struct sockaddr_in *in4; + struct sockaddr_in6 s6; + const struct sockaddr_in6 *in6; + + if (arg_size == sizeof (struct sockaddr_in)) + { + in4 = (const struct sockaddr_in *) arg; + s4 = *in4; + s4.sin_port = htons (h->adv_port); + add_to_address_list_as_is (h, src, (const struct sockaddr *) &s4, + sizeof (struct sockaddr_in)); + if (GNUNET_YES == h->enable_nat_server) + { + /* also add with PORT = 0 to indicate NAT server is enabled */ + s4.sin_port = htons (0); + add_to_address_list_as_is (h, src, (const struct sockaddr *) &s4, + sizeof (struct sockaddr_in)); + } + } + else if (arg_size == sizeof (struct sockaddr_in6)) + { + if (GNUNET_YES != h->disable_ipv6) + { + in6 = (const struct sockaddr_in6 *) arg; + s6 = *in6; + s6.sin6_port = htons (h->adv_port); + add_to_address_list_as_is (h, src, (const struct sockaddr *) &s6, + sizeof (struct sockaddr_in6)); + } + } + else + { + GNUNET_assert (0); + } +} + + +/** + * Add the given IP address to the list of 'local' addresses, thereby + * making it a 'legal' address for this peer to have. + * + * @param h handle to NAT + * @param src where did the local address originate from? + * @param addr the address, some 'struct in_addr' or 'struct in6_addr' + * @param addrlen number of bytes in addr + */ +static void +add_ip_to_address_list (struct GNUNET_NAT_Handle *h, + enum LocalAddressSource src, const void *addr, + socklen_t addrlen) +{ + struct sockaddr_in s4; + const struct in_addr *in4; + struct sockaddr_in6 s6; + const struct in6_addr *in6; + + if (addrlen == sizeof (struct in_addr)) + { + in4 = (const struct in_addr *) addr; + memset (&s4, 0, sizeof (s4)); + s4.sin_family = AF_INET; + s4.sin_port = 0; +#if HAVE_SOCKADDR_IN_SIN_LEN + s4.sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + s4.sin_addr = *in4; + add_to_address_list (h, src, (const struct sockaddr *) &s4, + sizeof (struct sockaddr_in)); + if (GNUNET_YES == h->enable_nat_server) + { + /* also add with PORT = 0 to indicate NAT server is enabled */ + s4.sin_port = htons (0); + add_to_address_list (h, src, (const struct sockaddr *) &s4, + sizeof (struct sockaddr_in)); + + } + } + else if (addrlen == sizeof (struct in6_addr)) + { + if (GNUNET_YES != h->disable_ipv6) + { + in6 = (const struct in6_addr *) addr; + memset (&s6, 0, sizeof (s6)); + s6.sin6_family = AF_INET6; + s6.sin6_port = htons (h->adv_port); +#if HAVE_SOCKADDR_IN_SIN_LEN + s6.sin6_len = (u_char) sizeof (struct sockaddr_in6); +#endif + s6.sin6_addr = *in6; + add_to_address_list (h, src, (const struct sockaddr *) &s6, + sizeof (struct sockaddr_in6)); + } + } + else + { + GNUNET_assert (0); + } +} + + +/** + * Task to do DNS lookup on our external hostname to + * get DynDNS-IP addresses. + * + * @param cls the NAT handle + * @param tc scheduler context + */ +static void +resolve_dns (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Our (external) hostname was resolved and the configuration says that + * the NAT was hole-punched. + * + * @param cls the 'struct Plugin' + * @param addr NULL on error, otherwise result of DNS lookup + * @param addrlen number of bytes in addr + */ +static void +process_external_ip (void *cls, const struct sockaddr *addr, socklen_t addrlen) +{ + struct GNUNET_NAT_Handle *h = cls; + struct in_addr dummy; + + if (addr == NULL) + { + h->ext_dns = NULL; + if (1 == inet_pton (AF_INET, h->external_address, &dummy)) + return; /* repated lookup pointless: was numeric! */ + h->dns_task = + GNUNET_SCHEDULER_add_delayed (h->dyndns_frequency, &resolve_dns, h); + return; + } + add_to_address_list (h, LAL_EXTERNAL_IP, addr, addrlen); +} + + +/** + * Task to do a lookup on our hostname for IP addresses. + * + * @param cls the NAT handle + * @param tc scheduler context + */ +static void +resolve_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Function called by the resolver for each address obtained from DNS + * for our own hostname. Add the addresses to the list of our IP + * addresses. + * + * @param cls closure + * @param addr one of the addresses of the host, NULL for the last address + * @param addrlen length of the address + */ +static void +process_hostname_ip (void *cls, const struct sockaddr *addr, socklen_t addrlen) +{ + struct GNUNET_NAT_Handle *h = cls; + + if (addr == NULL) + { + h->hostname_dns = NULL; + h->hostname_task = + GNUNET_SCHEDULER_add_delayed (h->hostname_dns_frequency, + &resolve_hostname, h); + return; + } + add_to_address_list (h, LAL_HOSTNAME_DNS, addr, addrlen); +} + + +/** + * Add the IP of our network interface to the list of + * our IP addresses. + * + * @param cls the 'struct GNUNET_NAT_Handle' + * @param name name of the interface + * @param isDefault do we think this may be our default interface + * @param addr address of the interface + * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) + * @param netmask the network mask (can be NULL for unknown or unassigned)) + * @param addrlen number of bytes in addr + * @return GNUNET_OK to continue iterating + */ +static int +process_interfaces (void *cls, const char *name, int isDefault, + const struct sockaddr *addr, + const struct sockaddr *broadcast_addr, + const struct sockaddr *netmask, socklen_t addrlen) +{ + struct GNUNET_NAT_Handle *h = cls; + const struct sockaddr_in *s4; + const struct sockaddr_in6 *s6; + const void *ip; + char buf[INET6_ADDRSTRLEN]; + + switch (addr->sa_family) + { + case AF_INET: + s4 = (struct sockaddr_in *) addr; + ip = &s4->sin_addr; + + /* Check if address is in 127.0.0.0/8 */ + uint32_t address = ntohl ((uint32_t) (s4->sin_addr.s_addr)); + uint32_t value = (address & 0xFF000000) ^ 0x7F000000; + + if ((h->return_localaddress == GNUNET_NO) && (value == 0)) + { + return GNUNET_OK; + } + if (GNUNET_YES == h->use_localaddresses) + { + add_ip_to_address_list (h, LAL_INTERFACE_ADDRESS, &s4->sin_addr, + sizeof (struct in_addr)); + } + break; + case AF_INET6: + s6 = (struct sockaddr_in6 *) addr; + if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) + { + /* skip link local addresses */ + return GNUNET_OK; + } + if ((h->return_localaddress == GNUNET_NO) && + (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr))) + { + return GNUNET_OK; + } + ip = &s6->sin6_addr; + if (GNUNET_YES == h->use_localaddresses) + { + add_ip_to_address_list (h, LAL_INTERFACE_ADDRESS, &s6->sin6_addr, + sizeof (struct in6_addr)); + } + break; + default: + GNUNET_break (0); + return GNUNET_OK; + } + if ((h->internal_address == NULL) && (h->server_proc == NULL) && + (h->server_read_task == GNUNET_SCHEDULER_NO_TASK) && + (GNUNET_YES == isDefault) && ((addr->sa_family == AF_INET) || + (addr->sa_family == AF_INET6))) + { + /* no internal address configured, but we found a "default" + * interface, try using that as our 'internal' address */ + h->internal_address = + GNUNET_strdup (inet_ntop (addr->sa_family, ip, buf, sizeof (buf))); + start_gnunet_nat_server (h); + } + return GNUNET_OK; +} + + +/** + * Task that restarts the gnunet-helper-nat-server process after a crash + * after a certain delay. + * + * @param cls the 'struct GNUNET_NAT_Handle' + * @param tc scheduler context + */ +static void +restart_nat_server (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_Handle *h = cls; + + h->server_read_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + start_gnunet_nat_server (h); +} + + +/** + * We have been notified that gnunet-helper-nat-server has written something to stdout. + * Handle the output, then reschedule this function to be called again once + * more is available. + * + * @param cls the NAT handle + * @param tc the scheduling context + */ +static void +nat_server_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_Handle *h = cls; + char mybuf[40]; + ssize_t bytes; + size_t i; + int port; + const char *port_start; + struct sockaddr_in sin_addr; + + h->server_read_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + memset (mybuf, 0, sizeof (mybuf)); + bytes = + GNUNET_DISK_file_read (h->server_stdout_handle, mybuf, sizeof (mybuf)); + if (bytes < 1) + { +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Finished reading from server stdout with code: %d\n", bytes); +#endif + if (0 != GNUNET_OS_process_kill (h->server_proc, SIGTERM)) + GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "kill"); + GNUNET_OS_process_wait (h->server_proc); + GNUNET_OS_process_close (h->server_proc); + h->server_proc = NULL; + GNUNET_DISK_pipe_close (h->server_stdout); + h->server_stdout = NULL; + h->server_stdout_handle = NULL; + /* now try to restart it */ + h->server_retry_delay = + GNUNET_TIME_relative_multiply (h->server_retry_delay, 2); + h->server_retry_delay = + GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_HOURS, + h->server_retry_delay); + h->server_read_task = + GNUNET_SCHEDULER_add_delayed (h->server_retry_delay, + &restart_nat_server, h); + return; + } + + port_start = NULL; + for (i = 0; i < sizeof (mybuf); i++) + { + if (mybuf[i] == '\n') + { + mybuf[i] = '\0'; + break; + } + if ((mybuf[i] == ':') && (i + 1 < sizeof (mybuf))) + { + mybuf[i] = '\0'; + port_start = &mybuf[i + 1]; + } + } + + /* construct socket address of sender */ + memset (&sin_addr, 0, sizeof (sin_addr)); + sin_addr.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + sin_addr.sin_len = sizeof (sin_addr); +#endif + if ((NULL == port_start) || (1 != sscanf (port_start, "%d", &port)) || + (-1 == inet_pton (AF_INET, mybuf, &sin_addr.sin_addr))) + { + /* should we restart gnunet-helper-nat-server? */ + LOG (GNUNET_ERROR_TYPE_WARNING, "nat", + _("gnunet-helper-nat-server generated malformed address `%s'\n"), + mybuf); + h->server_read_task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + h->server_stdout_handle, + &nat_server_read, h); + return; + } + sin_addr.sin_port = htons ((uint16_t) port); +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, "gnunet-helper-nat-server read: %s:%d\n", mybuf, + port); +#endif + h->reversal_callback (h->callback_cls, (const struct sockaddr *) &sin_addr, + sizeof (sin_addr)); + h->server_read_task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + h->server_stdout_handle, &nat_server_read, + h); +} + + +/** + * Try to start the gnunet-helper-nat-server (if it is not + * already running). + * + * @param h handle to NAT + */ +static void +start_gnunet_nat_server (struct GNUNET_NAT_Handle *h) +{ + if ((h->behind_nat == GNUNET_YES) && (h->enable_nat_server == GNUNET_YES) && + (h->internal_address != NULL) && + (NULL != + (h->server_stdout = + GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES)))) + { +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting `%s' at `%s'\n", + "gnunet-helper-nat-server", h->internal_address); +#endif + /* Start the server process */ + h->server_proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, h->server_stdout, + "gnunet-helper-nat-server", + "gnunet-helper-nat-server", + h->internal_address, NULL); + if (h->server_proc == NULL) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "nat", _("Failed to start %s\n"), + "gnunet-helper-nat-server"); + GNUNET_DISK_pipe_close (h->server_stdout); + h->server_stdout = NULL; + } + else + { + /* Close the write end of the read pipe */ + GNUNET_DISK_pipe_close_end (h->server_stdout, GNUNET_DISK_PIPE_END_WRITE); + h->server_stdout_handle = + GNUNET_DISK_pipe_handle (h->server_stdout, GNUNET_DISK_PIPE_END_READ); + h->server_read_task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + h->server_stdout_handle, + &nat_server_read, h); + } + } +} + + +/** + * Task to scan the local network interfaces for IP addresses. + * + * @param cls the NAT handle + * @param tc scheduler context + */ +static void +list_interfaces (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_Handle *h = cls; + + h->ifc_task = GNUNET_SCHEDULER_NO_TASK; + remove_from_address_list_by_source (h, LAL_INTERFACE_ADDRESS); + GNUNET_OS_network_interfaces_list (&process_interfaces, h); + h->ifc_task = + GNUNET_SCHEDULER_add_delayed (h->ifc_scan_frequency, &list_interfaces, h); +} + + +/** + * Task to do a lookup on our hostname for IP addresses. + * + * @param cls the NAT handle + * @param tc scheduler context + */ +static void +resolve_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_Handle *h = cls; + + h->hostname_task = GNUNET_SCHEDULER_NO_TASK; + remove_from_address_list_by_source (h, LAL_HOSTNAME_DNS); + h->hostname_dns = + GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, HOSTNAME_RESOLVE_TIMEOUT, + &process_hostname_ip, h); +} + + +/** + * Task to do DNS lookup on our external hostname to + * get DynDNS-IP addresses. + * + * @param cls the NAT handle + * @param tc scheduler context + */ +static void +resolve_dns (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_Handle *h = cls; + + h->dns_task = GNUNET_SCHEDULER_NO_TASK; + remove_from_address_list_by_source (h, LAL_EXTERNAL_IP); + h->ext_dns = + GNUNET_RESOLVER_ip_get (h->external_address, AF_INET, + GNUNET_TIME_UNIT_MINUTES, &process_external_ip, + h); +} + + +/** + * Add or remove UPnP-mapped addresses. + * + * @param cls the GNUNET_NAT_Handle + * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean + * the previous (now invalid) one + * @param addr either the previous or the new public IP address + * @param addrlen actual lenght of the address + */ +static void +upnp_add (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + struct GNUNET_NAT_Handle *h = cls; + struct LocalAddressList *pos; + struct LocalAddressList *next; + + if (GNUNET_YES == add_remove) + { + add_to_address_list (h, LAL_UPNP, addr, addrlen); + return; + } + /* remove address */ + next = h->lal_head; + while (NULL != (pos = next)) + { + next = pos->next; + if ((pos->source != LAL_UPNP) || (pos->addrlen != addrlen) || + (0 != memcmp (&pos[1], addr, addrlen))) + continue; + GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, pos); + if (NULL != h->address_callback) + h->address_callback (h->callback_cls, GNUNET_NO, + (const struct sockaddr *) &pos[1], pos->addrlen); + GNUNET_free (pos); + return; /* only remove once */ + } + /* asked to remove address that does not exist */ + GNUNET_break (0); +} + + +/** + * Try to add a port mapping using UPnP. + * + * @param h overall NAT handle + * @param port port to map with UPnP + */ +static void +add_minis (struct GNUNET_NAT_Handle *h, uint16_t port) +{ + struct MiniList *ml; + + ml = h->mini_head; + while (NULL != ml) + { + if (port == ml->port) + return; /* already got this port */ + ml = ml->next; + } + ml = GNUNET_malloc (sizeof (struct MiniList)); + ml->port = port; + ml->mini = GNUNET_NAT_mini_map_start (port, h->is_tcp, &upnp_add, h); + GNUNET_CONTAINER_DLL_insert (h->mini_head, h->mini_tail, ml); +} + + +/** + * Task to add addresses from original bind to set of valid addrs. + * + * @param cls the NAT handle + * @param tc scheduler context + */ +static void +add_from_bind (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static struct in6_addr any = IN6ADDR_ANY_INIT; + struct GNUNET_NAT_Handle *h = cls; + unsigned int i; + struct sockaddr *sa; + const struct sockaddr_in *v4; + + h->bind_task = GNUNET_SCHEDULER_NO_TASK; + for (i = 0; i < h->num_local_addrs; i++) + { + sa = h->local_addrs[i]; + switch (sa->sa_family) + { + case AF_INET: + if (sizeof (struct sockaddr_in) != h->local_addrlens[i]) + { + GNUNET_break (0); + break; + } + v4 = (const struct sockaddr_in *) sa; + if (0 != v4->sin_addr.s_addr) + add_to_address_list (h, LAL_BINDTO_ADDRESS, sa, + sizeof (struct sockaddr_in)); + if (h->enable_upnp) + add_minis (h, ntohs (v4->sin_port)); + break; + case AF_INET6: + if (sizeof (struct sockaddr_in6) != h->local_addrlens[i]) + { + GNUNET_break (0); + break; + } + if (0 != + memcmp (&((const struct sockaddr_in6 *) sa)->sin6_addr, &any, + sizeof (struct in6_addr))) + add_to_address_list (h, LAL_BINDTO_ADDRESS, sa, + sizeof (struct sockaddr_in6)); + break; + default: + break; + } + } +} + + + +/** + * Attempt to enable port redirection and detect public IP address contacting + * UPnP or NAT-PMP routers on the local network. Use addr to specify to which + * of the local host's addresses should the external port be mapped. The port + * is taken from the corresponding sockaddr_in[6] field. + * + * @param cfg configuration to use + * @param is_tcp GNUNET_YES for TCP, GNUNET_NO for UDP + * @param adv_port advertised port (port we are either bound to or that our OS + * locally performs redirection from to our bound port). + * @param num_addrs number of addresses in 'addrs' + * @param addrs the local addresses packets should be redirected to + * @param addrlens actual lengths of the addresses + * @param address_callback function to call everytime the public IP address changes + * @param reversal_callback function to call if someone wants connection reversal from us + * @param callback_cls closure for callbacks + * @return NULL on error, otherwise handle that can be used to unregister + */ +struct GNUNET_NAT_Handle * +GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, int is_tcp, + uint16_t adv_port, unsigned int num_addrs, + const struct sockaddr **addrs, const socklen_t * addrlens, + GNUNET_NAT_AddressCallback address_callback, + GNUNET_NAT_ReversalCallback reversal_callback, + void *callback_cls) +{ + struct GNUNET_NAT_Handle *h; + struct in_addr in_addr; + unsigned int i; + +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Registered with NAT service at port %u with %u IP bound local addresses\n", + (unsigned int) adv_port, num_addrs); +#endif + h = GNUNET_malloc (sizeof (struct GNUNET_NAT_Handle)); + h->server_retry_delay = GNUNET_TIME_UNIT_SECONDS; + h->cfg = cfg; + h->is_tcp = is_tcp; + h->address_callback = address_callback; + h->reversal_callback = reversal_callback; + h->callback_cls = callback_cls; + h->num_local_addrs = num_addrs; + h->adv_port = adv_port; + if (num_addrs != 0) + { + h->local_addrs = GNUNET_malloc (num_addrs * sizeof (struct sockaddr *)); + h->local_addrlens = GNUNET_malloc (num_addrs * sizeof (socklen_t)); + for (i = 0; i < num_addrs; i++) + { + GNUNET_assert (addrlens[i] > 0); + GNUNET_assert (addrs[i] != NULL); + h->local_addrlens[i] = addrlens[i]; + h->local_addrs[i] = GNUNET_malloc (addrlens[i]); + memcpy (h->local_addrs[i], addrs[i], addrlens[i]); + } + } + h->bind_task = GNUNET_SCHEDULER_add_now (&add_from_bind, h); + if (GNUNET_OK == + GNUNET_CONFIGURATION_have_value (cfg, "nat", "INTERNAL_ADDRESS")) + { + (void) GNUNET_CONFIGURATION_get_value_string (cfg, "nat", + "INTERNAL_ADDRESS", + &h->internal_address); + } + if ((h->internal_address != NULL) && + (inet_pton (AF_INET, h->internal_address, &in_addr) != 1)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "nat", + _("Malformed %s `%s' given in configuration!\n"), "INTERNAL_ADDRESS", + h->internal_address); + GNUNET_free (h->internal_address); + h->internal_address = NULL; + } + + if (GNUNET_OK == + GNUNET_CONFIGURATION_have_value (cfg, "nat", "EXTERNAL_ADDRESS")) + { + (void) GNUNET_CONFIGURATION_get_value_string (cfg, "nat", + "EXTERNAL_ADDRESS", + &h->external_address); + } + h->behind_nat = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "BEHIND_NAT"); + h->nat_punched = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "PUNCHED_NAT"); + h->enable_nat_client = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_ICMP_CLIENT"); + h->enable_nat_server = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_ICMP_SERVER"); + h->enable_upnp = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_UPNP"); + h->use_localaddresses = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "USE_LOCALADDR"); + h->return_localaddress = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", + "RETURN_LOCAL_ADDRESSES"); + + h->use_hostname = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "USE_HOSTNAME"); + h->disable_ipv6 = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "DISABLEV6"); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "DYNDNS_FREQUENCY", + &h->dyndns_frequency)) + h->dyndns_frequency = DYNDNS_FREQUENCY; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "IFC_SCAN_FREQUENCY", + &h->ifc_scan_frequency)) + h->ifc_scan_frequency = IFC_SCAN_FREQUENCY; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "HOSTNAME_DNS_FREQUENCY", + &h->hostname_dns_frequency)) + h->hostname_dns_frequency = HOSTNAME_DNS_FREQUENCY; + + if (NULL == reversal_callback) + h->enable_nat_server = GNUNET_NO; + + /* Check if NAT was hole-punched */ + if ((NULL != h->address_callback) && (h->external_address != NULL) && + (h->nat_punched == GNUNET_YES)) + { + h->dns_task = GNUNET_SCHEDULER_add_now (&resolve_dns, h); + h->enable_nat_server = GNUNET_NO; + h->enable_upnp = GNUNET_NO; + } + + /* Test for SUID binaries */ + if ((h->behind_nat == GNUNET_YES) && (GNUNET_YES == h->enable_nat_server) && + (GNUNET_YES != + GNUNET_OS_check_helper_binary ("gnunet-helper-nat-server"))) + { + h->enable_nat_server = GNUNET_NO; + LOG (GNUNET_ERROR_TYPE_WARNING, + _ + ("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), + "gnunet-helper-nat-server"); + } + if ((GNUNET_YES == h->enable_nat_client) && + (GNUNET_YES != + GNUNET_OS_check_helper_binary ("gnunet-helper-nat-client"))) + { + h->enable_nat_client = GNUNET_NO; + LOG (GNUNET_ERROR_TYPE_WARNING, + _ + ("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), + "gnunet-helper-nat-client"); + } + + start_gnunet_nat_server (h); + + /* FIXME: add support for UPnP, etc */ + + if (NULL != h->address_callback) + { + h->ifc_task = GNUNET_SCHEDULER_add_now (&list_interfaces, h); + if (GNUNET_YES == h->use_hostname) + h->hostname_task = GNUNET_SCHEDULER_add_now (&resolve_hostname, h); + } + + return h; +} + + +/** + * Stop port redirection and public IP address detection for the given handle. + * This frees the handle, after having sent the needed commands to close open ports. + * + * @param h the handle to stop + */ +void +GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h) +{ + unsigned int i; + struct LocalAddressList *lal; + struct MiniList *ml; + + while (NULL != (ml = h->mini_head)) + { + GNUNET_CONTAINER_DLL_remove (h->mini_head, h->mini_tail, ml); + if (NULL != ml->mini) + GNUNET_NAT_mini_map_stop (ml->mini); + GNUNET_free (ml); + } + if (h->ext_dns != NULL) + { + GNUNET_RESOLVER_request_cancel (h->ext_dns); + h->ext_dns = NULL; + } + if (NULL != h->hostname_dns) + { + GNUNET_RESOLVER_request_cancel (h->hostname_dns); + h->hostname_dns = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != h->server_read_task) + { + GNUNET_SCHEDULER_cancel (h->server_read_task); + h->server_read_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != h->bind_task) + { + GNUNET_SCHEDULER_cancel (h->bind_task); + h->bind_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != h->ifc_task) + { + GNUNET_SCHEDULER_cancel (h->ifc_task); + h->ifc_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != h->hostname_task) + { + GNUNET_SCHEDULER_cancel (h->hostname_task); + h->hostname_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != h->dns_task) + { + GNUNET_SCHEDULER_cancel (h->dns_task); + h->dns_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != h->server_proc) + { + if (0 != GNUNET_OS_process_kill (h->server_proc, SIGTERM)) + GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "kill"); + GNUNET_OS_process_wait (h->server_proc); + GNUNET_OS_process_close (h->server_proc); + h->server_proc = NULL; + GNUNET_DISK_pipe_close (h->server_stdout); + h->server_stdout = NULL; + h->server_stdout_handle = NULL; + } + if (NULL != h->server_stdout) + { + GNUNET_DISK_pipe_close (h->server_stdout); + h->server_stdout = NULL; + h->server_stdout_handle = NULL; + } + while (NULL != (lal = h->lal_head)) + { + GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, lal); + if (NULL != h->address_callback) + h->address_callback (h->callback_cls, GNUNET_NO, + (const struct sockaddr *) &lal[1], lal->addrlen); + GNUNET_free (lal); + } + for (i = 0; i < h->num_local_addrs; i++) + GNUNET_free (h->local_addrs[i]); + GNUNET_free_non_null (h->local_addrs); + GNUNET_free_non_null (h->local_addrlens); + GNUNET_free_non_null (h->external_address); + GNUNET_free_non_null (h->internal_address); + GNUNET_free (h); +} + + +/** + * We learned about a peer (possibly behind NAT) so run the + * gnunet-helper-nat-client to send dummy ICMP responses to cause + * that peer to connect to us (connection reversal). + * + * @param h NAT handle for us (largely used for configuration) + * @param sa the address of the peer (IPv4-only) + */ +void +GNUNET_NAT_run_client (struct GNUNET_NAT_Handle *h, + const struct sockaddr_in *sa) +{ + char inet4[INET_ADDRSTRLEN]; + char port_as_string[6]; + struct GNUNET_OS_Process *proc; + + if (GNUNET_YES != h->enable_nat_client) + return; /* not permitted / possible */ + + if (h->internal_address == NULL) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "nat", + _ + ("Internal IP address not known, cannot use ICMP NAT traversal method\n")); + return; + } + GNUNET_assert (sa->sin_family == AF_INET); + if (NULL == inet_ntop (AF_INET, &sa->sin_addr, inet4, INET_ADDRSTRLEN)) + { + GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "inet_ntop"); + return; + } + GNUNET_snprintf (port_as_string, sizeof (port_as_string), "%d", h->adv_port); +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, + _("Running gnunet-helper-nat-client %s %s %u\n"), h->internal_address, + inet4, (unsigned int) h->adv_port); +#endif + proc = + GNUNET_OS_start_process (GNUNET_NO, + NULL, NULL, "gnunet-helper-nat-client", + "gnunet-helper-nat-client", h->internal_address, + inet4, port_as_string, NULL); + if (NULL == proc) + return; + /* we know that the gnunet-helper-nat-client will terminate virtually + * instantly */ + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); +} + + +/** + * Test if the given address is (currently) a plausible IP address for this peer. + * + * @param h the handle returned by register + * @param addr IP address to test (IPv4 or IPv6) + * @param addrlen number of bytes in addr + * @return GNUNET_YES if the address is plausible, + * GNUNET_NO if the address is not plausible, + * GNUNET_SYSERR if the address is malformed + */ +int +GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *h, const void *addr, + socklen_t addrlen) +{ + struct LocalAddressList *pos; + const struct sockaddr_in *in4; + const struct sockaddr_in6 *in6; + + if ((addrlen != sizeof (struct in_addr)) && + (addrlen != sizeof (struct in6_addr))) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + pos = h->lal_head; + while (NULL != pos) + { + if (pos->addrlen == sizeof (struct sockaddr_in)) + { + in4 = (struct sockaddr_in *) &pos[1]; + if ((addrlen == sizeof (struct in_addr)) && + (0 == memcmp (&in4->sin_addr, addr, sizeof (struct in_addr)))) + return GNUNET_YES; + } + else if (pos->addrlen == sizeof (struct sockaddr_in6)) + { + in6 = (struct sockaddr_in6 *) &pos[1]; + if ((addrlen == sizeof (struct in6_addr)) && + (0 == memcmp (&in6->sin6_addr, addr, sizeof (struct in6_addr)))) + return GNUNET_YES; + } + else + { + GNUNET_assert (0); + } + pos = pos->next; + } + LOG (GNUNET_ERROR_TYPE_WARNING, + "Asked to validate one of my addresses and validation failed!\n"); + return GNUNET_NO; +} + + +/* end of nat.c */ diff --git a/src/nat/nat.conf b/src/nat/nat.conf new file mode 100644 index 0000000..e446122 --- /dev/null +++ b/src/nat/nat.conf @@ -0,0 +1,54 @@ +[nat] +# Are we behind NAT? +BEHIND_NAT = NO + +# Is the NAT hole-punched? +PUNCHED_NAT = NO + +# Enable UPNP by default? +ENABLE_UPNP = NO + +# Use addresses from the local network interfaces (inluding loopback, but also others) +USE_LOCALADDR = YES + +# Use address obtained from a DNS lookup of our hostname +USE_HOSTNAME = NO + +# External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) +# normal interface IP address for non-NATed peers; +# possibly auto-detected (using UPnP) if possible if not specified +# EXTERNAL_ADDRESS = + +# Should we use ICMP-based NAT traversal to try connect to NATed peers +# or, if we are behind NAT, to allow connections to us? +ENABLE_ICMP_CLIENT = NO +ENABLE_ICMP_SERVER = NO + +# IP address of the interface connected to the NAT box; IPv4 dotted-decimal ONLY; +# normal interface IP address for non-NATed peers; +# likely auto-detected (via interface list) if not specified (!) +# INTERNAL_ADDRESS = + +# Disable IPv6 support +DISABLEV6 = NO + +# Do we use addresses from localhost address ranges? (::1, 127.0.0.0/8) +RETURN_LOCAL_ADDRESSES = NO + +# How often do we query the DNS resolver +# for our hostname (to get our own IP), in ms +HOSTNAME_DNS_FREQUENCY = 1200000 + +# How often do we iterate over our +# network interfaces to check for changes +# in our IP address? in ms +IFC_SCAN_FREQUENCY = 3000000 + +# How often do we query the DNS resolver +# for our hostname (to get our own IP), in ms +DYNDNS_FREQUENCY = 140000 + +[gnunet-nat-server] +HOSTNAME = gnunet.org +PORT = 5724 + diff --git a/src/nat/nat.h b/src/nat/nat.h new file mode 100644 index 0000000..efab3a7 --- /dev/null +++ b/src/nat/nat.h @@ -0,0 +1,68 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/nat/nat.h + * @brief Messages for interaction with gnunet-nat-server + * @author Christian Grothoff + * + */ +#ifndef NAT_H +#define NAT_H +#include "gnunet_util_lib.h" + +#define DEBUG_NAT GNUNET_EXTRA_LOGGING + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Request to test NAT traversal. + */ +struct GNUNET_NAT_TestMessage +{ + /** + * Header with type "GNUNET_MESSAGE_TYPE_NAT_TEST" + */ + struct GNUNET_MessageHeader header; + + /** + * IPv4 target IP address + */ + uint32_t dst_ipv4; + + /** + * Port to use, 0 to send dummy ICMP response. + */ + uint16_t dport; + + /** + * Data to send OR advertised-port (in NBO) to use for dummy ICMP. + */ + uint16_t data; + + /** + * GNUNET_YES for TCP, GNUNET_NO for UDP. + */ + int32_t is_tcp; + +}; +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/nat/nat_mini.c b/src/nat/nat_mini.c new file mode 100644 index 0000000..830fdfd --- /dev/null +++ b/src/nat/nat_mini.c @@ -0,0 +1,591 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file nat/nat_mini.c + * @brief functions for interaction with miniupnp; tested with miniupnpc 1.5 + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_nat_lib.h" +#include "nat.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) + +/** + * How long do we give upnpc to create a mapping? + */ +#define MAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) + +/** + * How long do we give upnpc to remove a mapping? + */ +#define UNMAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * How often do we check for changes in the mapping? + */ +#define MAP_REFRESH_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) + + + +/** + * Opaque handle to cancel "GNUNET_NAT_mini_get_external_ipv4" operation. + */ +struct GNUNET_NAT_ExternalHandle +{ + + /** + * Function to call with the result. + */ + GNUNET_NAT_IPCallback cb; + + /** + * Closure for 'cb'. + */ + void *cb_cls; + + /** + * Read task. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Handle to 'external-ip' process. + */ + struct GNUNET_OS_Process *eip; + + /** + * Handle to stdout pipe of 'external-ip'. + */ + struct GNUNET_DISK_PipeHandle *opipe; + + /** + * Read handle of 'opipe'. + */ + const struct GNUNET_DISK_FileHandle *r; + + /** + * When should this operation time out? + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Number of bytes in 'buf' that are valid. + */ + size_t off; + + /** + * Destination of our read operation (output of 'external-ip'). + */ + char buf[17]; + +}; + + +/** + * Read the output of 'external-ip' into buf. When complete, parse the + * address and call our callback. + * + * @param cls the 'struct GNUNET_NAT_ExternalHandle' + * @param tc scheduler context + */ +static void +read_external_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_ExternalHandle *eh = cls; + ssize_t ret; + struct in_addr addr; + int iret; + + eh->task = GNUNET_SCHEDULER_NO_TASK; + if (GNUNET_YES == GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, eh->r)) + ret = + GNUNET_DISK_file_read (eh->r, &eh->buf[eh->off], + sizeof (eh->buf) - eh->off); + else + ret = -1; /* error reading, timeout, etc. */ + if (ret > 0) + { + /* try to read more */ + eh->off += ret; + eh->task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining + (eh->timeout), eh->r, + &read_external_ipv4, eh); + return; + } + iret = GNUNET_NO; + if ((eh->off > 7) && (eh->buf[eh->off - 1] == '\n')) + { + eh->buf[eh->off - 1] = '\0'; + if (1 == inet_pton (AF_INET, eh->buf, &addr)) + { + if (addr.s_addr == 0) + iret = GNUNET_NO; /* got 0.0.0.0 */ + else + iret = GNUNET_OK; + } + } + eh->cb (eh->cb_cls, (iret == GNUNET_OK) ? &addr : NULL); + GNUNET_NAT_mini_get_external_ipv4_cancel (eh); +} + + +/** + * Try to get the external IPv4 address of this peer. + * + * @param timeout when to fail + * @param cb function to call with result + * @param cb_cls closure for 'cb' + * @return handle for cancellation (can only be used until 'cb' is called), NULL on error + */ +struct GNUNET_NAT_ExternalHandle * +GNUNET_NAT_mini_get_external_ipv4 (struct GNUNET_TIME_Relative timeout, + GNUNET_NAT_IPCallback cb, void *cb_cls) +{ + struct GNUNET_NAT_ExternalHandle *eh; + + if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary ("external-ip")) + return NULL; + eh = GNUNET_malloc (sizeof (struct GNUNET_NAT_ExternalHandle)); + eh->cb = cb; + eh->cb_cls = cb_cls; + eh->opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); + if (NULL == eh->opipe) + { + GNUNET_free (eh); + return NULL; + } + eh->eip = + GNUNET_OS_start_process (GNUNET_NO, NULL, eh->opipe, "external-ip", "external-ip", + NULL); + if (NULL == eh->eip) + { + GNUNET_DISK_pipe_close (eh->opipe); + GNUNET_free (eh); + return NULL; + } + GNUNET_DISK_pipe_close_end (eh->opipe, GNUNET_DISK_PIPE_END_WRITE); + eh->timeout = GNUNET_TIME_relative_to_absolute (timeout); + eh->r = GNUNET_DISK_pipe_handle (eh->opipe, GNUNET_DISK_PIPE_END_READ); + eh->task = + GNUNET_SCHEDULER_add_read_file (timeout, eh->r, &read_external_ipv4, eh); + return eh; +} + + +/** + * Cancel operation. + * + * @param eh operation to cancel + */ +void +GNUNET_NAT_mini_get_external_ipv4_cancel (struct GNUNET_NAT_ExternalHandle *eh) +{ + (void) GNUNET_OS_process_kill (eh->eip, SIGKILL); + GNUNET_OS_process_close (eh->eip); + GNUNET_DISK_pipe_close (eh->opipe); + if (GNUNET_SCHEDULER_NO_TASK != eh->task) + GNUNET_SCHEDULER_cancel (eh->task); + GNUNET_free (eh); +} + + +/** + * Handle to a mapping created with upnpc. + */ +struct GNUNET_NAT_MiniHandle +{ + + /** + * Function to call on mapping changes. + */ + GNUNET_NAT_AddressCallback ac; + + /** + * Closure for 'ac'. + */ + void *ac_cls; + + /** + * Command used to install the map. + */ + struct GNUNET_OS_CommandHandle *map_cmd; + + /** + * Command used to refresh our map information. + */ + struct GNUNET_OS_CommandHandle *refresh_cmd; + + /** + * Command used to remove the mapping. + */ + struct GNUNET_OS_CommandHandle *unmap_cmd; + + /** + * Our current external mapping (if we have one). + */ + struct sockaddr_in current_addr; + + /** + * We check the mapping periodically to see if it + * still works. This task triggers the check. + */ + GNUNET_SCHEDULER_TaskIdentifier refresh_task; + + /** + * Are we mapping TCP or UDP? + */ + int is_tcp; + + /** + * Did we succeed with creating a mapping? + */ + int did_map; + + /** + * Did we find our mapping during refresh scan? + */ + int found; + + /** + * Which port are we mapping? + */ + uint16_t port; + +}; + + +/** + * Run upnpc -l to find out if our mapping changed. + * + * @param cls the 'struct GNUNET_NAT_MiniHandle' + * @param tc scheduler context + */ +static void +do_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Process the output from the 'upnpc -r' command. + * + * @param cls the 'struct GNUNET_NAT_MiniHandle' + * @param line line of output, NULL at the end + */ +static void +process_map_output (void *cls, const char *line); + + +/** + * Process the output from 'upnpc -l' to see if our + * external mapping changed. If so, do the notifications. + * + * @param cls the 'struct GNUNET_NAT_MiniHandle' + * @param line line of output, NULL at the end + */ +static void +process_refresh_output (void *cls, const char *line) +{ + struct GNUNET_NAT_MiniHandle *mini = cls; + char pstr[9]; + const char *s; + unsigned int nport; + struct in_addr exip; + + if (NULL == line) + { + GNUNET_OS_command_stop (mini->refresh_cmd); + mini->refresh_cmd = NULL; + if (mini->found == GNUNET_NO) + { + /* mapping disappeared, try to re-create */ + if (mini->did_map) + { + mini->ac (mini->ac_cls, GNUNET_NO, + (const struct sockaddr *) &mini->current_addr, + sizeof (mini->current_addr)); + mini->did_map = GNUNET_NO; + } + GNUNET_snprintf (pstr, sizeof (pstr), "%u", (unsigned int) mini->port); + mini->map_cmd = + GNUNET_OS_command_run (&process_map_output, mini, MAP_TIMEOUT, + "upnpc", "upnpc", "-r", pstr, + mini->is_tcp ? "tcp" : "udp", NULL); + if (NULL != mini->map_cmd) + return; + } + mini->refresh_task = + GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, &do_refresh, mini); + return; + } + if (!mini->did_map) + return; /* never mapped, won't find our mapping anyway */ + + /* we're looking for output of the form: + * "ExternalIPAddress = 12.134.41.124" */ + + s = strstr (line, "ExternalIPAddress = "); + if (NULL != s) + { + s += strlen ("ExternalIPAddress = "); + if (1 != inet_pton (AF_INET, s, &exip)) + return; /* skip */ + if (exip.s_addr == mini->current_addr.sin_addr.s_addr) + return; /* no change */ + /* update mapping */ + mini->ac (mini->ac_cls, GNUNET_NO, + (const struct sockaddr *) &mini->current_addr, + sizeof (mini->current_addr)); + mini->current_addr.sin_addr = exip; + mini->ac (mini->ac_cls, GNUNET_YES, + (const struct sockaddr *) &mini->current_addr, + sizeof (mini->current_addr)); + return; + } + /* + * we're looking for output of the form: + * + * "0 TCP 3000->192.168.2.150:3000 'libminiupnpc' ''" + * "1 UDP 3001->192.168.2.150:3001 'libminiupnpc' ''" + * + * the pattern we look for is: + * + * "%s TCP PORT->STRING:OURPORT *" or + * "%s UDP PORT->STRING:OURPORT *" + */ + GNUNET_snprintf (pstr, sizeof (pstr), ":%u ", mini->port); + if (NULL == (s = strstr (line, "->"))) + return; /* skip */ + if (NULL == strstr (s, pstr)) + return; /* skip */ + if (1 != + sscanf (line, + (mini->is_tcp) ? "%*u TCP %u->%*s:%*u %*s" : + "%*u UDP %u->%*s:%*u %*s", &nport)) + return; /* skip */ + mini->found = GNUNET_YES; + if (nport == ntohs (mini->current_addr.sin_port)) + return; /* no change */ + + /* external port changed, update mapping */ + mini->ac (mini->ac_cls, GNUNET_NO, + (const struct sockaddr *) &mini->current_addr, + sizeof (mini->current_addr)); + mini->current_addr.sin_port = htons ((uint16_t) nport); + mini->ac (mini->ac_cls, GNUNET_YES, + (const struct sockaddr *) &mini->current_addr, + sizeof (mini->current_addr)); +} + + +/** + * Run upnpc -l to find out if our mapping changed. + * + * @param cls the 'struct GNUNET_NAT_MiniHandle' + * @param tc scheduler context + */ +static void +do_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_MiniHandle *mini = cls; + + mini->refresh_task = GNUNET_SCHEDULER_NO_TASK; + mini->found = GNUNET_NO; + mini->refresh_cmd = + GNUNET_OS_command_run (&process_refresh_output, mini, MAP_TIMEOUT, + "upnpc", "upnpc", "-l", NULL); +} + + +/** + * Process the output from the 'upnpc -r' command. + * + * @param cls the 'struct GNUNET_NAT_MiniHandle' + * @param line line of output, NULL at the end + */ +static void +process_map_output (void *cls, const char *line) +{ + struct GNUNET_NAT_MiniHandle *mini = cls; + const char *ipaddr; + char *ipa; + const char *pstr; + unsigned int port; + + if (NULL == line) + { + GNUNET_OS_command_stop (mini->map_cmd); + mini->map_cmd = NULL; + mini->refresh_task = + GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, &do_refresh, mini); + return; + } + /* + * The upnpc output we're after looks like this: + * + * "external 87.123.42.204:3000 TCP is redirected to internal 192.168.2.150:3000" + */ + if ((NULL == (ipaddr = strstr (line, " "))) || + (NULL == (pstr = strstr (ipaddr, ":"))) || + (1 != sscanf (pstr + 1, "%u", &port))) + { + return; /* skip line */ + } + ipa = GNUNET_strdup (ipaddr + 1); + strstr (ipa, ":")[0] = '\0'; + if (1 != inet_pton (AF_INET, ipa, &mini->current_addr.sin_addr)) + { + GNUNET_free (ipa); + return; /* skip line */ + } + GNUNET_free (ipa); + + mini->current_addr.sin_port = htons (port); + mini->current_addr.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + mini->current_addr.sin_len = sizeof (struct sockaddr_in); +#endif + mini->did_map = GNUNET_YES; + mini->ac (mini->ac_cls, GNUNET_YES, + (const struct sockaddr *) &mini->current_addr, + sizeof (mini->current_addr)); +} + + +/** + * Start mapping the given port using (mini)upnpc. This function + * should typically not be used directly (it is used within the + * general-purpose 'GNUNET_NAT_register' code). However, it can be + * used if specifically UPnP-based NAT traversal is to be used or + * tested. + * + * @param port port to map + * @param is_tcp GNUNET_YES to map TCP, GNUNET_NO for UDP + * @param ac function to call with mapping result + * @param ac_cls closure for 'ac' + * @return NULL on error (no 'upnpc' installed) + */ +struct GNUNET_NAT_MiniHandle * +GNUNET_NAT_mini_map_start (uint16_t port, int is_tcp, + GNUNET_NAT_AddressCallback ac, void *ac_cls) +{ + struct GNUNET_NAT_MiniHandle *ret; + char pstr[6]; + + if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary ("upnpc")) + return NULL; + ret = GNUNET_malloc (sizeof (struct GNUNET_NAT_MiniHandle)); + ret->ac = ac; + ret->ac_cls = ac_cls; + ret->is_tcp = is_tcp; + ret->port = port; + GNUNET_snprintf (pstr, sizeof (pstr), "%u", (unsigned int) port); + ret->map_cmd = + GNUNET_OS_command_run (&process_map_output, ret, MAP_TIMEOUT, "upnpc", + "upnpc", "-r", pstr, is_tcp ? "tcp" : "udp", NULL); + if (NULL != ret->map_cmd) + return ret; + ret->refresh_task = + GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, &do_refresh, ret); + + return ret; +} + + +/** + * Process output from our 'unmap' command. + * + * @param cls the 'struct GNUNET_NAT_MiniHandle' + * @param line line of output, NULL at the end + */ +static void +process_unmap_output (void *cls, const char *line) +{ + struct GNUNET_NAT_MiniHandle *mini = cls; + + if (NULL == line) + { +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, "UPnP unmap done\n"); +#endif + GNUNET_OS_command_stop (mini->unmap_cmd); + mini->unmap_cmd = NULL; + GNUNET_free (mini); + return; + } + /* we don't really care about the output... */ +} + + +/** + * Remove a mapping created with (mini)upnpc. Calling + * this function will give 'upnpc' 1s to remove tha mapping, + * so while this function is non-blocking, a task will be + * left with the scheduler for up to 1s past this call. + * + * @param mini the handle + */ +void +GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini) +{ + char pstr[6]; + + if (GNUNET_SCHEDULER_NO_TASK != mini->refresh_task) + { + GNUNET_SCHEDULER_cancel (mini->refresh_task); + mini->refresh_task = GNUNET_SCHEDULER_NO_TASK; + } + if (mini->refresh_cmd != NULL) + { + GNUNET_OS_command_stop (mini->refresh_cmd); + mini->refresh_cmd = NULL; + } + if (!mini->did_map) + { + if (mini->map_cmd != NULL) + { + GNUNET_OS_command_stop (mini->map_cmd); + mini->map_cmd = NULL; + } + GNUNET_free (mini); + return; + } + mini->ac (mini->ac_cls, GNUNET_NO, + (const struct sockaddr *) &mini->current_addr, + sizeof (mini->current_addr)); + /* Note: oddly enough, deletion uses the external port whereas + * addition uses the internal port; this rarely matters since they + * often are the same, but it might... */ + GNUNET_snprintf (pstr, sizeof (pstr), "%u", + (unsigned int) ntohs (mini->current_addr.sin_port)); +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, "Unmapping port %u with UPnP\n", + ntohs (mini->current_addr.sin_port)); +#endif + mini->unmap_cmd = + GNUNET_OS_command_run (&process_unmap_output, mini, UNMAP_TIMEOUT, + "upnpc", "upnpc", "-d", pstr, + mini->is_tcp ? "tcp" : "udp", NULL); +} + + +/* end of nat_mini.c */ diff --git a/src/nat/nat_test.c b/src/nat/nat_test.c new file mode 100644 index 0000000..b6e2a74 --- /dev/null +++ b/src/nat/nat_test.c @@ -0,0 +1,479 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file nat/nat_test.c + * @brief functions to test if the NAT configuration is successful at achieving NAT traversal (with the help of a gnunet-nat-server) + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_nat_lib.h" +#include "nat.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) + +/** + * Entry we keep for each incoming connection. + */ +struct NatActivity +{ + /** + * This is a doubly-linked list. + */ + struct NatActivity *next; + + /** + * This is a doubly-linked list. + */ + struct NatActivity *prev; + + /** + * Socket of the incoming connection. + */ + struct GNUNET_NETWORK_Handle *sock; + + /** + * Handle of the master context. + */ + struct GNUNET_NAT_Test *h; + + /** + * Task reading from the incoming connection. + */ + GNUNET_SCHEDULER_TaskIdentifier rtask; +}; + + +/** + * Entry we keep for each connection to the gnunet-nat-service. + */ +struct ClientActivity +{ + /** + * This is a doubly-linked list. + */ + struct ClientActivity *next; + + /** + * This is a doubly-linked list. + */ + struct ClientActivity *prev; + + /** + * Socket of the incoming connection. + */ + struct GNUNET_CLIENT_Connection *client; + +}; + + +/** + * Handle to a NAT test. + */ +struct GNUNET_NAT_Test +{ + + /** + * Configuration used + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Function to call with success report + */ + GNUNET_NAT_TestCallback report; + + /** + * Closure for 'report'. + */ + void *report_cls; + + /** + * Handle to NAT traversal in use + */ + struct GNUNET_NAT_Handle *nat; + + /** + * Handle to listen socket, or NULL + */ + struct GNUNET_NETWORK_Handle *lsock; + + /** + * Head of list of nat activities. + */ + struct NatActivity *na_head; + + /** + * Tail of list of nat activities. + */ + struct NatActivity *na_tail; + + /** + * Head of list of client activities. + */ + struct ClientActivity *ca_head; + + /** + * Tail of list of client activities. + */ + struct ClientActivity *ca_tail; + + /** + * Identity of task for the listen socket (if any) + */ + GNUNET_SCHEDULER_TaskIdentifier ltask; + + /** + * GNUNET_YES if we're testing TCP + */ + int is_tcp; + + /** + * Data that should be transmitted or source-port. + */ + uint16_t data; + + /** + * Advertised port to the other peer. + */ + uint16_t adv_port; + +}; + + +/** + * Function called from GNUNET_NAT_register whenever someone asks us + * to do connection reversal. + * + * @param cls closure, our 'struct GNUNET_NAT_Handle' + * @param addr public IP address of the other peer + * @param addrlen actual lenght of the address + */ +static void +reversal_cb (void *cls, const struct sockaddr *addr, socklen_t addrlen) +{ + struct GNUNET_NAT_Test *h = cls; + const struct sockaddr_in *sa; + + if (addrlen != sizeof (struct sockaddr_in)) + return; + sa = (const struct sockaddr_in *) addr; + if (h->data != sa->sin_port) + { +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received connection reversal request for wrong port\n"); +#endif + return; /* wrong port */ + } + /* report success */ + h->report (h->report_cls, GNUNET_OK); +} + + +/** + * Activity on our incoming socket. Read data from the + * incoming connection. + * + * @param cls the 'struct NatActivity' + * @param tc scheduler context + */ +static void +do_udp_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_Test *tst = cls; + uint16_t data; + + tst->ltask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, tst->lsock, + &do_udp_read, tst); + if ((NULL != tc->write_ready) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, tst->lsock)) && + (sizeof (data) == + GNUNET_NETWORK_socket_recv (tst->lsock, &data, sizeof (data)))) + { + if (data == tst->data) + tst->report (tst->report_cls, GNUNET_OK); +#if DEBUG_NAT + else + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received data mismatches expected value\n"); +#endif + } +#if DEBUG_NAT + else + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to receive data from inbound connection\n"); +#endif +} + + +/** + * Activity on our incoming socket. Read data from the + * incoming connection. + * + * @param cls the 'struct NatActivity' + * @param tc scheduler context + */ +static void +do_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NatActivity *na = cls; + struct GNUNET_NAT_Test *tst; + uint16_t data; + + na->rtask = GNUNET_SCHEDULER_NO_TASK; + tst = na->h; + GNUNET_CONTAINER_DLL_remove (tst->na_head, tst->na_tail, na); + if ((NULL != tc->write_ready) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, na->sock)) && + (sizeof (data) == + GNUNET_NETWORK_socket_recv (na->sock, &data, sizeof (data)))) + { + if (data == tst->data) + tst->report (tst->report_cls, GNUNET_OK); +#if DEBUG_NAT + else + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received data mismatches expected value\n"); +#endif + } +#if DEBUG_NAT + else + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to receive data from inbound connection\n"); +#endif + GNUNET_NETWORK_socket_close (na->sock); + GNUNET_free (na); +} + + +/** + * Activity on our listen socket. Accept the + * incoming connection. + * + * @param cls the 'struct GNUNET_NAT_Test' + * @param tc scheduler context + */ +static void +do_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_Test *tst = cls; + struct GNUNET_NETWORK_Handle *s; + struct NatActivity *wl; + + tst->ltask = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + tst->ltask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, tst->lsock, + &do_accept, tst); + s = GNUNET_NETWORK_socket_accept (tst->lsock, NULL, NULL); + if (NULL == s) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "accept"); + return; /* odd error */ + } +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got an inbound connection, waiting for data\n"); +#endif + wl = GNUNET_malloc (sizeof (struct NatActivity)); + wl->sock = s; + wl->h = tst; + wl->rtask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, wl->sock, + &do_read, wl); + GNUNET_CONTAINER_DLL_insert (tst->na_head, tst->na_tail, wl); +} + + +/** + * Address-callback, used to send message to gnunet-nat-server. + * + * @param cls closure + * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean + * the previous (now invalid) one + * @param addr either the previous or the new public IP address + * @param addrlen actual lenght of the address + */ +static void +addr_cb (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + struct GNUNET_NAT_Test *h = cls; + struct ClientActivity *ca; + struct GNUNET_CLIENT_Connection *client; + struct GNUNET_NAT_TestMessage msg; + const struct sockaddr_in *sa; + + if (GNUNET_YES != add_remove) + return; + if (addrlen != sizeof (struct sockaddr_in)) + return; /* ignore IPv6 here */ +#if DEBUG_NAT + LOG (GNUNET_ERROR_TYPE_DEBUG, "Asking gnunet-nat-server to connect to `%s'\n", + GNUNET_a2s (addr, addrlen)); +#endif + sa = (const struct sockaddr_in *) addr; + msg.header.size = htons (sizeof (struct GNUNET_NAT_TestMessage)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_NAT_TEST); + msg.dst_ipv4 = sa->sin_addr.s_addr; + msg.dport = sa->sin_port; + msg.data = h->data; + msg.is_tcp = htonl ((uint32_t) h->is_tcp); + + client = GNUNET_CLIENT_connect ("gnunet-nat-server", h->cfg); + if (NULL == client) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to `gnunet-nat-server'\n")); + return; + } + ca = GNUNET_malloc (sizeof (struct ClientActivity)); + ca->client = client; + GNUNET_CONTAINER_DLL_insert (h->ca_head, h->ca_tail, ca); + GNUNET_break (GNUNET_OK == + GNUNET_CLIENT_transmit_and_get_response (client, &msg.header, + GNUNET_TIME_UNIT_SECONDS, + GNUNET_YES, NULL, + NULL)); +} + + +/** + * Start testing if NAT traversal works using the + * given configuration (IPv4-only). + * + * @param cfg configuration for the NAT traversal + * @param is_tcp GNUNET_YES to test TCP, GNUNET_NO to test UDP + * @param bnd_port port to bind to, 0 for connection reversal + * @param adv_port externally advertised port to use + * @param report function to call with the result of the test + * @param report_cls closure for report + * @return handle to cancel NAT test + */ +struct GNUNET_NAT_Test * +GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + int is_tcp, uint16_t bnd_port, uint16_t adv_port, + GNUNET_NAT_TestCallback report, void *report_cls) +{ + struct GNUNET_NAT_Test *ret; + struct sockaddr_in sa; + const struct sockaddr *addrs[] = { (const struct sockaddr *) &sa }; + const socklen_t addrlens[] = { sizeof (sa) }; + + memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons (bnd_port); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + + ret = GNUNET_malloc (sizeof (struct GNUNET_NAT_Test)); + ret->cfg = cfg; + ret->is_tcp = is_tcp; + ret->data = bnd_port; + ret->adv_port = adv_port; + ret->report = report; + ret->report_cls = report_cls; + if (bnd_port == 0) + { + ret->nat = + GNUNET_NAT_register (cfg, is_tcp, 0, 0, NULL, NULL, &addr_cb, + &reversal_cb, ret); + } + else + { + ret->lsock = + GNUNET_NETWORK_socket_create (AF_INET, + (is_tcp == + GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM, + 0); + if ((ret->lsock == NULL) || + (GNUNET_OK != + GNUNET_NETWORK_socket_bind (ret->lsock, (const struct sockaddr *) &sa, + sizeof (sa)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Failed to create listen socket bound to `%s' for NAT test: %s\n"), + GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)), + STRERROR (errno)); + if (NULL != ret->lsock) + GNUNET_NETWORK_socket_close (ret->lsock); + GNUNET_free (ret); + return NULL; + } + if (GNUNET_YES == is_tcp) + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_listen (ret->lsock, 5)); + ret->ltask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + ret->lsock, &do_accept, ret); + } + else + { + ret->ltask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + ret->lsock, &do_udp_read, ret); + } + ret->nat = + GNUNET_NAT_register (cfg, is_tcp, adv_port, 1, addrs, addrlens, + &addr_cb, NULL, ret); + } + return ret; +} + + +/** + * Stop an active NAT test. + * + * @param tst test to stop. + */ +void +GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst) +{ + struct NatActivity *pos; + struct ClientActivity *cpos; + + while (NULL != (cpos = tst->ca_head)) + { + GNUNET_CONTAINER_DLL_remove (tst->ca_head, tst->ca_tail, cpos); + GNUNET_CLIENT_disconnect (cpos->client, GNUNET_NO); + GNUNET_free (cpos); + } + while (NULL != (pos = tst->na_head)) + { + GNUNET_CONTAINER_DLL_remove (tst->na_head, tst->na_tail, pos); + GNUNET_SCHEDULER_cancel (pos->rtask); + GNUNET_NETWORK_socket_close (pos->sock); + GNUNET_free (pos); + } + if (GNUNET_SCHEDULER_NO_TASK != tst->ltask) + GNUNET_SCHEDULER_cancel (tst->ltask); + if (NULL != tst->lsock) + GNUNET_NETWORK_socket_close (tst->lsock); + GNUNET_NAT_unregister (tst->nat); + GNUNET_free (tst); +} + +/* end of nat_test.c */ diff --git a/src/nat/test_nat.c b/src/nat/test_nat.c new file mode 100644 index 0000000..98b57b3 --- /dev/null +++ b/src/nat/test_nat.c @@ -0,0 +1,192 @@ +/* + This file is part of GNUnet. + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * Testcase for port redirection and public IP address retrieval. + * This test never fails, because there need to be a NAT box set up for that. + * So we only get IP address and open the 2086 port using any NAT traversal + * method available, wait for 30s, close ports and return. + * Have a look at the logs and use NMAP to check that it works with your box. + * + * @file nat/test_nat.c + * @brief Testcase for NAT library + * @author Milan Bouchet-Valat + * @author Christian Grothoff + * + * TODO: actually use ARM to start resolver service to make DNS work! + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_util_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_nat_lib.h" + + +#define VERBOSE GNUNET_NO + + +/** + * Time to wait before stopping NAT, in seconds + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + + +/** + * Function called on each address that the NAT service + * believes to be valid for the transport. + */ +static void +addr_callback (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Address changed: %s `%s' (%u bytes)\n", + add_remove == GNUNET_YES ? "added" : "removed", GNUNET_a2s (addr, + addrlen), + (unsigned int) addrlen); +} + + +/** + * Function that terminates the test. + */ +static void +stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_Handle *nat = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping NAT and quitting...\n"); + GNUNET_NAT_unregister (nat); +} + + +struct addr_cls +{ + struct sockaddr *addr; + socklen_t addrlen; +}; + + +/** + * Return the address of the default interface, + * or any interface with a valid address if the default is not valid + * + * @param cls the 'struct addr_cls' + * @param name name of the interface + * @param isDefault do we think this may be our default interface + * @param addr address of the interface + * @param addrlen number of bytes in addr + * @return GNUNET_OK to continue iterating + */ +static int +process_if (void *cls, const char *name, int isDefault, + const struct sockaddr *addr, const struct sockaddr *broadcast_addr, + const struct sockaddr *netmask, socklen_t addrlen) +{ + struct addr_cls *data = cls; + + if (addr == NULL) + return GNUNET_OK; + GNUNET_free_non_null (data->addr); + data->addr = GNUNET_malloc (addrlen); + memcpy (data->addr, addr, addrlen); + data->addrlen = addrlen; + if (isDefault) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Main function run with scheduler. + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_NAT_Handle *nat; + struct addr_cls data; + struct sockaddr *addr; + + data.addr = NULL; + GNUNET_OS_network_interfaces_list (process_if, &data); + if (NULL == data.addr) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not find a valid interface address!\n"); + exit (GNUNET_SYSERR); + } + addr = data.addr; + GNUNET_assert (addr->sa_family == AF_INET || addr->sa_family == AF_INET6); + if (addr->sa_family == AF_INET) + ((struct sockaddr_in *) addr)->sin_port = htons (2086); + else + ((struct sockaddr_in6 *) addr)->sin6_port = htons (2086); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requesting NAT redirection from address %s...\n", + GNUNET_a2s (addr, data.addrlen)); + + nat = GNUNET_NAT_register (cfg, GNUNET_YES /* tcp */ , + 2086, 1, (const struct sockaddr **) &addr, + &data.addrlen, &addr_callback, NULL, NULL); + GNUNET_free (addr); + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &stop, nat); +} + + +int +main (int argc, char *const argv[]) +{ + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + char *const argv_prog[] = { + "test-nat", + "-c", + "test_nat_data.conf", + "-L", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL + }; + + GNUNET_log_setup ("test-nat", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Testing NAT library, timeout set to %d seconds\n", TIMEOUT); + + GNUNET_PROGRAM_run (5, argv_prog, "test-nat", "nohelp", options, &run, NULL); + + return 0; +} + +/* end of test_nat.c */ diff --git a/src/nat/test_nat_data.conf b/src/nat/test_nat_data.conf new file mode 100644 index 0000000..83bcf83 --- /dev/null +++ b/src/nat/test_nat_data.conf @@ -0,0 +1,141 @@ +[PATHS] +SERVICEHOME = /tmp/nat-test +# SERVICEHOME = /var/lib/gnunet/ +# DEFAULTCONFIG = /etc/gnunet.conf +# If 'DEFAULTCONFIG' is not defined, the current +# configuration file is assumed to be the default, +# which is what we want by default... + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[TESTING] +WEAKRANDOM = NO + +[client] +HOME = $SERVICEHOME + + +[nat] +# Are we behind NAT? +BEHIND_NAT = YES + +# Is the NAT hole-punched? +PUNCHED_NAT = NO + +# Disable UPNP by default until it gets cleaner! +ENABLE_UPNP = YES + +# Use addresses from the local network interfaces (inluding loopback, but also others) +USE_LOCALADDR = YES + +# External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) +# normal interface IP address for non-NATed peers; +# possibly auto-detected (using UPnP) if possible if not specified +# EXTERNAL_ADDRESS = + +# Should we use ICMP-based NAT traversal to try connect to NATed peers +# or, if we are behind NAT, to allow connections to us? +ENABLE_ICMP_CLIENT = YES +ENABLE_ICMP_SERVER = YES + +# IP address of the interface connected to the NAT box; IPv4 dotted-decimal ONLY; +# normal interface IP address for non-NATed peers; +# likely auto-detected (via interface list) if not specified (!) +# INTERNAL_ADDRESS = + +# Disable IPv6 support +DISABLEV6 = NO + +[arm] +PORT = 2087 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-arm +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DEFAULTSERVICES = topology hostlist +UNIXPATH = /tmp/gnunet-service-arm.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +# GLOBAL_POSTFIX = -l $SERVICEHOME/{}-logs +# GLOBAL_PREFIX = +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = + +[statistics] +AUTOSTART = YES +PORT = 2088 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-statistics +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-statistics.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +# DISABLE_SOCKET_FORWARDING = NO +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = + +[resolver] +AUTOSTART = YES +PORT = 2089 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-resolver +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-resolver.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = NO +# DISABLE_SOCKET_FORWARDING = NO +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = + +[peerinfo] +AUTOSTART = NO + +[transport] +AUTOSTART = NO + +[core] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[fs] +AUTOSTART = NO + +[dht] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + + diff --git a/src/nat/test_nat_mini.c b/src/nat/test_nat_mini.c new file mode 100644 index 0000000..2c6da3b --- /dev/null +++ b/src/nat/test_nat_mini.c @@ -0,0 +1,131 @@ +/* + This file is part of GNUnet. + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * Testcase for port redirection and public IP address retrieval. + * This test never fails, because there need to be a NAT box set up for tha * + * @file nat/test_nat_mini.c + * @brief Testcase for NAT library - mini + * @author Christian Grothoff + * + * TODO: actually use ARM to start resolver service to make DNS work! + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_util_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_nat_lib.h" + + +#define VERBOSE GNUNET_NO + +/* Time to wait before stopping NAT, in seconds */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +/** + * Function called on each address that the NAT service + * believes to be valid for the transport. + */ +static void +addr_callback (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + fprintf (stderr, "Address changed: %s `%s' (%u bytes)\n", + add_remove == GNUNET_YES ? "added" : "removed", GNUNET_a2s (addr, + addrlen), + (unsigned int) addrlen); +} + + +/** + * Function that terminates the test. + */ +static void +stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NAT_MiniHandle *mini = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping NAT and quitting...\n"); + GNUNET_NAT_mini_map_stop (mini); +} + +#define PORT 10000 + +/** + * Main function run with scheduler. + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_NAT_MiniHandle *mini; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requesting NAT redirection for port %u...\n", PORT); + mini = GNUNET_NAT_mini_map_start (PORT, GNUNET_YES /* tcp */ , + &addr_callback, NULL); + if (NULL == mini) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Could not start UPnP interaction\n"); + return; + } + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &stop, mini); +} + + +int +main (int argc, char *const argv[]) +{ + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + char *const argv_prog[] = { + "test-nat-mini", + "-c", + "test_nat_data.conf", + "-L", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL + }; + + GNUNET_log_setup ("test-nat-mini", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "UPnP test for NAT library, timeout set to %d seconds\n", + TIMEOUT); + GNUNET_PROGRAM_run (5, argv_prog, "test-nat-mini", "nohelp", options, &run, + NULL); + return 0; +} + +/* end of test_nat_mini.c */ diff --git a/src/nat/test_nat_test.c b/src/nat/test_nat_test.c new file mode 100644 index 0000000..6461788 --- /dev/null +++ b/src/nat/test_nat_test.c @@ -0,0 +1,136 @@ +/* + This file is part of GNUnet. + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * Testcase for the NAT testing code. + * + * @file nat/test_nat_test.c + * @brief Testcase for NAT testing functions + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_util_lib.h" +#include "gnunet_nat_lib.h" + + +#define VERBOSE GNUNET_NO + + +/** + * Time to wait before stopping NAT test, in seconds + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) + + +static int ret = 1; + +static struct GNUNET_NAT_Test *tst; + +static GNUNET_SCHEDULER_TaskIdentifier end; + +static void +end_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_NAT_test_stop (tst); +} + +static void +report_success (void *cls, int success) +{ + GNUNET_assert (GNUNET_OK == success); + ret = 0; + GNUNET_SCHEDULER_cancel (end); + end = GNUNET_SCHEDULER_add_now (&end_test, NULL); +} + +/** + * Main function run with scheduler. + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + tst = + GNUNET_NAT_test_start (cfg, GNUNET_YES, 1285, 1285, &report_success, + NULL); + if (NULL == tst) + return; + end = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_test, NULL); +} + + +int +main (int argc, char *const argv[]) +{ + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + struct GNUNET_OS_Process *gns; + + int nat_res; + + char *const argv_prog[] = { + "test-nat-test", + "-c", + "test_nat_test_data.conf", + "-L", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL + }; + + GNUNET_log_setup ("test-nat-test", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + nat_res = GNUNET_OS_check_helper_binary ("gnunet-nat-server"); + if (GNUNET_SYSERR == nat_res) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Cannot run NAT test: `%s' file not found\n", + "gnunet-nat-server"); + return 0; + } + + gns = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-nat-server", + "gnunet-nat-server", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", "test_nat_test_data.conf", "12345", NULL); + GNUNET_assert (NULL != gns); + GNUNET_PROGRAM_run (5, argv_prog, "test-nat-test", "nohelp", options, &run, + NULL); + GNUNET_break (0 == GNUNET_OS_process_kill (gns, SIGTERM)); + GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (gns)); + GNUNET_OS_process_close (gns); + return ret; +} + +/* end of test_nat_test.c */ diff --git a/src/nat/test_nat_test_data.conf b/src/nat/test_nat_test_data.conf new file mode 100644 index 0000000..f153e17 --- /dev/null +++ b/src/nat/test_nat_test_data.conf @@ -0,0 +1,48 @@ +[PATHS] +SERVICEHOME = /tmp/nat-test +# SERVICEHOME = /var/lib/gnunet/ +# DEFAULTCONFIG = /etc/gnunet.conf +# If 'DEFAULTCONFIG' is not defined, the current +# configuration file is assumed to be the default, +# which is what we want by default... + +[gnunet-nat-server] +HOSTNAME = localhost +PORT = 12345 + +[nat] +# Are we behind NAT? +BEHIND_NAT = YES + +# Is the NAT hole-punched? +PUNCHED_NAT = NO + +# Disable UPNP by default until it gets cleaner! +ENABLE_UPNP = YES + +# Use addresses from the local network interfaces (inluding loopback, but also others) +USE_LOCALADDR = YES + +# External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) +# normal interface IP address for non-NATed peers; +# possibly auto-detected (using UPnP) if possible if not specified +# EXTERNAL_ADDRESS = + +# Should we use ICMP-based NAT traversal to try connect to NATed peers +# or, if we are behind NAT, to allow connections to us? +ENABLE_ICMP_CLIENT = YES +ENABLE_ICMP_SERVER = YES + +# IP address of the interface connected to the NAT box; IPv4 dotted-decimal ONLY; +# normal interface IP address for non-NATed peers; +# likely auto-detected (via interface list) if not specified (!) +INTERNAL_ADDRESS = 127.0.0.1 + +# Disable IPv6 support +DISABLEV6 = YES + + +[nse] +AUTOSTART = NO + + diff --git a/src/nse/Makefile.am b/src/nse/Makefile.am new file mode 100644 index 0000000..054a776 --- /dev/null +++ b/src/nse/Makefile.am @@ -0,0 +1,90 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + nse.conf + + +lib_LTLIBRARIES = libgnunetnse.la + +libgnunetnse_la_SOURCES = \ + nse_api.c nse.h +libgnunetnse_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) +libgnunetnse_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + + +bin_PROGRAMS = \ + gnunet-service-nse + +noinst_PROGRAMS = \ + gnunet-nse-profiler + +gnunet_nse_profiler_SOURCES = \ + gnunet-nse-profiler.c +gnunet_nse_profiler_LDADD = -lm \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(GN_LIBINTL) +gnunet_nse_profiler_DEPENDENCIES = \ + libgnunetnse.la + +gnunet_service_nse_SOURCES = \ + gnunet-service-nse.c +gnunet_service_nse_LDADD = \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + -lm \ + $(GN_LIBINTL) +gnunet_service_nse_DEPENDENCIES = \ + libgnunetnse.la + +if HAVE_BENCHMARKS + MULTIPEER_TEST = test_nse_multipeer +endif + +check_PROGRAMS = \ + test_nse_api \ + $(MULTIPEER_TEST) + + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_nse_api_SOURCES = \ + test_nse_api.c +test_nse_api_LDADD = \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_nse_multipeer_SOURCES = \ + test_nse_multipeer.c +test_nse_multipeer_LDADD = \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + -lm + +EXTRA_DIST = \ + test_nse.conf \ + nse_profiler_test.conf + + diff --git a/src/nse/Makefile.in b/src/nse/Makefile.in new file mode 100644 index 0000000..7c03cbe --- /dev/null +++ b/src/nse/Makefile.in @@ -0,0 +1,939 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-nse$(EXEEXT) +noinst_PROGRAMS = gnunet-nse-profiler$(EXEEXT) +check_PROGRAMS = test_nse_api$(EXEEXT) $(am__EXEEXT_1) +subdir = src/nse +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/nse.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = nse.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunetnse_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgnunetnse_la_OBJECTS = nse_api.lo +libgnunetnse_la_OBJECTS = $(am_libgnunetnse_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetnse_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetnse_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +@HAVE_BENCHMARKS_TRUE@am__EXEEXT_1 = test_nse_multipeer$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am_gnunet_nse_profiler_OBJECTS = gnunet-nse-profiler.$(OBJEXT) +gnunet_nse_profiler_OBJECTS = $(am_gnunet_nse_profiler_OBJECTS) +am_gnunet_service_nse_OBJECTS = gnunet-service-nse.$(OBJEXT) +gnunet_service_nse_OBJECTS = $(am_gnunet_service_nse_OBJECTS) +am_test_nse_api_OBJECTS = test_nse_api.$(OBJEXT) +test_nse_api_OBJECTS = $(am_test_nse_api_OBJECTS) +test_nse_api_DEPENDENCIES = $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_nse_multipeer_OBJECTS = test_nse_multipeer.$(OBJEXT) +test_nse_multipeer_OBJECTS = $(am_test_nse_multipeer_OBJECTS) +test_nse_multipeer_DEPENDENCIES = \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetnse_la_SOURCES) $(gnunet_nse_profiler_SOURCES) \ + $(gnunet_service_nse_SOURCES) $(test_nse_api_SOURCES) \ + $(test_nse_multipeer_SOURCES) +DIST_SOURCES = $(libgnunetnse_la_SOURCES) \ + $(gnunet_nse_profiler_SOURCES) $(gnunet_service_nse_SOURCES) \ + $(test_nse_api_SOURCES) $(test_nse_multipeer_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + nse.conf + +lib_LTLIBRARIES = libgnunetnse.la +libgnunetnse_la_SOURCES = \ + nse_api.c nse.h + +libgnunetnse_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) + +libgnunetnse_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +gnunet_nse_profiler_SOURCES = \ + gnunet-nse-profiler.c + +gnunet_nse_profiler_LDADD = -lm \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(GN_LIBINTL) + +gnunet_nse_profiler_DEPENDENCIES = \ + libgnunetnse.la + +gnunet_service_nse_SOURCES = \ + gnunet-service-nse.c + +gnunet_service_nse_LDADD = \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + -lm \ + $(GN_LIBINTL) + +gnunet_service_nse_DEPENDENCIES = \ + libgnunetnse.la + +@HAVE_BENCHMARKS_TRUE@MULTIPEER_TEST = test_nse_multipeer +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_nse_api_SOURCES = \ + test_nse_api.c + +test_nse_api_LDADD = \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_nse_multipeer_SOURCES = \ + test_nse_multipeer.c + +test_nse_multipeer_LDADD = \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + -lm + +EXTRA_DIST = \ + test_nse.conf \ + nse_profiler_test.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/nse/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/nse/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +nse.conf: $(top_builddir)/config.status $(srcdir)/nse.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetnse.la: $(libgnunetnse_la_OBJECTS) $(libgnunetnse_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetnse_la_LINK) -rpath $(libdir) $(libgnunetnse_la_OBJECTS) $(libgnunetnse_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-nse-profiler$(EXEEXT): $(gnunet_nse_profiler_OBJECTS) $(gnunet_nse_profiler_DEPENDENCIES) + @rm -f gnunet-nse-profiler$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_nse_profiler_OBJECTS) $(gnunet_nse_profiler_LDADD) $(LIBS) +gnunet-service-nse$(EXEEXT): $(gnunet_service_nse_OBJECTS) $(gnunet_service_nse_DEPENDENCIES) + @rm -f gnunet-service-nse$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_nse_OBJECTS) $(gnunet_service_nse_LDADD) $(LIBS) +test_nse_api$(EXEEXT): $(test_nse_api_OBJECTS) $(test_nse_api_DEPENDENCIES) + @rm -f test_nse_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_nse_api_OBJECTS) $(test_nse_api_LDADD) $(LIBS) +test_nse_multipeer$(EXEEXT): $(test_nse_multipeer_OBJECTS) $(test_nse_multipeer_DEPENDENCIES) + @rm -f test_nse_multipeer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_nse_multipeer_OBJECTS) $(test_nse_multipeer_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-nse-profiler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-nse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nse_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_nse_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_nse_multipeer.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-pkgcfgDATA \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-libLTLIBRARIES uninstall-pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/nse/gnunet-nse-profiler.c b/src/nse/gnunet-nse-profiler.c new file mode 100644 index 0000000..a10d237 --- /dev/null +++ b/src/nse/gnunet-nse-profiler.c @@ -0,0 +1,934 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file nse/gnunet-nse-profiler.c + * + * @brief Profiling driver for the network size estimation service. + * Generally, the profiler starts a given number of peers, + * then churns some off, waits a certain amount of time, then + * churns again, and repeats. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_nse_service.h" + +#define VERBOSE 3 + +struct NSEPeer +{ + struct NSEPeer *prev; + + struct NSEPeer *next; + + struct GNUNET_TESTING_Daemon *daemon; + + struct GNUNET_NSE_Handle *nse_handle; + + struct GNUNET_STATISTICS_Handle *stats; + + GNUNET_SCHEDULER_TaskIdentifier stats_task; +}; + + +struct StatsContext +{ + /** + * Whether or not shoutdown after finishing. + */ + int shutdown; + + /** + * How many messages have peers received during the test. + */ + unsigned long long total_nse_received_messages; + + /** + * How many messages have peers send during the test (should be == received). + */ + unsigned long long total_nse_transmitted_messages; + + /** + * How many messages have travelled an edge in both directions. + */ + unsigned long long total_nse_cross; + + /** + * How many extra messages per edge (corrections) have been received. + */ + unsigned long long total_nse_extra; + + /** + * How many messages have been discarded. + */ + unsigned long long total_discarded; +}; + + +static struct NSEPeer *peer_head; + +static struct NSEPeer *peer_tail; + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) + +static int ok; + +/** + * Be verbose + */ +static int verbose; + +/** + * Total number of peers in the test. + */ +static unsigned long long num_peers; + +/** + * Global configuration file + */ +static struct GNUNET_CONFIGURATION_Handle *testing_cfg; + +/** + * Total number of currently running peers. + */ +static unsigned long long peers_running; + +/** + * Current round we are in. + */ +static unsigned long long current_round; + +/** + * Peers desired in the next round. + */ +static unsigned long long peers_next_round; + +/** + * Maximum number of connections to NSE services. + */ +static unsigned long long connection_limit; + +/** + * Total number of connections in the whole network. + */ +static unsigned int total_connections; + +/** + * The currently running peer group. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * File to report results to. + */ +static struct GNUNET_DISK_FileHandle *output_file; + +/** + * File to log connection info, statistics to. + */ +static struct GNUNET_DISK_FileHandle *data_file; + +/** + * How many data points to capture before triggering next round? + */ +static struct GNUNET_TIME_Relative wait_time; + +/** + * NSE interval. + */ +static struct GNUNET_TIME_Relative interval; + +/** + * Task called to disconnect peers. + */ +static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +/** + * Task called to shutdown test. + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; + +/** + * Task used to churn the network. + */ +static GNUNET_SCHEDULER_TaskIdentifier churn_task; + +static char *topology_file; + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + ok = 0; + } +} + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NSEPeer *pos; + +#if VERBOSE + FPRINTF (stderr, "%s", "Ending test.\n"); +#endif + + if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + while (NULL != (pos = peer_head)) + { + if (pos->nse_handle != NULL) + GNUNET_NSE_disconnect (pos->nse_handle); + GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos); + if (GNUNET_SCHEDULER_NO_TASK != pos->stats_task) + { + GNUNET_SCHEDULER_cancel (pos->stats_task); + if (NULL != pos->stats) + GNUNET_STATISTICS_destroy(pos->stats, GNUNET_NO); + } + GNUNET_free (pos); + } + + if (data_file != NULL) + GNUNET_DISK_file_close (data_file); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +/** + * Callback to call when network size estimate is updated. + * + * @param cls closure + * @param timestamp server timestamp + * @param estimate the value of the current network size estimate + * @param std_dev standard deviation (rounded down to nearest integer) + * of the size estimation values seen + * + */ +static void +handle_estimate (void *cls, struct GNUNET_TIME_Absolute timestamp, + double estimate, double std_dev) +{ + struct NSEPeer *peer = cls; + char *output_buffer; + size_t size; + + if (output_file != NULL) + { + size = + GNUNET_asprintf (&output_buffer, "%s %llu %llu %f %f %f\n", + GNUNET_i2s (&peer->daemon->id), peers_running, + timestamp.abs_value, + GNUNET_NSE_log_estimate_to_n (estimate), estimate, + std_dev); + if (size != GNUNET_DISK_file_write (output_file, output_buffer, size)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n"); + GNUNET_free (output_buffer); + } + else + FPRINTF (stderr, + "Received network size estimate from peer %s. Size: %f std.dev. %f\n", + GNUNET_i2s (&peer->daemon->id), estimate, std_dev); + +} + +/** + * Process core statistic values. + * + * @param cls closure + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +core_stats_iterator (void *cls, const char *subsystem, const char *name, + uint64_t value, int is_persistent) +{ + struct NSEPeer *peer = cls; + char *output_buffer; + size_t size; + + if (output_file != NULL) + { + size = + GNUNET_asprintf (&output_buffer, "%s [%s] %s %llu\n", + GNUNET_i2s (&peer->daemon->id), + subsystem, name, value); + if (size != GNUNET_DISK_file_write (output_file, output_buffer, size)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n"); + GNUNET_free (output_buffer); + } + else + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%s -> %s [%s]: %llu\n", + GNUNET_i2s (&peer->daemon->id), subsystem, name, value); + + return GNUNET_OK; +} + +/** + * Continuation called by "get_stats" function. + * + * @param cls closure + * @param success GNUNET_OK if statistics were + * successfully obtained, GNUNET_SYSERR if not. + */ +static void +core_stats_cont (void *cls, int success); + +static void +core_get_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NSEPeer *peer = cls; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + GNUNET_STATISTICS_destroy(peer->stats, GNUNET_NO); + peer->stats = NULL; + return; + } + else + { + GNUNET_STATISTICS_get(peer->stats, "core", NULL, + GNUNET_TIME_UNIT_FOREVER_REL, + &core_stats_cont, &core_stats_iterator, peer); + GNUNET_STATISTICS_get(peer->stats, "transport", NULL, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, &core_stats_iterator, peer); + GNUNET_STATISTICS_get(peer->stats, "nse", NULL, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, &core_stats_iterator, peer); + } + peer->stats_task = GNUNET_SCHEDULER_NO_TASK; +} + +/** + * Continuation called by "get_stats" function. + * + * @param cls closure + * @param success GNUNET_OK if statistics were + * successfully obtained, GNUNET_SYSERR if not. + */ +static void +core_stats_cont (void *cls, int success) +{ + struct NSEPeer *peer = cls; + peer->stats_task = GNUNET_SCHEDULER_add_delayed (interval, &core_get_stats, + peer); +} + + +/** + * + */ +static void +connect_nse_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NSEPeer *current_peer; + unsigned int i; + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to nse service of peers\n"); +#endif + for (i = 0; i < num_peers; i++) + { + if ((connection_limit > 0) && (i % (num_peers / connection_limit) != 0)) + continue; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "nse-profiler: connecting to nse service of peer %d\n", i); +#endif + current_peer = GNUNET_malloc (sizeof (struct NSEPeer)); + current_peer->daemon = GNUNET_TESTING_daemon_get (pg, i); + if (GNUNET_YES == + GNUNET_TESTING_test_daemon_running (GNUNET_TESTING_daemon_get (pg, i))) + { + current_peer->nse_handle = + GNUNET_NSE_connect (current_peer->daemon->cfg, &handle_estimate, + current_peer); + GNUNET_assert (current_peer->nse_handle != NULL); + } + current_peer->stats = GNUNET_STATISTICS_create("profiler", current_peer->daemon->cfg); + GNUNET_STATISTICS_get(current_peer->stats, "core", NULL, + GNUNET_TIME_UNIT_FOREVER_REL, + &core_stats_cont, &core_stats_iterator, current_peer); + GNUNET_STATISTICS_get(current_peer->stats, "transport", NULL, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, &core_stats_iterator, current_peer); + GNUNET_STATISTICS_get(current_peer->stats, "nse", NULL, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, &core_stats_iterator, current_peer); + GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer); + } +} + + +static void +churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Continuation called by the "get_all" and "get" functions. + * + * @param cls struct StatsContext + * @param success GNUNET_OK if statistics were + * successfully obtained, GNUNET_SYSERR if not. + */ +static void +stats_finished_callback (void *cls, int success) +{ + struct StatsContext *stats_context = cls; + char *buf; + int buf_len; + + if ((GNUNET_OK == success) && (data_file != NULL)) + { + /* Stats lookup successful, write out data */ + buf = NULL; + buf_len = + GNUNET_asprintf (&buf, "TOTAL_NSE_RECEIVED_MESSAGES_%d: %u \n", + stats_context->shutdown, + stats_context->total_nse_received_messages); + if (buf_len > 0) + { + GNUNET_DISK_file_write (data_file, buf, buf_len); + } + GNUNET_free_non_null (buf); + + buf = NULL; + buf_len = + GNUNET_asprintf (&buf, "TOTAL_NSE_TRANSMITTED_MESSAGES_%d: %u\n", + stats_context->shutdown, + stats_context->total_nse_transmitted_messages); + if (buf_len > 0) + { + GNUNET_DISK_file_write (data_file, buf, buf_len); + } + GNUNET_free_non_null (buf); + + buf = NULL; + buf_len = + GNUNET_asprintf (&buf, "TOTAL_NSE_CROSS_%d: %u \n", + stats_context->shutdown, + stats_context->total_nse_cross); + if (buf_len > 0) + { + GNUNET_DISK_file_write (data_file, buf, buf_len); + } + GNUNET_free_non_null (buf); + + buf = NULL; + buf_len = + GNUNET_asprintf (&buf, "TOTAL_NSE_EXTRA_%d: %u \n", + stats_context->shutdown, + stats_context->total_nse_extra); + if (buf_len > 0) + { + GNUNET_DISK_file_write (data_file, buf, buf_len); + } + GNUNET_free_non_null (buf); + + buf = NULL; + buf_len = + GNUNET_asprintf (&buf, "TOTAL_NSE_DISCARDED_%d: %u \n", + stats_context->shutdown, + stats_context->total_discarded); + if (buf_len > 0) + { + GNUNET_DISK_file_write (data_file, buf, buf_len); + } + GNUNET_free_non_null (buf); + + } + + if (GNUNET_YES == stats_context->shutdown) + { + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == shutdown_handle); + shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + } + else + { + GNUNET_assert (churn_task == GNUNET_SCHEDULER_NO_TASK); + churn_task = GNUNET_SCHEDULER_add_now (&churn_peers, NULL); + } + GNUNET_free (stats_context); +} + + +/** + * Callback function to process statistic values. + * + * @param cls struct StatsContext + * @param peer the peer the statistics belong to + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +statistics_iterator (void *cls, const struct GNUNET_PeerIdentity *peer, + const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + struct StatsContext *stats_context = cls; + + if (0 == strcmp (subsystem, "nse")) + { + if (0 == strcmp (name, "# flood messages received")) + { + stats_context->total_nse_received_messages += value; +#if VERBOSE + if (data_file != NULL) + { + char *buf; + int buf_len; + + buf = NULL; + buf_len = + GNUNET_asprintf (&buf, "%s %u RECEIVED\n", GNUNET_i2s(peer), value); + if (buf_len > 0) + { + GNUNET_DISK_file_write (data_file, buf, buf_len); + } + GNUNET_free_non_null (buf); + } +#endif + } + if (0 == strcmp (name, "# flood messages transmitted")) + { + stats_context->total_nse_transmitted_messages += value; +#if VERBOSE + if (data_file != NULL) + { + char *buf; + int buf_len; + + buf = NULL; + buf_len = + GNUNET_asprintf (&buf, "%s %u TRANSMITTED\n", + GNUNET_i2s(peer), value); + if (buf_len > 0) + { + GNUNET_DISK_file_write (data_file, buf, buf_len); + } + GNUNET_free_non_null (buf); + } +#endif + } + if (0 == strcmp (name, "# cross messages")) + { + stats_context->total_nse_cross += value; + } + if (0 == strcmp (name, "# extra messages")) + { + stats_context->total_nse_extra += value; + } + if (0 == strcmp (name, "# flood messages discarded (clock skew too large)")) + { + stats_context->total_discarded += value; + } + } + return GNUNET_OK; +} + + +static void +disconnect_nse_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NSEPeer *pos; + char *buf; + struct StatsContext *stats_context; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnecting nse service of peers\n"); + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + while (NULL != (pos = peer_head)) + { + if (pos->nse_handle != NULL) + { + GNUNET_NSE_disconnect (pos->nse_handle); + pos->nse_handle = NULL; + } + GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos); + if (NULL != pos->stats) + GNUNET_STATISTICS_destroy(pos->stats, GNUNET_NO); + if (GNUNET_SCHEDULER_NO_TASK != pos->stats_task) + GNUNET_SCHEDULER_cancel (pos->stats_task); + GNUNET_free (pos); + } + + GNUNET_asprintf (&buf, "round%llu", current_round); + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (testing_cfg, "nse-profiler", buf, + &peers_next_round)) + { + current_round++; + if (current_round == 1) + { + stats_context = GNUNET_malloc (sizeof (struct StatsContext)); + stats_context->shutdown = GNUNET_NO; + GNUNET_TESTING_get_statistics (pg, &stats_finished_callback, + &statistics_iterator, stats_context); + } + else + { + GNUNET_assert (churn_task == GNUNET_SCHEDULER_NO_TASK); + churn_task = GNUNET_SCHEDULER_add_now (&churn_peers, NULL); + } + } + else /* No more rounds, let's shut it down! */ + { + stats_context = GNUNET_malloc (sizeof (struct StatsContext)); + stats_context->shutdown = GNUNET_YES; + GNUNET_SCHEDULER_cancel (shutdown_handle); + shutdown_handle = GNUNET_SCHEDULER_NO_TASK; + GNUNET_TESTING_get_statistics (pg, &stats_finished_callback, + &statistics_iterator, stats_context); + } + GNUNET_free (buf); +} + + +/** + * FIXME. + * + * @param cls unused + * @param emsg NULL on success + */ +static void +topology_output_callback (void *cls, const char *emsg) +{ + disconnect_task = + GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL); + GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); +} + + +/** + * FIXME. + * + * @param cls closure + * @param emsg NULL on success + */ +static void +churn_callback (void *cls, const char *emsg) +{ + char *temp_output_file; + + if (emsg == NULL) /* Everything is okay! */ + { + peers_running = peers_next_round; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Round %llu, churn finished successfully.\n", current_round); + GNUNET_assert (disconnect_task == GNUNET_SCHEDULER_NO_TASK); + GNUNET_asprintf (&temp_output_file, "%s_%llu.dot", topology_file, + current_round); + GNUNET_TESTING_peergroup_topology_to_file (pg, temp_output_file, + &topology_output_callback, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Writing topology to file %s\n", + temp_output_file); + GNUNET_free (temp_output_file); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %llu, churn FAILED!!\n", + current_round); + GNUNET_SCHEDULER_cancel (shutdown_handle); + shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + } +} + + +static void +churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + /* peers_running = GNUNET_TESTING_daemons_running(pg); */ + churn_task = GNUNET_SCHEDULER_NO_TASK; + if (peers_next_round == peers_running) + { + /* Nothing to do... */ + GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); + GNUNET_assert (disconnect_task == GNUNET_SCHEDULER_NO_TASK); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %lu, doing nothing!\n", + current_round); + } + else + { + if (peers_next_round > num_peers) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Asked to turn on more peers than we have!!\n"); + GNUNET_SCHEDULER_cancel (shutdown_handle); + GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + } + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Round %llu, turning off %llu peers, turning on %llu peers!\n", + current_round, + (peers_running > + peers_next_round) ? peers_running - peers_next_round : 0, + (peers_next_round > + peers_running) ? peers_next_round - peers_running : 0); + GNUNET_TESTING_daemons_churn (pg, "nse", + (peers_running > + peers_next_round) ? peers_running - + peers_next_round : 0, + (peers_next_round > + peers_running) ? peers_next_round - + peers_running : 0, wait_time, &churn_callback, + NULL); + } +} + + +static void +nse_started_cb (void *cls, const char *emsg) +{ + GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL); +} + + +static void +my_cb (void *cls, const char *emsg) +{ + char *buf; + int buf_len; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); + ok = 1; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer Group started successfully, connecting to NSE service for each peer!\n"); +#endif + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Have %u connections\n", + total_connections); + if (data_file != NULL) + { + buf = NULL; + buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections); + if (buf_len > 0) + GNUNET_DISK_file_write (data_file, buf, buf_len); + GNUNET_free (buf); + } + peers_running = GNUNET_TESTING_daemons_running (pg); + GNUNET_TESTING_daemons_start_service (pg, "nse", wait_time, &nse_started_cb, + NULL); + +} + + +/** + * Function that will be called whenever two daemons are connected by + * the testing library. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param first_cfg config for the first daemon + * @param second_cfg config for the second daemon + * @param first_daemon handle for the first daemon + * @param second_daemon handle for the second daemon + * @param emsg error message (NULL on success) + */ +static void +connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) +{ + if (emsg == NULL) + total_connections++; +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *temp_str; + struct GNUNET_TESTING_Host *hosts; + char *data_filename; + + ok = 1; + //testing_cfg = GNUNET_CONFIGURATION_create (); + testing_cfg = GNUNET_CONFIGURATION_dup (cfg); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", "YES"); +#endif + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", + "num_peers", &num_peers)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option TESTING:NUM_PEERS is required!\n"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (testing_cfg, "nse-profiler", + "WAIT_TIME", &wait_time)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option nse-profiler:wait_time is required!\n"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (testing_cfg, "nse", + "INTERVAL", &interval)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option nse:interval is required!\n"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (testing_cfg, "nse-profiler", + "connection_limit", + &connection_limit)) + { + connection_limit = 0; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (testing_cfg, "nse-profiler", + "topology_output_file", + &topology_file)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option nse-profiler:topology_output_file is required!\n"); + return; + } + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (testing_cfg, "nse-profiler", + "data_output_file", + &data_filename)) + { + data_file = + GNUNET_DISK_file_open (data_filename, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_TRUNCATE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (data_file == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", + data_filename); + GNUNET_free (data_filename); + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "nse-profiler", "output_file", + &temp_str)) + { + output_file = + GNUNET_DISK_file_open (temp_str, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (output_file == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", + temp_str); + } + GNUNET_free_non_null (temp_str); + + hosts = GNUNET_TESTING_hosts_load (testing_cfg); + + pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, + &connect_cb, &my_cb, NULL, hosts); + GNUNET_assert (pg != NULL); + shutdown_handle = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (), + &shutdown_task, NULL); +} + + + +/** + * nse-profiler command line options + */ +static struct GNUNET_GETOPT_CommandLineOption options[] = { + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END +}; + + +int +main (int argc, char *argv[]) +{ + GNUNET_log_setup ("nse-profiler", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run (argc, argv, "nse-profiler", + gettext_noop + ("Measure quality and performance of the NSE service."), + options, &run, NULL); +#if REMOVE_DIR + GNUNET_DISK_directory_remove ("/tmp/nse-profiler"); +#endif + return ok; +} + +/* end of nse-profiler.c */ diff --git a/src/nse/gnunet-service-nse.c b/src/nse/gnunet-service-nse.c new file mode 100644 index 0000000..3af9bb7 --- /dev/null +++ b/src/nse/gnunet-service-nse.c @@ -0,0 +1,1497 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file nse/gnunet-service-nse.c + * @brief network size estimation service + * @author Nathan Evans + * @author Christian Grothoff + * + * The purpose of this service is to estimate the size of the network. + * Given a specified interval, each peer hashes the most recent + * timestamp which is evenly divisible by that interval. This hash is + * compared in distance to the peer identity to choose an offset. The + * closer the peer identity to the hashed timestamp, the earlier the + * peer sends out a "nearest peer" message. The closest peer's + * message should thus be received before any others, which stops + * those peer from sending their messages at a later duration. So + * every peer should receive the same nearest peer message, and from + * this can calculate the expected number of peers in the network. + */ +#include "platform.h" +#include +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_protocols.h" +#include "gnunet_signatures.h" +#include "gnunet_statistics_service.h" +#include "gnunet_core_service.h" +#include "gnunet_nse_service.h" +#include "nse.h" + +/** + * Should messages be delayed randomly? This option should be set to + * GNUNET_NO only for experiments, not in production. It should also + * be removed once the initial experiments have been completed. + */ +#define USE_RANDOM_DELAYS GNUNET_YES + +/** + * Should we generate a histogram with the time stamps of when we received + * NSE messages to disk? (for performance evaluation only, not useful in + * production). The associated code should also probably be removed + * once we're done with experiments. + */ +#define ENABLE_HISTOGRAM GNUNET_NO + +/** + * Over how many values do we calculate the weighted average? + */ +#define HISTORY_SIZE 64 + +/** + * Message priority to use. + */ +#define NSE_PRIORITY 5 + +#if FREEBSD +#define log2(a) (log(a)/log(2)) +#endif + +/** + * Amount of work required (W-bit collisions) for NSE proofs, in collision-bits. + */ +static unsigned long long nse_work_required; + +/** + * Interval for sending network size estimation flood requests. + */ +static struct GNUNET_TIME_Relative gnunet_nse_interval; + +/** + * Interval between proof find runs. + */ +static struct GNUNET_TIME_Relative proof_find_delay; + +#if ENABLE_HISTOGRAM +/** + * Handle for writing when we received messages to disk. + */ +static struct GNUNET_BIO_WriteHandle *wh; +#endif + + +/** + * Per-peer information. + */ +struct NSEPeerEntry +{ + + /** + * Core handle for sending messages to this peer. + */ + struct GNUNET_CORE_TransmitHandle *th; + + /** + * What is the identity of the peer? + */ + struct GNUNET_PeerIdentity id; + + /** + * Task scheduled to send message to this peer. + */ + GNUNET_SCHEDULER_TaskIdentifier transmit_task; + + /** + * Did we receive or send a message about the previous round + * to this peer yet? GNUNET_YES if the previous round has + * been taken care of. + */ + int previous_round; + +#if ENABLE_HISTOGRAM + + /** + * Amount of messages received from this peer on this round. + */ + unsigned int received_messages; + + /** + * Amount of messages transmitted to this peer on this round. + */ + unsigned int transmitted_messages; + + /** + * Which size did we tell the peer the network is? + */ + unsigned int last_transmitted_size; + +#endif + +}; + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Network size estimate reply; sent when "this" + * peer's timer has run out before receiving a + * valid reply from another peer. + */ +struct GNUNET_NSE_FloodMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD + */ + struct GNUNET_MessageHeader header; + + /** + * Number of hops this message has taken so far. + */ + uint32_t hop_count GNUNET_PACKED; + + /** + * Purpose. + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * The current timestamp value (which all + * peers should agree on). + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + + /** + * Number of matching bits between the hash + * of timestamp and the initiator's public + * key. + */ + uint32_t matching_bits GNUNET_PACKED; + + /** + * Public key of the originator. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + + /** + * Proof of work, causing leading zeros when hashed with pkey. + */ + uint64_t proof_of_work GNUNET_PACKED; + + /** + * Signature (over range specified in purpose). + */ + struct GNUNET_CRYPTO_RsaSignature signature; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Handle to our current configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Handle to the statistics service. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * Handle to the core service. + */ +static struct GNUNET_CORE_Handle *coreAPI; + +/** + * Map of all connected peers. + */ +static struct GNUNET_CONTAINER_MultiHashMap *peers; + +/** + * The current network size estimate. Number of bits matching on + * average thus far. + */ +static double current_size_estimate; + +/** + * The standard deviation of the last HISTORY_SIZE network + * size estimates. + */ +static double current_std_dev = NAN; + +/** + * Current hop counter estimate (estimate for network diameter). + */ +static uint32_t hop_count_max; + +/** + * Message for the next round, if we got any. + */ +static struct GNUNET_NSE_FloodMessage next_message; + +/** + * Array of recent size estimate messages. + */ +static struct GNUNET_NSE_FloodMessage size_estimate_messages[HISTORY_SIZE]; + +/** + * Index of most recent estimate. + */ +static unsigned int estimate_index; + +/** + * Number of valid entries in the history. + */ +static unsigned int estimate_count; + +/** + * Task scheduled to update our flood message for the next round. + */ +static GNUNET_SCHEDULER_TaskIdentifier flood_task; + +/** + * Task scheduled to compute our proof. + */ +static GNUNET_SCHEDULER_TaskIdentifier proof_task; + +/** + * Notification context, simplifies client broadcasts. + */ +static struct GNUNET_SERVER_NotificationContext *nc; + +/** + * The next major time. + */ +static struct GNUNET_TIME_Absolute next_timestamp; + +/** + * The current major time. + */ +static struct GNUNET_TIME_Absolute current_timestamp; + +/** + * The public key of this peer. + */ +static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; + +/** + * The private key of this peer. + */ +static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; + +/** + * The peer identity of this peer. + */ +static struct GNUNET_PeerIdentity my_identity; + +/** + * Proof of work for this peer. + */ +static uint64_t my_proof; + + +/** + * Initialize a message to clients with the current network + * size estimate. + * + * @param em message to fill in + */ +static void +setup_estimate_message (struct GNUNET_NSE_ClientMessage *em) +{ + unsigned int i; + unsigned int j; + double mean; + double sum; + double std_dev; + double variance; + double val; + double nsize; + +#define WEST 1 + /* Weighted incremental algorithm for stddev according to West (1979) */ +#if WEST + double sumweight; + double weight; + double q; + double r; + double temp; + + mean = 0.0; + sum = 0.0; + sumweight = 0.0; + variance = 0.0; + for (i = 0; i < estimate_count; i++) + { + j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE; + val = htonl (size_estimate_messages[j].matching_bits); + weight = estimate_count + 1 - i; + + temp = weight + sumweight; + q = val - mean; + r = q * weight / temp; + mean += r; + sum += sumweight * q * r; + sumweight = temp; + } + if (estimate_count > 0) + variance = (sum / sumweight) * estimate_count / (estimate_count - 1.0); +#else + /* trivial version for debugging */ + double vsq; + + /* non-weighted trivial version */ + sum = 0.0; + vsq = 0.0; + variance = 0.0; + mean = 0.0; + + for (i = 0; i < estimate_count; i++) + { + j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE; + val = htonl (size_estimate_messages[j].matching_bits); + sum += val; + vsq += val * val; + } + if (0 != estimate_count) + { + mean = sum / estimate_count; + variance = (vsq - mean * sum) / (estimate_count - 1.0); // terrible for numerical stability... + } +#endif + if (variance >= 0) + std_dev = sqrt (variance); + else + std_dev = variance; /* must be infinity due to estimate_count == 0 */ + current_std_dev = std_dev; + current_size_estimate = mean; + + em->header.size = htons (sizeof (struct GNUNET_NSE_ClientMessage)); + em->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE); + em->reserved = htonl (0); + em->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + double se = mean - 0.332747; + nsize = log2 (GNUNET_CONTAINER_multihashmap_size (peers) + 1); + em->size_estimate = GNUNET_hton_double (GNUNET_MAX (se, nsize)); + em->std_deviation = GNUNET_hton_double (std_dev); + GNUNET_STATISTICS_set (stats, "# nodes in the network (estimate)", + (uint64_t) pow (2, mean - 1.0 / 3.0), GNUNET_NO); +} + + +/** + * Handler for START message from client, triggers an + * immediate current network estimate notification. + * Also, we remember the client for updates upon future + * estimate measurements. + * + * @param cls unused + * @param client who sent the message + * @param message the message received + */ +static void +handle_start_message (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_NSE_ClientMessage em; + +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received START message from client\n"); +#endif + GNUNET_SERVER_notification_context_add (nc, client); + setup_estimate_message (&em); + GNUNET_SERVER_notification_context_unicast (nc, client, &em.header, + GNUNET_YES); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * How long should we delay a message to go the given number of + * matching bits? + * + * @param matching_bits number of matching bits to consider + */ +static double +get_matching_bits_delay (uint32_t matching_bits) +{ + /* Calculated as: S + f/2 - (f / pi) * (atan(x - p')) */ + // S is next_timestamp (ignored in return value) + // f is frequency (gnunet_nse_interval) + // x is matching_bits + // p' is current_size_estimate + return ((double) gnunet_nse_interval.rel_value / (double) 2.0) - + ((gnunet_nse_interval.rel_value / M_PI) * + atan (matching_bits - current_size_estimate)); +} + + +/** + * What delay randomization should we apply for a given number of matching bits? + * + * @param matching_bits number of matching bits + * @return random delay to apply + */ +static struct GNUNET_TIME_Relative +get_delay_randomization (uint32_t matching_bits) +{ +#if USE_RANDOM_DELAYS + struct GNUNET_TIME_Relative ret; + uint32_t i; + double d; + + d = get_matching_bits_delay (matching_bits); + i = (uint32_t) (d / (double) (hop_count_max + 1)); +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Randomizing flood using latencies up to %u ms\n", + (unsigned int) i); +#endif + ret.rel_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, i + 1); + return ret; +#else + return GNUNET_TIME_UNIT_ZERO; +#endif +} + + +/** + * Get the number of matching bits that the given timestamp has to the given peer ID. + * + * @param timestamp time to generate key + * @param id peer identity to compare with + * @return number of matching bits + */ +static uint32_t +get_matching_bits (struct GNUNET_TIME_Absolute timestamp, + const struct GNUNET_PeerIdentity *id) +{ + GNUNET_HashCode timestamp_hash; + + GNUNET_CRYPTO_hash (×tamp.abs_value, sizeof (timestamp.abs_value), + ×tamp_hash); + return GNUNET_CRYPTO_hash_matching_bits (×tamp_hash, &id->hashPubKey); +} + + +/** + * Get the transmission delay that should be applied for a + * particular round. + * + * @param round_offset -1 for the previous round (random delay between 0 and 50ms) + * 0 for the current round (based on our proximity to time key) + * @return delay that should be applied + */ +static struct GNUNET_TIME_Relative +get_transmit_delay (int round_offset) +{ + struct GNUNET_TIME_Relative ret; + struct GNUNET_TIME_Absolute tgt; + double dist_delay; + uint32_t matching_bits; + + switch (round_offset) + { + case -1: + /* previous round is randomized between 0 and 50 ms */ +#if USE_RANDOM_DELAYS + ret.rel_value = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 50); +#else + ret = GNUNET_TIME_UNIT_ZERO; +#endif +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting previous round behind schedule in %llu ms\n", + (unsigned long long) ret.rel_value); +#endif + return ret; + case 0: + /* current round is based on best-known matching_bits */ + matching_bits = + ntohl (size_estimate_messages[estimate_index].matching_bits); + dist_delay = get_matching_bits_delay (matching_bits); + dist_delay += get_delay_randomization (matching_bits).rel_value; + ret.rel_value = (uint64_t) dist_delay; +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "For round %llu, delay for %u matching bits is %llu ms\n", + (unsigned long long) current_timestamp.abs_value, + (unsigned int) matching_bits, + (unsigned long long) ret.rel_value); +#endif + /* now consider round start time and add delay to it */ + tgt = GNUNET_TIME_absolute_add (current_timestamp, ret); + return GNUNET_TIME_absolute_get_remaining (tgt); + } + GNUNET_break (0); + return GNUNET_TIME_UNIT_FOREVER_REL; +} + + +/** + * Task that triggers a NSE P2P transmission. + * + * @param cls the 'struct NSEPeerEntry' + * @param tc scheduler context + */ +static void +transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Called when core is ready to send a message we asked for + * out to the destination. + * + * @param cls closure (NULL) + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_ready (void *cls, size_t size, void *buf) +{ + struct NSEPeerEntry *peer_entry = cls; + unsigned int idx; + + peer_entry->th = NULL; + if (buf == NULL) + { + /* client disconnected */ + return 0; + } + GNUNET_assert (size >= sizeof (struct GNUNET_NSE_FloodMessage)); + idx = estimate_index; + if (peer_entry->previous_round == GNUNET_NO) + { + idx = (idx + HISTORY_SIZE - 1) % HISTORY_SIZE; + peer_entry->previous_round = GNUNET_YES; + peer_entry->transmit_task = + GNUNET_SCHEDULER_add_delayed (get_transmit_delay (0), &transmit_task_cb, + peer_entry); + } + if ((ntohl (size_estimate_messages[idx].hop_count) == 0) && + (GNUNET_SCHEDULER_NO_TASK != proof_task)) + { + GNUNET_STATISTICS_update (stats, + "# flood messages not generated (no proof yet)", + 1, GNUNET_NO); + return 0; + } + if (ntohs (size_estimate_messages[idx].header.size) == 0) + { + GNUNET_STATISTICS_update (stats, + "# flood messages not generated (lack of history)", + 1, GNUNET_NO); + return 0; + } +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "In round %llu, sending to `%s' estimate with %u bits\n", + (unsigned long long) + GNUNET_TIME_absolute_ntoh (size_estimate_messages[idx]. + timestamp).abs_value, + GNUNET_i2s (&peer_entry->id), + (unsigned int) ntohl (size_estimate_messages[idx].matching_bits)); +#endif + if (ntohl (size_estimate_messages[idx].hop_count) == 0) + GNUNET_STATISTICS_update (stats, "# flood messages started", 1, GNUNET_NO); + GNUNET_STATISTICS_update (stats, "# flood messages transmitted", 1, + GNUNET_NO); +#if ENABLE_HISTOGRAM + peer_entry->transmitted_messages++; + peer_entry->last_transmitted_size = + ntohl(size_estimate_messages[idx].matching_bits); +#endif + memcpy (buf, &size_estimate_messages[idx], + sizeof (struct GNUNET_NSE_FloodMessage)); + return sizeof (struct GNUNET_NSE_FloodMessage); +} + + +/** + * Task that triggers a NSE P2P transmission. + * + * @param cls the 'struct NSEPeerEntry' + * @param tc scheduler context + */ +static void +transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NSEPeerEntry *peer_entry = cls; + + peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (NULL == peer_entry->th); + peer_entry->th = + GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_NO, NSE_PRIORITY, + GNUNET_TIME_UNIT_FOREVER_REL, + &peer_entry->id, + sizeof (struct + GNUNET_NSE_FloodMessage), + &transmit_ready, peer_entry); +} + + +/** + * We've sent on our flood message or one that we received which was + * validated and closer than ours. Update the global list of recent + * messages and the average. Also re-broadcast the message to any + * clients. + */ +static void +update_network_size_estimate () +{ + struct GNUNET_NSE_ClientMessage em; + + setup_estimate_message (&em); + GNUNET_SERVER_notification_context_broadcast (nc, &em.header, GNUNET_YES); +} + + +/** + * Setup a flood message in our history array at the given + * slot offset for the given timestamp. + * + * @param slot index to use + * @param ts timestamp to use + */ +static void +setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts) +{ + struct GNUNET_NSE_FloodMessage *fm; + uint32_t matching_bits; + + matching_bits = get_matching_bits (ts, &my_identity); + fm = &size_estimate_messages[slot]; + fm->header.size = htons (sizeof (struct GNUNET_NSE_FloodMessage)); + fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD); + fm->hop_count = htonl (0); + fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND); + fm->purpose.size = + htonl (sizeof (struct GNUNET_NSE_FloodMessage) - + sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) - + sizeof (struct GNUNET_CRYPTO_RsaSignature)); + fm->matching_bits = htonl (matching_bits); + fm->timestamp = GNUNET_TIME_absolute_hton (ts); + fm->pkey = my_public_key; + fm->proof_of_work = my_proof; + if (nse_work_required > 0) + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (my_private_key, &fm->purpose, + &fm->signature)); + else + memset (&fm->signature, 0, sizeof (fm->signature)); +} + + +/** + * Schedule transmission for the given peer for the current round based + * on what we know about the desired delay. + * + * @param cls unused + * @param key hash of peer identity + * @param value the 'struct NSEPeerEntry' + * @return GNUNET_OK (continue to iterate) + */ +static int +schedule_current_round (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct NSEPeerEntry *peer_entry = value; + struct GNUNET_TIME_Relative delay; + + if (peer_entry->th != NULL) + { + peer_entry->previous_round = GNUNET_NO; + return GNUNET_OK; + } + if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (peer_entry->transmit_task); + peer_entry->previous_round = GNUNET_NO; + } +#if ENABLE_HISTOGRAM + if (peer_entry->received_messages > 1) + GNUNET_STATISTICS_update(stats, "# extra messages", + peer_entry->received_messages - 1, GNUNET_NO); + peer_entry->transmitted_messages = 0; + peer_entry->last_transmitted_size = 0; + peer_entry->received_messages = 0; +#endif + delay = + get_transmit_delay ((peer_entry->previous_round == GNUNET_NO) ? -1 : 0); + peer_entry->transmit_task = + GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry); + return GNUNET_OK; +} + + +/** + * Update our flood message to be sent (and our timestamps). + * + * @param cls unused + * @param tc context for this message + */ +static void +update_flood_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TIME_Relative offset; + unsigned int i; + + flood_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + offset = GNUNET_TIME_absolute_get_remaining (next_timestamp); + if (0 != offset.rel_value) + { + /* somehow run early, delay more */ + flood_task = + GNUNET_SCHEDULER_add_delayed (offset, &update_flood_message, NULL); + return; + } + current_timestamp = next_timestamp; + next_timestamp = + GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval); + estimate_index = (estimate_index + 1) % HISTORY_SIZE; + if (estimate_count < HISTORY_SIZE) + estimate_count++; + if (next_timestamp.abs_value == + GNUNET_TIME_absolute_ntoh (next_message.timestamp).abs_value) + { + /* we received a message for this round way early, use it! */ + size_estimate_messages[estimate_index] = next_message; + size_estimate_messages[estimate_index].hop_count = + htonl (1 + ntohl (next_message.hop_count)); + } + else + setup_flood_message (estimate_index, current_timestamp); + next_message.matching_bits = htonl (0); /* reset for 'next' round */ + hop_count_max = 0; + for (i = 0; i < HISTORY_SIZE; i++) + hop_count_max = + GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count), hop_count_max); + GNUNET_CONTAINER_multihashmap_iterate (peers, &schedule_current_round, NULL); + flood_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (next_timestamp), &update_flood_message, + NULL); +} + + +/** + * Count the leading zeroes in hash. + * + * @param hash + * @return the number of leading zero bits. + */ +static unsigned int +count_leading_zeroes (const GNUNET_HashCode * hash) +{ + unsigned int hash_count; + + hash_count = 0; + while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count))) + hash_count++; + return hash_count; +} + + +/** + * Check whether the given public key + * and integer are a valid proof of work. + * + * @param pkey the public key + * @param val the integer + * + * @return GNUNET_YES if valid, GNUNET_NO if not + */ +static int +check_proof_of_work (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey, + uint64_t val) +{ + char buf[sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + sizeof (val)]; + GNUNET_HashCode result; + + memcpy (buf, &val, sizeof (val)); + memcpy (&buf[sizeof (val)], pkey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + GNUNET_CRYPTO_hash (buf, sizeof (buf), &result); + return (count_leading_zeroes (&result) >= + nse_work_required) ? GNUNET_YES : GNUNET_NO; +} + + +/** + * Write our current proof to disk. + */ +static void +write_proof () +{ + char *proof; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof)) + return; + if (sizeof (my_proof) != + GNUNET_DISK_fn_write (proof, &my_proof, sizeof (my_proof), + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", proof); + GNUNET_free (proof); + +} + + +/** + * Find our proof of work. + * + * @param cls closure (unused) + * @param tc task context + */ +static void +find_proof (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#define ROUND_SIZE 10 + uint64_t counter; + char buf[sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + sizeof (uint64_t)]; + GNUNET_HashCode result; + unsigned int i; + + proof_task = GNUNET_SCHEDULER_NO_TASK; + memcpy (&buf[sizeof (uint64_t)], &my_public_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + i = 0; + counter = my_proof; + while ((counter != UINT64_MAX) && (i < ROUND_SIZE)) + { + memcpy (buf, &counter, sizeof (uint64_t)); + GNUNET_CRYPTO_hash (buf, sizeof (buf), &result); + if (nse_work_required <= count_leading_zeroes (&result)) + { + my_proof = counter; +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Proof of work found: %llu!\n", + (unsigned long long) GNUNET_ntohll (counter)); +#endif + write_proof (); + setup_flood_message (estimate_index, current_timestamp); + return; + } + counter++; + i++; + } + if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE)) + { +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing proofs currently at %llu\n", + (unsigned long long) counter); +#endif + /* remember progress every 100 rounds */ + my_proof = counter; + write_proof (); + } + else + { + my_proof = counter; + } + proof_task = + GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay, + GNUNET_SCHEDULER_PRIORITY_IDLE, + &find_proof, NULL); +} + + +/** + * An incoming flood message has been received which claims + * to have more bits matching than any we know in this time + * period. Verify the signature and/or proof of work. + * + * @param incoming_flood the message to verify + * + * @return GNUNET_YES if the message is verified + * GNUNET_NO if the key/signature don't verify + */ +static int +verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood) +{ + if (GNUNET_YES != + check_proof_of_work (&incoming_flood->pkey, + incoming_flood->proof_of_work)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Proof of work invalid: %llu!\n"), + (unsigned long long) + GNUNET_ntohll (incoming_flood->proof_of_work)); + GNUNET_break_op (0); + return GNUNET_NO; + } + if ((nse_work_required > 0) && + (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND, + &incoming_flood->purpose, + &incoming_flood->signature, + &incoming_flood->pkey))) + { + GNUNET_break_op (0); + return GNUNET_NO; + } + return GNUNET_YES; +} + + +/** + * Update transmissions for the given peer for the current round based + * on updated proximity information. + * + * @param cls peer entry to exclude from updates + * @param key hash of peer identity + * @param value the 'struct NSEPeerEntry' + * @return GNUNET_OK (continue to iterate) + */ +static int +update_flood_times (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct NSEPeerEntry *exclude = cls; + struct NSEPeerEntry *peer_entry = value; + struct GNUNET_TIME_Relative delay; + + if (peer_entry->th != NULL) + return GNUNET_OK; /* already active */ + if (peer_entry == exclude) + return GNUNET_OK; /* trigger of the update */ + if (peer_entry->previous_round == GNUNET_NO) + { + /* still stuck in previous round, no point to update, check that + * we are active here though... */ + GNUNET_break (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK); + return GNUNET_OK; + } + if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (peer_entry->transmit_task); + peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK; + } + delay = get_transmit_delay (0); + peer_entry->transmit_task = + GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry); + return GNUNET_OK; +} + + +/** + * Core handler for size estimate flooding messages. + * + * @param cls closure unused + * @param message message + * @param peer peer identity this message is from (ignored) + * @param atsi performance data (ignored) + * @param atsi_count number of records in 'atsi' + */ +static int +handle_p2p_size_estimate (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + const struct GNUNET_NSE_FloodMessage *incoming_flood; + struct GNUNET_TIME_Absolute ts; + struct NSEPeerEntry *peer_entry; + uint32_t matching_bits; + unsigned int idx; + +#if ENABLE_HISTOGRAM + if (NULL != wh) + GNUNET_BIO_write_int64 (wh, GNUNET_TIME_absolute_get ().abs_value); +#endif + incoming_flood = (const struct GNUNET_NSE_FloodMessage *) message; + GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO); + matching_bits = ntohl (incoming_flood->matching_bits); +#if DEBUG_NSE + { + char origin[5]; + char pred[5]; + struct GNUNET_PeerIdentity os; + + GNUNET_CRYPTO_hash (&incoming_flood->pkey, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &os.hashPubKey); + GNUNET_snprintf (origin, sizeof (origin), "%s", GNUNET_i2s (&os)); + GNUNET_snprintf (pred, sizeof (pred), "%s", GNUNET_i2s (peer)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Flood at %llu from `%s' via `%s' at `%s' with bits %u\n", + (unsigned long long) + GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value, + origin, pred, GNUNET_i2s (&my_identity), + (unsigned int) matching_bits); + } +#endif + + peer_entry = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); + if (NULL == peer_entry) + { + GNUNET_break (0); + return GNUNET_OK; + } +#if ENABLE_HISTOGRAM + peer_entry->received_messages++; + if (peer_entry->transmitted_messages > 0 && + peer_entry->last_transmitted_size >= matching_bits) + GNUNET_STATISTICS_update(stats, "# cross messages", 1, GNUNET_NO); +#endif + + ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp); + + if (ts.abs_value == current_timestamp.abs_value) + idx = estimate_index; + else if (ts.abs_value == + current_timestamp.abs_value - gnunet_nse_interval.rel_value) + idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE; + else if (ts.abs_value == + next_timestamp.abs_value - gnunet_nse_interval.rel_value) + { + if (matching_bits <= ntohl (next_message.matching_bits)) + return GNUNET_OK; /* ignore, simply too early/late */ + if (GNUNET_YES != verify_message_crypto (incoming_flood)) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + next_message = *incoming_flood; + return GNUNET_OK; + } + else + { + GNUNET_STATISTICS_update (stats, + "# flood messages discarded (clock skew too large)", + 1, GNUNET_NO); + return GNUNET_OK; + } + if (0 == (memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))) + { + /* send to self, update our own estimate IF this also comes from us! */ + if (0 == + memcmp (&incoming_flood->pkey, &my_public_key, sizeof (my_public_key))) + update_network_size_estimate (); + return GNUNET_OK; + } + if (matching_bits == ntohl (size_estimate_messages[idx].matching_bits)) + { + /* Cancel transmission in the other direction, as this peer clearly has + up-to-date information already. Even if we didn't talk to this peer in + the previous round, we should no longer send it stale information as it + told us about the current round! */ + peer_entry->previous_round = GNUNET_YES; + if (idx != estimate_index) + { + /* do not transmit information for the previous round to this peer + anymore (but allow current round) */ + return GNUNET_OK; + } + /* got up-to-date information for current round, cancel transmission to + * this peer altogether */ + if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task) + { + GNUNET_SCHEDULER_cancel (peer_entry->transmit_task); + peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK; + } + if (peer_entry->th != NULL) + { + GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th); + peer_entry->th = NULL; + } + return GNUNET_OK; + } + if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits)) + { + if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES)) + peer_entry->previous_round = GNUNET_NO; + /* push back our result now, that peer is spreading bad information... */ + if (NULL == peer_entry->th) + { + if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (peer_entry->transmit_task); + peer_entry->transmit_task = + GNUNET_SCHEDULER_add_now (&transmit_task_cb, peer_entry); + } + /* Not closer than our most recent message, no need to do work here */ + GNUNET_STATISTICS_update (stats, + "# flood messages ignored (had closer already)", + 1, GNUNET_NO); + return GNUNET_OK; + } + if (GNUNET_YES != verify_message_crypto (incoming_flood)) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + GNUNET_assert (matching_bits > + ntohl (size_estimate_messages[idx].matching_bits)); + /* cancel transmission from us to this peer for this round */ + if (idx == estimate_index) + { + /* cancel any activity for current round */ + if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (peer_entry->transmit_task); + peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK; + } + if (peer_entry->th != NULL) + { + GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th); + peer_entry->th = NULL; + } + } + else + { + /* cancel previous round only */ + peer_entry->previous_round = GNUNET_YES; + } + size_estimate_messages[idx] = *incoming_flood; + size_estimate_messages[idx].hop_count = + htonl (ntohl (incoming_flood->hop_count) + 1); + hop_count_max = + GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max); + GNUNET_STATISTICS_set (stats, + "# estimated network diameter", + hop_count_max, GNUNET_NO); + + /* have a new, better size estimate, inform clients */ + update_network_size_estimate (); + + /* flood to rest */ + GNUNET_CONTAINER_multihashmap_iterate (peers, &update_flood_times, + peer_entry); + return GNUNET_OK; +} + + + +/** + * Method called whenever a peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + */ +static void +handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct NSEPeerEntry *peer_entry; + +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected to us\n", + GNUNET_i2s (peer)); +#endif + peer_entry = GNUNET_malloc (sizeof (struct NSEPeerEntry)); + peer_entry->id = *peer; + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey, + peer_entry, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + peer_entry->transmit_task = + GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1), &transmit_task_cb, + peer_entry); + GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO); +} + + +/** + * Method called whenever a peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct NSEPeerEntry *pos; + +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected from us\n", + GNUNET_i2s (peer)); +#endif + pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); + if (NULL == pos) + { + GNUNET_break (0); + return; + } + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (peers, &peer->hashPubKey, + pos)); + if (pos->transmit_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (pos->transmit_task); + if (pos->th != NULL) + { + GNUNET_CORE_notify_transmit_ready_cancel (pos->th); + pos->th = NULL; + } + GNUNET_free (pos); + GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO); +} + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (flood_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (flood_task); + flood_task = GNUNET_SCHEDULER_NO_TASK; + } + if (proof_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (proof_task); + proof_task = GNUNET_SCHEDULER_NO_TASK; + write_proof (); /* remember progress */ + } + if (nc != NULL) + { + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; + } + if (coreAPI != NULL) + { + GNUNET_CORE_disconnect (coreAPI); + coreAPI = NULL; + } + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + stats = NULL; + } + if (peers != NULL) + { + GNUNET_CONTAINER_multihashmap_destroy (peers); + peers = NULL; + } + if (my_private_key != NULL) + { + GNUNET_CRYPTO_rsa_key_free (my_private_key); + my_private_key = NULL; + } +#if ENABLE_HISTOGRAM + if (wh != NULL) + { + GNUNET_BIO_write_close (wh); + wh = NULL; + } +#endif +} + + +/** + * Called on core init/fail. + * + * @param cls service closure + * @param server handle to the server for this service + * @param identity the public identity of this peer + */ +static void +core_init (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *identity) +{ + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute prev_time; + + if (server == NULL) + { +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to core FAILED!\n"); +#endif + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_assert (0 == + memcmp (&my_identity, identity, + sizeof (struct GNUNET_PeerIdentity))); + now = GNUNET_TIME_absolute_get (); + current_timestamp.abs_value = + (now.abs_value / gnunet_nse_interval.rel_value) * + gnunet_nse_interval.rel_value; + next_timestamp = + GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval); + estimate_index = HISTORY_SIZE - 1; + estimate_count = 0; + if (GNUNET_YES == check_proof_of_work (&my_public_key, my_proof)) + { + prev_time.abs_value = + current_timestamp.abs_value - gnunet_nse_interval.rel_value; + setup_flood_message (estimate_index, prev_time); + estimate_count++; + } + flood_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (next_timestamp), &update_flood_message, + NULL); +} + + +/** + * Handle network size estimate clients. + * + * @param cls closure + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + char *keyfile; + char *proof; + + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START, + sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} + }; + static const struct GNUNET_CORE_MessageHandler core_handlers[] = { + {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, + sizeof (struct GNUNET_NSE_FloodMessage)}, + {NULL, 0, 0} + }; + cfg = c; + + if ((GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "INTERVAL", + &gnunet_nse_interval)) || + (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "WORKDELAY", + &proof_find_delay)) || + (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS", + &nse_work_required))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("NSE service is lacking key configuration settings. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (nse_work_required >= sizeof (GNUNET_HashCode) * 8) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Invalid work requirement for NSE service. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", + &keyfile)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("NSE service is lacking key configuration settings. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_free (keyfile); + if (my_private_key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("NSE service could not access hostkey. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); + GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), + &my_identity.hashPubKey); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("NSE service is lacking key configuration settings. Exiting.\n")); + if (my_private_key != NULL) + { + GNUNET_CRYPTO_rsa_key_free (my_private_key); + my_private_key = NULL; + } + GNUNET_SCHEDULER_shutdown (); + return; + } + if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) || + (sizeof (my_proof) != + GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof)))) + my_proof = 0; + GNUNET_free (proof); + proof_task = + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, + &find_proof, NULL); + + peers = GNUNET_CONTAINER_multihashmap_create (128); + GNUNET_SERVER_add_handlers (server, handlers); + nc = GNUNET_SERVER_notification_context_create (server, 1); + /* Connect to core service and register core handlers */ + coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */ + 1, NULL, /* Closure passed to functions */ + &core_init, /* Call core_init once connected */ + &handle_core_connect, /* Handle connects */ + &handle_core_disconnect, /* Handle disconnects */ + NULL, /* Don't want notified about all incoming messages */ + GNUNET_NO, /* For header only inbound notification */ + NULL, /* Don't want notified about all outbound messages */ + GNUNET_NO, /* For header only outbound notification */ + core_handlers); /* Register these handlers */ + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); +#if ENABLE_HISTOGRAM + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "HISTOGRAM", &proof)) + { + wh = GNUNET_BIO_write_open (proof); + GNUNET_free (proof); + } +#endif + if (coreAPI == NULL) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + stats = GNUNET_STATISTICS_create ("nse", cfg); +} + + +/** + * The main function for the statistics service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "nse", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-service-nse.c */ diff --git a/src/nse/nse.conf.in b/src/nse/nse.conf.in new file mode 100644 index 0000000..b04f5ac --- /dev/null +++ b/src/nse/nse.conf.in @@ -0,0 +1,25 @@ +[nse] +AUTOSTART = YES +@UNIXONLY@ PORT = 2097 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-nse +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/test-nse-service-nse.unix +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +PROOFFILE = $SERVICEHOME/.nse-proof +HISTOGRAM = $SERVICEHOME/nse-history.log + +# How 'slowly' should the proof-of-work be constructed (delay +# between rounds); sane values between 0 and ~1000. +WORKDELAY = 5 ms + +# Note: changing any of the values below will make this peer +# completely incompatible with other peers! +INTERVAL = 1 h +# 26 is about 10 minutes on a modern i7 (single-core) +WORKBITS = 26 + diff --git a/src/nse/nse.h b/src/nse/nse.h new file mode 100644 index 0000000..de8bc5a --- /dev/null +++ b/src/nse/nse.h @@ -0,0 +1,78 @@ +/* + This file is part of GNUnet. + (C) 2001-2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Nathan Evans + * @file nse/nse.h + * + * @brief Common type definitions for the network size estimation + * service and API. + */ +#ifndef NSE_H +#define NSE_H + +#include "gnunet_common.h" + +/** + * Generate debug-level log messages? + */ +#define DEBUG_NSE GNUNET_EXTRA_LOGGING + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Network size estimate sent from the service + * to clients. Contains the current size estimate + * (or 0 if none has been calculated) and the + * standard deviation of known estimates. + * + */ +struct GNUNET_NSE_ClientMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_NSE_ESTIMATE + */ + struct GNUNET_MessageHeader header; + + /** + * For alignment. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Timestamp at which the server received the message. + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + + /** + * The current estimated network size. + */ + double size_estimate GNUNET_PACKED; + + /** + * The standard deviation (rounded down + * to the nearest integer) of size + * estimations. + */ + double std_deviation GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/nse/nse_api.c b/src/nse/nse_api.c new file mode 100644 index 0000000..4d5f6bb --- /dev/null +++ b/src/nse/nse_api.c @@ -0,0 +1,298 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file nse/nse_api.c + * @brief api to get information from the network size estimation service + * @author Nathan Evans + */ +#include "platform.h" +#include "gnunet_client_lib.h" +#include "gnunet_constants.h" +#include "gnunet_container_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_nse_service.h" +#include "nse.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "nse-api",__VA_ARGS__) + +/** + * Handle for the service. + */ +struct GNUNET_NSE_Handle +{ + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Socket (if available). + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Currently pending transmission request. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Task doing exponential back-off trying to reconnect. + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * Time for next connect retry. + */ + struct GNUNET_TIME_Relative reconnect_delay; + + /** + * Callback function to call when message is received. + */ + GNUNET_NSE_Callback recv_cb; + + /** + * Closure to pass to callback. + */ + void *recv_cb_cls; + +}; + + +/** + * Try again to connect to network size estimation service. + * + * @param cls the handle to the transport service + * @param tc scheduler context + */ +static void +reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +message_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_NSE_Handle *h = cls; + const struct GNUNET_NSE_ClientMessage *client_msg; + + if (msg == NULL) + { + /* Error, timeout, death */ + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->client = NULL; + h->reconnect_task = + GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h); + return; + } + if ((ntohs (msg->size) != sizeof (struct GNUNET_NSE_ClientMessage)) || + (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_NSE_ESTIMATE)) + { + GNUNET_break (0); + return; + } + client_msg = (const struct GNUNET_NSE_ClientMessage *) msg; + h->recv_cb (h->recv_cb_cls, GNUNET_TIME_absolute_ntoh (client_msg->timestamp), + GNUNET_ntoh_double (client_msg->size_estimate), + GNUNET_ntoh_double (client_msg->std_deviation)); + GNUNET_CLIENT_receive (h->client, &message_handler, h, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + + +/** + * Reschedule a connect attempt to the service. + * + * @param h transport service to reconnect + */ +static void +reschedule_connect (struct GNUNET_NSE_Handle *h) +{ + GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); + + if (NULL != h->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } + if (NULL != h->client) + { + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->client = NULL; + } + +#if DEBUG_NSE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling task to reconnect to nse service in %llu ms.\n", + h->reconnect_delay.rel_value); +#endif + h->reconnect_task = + GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h); + if (h->reconnect_delay.rel_value == 0) + { + h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; + } + else + { + h->reconnect_delay = GNUNET_TIME_relative_multiply (h->reconnect_delay, 2); + h->reconnect_delay = + GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, h->reconnect_delay); + } +} + + +/** + * Transmit START message to service. + * + * @param cls unused + * @param size number of bytes available in buf + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +send_start (void *cls, size_t size, void *buf) +{ + struct GNUNET_NSE_Handle *h = cls; + struct GNUNET_MessageHeader *msg; + + h->th = NULL; + if (buf == NULL) + { + /* Connect error... */ +#if DEBUG_NSE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Shutdown while trying to transmit `%s' request.\n", "START"); +#endif + reschedule_connect (h); + return 0; + } +#if DEBUG_NSE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "START"); +#endif + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + + msg = (struct GNUNET_MessageHeader *) buf; + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + msg->type = htons (GNUNET_MESSAGE_TYPE_NSE_START); + GNUNET_CLIENT_receive (h->client, &message_handler, h, + GNUNET_TIME_UNIT_FOREVER_REL); + return sizeof (struct GNUNET_MessageHeader); +} + + +/** + * Try again to connect to network size estimation service. + * + * @param cls the handle to the transport service + * @param tc scheduler context + */ +static void +reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NSE_Handle *h = cls; + + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + /* shutdown, just give up */ + return; + } +#if DEBUG_NSE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Connecting to network size estimation service.\n"); +#endif + GNUNET_assert (h->client == NULL); + h->client = GNUNET_CLIENT_connect ("nse", h->cfg); + GNUNET_assert (h->client != NULL); + + h->th = + GNUNET_CLIENT_notify_transmit_ready (h->client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, &send_start, h); + GNUNET_assert (h->th != NULL); +} + + +/** + * Connect to the network size estimation service. + * + * @param cfg the configuration to use + * @param func funtion to call with network size estimate + * @param func_cls closure to pass for network size estimate callback + * + * @return handle to use + */ +struct GNUNET_NSE_Handle * +GNUNET_NSE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_NSE_Callback func, void *func_cls) +{ + struct GNUNET_NSE_Handle *ret; + + GNUNET_assert (func != NULL); + ret = GNUNET_malloc (sizeof (struct GNUNET_NSE_Handle)); + ret->cfg = cfg; + ret->recv_cb = func; + ret->recv_cb_cls = func_cls; + ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO; + ret->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, ret); + return ret; +} + + +/** + * Disconnect from network size estimation service + * + * @param h handle to destroy + */ +void +GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h) +{ + GNUNET_assert (h != NULL); + if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (h->reconnect_task); + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + if (h->th != NULL) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } + if (h->client != NULL) + { + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->client = NULL; + } + GNUNET_free (h); +} + +/* end of nse_api.c */ diff --git a/src/nse/nse_profiler_test.conf b/src/nse/nse_profiler_test.conf new file mode 100644 index 0000000..964cceb --- /dev/null +++ b/src/nse/nse_profiler_test.conf @@ -0,0 +1,170 @@ +[PATHS] +SERVICEHOME = /tmp/nse-profiler/ +DEFAULTCONFIG = nse_profiler_test.conf + +[nse] +PORT = 0 +UNIXPATH = /tmp/test-nse-service-nse.unix +BINARY = gnunet-service-nse +#BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/nse/.libs/gnunet-service-nse +#PREFIX = valgrind --leak-check=full --log-file=valgrind_nse.%p +AUTOSTART = YES +DEBUG = YES +CONFIG = $DEFAULTCONFIG +# Overriding network settings for faster testing (do NOT use +# these values in production just because they are here) +WORKDELAY = 60 s +INTERVAL = 30 s +WORKBITS = 0 +PROOFFILE = $SERVICEHOME/nse.proof + +[arm] +PORT = 0 +DEFAULTSERVICES = core +UNIXPATH = /tmp/test-nse-service-arm.unix +#DEBUG = YES + +[statistics] +AUTOSTART = YES +PORT=0 + +[fs] +AUTOSTART = NO +PORT=0 + +[datastore] +AUTOSTART = NO +PORT = 0 + +[dht] +AUTOSTART = NO +PORT = 0 + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[transport] +PORT = 0 +plugins = unix + +[transport-unix] +PORT = 1 + +[transport-tcp] +PORT = 0 + +[transport-udp] +PORT = 0 + +[transport-http] +PORT = 0 + +[transport-https] +PORT = 0 + +[core] +AUTOSTART = YES +PORT = 0 + +[peerinfo] +AUTOSTART = YES +PORT = 0 + +[dns] +AUTOSTART = NO + +[topology] +AUTOSTART = NO + +[dv] +AUTOSTART = NO + +[resolver] +PORT = 0 + +[ats] +PORT = 0 + +[mesh] +AUTOSTART = NO + +[chat] +AUTOSTART = NO + +[gns] +AUTOSTART = NO + +[vpn] +AUTOSTART = NO + +[testing] +NUM_PEERS = 4000 +WEAKRANDOM = YES +TOPOLOGY = NONE +#CONNECT_TOPOLOGY = SMALL_WORLD_RING +CONNECT_TOPOLOGY = ERDOS_RENYI +CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM +CONNECT_TOPOLOGY_OPTION_MODIFIER = 5 +# PERCENTAGE = 3 +PROBABILITY = .1 +F2F = NO +CONNECT_TIMEOUT = 360 s +CONNECT_ATTEMPTS = 3 +DEBUG = YES +#HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat +HOSTKEYSFILE = hostkeys.dat +MAX_CONCURRENT_SSH = 20 +USE_PROGRESSBARS = YES +PEERGROUP_TIMEOUT = 1000 s +TOPOLOGY_OUTPUT_FILE = nse_topo_4000_peers_initial +MAX_OUTSTANDING_CONNECTIONS = 100 +#SINGLE_PEERINFO_PER_HOST = YES +#NUM_PEERINFO_PER_HOST = 10 +#SINGLE_STATISTICS_PER_HOST = YES +#NUM_STATISTICS_PER_HOST = 10 +DELETE_FILES = NO +#SKEW_VARIANCE = 30000 + +[nse-profiler] +OUTPUT_FILE = nse_output_4000_peers.dat +TOPOLOGY_OUTPUT_FILE = nse_topo_4000_peers +DATA_OUTPUT_FILE = nse_stats_4000_peers +ROUND0 = 4000 +ROUND1 = 4000 +ROUND2 = 4000 +ROUND3 = 4000 +ROUND4 = 4000 +ROUND5 = 4000 +ROUND6 = 4000 +ROUND7 = 4000 +ROUND8 = 4000 +ROUND9 = 4000 +ROUND10 = 4000 +ROUND11 = 1000 +ROUND12 = 1000 +ROUND13 = 1000 +ROUND14 = 1000 +ROUND15 = 1000 +ROUND16 = 1000 +ROUND17 = 1000 +ROUND18 = 1000 +ROUND19 = 1000 +ROUND20 = 1000 +ROUND21 = 2000 +ROUND22 = 2000 +ROUND23 = 2000 +ROUND24 = 2000 +ROUND25 = 2000 +ROUND26 = 2000 +ROUND27 = 2000 +ROUND28 = 2000 +ROUND29 = 2000 +ROUND30 = 2000 +WAIT_TIME = 1920 s +CONNECTION_LIMIT = 10 diff --git a/src/nse/test_nse.conf b/src/nse/test_nse.conf new file mode 100644 index 0000000..48944c1 --- /dev/null +++ b/src/nse/test_nse.conf @@ -0,0 +1,77 @@ +[PATHS] +SERVICEHOME = /tmp/test-nse-multipeer/ +DEFAULTCONFIG = test_nse.conf + +[nse] +PORT = 22353 +UNIXPATH = /tmp/test-nse-service-nse.unix +BINARY = gnunet-service-nse +#BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/nse/.libs/gnunet-service-nse +#PREFIX = valgrind --leak-check=full --log-file=valgrind_nse.%p +AUTOSTART = YES +DEBUG = NO +CONFIG = $DEFAULTCONFIG +PROOFFILE = $SERVICEHOME/proof.nse +# Overriding network settings for faster testing (do NOT use +# these values in production just because they are here) +WORKDELAY = 1 ms +INTERVAL = 60 s +WORKBITS = 1 + +HISTOGRAM = $SERVICEHOME/nse-histogram + + +[arm] +PORT = 22354 +DEFAULTSERVICES = nse core +UNIXPATH = /tmp/test-nse-service-arm.unix +#DEBUG = YES + +[fs] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[dht] +AUTOSTART = NO + +[transport] +AUTOSTART = YES + +[core] +AUTOSTART = YES + +[peerinfo] +AUTOSTART = YES + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[dns] +AUTOSTART = NO + +[testing] +NUM_PEERS = 10 +WEAKRANDOM = YES +TOPOLOGY = NONE +CONNECT_TOPOLOGY = SMALL_WORLD_RING +PERCENTAGE = 3 +F2F = NO +CONNECT_TIMEOUT = 60 s +CONNECT_ATTEMPTS = 3 +#DEBUG = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat +MAX_CONCURRENT_SSH = 20 +USE_PROGRESSBARS = YES +PEERGROUP_TIMEOUT = 1000 s + +DELETE_FILES = NO + + diff --git a/src/nse/test_nse_api.c b/src/nse/test_nse_api.c new file mode 100644 index 0000000..f6cde3f --- /dev/null +++ b/src/nse/test_nse_api.c @@ -0,0 +1,187 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file nse/test_nse_api.c + * @brief testcase for nse_api.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_nse_service.h" + +#define DEBUG_NSE GNUNET_YES + +#define START_ARM GNUNET_YES + +static struct GNUNET_NSE_Handle *h; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + + +static void +stop_arm (struct PeerContext *p) +{ +#if START_ARM + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + GNUNET_OS_process_wait (p->arm_proc); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + +/** + * Signature of the main function of a task. + * + * @param cls closure + * @param tc context information (why was this task triggered now) + */ +static void +end_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (h != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from NSE service.\n"); + GNUNET_NSE_disconnect (h); + } +} + +/** + * Callback to call when network size estimate is updated. + * + * @param cls unused + * @param timestamp time when the estimate was received from the server (or created by the server) + * @param estimate the value of the current network size estimate + * @param std_dev standard deviation (rounded down to nearest integer) + * of the size estimation values seen + * + */ +static void +check_nse_message (void *cls, struct GNUNET_TIME_Absolute timestamp, + double estimate, double std_dev) +{ + int *ok = cls; + + FPRINTF (stderr, + "Received NSE message, estimate %f, standard deviation %f.\n", + estimate, std_dev); + /* Fantastic check below. Expect NaN, the only thing not equal to itself. */ + (*ok) = 0; + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_test, NULL); +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE_ARM + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + +} + + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 1), &end_test, + NULL); + + setup_peer (&p1, cfgfile); + h = GNUNET_NSE_connect (cfg, &check_nse_message, cls); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to NSE service.\n"); + GNUNET_assert (h != NULL); +} + + +static int +check () +{ + int ok = 1; + + char *const argv[] = { "test-nse-api", + "-c", + "test_nse.conf", +#if DEBUG_NSE + "-L", "DEBUG", +#else + "-L", "WARNING", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_PROGRAM_run (5, argv, "test-nse-api", "nohelp", options, &run, &ok); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping arm.\n"); + stop_arm (&p1); + if (0 != ok) + FPRINTF (stderr, "%s", "No information received from NSE service!\n"); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test_nse_api", +#if DEBUG_NSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + return ret; +} + +/* end of test_nse_api.c */ diff --git a/src/nse/test_nse_multipeer.c b/src/nse/test_nse_multipeer.c new file mode 100644 index 0000000..28d066b --- /dev/null +++ b/src/nse/test_nse_multipeer.c @@ -0,0 +1,275 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file nse/test_nse_multipeer.c + * + * @brief Testcase for the network size estimation service. Starts + * a peergroup with a given number of peers, then waits to + * receive size estimates from each peer. Expects to wait + * for one message from each peer. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_nse_service.h" + +#define VERBOSE GNUNET_NO + +#define NUM_PEERS 4 + +struct NSEPeer +{ + struct NSEPeer *prev; + + struct NSEPeer *next; + + struct GNUNET_TESTING_Daemon *daemon; + + struct GNUNET_NSE_Handle *nse_handle; +}; + +struct NSEPeer *peer_head; + +struct NSEPeer *peer_tail; + +/** + * How long do we run the test? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +static int ok; + +static int peers_left; + +static unsigned int num_peers; + +static unsigned int total_connections; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed: %s!\n", + emsg); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + ok = 0; + } +} + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NSEPeer *pos; + +#if VERBOSE + FPRINTF (stderr, "%s", "Ending test.\n"); +#endif + + while (NULL != (pos = peer_head)) + { + GNUNET_NSE_disconnect (pos->nse_handle); + GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos); + GNUNET_free (pos); + } + + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + +/** + * Callback to call when network size estimate is updated. + * + * @param cls closure + * @param timestamp server timestamp + * @param estimate the value of the current network size estimate + * @param std_dev standard deviation (rounded down to nearest integer) + * of the size estimation values seen + * + */ +static void +handle_estimate (void *cls, struct GNUNET_TIME_Absolute timestamp, + double estimate, double std_dev) +{ + struct NSEPeer *peer = cls; + + FPRINTF (stderr, + "Received network size estimate from peer %s. logSize: %f std.dev. %f (%f/%u)\n", + GNUNET_i2s (&peer->daemon->id), estimate, std_dev, + GNUNET_NSE_log_estimate_to_n (estimate), num_peers); +} + + +static void +connect_nse_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NSEPeer *current_peer; + unsigned int i; + +#if VERBOSE + FPRINTF (stderr, "%s", "TEST_NSE_MULTIPEER: connecting to nse service of peers\n"); +#endif + for (i = 0; i < num_peers; i++) + { + current_peer = GNUNET_malloc (sizeof (struct NSEPeer)); + current_peer->daemon = GNUNET_TESTING_daemon_get (pg, i); + current_peer->nse_handle = + GNUNET_NSE_connect (current_peer->daemon->cfg, &handle_estimate, + current_peer); + GNUNET_assert (current_peer->nse_handle != NULL); + GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer); + } +} + + +static void +my_cb (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); + ok = 1; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer Group started successfully, connecting to NSE service for each peer!\n"); +#endif + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Have %u connections\n", + total_connections); + + GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); +} + + +/** + * Function that will be called whenever + * two daemons are connected by the testing library. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param first_cfg config for the first daemon + * @param second_cfg config for the second daemon + * @param first_daemon handle for the first daemon + * @param second_daemon handle for the second daemon + * @param emsg error message (NULL on success) + */ +static void +connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) +{ + if (emsg == NULL) + { + //fprintf(stderr, "Connected %s -> %s\n", GNUNET_i2s(first), second_id); + total_connections++; + } +} + + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_CONFIGURATION_Handle *testing_cfg; + unsigned long long total_peers; + + ok = 1; + testing_cfg = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (testing_cfg, cfgfile)); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", "YES"); +#endif + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", + "num_peers", &total_peers)) + total_peers = NUM_PEERS; + + peers_left = total_peers; + num_peers = peers_left; + pg = GNUNET_TESTING_peergroup_start (testing_cfg, peers_left, TIMEOUT, + &connect_cb, &my_cb, NULL, NULL); + GNUNET_assert (pg != NULL); + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL); +} + + +static int +check () +{ + char *const argv[] = { "test-nse-multipeer", + "-c", + "test_nse.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-nse-multipeer", "nohelp", options, &run, &ok); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-nse-multipeer", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + // GNUNET_DISK_directory_remove ("/tmp/test-nse-multipeer"); + return ret; +} + +/* end of test_nse_multipeer.c */ diff --git a/src/peerinfo-tool/Makefile.am b/src/peerinfo-tool/Makefile.am new file mode 100644 index 0000000..8c5fd8f --- /dev/null +++ b/src/peerinfo-tool/Makefile.am @@ -0,0 +1,42 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +bin_PROGRAMS = \ + gnunet-peerinfo + +gnunet_peerinfo_SOURCES = \ + gnunet-peerinfo.c +gnunet_peerinfo_LDADD = \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la + +if HAVE_PYTHON_PEXPECT +check_SCRIPTS = \ + test_gnunet_peerinfo.py +endif + +if ENABLE_TEST_RUN +TESTS = $(check_SCRIPTS) +endif + +do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' + +test_gnunet_peerinfo.py: test_gnunet_peerinfo.py.in Makefile + $(do_subst) < $(srcdir)/test_gnunet_peerinfo.py.in > test_gnunet_peerinfo.py + chmod +x test_gnunet_peerinfo.py + +EXTRA_DIST = \ + test_gnunet_peerinfo.py.in \ + test_gnunet_peerinfo_data.conf + +CLEANFILES = $(check_SCRIPTS) diff --git a/src/peerinfo-tool/Makefile.in b/src/peerinfo-tool/Makefile.in new file mode 100644 index 0000000..1984b45 --- /dev/null +++ b/src/peerinfo-tool/Makefile.in @@ -0,0 +1,753 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-peerinfo$(EXEEXT) +subdir = src/peerinfo-tool +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_peerinfo_OBJECTS = gnunet-peerinfo.$(OBJEXT) +gnunet_peerinfo_OBJECTS = $(am_gnunet_peerinfo_OBJECTS) +gnunet_peerinfo_DEPENDENCIES = \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(gnunet_peerinfo_SOURCES) +DIST_SOURCES = $(gnunet_peerinfo_SOURCES) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +gnunet_peerinfo_SOURCES = \ + gnunet-peerinfo.c + +gnunet_peerinfo_LDADD = \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la + +@HAVE_PYTHON_PEXPECT_TRUE@check_SCRIPTS = \ +@HAVE_PYTHON_PEXPECT_TRUE@ test_gnunet_peerinfo.py + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_SCRIPTS) +do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' +EXTRA_DIST = \ + test_gnunet_peerinfo.py.in \ + test_gnunet_peerinfo_data.conf + +CLEANFILES = $(check_SCRIPTS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/peerinfo-tool/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/peerinfo-tool/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-peerinfo$(EXEEXT): $(gnunet_peerinfo_OBJECTS) $(gnunet_peerinfo_DEPENDENCIES) + @rm -f gnunet-peerinfo$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_peerinfo_OBJECTS) $(gnunet_peerinfo_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-peerinfo.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-generic clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS + + +test_gnunet_peerinfo.py: test_gnunet_peerinfo.py.in Makefile + $(do_subst) < $(srcdir)/test_gnunet_peerinfo.py.in > test_gnunet_peerinfo.py + chmod +x test_gnunet_peerinfo.py + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/peerinfo-tool/gnunet-peerinfo.c b/src/peerinfo-tool/gnunet-peerinfo.c new file mode 100644 index 0000000..21c9966 --- /dev/null +++ b/src/peerinfo-tool/gnunet-peerinfo.c @@ -0,0 +1,268 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2006, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file peerinfo-tool/gnunet-peerinfo.c + * @brief Print information about other known peers. + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_program_lib.h" + +static int no_resolve; + +static int be_quiet; + +static int get_self; + +static struct GNUNET_PEERINFO_Handle *peerinfo; + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +struct PrintContext +{ + struct GNUNET_PeerIdentity peer; + char **address_list; + unsigned int num_addresses; + uint32_t off; +}; + + +static void +dump_pc (struct PrintContext *pc) +{ + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + unsigned int i; + + GNUNET_CRYPTO_hash_to_enc (&pc->peer.hashPubKey, &enc); + printf (_("Peer `%s'\n"), (const char *) &enc); + for (i = 0; i < pc->num_addresses; i++) + { + printf ("\t%s\n", pc->address_list[i]); + GNUNET_free (pc->address_list[i]); + } + printf ("\n"); + GNUNET_array_grow (pc->address_list, pc->num_addresses, 0); + GNUNET_free (pc); +} + + +/** + * Function to call with a human-readable format of an address + * + * @param cls closure + * @param address NULL on error, otherwise 0-terminated printable UTF-8 string + */ +static void +process_resolved_address (void *cls, const char *address) +{ + struct PrintContext *pc = cls; + + if (address == NULL) + { + pc->off--; + if (pc->off == 0) + dump_pc (pc); + return; + } + GNUNET_array_append (pc->address_list, pc->num_addresses, + GNUNET_strdup (address)); +} + + +/** + * Iterator callback to go over all addresses. + * + * @param cls closure + * @param address the address + * @param expiration expiration time + * @return GNUNET_OK to keep the address and continue + */ +static int +count_address (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + struct PrintContext *pc = cls; + + pc->off++; + return GNUNET_OK; +} + + +/** + * Iterator callback to go over all addresses. + * + * @param cls closure + * @param address the address + * @param expiration expiration time + * @return GNUNET_OK to keep the address and continue + */ +static int +print_address (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + struct PrintContext *pc = cls; + + GNUNET_TRANSPORT_address_to_string (cfg, address, no_resolve, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 10), + &process_resolved_address, pc); + return GNUNET_OK; +} + + +/** + * Print information about the peer. + * Currently prints the GNUNET_PeerIdentity and the IP. + * Could of course do more (e.g. resolve via DNS). + */ +static void +print_peer_info (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, const char *err_msg) +{ + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + struct PrintContext *pc; + + if (peer == NULL) + { + if (err_msg != NULL) + FPRINTF (stderr, "%s", _("Error in communication with PEERINFO service\n")); + GNUNET_PEERINFO_disconnect (peerinfo); + return; + } + if ((be_quiet) || (NULL == hello)) + { + GNUNET_CRYPTO_hash_to_enc (&peer->hashPubKey, &enc); + printf ("%s\n", (const char *) &enc); + return; + } + pc = GNUNET_malloc (sizeof (struct PrintContext)); + pc->peer = *peer; + GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &count_address, pc); + if (0 == pc->off) + { + dump_pc (pc); + return; + } + GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &print_address, pc); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + struct GNUNET_CRYPTO_RsaPrivateKey *priv; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; + struct GNUNET_PeerIdentity pid; + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + char *fn; + + cfg = c; + if (args[0] != NULL) + { + FPRINTF (stderr, _("Invalid command line argument `%s'\n"), args[0]); + return; + } + if (get_self != GNUNET_YES) + { + peerinfo = GNUNET_PEERINFO_connect (cfg); + if (peerinfo == NULL) + { + FPRINTF (stderr, "%s", _("Could not access PEERINFO service. Exiting.\n")); + return; + } + GNUNET_PEERINFO_iterate (peerinfo, NULL, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), &print_peer_info, + NULL); + } + else + { + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", + &fn)) + { + FPRINTF (stderr, _("Could not find option `%s:%s' in configuration.\n"), + "GNUNETD", "HOSTKEYFILE"); + return; + } + priv = GNUNET_CRYPTO_rsa_key_create_from_file (fn); + if (priv == NULL) + { + FPRINTF (stderr, _("Loading hostkey from `%s' failed.\n"), fn); + GNUNET_free (fn); + return; + } + GNUNET_free (fn); + GNUNET_CRYPTO_rsa_key_get_public (priv, &pub); + GNUNET_CRYPTO_rsa_key_free (priv); + GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey); + GNUNET_CRYPTO_hash_to_enc (&pid.hashPubKey, &enc); + if (be_quiet) + printf ("%s\n", (char *) &enc); + else + printf (_("I am peer `%s'.\n"), (const char *) &enc); + } +} + + +/** + * The main function to obtain peer information. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'n', "numeric", NULL, + gettext_noop ("don't resolve host names"), + 0, &GNUNET_GETOPT_set_one, &no_resolve}, + {'q', "quiet", NULL, + gettext_noop ("output only the identity strings"), + 0, &GNUNET_GETOPT_set_one, &be_quiet}, + {'s', "self", NULL, + gettext_noop ("output our own identity only"), + 0, &GNUNET_GETOPT_set_one, &get_self}, + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-peerinfo", + gettext_noop ("Print information about peers."), + options, &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-peerinfo.c */ diff --git a/src/peerinfo-tool/test_gnunet_peerinfo.py.in b/src/peerinfo-tool/test_gnunet_peerinfo.py.in new file mode 100755 index 0000000..ee8bc4a --- /dev/null +++ b/src/peerinfo-tool/test_gnunet_peerinfo.py.in @@ -0,0 +1,93 @@ +#!@PYTHON@ +# This file is part of GNUnet. +# (C) 2010 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# GNUnet is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNUnet; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Testcase for gnunet-peerinfo +import sys +import os +import subprocess +import re +import shutil +import time + +srcdir = "../.." +gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") +if gnunet_pyexpect_dir not in sys.path: + sys.path.append (gnunet_pyexpect_dir) + +from gnunet_pyexpect import pexpect + +if os.name == 'posix': + peerinfo = 'gnunet-peerinfo' + gnunetarm = 'gnunet-arm' +elif os.name == 'nt': + peerinfo = 'gnunet-peerinfo.exe' + gnunetarm = 'gnunet-arm.exe' + + + +pinfo = pexpect () +pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-L', 'ERROR'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) +pinfo.expect ("stdout", re.compile (r'Error in communication with PEERINFO service\r?\n')) +pinfo.expect ("stdout", "EOF") + +if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-peerinfo"), True) +else: + shutil.rmtree ("/tmp/gnunet-test-peerinfo", True) +arm = subprocess.Popen ([gnunetarm, '-sq', '-c', 'test_gnunet_peerinfo_data.conf']) +arm.communicate () + +try: + pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-s'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pinfo.expect ("stdout", re.compile (r'I am peer `.*\'.\r?\n')) + + pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-qs'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pinfo.expect ("stdout", re.compile (r'.......................................................................................................\r?\n')) + + pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', 'invalid'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pinfo.expect ("stdout", re.compile (r'Invalid command line argument `invalid\'\r?\n')) + + arm = subprocess.Popen ([gnunetarm, '-q', '-i', 'transport', '-c', 'test_gnunet_peerinfo_data.conf']) + arm.communicate () + time.sleep (1) + + pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pinfo.expect ("stdout", re.compile ("Peer `.*'\r?\n")) + m = pinfo.expect ("stdout", re.compile ("\s.*:24357\r?\n")) + while len (m.group (0)) > 0: + m = pinfo.expect ("stdout", re.compile ("(\s.*:24357\r?\n|\r?\n|)")) + + pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-n'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pinfo.expect ("stdout", re.compile ("Peer `.*'\r?\n")) + m = pinfo.expect ("stdout", re.compile ("\s.*:24357\r?\n")) + while len (m.group (0)) > 0: + m = pinfo.expect ("stdout", re.compile ("(\s.*:24357\r?\n|\r?\n|)")) + + pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-qs'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + pid = pinfo.read ("stdout") + pid.strip () + +finally: + arm = subprocess.Popen ([gnunetarm, '-eq', '-c', 'test_gnunet_peerinfo_data.conf']) + arm.communicate () + if os.name == "nt": + shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-peerinfo"), True) + else: + shutil.rmtree ("/tmp/gnunet-test-peerinfo", True) + diff --git a/src/peerinfo-tool/test_gnunet_peerinfo_data.conf b/src/peerinfo-tool/test_gnunet_peerinfo_data.conf new file mode 100644 index 0000000..90da74f --- /dev/null +++ b/src/peerinfo-tool/test_gnunet_peerinfo_data.conf @@ -0,0 +1,32 @@ +[PATHS] +SERVICEHOME = /tmp/gnunet-test-peerinfo/ + +[peerinfo] +PORT = 24354 + +[resolver] +PORT = 24355 + +[arm] +DEFAULTSERVICES = + +[testing] +WEAKRANDOM = YES + +[transport] +plugins = tcp +PORT = 24356 + +[transport-tcp] +PORT = 24357 + +[dns] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + + diff --git a/src/peerinfo/Makefile.am b/src/peerinfo/Makefile.am new file mode 100644 index 0000000..468fab5 --- /dev/null +++ b/src/peerinfo/Makefile.am @@ -0,0 +1,69 @@ +INCLUDES = -I$(top_srcdir)/src/include + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + peerinfo.conf + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +lib_LTLIBRARIES = libgnunetpeerinfo.la + +libgnunetpeerinfo_la_SOURCES = \ + peerinfo_api.c peerinfo.h \ + peerinfo_api_notify.c +libgnunetpeerinfo_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(XLIB) +libgnunetpeerinfo_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + + +bin_PROGRAMS = \ + gnunet-service-peerinfo + +gnunet_service_peerinfo_SOURCES = \ + gnunet-service-peerinfo.c +gnunet_service_peerinfo_LDADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +if HAVE_BENCHMARKS + PEERINFO_BENCHMARKS = \ + perf_peerinfo_api +endif + +check_PROGRAMS = \ + test_peerinfo_api \ + $(PEERINFO_BENCHMARKS) + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_peerinfo_api_SOURCES = \ + test_peerinfo_api.c +test_peerinfo_api_LDADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_peerinfo_api_SOURCES = \ + perf_peerinfo_api.c +perf_peerinfo_api_LDADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_peerinfo_api_data.conf diff --git a/src/peerinfo/Makefile.in b/src/peerinfo/Makefile.in new file mode 100644 index 0000000..639e43f --- /dev/null +++ b/src/peerinfo/Makefile.in @@ -0,0 +1,917 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-service-peerinfo$(EXEEXT) +check_PROGRAMS = test_peerinfo_api$(EXEEXT) $(am__EXEEXT_1) +subdir = src/peerinfo +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/peerinfo.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = peerinfo.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunetpeerinfo_la_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunetpeerinfo_la_OBJECTS = peerinfo_api.lo \ + peerinfo_api_notify.lo +libgnunetpeerinfo_la_OBJECTS = $(am_libgnunetpeerinfo_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetpeerinfo_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetpeerinfo_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@HAVE_BENCHMARKS_TRUE@am__EXEEXT_1 = perf_peerinfo_api$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_service_peerinfo_OBJECTS = \ + gnunet-service-peerinfo.$(OBJEXT) +gnunet_service_peerinfo_OBJECTS = \ + $(am_gnunet_service_peerinfo_OBJECTS) +gnunet_service_peerinfo_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_perf_peerinfo_api_OBJECTS = perf_peerinfo_api.$(OBJEXT) +perf_peerinfo_api_OBJECTS = $(am_perf_peerinfo_api_OBJECTS) +perf_peerinfo_api_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_peerinfo_api_OBJECTS = test_peerinfo_api.$(OBJEXT) +test_peerinfo_api_OBJECTS = $(am_test_peerinfo_api_OBJECTS) +test_peerinfo_api_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetpeerinfo_la_SOURCES) \ + $(gnunet_service_peerinfo_SOURCES) \ + $(perf_peerinfo_api_SOURCES) $(test_peerinfo_api_SOURCES) +DIST_SOURCES = $(libgnunetpeerinfo_la_SOURCES) \ + $(gnunet_service_peerinfo_SOURCES) \ + $(perf_peerinfo_api_SOURCES) $(test_peerinfo_api_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + peerinfo.conf + +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +lib_LTLIBRARIES = libgnunetpeerinfo.la +libgnunetpeerinfo_la_SOURCES = \ + peerinfo_api.c peerinfo.h \ + peerinfo_api_notify.c + +libgnunetpeerinfo_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(XLIB) + +libgnunetpeerinfo_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +gnunet_service_peerinfo_SOURCES = \ + gnunet-service-peerinfo.c + +gnunet_service_peerinfo_LDADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +@HAVE_BENCHMARKS_TRUE@PEERINFO_BENCHMARKS = \ +@HAVE_BENCHMARKS_TRUE@ perf_peerinfo_api + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_peerinfo_api_SOURCES = \ + test_peerinfo_api.c + +test_peerinfo_api_LDADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_peerinfo_api_SOURCES = \ + perf_peerinfo_api.c + +perf_peerinfo_api_LDADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_peerinfo_api_data.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/peerinfo/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/peerinfo/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +peerinfo.conf: $(top_builddir)/config.status $(srcdir)/peerinfo.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetpeerinfo.la: $(libgnunetpeerinfo_la_OBJECTS) $(libgnunetpeerinfo_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetpeerinfo_la_LINK) -rpath $(libdir) $(libgnunetpeerinfo_la_OBJECTS) $(libgnunetpeerinfo_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-service-peerinfo$(EXEEXT): $(gnunet_service_peerinfo_OBJECTS) $(gnunet_service_peerinfo_DEPENDENCIES) + @rm -f gnunet-service-peerinfo$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_peerinfo_OBJECTS) $(gnunet_service_peerinfo_LDADD) $(LIBS) +perf_peerinfo_api$(EXEEXT): $(perf_peerinfo_api_OBJECTS) $(perf_peerinfo_api_DEPENDENCIES) + @rm -f perf_peerinfo_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_peerinfo_api_OBJECTS) $(perf_peerinfo_api_LDADD) $(LIBS) +test_peerinfo_api$(EXEEXT): $(test_peerinfo_api_OBJECTS) $(test_peerinfo_api_DEPENDENCIES) + @rm -f test_peerinfo_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_peerinfo_api_OBJECTS) $(test_peerinfo_api_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-peerinfo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peerinfo_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peerinfo_api_notify.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_peerinfo_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_peerinfo_api.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/peerinfo/gnunet-service-peerinfo.c b/src/peerinfo/gnunet-service-peerinfo.c new file mode 100644 index 0000000..d6e52d4 --- /dev/null +++ b/src/peerinfo/gnunet-service-peerinfo.c @@ -0,0 +1,671 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file peerinfo/gnunet-service-peerinfo.c + * @brief maintains list of known peers + * + * Code to maintain the list of currently known hosts (in memory + * structure of data/hosts/). + * + * @author Christian Grothoff + * + * TODO: + * - HostEntries are never 'free'd (add expiration, upper bound?) + */ + +#include "platform.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_disk_lib.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_service_lib.h" +#include "gnunet_statistics_service.h" +#include "peerinfo.h" + +/** + * How often do we scan the HOST_DIR for new entries? + */ +#define DATA_HOST_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +/** + * How often do we discard old entries in data/hosts/? + */ +#define DATA_HOST_CLEAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 60) + +/** + * In-memory cache of known hosts. + */ +struct HostEntry +{ + + /** + * Identity of the peer. + */ + struct GNUNET_PeerIdentity identity; + + /** + * Hello for the peer (can be NULL) + */ + struct GNUNET_HELLO_Message *hello; + +}; + + +/** + * The in-memory list of known hosts, mapping of + * host IDs to 'struct HostEntry*' values. + */ +static struct GNUNET_CONTAINER_MultiHashMap *hostmap; + +/** + * Clients to immediately notify about all changes. + */ +static struct GNUNET_SERVER_NotificationContext *notify_list; + +/** + * Directory where the hellos are stored in (data/hosts) + */ +static char *networkIdDirectory; + +/** + * Handle for reporting statistics. + */ +static struct GNUNET_STATISTICS_Handle *stats; + + +/** + * Notify all clients in the notify list about the + * given host entry changing. + */ +static struct InfoMessage * +make_info_message (const struct HostEntry *he) +{ + struct InfoMessage *im; + size_t hs; + + hs = (he->hello == NULL) ? 0 : GNUNET_HELLO_size (he->hello); + im = GNUNET_malloc (sizeof (struct InfoMessage) + hs); + im->header.size = htons (hs + sizeof (struct InfoMessage)); + im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO); + im->peer = he->identity; + if (he->hello != NULL) + memcpy (&im[1], he->hello, hs); + return im; +} + + +/** + * Address iterator that causes expired entries to be discarded. + * + * @param cls pointer to the current time + * @param address the address + * @param expiration expiration time for the address + * @return GNUNET_NO if expiration smaller than the current time + */ +static int +discard_expired (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + const struct GNUNET_TIME_Absolute *now = cls; + + if (now->abs_value > expiration.abs_value) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Removing expired address of transport `%s'\n"), + address->transport_name); + return GNUNET_NO; + } + return GNUNET_OK; +} + + +/** + * Get the filename under which we would store the GNUNET_HELLO_Message + * for the given host and protocol. + * @return filename of the form DIRECTORY/HOSTID + */ +static char * +get_host_filename (const struct GNUNET_PeerIdentity *id) +{ + struct GNUNET_CRYPTO_HashAsciiEncoded fil; + char *fn; + + GNUNET_CRYPTO_hash_to_enc (&id->hashPubKey, &fil); + GNUNET_asprintf (&fn, "%s%s%s", networkIdDirectory, DIR_SEPARATOR_STR, &fil); + return fn; +} + + +/** + * Broadcast information about the given entry to all + * clients that care. + * + * @param entry entry to broadcast about + */ +static void +notify_all (struct HostEntry *entry) +{ + struct InfoMessage *msg; + + msg = make_info_message (entry); + GNUNET_SERVER_notification_context_broadcast (notify_list, &msg->header, + GNUNET_NO); + GNUNET_free (msg); +} + + +/** + * Add a host to the list. + * + * @param identity the identity of the host + */ +static void +add_host_to_known_hosts (const struct GNUNET_PeerIdentity *identity) +{ + struct HostEntry *entry; + char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + const struct GNUNET_HELLO_Message *hello; + struct GNUNET_HELLO_Message *hello_clean; + int size; + struct GNUNET_TIME_Absolute now; + char *fn; + + entry = GNUNET_CONTAINER_multihashmap_get (hostmap, &identity->hashPubKey); + if (entry != NULL) + return; + GNUNET_STATISTICS_update (stats, gettext_noop ("# peers known"), 1, + GNUNET_NO); + entry = GNUNET_malloc (sizeof (struct HostEntry)); + entry->identity = *identity; + + fn = get_host_filename (identity); + if (GNUNET_DISK_file_test (fn) == GNUNET_YES) + { + size = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer)); + hello = (const struct GNUNET_HELLO_Message *) buffer; + if ((size < sizeof (struct GNUNET_MessageHeader)) || + (size != ntohs ((((const struct GNUNET_MessageHeader *) hello)->size))) + || (size != GNUNET_HELLO_size (hello))) + { + GNUNET_break (0); + if (0 != UNLINK (fn)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); + } + else + { + now = GNUNET_TIME_absolute_get (); + hello_clean = + GNUNET_HELLO_iterate_addresses (hello, GNUNET_YES, &discard_expired, + &now); + entry->hello = hello_clean; + } + } + GNUNET_free (fn); + GNUNET_CONTAINER_multihashmap_put (hostmap, &identity->hashPubKey, entry, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + notify_all (entry); +} + + +/** + * Remove a file that should not be there. LOG + * success or failure. + */ +static void +remove_garbage (const char *fullname) +{ + if (0 == UNLINK (fullname)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + _ + ("File `%s' in directory `%s' does not match naming convention. " + "Removed.\n"), fullname, networkIdDirectory); + else + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "unlink", fullname); +} + + +static int +hosts_directory_scan_callback (void *cls, const char *fullname) +{ + unsigned int *matched = cls; + struct GNUNET_PeerIdentity identity; + const char *filename; + + if (GNUNET_DISK_file_test (fullname) != GNUNET_YES) + return GNUNET_OK; /* ignore non-files */ + if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) + { + remove_garbage (fullname); + return GNUNET_OK; + } + filename = + &fullname[strlen (fullname) - + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1]; + if (filename[-1] != DIR_SEPARATOR) + { + remove_garbage (fullname); + return GNUNET_OK; + } + if (GNUNET_OK != + GNUNET_CRYPTO_hash_from_string (filename, &identity.hashPubKey)) + { + remove_garbage (fullname); + return GNUNET_OK; + } + (*matched)++; + add_host_to_known_hosts (&identity); + return GNUNET_OK; +} + + +/** + * Call this method periodically to scan data/hosts for new hosts. + */ +static void +cron_scan_directory_data_hosts (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static unsigned int retries; + unsigned int count; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + count = 0; + if (GNUNET_SYSERR == GNUNET_DISK_directory_create (networkIdDirectory)) + { + GNUNET_SCHEDULER_add_delayed_with_priority (DATA_HOST_FREQ, + GNUNET_SCHEDULER_PRIORITY_IDLE, + &cron_scan_directory_data_hosts, NULL); + return; + } + GNUNET_DISK_directory_scan (networkIdDirectory, + &hosts_directory_scan_callback, &count); + if ((0 == count) && (0 == (++retries & 31))) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + _("Still no peers found in `%s'!\n"), networkIdDirectory); + GNUNET_SCHEDULER_add_delayed_with_priority (DATA_HOST_FREQ, + GNUNET_SCHEDULER_PRIORITY_IDLE, + &cron_scan_directory_data_hosts, + NULL); +} + + +/** + * Bind a host address (hello) to a hostId. + * + * @param peer the peer for which this is a hello + * @param hello the verified (!) hello message + */ +static void +bind_address (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello) +{ + char *fn; + struct HostEntry *host; + struct GNUNET_HELLO_Message *mrg; + struct GNUNET_TIME_Absolute delta; + + add_host_to_known_hosts (peer); + host = GNUNET_CONTAINER_multihashmap_get (hostmap, &peer->hashPubKey); + GNUNET_assert (host != NULL); + if (host->hello == NULL) + { + host->hello = GNUNET_malloc (GNUNET_HELLO_size (hello)); + memcpy (host->hello, hello, GNUNET_HELLO_size (hello)); + } + else + { + mrg = GNUNET_HELLO_merge (host->hello, hello); + delta = GNUNET_HELLO_equals (mrg, host->hello, GNUNET_TIME_absolute_get ()); + if (delta.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) + { + GNUNET_free (mrg); + return; + } + GNUNET_free (host->hello); + host->hello = mrg; + } + fn = get_host_filename (peer); + if (GNUNET_OK == GNUNET_DISK_directory_create_for_file (fn)) + { + if (GNUNET_SYSERR == + GNUNET_DISK_fn_write (fn, host->hello, GNUNET_HELLO_size (host->hello), + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE | + GNUNET_DISK_PERM_GROUP_READ | + GNUNET_DISK_PERM_OTHER_READ)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn); + + } + GNUNET_free (fn); + notify_all (host); +} + + + +/** + * Do transmit info about peer to given host. + * + * @param cls NULL to hit all hosts, otherwise specifies a particular target + * @param key hostID + * @param value information to transmit + * @return GNUNET_YES (continue to iterate) + */ +static int +add_to_tc (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_SERVER_TransmitContext *tc = cls; + struct HostEntry *pos = value; + struct InfoMessage *im; + uint16_t hs; + char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + + hs = 0; + im = (struct InfoMessage *) buf; + if (pos->hello != NULL) + { + hs = GNUNET_HELLO_size (pos->hello); + GNUNET_assert (hs < + GNUNET_SERVER_MAX_MESSAGE_SIZE - + sizeof (struct InfoMessage)); + memcpy (&im[1], pos->hello, hs); + } + im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO); + im->header.size = htons (sizeof (struct InfoMessage) + hs); + im->reserved = htonl (0); + im->peer = pos->identity; + GNUNET_SERVER_transmit_context_append_message (tc, &im->header); + return GNUNET_YES; +} + + +/** + * @brief delete expired HELLO entries in data/hosts/ + */ +static int +discard_hosts_helper (void *cls, const char *fn) +{ + struct GNUNET_TIME_Absolute *now = cls; + char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + const struct GNUNET_HELLO_Message *hello; + struct GNUNET_HELLO_Message *new_hello; + int size; + + size = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer)); + if (size < sizeof (struct GNUNET_MessageHeader)) + { + if (0 != UNLINK (fn)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING | + GNUNET_ERROR_TYPE_BULK, "unlink", fn); + return GNUNET_OK; + } + hello = (const struct GNUNET_HELLO_Message *) buffer; + new_hello = + GNUNET_HELLO_iterate_addresses (hello, GNUNET_YES, &discard_expired, now); + if (new_hello != NULL) + { + GNUNET_DISK_fn_write (fn, new_hello, GNUNET_HELLO_size (new_hello), + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE | + GNUNET_DISK_PERM_GROUP_READ | + GNUNET_DISK_PERM_OTHER_READ); + GNUNET_free (new_hello); + } + else + { + if (0 != UNLINK (fn)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING | + GNUNET_ERROR_TYPE_BULK, "unlink", fn); + } + return GNUNET_OK; +} + + +/** + * Call this method periodically to scan data/hosts for new hosts. + */ +static void +cron_clean_data_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TIME_Absolute now; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + now = GNUNET_TIME_absolute_get (); + GNUNET_DISK_directory_scan (networkIdDirectory, &discard_hosts_helper, &now); + GNUNET_SCHEDULER_add_delayed (DATA_HOST_CLEAN_FREQ, &cron_clean_data_hosts, + NULL); +} + + +/** + * Handle HELLO-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_hello (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_HELLO_Message *hello; + struct GNUNET_PeerIdentity pid; + + hello = (const struct GNUNET_HELLO_Message *) message; + if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } +#if DEBUG_PEERINFO + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received for peer `%4s'\n", + "HELLO", GNUNET_i2s (&pid)); +#endif + bind_address (&pid, hello); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handle GET-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_get (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct ListPeerMessage *lpm; + struct GNUNET_SERVER_TransmitContext *tc; + + lpm = (const struct ListPeerMessage *) message; + GNUNET_break (0 == ntohl (lpm->reserved)); +#if DEBUG_PEERINFO + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received for peer `%4s'\n", + "GET", GNUNET_i2s (&lpm->peer)); +#endif + tc = GNUNET_SERVER_transmit_context_create (client); + GNUNET_CONTAINER_multihashmap_get_multiple (hostmap, &lpm->peer.hashPubKey, + &add_to_tc, tc); + GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END); + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Handle GET-ALL-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_get_all (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_SERVER_TransmitContext *tc; + +#if DEBUG_PEERINFO + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received\n", "GET_ALL"); +#endif + tc = GNUNET_SERVER_transmit_context_create (client); + GNUNET_CONTAINER_multihashmap_iterate (hostmap, &add_to_tc, tc); + GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END); + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); +} + + +static int +do_notify_entry (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_SERVER_Client *client = cls; + struct HostEntry *he = value; + struct InfoMessage *msg; + + msg = make_info_message (he); + GNUNET_SERVER_notification_context_unicast (notify_list, client, &msg->header, + GNUNET_NO); + GNUNET_free (msg); + return GNUNET_YES; +} + + +/** + * Handle NOTIFY-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_notify (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ +#if DEBUG_PEERINFO + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received\n", "NOTIFY"); +#endif + GNUNET_SERVER_notification_context_add (notify_list, client); + GNUNET_CONTAINER_multihashmap_iterate (hostmap, &do_notify_entry, client); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +static int +free_host_entry (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct HostEntry *he = value; + + GNUNET_free_non_null (he->hello); + GNUNET_free (he); + return GNUNET_YES; +} + +/** + * Clean up our state. Called during shutdown. + * + * @param cls unused + * @param tc scheduler task context, unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_SERVER_notification_context_destroy (notify_list); + notify_list = NULL; + GNUNET_CONTAINER_multihashmap_iterate (hostmap, &free_host_entry, NULL); + GNUNET_CONTAINER_multihashmap_destroy (hostmap); + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + stats = NULL; + } +} + + +/** + * Process statistics requests. + * + * @param cls closure + * @param server the initialized server + * @param cfg configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_hello, NULL, GNUNET_MESSAGE_TYPE_HELLO, 0}, + {&handle_get, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET, + sizeof (struct ListPeerMessage)}, + {&handle_get_all, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL, + sizeof (struct GNUNET_MessageHeader)}, + {&handle_notify, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY, + sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} + }; + + hostmap = GNUNET_CONTAINER_multihashmap_create (1024); + stats = GNUNET_STATISTICS_create ("peerinfo", cfg); + notify_list = GNUNET_SERVER_notification_context_create (server, 0); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_filename (cfg, "peerinfo", + "HOSTS", + &networkIdDirectory)); + GNUNET_DISK_directory_create (networkIdDirectory); + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, + &cron_scan_directory_data_hosts, NULL); + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, + &cron_clean_data_hosts, NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + GNUNET_SERVER_add_handlers (server, handlers); +} + + +/** + * The main function for the statistics service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + int ret; + + ret = + (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "peerinfo", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; + GNUNET_free_non_null (networkIdDirectory); + return ret; +} + + +/* end of gnunet-service-peerinfo.c */ diff --git a/src/peerinfo/peerinfo.conf.in b/src/peerinfo/peerinfo.conf.in new file mode 100644 index 0000000..a40cc4f --- /dev/null +++ b/src/peerinfo/peerinfo.conf.in @@ -0,0 +1,24 @@ +[peerinfo] +AUTOSTART = YES +@UNIXONLY@ PORT = 2090 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-peerinfo +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-peerinfo.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +# DISABLE_SOCKET_FORWARDING = NO +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = +HOSTS = $SERVICEHOME/data/hosts/ + + diff --git a/src/peerinfo/peerinfo.h b/src/peerinfo/peerinfo.h new file mode 100644 index 0000000..bf56774 --- /dev/null +++ b/src/peerinfo/peerinfo.h @@ -0,0 +1,88 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file peerinfo/peerinfo.h + * @brief common internal definitions for peerinfo service + * @author Christian Grothoff + */ +#include "gnunet_crypto_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_peerinfo_service.h" + +#define DEBUG_PEERINFO GNUNET_EXTRA_LOGGING + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message requesting a listing of all known peers, + * possibly restricted to the specified peer identity. + */ +struct ListPeerMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_PEERINFO_GET + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Restrict to peers with this identity (optional + * field, check header.size!). + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Message used to inform the client about + * a particular peer; this message is optionally followed + * by a HELLO message for the respective peer (if available). + * Check the header.size field to see if a HELLO is + * present. + */ +struct InfoMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_PEERINFO_INFO + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * About which peer are we talking here? + */ + struct GNUNET_PeerIdentity peer; + +}; +GNUNET_NETWORK_STRUCT_END + +/* end of peerinfo.h */ diff --git a/src/peerinfo/peerinfo_api.c b/src/peerinfo/peerinfo_api.c new file mode 100644 index 0000000..4c5d795 --- /dev/null +++ b/src/peerinfo/peerinfo_api.c @@ -0,0 +1,661 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file peerinfo/peerinfo_api.c + * @brief API to access peerinfo service + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_client_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_protocols.h" +#include "gnunet_time_lib.h" +#include "peerinfo.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "nse-api",__VA_ARGS__) + +/** + * Function to call after transmission has succeeded. + * + * @param cls closure + * @param success GNUNET_OK if transmission worked, GNUNET_SYSERR on error + */ +typedef void (*TransmissionContinuation) (void *cls, int success); + + +/** + * Entry in the transmission queue to PEERINFO service. + */ +struct TransmissionQueueEntry +{ + /** + * This is a linked list. + */ + struct TransmissionQueueEntry *next; + + /** + * This is a linked list. + */ + struct TransmissionQueueEntry *prev; + + /** + * Function to call after request has been transmitted, or NULL (in which + * case we must consider sending the next entry immediately). + */ + TransmissionContinuation cont; + + /** + * Closure for 'cont'. + */ + void *cont_cls; + + /** + * Timeout for the operation. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Number of bytes of the request message (follows after this struct). + */ + size_t size; + +}; + + +/** + * Handle to the peerinfo service. + */ +struct GNUNET_PEERINFO_Handle +{ + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Connection to the service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Head of transmission queue. + */ + struct TransmissionQueueEntry *tq_head; + + /** + * Tail of transmission queue. + */ + struct TransmissionQueueEntry *tq_tail; + + /** + * Handle for the current transmission request, or NULL if none is pending. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * ID for a reconnect task. + */ + GNUNET_SCHEDULER_TaskIdentifier r_task; + + /** + * Set to GNUNET_YES if we are currently receiving replies from the + * service. + */ + int in_receive; + +}; + + +/** + * Connect to the peerinfo service. + * + * @param cfg configuration to use + * @return NULL on error (configuration related, actual connection + * establishment may happen asynchronously). + */ +struct GNUNET_PEERINFO_Handle * +GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_PEERINFO_Handle *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_Handle)); + ret->client = GNUNET_CLIENT_connect ("peerinfo", cfg); + ret->cfg = cfg; + return ret; +} + + +/** + * Disconnect from the peerinfo service. Note that all iterators must + * have completed or have been cancelled by the time this function is + * called (otherwise, calling this function is a serious error). + * Furthermore, if 'GNUNET_PEERINFO_add_peer' operations are still + * pending, they will be cancelled silently on disconnect. + * + * @param h handle to disconnect + */ +void +GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h) +{ + struct TransmissionQueueEntry *tqe; + + while (NULL != (tqe = h->tq_head)) + { + GNUNET_CONTAINER_DLL_remove (h->tq_head, h->tq_tail, tqe); + if (tqe->cont != NULL) + tqe->cont (tqe->cont_cls, GNUNET_SYSERR); + GNUNET_free (tqe); + } + if (h->th != NULL) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } + if (NULL != h->client) + { + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->client = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != h->r_task) + { + GNUNET_SCHEDULER_cancel (h->r_task); + h->r_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (h); +} + + +/** + * Check if we have a request pending in the transmission queue and are + * able to transmit it right now. If so, schedule transmission. + * + * @param h handle to the service + */ +static void +trigger_transmit (struct GNUNET_PEERINFO_Handle *h); + + +/** + * Close the existing connection to PEERINFO and reconnect. + * + * @param h handle to the service + */ +static void +reconnect (struct GNUNET_PEERINFO_Handle *h); + +/** + * Task scheduled to re-try connecting to the peerinfo service. + * + * @param cls the 'struct GNUNET_PEERINFO_Handle' + * @param tc scheduler context + */ +static void +reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_PEERINFO_Handle *h = cls; + + h->r_task = GNUNET_SCHEDULER_NO_TASK; + reconnect (h); +} + + +/** + * Close the existing connection to PEERINFO and reconnect. + * + * @param h handle to the service + */ +static void +reconnect (struct GNUNET_PEERINFO_Handle *h) +{ + if (h->r_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (h->r_task); + h->r_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != h->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } + if (NULL != h->client) + { + GNUNET_CLIENT_disconnect (h->client, GNUNET_SYSERR); + h->client = NULL; + } + h->client = GNUNET_CLIENT_connect ("peerinfo", h->cfg); + if (NULL == h->client) + { + h->r_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task, + h); + return; + } + trigger_transmit (h); +} + + +/** + * Transmit the request at the head of the transmission queue + * and trigger continuation (if any). + * + * @param cls the 'struct GNUNET_PEERINFO_Handle' (with the queue) + * @param size size of the buffer (0 on error) + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +do_transmit (void *cls, size_t size, void *buf) +{ + struct GNUNET_PEERINFO_Handle *h = cls; + struct TransmissionQueueEntry *tqe = h->tq_head; + size_t ret; + + h->th = NULL; + if (tqe == NULL) + return 0; + if (buf == NULL) + { +#if DEBUG_PEERINFO + LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + _("Failed to transmit message to `%s' service.\n"), "PEERINFO"); +#endif + GNUNET_CONTAINER_DLL_remove (h->tq_head, h->tq_tail, tqe); + reconnect (h); + if (tqe->cont != NULL) + tqe->cont (tqe->cont_cls, GNUNET_SYSERR); + GNUNET_free (tqe); + return 0; + } + ret = tqe->size; + GNUNET_assert (size >= ret); + memcpy (buf, &tqe[1], ret); +#if DEBUG_PEERINFO + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting request of size %u to `%s' service.\n", ret, "PEERINFO"); +#endif + GNUNET_CONTAINER_DLL_remove (h->tq_head, h->tq_tail, tqe); + if (tqe->cont != NULL) + tqe->cont (tqe->cont_cls, GNUNET_OK); + else + trigger_transmit (h); + GNUNET_free (tqe); + return ret; +} + + +/** + * Check if we have a request pending in the transmission queue and are + * able to transmit it right now. If so, schedule transmission. + * + * @param h handle to the service + */ +static void +trigger_transmit (struct GNUNET_PEERINFO_Handle *h) +{ + struct TransmissionQueueEntry *tqe; + + if (NULL == (tqe = h->tq_head)) + return; + if (h->th != NULL) + return; + if (h->in_receive == GNUNET_YES) + return; + if (NULL == h->client) + { + reconnect (h); + return; + } + h->th = + GNUNET_CLIENT_notify_transmit_ready (h->client, tqe->size, + GNUNET_TIME_absolute_get_remaining + (tqe->timeout), GNUNET_YES, + &do_transmit, h); +} + + +/** + * Add a host to the persistent list. This method operates in + * semi-reliable mode: if the transmission is not completed by + * the time 'GNUNET_PEERINFO_disconnect' is called, it will be + * aborted. Furthermore, if a second HELLO is added for the + * same peer before the first one was transmitted, PEERINFO may + * merge the two HELLOs prior to transmission to the service. + * + * @param h handle to the peerinfo service + * @param hello the verified (!) HELLO message + */ +void +GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h, + const struct GNUNET_HELLO_Message *hello) +{ + uint16_t hs = GNUNET_HELLO_size (hello); + struct TransmissionQueueEntry *tqe; + +#if DEBUG_PEERINFO + struct GNUNET_PeerIdentity peer; + + GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (hello, &peer)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding peer `%s' to PEERINFO database (%u bytes of `%s')\n", + GNUNET_i2s (&peer), hs, "HELLO"); +#endif + tqe = GNUNET_malloc (sizeof (struct TransmissionQueueEntry) + hs); + tqe->size = hs; + tqe->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; + memcpy (&tqe[1], hello, hs); + GNUNET_CONTAINER_DLL_insert_after (h->tq_head, h->tq_tail, h->tq_tail, tqe); + trigger_transmit (h); +} + + +/** + * Context for an iteration request. + */ +struct GNUNET_PEERINFO_IteratorContext +{ + /** + * Handle to the PEERINFO service. + */ + struct GNUNET_PEERINFO_Handle *h; + + /** + * Function to call with the results. + */ + GNUNET_PEERINFO_Processor callback; + + /** + * Closure for 'callback'. + */ + void *callback_cls; + + /** + * Our entry in the transmission queue. + */ + struct TransmissionQueueEntry *tqe; + + /** + * Task responsible for timeout. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * Timeout for the operation. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Are we now receiving? + */ + int in_receive; +}; + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_PEERINFO_IteratorContext *ic = cls; + const struct InfoMessage *im; + const struct GNUNET_HELLO_Message *hello; + uint16_t ms; + + ic->h->in_receive = GNUNET_NO; + if (msg == NULL) + { + reconnect (ic->h); + if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (ic->timeout_task); + if (ic->callback != NULL) + ic->callback (ic->callback_cls, NULL, NULL, + _("Failed to receive response from `PEERINFO' service.")); + GNUNET_free (ic); + return; + } + if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END) + { +#if DEBUG_PEERINFO + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received end of list of peers from `%s' service\n", "PEERINFO"); +#endif + trigger_transmit (ic->h); + if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (ic->timeout_task); + if (ic->callback != NULL) + ic->callback (ic->callback_cls, NULL, NULL, NULL); + GNUNET_free (ic); + return; + } + ms = ntohs (msg->size); + if ((ms < sizeof (struct InfoMessage)) || + (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO)) + { + GNUNET_break (0); + reconnect (ic->h); + if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (ic->timeout_task); + if (ic->callback != NULL) + ic->callback (ic->callback_cls, NULL, NULL, + _("Received invalid message from `PEERINFO' service.\n")); + GNUNET_free (ic); + return; + } + im = (const struct InfoMessage *) msg; + GNUNET_break (0 == ntohl (im->reserved)); + hello = NULL; + if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader)) + { + hello = (const struct GNUNET_HELLO_Message *) &im[1]; + if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello)) + { + GNUNET_break (0); + reconnect (ic->h); + if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (ic->timeout_task); + if (ic->callback != NULL) + ic->callback (ic->callback_cls, NULL, NULL, + _("Received invalid message from `PEERINFO' service.\n")); + GNUNET_free (ic); + return; + } + } +#if DEBUG_PEERINFO + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received %u bytes of `%s' information about peer `%s' from `%s' service\n", + (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello), "HELLO", + GNUNET_i2s (&im->peer), "PEERINFO"); +#endif + ic->h->in_receive = GNUNET_YES; + if (ic->callback != NULL) + ic->callback (ic->callback_cls, &im->peer, hello, NULL); + GNUNET_CLIENT_receive (ic->h->client, &peerinfo_handler, ic, + GNUNET_TIME_absolute_get_remaining (ic->timeout)); +} + + +/** + * We've transmitted the iteration request. Now get ready to process + * the results (or handle transmission error). + * + * @param cls the 'struct GNUNET_PEERINFO_IteratorContext' + * @param transmit_success GNUNET_OK if transmission worked + */ +static void +iterator_start_receive (void *cls, int transmit_success) +{ + struct GNUNET_PEERINFO_IteratorContext *ic = cls; + + if (GNUNET_OK != transmit_success) + { + if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ic->timeout_task); + ic->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + reconnect (ic->h); + if (ic->callback != NULL) + ic->callback (ic->callback_cls, NULL, NULL, + _ + ("Failed to transmit iteration request to `PEERINFO' service\n")); + GNUNET_free (ic); + return; + } +#if DEBUG_PEERINFO + LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n", + "PEERINFO"); +#endif + ic->h->in_receive = GNUNET_YES; + ic->in_receive = GNUNET_YES; + ic->tqe = NULL; + GNUNET_CLIENT_receive (ic->h->client, &peerinfo_handler, ic, + GNUNET_TIME_absolute_get_remaining (ic->timeout)); +} + + +/** + * Peerinfo iteration request has timed out. + * + * @param cls the 'struct GNUNET_PEERINFO_IteratorContext*' + * @param tc scheduler context + */ +static void +signal_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_PEERINFO_IteratorContext *ic = cls; + + ic->timeout_task = GNUNET_SCHEDULER_NO_TASK; + if (!ic->in_receive) + GNUNET_CONTAINER_DLL_remove (ic->h->tq_head, ic->h->tq_tail, ic->tqe); + else + reconnect (ic->h); + ic->callback (ic->callback_cls, NULL, NULL, + _ + ("Timeout transmitting iteration request to `PEERINFO' service.\n")); + ic->callback = NULL; + GNUNET_free_non_null (ic->tqe); + GNUNET_free (ic); +} + + +/** + * Call a method for each known matching host and change its trust + * value. The callback method will be invoked once for each matching + * host and then finally once with a NULL pointer. After that final + * invocation, the iterator context must no longer be used. + * + * Instead of calling this function with 'peer == NULL' it is often + * better to use 'GNUNET_PEERINFO_notify'. + * + * @param h handle to the peerinfo service + * @param peer restrict iteration to this peer only (can be NULL) + * @param timeout how long to wait until timing out + * @param callback the method to call for each peer + * @param callback_cls closure for callback + * @return iterator context + */ +struct GNUNET_PEERINFO_IteratorContext * +GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h, + const struct GNUNET_PeerIdentity *peer, + struct GNUNET_TIME_Relative timeout, + GNUNET_PEERINFO_Processor callback, void *callback_cls) +{ + struct GNUNET_MessageHeader *lapm; + struct ListPeerMessage *lpm; + struct GNUNET_PEERINFO_IteratorContext *ic; + struct TransmissionQueueEntry *tqe; + + if (peer == NULL) + { +#if DEBUG_PEERINFO + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Requesting list of peers from PEERINFO service\n"); +#endif + tqe = + GNUNET_malloc (sizeof (struct TransmissionQueueEntry) + + sizeof (struct GNUNET_MessageHeader)); + tqe->size = sizeof (struct GNUNET_MessageHeader); + lapm = (struct GNUNET_MessageHeader *) &tqe[1]; + lapm->size = htons (sizeof (struct GNUNET_MessageHeader)); + lapm->type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL); + } + else + { +#if DEBUG_PEERINFO + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Requesting information on peer `%4s' from PEERINFO service\n", + GNUNET_i2s (peer)); +#endif + tqe = + GNUNET_malloc (sizeof (struct TransmissionQueueEntry) + + sizeof (struct ListPeerMessage)); + tqe->size = sizeof (struct ListPeerMessage); + lpm = (struct ListPeerMessage *) &tqe[1]; + lpm->header.size = htons (sizeof (struct ListPeerMessage)); + lpm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET); + memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity)); + } + ic = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_IteratorContext)); + ic->h = h; + ic->tqe = tqe; + ic->callback = callback; + ic->callback_cls = callback_cls; + ic->timeout = GNUNET_TIME_relative_to_absolute (timeout); + ic->timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, &signal_timeout, ic); + tqe->timeout = ic->timeout; + tqe->cont = &iterator_start_receive; + tqe->cont_cls = ic; + tqe->timeout = ic->timeout; + GNUNET_CONTAINER_DLL_insert_after (h->tq_head, h->tq_tail, h->tq_tail, tqe); + trigger_transmit (h); + return ic; +} + + +/** + * Cancel an iteration over peer information. + * + * @param ic context of the iterator to cancel + */ +void +GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic) +{ + if (ic->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ic->timeout_task); + ic->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + ic->callback = NULL; + if (GNUNET_YES == ic->in_receive) + return; /* need to finish processing */ + GNUNET_CONTAINER_DLL_remove (ic->h->tq_head, ic->h->tq_tail, ic->tqe); + GNUNET_free (ic->tqe); + GNUNET_free (ic); +} + + +/* end of peerinfo_api.c */ diff --git a/src/peerinfo/peerinfo_api_notify.c b/src/peerinfo/peerinfo_api_notify.c new file mode 100644 index 0000000..a0588db --- /dev/null +++ b/src/peerinfo/peerinfo_api_notify.c @@ -0,0 +1,292 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file peerinfo/peerinfo_api_notify.c + * @brief notify API to access peerinfo service + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_client_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_protocols.h" +#include "gnunet_time_lib.h" +#include "peerinfo.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "nse-api",__VA_ARGS__) + +/** + * Context for the info handler. + */ +struct GNUNET_PEERINFO_NotifyContext +{ + + /** + * Our connection to the PEERINFO service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Function to call with information. + */ + GNUNET_PEERINFO_Processor callback; + + /** + * Closure for callback. + */ + void *callback_cls; + + /** + * Handle to our initial request for message transmission to + * the peerinfo service. + */ + struct GNUNET_CLIENT_TransmitHandle *init; + + /** + * Configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Tasked used for delayed re-connection attempt. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + +}; + + +/** + * Send a request to the peerinfo service to start being + * notified about all changes to peer information. + * + * @param nc our context + */ +static void +request_notifications (struct GNUNET_PEERINFO_NotifyContext *nc); + + +/** + * Read notifications from the client handle and pass them + * to the callback. + * + * @param nc our context + */ +static void +receive_notifications (struct GNUNET_PEERINFO_NotifyContext *nc); + + +/** + * Task to re-try connecting to peerinfo. + * + * @param cls the 'struct GNUNET_PEERINFO_NotifyContext' + * @param tc scheduler context + */ +static void +reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_PEERINFO_NotifyContext *nc = cls; + + nc->task = GNUNET_SCHEDULER_NO_TASK; + nc->client = GNUNET_CLIENT_connect ("peerinfo", nc->cfg); + if (NULL == nc->client) + { + /* ugh */ + nc->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, nc); + return; + } + request_notifications (nc); +} + + +/** + * Receive a peerinfo information message, process it and + * go for more. + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +process_notification (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_PEERINFO_NotifyContext *nc = cls; + const struct InfoMessage *im; + const struct GNUNET_HELLO_Message *hello; + uint16_t ms; + + if (msg == NULL) + { + GNUNET_CLIENT_disconnect (nc->client, GNUNET_NO); + reconnect (nc, NULL); + return; + } + ms = ntohs (msg->size); + if ((ms < sizeof (struct InfoMessage)) || + (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO)) + { + GNUNET_break (0); + GNUNET_CLIENT_disconnect (nc->client, GNUNET_NO); + nc->client = GNUNET_CLIENT_connect ("peerinfo", nc->cfg); + request_notifications (nc); + return; + } + im = (const struct InfoMessage *) msg; + hello = NULL; + if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader)) + { + hello = (const struct GNUNET_HELLO_Message *) &im[1]; + if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello)) + { + GNUNET_break (0); + GNUNET_CLIENT_disconnect (nc->client, GNUNET_NO); + nc->client = GNUNET_CLIENT_connect ("peerinfo", nc->cfg); + request_notifications (nc); + return; + } + } +#if DEBUG_PEERINFO + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received information about peer `%s' from peerinfo database\n", + GNUNET_i2s (&im->peer)); +#endif + nc->callback (nc->callback_cls, &im->peer, hello, NULL); + receive_notifications (nc); +} + + +/** + * Read notifications from the client handle and pass them + * to the callback. + * + * @param nc our context + */ +static void +receive_notifications (struct GNUNET_PEERINFO_NotifyContext *nc) +{ + GNUNET_CLIENT_receive (nc->client, &process_notification, nc, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Transmit our init-notify request, start receiving. + * + * @param cls closure (our 'struct GNUNET_PEERINFO_NotifyContext') + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_notify_request (void *cls, size_t size, void *buf) +{ + struct GNUNET_PEERINFO_NotifyContext *nc = cls; + struct GNUNET_MessageHeader hdr; + + nc->init = NULL; + if (buf == NULL) + { + GNUNET_CLIENT_disconnect (nc->client, GNUNET_NO); + nc->client = GNUNET_CLIENT_connect ("peerinfo", nc->cfg); + request_notifications (nc); + return 0; + } + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + hdr.size = htons (sizeof (struct GNUNET_MessageHeader)); + hdr.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY); + memcpy (buf, &hdr, sizeof (struct GNUNET_MessageHeader)); + receive_notifications (nc); + return sizeof (struct GNUNET_MessageHeader); +} + + +/** + * Send a request to the peerinfo service to start being + * notified about all changes to peer information. + * + * @param nc our context + */ +static void +request_notifications (struct GNUNET_PEERINFO_NotifyContext *nc) +{ + GNUNET_assert (NULL == nc->init); + nc->init = + GNUNET_CLIENT_notify_transmit_ready (nc->client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &transmit_notify_request, + nc); +} + + +/** + * Call a method whenever our known information about peers + * changes. Initially calls the given function for all known + * peers and then only signals changes. + * + * @param cfg configuration to use + * @param callback the method to call for each peer + * @param callback_cls closure for callback + * @return NULL on error + */ +struct GNUNET_PEERINFO_NotifyContext * +GNUNET_PEERINFO_notify (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_PEERINFO_Processor callback, void *callback_cls) +{ + struct GNUNET_PEERINFO_NotifyContext *nc; + struct GNUNET_CLIENT_Connection *client; + + client = GNUNET_CLIENT_connect ("peerinfo", cfg); + if (client == NULL) + { + LOG (GNUNET_ERROR_TYPE_WARNING, _("Could not connect to `%s' service.\n"), + "peerinfo"); + return NULL; + } + nc = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_NotifyContext)); + nc->cfg = cfg; + nc->client = client; + nc->callback = callback; + nc->callback_cls = callback_cls; + request_notifications (nc); + return nc; +} + + +/** + * Stop notifying about changes. + * + * @param nc context to stop notifying + */ +void +GNUNET_PEERINFO_notify_cancel (struct GNUNET_PEERINFO_NotifyContext *nc) +{ + if (NULL != nc->init) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (nc->init); + nc->init = NULL; + } + if (NULL != nc->client) + GNUNET_CLIENT_disconnect (nc->client, GNUNET_NO); + if (GNUNET_SCHEDULER_NO_TASK != nc->task) + GNUNET_SCHEDULER_cancel (nc->task); + GNUNET_free (nc); +} + +/* end of peerinfo_api_notify.c */ diff --git a/src/peerinfo/perf_peerinfo_api.c b/src/peerinfo/perf_peerinfo_api.c new file mode 100755 index 0000000..3396930 --- /dev/null +++ b/src/peerinfo/perf_peerinfo_api.c @@ -0,0 +1,217 @@ +/* + This file is part of GNUnet. + (C) 2004, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file peerinfo/test_peerinfo_hammer.c + * @brief testcase for peerinfo_api.c, hopefully hammer the peerinfo service + * @author Nathan Evans + */ + +#include "platform.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_program_lib.h" +#include "gnunet_time_lib.h" +#include "peerinfo.h" +#include + +#define START_SERVICE 1 + +#define NUM_REQUESTS 5000 + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_PEERINFO_IteratorContext *ic[NUM_REQUESTS]; + +static struct GNUNET_PEERINFO_Handle *h; + +static unsigned int numpeers; + +static struct GNUNET_PeerIdentity pid; + + +static int +check_it (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ +#if DEBUG + if (addrlen > 0) + { + FPRINTF (stderr, "name: %s, addr: %s\n", tname, (const char *) addr); + } +#endif + return GNUNET_OK; +} + + +static size_t +address_generator (void *cls, size_t max, void *buf) +{ + size_t *agc = cls; + size_t ret; + char *caddress; + struct GNUNET_HELLO_Address address; + + if (*agc == 0) + return 0; + + GNUNET_asprintf (&caddress, "Address%d", *agc); + address.peer = pid; + address.address_length = strlen (caddress) + 1; + address.address = caddress; + address.transport_name = "peerinfotest"; + ret = + GNUNET_HELLO_add_address (&address, + GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_UNIT_HOURS), buf, max); + GNUNET_free (caddress); + *agc = 0; + return ret; +} + + +static void +add_peer (size_t i) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + struct GNUNET_HELLO_Message *h2; + + memset (&pkey, i, sizeof (pkey)); + GNUNET_CRYPTO_hash (&pkey, sizeof (pkey), &pid.hashPubKey); + h2 = GNUNET_HELLO_create (&pkey, &address_generator, &i); + GNUNET_PEERINFO_add_peer (h, h2); + GNUNET_free (h2); +} + + +static void +process (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, const char *err_msg) +{ + if (peer == NULL) + { +#if DEBUG + FPRINTF (stderr, "Process received NULL response\n"); +#endif + } + else + { +#if DEBUG + FPRINTF (stderr, "Processed a peer\n"); +#endif + numpeers++; + if (0 && (hello != NULL)) + GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &check_it, NULL); + + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + size_t i; + + cfg = c; + h = GNUNET_PEERINFO_connect (cfg); + GNUNET_assert (h != NULL); + for (i = 0; i < NUM_REQUESTS; i++) + { + add_peer (i); + ic[i] = + GNUNET_PEERINFO_iterate (h, NULL, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 30), &process, cls); + } +} + +static int +check () +{ + int ok = 0; + + char *const argv[] = { "perf-peerinfo-api", + "-c", + "test_peerinfo_api_data.conf", +#if DEBUG_PEERINFO + "-L", "DEBUG", +#else + "-L", "ERROR", +#endif + NULL + }; +#if START_SERVICE + struct GNUNET_OS_Process *proc; + + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-peerinfo", + "gnunet-service-peerinfo", +#if DEBUG_PEERINFO + "-L", "DEBUG", +#else + "-L", "ERROR", +#endif + "-c", "test_peerinfo_api_data.conf", NULL); +#endif + GNUNET_assert (NULL != proc); + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "perf-peerinfo-api", "nohelp", options, &run, &ok); + FPRINTF (stderr, "Received %u/%u calls before timeout\n", numpeers, + NUM_REQUESTS * NUM_REQUESTS / 2); + GAUGER ("PEERINFO", "Peerinfo lookups", numpeers / 30, "peers/s"); +#if START_SERVICE + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + ok = 1; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; + +#endif + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("perf_peerinfo_api", +#if DEBUG_PEERINFO + "DEBUG", +#else + "ERROR", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-peerinfo"); + return ret; +} + +/* end of perf_peerinfo_api.c */ diff --git a/src/peerinfo/test_peerinfo_api.c b/src/peerinfo/test_peerinfo_api.c new file mode 100644 index 0000000..71da46b --- /dev/null +++ b/src/peerinfo/test_peerinfo_api.c @@ -0,0 +1,220 @@ +/* + This file is part of GNUnet. + (C) 2004, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file peerinfo/test_peerinfo_api.c + * @brief testcase for peerinfo_api.c + * @author Christian Grothoff + * + * TODO: + * - test merging of HELLOs (add same peer twice...) + */ + +#include "platform.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_program_lib.h" +#include "gnunet_time_lib.h" +#include "peerinfo.h" + +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_PEERINFO_IteratorContext *ic; + +static struct GNUNET_PEERINFO_Handle *h; + +static unsigned int retries; + +static int +check_it (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + unsigned int *agc = cls; + + if (address != NULL) + { + GNUNET_assert (0 == strcmp ("peerinfotest", address->transport_name)); + GNUNET_assert (0 == + strncmp ("Address", address->address, + address->address_length)); + (*agc) -= (1 << (address->address_length - 1)); + } + return GNUNET_OK; +} + + +static size_t +address_generator (void *cls, size_t max, void *buf) +{ + size_t *agc = cls; + size_t ret; + struct GNUNET_HELLO_Address address; + + if (0 == *agc) + return 0; + memset (&address.peer, 0, sizeof (struct GNUNET_PeerIdentity)); + address.address = "Address"; + address.transport_name = "peerinfotest"; + address.address_length = *agc; + ret = + GNUNET_HELLO_add_address (&address, + GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_UNIT_HOURS), buf, max); + (*agc)--; + return ret; +} + + +static void +add_peer () +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + struct GNUNET_PeerIdentity pid; + struct GNUNET_HELLO_Message *h2; + size_t agc; + + agc = 2; + memset (&pkey, 32, sizeof (pkey)); + GNUNET_CRYPTO_hash (&pkey, sizeof (pkey), &pid.hashPubKey); + h2 = GNUNET_HELLO_create (&pkey, &address_generator, &agc); + GNUNET_PEERINFO_add_peer (h, h2); + GNUNET_free (h2); + +} + + +static void +process (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, const char *err_msg) +{ + int *ok = cls; + unsigned int agc; + + if (err_msg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Error in communication with PEERINFO service\n")); + } + + if (peer == NULL) + { + ic = NULL; + if ((3 == *ok) && (retries < 50)) + { + /* try again */ + retries++; + add_peer (); + ic = GNUNET_PEERINFO_iterate (h, NULL, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 15), &process, + cls); + return; + } + GNUNET_assert (peer == NULL); + GNUNET_assert (2 == *ok); + GNUNET_PEERINFO_disconnect (h); + h = NULL; + *ok = 0; + return; + } + if (hello != NULL) + { + GNUNET_assert (3 == *ok); + agc = 3; + GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &check_it, &agc); + GNUNET_assert (agc == 0); + *ok = 2; + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + h = GNUNET_PEERINFO_connect (cfg); + GNUNET_assert (h != NULL); + add_peer (); + ic = GNUNET_PEERINFO_iterate (h, NULL, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 15), &process, cls); +} + + +static int +check () +{ + int ok = 3; + struct GNUNET_OS_Process *proc; + + char *const argv[] = { "test-peerinfo-api", + "-c", + "test_peerinfo_api_data.conf", +#if DEBUG_PEERINFO + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-peerinfo", + "gnunet-service-peerinfo", +#if DEBUG_PEERINFO + "-L", "DEBUG", +#endif + "-c", "test_peerinfo_api_data.conf", NULL); + GNUNET_assert (NULL != proc); + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-peerinfo-api", "nohelp", options, &run, &ok); + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + ok = 1; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_peerinfo_api", +#if DEBUG_PEERINFO + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-peerinfo"); + return ret; +} + +/* end of test_peerinfo_api.c */ diff --git a/src/peerinfo/test_peerinfo_api_data.conf b/src/peerinfo/test_peerinfo_api_data.conf new file mode 100644 index 0000000..6caa1e4 --- /dev/null +++ b/src/peerinfo/test_peerinfo_api_data.conf @@ -0,0 +1,16 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunet-peerinfo/ + +[peerinfo] +PORT = 22354 +DEBUG = NO + +[dns] +AUTOSTART = NO + + + +[nse] +AUTOSTART = NO + + diff --git a/src/pt/Makefile.am b/src/pt/Makefile.am new file mode 100644 index 0000000..385bff6 --- /dev/null +++ b/src/pt/Makefile.am @@ -0,0 +1,31 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +plugindir = $(libdir)/gnunet + +dist_pkgcfg_DATA = \ + pt.conf + +bin_PROGRAMS = \ + gnunet-daemon-pt $(PTBIN) + +gnunet_daemon_pt_SOURCES = \ + gnunet-daemon-pt.c +gnunet_daemon_pt_LDADD = \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(GN_LIBINTL) diff --git a/src/pt/Makefile.in b/src/pt/Makefile.in new file mode 100644 index 0000000..ebdc995 --- /dev/null +++ b/src/pt/Makefile.in @@ -0,0 +1,700 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-daemon-pt$(EXEEXT) +subdir = src/pt +DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_daemon_pt_OBJECTS = gnunet-daemon-pt.$(OBJEXT) +gnunet_daemon_pt_OBJECTS = $(am_gnunet_daemon_pt_OBJECTS) +am__DEPENDENCIES_1 = +gnunet_daemon_pt_DEPENDENCIES = \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(gnunet_daemon_pt_SOURCES) +DIST_SOURCES = $(gnunet_daemon_pt_SOURCES) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +DATA = $(dist_pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +pkgcfgdir = $(pkgdatadir)/config.d/ +plugindir = $(libdir)/gnunet +dist_pkgcfg_DATA = \ + pt.conf + +gnunet_daemon_pt_SOURCES = \ + gnunet-daemon-pt.c + +gnunet_daemon_pt_LDADD = \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/dns/libgnunetdns.la \ + $(top_builddir)/src/dns/libgnunetdnsparser.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(GN_LIBINTL) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pt/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/pt/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-daemon-pt$(EXEEXT): $(gnunet_daemon_pt_OBJECTS) $(gnunet_daemon_pt_DEPENDENCIES) + @rm -f gnunet-daemon-pt$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_daemon_pt_OBJECTS) $(gnunet_daemon_pt_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-daemon-pt.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-dist_pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am \ + install-dist_pkgcfgDATA install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-dist_pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/pt/gnunet-daemon-pt.c b/src/pt/gnunet-daemon-pt.c new file mode 100644 index 0000000..2ad8468 --- /dev/null +++ b/src/pt/gnunet-daemon-pt.c @@ -0,0 +1,978 @@ +/* + This file is part of GNUnet. + (C) 2010, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file pt/gnunet-daemon-pt.c + * @brief tool to manipulate DNS and VPN services to perform protocol translation (IPvX over GNUnet) + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_dns_service.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_mesh_service.h" +#include "gnunet_tun_lib.h" +#include "gnunet_vpn_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_applications.h" + + +/** + * After how long do we time out if we could not get an IP from VPN or MESH? + */ +#define TIMEOUT GNUNET_TIME_UNIT_MINUTES + + +/** + * How many bytes of payload do we allow at most for a DNS reply? + * Given that this is pretty much limited to loopback, we can be + * pretty high (Linux loopback defaults to 16k, most local UDP packets + * should survive up to 9k (NFS), so 8k should be pretty safe in + * general). + */ +#define MAX_DNS_SIZE (8 * 1024) + + +/** + * Which group of DNS records are we currently processing? + */ +enum RequestGroup + { + /** + * DNS answers + */ + ANSWERS = 0, + + /** + * DNS authority records + */ + AUTHORITY_RECORDS = 1, + + /** + * DNS additional records + */ + ADDITIONAL_RECORDS = 2, + + /** + * We're done processing. + */ + END = 3 + }; + + +/** + * Information tracked per DNS reply that we are processing. + */ +struct ReplyContext +{ + /** + * Handle to submit the final result. + */ + struct GNUNET_DNS_RequestHandle *rh; + + /** + * DNS packet that is being modified. + */ + struct GNUNET_DNSPARSER_Packet *dns; + + /** + * Active redirection request with the VPN. + */ + struct GNUNET_VPN_RedirectionRequest *rr; + + /** + * Record for which we have an active redirection request. + */ + struct GNUNET_DNSPARSER_Record *rec; + + /** + * Offset in the current record group that is being modified. + */ + unsigned int offset; + + /** + * Group that is being modified + */ + enum RequestGroup group; + +}; + + +/** + * State we keep for a request that is going out via MESH. + */ +struct RequestContext +{ + /** + * We keep these in a DLL. + */ + struct RequestContext *next; + + /** + * We keep these in a DLL. + */ + struct RequestContext *prev; + + /** + * Handle for interaction with DNS service. + */ + struct GNUNET_DNS_RequestHandle *rh; + + /** + * Message we're sending out via MESH, allocated at the + * end of this struct. + */ + const struct GNUNET_MessageHeader *mesh_message; + + /** + * Task used to abort this operation with timeout. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * ID of the original DNS request (used to match the reply). + */ + uint16_t dns_id; + + /** + * GNUNET_NO if this request is still in the transmit_queue, + * GNUNET_YES if we are in the receive_queue. + */ + int16_t was_transmitted; + +}; + + +/** + * The handle to the configuration used throughout the process + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * The handle to the VPN + */ +static struct GNUNET_VPN_Handle *vpn_handle; + +/** + * The handle to the MESH service + */ +static struct GNUNET_MESH_Handle *mesh_handle; + +/** + * Tunnel we use for DNS requests over MESH. + */ +static struct GNUNET_MESH_Tunnel *mesh_tunnel; + +/** + * Active transmission request with MESH (or NULL). + */ +static struct GNUNET_MESH_TransmitHandle *mesh_th; + +/** + * Head of DLL of requests to be transmitted to mesh_tunnel. + */ +static struct RequestContext *transmit_queue_head; + +/** + * Tail of DLL of requests to be transmitted to mesh_tunnel. + */ +static struct RequestContext *transmit_queue_tail; + +/** + * Head of DLL of requests waiting for a response. + */ +static struct RequestContext *receive_queue_head; + +/** + * Tail of DLL of requests waiting for a response. + */ +static struct RequestContext *receive_queue_tail; + +/** + * Statistics. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * The handle to DNS post-resolution modifications. + */ +static struct GNUNET_DNS_Handle *dns_post_handle; + +/** + * The handle to DNS pre-resolution modifications. + */ +static struct GNUNET_DNS_Handle *dns_pre_handle; + +/** + * Are we doing IPv4-pt? + */ +static int ipv4_pt; + +/** + * Are we doing IPv6-pt? + */ +static int ipv6_pt; + +/** + * Are we tunneling DNS queries? + */ +static int dns_tunnel; + +/** + * Number of DNS exit peers we currently have in the mesh tunnel. + * Used to see if using the mesh tunnel makes any sense right now. + */ +static unsigned int dns_exit_available; + + +/** + * We're done modifying all records in the response. Submit the reply + * and free the resources of the rc. + * + * @param rc context to process + */ +static void +finish_request (struct ReplyContext *rc) +{ + char *buf; + size_t buf_len; + + if (GNUNET_SYSERR == + GNUNET_DNSPARSER_pack (rc->dns, + MAX_DNS_SIZE, + &buf, + &buf_len)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to pack DNS request. Dropping.\n")); + GNUNET_DNS_request_drop (rc->rh); + } + else + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS requests mapped to VPN"), + 1, GNUNET_NO); + GNUNET_DNS_request_answer (rc->rh, + buf_len, buf); + GNUNET_free (buf); + } + GNUNET_DNSPARSER_free_packet (rc->dns); + GNUNET_free (rc); +} + + +/** + * Process the next record of the given request context. + * When done, submit the reply and free the resources of + * the rc. + * + * @param rc context to process + */ +static void +submit_request (struct ReplyContext *rc); + + +/** + * Callback invoked from the VPN service once a redirection is + * available. Provides the IP address that can now be used to + * reach the requested destination. We substitute the active + * record and then continue with 'submit_request' to look at + * the other records. + * + * @param cls our 'struct ReplyContext' + * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error; + * will match 'result_af' from the request + * @param address IP address (struct in_addr or struct in_addr6, depending on 'af') + * that the VPN allocated for the redirection; + * traffic to this IP will now be redirected to the + * specified target peer; NULL on error + */ +static void +vpn_allocation_callback (void *cls, + int af, + const void *address) +{ + struct ReplyContext *rc = cls; + + rc->rr = NULL; + if (af == AF_UNSPEC) + { + GNUNET_DNS_request_drop (rc->rh); + GNUNET_DNSPARSER_free_packet (rc->dns); + GNUNET_free (rc); + return; + } + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS records modified"), + 1, GNUNET_NO); + switch (rc->rec->type) + { + case GNUNET_DNSPARSER_TYPE_A: + GNUNET_assert (AF_INET == af); + memcpy (rc->rec->data.raw.data, address, sizeof (struct in_addr)); + break; + case GNUNET_DNSPARSER_TYPE_AAAA: + GNUNET_assert (AF_INET6 == af); + memcpy (rc->rec->data.raw.data, address, sizeof (struct in6_addr)); + break; + default: + GNUNET_assert (0); + return; + } + rc->rec = NULL; + submit_request (rc); +} + + +/** + * Modify the given DNS record by asking VPN to create a tunnel + * to the given address. When done, continue with submitting + * other records from the request context ('submit_request' is + * our continuation). + * + * @param rc context to process + * @param rec record to modify + */ +static void +modify_address (struct ReplyContext *rc, + struct GNUNET_DNSPARSER_Record *rec) +{ + int af; + + switch (rec->type) + { + case GNUNET_DNSPARSER_TYPE_A: + af = AF_INET; + GNUNET_assert (rec->data.raw.data_len == sizeof (struct in_addr)); + break; + case GNUNET_DNSPARSER_TYPE_AAAA: + af = AF_INET6; + GNUNET_assert (rec->data.raw.data_len == sizeof (struct in6_addr)); + break; + default: + GNUNET_assert (0); + return; + } + rc->rec = rec; + rc->rr = GNUNET_VPN_redirect_to_ip (vpn_handle, + af, af, + rec->data.raw.data, + GNUNET_NO /* nac */, + GNUNET_TIME_relative_to_absolute (TIMEOUT), + &vpn_allocation_callback, + rc); +} + + +/** + * Process the next record of the given request context. + * When done, submit the reply and free the resources of + * the rc. + * + * @param rc context to process + */ +static void +submit_request (struct ReplyContext *rc) +{ + struct GNUNET_DNSPARSER_Record *ra; + unsigned int ra_len; + unsigned int i; + + while (1) + { + switch (rc->group) + { + case ANSWERS: + ra = rc->dns->answers; + ra_len = rc->dns->num_answers; + break; + case AUTHORITY_RECORDS: + ra = rc->dns->authority_records; + ra_len = rc->dns->num_authority_records; + break; + case ADDITIONAL_RECORDS: + ra = rc->dns->additional_records; + ra_len = rc->dns->num_additional_records; + break; + case END: + finish_request (rc); + return; + default: + GNUNET_assert (0); + } + for (i=rc->offset;ioffset = i + 1; + modify_address (rc, &ra[i]); + return; + } + break; + case GNUNET_DNSPARSER_TYPE_AAAA: + if (ipv6_pt) + { + rc->offset = i + 1; + modify_address (rc, &ra[i]); + return; + } + break; + } + } + rc->group++; + } +} + + +/** + * Test if any of the given records need protocol-translation work. + * + * @param ra array of records + * @param ra_len number of entries in ra + * @return GNUNET_YES if any of the given records require protocol-translation + */ +static int +work_test (const struct GNUNET_DNSPARSER_Record *ra, + unsigned int ra_len) +{ + unsigned int i; + + for (i=0;ianswers, dns->num_answers); + work |= work_test (dns->authority_records, dns->num_authority_records); + work |= work_test (dns->additional_records, dns->num_additional_records); + if (! work) + { + GNUNET_DNS_request_forward (rh); + GNUNET_DNSPARSER_free_packet (dns); + return; + } + rc = GNUNET_malloc (sizeof (struct ReplyContext)); + rc->rh = rh; + rc->dns = dns; + rc->offset = 0; + rc->group = ANSWERS; + submit_request (rc); +} + + +/** + * Transmit a DNS request via MESH and move the request + * handle to the receive queue. + * + * @param cls NULL + * @param size number of bytes available in buf + * @param buf where to copy the message + * @return number of bytes written to buf + */ +static size_t +transmit_dns_request_to_mesh (void *cls, + size_t size, + void *buf) +{ + struct RequestContext *rc; + size_t mlen; + + mesh_th = NULL; + if (NULL == (rc = transmit_queue_head)) + return 0; + mlen = ntohs (rc->mesh_message->size); + if (mlen > size) + { + mesh_th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, + GNUNET_NO, 0, + TIMEOUT, + NULL, mlen, + &transmit_dns_request_to_mesh, + NULL); + return 0; + } + GNUNET_assert (GNUNET_NO == rc->was_transmitted); + memcpy (buf, rc->mesh_message, mlen); + GNUNET_CONTAINER_DLL_remove (transmit_queue_head, + transmit_queue_tail, + rc); + rc->was_transmitted = GNUNET_YES; + GNUNET_CONTAINER_DLL_insert (receive_queue_head, + receive_queue_tail, + rc); + rc = transmit_queue_head; + if (NULL != rc) + mesh_th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, + GNUNET_NO, 0, + TIMEOUT, + NULL, ntohs (rc->mesh_message->size), + &transmit_dns_request_to_mesh, + NULL); + return mlen; +} + + +/** + * Task run if the time to answer a DNS request via MESH is over. + * + * @param cls the 'struct RequestContext' to abort + * @param tc scheduler context + */ +static void +timeout_request (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct RequestContext *rc = cls; + + if (rc->was_transmitted) + GNUNET_CONTAINER_DLL_remove (receive_queue_head, + receive_queue_tail, + rc); + else + GNUNET_CONTAINER_DLL_remove (transmit_queue_head, + transmit_queue_tail, + rc); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS requests dropped (timeout)"), + 1, GNUNET_NO); + GNUNET_DNS_request_drop (rc->rh); + GNUNET_free (rc); +} + + +/** + * This function is called *before* the DNS request has been + * given to a "local" DNS resolver. Tunneling for DNS requests + * was enabled, so we now need to send the request via some MESH + * tunnel to a DNS EXIT for resolution. + * + * @param cls closure + * @param rh request handle to user for reply + * @param request_length number of bytes in request + * @param request udp payload of the DNS request + */ +static void +dns_pre_request_handler (void *cls, + struct GNUNET_DNS_RequestHandle *rh, + size_t request_length, + const char *request) +{ + struct RequestContext *rc; + size_t mlen; + struct GNUNET_MessageHeader hdr; + struct GNUNET_TUN_DnsHeader dns; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS requests intercepted"), + 1, GNUNET_NO); + if (0 == dns_exit_available) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS requests dropped (DNS mesh tunnel down)"), + 1, GNUNET_NO); + GNUNET_DNS_request_drop (rh); + return; + } + if (request_length < sizeof (dns)) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS requests dropped (malformed)"), + 1, GNUNET_NO); + GNUNET_DNS_request_drop (rh); + return; + } + memcpy (&dns, request, sizeof (dns)); + GNUNET_assert (NULL != mesh_tunnel); + mlen = sizeof (struct GNUNET_MessageHeader) + request_length; + rc = GNUNET_malloc (sizeof (struct RequestContext) + mlen); + rc->rh = rh; + rc->mesh_message = (const struct GNUNET_MessageHeader*) &rc[1]; + rc->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, + &timeout_request, + rc); + rc->dns_id = dns.id; + hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET); + hdr.size = htons (mlen); + memcpy (&rc[1], &hdr, sizeof (struct GNUNET_MessageHeader)); + memcpy (&(((char*)&rc[1])[sizeof (struct GNUNET_MessageHeader)]), + request, + request_length); + GNUNET_CONTAINER_DLL_insert_tail (transmit_queue_head, + transmit_queue_tail, + rc); + if (NULL == mesh_th) + mesh_th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, + GNUNET_NO, 0, + TIMEOUT, + NULL, mlen, + &transmit_dns_request_to_mesh, + NULL); +} + + +/** + * Process a request via mesh to perform a DNS query. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_dns_response (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct GNUNET_TUN_DnsHeader dns; + size_t mlen; + struct RequestContext *rc; + + mlen = ntohs (message->size); + mlen -= sizeof (struct GNUNET_MessageHeader); + if (mlen < sizeof (struct GNUNET_TUN_DnsHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + memcpy (&dns, &message[1], sizeof (dns)); + for (rc = receive_queue_head; NULL != rc; rc = rc->next) + { + GNUNET_assert (GNUNET_YES == rc->was_transmitted); + if (dns.id == rc->dns_id) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS replies received"), + 1, GNUNET_NO); + GNUNET_DNS_request_answer (rc->rh, + mlen, + (const void*) &message[1]); + GNUNET_CONTAINER_DLL_remove (receive_queue_head, + receive_queue_tail, + rc); + GNUNET_SCHEDULER_cancel (rc->timeout_task); + GNUNET_free (rc); + return GNUNET_OK; + } + } + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS replies dropped (too late?)"), + 1, GNUNET_NO); + return GNUNET_OK; +} + + +/** + * The MESH DNS tunnel went down. Abort all pending DNS + * requests (we're unlikely to get an answer in time). + */ +static void +abort_all_requests () +{ + struct RequestContext *rc; + + while (NULL != (rc = receive_queue_head)) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS requests aborted (tunnel down)"), + 1, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (receive_queue_head, + receive_queue_tail, + rc); + GNUNET_DNS_request_drop (rc->rh); + GNUNET_SCHEDULER_cancel (rc->timeout_task); + GNUNET_free (rc); + } + while (NULL != (rc = transmit_queue_head)) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# DNS requests aborted (tunnel down)"), + 1, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (transmit_queue_head, + transmit_queue_tail, + rc); + GNUNET_DNS_request_drop (rc->rh); + GNUNET_SCHEDULER_cancel (rc->timeout_task); + GNUNET_free (rc); + } +} + + +/** + * Method called whenever a peer has disconnected from the tunnel. + * + * @param cls closure + * @param peer peer identity the tunnel stopped working with + */ +static void +mesh_disconnect_handler (void *cls, + const struct + GNUNET_PeerIdentity * peer) +{ + GNUNET_assert (dns_exit_available > 0); + dns_exit_available--; + if (0 == dns_exit_available) + { + if (NULL != mesh_th) + { + GNUNET_MESH_notify_transmit_ready_cancel (mesh_th); + mesh_th = NULL; + } + abort_all_requests (); + } +} + + +/** + * Method called whenever a peer has connected to the tunnel. + * + * @param cls closure + * @param peer peer identity the tunnel was created to, NULL on timeout + * @param atsi performance data for the connection + */ +static void +mesh_connect_handler (void *cls, + const struct GNUNET_PeerIdentity + * peer, + const struct + GNUNET_ATS_Information * atsi) +{ + dns_exit_available++; +} + + +/** + * Function scheduled as very last function, cleans up after us + */ +static void +cleanup (void *cls GNUNET_UNUSED, + const struct GNUNET_SCHEDULER_TaskContext *tskctx) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Protocol translation daemon is shutting down now\n"); + if (vpn_handle != NULL) + { + GNUNET_VPN_disconnect (vpn_handle); + vpn_handle = NULL; + } + if (NULL != mesh_th) + { + GNUNET_MESH_notify_transmit_ready_cancel (mesh_th); + mesh_th = NULL; + } + if (NULL != mesh_tunnel) + { + GNUNET_MESH_tunnel_destroy (mesh_tunnel); + mesh_tunnel = NULL; + } + if (mesh_handle != NULL) + { + GNUNET_MESH_disconnect (mesh_handle); + mesh_handle = NULL; + } + abort_all_requests (); + if (dns_post_handle != NULL) + { + GNUNET_DNS_disconnect (dns_post_handle); + dns_post_handle = NULL; + } + if (dns_pre_handle != NULL) + { + GNUNET_DNS_disconnect (dns_pre_handle); + dns_pre_handle = NULL; + } + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_YES); + stats = NULL; + } +} + + +/** + * @brief Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg_ configuration + */ +static void +run (void *cls, char *const *args GNUNET_UNUSED, + const char *cfgfile GNUNET_UNUSED, + const struct GNUNET_CONFIGURATION_Handle *cfg_) +{ + cfg = cfg_; + stats = GNUNET_STATISTICS_create ("pt", cfg); + ipv4_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg, "pt", "TUNNEL_IPV4"); + ipv6_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg, "pt", "TUNNEL_IPV6"); + dns_tunnel = GNUNET_CONFIGURATION_get_value_yesno (cfg, "pt", "TUNNEL_DNS"); + if (! (ipv4_pt || ipv6_pt || dns_tunnel)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("No useful service enabled. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); + if (ipv4_pt || ipv6_pt) + { + dns_post_handle + = GNUNET_DNS_connect (cfg, + GNUNET_DNS_FLAG_POST_RESOLUTION, + &dns_post_request_handler, NULL); + if (NULL == dns_post_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to %s service. Exiting.\n"), + "DNS"); + GNUNET_SCHEDULER_shutdown (); + return; + } + vpn_handle = GNUNET_VPN_connect (cfg); + if (NULL == vpn_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to %s service. Exiting.\n"), + "VPN"); + GNUNET_SCHEDULER_shutdown (); + return; + } + } + if (dns_tunnel) + { + static struct GNUNET_MESH_MessageHandler mesh_handlers[] = { + {&receive_dns_response, GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET, 0}, + {NULL, 0, 0} + }; + static GNUNET_MESH_ApplicationType mesh_types[] = { + GNUNET_APPLICATION_TYPE_END + }; + + dns_pre_handle + = GNUNET_DNS_connect (cfg, + GNUNET_DNS_FLAG_PRE_RESOLUTION, + &dns_pre_request_handler, NULL); + if (NULL == dns_pre_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to %s service. Exiting.\n"), + "DNS"); + GNUNET_SCHEDULER_shutdown (); + return; + } + mesh_handle = GNUNET_MESH_connect (cfg, 1, NULL, NULL, NULL, + mesh_handlers, mesh_types); + if (NULL == mesh_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to %s service. Exiting.\n"), + "MESH"); + GNUNET_SCHEDULER_shutdown (); + return; + } + mesh_tunnel = GNUNET_MESH_tunnel_create (mesh_handle, + NULL, + &mesh_connect_handler, + &mesh_disconnect_handler, + NULL); + GNUNET_MESH_peer_request_connect_by_type (mesh_tunnel, + GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER); + } +} + + +/** + * The main function + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-pt", + gettext_noop + ("Daemon to run to perform IP protocol translation to GNUnet"), + options, &run, NULL)) ? 0 : 1; +} + + +/* end of gnunet-daemon-pt.c */ diff --git a/src/pt/pt.conf b/src/pt/pt.conf new file mode 100644 index 0000000..39c1fb6 --- /dev/null +++ b/src/pt/pt.conf @@ -0,0 +1,13 @@ +[pt] +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-pt + +# Set this to YES to tunnel IPv4 traffic over GNUnet +TUNNEL_IPV4 = NO + +# Set this to YES to tunnel IPv6 traffic over GNUnet +TUNNEL_IPV6 = NO + +# Set this to YES to tunnel DNS traffic over GNUnet +TUNNEL_DNS = NO + diff --git a/src/statistics/Makefile.am b/src/statistics/Makefile.am new file mode 100644 index 0000000..2d1daf8 --- /dev/null +++ b/src/statistics/Makefile.am @@ -0,0 +1,85 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + statistics.conf + +lib_LTLIBRARIES = libgnunetstatistics.la + +libgnunetstatistics_la_SOURCES = \ + statistics_api.c statistics.h +libgnunetstatistics_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) +libgnunetstatistics_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 1:0:1 + + +bin_PROGRAMS = \ + gnunet-statistics \ + gnunet-service-statistics + +gnunet_statistics_SOURCES = \ + gnunet-statistics.c +gnunet_statistics_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_statistics_DEPENDENCIES = \ + libgnunetstatistics.la + +gnunet_service_statistics_SOURCES = \ + gnunet-service-statistics.c +gnunet_service_statistics_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_service_statistics_DEPENDENCIES = \ + libgnunetstatistics.la + +check_PROGRAMS = \ + test_statistics_api \ + test_statistics_api_loop \ + test_statistics_api_watch + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +endif + +test_statistics_api_SOURCES = \ + test_statistics_api.c +test_statistics_api_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_statistics_api_loop_SOURCES = \ + test_statistics_api_loop.c +test_statistics_api_loop_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_statistics_api_watch_SOURCES = \ + test_statistics_api_watch.c +test_statistics_api_watch_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +check_SCRIPTS = \ + test_gnunet_statistics.sh + +EXTRA_DIST = \ + test_statistics_api_data.conf \ + $(check_SCRIPTS) + + diff --git a/src/statistics/Makefile.in b/src/statistics/Makefile.in new file mode 100644 index 0000000..1930c3a --- /dev/null +++ b/src/statistics/Makefile.in @@ -0,0 +1,951 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-statistics$(EXEEXT) \ + gnunet-service-statistics$(EXEEXT) +check_PROGRAMS = test_statistics_api$(EXEEXT) \ + test_statistics_api_loop$(EXEEXT) \ + test_statistics_api_watch$(EXEEXT) +subdir = src/statistics +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/statistics.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = statistics.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunetstatistics_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgnunetstatistics_la_OBJECTS = statistics_api.lo +libgnunetstatistics_la_OBJECTS = $(am_libgnunetstatistics_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetstatistics_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetstatistics_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_service_statistics_OBJECTS = \ + gnunet-service-statistics.$(OBJEXT) +gnunet_service_statistics_OBJECTS = \ + $(am_gnunet_service_statistics_OBJECTS) +am_gnunet_statistics_OBJECTS = gnunet-statistics.$(OBJEXT) +gnunet_statistics_OBJECTS = $(am_gnunet_statistics_OBJECTS) +am_test_statistics_api_OBJECTS = test_statistics_api.$(OBJEXT) +test_statistics_api_OBJECTS = $(am_test_statistics_api_OBJECTS) +test_statistics_api_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_statistics_api_loop_OBJECTS = \ + test_statistics_api_loop.$(OBJEXT) +test_statistics_api_loop_OBJECTS = \ + $(am_test_statistics_api_loop_OBJECTS) +test_statistics_api_loop_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_statistics_api_watch_OBJECTS = \ + test_statistics_api_watch.$(OBJEXT) +test_statistics_api_watch_OBJECTS = \ + $(am_test_statistics_api_watch_OBJECTS) +test_statistics_api_watch_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetstatistics_la_SOURCES) \ + $(gnunet_service_statistics_SOURCES) \ + $(gnunet_statistics_SOURCES) $(test_statistics_api_SOURCES) \ + $(test_statistics_api_loop_SOURCES) \ + $(test_statistics_api_watch_SOURCES) +DIST_SOURCES = $(libgnunetstatistics_la_SOURCES) \ + $(gnunet_service_statistics_SOURCES) \ + $(gnunet_statistics_SOURCES) $(test_statistics_api_SOURCES) \ + $(test_statistics_api_loop_SOURCES) \ + $(test_statistics_api_watch_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + statistics.conf + +lib_LTLIBRARIES = libgnunetstatistics.la +libgnunetstatistics_la_SOURCES = \ + statistics_api.c statistics.h + +libgnunetstatistics_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) + +libgnunetstatistics_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 1:0:1 + +gnunet_statistics_SOURCES = \ + gnunet-statistics.c + +gnunet_statistics_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_statistics_DEPENDENCIES = \ + libgnunetstatistics.la + +gnunet_service_statistics_SOURCES = \ + gnunet-service-statistics.c + +gnunet_service_statistics_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_service_statistics_DEPENDENCIES = \ + libgnunetstatistics.la + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +test_statistics_api_SOURCES = \ + test_statistics_api.c + +test_statistics_api_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_statistics_api_loop_SOURCES = \ + test_statistics_api_loop.c + +test_statistics_api_loop_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_statistics_api_watch_SOURCES = \ + test_statistics_api_watch.c + +test_statistics_api_watch_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la + +check_SCRIPTS = \ + test_gnunet_statistics.sh + +EXTRA_DIST = \ + test_statistics_api_data.conf \ + $(check_SCRIPTS) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/statistics/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/statistics/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +statistics.conf: $(top_builddir)/config.status $(srcdir)/statistics.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetstatistics.la: $(libgnunetstatistics_la_OBJECTS) $(libgnunetstatistics_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetstatistics_la_LINK) -rpath $(libdir) $(libgnunetstatistics_la_OBJECTS) $(libgnunetstatistics_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-service-statistics$(EXEEXT): $(gnunet_service_statistics_OBJECTS) $(gnunet_service_statistics_DEPENDENCIES) + @rm -f gnunet-service-statistics$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_statistics_OBJECTS) $(gnunet_service_statistics_LDADD) $(LIBS) +gnunet-statistics$(EXEEXT): $(gnunet_statistics_OBJECTS) $(gnunet_statistics_DEPENDENCIES) + @rm -f gnunet-statistics$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_statistics_OBJECTS) $(gnunet_statistics_LDADD) $(LIBS) +test_statistics_api$(EXEEXT): $(test_statistics_api_OBJECTS) $(test_statistics_api_DEPENDENCIES) + @rm -f test_statistics_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_statistics_api_OBJECTS) $(test_statistics_api_LDADD) $(LIBS) +test_statistics_api_loop$(EXEEXT): $(test_statistics_api_loop_OBJECTS) $(test_statistics_api_loop_DEPENDENCIES) + @rm -f test_statistics_api_loop$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_statistics_api_loop_OBJECTS) $(test_statistics_api_loop_LDADD) $(LIBS) +test_statistics_api_watch$(EXEEXT): $(test_statistics_api_watch_OBJECTS) $(test_statistics_api_watch_DEPENDENCIES) + @rm -f test_statistics_api_watch$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_statistics_api_watch_OBJECTS) $(test_statistics_api_watch_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-statistics.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-statistics.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statistics_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_statistics_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_statistics_api_loop.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_statistics_api_watch.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/statistics/gnunet-service-statistics.c b/src/statistics/gnunet-service-statistics.c new file mode 100644 index 0000000..a890d6d --- /dev/null +++ b/src/statistics/gnunet-service-statistics.c @@ -0,0 +1,737 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file statistics/gnunet-service-statistics.c + * @brief program that tracks statistics + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_bio_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_disk_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_service_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_strings_lib.h" +#include "gnunet_time_lib.h" +#include "statistics.h" + +/** + * Watch entry. + */ +struct WatchEntry +{ + + struct WatchEntry *next; + + struct WatchEntry *prev; + + struct GNUNET_SERVER_Client *client; + + uint64_t last_value; + + uint32_t wid; + +}; + + +/** + * Client entry. + */ +struct ClientEntry +{ + + struct ClientEntry *next; + + struct ClientEntry *prev; + + struct GNUNET_SERVER_Client *client; + + uint32_t max_wid; + +}; + +/** + * Entry in the statistics list. + */ +struct StatsEntry +{ + /** + * This is a linked list. + */ + struct StatsEntry *next; + + /** + * Name of the service, points into the + * middle of msg. + */ + const char *service; + + /** + * Name for the value, points into + * the middle of msg. + */ + const char *name; + + /** + * Message that can be used to set this value, + * stored at the end of the memory used by + * this struct. + */ + struct GNUNET_STATISTICS_SetMessage *msg; + + /** + * Watch context for changes to this + * value, or NULL for none. + */ + struct WatchEntry *we_head; + + /** + * Watch context for changes to this + * value, or NULL for none. + */ + struct WatchEntry *we_tail; + + /** + * Our value. + */ + uint64_t value; + + /** + * Unique ID. + */ + uint32_t uid; + + /** + * Is this value persistent? + */ + int persistent; + +}; + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Linked list of our active statistics. + */ +static struct StatsEntry *start; + +static struct ClientEntry *client_head; + +static struct ClientEntry *client_tail; + +/** + * Our notification context. + */ +static struct GNUNET_SERVER_NotificationContext *nc; + +/** + * Counter used to generate unique values. + */ +static uint32_t uidgen; + + +static void +inject_message (void *cls, void *client, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_SERVER_Handle *server = cls; + + GNUNET_break (GNUNET_OK == GNUNET_SERVER_inject (server, NULL, msg)); +} + + +/** + * Load persistent values from disk. Disk format is + * exactly the same format that we also use for + * setting the values over the network. + * + * @param server handle to the server context + */ +static void +load (struct GNUNET_SERVER_Handle *server) +{ + char *fn; + struct GNUNET_BIO_ReadHandle *rh; + struct stat sb; + char *buf; + struct GNUNET_SERVER_MessageStreamTokenizer *mst; + char *emsg; + + fn = GNUNET_DISK_get_home_filename (cfg, "statistics", "statistics.data", + NULL); + if (fn == NULL) + return; + if ((0 != stat (fn, &sb)) || (sb.st_size == 0)) + { + GNUNET_free (fn); + return; + } + buf = GNUNET_malloc (sb.st_size); + rh = GNUNET_BIO_read_open (fn); + if (!rh) + { + GNUNET_free (buf); + GNUNET_free (fn); + return; + } + if (GNUNET_OK != GNUNET_BIO_read (rh, fn, buf, sb.st_size)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "read", fn); + GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg)); + GNUNET_free (buf); + GNUNET_free_non_null (emsg); + GNUNET_free (fn); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Loading %llu bytes of statistics from `%s'\n"), + (unsigned long long) sb.st_size, fn); + mst = GNUNET_SERVER_mst_create (&inject_message, server); + GNUNET_break (GNUNET_OK == + GNUNET_SERVER_mst_receive (mst, NULL, buf, sb.st_size, + GNUNET_YES, GNUNET_NO)); + GNUNET_SERVER_mst_destroy (mst); + GNUNET_free (buf); + GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg)); + GNUNET_free_non_null (emsg); + GNUNET_free (fn); +} + +/** + * Write persistent statistics to disk. + */ +static void +save () +{ + struct StatsEntry *pos; + char *fn; + struct GNUNET_BIO_WriteHandle *wh; + + uint16_t size; + unsigned long long total; + + wh = NULL; + fn = GNUNET_DISK_get_home_filename (cfg, "statistics", "statistics.data", + NULL); + if (fn != NULL) + wh = GNUNET_BIO_write_open (fn); + total = 0; + while (NULL != (pos = start)) + { + start = pos->next; + if ((pos->persistent) && (NULL != wh)) + { + size = htons (pos->msg->header.size); + if (GNUNET_OK != GNUNET_BIO_write (wh, pos->msg, size)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn); + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn); + wh = NULL; + } + else + total += size; + } + GNUNET_free (pos); + } + if (NULL != wh) + { + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn); + if (total == 0) + GNUNET_break (0 == UNLINK (fn)); + else + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Wrote %llu bytes of statistics to `%s'\n"), total, fn); + } + GNUNET_free_non_null (fn); +} + + +/** + * Transmit the given stats value. + */ +static void +transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e) +{ + struct GNUNET_STATISTICS_ReplyMessage *m; + size_t size; + + size = + sizeof (struct GNUNET_STATISTICS_ReplyMessage) + strlen (e->service) + 1 + + strlen (e->name) + 1; + GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); + m = GNUNET_malloc (size); + m->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_VALUE); + m->header.size = htons (size); + m->uid = htonl (e->uid); + if (e->persistent) + m->uid |= htonl (GNUNET_STATISTICS_PERSIST_BIT); + m->value = GNUNET_htonll (e->value); + size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage); + GNUNET_assert (size == + GNUNET_STRINGS_buffer_fill ((char *) &m[1], size, 2, + e->service, e->name)); +#if DEBUG_STATISTICS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting value for `%s:%s' (%d): %llu\n", e->service, + e->name, e->persistent, e->value); +#endif + GNUNET_SERVER_notification_context_unicast (nc, client, &m->header, + GNUNET_NO); + GNUNET_free (m); +} + + +/** + * Does this entry match the request? + */ +static int +matches (const struct StatsEntry *e, const char *service, const char *name) +{ + return ((0 == strlen (service)) || (0 == strcmp (service, e->service))) && + ((0 == strlen (name)) || (0 == strcmp (name, e->name))); +} + + +static struct ClientEntry * +make_client_entry (struct GNUNET_SERVER_Client *client) +{ + struct ClientEntry *ce; + + GNUNET_assert (client != NULL); + ce = client_head; + while (ce != NULL) + { + if (ce->client == client) + return ce; + ce = ce->next; + } + ce = GNUNET_malloc (sizeof (struct ClientEntry)); + ce->client = client; + GNUNET_SERVER_client_keep (client); + GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ce); + GNUNET_SERVER_notification_context_add (nc, client); + return ce; +} + + +/** + * Handle GET-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static void +handle_get (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_MessageHeader end; + char *service; + char *name; + struct StatsEntry *pos; + size_t size; + + if (client != NULL) + make_client_entry (client); + size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader); + if (size != + GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], size, 2, + &service, &name)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } +#if DEBUG_STATISTICS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received request for statistics on `%s:%s'\n", + strlen (service) ? service : "*", strlen (name) ? name : "*"); +#endif + pos = start; + while (pos != NULL) + { + if (matches (pos, service, name)) + transmit (client, pos); + pos = pos->next; + } + end.size = htons (sizeof (struct GNUNET_MessageHeader)); + end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END); + GNUNET_SERVER_notification_context_unicast (nc, client, &end, GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +static void +notify_change (struct StatsEntry *se) +{ + struct GNUNET_STATISTICS_WatchValueMessage wvm; + struct WatchEntry *pos; + + pos = se->we_head; + while (pos != NULL) + { + if (pos->last_value != se->value) + { + wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE); + wvm.header.size = + htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage)); + wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0); + wvm.wid = htonl (pos->wid); + wvm.reserved = htonl (0); + wvm.value = GNUNET_htonll (se->value); + GNUNET_SERVER_notification_context_unicast (nc, pos->client, &wvm.header, + GNUNET_NO); + pos->last_value = se->value; + } + pos = pos->next; + } +} + +/** + * Handle SET-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_set (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + char *service; + char *name; + uint16_t msize; + uint16_t size; + const struct GNUNET_STATISTICS_SetMessage *msg; + struct StatsEntry *pos; + struct StatsEntry *prev; + uint32_t flags; + uint64_t value; + int64_t delta; + int changed; + + if (client != NULL) + make_client_entry (client); + msize = ntohs (message->size); + if (msize < sizeof (struct GNUNET_STATISTICS_SetMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + size = msize - sizeof (struct GNUNET_STATISTICS_SetMessage); + msg = (const struct GNUNET_STATISTICS_SetMessage *) message; + + if (size != + GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1], size, 2, &service, + &name)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + flags = ntohl (msg->flags); + value = GNUNET_ntohll (msg->value); +#if DEBUG_STATISTICS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received request to update statistic on `%s:%s' (%u) to/by %llu\n", + service, name, (unsigned int) flags, (unsigned long long) value); +#endif + pos = start; + prev = NULL; + while (pos != NULL) + { + if (matches (pos, service, name)) + { + if ((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) + { + changed = (pos->value != value); + pos->value = value; + } + else + { + delta = (int64_t) value; + if ((delta < 0) && (pos->value < -delta)) + { + changed = (pos->value != 0); + pos->value = 0; + } + else + { + changed = (delta != 0); + GNUNET_break ((delta <= 0) || (pos->value + delta > pos->value)); + pos->value += delta; + } + } + pos->msg->value = GNUNET_htonll (pos->value); + pos->msg->flags = msg->flags; + pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); + if (prev != NULL) + { + /* move to front for faster setting next time! */ + prev->next = pos->next; + pos->next = start; + start = pos; + } +#if DEBUG_STATISTICS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Statistic `%s:%s' updated to value %llu.\n", service, name, + pos->value); +#endif + if (changed) + notify_change (pos); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + prev = pos; + pos = pos->next; + } + pos = GNUNET_malloc (sizeof (struct StatsEntry) + msize); + pos->next = start; + if (((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) || + (0 < (int64_t) GNUNET_ntohll (msg->value))) + pos->value = GNUNET_ntohll (msg->value); + pos->uid = uidgen++; + pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); + pos->msg = (void *) &pos[1]; + memcpy (pos->msg, message, ntohs (message->size)); + pos->service = (const char *) &pos->msg[1]; + pos->name = &pos->service[strlen (pos->service) + 1]; + + start = pos; +#if DEBUG_STATISTICS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "New statistic on `%s:%s' with value %llu created.\n", service, + name, pos->value); +#endif + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Handle WATCH-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_watch (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + char *service; + char *name; + uint16_t msize; + uint16_t size; + struct StatsEntry *pos; + struct ClientEntry *ce; + struct WatchEntry *we; + size_t slen; + + ce = make_client_entry (client); + msize = ntohs (message->size); + if (msize < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + size = msize - sizeof (struct GNUNET_MessageHeader); + if (size != + GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], size, 2, + &service, &name)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } +#if DEBUG_STATISTICS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received request to watch statistic on `%s:%s'\n", service, + name); +#endif + pos = start; + while (pos != NULL) + { + if (matches (pos, service, name)) + break; + pos = pos->next; + } + if (pos == NULL) + { + pos = + GNUNET_malloc (sizeof (struct StatsEntry) + + sizeof (struct GNUNET_STATISTICS_SetMessage) + size); + pos->next = start; + pos->uid = uidgen++; + pos->msg = (void *) &pos[1]; + pos->msg->header.size = + htons (sizeof (struct GNUNET_STATISTICS_SetMessage) + size); + pos->msg->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET); + pos->service = (const char *) &pos->msg[1]; + slen = strlen (service) + 1; + memcpy ((void *) pos->service, service, slen); + pos->name = &pos->service[slen]; + memcpy ((void *) pos->name, name, strlen (name) + 1); + start = pos; + } + we = GNUNET_malloc (sizeof (struct WatchEntry)); + we->client = client; + GNUNET_SERVER_client_keep (client); + we->wid = ce->max_wid++; + GNUNET_CONTAINER_DLL_insert (pos->we_head, pos->we_tail, we); + if (pos->value != 0) + notify_change (pos); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ClientEntry *ce; + struct WatchEntry *we; + struct StatsEntry *se; + + save (); + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; + while (NULL != (ce = client_head)) + { + GNUNET_SERVER_client_drop (ce->client); + GNUNET_CONTAINER_DLL_remove (client_head, client_tail, ce); + GNUNET_free (ce); + } + while (NULL != (se = start)) + { + start = se->next; + while (NULL != (we = se->we_head)) + { + GNUNET_SERVER_client_drop (we->client); + GNUNET_CONTAINER_DLL_remove (se->we_head, se->we_tail, we); + GNUNET_free (we); + } + GNUNET_free (se); + } +} + + +/** + * A client disconnected. Remove all of its data structure entries. + * + * @param cls closure, NULL + * @param client identification of the client + */ +static void +handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct ClientEntry *ce; + struct WatchEntry *we; + struct WatchEntry *wen; + struct StatsEntry *se; + + ce = client_head; + while (NULL != ce) + { + if (ce->client == client) + { + GNUNET_SERVER_client_drop (ce->client); + GNUNET_CONTAINER_DLL_remove (client_head, client_tail, ce); + GNUNET_free (ce); + break; + } + ce = ce->next; + } + se = start; + while (NULL != se) + { + wen = se->we_head; + while (NULL != (we = wen)) + { + wen = we->next; + if (we->client != client) + continue; + GNUNET_SERVER_client_drop (we->client); + GNUNET_CONTAINER_DLL_remove (se->we_head, se->we_tail, we); + GNUNET_free (we); + } + se = se->next; + } +} + + +/** + * Process statistics requests. + * + * @param cls closure + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_set, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_SET, 0}, + {&handle_get, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_GET, 0}, + {&handle_watch, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_WATCH, 0}, + {NULL, NULL, 0, 0} + }; + cfg = c; + GNUNET_SERVER_add_handlers (server, handlers); + nc = GNUNET_SERVER_notification_context_create (server, 16); + GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); + load (server); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); +} + + +/** + * The main function for the statistics service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "statistics", + GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-service-statistics.c */ diff --git a/src/statistics/gnunet-statistics.c b/src/statistics/gnunet-statistics.c new file mode 100644 index 0000000..ce91572 --- /dev/null +++ b/src/statistics/gnunet-statistics.c @@ -0,0 +1,184 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file statistics/gnunet-statistics.c + * @brief tool to obtain statistics + * @author Christian Grothoff + * @author Igor Wronsky + */ +#include "platform.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_statistics_service.h" +#include "statistics.h" + +#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * Final status code. + */ +static int ret; + +/** + * Set to subsystem that we're going to get stats for (or NULL for all). + */ +static char *subsystem; + +/** + * Set to the specific stat value that we are after (or NULL for all). + */ +static char *name; + +/** + * Make the value that is being set persistent. + */ +static int persistent; + +/** + * Quiet mode + */ +static int quiet; + +/** + * Callback function to process statistic values. + * + * @param cls closure + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +printer (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + if (quiet == GNUNET_NO) + FPRINTF (stdout, "%s%-12s %-50s: %16llu\n", is_persistent ? "!" : " ", + subsystem, _(name), (unsigned long long) value); + else + FPRINTF (stdout, "%llu\n", (unsigned long long) value); + + return GNUNET_OK; +} + + +/** + * Function called last by the statistics code. + * + * @param cls closure + * @param success GNUNET_OK if statistics were + * successfully obtained, GNUNET_SYSERR if not. + */ +static void +cleanup (void *cls, int success) +{ + struct GNUNET_STATISTICS_Handle *h = cls; + + if (success != GNUNET_OK) + { + FPRINTF (stderr, "%s", _("Failed to obtain statistics.\n")); + ret = 1; + } + if (h != NULL) + GNUNET_STATISTICS_destroy (h, GNUNET_NO); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_STATISTICS_Handle *h; + unsigned long long val; + + if (args[0] != NULL) + { + if ((1 != SSCANF (args[0], "%llu", &val)) || (subsystem == NULL) || + (name == NULL)) + { + FPRINTF (stderr, _("Invalid argument `%s'\n"), args[0]); + ret = 1; + return; + } + h = GNUNET_STATISTICS_create (subsystem, cfg); + if (h == NULL) + { + ret = 1; + return; + } + GNUNET_STATISTICS_set (h, name, (uint64_t) val, persistent); + GNUNET_STATISTICS_destroy (h, GNUNET_YES); + return; + } + h = GNUNET_STATISTICS_create ("gnunet-statistics", cfg); + if (h == NULL) + { + ret = 1; + return; + } + if (NULL == + GNUNET_STATISTICS_get (h, subsystem, name, GET_TIMEOUT, &cleanup, + &printer, h)) + cleanup (h, GNUNET_SYSERR); +} + +/** + * The main function to obtain statistics in GNUnet. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'n', "name", "NAME", + gettext_noop ("limit output to statistics for the given NAME"), 1, + &GNUNET_GETOPT_set_string, &name}, + {'p', "persistent", NULL, + gettext_noop ("make the value being set persistent"), 0, + &GNUNET_GETOPT_set_one, &persistent}, + {'s', "subsystem", "SUBSYSTEM", + gettext_noop ("limit output to the given SUBSYSTEM"), 1, + &GNUNET_GETOPT_set_string, &subsystem}, + {'q', "quiet", NULL, + gettext_noop ("just print the statistics value"), 0, + &GNUNET_GETOPT_set_one, &quiet}, + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-statistics [options [value]]", + gettext_noop + ("Print statistics about GNUnet operations."), + options, &run, NULL)) ? ret : 1; +} + +/* end of gnunet-statistics.c */ diff --git a/src/statistics/statistics.conf.in b/src/statistics/statistics.conf.in new file mode 100644 index 0000000..4482b0f --- /dev/null +++ b/src/statistics/statistics.conf.in @@ -0,0 +1,22 @@ +[statistics] +AUTOSTART = YES +@UNIXONLY@ PORT = 2088 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-statistics +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-statistics.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +# DISABLE_SOCKET_FORWARDING = NO +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = + diff --git a/src/statistics/statistics.h b/src/statistics/statistics.h new file mode 100644 index 0000000..3fcac27 --- /dev/null +++ b/src/statistics/statistics.h @@ -0,0 +1,135 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Christian Grothoff + * @file statistics/statistics.h + */ +#ifndef STATISTICS_H +#define STATISTICS_H + +#include "gnunet_common.h" + +#define DEBUG_STATISTICS GNUNET_EXTRA_LOGGING + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Statistics message. Contains how long the system is up + * and one value. + * + * The struct is be followed by the service name and + * name of the statistic, both 0-terminated. + */ +struct GNUNET_STATISTICS_ReplyMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_STATISTICS_VALUE + */ + struct GNUNET_MessageHeader header; + + /** + * Unique numerical identifier for the value (will + * not change during the same client-session). Highest + * bit will be set for persistent values. + */ + uint32_t uid GNUNET_PACKED; + + /** + * The value. + */ + uint64_t value GNUNET_PACKED; + +}; + +#define GNUNET_STATISTICS_PERSIST_BIT (1<<31) + +#define GNUNET_STATISTICS_SETFLAG_ABSOLUTE 0 + +#define GNUNET_STATISTICS_SETFLAG_RELATIVE 1 + +#define GNUNET_STATISTICS_SETFLAG_PERSISTENT 2 + +/** + * Message to set a statistic. Followed + * by the subsystem name and the name of + * the statistic (each 0-terminated). + */ +struct GNUNET_STATISTICS_SetMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_STATISTICS_SET + */ + struct GNUNET_MessageHeader header; + + /** + * 0 for absolute value, 1 for relative value; 2 to make persistent + * (see GNUNET_STATISTICS_SETFLAG_*). + */ + uint32_t flags GNUNET_PACKED; + + /** + * Value. Note that if this is a relative value, it will + * be signed even though the type given here is unsigned. + */ + uint64_t value GNUNET_PACKED; + +}; + + +/** + * Message transmitted if a watched value changes. + */ +struct GNUNET_STATISTICS_WatchValueMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE + */ + struct GNUNET_MessageHeader header; + + /** + * 0 for absolute value, 1 for relative value; 2 to make persistent + * (see GNUNET_STATISTICS_SETFLAG_*). + */ + uint32_t flags GNUNET_PACKED; + + /** + * Unique watch identification number (watch + * requests are enumerated in the order they + * are received, the first request having + * a wid of zero). + */ + uint32_t wid GNUNET_PACKED; + + /** + * Reserved (always 0). + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Value. Note that if this is a relative value, it will + * be signed even though the type given here is unsigned. + */ + uint64_t value GNUNET_PACKED; + +}; +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/statistics/statistics_api.c b/src/statistics/statistics_api.c new file mode 100644 index 0000000..2838b70 --- /dev/null +++ b/src/statistics/statistics_api.c @@ -0,0 +1,1277 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file statistics/statistics_api.c + * @brief API of the statistics service + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_client_lib.h" +#include "gnunet_constants.h" +#include "gnunet_container_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_server_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_strings_lib.h" +#include "statistics.h" + +/** + * How long do we wait until a statistics request for setting + * a value times out? (The update will be lost if the + * service does not react within this timeframe). + */ +#define SET_TRANSMIT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) + +#define LOG(kind,...) GNUNET_log_from (kind, "statistics-api",__VA_ARGS__) + +/** + * Types of actions. + */ +enum ActionType +{ + /** + * Get a value. + */ + ACTION_GET, + + /** + * Set a value. + */ + ACTION_SET, + + /** + * Update a value. + */ + ACTION_UPDATE, + + /** + * Watch a value. + */ + ACTION_WATCH +}; + + +/** + * Entry kept for each value we are watching. + */ +struct GNUNET_STATISTICS_WatchEntry +{ + + /** + * What subsystem is this action about? (never NULL) + */ + char *subsystem; + + /** + * What value is this action about? (never NULL) + */ + char *name; + + /** + * Function to call + */ + GNUNET_STATISTICS_Iterator proc; + + /** + * Closure for proc + */ + void *proc_cls; + +}; + + +/** + * Linked list of things we still need to do. + */ +struct GNUNET_STATISTICS_GetHandle +{ + + /** + * This is a doubly linked list. + */ + struct GNUNET_STATISTICS_GetHandle *next; + + /** + * This is a doubly linked list. + */ + struct GNUNET_STATISTICS_GetHandle *prev; + + /** + * Main statistics handle. + */ + struct GNUNET_STATISTICS_Handle *sh; + + /** + * What subsystem is this action about? (can be NULL) + */ + char *subsystem; + + /** + * What value is this action about? (can be NULL) + */ + char *name; + + /** + * Continuation to call once action is complete. + */ + GNUNET_STATISTICS_Callback cont; + + /** + * Function to call (for GET actions only). + */ + GNUNET_STATISTICS_Iterator proc; + + /** + * Closure for proc and cont. + */ + void *cls; + + /** + * Timeout for this action. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Associated value. + */ + uint64_t value; + + /** + * Flag for SET/UPDATE actions. + */ + int make_persistent; + + /** + * Has the current iteration been aborted; for GET actions. + */ + int aborted; + + /** + * Is this a GET, SET, UPDATE or WATCH? + */ + enum ActionType type; + + /** + * Size of the message that we will be transmitting. + */ + uint16_t msize; + +}; + + +/** + * Handle for the service. + */ +struct GNUNET_STATISTICS_Handle +{ + /** + * Name of our subsystem. + */ + char *subsystem; + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Socket (if available). + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Currently pending transmission request. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Head of the linked list of pending actions (first action + * to be performed). + */ + struct GNUNET_STATISTICS_GetHandle *action_head; + + /** + * Tail of the linked list of actions (for fast append). + */ + struct GNUNET_STATISTICS_GetHandle *action_tail; + + /** + * Action we are currently busy with (action request has been + * transmitted, we're now receiving the response from the + * service). + */ + struct GNUNET_STATISTICS_GetHandle *current; + + /** + * Array of watch entries. + */ + struct GNUNET_STATISTICS_WatchEntry **watches; + + /** + * Task doing exponential back-off trying to reconnect. + */ + GNUNET_SCHEDULER_TaskIdentifier backoff_task; + + /** + * Time for next connect retry. + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Size of the 'watches' array. + */ + unsigned int watches_size; + + /** + * Should this handle auto-destruct once all actions have + * been processed? + */ + int do_destroy; + + /** + * Are we currently receiving from the service? + */ + int receiving; + +}; + + +/** + * Schedule the next action to be performed. + * + * @param h statistics handle to reconnect + */ +static void +schedule_action (struct GNUNET_STATISTICS_Handle *h); + + +/** + * Transmit request to service that we want to watch + * the development of a particular value. + * + * @param h statistics handle + * @param watch watch entry of the value to watch + */ +static void +schedule_watch_request (struct GNUNET_STATISTICS_Handle *h, + struct GNUNET_STATISTICS_WatchEntry *watch) +{ + + struct GNUNET_STATISTICS_GetHandle *ai; + size_t slen; + size_t nlen; + size_t nsize; + + GNUNET_assert (h != NULL); + slen = strlen (watch->subsystem) + 1; + nlen = strlen (watch->name) + 1; + nsize = sizeof (struct GNUNET_MessageHeader) + slen + nlen; + if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle)); + ai->sh = h; + ai->subsystem = GNUNET_strdup (watch->subsystem); + ai->name = GNUNET_strdup (watch->name); + ai->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; + ai->msize = nsize; + ai->type = ACTION_WATCH; + ai->proc = watch->proc; + ai->cls = watch->proc_cls; + GNUNET_CONTAINER_DLL_insert_tail (h->action_head, h->action_tail, + ai); + schedule_action (h); +} + + +/** + * Free memory associated with the given action item. + * + * @param gh action item to free + */ +static void +free_action_item (struct GNUNET_STATISTICS_GetHandle *gh) +{ + GNUNET_free_non_null (gh->subsystem); + GNUNET_free_non_null (gh->name); + GNUNET_free (gh); +} + + +/** + * Disconnect from the statistics service. + * + * @param h statistics handle to disconnect from + */ +static void +do_disconnect (struct GNUNET_STATISTICS_Handle *h) +{ + struct GNUNET_STATISTICS_GetHandle *c; + + if (NULL != h->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } + if (NULL != h->client) + { + GNUNET_CLIENT_disconnect (h->client, GNUNET_NO); + h->client = NULL; + } + h->receiving = GNUNET_NO; + if (NULL != (c = h->current)) + { + h->current = NULL; + if (c->cont != NULL) + c->cont (c->cls, GNUNET_SYSERR); + free_action_item (c); + } +} + + +/** + * Try to (re)connect to the statistics service. + * + * @param h statistics handle to reconnect + * @return GNUNET_YES on success, GNUNET_NO on failure. + */ +static int +try_connect (struct GNUNET_STATISTICS_Handle *h) +{ + struct GNUNET_STATISTICS_GetHandle *gh; + struct GNUNET_STATISTICS_GetHandle *gn; + unsigned int i; + + if (h->backoff_task != GNUNET_SCHEDULER_NO_TASK) + return GNUNET_NO; + if (h->client != NULL) + return GNUNET_YES; + h->client = GNUNET_CLIENT_connect ("statistics", h->cfg); + if (h->client != NULL) + { + gn = h->action_head; + while (NULL != (gh = gn)) + { + gn = gh->next; + if (gh->type == ACTION_WATCH) + { + GNUNET_CONTAINER_DLL_remove (h->action_head, + h->action_tail, + gh); + free_action_item (gh); + } + } + for (i = 0; i < h->watches_size; i++) + schedule_watch_request (h, h->watches[i]); + return GNUNET_YES; + } +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, + _("Failed to connect to statistics service!\n")); +#endif + return GNUNET_NO; +} + + +/** + * We've waited long enough, reconnect now. + * + * @param cls the 'struct GNUNET_STATISTICS_Handle' to reconnect + * @param tc scheduler context (unused) + */ +static void +reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_STATISTICS_Handle *h = cls; + + h->backoff_task = GNUNET_SCHEDULER_NO_TASK; + schedule_action (h); +} + + +/** + * Reconnect at a later time, respecting back-off. + * + * @param h statistics handle + */ +static void +reconnect_later (struct GNUNET_STATISTICS_Handle *h) +{ + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->backoff_task); + h->backoff_task = + GNUNET_SCHEDULER_add_delayed (h->backoff, &reconnect_task, h); + h->backoff = GNUNET_TIME_relative_multiply (h->backoff, 2); + h->backoff = + GNUNET_TIME_relative_min (h->backoff, GNUNET_CONSTANTS_SERVICE_TIMEOUT); +} + + +/** + * Process a 'GNUNET_MESSAGE_TYPE_STATISTICS_VALUE' message. + * + * @param h statistics handle + * @param msg message received from the service, never NULL + * @return GNUNET_OK if the message was well-formed + */ +static int +process_statistics_value_message (struct GNUNET_STATISTICS_Handle *h, + const struct GNUNET_MessageHeader *msg) +{ + char *service; + char *name; + const struct GNUNET_STATISTICS_ReplyMessage *smsg; + uint16_t size; + + if (h->current->aborted) + { +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, "Iteration was aborted, ignoring VALUE\n"); +#endif + return GNUNET_OK; /* don't bother */ + } + size = ntohs (msg->size); + if (size < sizeof (struct GNUNET_STATISTICS_ReplyMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + smsg = (const struct GNUNET_STATISTICS_ReplyMessage *) msg; + size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage); + if (size != + GNUNET_STRINGS_buffer_tokenize ((const char *) &smsg[1], size, 2, + &service, &name)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received valid statistic on `%s:%s': %llu\n", + service, name, GNUNET_ntohll (smsg->value)); +#endif + if (GNUNET_OK != + h->current->proc (h->current->cls, service, name, + GNUNET_ntohll (smsg->value), + 0 != + (ntohl (smsg->uid) & GNUNET_STATISTICS_PERSIST_BIT))) + { +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing of remaining statistics aborted by client.\n"); +#endif + h->current->aborted = GNUNET_YES; + } +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, "VALUE processed successfully\n"); +#endif + return GNUNET_OK; +} + + +/** + * We have received a watch value from the service. Process it. + * + * @param h statistics handle + * @param msg the watch value message + * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not, + * GNUNET_NO if this watch has been cancelled + */ +static int +process_watch_value (struct GNUNET_STATISTICS_Handle *h, + const struct GNUNET_MessageHeader *msg) +{ + const struct GNUNET_STATISTICS_WatchValueMessage *wvm; + struct GNUNET_STATISTICS_WatchEntry *w; + uint32_t wid; + + if (sizeof (struct GNUNET_STATISTICS_WatchValueMessage) != ntohs (msg->size)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + wvm = (const struct GNUNET_STATISTICS_WatchValueMessage *) msg; + GNUNET_break (0 == ntohl (wvm->reserved)); + wid = ntohl (wvm->wid); + if (wid >= h->watches_size) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + w = h->watches[wid]; + if (NULL == w) + return GNUNET_NO; + (void) w->proc (w->proc_cls, w->subsystem, w->name, + GNUNET_ntohll (wvm->value), + 0 != (ntohl (wvm->flags) & GNUNET_STATISTICS_PERSIST_BIT)); + return GNUNET_OK; +} + + +/** + * Function called with messages from stats service. + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +receive_stats (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_STATISTICS_Handle *h = cls; + struct GNUNET_STATISTICS_GetHandle *c; + int ret; + + if (msg == NULL) + { +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Error receiving statistics from service, is the service running?\n"); +#endif + do_disconnect (h); + reconnect_later (h); + return; + } + switch (ntohs (msg->type)) + { + case GNUNET_MESSAGE_TYPE_STATISTICS_END: +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received end of statistics marker\n"); +#endif + if (NULL == (c = h->current)) + { + GNUNET_break (0); + do_disconnect (h); + reconnect_later (h); + return; + } + h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; + if (h->watches_size > 0) + { + GNUNET_CLIENT_receive (h->client, &receive_stats, h, + GNUNET_TIME_UNIT_FOREVER_REL); + } + else + { + h->receiving = GNUNET_NO; + } + h->current = NULL; + schedule_action (h); + if (c->cont != NULL) + c->cont (c->cls, GNUNET_OK); + free_action_item (c); + return; + case GNUNET_MESSAGE_TYPE_STATISTICS_VALUE: + if (GNUNET_OK != process_statistics_value_message (h, msg)) + { + do_disconnect (h); + reconnect_later (h); + return; + } + /* finally, look for more! */ +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing VALUE done, now reading more\n"); +#endif + GNUNET_CLIENT_receive (h->client, &receive_stats, h, + GNUNET_TIME_absolute_get_remaining (h-> + current->timeout)); + h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; + return; + case GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE: + if (GNUNET_OK != + (ret = process_watch_value (h, msg))) + { + do_disconnect (h); + if (GNUNET_NO == ret) + h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; + reconnect_later (h); + return; + } + h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; + GNUNET_assert (h->watches_size > 0); + GNUNET_CLIENT_receive (h->client, &receive_stats, h, + GNUNET_TIME_UNIT_FOREVER_REL); + return; + default: + GNUNET_break (0); + do_disconnect (h); + reconnect_later (h); + return; + } +} + + +/** + * Transmit a GET request (and if successful, start to receive + * the response). + * + * @param handle statistics handle + * @param size how many bytes can we write to buf + * @param buf where to write requests to the service + * @return number of bytes written to buf + */ +static size_t +transmit_get (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) +{ + struct GNUNET_STATISTICS_GetHandle *c; + struct GNUNET_MessageHeader *hdr; + size_t slen1; + size_t slen2; + uint16_t msize; + + GNUNET_assert (NULL != (c = handle->current)); + if (buf == NULL) + { + /* timeout / error */ +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmission of request for statistics failed!\n"); +#endif + do_disconnect (handle); + reconnect_later (handle); + return 0; + } + slen1 = strlen (c->subsystem) + 1; + slen2 = strlen (c->name) + 1; + msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); + GNUNET_assert (msize <= size); + hdr = (struct GNUNET_MessageHeader *) buf; + hdr->size = htons (msize); + hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_GET); + GNUNET_assert (slen1 + slen2 == + GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], slen1 + slen2, 2, + c->subsystem, + c->name)); + if (GNUNET_YES != handle->receiving) + { +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmission of GET done, now reading response\n"); +#endif + handle->receiving = GNUNET_YES; + GNUNET_CLIENT_receive (handle->client, &receive_stats, handle, + GNUNET_TIME_absolute_get_remaining (c->timeout)); + } + return msize; +} + + +/** + * Transmit a WATCH request (and if successful, start to receive + * the response). + * + * @param handle statistics handle + * @param size how many bytes can we write to buf + * @param buf where to write requests to the service + * @return number of bytes written to buf + */ +static size_t +transmit_watch (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *hdr; + size_t slen1; + size_t slen2; + uint16_t msize; + + if (buf == NULL) + { + /* timeout / error */ +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmission of request for statistics failed!\n"); +#endif + do_disconnect (handle); + reconnect_later (handle); + return 0; + } +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting watch request for `%s'\n", + handle->current->name); +#endif + slen1 = strlen (handle->current->subsystem) + 1; + slen2 = strlen (handle->current->name) + 1; + msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); + GNUNET_assert (msize <= size); + hdr = (struct GNUNET_MessageHeader *) buf; + hdr->size = htons (msize); + hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH); + GNUNET_assert (slen1 + slen2 == + GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], slen1 + slen2, 2, + handle->current->subsystem, + handle->current->name)); + if (GNUNET_YES != handle->receiving) + { + handle->receiving = GNUNET_YES; + GNUNET_CLIENT_receive (handle->client, &receive_stats, handle, + GNUNET_TIME_UNIT_FOREVER_REL); + } + GNUNET_assert (NULL == handle->current->cont); + free_action_item (handle->current); + handle->current = NULL; + return msize; +} + + +/** + * Transmit a SET/UPDATE request. + * + * @param handle statistics handle + * @param size how many bytes can we write to buf + * @param buf where to write requests to the service + * @return number of bytes written to buf + */ +static size_t +transmit_set (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) +{ + struct GNUNET_STATISTICS_SetMessage *r; + size_t slen; + size_t nlen; + size_t nsize; + + if (NULL == buf) + { + do_disconnect (handle); + reconnect_later (handle); + return 0; + } + slen = strlen (handle->current->subsystem) + 1; + nlen = strlen (handle->current->name) + 1; + nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen; + if (size < nsize) + { + GNUNET_break (0); + do_disconnect (handle); + reconnect_later (handle); + return 0; + } + r = buf; + r->header.size = htons (nsize); + r->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET); + r->flags = 0; + r->value = GNUNET_htonll (handle->current->value); + if (handle->current->make_persistent) + r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_PERSISTENT); + if (handle->current->type == ACTION_UPDATE) + r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_RELATIVE); + GNUNET_assert (slen + nlen == + GNUNET_STRINGS_buffer_fill ((char *) &r[1], slen + nlen, 2, + handle->current->subsystem, + handle->current->name)); + GNUNET_assert (NULL == handle->current->cont); + free_action_item (handle->current); + handle->current = NULL; + return nsize; +} + + +/** + * Function called when we are ready to transmit a request to the service. + * + * @param cls the 'struct GNUNET_STATISTICS_Handle' + * @param size how many bytes can we write to buf + * @param buf where to write requests to the service + * @return number of bytes written to buf + */ +static size_t +transmit_action (void *cls, size_t size, void *buf) +{ + struct GNUNET_STATISTICS_Handle *h = cls; + size_t ret; + + h->th = NULL; + ret = 0; + if (NULL != h->current) + switch (h->current->type) + { + case ACTION_GET: + ret = transmit_get (h, size, buf); + break; + case ACTION_SET: + case ACTION_UPDATE: + ret = transmit_set (h, size, buf); + break; + case ACTION_WATCH: + ret = transmit_watch (h, size, buf); + break; + default: + GNUNET_assert (0); + break; + } + schedule_action (h); + return ret; +} + + +/** + * Get handle for the statistics service. + * + * @param subsystem name of subsystem using the service + * @param cfg services configuration in use + * @return handle to use + */ +struct GNUNET_STATISTICS_Handle * +GNUNET_STATISTICS_create (const char *subsystem, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_STATISTICS_Handle *ret; + + GNUNET_assert (subsystem != NULL); + GNUNET_assert (cfg != NULL); + ret = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_Handle)); + ret->cfg = cfg; + ret->subsystem = GNUNET_strdup (subsystem); + ret->backoff = GNUNET_TIME_UNIT_MILLISECONDS; + return ret; +} + + +/** + * Destroy a handle (free all state associated with + * it). + * + * @param h statistics handle to destroy + * @param sync_first set to GNUNET_YES if pending SET requests should + * be completed + */ +void +GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first) +{ + struct GNUNET_STATISTICS_GetHandle *pos; + struct GNUNET_STATISTICS_GetHandle *next; + struct GNUNET_TIME_Relative timeout; + int i; + + if (h == NULL) + return; + if (GNUNET_SCHEDULER_NO_TASK != h->backoff_task) + { + GNUNET_SCHEDULER_cancel (h->backoff_task); + h->backoff_task = GNUNET_SCHEDULER_NO_TASK; + } + if (sync_first) + { + if (h->current != NULL) + { + if (h->current->type == ACTION_GET) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + free_action_item (h->current); + h->current = NULL; + } + } + next = h->action_head; + while (NULL != (pos = next)) + { + next = pos->next; + if (pos->type == ACTION_GET) + { + GNUNET_CONTAINER_DLL_remove (h->action_head, + h->action_tail, + pos); + free_action_item (pos); + } + } + if ( (NULL == h->current) && + (NULL != (h->current = h->action_head)) ) + GNUNET_CONTAINER_DLL_remove (h->action_head, + h->action_tail, + h->current); + h->do_destroy = GNUNET_YES; + if ((h->current != NULL) && (h->th == NULL)) + { + if (NULL == h->client) + { + /* instant-connect (regardless of back-off) to submit final value */ + h->client = GNUNET_CLIENT_connect ("statistics", h->cfg); + } + if (NULL != h->client) + { + timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout); + h->th = + GNUNET_CLIENT_notify_transmit_ready (h->client, h->current->msize, + timeout, GNUNET_YES, + &transmit_action, h); + GNUNET_assert (NULL != h->th); + } + } + if (h->th != NULL) + return; /* do not finish destruction just yet */ + } + while (NULL != (pos = h->action_head)) + { + GNUNET_CONTAINER_DLL_remove (h->action_head, + h->action_tail, + pos); + free_action_item (pos); + } + do_disconnect (h); + for (i = 0; i < h->watches_size; i++) + { + if (NULL == h->watches[i]) + continue; + GNUNET_free (h->watches[i]->subsystem); + GNUNET_free (h->watches[i]->name); + GNUNET_free (h->watches[i]); + } + GNUNET_array_grow (h->watches, h->watches_size, 0); + GNUNET_free (h->subsystem); + GNUNET_free (h); +} + + +/** + * Schedule the next action to be performed. + * + * @param h statistics handle + */ +static void +schedule_action (struct GNUNET_STATISTICS_Handle *h) +{ + struct GNUNET_TIME_Relative timeout; + + if ( (h->th != NULL) || + (h->backoff_task != GNUNET_SCHEDULER_NO_TASK) ) + return; /* action already pending */ + if (GNUNET_YES != try_connect (h)) + { + reconnect_later (h); + return; + } + if (NULL != h->current) + return; /* action already pending */ + /* schedule next action */ + h->current = h->action_head; + if (NULL == h->current) + { + if (h->do_destroy) + { + h->do_destroy = GNUNET_NO; + GNUNET_STATISTICS_destroy (h, GNUNET_YES); + } + return; + } + GNUNET_CONTAINER_DLL_remove (h->action_head, h->action_tail, h->current); + timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout); + if (NULL == + (h->th = + GNUNET_CLIENT_notify_transmit_ready (h->client, h->current->msize, + timeout, GNUNET_YES, + &transmit_action, h))) + { +#if DEBUG_STATISTICS + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to transmit request to statistics service.\n"); +#endif + do_disconnect (h); + reconnect_later (h); + } +} + + +/** + * Get statistic from the peer. + * + * @param handle identification of the statistics service + * @param subsystem limit to the specified subsystem, NULL for our subsystem + * @param name name of the statistic value, NULL for all values + * @param timeout after how long should we give up (and call + * cont with an error code)? + * @param cont continuation to call when done (can be NULL) + * @param proc function to call on each value + * @param cls closure for cont and proc + * @return NULL on error + */ +struct GNUNET_STATISTICS_GetHandle * +GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle, + const char *subsystem, const char *name, + struct GNUNET_TIME_Relative timeout, + GNUNET_STATISTICS_Callback cont, + GNUNET_STATISTICS_Iterator proc, void *cls) +{ + size_t slen1; + size_t slen2; + struct GNUNET_STATISTICS_GetHandle *ai; + + if (NULL == handle) + return NULL; + GNUNET_assert (proc != NULL); + GNUNET_assert (GNUNET_NO == handle->do_destroy); + if (subsystem == NULL) + subsystem = ""; + if (name == NULL) + name = ""; + slen1 = strlen (subsystem) + 1; + slen2 = strlen (name) + 1; + GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) < + GNUNET_SERVER_MAX_MESSAGE_SIZE); + ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle)); + ai->sh = handle; + ai->subsystem = GNUNET_strdup (subsystem); + ai->name = GNUNET_strdup (name); + ai->cont = cont; + ai->proc = proc; + ai->cls = cls; + ai->timeout = GNUNET_TIME_relative_to_absolute (timeout); + ai->type = ACTION_GET; + ai->msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); + GNUNET_CONTAINER_DLL_insert_tail (handle->action_head, handle->action_tail, + ai); + schedule_action (handle); + return ai; +} + + +/** + * Cancel a 'get' request. Must be called before the 'cont' + * function is called. + * + * @param gh handle of the request to cancel + */ +void +GNUNET_STATISTICS_get_cancel (struct GNUNET_STATISTICS_GetHandle *gh) +{ + if (NULL == gh) + return; + if (gh->sh->current == gh) + { + gh->aborted = GNUNET_YES; + } + else + { + GNUNET_CONTAINER_DLL_remove (gh->sh->action_head, gh->sh->action_tail, gh); + GNUNET_free (gh->name); + GNUNET_free (gh->subsystem); + GNUNET_free (gh); + } +} + + +/** + * Watch statistics from the peer (be notified whenever they change). + * + * @param handle identification of the statistics service + * @param subsystem limit to the specified subsystem, never NULL + * @param name name of the statistic value, never NULL + * @param proc function to call on each value + * @param proc_cls closure for proc + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_STATISTICS_watch (struct GNUNET_STATISTICS_Handle *handle, + const char *subsystem, const char *name, + GNUNET_STATISTICS_Iterator proc, void *proc_cls) +{ + struct GNUNET_STATISTICS_WatchEntry *w; + + if (handle == NULL) + return GNUNET_SYSERR; + w = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_WatchEntry)); + w->subsystem = GNUNET_strdup (subsystem); + w->name = GNUNET_strdup (name); + w->proc = proc; + w->proc_cls = proc_cls; + GNUNET_array_append (handle->watches, handle->watches_size, w); + schedule_watch_request (handle, w); + return GNUNET_OK; +} + + +/** + * Stop watching statistics from the peer. + * + * @param handle identification of the statistics service + * @param subsystem limit to the specified subsystem, never NULL + * @param name name of the statistic value, never NULL + * @param proc function to call on each value + * @param proc_cls closure for proc + * @return GNUNET_OK on success, GNUNET_SYSERR on error (no such watch) + */ +int +GNUNET_STATISTICS_watch_cancel (struct GNUNET_STATISTICS_Handle *handle, + const char *subsystem, const char *name, + GNUNET_STATISTICS_Iterator proc, void *proc_cls) +{ + struct GNUNET_STATISTICS_WatchEntry *w; + unsigned int i; + + if (handle == NULL) + return GNUNET_SYSERR; + for (i=0;iwatches_size;i++) + { + w = handle->watches[i]; + if ( (w->proc == proc) && + (w->proc_cls == proc_cls) && + (0 == strcmp (w->name, name)) && + (0 == strcmp (w->subsystem, subsystem)) ) + { + GNUNET_free (w->name); + GNUNET_free (w->subsystem); + GNUNET_free (w); + handle->watches[i] = NULL; + return GNUNET_OK; + } + } + return GNUNET_SYSERR; +} + + + +/** + * Queue a request to change a statistic. + * + * @param h statistics handle + * @param name name of the value + * @param make_persistent should the value be kept across restarts? + * @param value new value or change + * @param type type of the action (ACTION_SET or ACTION_UPDATE) + */ +static void +add_setter_action (struct GNUNET_STATISTICS_Handle *h, const char *name, + int make_persistent, uint64_t value, enum ActionType type) +{ + struct GNUNET_STATISTICS_GetHandle *ai; + size_t slen; + size_t nlen; + size_t nsize; + int64_t delta; + + GNUNET_assert (h != NULL); + GNUNET_assert (name != NULL); + slen = strlen (h->subsystem) + 1; + nlen = strlen (name) + 1; + nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen; + if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + for (ai = h->action_head; ai != NULL; ai = ai->next) + { + if (! ( (0 == strcmp (ai->subsystem, h->subsystem)) && + (0 == strcmp (ai->name, name)) && + ( (ai->type == ACTION_UPDATE) || + (ai->type == ACTION_SET) ) ) ) + continue; + if (ai->type == ACTION_SET) + { + if (type == ACTION_UPDATE) + { + delta = (int64_t) value; + if (delta > 0) + { + /* update old set by new delta */ + ai->value += delta; + } + else + { + /* update old set by new delta, but never go negative */ + if (ai->value < -delta) + ai->value = 0; + else + ai->value += delta; + } + } + else + { + /* new set overrides old set */ + ai->value = value; + } + } + else + { + if (type == ACTION_UPDATE) + { + /* make delta cummulative */ + delta = (int64_t) value; + ai->value += delta; + } + else + { + /* drop old 'update', use new 'set' instead */ + ai->value = value; + ai->type = type; + } + } + ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT); + ai->make_persistent = make_persistent; + return; + } + /* no existing entry matches, create a fresh one */ + ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle)); + ai->sh = h; + ai->subsystem = GNUNET_strdup (h->subsystem); + ai->name = GNUNET_strdup (name); + ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT); + ai->make_persistent = make_persistent; + ai->msize = nsize; + ai->value = value; + ai->type = type; + GNUNET_CONTAINER_DLL_insert_tail (h->action_head, h->action_tail, + ai); + schedule_action (h); +} + + +/** + * Set statistic value for the peer. Will always use our + * subsystem (the argument used when "handle" was created). + * + * @param handle identification of the statistics service + * @param name name of the statistic value + * @param value new value to set + * @param make_persistent should the value be kept across restarts? + */ +void +GNUNET_STATISTICS_set (struct GNUNET_STATISTICS_Handle *handle, + const char *name, uint64_t value, int make_persistent) +{ + if (handle == NULL) + return; + GNUNET_assert (GNUNET_NO == handle->do_destroy); + add_setter_action (handle, name, make_persistent, value, ACTION_SET); +} + + +/** + * Set statistic value for the peer. Will always use our + * subsystem (the argument used when "handle" was created). + * + * @param handle identification of the statistics service + * @param name name of the statistic value + * @param delta change in value (added to existing value) + * @param make_persistent should the value be kept across restarts? + */ +void +GNUNET_STATISTICS_update (struct GNUNET_STATISTICS_Handle *handle, + const char *name, int64_t delta, int make_persistent) +{ + if (handle == NULL) + return; + if (delta == 0) + return; + GNUNET_assert (GNUNET_NO == handle->do_destroy); + add_setter_action (handle, name, make_persistent, (uint64_t) delta, + ACTION_UPDATE); +} + + +/* end of statistics_api.c */ diff --git a/src/statistics/test_gnunet_statistics.sh b/src/statistics/test_gnunet_statistics.sh new file mode 100755 index 0000000..eb2d618 --- /dev/null +++ b/src/statistics/test_gnunet_statistics.sh @@ -0,0 +1,199 @@ +#!/bin/sh + +rm -rf /tmp/test-gnunetd-statistics/ +exe="./gnunet-statistics -c test_statistics_api_data.conf" +out=`mktemp /tmp/test-gnunet-statistics-logXXXXXXXX` +arm="gnunet-arm -c test_statistics_api_data.conf $DEBUG" +#DEBUG="-L DEBUG" +# ----------------------------------- +echo -n "Preparing: Starting service..." + +$arm -s > /dev/null +sleep 1 +$arm -i statistics > /dev/null +sleep 1 +echo "DONE" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: Bad argument checking..." + +if $exe -x 2> /dev/null; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +echo "PASS" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: Set value..." + +if ! $exe $DEBUG -n test -s subsystem 42 ; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +echo "PASS" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: Set another value..." + +if ! $exe $DEBUG -n other -s osystem 43 ; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +echo "PASS" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: viewing all stats..." + +if ! $exe $DEBUG > $out; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +LINES=`cat $out | wc -l` +if test $LINES -ne 2; then + echo "FAIL: unexpected output" + $arm -e + exit 1 +fi +echo "PASS" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: viewing stats by name..." + +if ! $exe $DEBUG -n other > $out; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +LINES=`cat $out | grep 43 | wc -l` +if test $LINES -ne 1; then + echo "FAIL: unexpected output" + $arm -e + exit 1 +fi +echo "PASS" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: viewing stats by subsystem..." + +if ! $exe $DEBUG -s subsystem > $out; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +LINES=`cat $out | grep 42 | wc -l` +if test $LINES -ne 1; then + echo "FAIL: unexpected output" + $arm -e + exit 1 +fi +echo "PASS" + + +# ---------------------------------------------------------------------------------- +echo -n "TEST: Set persistent value..." + +if ! $exe $DEBUG -n lasting -s subsystem 40 -p; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +if ! $exe $DEBUG > $out; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +LINES=`cat $out | grep 40 | wc -l` +if test $LINES -ne 1; then + echo "FAIL: unexpected output" + cat $out + $arm -e + exit 1 +fi +echo "PASS" + +# ----------------------------------- +echo -n "Restarting service..." +$arm -k statistics > /dev/null +sleep 1 +$arm -i statistics > /dev/null +sleep 1 +echo "DONE" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: checking persistence..." + +if ! $exe $DEBUG > $out; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +LINES=`cat $out | grep 40 | wc -l` +if test $LINES -ne 1; then + echo "FAIL: unexpected output" + cat $out + $arm -e + exit 1 +fi +echo "PASS" + + + +# ---------------------------------------------------------------------------------- +echo -n "TEST: Removing persistence..." + +if ! $exe $DEBUG -n lasting -s subsystem 40; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +if ! $exe $DEBUG > $out; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +LINES=`cat $out | grep \! | wc -l` +if test $LINES -ne 0; then + echo "FAIL: unexpected output" + cat $out + $arm -e + exit 1 +fi +echo "PASS" + + +# ----------------------------------- +echo -n "Restarting service..." +$arm -k statistics > /dev/null +sleep 1 +$arm -i statistics > /dev/null +sleep 1 +echo "DONE" + +# ---------------------------------------------------------------------------------- +echo -n "TEST: checking removed persistence..." + +if ! $exe $DEBUG > $out; then + echo "FAIL: error running $exe" + $arm -e + exit 1 +fi +LINES=`cat $out | grep 40 | wc -l` +if test $LINES -ne 0; then + echo "FAIL: unexpected output" + cat $out + $arm -e + exit 1 +fi +echo "PASS" + +# ----------------------------------- +echo -n "Stopping service..." +$arm -e > /dev/null +sleep 1 +echo "DONE" +rm -f $out +rm -rf /tmp/test-gnunetd-statistics/ diff --git a/src/statistics/test_statistics_api.c b/src/statistics/test_statistics_api.c new file mode 100644 index 0000000..0647a49 --- /dev/null +++ b/src/statistics/test_statistics_api.c @@ -0,0 +1,212 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file statistics/test_statistics_api.c + * @brief testcase for statistics_api.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_statistics_service.h" + +#define DEBUG_STATISTICS GNUNET_EXTRA_LOGGING + +#define START_SERVICE GNUNET_YES + +static int +check_1 (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value %llu for `%s:%s\n", + (unsigned long long) value, subsystem, name); + GNUNET_assert (0 == strcmp (name, "test-1")); + GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); + GNUNET_assert (value == 1); + GNUNET_assert (is_persistent == GNUNET_NO); + return GNUNET_OK; +} + +static int +check_2 (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value %llu for `%s:%s\n", + (unsigned long long) value, subsystem, name); + GNUNET_assert (0 == strcmp (name, "test-2")); + GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); + GNUNET_assert (value == 2); + GNUNET_assert (is_persistent == GNUNET_NO); + return GNUNET_OK; +} + +static int +check_3 (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value %llu for `%s:%s\n", + (unsigned long long) value, subsystem, name); + GNUNET_assert (0 == strcmp (name, "test-3")); + GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); + GNUNET_assert (value == 3); + GNUNET_assert (is_persistent == GNUNET_YES); + return GNUNET_OK; +} + +static struct GNUNET_STATISTICS_Handle *h; + +static void +next_fin (void *cls, int success) +{ + int *ok = cls; + + GNUNET_STATISTICS_destroy (h, GNUNET_NO); + GNUNET_assert (success == GNUNET_OK); + *ok = 0; +} + +static void +next (void *cls, int success) +{ + GNUNET_assert (success == GNUNET_OK); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Issuing GET request\n"); + GNUNET_break (NULL != + GNUNET_STATISTICS_get (h, NULL, "test-2", + GNUNET_TIME_UNIT_SECONDS, &next_fin, + &check_2, cls)); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + h = GNUNET_STATISTICS_create ("test-statistics-api", cfg); + GNUNET_STATISTICS_set (h, "test-1", 1, GNUNET_NO); + GNUNET_STATISTICS_set (h, "test-2", 2, GNUNET_NO); + GNUNET_STATISTICS_set (h, "test-3", 2, GNUNET_NO); + GNUNET_STATISTICS_update (h, "test-3", 1, GNUNET_YES); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Issuing GET request\n"); + GNUNET_break (NULL != + GNUNET_STATISTICS_get (h, NULL, "test-1", + GNUNET_TIME_UNIT_SECONDS, &next, + &check_1, cls)); +} + +static void +run_more (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + h = GNUNET_STATISTICS_create ("test-statistics-api", cfg); + GNUNET_break (NULL != + GNUNET_STATISTICS_get (h, NULL, "test-3", + GNUNET_TIME_UNIT_SECONDS, &next_fin, + &check_3, cls)); +} + +static int +check () +{ + int ok = 1; + + char *const argv[] = { "test-statistics-api", + "-c", + "test_statistics_api_data.conf", +#if DEBUG_STATISTICS + "-L", "DEBUG", +#else + "-L", "WARNING", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; +#if START_SERVICE + struct GNUNET_OS_Process *proc; + + proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics", + "gnunet-service-statistics", +#if DEBUG_STATISTICS + "-L", "DEBUG", +#endif + "-c", "test_statistics_api_data.conf", NULL); +#endif + GNUNET_assert (NULL != proc); + GNUNET_PROGRAM_run (5, argv, "test-statistics-api", "nohelp", options, &run, + &ok); +#if START_SERVICE + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + ok = 1; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; +#endif + if (ok != 0) + return ok; + ok = 1; +#if START_SERVICE + /* restart to check persistence! */ + proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics", + "gnunet-service-statistics", +#if DEBUG_STATISTICS + "-L", "DEBUG", +#endif + "-c", "test_statistics_api_data.conf", NULL); +#endif + GNUNET_PROGRAM_run (5, argv, "test-statistics-api", "nohelp", options, + &run_more, &ok); +#if START_SERVICE + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + ok = 1; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; +#endif + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test_statistics_api", +#if DEBUG_STATISTICS + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + return ret; +} + +/* end of test_statistics_api.c */ diff --git a/src/statistics/test_statistics_api_data.conf b/src/statistics/test_statistics_api_data.conf new file mode 100644 index 0000000..9ccb770 --- /dev/null +++ b/src/statistics/test_statistics_api_data.conf @@ -0,0 +1,43 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunetd-statistics/ +DEFAULTCONFIG = test_statistics_api_data.conf + +[statistics] +PORT = 22353 +UNIXPATH = /tmp/test-statistics-service-statistics.unix +#DEBUG = YES + +[arm] +PORT = 22354 +DEFAULTSERVICES = +UNIXPATH = /tmp/test-statistics-service-arm.unix +# DEBUG = YES + +[fs] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[dht] +AUTOSTART = NO + +[transport] +AUTOSTART = NO + +[core] +AUTOSTART = NO + +[peerinfo] +AUTOSTART = NO + + +[dns] +AUTOSTART = NO + + + +[nse] +AUTOSTART = NO + + diff --git a/src/statistics/test_statistics_api_loop.c b/src/statistics/test_statistics_api_loop.c new file mode 100644 index 0000000..32b176c --- /dev/null +++ b/src/statistics/test_statistics_api_loop.c @@ -0,0 +1,133 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file statistics/test_statistics_api_loop.c + * @brief testcase for statistics_api.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_statistics_service.h" + +#define VERBOSE GNUNET_NO + +#define START_SERVICE GNUNET_YES + +#define ROUNDS (1024 * 1024) + +static int +check_1 (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + GNUNET_assert (0 == strcmp (name, "test-0")); + GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api-loop")); + GNUNET_assert (is_persistent == GNUNET_NO); + return GNUNET_OK; +} + +static struct GNUNET_STATISTICS_Handle *h; + +static void +next (void *cls, int success) +{ + int *ok = cls; + + GNUNET_STATISTICS_destroy (h, GNUNET_NO); + GNUNET_assert (success == GNUNET_OK); + *ok = 0; +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + int i; + char name[128]; + + h = GNUNET_STATISTICS_create ("test-statistics-api-loop", cfg); + for (i = 0; i < ROUNDS; i++) + { + GNUNET_snprintf (name, sizeof (name), "test-%d", i % 256); + GNUNET_STATISTICS_set (h, name, i, GNUNET_NO); + GNUNET_snprintf (name, sizeof (name), "test-%d", i % 128); + GNUNET_STATISTICS_update (h, name, 1, GNUNET_NO); + } + i = 0; + GNUNET_break (NULL != + GNUNET_STATISTICS_get (h, NULL, "test-0", + GNUNET_TIME_UNIT_MINUTES, &next, + &check_1, cls)); +} + + +static int +check () +{ + int ok = 1; + + char *const argv[] = { "test-statistics-api", + "-c", + "test_statistics_api_data.conf", + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; +#if START_SERVICE + struct GNUNET_OS_Process *proc; + + proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics", + "gnunet-service-statistics", +#if DEBUG_STATISTICS + "-L", "DEBUG", +#endif + "-c", "test_statistics_api_data.conf", NULL); +#endif + GNUNET_assert (NULL != proc); + GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", options, &run, + &ok); +#if START_SERVICE + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + ok = 1; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; +#endif + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + ret = check (); + + return ret; +} + +/* end of test_statistics_api_loop.c */ diff --git a/src/statistics/test_statistics_api_watch.c b/src/statistics/test_statistics_api_watch.c new file mode 100644 index 0000000..979b561 --- /dev/null +++ b/src/statistics/test_statistics_api_watch.c @@ -0,0 +1,164 @@ +/* + This file is part of GNUnet. + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file statistics/test_statistics_api_watch.c + * @brief testcase for statistics_api.c watch functions + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_statistics_service.h" + +#define VERBOSE GNUNET_NO + +#define START_SERVICE GNUNET_YES + +static int ok; + +static struct GNUNET_STATISTICS_Handle *h; + +static struct GNUNET_STATISTICS_Handle *h2; + +static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + + +static void +force_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + fprintf (stderr, "Timeout, failed to receive notifications: %d\n", ok); + GNUNET_STATISTICS_destroy (h, GNUNET_NO); + GNUNET_STATISTICS_destroy (h2, GNUNET_NO); + ok = 7; +} + + +static void +normal_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_STATISTICS_destroy (h, GNUNET_NO); + GNUNET_STATISTICS_destroy (h2, GNUNET_NO); +} + + +static int +watch_1 (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + GNUNET_assert (value == 42); + GNUNET_assert (0 == strcmp (name, "test-1")); + ok &= ~1; + if (0 == ok) + { + GNUNET_SCHEDULER_cancel (shutdown_task); + GNUNET_SCHEDULER_add_now (&normal_shutdown, NULL); + } + return GNUNET_OK; +} + + +static int +watch_2 (void *cls, const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + GNUNET_assert (value == 43); + GNUNET_assert (0 == strcmp (name, "test-2")); + ok &= ~2; + if (0 == ok) + { + GNUNET_SCHEDULER_cancel (shutdown_task); + GNUNET_SCHEDULER_add_now (&normal_shutdown, NULL); + } + return GNUNET_OK; +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + h = GNUNET_STATISTICS_create ("dummy", cfg); + GNUNET_assert (GNUNET_OK == + GNUNET_STATISTICS_watch (h, "test-statistics-api-watch", + "test-1", &watch_1, NULL)); + GNUNET_assert (GNUNET_OK == + GNUNET_STATISTICS_watch (h, "test-statistics-api-watch", + "test-2", &watch_2, NULL)); + h2 = GNUNET_STATISTICS_create ("test-statistics-api-watch", cfg); + GNUNET_STATISTICS_set (h2, "test-1", 42, GNUNET_NO); + GNUNET_STATISTICS_set (h2, "test-2", 43, GNUNET_NO); + shutdown_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &force_shutdown, + NULL); +} + + +static int +check () +{ + char *const argv[] = { "test-statistics-api", + "-c", + "test_statistics_api_data.conf", + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; +#if START_SERVICE + struct GNUNET_OS_Process *proc; + + proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics", + "gnunet-service-statistics", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", "test_statistics_api_data.conf", NULL); +#endif + GNUNET_assert (NULL != proc); + ok = 3; + GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", options, &run, + NULL); +#if START_SERVICE + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + ok = 1; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; +#endif + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + ret = check (); + + return ret; +} + +/* end of test_statistics_api_watch.c */ diff --git a/src/stream/Makefile.am b/src/stream/Makefile.am new file mode 100644 index 0000000..385c0cf --- /dev/null +++ b/src/stream/Makefile.am @@ -0,0 +1,43 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +lib_LTLIBRARIES = libgnunetstream.la + +libgnunetstream_la_SOURCES = \ + stream_api.c stream_protocol.h +libgnunetstream_la_LIBADD = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +libgnunetstream_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) + +check_PROGRAMS = \ + test_stream_local +# test_stream_halfclose + +EXTRA_DIST = test_stream_local.conf + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_stream_local_SOURCES = \ + test_stream_local.c +test_stream_local_LDADD = \ + $(top_builddir)/src/stream/libgnunetstream.la \ + $(top_builddir)/src/util/libgnunetutil.la + +#test_stream_halfclose_SOURCES = \ +# test_stream_halfclose.c +#test_stream_halfclose_LDADD = \ +# $(top_builddir)/src/stream/libgnunetstream.la \ +# $(top_builddir)/src/util/libgnunetutil.la + diff --git a/src/stream/Makefile.in b/src/stream/Makefile.in new file mode 100644 index 0000000..44b63f7 --- /dev/null +++ b/src/stream/Makefile.in @@ -0,0 +1,789 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +check_PROGRAMS = test_stream_local$(EXEEXT) +subdir = src/stream +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunetstream_la_DEPENDENCIES = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunetstream_la_OBJECTS = stream_api.lo +libgnunetstream_la_OBJECTS = $(am_libgnunetstream_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetstream_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetstream_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_test_stream_local_OBJECTS = test_stream_local.$(OBJEXT) +test_stream_local_OBJECTS = $(am_test_stream_local_OBJECTS) +test_stream_local_DEPENDENCIES = \ + $(top_builddir)/src/stream/libgnunetstream.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetstream_la_SOURCES) $(test_stream_local_SOURCES) +DIST_SOURCES = $(libgnunetstream_la_SOURCES) \ + $(test_stream_local_SOURCES) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +lib_LTLIBRARIES = libgnunetstream.la +libgnunetstream_la_SOURCES = \ + stream_api.c stream_protocol.h + +libgnunetstream_la_LIBADD = \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) + +libgnunetstream_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) + +# test_stream_halfclose +EXTRA_DIST = test_stream_local.conf +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_stream_local_SOURCES = \ + test_stream_local.c + +test_stream_local_LDADD = \ + $(top_builddir)/src/stream/libgnunetstream.la \ + $(top_builddir)/src/util/libgnunetutil.la + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/stream/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/stream/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetstream.la: $(libgnunetstream_la_OBJECTS) $(libgnunetstream_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetstream_la_LINK) -rpath $(libdir) $(libgnunetstream_la_OBJECTS) $(libgnunetstream_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +test_stream_local$(EXEEXT): $(test_stream_local_OBJECTS) $(test_stream_local_DEPENDENCIES) + @rm -f test_stream_local$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_stream_local_OBJECTS) $(test_stream_local_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_stream_local.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-libLTLIBRARIES + + +#test_stream_halfclose_SOURCES = \ +# test_stream_halfclose.c +#test_stream_halfclose_LDADD = \ +# $(top_builddir)/src/stream/libgnunetstream.la \ +# $(top_builddir)/src/util/libgnunetutil.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/stream/README b/src/stream/README new file mode 100644 index 0000000..9b550b0 --- /dev/null +++ b/src/stream/README @@ -0,0 +1,11 @@ +The aim of the stream library is to provide stream connections between peers in +GNUnet. This is a convenience library which hides the complexity of dividing +data stream into packets, transmitting them and retransmitting them in case of +errors. + +This library's API are similar to unix PIPE API. The user is expected to open a +stream to a listening target peer. Once the stream is established, the user can +use it as a pipe. Any data written into the stream will be readable by the +target peer. + +This library uses mesh API for establishing streams between peers. \ No newline at end of file diff --git a/src/stream/stream_api.c b/src/stream/stream_api.c new file mode 100644 index 0000000..84fcdfd --- /dev/null +++ b/src/stream/stream_api.c @@ -0,0 +1,2180 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file stream/stream_api.c + * @brief Implementation of the stream library + * @author Sree Harsha Totakura + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_stream_lib.h" +#include "stream_protocol.h" + + +/** + * The maximum packet size of a stream packet + */ +#define MAX_PACKET_SIZE 64000 + +/** + * The maximum payload a data message packet can carry + */ +static size_t max_payload_size = + MAX_PACKET_SIZE - sizeof (struct GNUNET_STREAM_DataMessage); + +/** + * Receive buffer + */ +#define RECEIVE_BUFFER_SIZE 4096000 + +/** + * states in the Protocol + */ +enum State + { + /** + * Client initialization state + */ + STATE_INIT, + + /** + * Listener initialization state + */ + STATE_LISTEN, + + /** + * Pre-connection establishment state + */ + STATE_HELLO_WAIT, + + /** + * State where a connection has been established + */ + STATE_ESTABLISHED, + + /** + * State where the socket is closed on our side and waiting to be ACK'ed + */ + STATE_RECEIVE_CLOSE_WAIT, + + /** + * State where the socket is closed for reading + */ + STATE_RECEIVE_CLOSED, + + /** + * State where the socket is closed on our side and waiting to be ACK'ed + */ + STATE_TRANSMIT_CLOSE_WAIT, + + /** + * State where the socket is closed for writing + */ + STATE_TRANSMIT_CLOSED, + + /** + * State where the socket is closed on our side and waiting to be ACK'ed + */ + STATE_CLOSE_WAIT, + + /** + * State where the socket is closed + */ + STATE_CLOSED + }; + + +/** + * Functions of this type are called when a message is written + * + * @param cls the closure from queue_message + * @param socket the socket the written message was bound to + */ +typedef void (*SendFinishCallback) (void *cls, + struct GNUNET_STREAM_Socket *socket); + + +/** + * The send message queue + */ +struct MessageQueue +{ + /** + * The message + */ + struct GNUNET_STREAM_MessageHeader *message; + + /** + * Callback to be called when the message is sent + */ + SendFinishCallback finish_cb; + + /** + * The closure for finish_cb + */ + void *finish_cb_cls; + + /** + * The next message in queue. Should be NULL in the last message + */ + struct MessageQueue *next; + + /** + * The next message in queue. Should be NULL in the first message + */ + struct MessageQueue *prev; +}; + + +/** + * The STREAM Socket Handler + */ +struct GNUNET_STREAM_Socket +{ + + /** + * The peer identity of the peer at the other end of the stream + */ + struct GNUNET_PeerIdentity other_peer; + + /** + * Retransmission timeout + */ + struct GNUNET_TIME_Relative retransmit_timeout; + + /** + * The Acknowledgement Bitmap + */ + GNUNET_STREAM_AckBitmap ack_bitmap; + + /** + * Time when the Acknowledgement was queued + */ + struct GNUNET_TIME_Absolute ack_time_registered; + + /** + * Queued Acknowledgement deadline + */ + struct GNUNET_TIME_Relative ack_time_deadline; + + /** + * The task for sending timely Acks + */ + GNUNET_SCHEDULER_TaskIdentifier ack_task_id; + + /** + * Task scheduled to continue a read operation. + */ + GNUNET_SCHEDULER_TaskIdentifier read_task; + + /** + * The mesh handle + */ + struct GNUNET_MESH_Handle *mesh; + + /** + * The mesh tunnel handle + */ + struct GNUNET_MESH_Tunnel *tunnel; + + /** + * Stream open closure + */ + void *open_cls; + + /** + * Stream open callback + */ + GNUNET_STREAM_OpenCallback open_cb; + + /** + * The current transmit handle (if a pending transmit request exists) + */ + struct GNUNET_MESH_TransmitHandle *transmit_handle; + + /** + * The current message associated with the transmit handle + */ + struct MessageQueue *queue_head; + + /** + * The queue tail, should always point to the last message in queue + */ + struct MessageQueue *queue_tail; + + /** + * The write IO_handle associated with this socket + */ + struct GNUNET_STREAM_IOWriteHandle *write_handle; + + /** + * The read IO_handle associated with this socket + */ + struct GNUNET_STREAM_IOReadHandle *read_handle; + + /** + * Buffer for storing received messages + */ + void *receive_buffer; + + /** + * Task identifier for the read io timeout task + */ + GNUNET_SCHEDULER_TaskIdentifier read_io_timeout_task; + + /** + * The state of the protocol associated with this socket + */ + enum State state; + + /** + * The status of the socket + */ + enum GNUNET_STREAM_Status status; + + /** + * The number of previous timeouts; FIXME: currently not used + */ + unsigned int retries; + + /** + * The session id associated with this stream connection + * FIXME: Not used currently, may be removed + */ + uint32_t session_id; + + /** + * Write sequence number. Set to random when sending HELLO(client) and + * HELLO_ACK(server) + */ + uint32_t write_sequence_number; + + /** + * Read sequence number. This number's value is determined during handshake + */ + uint32_t read_sequence_number; + + /** + * The receiver buffer size + */ + uint32_t receive_buffer_size; + + /** + * The receiver buffer boundaries + */ + uint32_t receive_buffer_boundaries[GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH]; + + /** + * receiver's available buffer after the last acknowledged packet + */ + uint32_t receive_window_available; + + /** + * The offset pointer used during write operation + */ + uint32_t write_offset; + + /** + * The offset after which we are expecting data + */ + uint32_t read_offset; + + /** + * The offset upto which user has read from the received buffer + */ + uint32_t copy_offset; +}; + + +/** + * A socket for listening + */ +struct GNUNET_STREAM_ListenSocket +{ + + /** + * The mesh handle + */ + struct GNUNET_MESH_Handle *mesh; + + /** + * The callback function which is called after successful opening socket + */ + GNUNET_STREAM_ListenCallback listen_cb; + + /** + * The call back closure + */ + void *listen_cb_cls; + + /** + * The service port + */ + GNUNET_MESH_ApplicationType port; +}; + + +/** + * The IO Write Handle + */ +struct GNUNET_STREAM_IOWriteHandle +{ + /** + * The packet_buffers associated with this Handle + */ + struct GNUNET_STREAM_DataMessage *messages[64]; + + /** + * The bitmap of this IOHandle; Corresponding bit for a message is set when + * it has been acknowledged by the receiver + */ + GNUNET_STREAM_AckBitmap ack_bitmap; + + /** + * Number of packets sent before waiting for an ack + * + * FIXME: Do we need this? + */ + unsigned int sent_packets; +}; + + +/** + * The IO Read Handle + */ +struct GNUNET_STREAM_IOReadHandle +{ + /** + * Callback for the read processor + */ + GNUNET_STREAM_DataProcessor proc; + + /** + * The closure pointer for the read processor callback + */ + void *proc_cls; +}; + + +/** + * Default value in seconds for various timeouts + */ +static unsigned int default_timeout = 300; + + +/** + * Callback function for sending hello message + * + * @param cls closure the socket + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +send_message_notify (void *cls, size_t size, void *buf) +{ + struct GNUNET_STREAM_Socket *socket = cls; + struct MessageQueue *head; + size_t ret; + + socket->transmit_handle = NULL; /* Remove the transmit handle */ + head = socket->queue_head; + if (NULL == head) + return 0; /* just to be safe */ + if (0 == size) /* request timed out */ + { + socket->retries++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Message sending timed out. Retry %d \n", + socket->retries); + socket->transmit_handle = + GNUNET_MESH_notify_transmit_ready (socket->tunnel, + 0, /* Corking */ + 1, /* Priority */ + /* FIXME: exponential backoff */ + socket->retransmit_timeout, + &socket->other_peer, + ntohs (head->message->header.size), + &send_message_notify, + socket); + return 0; + } + + ret = ntohs (head->message->header.size); + GNUNET_assert (size >= ret); + memcpy (buf, head->message, ret); + if (NULL != head->finish_cb) + { + head->finish_cb (socket, head->finish_cb_cls); + } + GNUNET_CONTAINER_DLL_remove (socket->queue_head, + socket->queue_tail, + head); + GNUNET_free (head->message); + GNUNET_free (head); + head = socket->queue_head; + if (NULL != head) /* more pending messages to send */ + { + socket->retries = 0; + socket->transmit_handle = + GNUNET_MESH_notify_transmit_ready (socket->tunnel, + 0, /* Corking */ + 1, /* Priority */ + /* FIXME: exponential backoff */ + socket->retransmit_timeout, + &socket->other_peer, + ntohs (head->message->header.size), + &send_message_notify, + socket); + } + return ret; +} + + +/** + * Queues a message for sending using the mesh connection of a socket + * + * @param socket the socket whose mesh connection is used + * @param message the message to be sent + * @param finish_cb the callback to be called when the message is sent + * @param finish_cb_cls the closure for the callback + */ +static void +queue_message (struct GNUNET_STREAM_Socket *socket, + struct GNUNET_STREAM_MessageHeader *message, + SendFinishCallback finish_cb, + void *finish_cb_cls) +{ + struct MessageQueue *queue_entity; + + queue_entity = GNUNET_malloc (sizeof (struct MessageQueue)); + queue_entity->message = message; + queue_entity->finish_cb = finish_cb; + queue_entity->finish_cb_cls = finish_cb_cls; + GNUNET_CONTAINER_DLL_insert_tail (socket->queue_head, + socket->queue_tail, + queue_entity); + if (NULL == socket->transmit_handle) + { + socket->retries = 0; + socket->transmit_handle = + GNUNET_MESH_notify_transmit_ready (socket->tunnel, + 0, /* Corking */ + 1, /* Priority */ + socket->retransmit_timeout, + &socket->other_peer, + ntohs (message->header.size), + &send_message_notify, + socket); + } +} + + +/** + * Callback function for sending ack message + * + * @param cls closure the ACK message created in ack_task + * @param size number of bytes available in buffer + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +send_ack_notify (void *cls, size_t size, void *buf) +{ + struct GNUNET_STREAM_AckMessage *ack_msg = cls; + + if (0 == size) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s called with size 0\n", __func__); + return 0; + } + GNUNET_assert (ack_msg->header.header.size <= size); + + size = ack_msg->header.header.size; + memcpy (buf, ack_msg, size); + return size; +} + + +/** + * Task for sending ACK message + * + * @param cls the socket + * @param tc the Task context + */ +static void +ack_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_STREAM_Socket *socket = cls; + struct GNUNET_STREAM_AckMessage *ack_msg; + + if (GNUNET_SCHEDULER_REASON_SHUTDOWN == tc->reason) + { + return; + } + + socket->ack_task_id = 0; + + /* Create the ACK Message */ + ack_msg = GNUNET_malloc (sizeof (struct GNUNET_STREAM_AckMessage)); + ack_msg->header.header.size = htons (sizeof (struct + GNUNET_STREAM_AckMessage)); + ack_msg->header.header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_ACK); + ack_msg->bitmap = GNUNET_htonll (socket->ack_bitmap); + ack_msg->base_sequence_number = htonl (socket->read_sequence_number); + ack_msg->receive_window_remaining = + htonl (RECEIVE_BUFFER_SIZE - socket->receive_buffer_size); + + /* Request MESH for sending ACK */ + GNUNET_MESH_notify_transmit_ready (socket->tunnel, + 0, /* Corking */ + 1, /* Priority */ + socket->retransmit_timeout, + &socket->other_peer, + ntohs (ack_msg->header.header.size), + &send_ack_notify, + ack_msg); + + +} + + +/** + * Function to modify a bit in GNUNET_STREAM_AckBitmap + * + * @param bitmap the bitmap to modify + * @param bit the bit number to modify + * @param value GNUNET_YES to on, GNUNET_NO to off + */ +static void +ackbitmap_modify_bit (GNUNET_STREAM_AckBitmap *bitmap, + unsigned int bit, + int value) +{ + GNUNET_assert (bit < 64); + if (GNUNET_YES == value) + *bitmap |= (1LL << bit); + else + *bitmap &= ~(1LL << bit); +} + + +/** + * Function to check if a bit is set in the GNUNET_STREAM_AckBitmap + * + * @param bitmap address of the bitmap that has to be checked + * @param bit the bit number to check + * @return GNUNET_YES if the bit is set; GNUNET_NO if not + */ +static uint8_t +ackbitmap_is_bit_set (const GNUNET_STREAM_AckBitmap *bitmap, + unsigned int bit) +{ + GNUNET_assert (bit < 64); + return 0 != (*bitmap & (1LL << bit)); +} + + + +/** + * Function called when Data Message is sent + * + * @param cls the io_handle corresponding to the Data Message + * @param socket the socket which was used + */ +static void +write_data_finish_cb (void *cls, + struct GNUNET_STREAM_Socket *socket) +{ + struct GNUNET_STREAM_IOWriteHandle *io_handle = cls; + + io_handle->sent_packets++; +} + + +/** + * Writes data using the given socket. The amount of data written is limited by + * the receive_window_size + * + * @param socket the socket to use + */ +static void +write_data (struct GNUNET_STREAM_Socket *socket) +{ + struct GNUNET_STREAM_IOWriteHandle *io_handle = socket->write_handle; + unsigned int packet; + int ack_packet; + + ack_packet = -1; + /* Find the last acknowledged packet */ + for (packet=0; packet < 64; packet++) + { + if (GNUNET_YES == ackbitmap_is_bit_set (&io_handle->ack_bitmap, + packet)) + ack_packet = packet; + else if (NULL == io_handle->messages[packet]) + break; + } + /* Resend packets which weren't ack'ed */ + for (packet=0; packet < ack_packet; packet++) + { + if (GNUNET_NO == ackbitmap_is_bit_set (&io_handle->ack_bitmap, + packet)) + { + queue_message (socket, + &io_handle->messages[packet]->header, + NULL, + NULL); + } + } + packet = ack_packet + 1; + /* Now send new packets if there is enough buffer space */ + while ( (NULL != io_handle->messages[packet]) && + (socket->receive_window_available >= ntohs (io_handle->messages[packet]->header.header.size)) ) + { + socket->receive_window_available -= ntohs (io_handle->messages[packet]->header.header.size); + queue_message (socket, + &io_handle->messages[packet]->header, + &write_data_finish_cb, + io_handle); + packet++; + } +} + + +/** + * Task for calling the read processor + * + * @param cls the socket + * @param tc the task context + */ +static void +call_read_processor (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_STREAM_Socket *socket = cls; + size_t read_size; + size_t valid_read_size; + unsigned int packet; + uint32_t sequence_increase; + uint32_t offset_increase; + + socket->read_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + GNUNET_assert (NULL != socket->read_handle); + GNUNET_assert (NULL != socket->read_handle->proc); + + /* Check the bitmap for any holes */ + for (packet=0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) + { + if (GNUNET_NO == ackbitmap_is_bit_set (&socket->ack_bitmap, + packet)) + break; + } + /* We only call read processor if we have the first packet */ + GNUNET_assert (0 < packet); + + valid_read_size = + socket->receive_buffer_boundaries[packet-1] - socket->copy_offset; + + GNUNET_assert (0 != valid_read_size); + + /* Cancel the read_io_timeout_task */ + GNUNET_SCHEDULER_cancel (socket->read_io_timeout_task); + socket->read_io_timeout_task = GNUNET_SCHEDULER_NO_TASK; + + /* Call the data processor */ + read_size = + socket->read_handle->proc (socket->read_handle->proc_cls, + socket->status, + socket->receive_buffer + socket->copy_offset, + valid_read_size); + /* Free the read handle */ + GNUNET_free (socket->read_handle); + socket->read_handle = NULL; + + GNUNET_assert (read_size <= valid_read_size); + socket->copy_offset += read_size; + + /* Determine upto which packet we can remove from the buffer */ + for (packet = 0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) + if (socket->copy_offset < socket->receive_buffer_boundaries[packet]) + break; + + /* If no packets can be removed we can't move the buffer */ + if (0 == packet) return; + + sequence_increase = packet; + + /* Shift the data in the receive buffer */ + memmove (socket->receive_buffer, + socket->receive_buffer + + socket->receive_buffer_boundaries[sequence_increase-1], + socket->receive_buffer_size - socket->receive_buffer_boundaries[sequence_increase-1]); + + /* Shift the bitmap */ + socket->ack_bitmap = socket->ack_bitmap >> sequence_increase; + + /* Set read_sequence_number */ + socket->read_sequence_number += sequence_increase; + + /* Set read_offset */ + offset_increase = socket->receive_buffer_boundaries[sequence_increase-1]; + socket->read_offset += offset_increase; + + /* Fix copy_offset */ + GNUNET_assert (offset_increase <= socket->copy_offset); + socket->copy_offset -= offset_increase; + + /* Fix relative boundaries */ + for (packet=0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) + { + if (packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH - sequence_increase) + { + socket->receive_buffer_boundaries[packet] = + socket->receive_buffer_boundaries[packet + sequence_increase] + - offset_increase; + } + else + socket->receive_buffer_boundaries[packet] = 0; + } +} + + +/** + * Cancels the existing read io handle + * + * @param cls the closure from the SCHEDULER call + * @param tc the task context + */ +static void +read_io_timeout (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_STREAM_Socket *socket = cls; + + socket->read_io_timeout_task = GNUNET_SCHEDULER_NO_TASK; + if (socket->read_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (socket->read_task); + socket->read_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_assert (NULL != socket->read_handle); + + GNUNET_free (socket->read_handle); + socket->read_handle = NULL; +} + + +/** + * Handler for DATA messages; Same for both client and server + * + * @param socket the socket through which the ack was received + * @param tunnel connection to the other end + * @param sender who sent the message + * @param msg the data message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_data (struct GNUNET_STREAM_Socket *socket, + struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_STREAM_DataMessage *msg, + const struct GNUNET_ATS_Information*atsi) +{ + const void *payload; + uint32_t bytes_needed; + uint32_t relative_offset; + uint32_t relative_sequence_number; + uint16_t size; + + size = htons (msg->header.header.size); + if (size < sizeof (struct GNUNET_STREAM_DataMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + switch (socket->state) + { + case STATE_ESTABLISHED: + case STATE_TRANSMIT_CLOSED: + case STATE_TRANSMIT_CLOSE_WAIT: + + /* check if the message's sequence number is in the range we are + expecting */ + relative_sequence_number = + ntohl (msg->sequence_number) - socket->read_sequence_number; + if ( relative_sequence_number > 64) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Ignoring received message with sequence number %d", + ntohl (msg->sequence_number)); + return GNUNET_YES; + } + + /* Check if we have to allocate the buffer */ + size -= sizeof (struct GNUNET_STREAM_DataMessage); + relative_offset = ntohl (msg->offset) - socket->read_offset; + bytes_needed = relative_offset + size; + + if (bytes_needed > socket->receive_buffer_size) + { + if (bytes_needed <= RECEIVE_BUFFER_SIZE) + { + socket->receive_buffer = GNUNET_realloc (socket->receive_buffer, + bytes_needed); + socket->receive_buffer_size = bytes_needed; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cannot accommodate packet %d as buffer is full\n", + ntohl (msg->sequence_number)); + return GNUNET_YES; + } + } + + /* Copy Data to buffer */ + payload = &msg[1]; + GNUNET_assert (relative_offset + size <= socket->receive_buffer_size); + memcpy (socket->receive_buffer + relative_offset, + payload, + size); + socket->receive_buffer_boundaries[relative_sequence_number] = + relative_offset + size; + + /* Modify the ACK bitmap */ + ackbitmap_modify_bit (&socket->ack_bitmap, + relative_sequence_number, + GNUNET_YES); + + /* Start ACK sending task if one is not already present */ + if (0 == socket->ack_task_id) + { + socket->ack_task_id = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_ntoh + (msg->ack_deadline), + &ack_task, + socket); + } + + if ((NULL != socket->read_handle) /* A read handle is waiting */ + /* There is no current read task */ + && (GNUNET_SCHEDULER_NO_TASK == socket->read_task) + /* We have the first packet */ + && (GNUNET_YES == ackbitmap_is_bit_set(&socket->ack_bitmap, + 0))) + { + socket->read_task = + GNUNET_SCHEDULER_add_now (&call_read_processor, + socket); + } + + break; + + default: + /* FIXME: call statistics */ + break; + } + return GNUNET_YES; +} + +/** + * Client's message Handler for GNUNET_MESSAGE_TYPE_STREAM_DATA + * + * @param cls the socket (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx place to store local state associated with the tunnel + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +client_handle_data (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + + return handle_data (socket, + tunnel, + sender, + (const struct GNUNET_STREAM_DataMessage *) message, + atsi); +} + + +/** + * Callback to set state to ESTABLISHED + * + * @param cls the closure from queue_message FIXME: document + * @param socket the socket to requiring state change + */ +static void +set_state_established (void *cls, + struct GNUNET_STREAM_Socket *socket) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attaining ESTABLISHED state\n"); + socket->write_offset = 0; + socket->read_offset = 0; + socket->state = STATE_ESTABLISHED; +} + + +/** + * Callback to set state to HELLO_WAIT + * + * @param cls the closure from queue_message + * @param socket the socket to requiring state change + */ +static void +set_state_hello_wait (void *cls, + struct GNUNET_STREAM_Socket *socket) +{ + GNUNET_assert (STATE_INIT == socket->state); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attaining HELLO_WAIT state\n"); + socket->state = STATE_HELLO_WAIT; +} + + +/** + * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK + * + * @param cls the socket (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx this is NULL + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +client_handle_hello_ack (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + const struct GNUNET_STREAM_HelloAckMessage *ack_msg; + struct GNUNET_STREAM_HelloAckMessage *reply; + + ack_msg = (const struct GNUNET_STREAM_HelloAckMessage *) message; + GNUNET_assert (socket->tunnel == tunnel); + switch (socket->state) + { + case STATE_HELLO_WAIT: + socket->read_sequence_number = ntohl (ack_msg->sequence_number); + socket->receive_window_available = ntohl (ack_msg->receive_window_size); + /* Get the random sequence number */ + socket->write_sequence_number = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + reply = + GNUNET_malloc (sizeof (struct GNUNET_STREAM_HelloAckMessage)); + reply->header.header.size = + htons (sizeof (struct GNUNET_STREAM_MessageHeader)); + reply->header.header.type = + htons (GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK); + reply->sequence_number = htonl (socket->write_sequence_number); + reply->receive_window_size = htonl (RECEIVE_BUFFER_SIZE); + queue_message (socket, + &reply->header, + &set_state_established, + NULL); + return GNUNET_OK; + case STATE_ESTABLISHED: + case STATE_RECEIVE_CLOSE_WAIT: + // call statistics (# ACKs ignored++) + return GNUNET_OK; + case STATE_INIT: + default: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Server sent HELLO_ACK when in state %d\n", socket->state); + socket->state = STATE_CLOSED; // introduce STATE_ERROR? + return GNUNET_SYSERR; + } + +} + + +/** + * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_RESET + * + * @param cls the socket (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx this is NULL + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +client_handle_reset (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + + return GNUNET_OK; +} + + +/** + * Common message handler for handling TRANSMIT_CLOSE messages + * + * @param socket the socket through which the ack was received + * @param tunnel connection to the other end + * @param sender who sent the message + * @param msg the transmit close message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_transmit_close (struct GNUNET_STREAM_Socket *socket, + struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_STREAM_MessageHeader *msg, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_MessageHeader *reply; + + switch (socket->state) + { + case STATE_ESTABLISHED: + socket->state = STATE_RECEIVE_CLOSED; + + /* Send TRANSMIT_CLOSE_ACK */ + reply = GNUNET_malloc (sizeof (struct GNUNET_STREAM_MessageHeader)); + reply->header.type = + htons (GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK); + reply->header.size = htons (sizeof (struct GNUNET_STREAM_MessageHeader)); + queue_message (socket, reply, NULL, NULL); + break; + + default: + /* FIXME: Call statistics? */ + break; + } + return GNUNET_YES; +} + + +/** + * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE + * + * @param cls the socket (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx this is NULL + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +client_handle_transmit_close (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + + return handle_transmit_close (socket, + tunnel, + sender, + (struct GNUNET_STREAM_MessageHeader *)message, + atsi); +} + + +/** + * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK + * + * @param cls the socket (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx this is NULL + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +client_handle_transmit_close_ack (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + + return GNUNET_OK; +} + + +/** + * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE + * + * @param cls the socket (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx this is NULL + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +client_handle_receive_close (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + + return GNUNET_OK; +} + + +/** + * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK + * + * @param cls the socket (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx this is NULL + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +client_handle_receive_close_ack (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + + return GNUNET_OK; +} + + +/** + * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_CLOSE + * + * @param cls the socket (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx this is NULL + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +client_handle_close (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + + return GNUNET_OK; +} + + +/** + * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK + * + * @param cls the socket (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx this is NULL + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +client_handle_close_ack (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + + return GNUNET_OK; +} + +/*****************************/ +/* Server's Message Handlers */ +/*****************************/ + +/** + * Server's message Handler for GNUNET_MESSAGE_TYPE_STREAM_DATA + * + * @param cls the closure + * @param tunnel connection to the other end + * @param tunnel_ctx the socket + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_data (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + + return handle_data (socket, + tunnel, + sender, + (const struct GNUNET_STREAM_DataMessage *)message, + atsi); +} + + +/** + * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_HELLO + * + * @param cls the closure + * @param tunnel connection to the other end + * @param tunnel_ctx the socket + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_hello (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + struct GNUNET_STREAM_HelloAckMessage *reply; + + GNUNET_assert (socket->tunnel == tunnel); + if (STATE_INIT == socket->state) + { + /* Get the random sequence number */ + socket->write_sequence_number = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + reply = + GNUNET_malloc (sizeof (struct GNUNET_STREAM_HelloAckMessage)); + reply->header.header.size = + htons (sizeof (struct GNUNET_STREAM_MessageHeader)); + reply->header.header.type = + htons (GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK); + reply->sequence_number = htonl (socket->write_sequence_number); + queue_message (socket, + &reply->header, + &set_state_hello_wait, + NULL); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client sent HELLO when in state %d\n", socket->state); + /* FIXME: Send RESET? */ + + } + return GNUNET_OK; +} + + +/** + * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK + * + * @param cls the closure + * @param tunnel connection to the other end + * @param tunnel_ctx the socket + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_hello_ack (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + const struct GNUNET_STREAM_HelloAckMessage *ack_message; + + ack_message = (struct GNUNET_STREAM_HelloAckMessage *) message; + GNUNET_assert (socket->tunnel == tunnel); + if (STATE_HELLO_WAIT == socket->state) + { + socket->read_sequence_number = ntohl (ack_message->sequence_number); + socket->receive_window_available = + ntohl (ack_message->receive_window_size); + /* Attain ESTABLISHED state */ + set_state_established (NULL, socket); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client sent HELLO_ACK when in state %d\n", socket->state); + /* FIXME: Send RESET? */ + + } + return GNUNET_OK; +} + + +/** + * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_RESET + * + * @param cls the closure + * @param tunnel connection to the other end + * @param tunnel_ctx the socket + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_reset (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + + return GNUNET_OK; +} + + +/** + * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE + * + * @param cls the closure + * @param tunnel connection to the other end + * @param tunnel_ctx the socket + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_transmit_close (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + + return handle_transmit_close (socket, + tunnel, + sender, + (struct GNUNET_STREAM_MessageHeader *)message, + atsi); +} + + +/** + * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK + * + * @param cls the closure + * @param tunnel connection to the other end + * @param tunnel_ctx the socket + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_transmit_close_ack (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + + return GNUNET_OK; +} + + +/** + * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE + * + * @param cls the closure + * @param tunnel connection to the other end + * @param tunnel_ctx the socket + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_receive_close (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + + return GNUNET_OK; +} + + +/** + * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK + * + * @param cls the closure + * @param tunnel connection to the other end + * @param tunnel_ctx the socket + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_receive_close_ack (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + + return GNUNET_OK; +} + + +/** + * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_CLOSE + * + * @param cls the closure + * @param tunnel connection to the other end + * @param tunnel_ctx the socket + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_close (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + + return GNUNET_OK; +} + + +/** + * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK + * + * @param cls the closure + * @param tunnel connection to the other end + * @param tunnel_ctx the socket + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_close_ack (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + + return GNUNET_OK; +} + + +/** + * Message Handler for mesh + * + * @param socket the socket through which the ack was received + * @param tunnel connection to the other end + * @param sender who sent the message + * @param ack the acknowledgment message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_ack (struct GNUNET_STREAM_Socket *socket, + struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_STREAM_AckMessage *ack, + const struct GNUNET_ATS_Information*atsi) +{ + switch (socket->state) + { + case (STATE_ESTABLISHED): + if (NULL == socket->write_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received DATA ACK when write_handle is NULL\n"); + return GNUNET_OK; + } + + socket->write_handle->ack_bitmap = GNUNET_ntohll (ack->bitmap); + socket->receive_window_available = + ntohl (ack->receive_window_remaining); + write_data (socket); + break; + default: + break; + } + return GNUNET_OK; +} + + +/** + * Message Handler for mesh + * + * @param cls the 'struct GNUNET_STREAM_Socket' + * @param tunnel connection to the other end + * @param tunnel_ctx unused + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +client_handle_ack (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + const struct GNUNET_STREAM_AckMessage *ack = (const struct GNUNET_STREAM_AckMessage *) message; + + return handle_ack (socket, tunnel, sender, ack, atsi); +} + + +/** + * Message Handler for mesh + * + * @param cls the server's listen socket + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to the 'struct GNUNET_STREAM_Socket*' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +server_handle_ack (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information*atsi) +{ + struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; + const struct GNUNET_STREAM_AckMessage *ack = (const struct GNUNET_STREAM_AckMessage *) message; + + return handle_ack (socket, tunnel, sender, ack, atsi); +} + + +/** + * For client message handlers, the stream socket is in the + * closure argument. + */ +static struct GNUNET_MESH_MessageHandler client_message_handlers[] = { + {&client_handle_data, GNUNET_MESSAGE_TYPE_STREAM_DATA, 0}, + {&client_handle_ack, GNUNET_MESSAGE_TYPE_STREAM_ACK, + sizeof (struct GNUNET_STREAM_AckMessage) }, + {&client_handle_hello_ack, GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK, + sizeof (struct GNUNET_STREAM_HelloAckMessage)}, + {&client_handle_reset, GNUNET_MESSAGE_TYPE_STREAM_RESET, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&client_handle_transmit_close, GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&client_handle_transmit_close_ack, GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&client_handle_receive_close, GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&client_handle_receive_close_ack, GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&client_handle_close, GNUNET_MESSAGE_TYPE_STREAM_CLOSE, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&client_handle_close_ack, GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {NULL, 0, 0} +}; + + +/** + * For server message handlers, the stream socket is in the + * tunnel context, and the listen socket in the closure argument. + */ +static struct GNUNET_MESH_MessageHandler server_message_handlers[] = { + {&server_handle_data, GNUNET_MESSAGE_TYPE_STREAM_DATA, 0}, + {&server_handle_ack, GNUNET_MESSAGE_TYPE_STREAM_ACK, + sizeof (struct GNUNET_STREAM_AckMessage) }, + {&server_handle_hello, GNUNET_MESSAGE_TYPE_STREAM_HELLO, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&server_handle_hello_ack, GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK, + sizeof (struct GNUNET_STREAM_HelloAckMessage)}, + {&server_handle_reset, GNUNET_MESSAGE_TYPE_STREAM_RESET, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&server_handle_transmit_close, GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&server_handle_transmit_close_ack, GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&server_handle_receive_close, GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&server_handle_receive_close_ack, GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&server_handle_close, GNUNET_MESSAGE_TYPE_STREAM_CLOSE, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {&server_handle_close_ack, GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK, + sizeof (struct GNUNET_STREAM_MessageHeader)}, + {NULL, 0, 0} +}; + + +/** + * Function called when our target peer is connected to our tunnel + * + * @param cls the socket for which this tunnel is created + * @param peer the peer identity of the target + * @param atsi performance data for the connection + */ +static void +mesh_peer_connect_callback (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information * atsi) +{ + struct GNUNET_STREAM_Socket *socket = cls; + struct GNUNET_STREAM_MessageHeader *message; + + if (0 != memcmp (&socket->other_peer, + peer, + sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "A peer (%s) which is not our target has connected to our tunnel", + GNUNET_i2s (peer)); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Target peer %s connected\n", GNUNET_i2s (peer)); + + /* Set state to INIT */ + socket->state = STATE_INIT; + + /* Send HELLO message */ + message = GNUNET_malloc (sizeof (struct GNUNET_STREAM_MessageHeader)); + message->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_HELLO); + message->header.size = htons (sizeof (struct GNUNET_STREAM_MessageHeader)); + queue_message (socket, + message, + &set_state_hello_wait, + NULL); + + /* Call open callback */ + if (NULL == socket->open_cb) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "STREAM_open callback is NULL\n"); + } + else + { + socket->open_cb (socket->open_cls, socket); + } +} + + +/** + * Function called when our target peer is disconnected from our tunnel + * + * @param cls the socket associated which this tunnel + * @param peer the peer identity of the target + */ +static void +mesh_peer_disconnect_callback (void *cls, + const struct GNUNET_PeerIdentity *peer) +{ + +} + + +/*****************/ +/* API functions */ +/*****************/ + + +/** + * Tries to open a stream to the target peer + * + * @param cfg configuration to use + * @param target the target peer to which the stream has to be opened + * @param app_port the application port number which uniquely identifies this + * stream + * @param open_cb this function will be called after stream has be established + * @param open_cb_cls the closure for open_cb + * @param ... options to the stream, terminated by GNUNET_STREAM_OPTION_END + * @return if successful it returns the stream socket; NULL if stream cannot be + * opened + */ +struct GNUNET_STREAM_Socket * +GNUNET_STREAM_open (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PeerIdentity *target, + GNUNET_MESH_ApplicationType app_port, + GNUNET_STREAM_OpenCallback open_cb, + void *open_cb_cls, + ...) +{ + struct GNUNET_STREAM_Socket *socket; + enum GNUNET_STREAM_Option option; + va_list vargs; /* Variable arguments */ + + socket = GNUNET_malloc (sizeof (struct GNUNET_STREAM_Socket)); + socket->other_peer = *target; + socket->open_cb = open_cb; + socket->open_cls = open_cb_cls; + + /* Set defaults */ + socket->retransmit_timeout = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, default_timeout); + + va_start (vargs, open_cb_cls); /* Parse variable args */ + do { + option = va_arg (vargs, enum GNUNET_STREAM_Option); + switch (option) + { + case GNUNET_STREAM_OPTION_INITIAL_RETRANSMIT_TIMEOUT: + /* Expect struct GNUNET_TIME_Relative */ + socket->retransmit_timeout = va_arg (vargs, + struct GNUNET_TIME_Relative); + break; + case GNUNET_STREAM_OPTION_END: + break; + } + } while (GNUNET_STREAM_OPTION_END != option); + va_end (vargs); /* End of variable args parsing */ + + socket->mesh = GNUNET_MESH_connect (cfg, /* the configuration handle */ + 1, /* QUEUE size as parameter? */ + socket, /* cls */ + NULL, /* No inbound tunnel handler */ + NULL, /* No inbound tunnel cleaner */ + client_message_handlers, + NULL); /* We don't get inbound tunnels */ + // FIXME: if (NULL == socket->mesh) ... + + /* Now create the mesh tunnel to target */ + socket->tunnel = GNUNET_MESH_tunnel_create (socket->mesh, + NULL, /* Tunnel context */ + &mesh_peer_connect_callback, + &mesh_peer_disconnect_callback, + socket); + // FIXME: if (NULL == socket->tunnel) ... + + return socket; +} + + +/** + * Closes the stream + * + * @param socket the stream socket + */ +void +GNUNET_STREAM_close (struct GNUNET_STREAM_Socket *socket) +{ + struct MessageQueue *head; + + if (socket->read_task != GNUNET_SCHEDULER_NO_TASK) + { + /* socket closed with read task pending!? */ + GNUNET_break (0); + GNUNET_SCHEDULER_cancel (socket->read_task); + socket->read_task = GNUNET_SCHEDULER_NO_TASK; + } + + /* Clear Transmit handles */ + if (NULL != socket->transmit_handle) + { + GNUNET_MESH_notify_transmit_ready_cancel (socket->transmit_handle); + socket->transmit_handle = NULL; + } + + /* Clear existing message queue */ + while (NULL != (head = socket->queue_head)) { + GNUNET_CONTAINER_DLL_remove (socket->queue_head, + socket->queue_tail, + head); + GNUNET_free (head->message); + GNUNET_free (head); + } + + /* Close associated tunnel */ + if (NULL != socket->tunnel) + { + GNUNET_MESH_tunnel_destroy (socket->tunnel); + socket->tunnel = NULL; + } + + /* Close mesh connection */ + if (NULL != socket->mesh) + { + GNUNET_MESH_disconnect (socket->mesh); + socket->mesh = NULL; + } + + /* Release receive buffer */ + if (NULL != socket->receive_buffer) + { + GNUNET_free (socket->receive_buffer); + } + + GNUNET_free (socket); +} + + +/** + * Method called whenever a peer creates a tunnel to us + * + * @param cls closure + * @param tunnel new handle to the tunnel + * @param initiator peer that started the tunnel + * @param atsi performance information for the tunnel + * @return initial tunnel context for the tunnel + * (can be NULL -- that's not an error) + */ +static void * +new_tunnel_notify (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *initiator, + const struct GNUNET_ATS_Information *atsi) +{ + struct GNUNET_STREAM_ListenSocket *lsocket = cls; + struct GNUNET_STREAM_Socket *socket; + + socket = GNUNET_malloc (sizeof (struct GNUNET_STREAM_Socket)); + socket->tunnel = tunnel; + socket->session_id = 0; /* FIXME */ + socket->other_peer = *initiator; + socket->state = STATE_INIT; + + if (GNUNET_SYSERR == lsocket->listen_cb (lsocket->listen_cb_cls, + socket, + &socket->other_peer)) + { + socket->state = STATE_CLOSED; + /* FIXME: Send CLOSE message and then free */ + GNUNET_free (socket); + GNUNET_MESH_tunnel_destroy (tunnel); /* Destroy the tunnel */ + } + return socket; +} + + +/** + * Function called whenever an inbound tunnel is destroyed. Should clean up + * any associated state. This function is NOT called if the client has + * explicitly asked for the tunnel to be destroyed using + * GNUNET_MESH_tunnel_destroy. It must NOT call GNUNET_MESH_tunnel_destroy on + * the tunnel. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end (henceforth invalid) + * @param tunnel_ctx place where local state associated + * with the tunnel is stored + */ +static void +tunnel_cleaner (void *cls, + const struct GNUNET_MESH_Tunnel *tunnel, + void *tunnel_ctx) +{ + struct GNUNET_STREAM_Socket *socket = tunnel_ctx; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %s has terminated connection abruptly\n", + GNUNET_i2s (&socket->other_peer)); + + socket->status = GNUNET_STREAM_SHUTDOWN; + /* Clear Transmit handles */ + if (NULL != socket->transmit_handle) + { + GNUNET_MESH_notify_transmit_ready_cancel (socket->transmit_handle); + socket->transmit_handle = NULL; + } + socket->tunnel = NULL; +} + + +/** + * Listens for stream connections for a specific application ports + * + * @param cfg the configuration to use + * @param app_port the application port for which new streams will be accepted + * @param listen_cb this function will be called when a peer tries to establish + * a stream with us + * @param listen_cb_cls closure for listen_cb + * @return listen socket, NULL for any error + */ +struct GNUNET_STREAM_ListenSocket * +GNUNET_STREAM_listen (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_MESH_ApplicationType app_port, + GNUNET_STREAM_ListenCallback listen_cb, + void *listen_cb_cls) +{ + /* FIXME: Add variable args for passing configration options? */ + struct GNUNET_STREAM_ListenSocket *lsocket; + GNUNET_MESH_ApplicationType app_types[2]; + + app_types[0] = app_port; + app_types[1] = 0; + lsocket = GNUNET_malloc (sizeof (struct GNUNET_STREAM_ListenSocket)); + lsocket->port = app_port; + lsocket->listen_cb = listen_cb; + lsocket->listen_cb_cls = listen_cb_cls; + lsocket->mesh = GNUNET_MESH_connect (cfg, + 10, /* FIXME: QUEUE size as parameter? */ + lsocket, /* Closure */ + &new_tunnel_notify, + &tunnel_cleaner, + server_message_handlers, + app_types); + return lsocket; +} + + +/** + * Closes the listen socket + * + * @param lsocket the listen socket + */ +void +GNUNET_STREAM_listen_close (struct GNUNET_STREAM_ListenSocket *lsocket) +{ + /* Close MESH connection */ + GNUNET_MESH_disconnect (lsocket->mesh); + + GNUNET_free (lsocket); +} + + +/** + * Tries to write the given data to the stream + * + * @param socket the socket representing a stream + * @param data the data buffer from where the data is written into the stream + * @param size the number of bytes to be written from the data buffer + * @param timeout the timeout period + * @param write_cont the function to call upon writing some bytes into the stream + * @param write_cont_cls the closure + * @return handle to cancel the operation + */ +struct GNUNET_STREAM_IOWriteHandle * +GNUNET_STREAM_write (struct GNUNET_STREAM_Socket *socket, + const void *data, + size_t size, + struct GNUNET_TIME_Relative timeout, + GNUNET_STREAM_CompletionContinuation write_cont, + void *write_cont_cls) +{ + unsigned int num_needed_packets; + unsigned int packet; + struct GNUNET_STREAM_IOWriteHandle *io_handle; + uint32_t packet_size; + uint32_t payload_size; + struct GNUNET_STREAM_DataMessage *data_msg; + const void *sweep; + + /* Return NULL if there is already a write request pending */ + if (NULL != socket->write_handle) + { + GNUNET_break (0); + return NULL; + } + if (!((STATE_ESTABLISHED == socket->state) + || (STATE_RECEIVE_CLOSE_WAIT == socket->state) + || (STATE_RECEIVE_CLOSED == socket->state))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Attempting to write on a closed (OR) not-yet-established" + "stream\n"); + return NULL; + } + if (GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH * max_payload_size < size) + size = GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH * max_payload_size; + num_needed_packets = (size + (max_payload_size - 1)) / max_payload_size; + io_handle = GNUNET_malloc (sizeof (struct GNUNET_STREAM_IOWriteHandle)); + sweep = data; + /* Divide the given buffer into packets for sending */ + for (packet=0; packet < num_needed_packets; packet++) + { + if ((packet + 1) * max_payload_size < size) + { + payload_size = max_payload_size; + packet_size = MAX_PACKET_SIZE; + } + else + { + payload_size = size - packet * max_payload_size; + packet_size = payload_size + sizeof (struct + GNUNET_STREAM_DataMessage); + } + io_handle->messages[packet] = GNUNET_malloc (packet_size); + io_handle->messages[packet]->header.header.size = htons (packet_size); + io_handle->messages[packet]->header.header.type = + htons (GNUNET_MESSAGE_TYPE_STREAM_DATA); + io_handle->messages[packet]->sequence_number = + htons (socket->write_sequence_number++); + io_handle->messages[packet]->offset = htons (socket->write_offset); + + /* FIXME: Remove the fixed delay for ack deadline; Set it to the value + determined from RTT */ + io_handle->messages[packet]->ack_deadline = + GNUNET_TIME_relative_hton (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5)); + data_msg = io_handle->messages[packet]; + /* Copy data from given buffer to the packet */ + memcpy (&data_msg[1], + sweep, + payload_size); + sweep += payload_size; + socket->write_offset += payload_size; + } + socket->write_handle = io_handle; + write_data (socket); + + return io_handle; +} + + +/** + * Tries to read data from the stream + * + * @param socket the socket representing a stream + * @param timeout the timeout period + * @param proc function to call with data (once only) + * @param proc_cls the closure for proc + * @return handle to cancel the operation + */ +struct GNUNET_STREAM_IOReadHandle * +GNUNET_STREAM_read (struct GNUNET_STREAM_Socket *socket, + struct GNUNET_TIME_Relative timeout, + GNUNET_STREAM_DataProcessor proc, + void *proc_cls) +{ + struct GNUNET_STREAM_IOReadHandle *read_handle; + + /* Return NULL if there is already a read handle; the user has to cancel that + first before continuing or has to wait until it is completed */ + if (NULL != socket->read_handle) return NULL; + + read_handle = GNUNET_malloc (sizeof (struct GNUNET_STREAM_IOReadHandle)); + read_handle->proc = proc; + socket->read_handle = read_handle; + + /* Check if we have a packet at bitmap 0 */ + if (GNUNET_YES == ackbitmap_is_bit_set (&socket->ack_bitmap, + 0)) + { + socket->read_task = GNUNET_SCHEDULER_add_now (&call_read_processor, + socket); + + } + + /* Setup the read timeout task */ + socket->read_io_timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, + &read_io_timeout, + socket); + return read_handle; +} diff --git a/src/stream/stream_protocol.h b/src/stream/stream_protocol.h new file mode 100644 index 0000000..0c1987e --- /dev/null +++ b/src/stream/stream_protocol.h @@ -0,0 +1,197 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file stream/stream_protocol.h + * @brief P2P protocol for the stream connections + * @author Sree Harsha Totakura + */ + +#ifndef STREAM_PROTOCOL_H +#define STREAM_PROTOCOL_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_util_lib.h" + +GNUNET_NETWORK_STRUCT_BEGIN + + +/** + * The stream message header + * All messages of STREAM should commonly have this as header + */ +struct GNUNET_STREAM_MessageHeader +{ + /** + * The GNUNET message header, types are from GNUNET_MESSAGE_TYPE_STREAM_*-range. + */ + struct GNUNET_MessageHeader header; + + /** + * A number which identifies a session between the two peers. FIXME: not needed + */ + uint32_t session_id GNUNET_PACKED; + +}; + + +/** + * The Data message, should be prefixed with stream header with its type set to + * GNUNET_STREAM_Data + */ +struct GNUNET_STREAM_DataMessage +{ + + /** + * Type is GNUNET_MESSAGE_TYPE_STREAM_DATA + */ + struct GNUNET_STREAM_MessageHeader header; + + /** + * Sequence number; starts with a random value. (Just in case + * someone breaks mesh and is able to try to do a Sequence + * Prediction Attack on us.) + */ + uint32_t sequence_number GNUNET_PACKED; + + /** + * number of milliseconds to the soft deadline for sending acknowledgement + * measured from the time this message is received. It is optimal for the + * communication to send the ack within the soft deadline + */ + struct GNUNET_TIME_RelativeNBO ack_deadline; + + /** + * Offset of the packet in the overall stream, modulo 2^32; allows + * the receiver to calculate where in the destination buffer the + * message should be placed. In network byte order. + */ + uint32_t offset GNUNET_PACKED; + + /** + * The data should be appended here + */ +}; + + +/** + * Number of bits in GNUNET_STREAM_AckBitmap + */ +#define GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH 64 + +/** + * The Selective Acknowledgement Bitmap + */ +typedef uint64_t GNUNET_STREAM_AckBitmap; + + +/** + * The Acknowledgment Message to confirm receipt of DATA. + */ +struct GNUNET_STREAM_AckMessage +{ + + /** + * Type is GNUNET_MESSAGE_TYPE_STREAM_ACK + */ + struct GNUNET_STREAM_MessageHeader header; + + /** + * The Selective Acknowledgement Bitmap. Computed relative to the base_seq + * (bit n corresponds to the Data message with sequence number base_seq+n) + */ + GNUNET_STREAM_AckBitmap bitmap GNUNET_PACKED; + + /** + * The sequence number of the Data Message upto which the receiver has filled + * its buffer without any missing packets + * + * FIXME: Do we need this? + */ + uint32_t base_sequence_number GNUNET_PACKED; + + /** + * Available buffer space past the last acknowledged buffer (for flow control), + * in bytes. + */ + uint32_t receive_window_remaining GNUNET_PACKED; +}; + + +/** + * Message for Acknowledging HELLO + */ +struct GNUNET_STREAM_HelloAckMessage +{ + /** + * The stream message header + */ + struct GNUNET_STREAM_MessageHeader header; + + /** + * The selected sequence number. Following data tranmissions from the sender + * start with this sequence + */ + uint32_t sequence_number; + + /** + * The size(in bytes) of the receive window on the peer sending this message + * + * FIXME: Remove if not needed + */ + uint32_t receive_window_size; +}; + + +/** + * The Transmit close message(used to signal transmission is closed) + */ +struct GNUNET_STREAM_TransmitCloseMessage +{ + /** + * The stream message header + */ + struct GNUNET_STREAM_MessageHeader header; + + /** + * The last sequence number of the packet after which the transmission has + * ended + */ + uint32_t final_sequence_number GNUNET_PACKED; +}; + +GNUNET_NETWORK_STRUCT_END + + +#if 0 /** keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif /* STREAM_PROTOCOL_H */ diff --git a/src/stream/test_stream_local.c b/src/stream/test_stream_local.c new file mode 100644 index 0000000..4da1258 --- /dev/null +++ b/src/stream/test_stream_local.c @@ -0,0 +1,386 @@ +/* + This file is part of GNUnet. + (C) 2011, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file stream/test_stream_local.c + * @brief Stream API testing between local peers + * @author Sree Harsha Totakura + */ + +#include + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_mesh_service.h" +#include "gnunet_stream_lib.h" + +#define VERBOSE 1 + +/** + * Structure for holding peer's sockets and IO Handles + */ +struct PeerData +{ + /** + * Peer's stream socket + */ + struct GNUNET_STREAM_Socket *socket; + + /** + * Peer's io handle + */ + struct GNUNET_STREAM_IOHandle *io_handle; + + /** + * Bytes the peer has written + */ + unsigned int bytes_wrote; + + /** + * Byte the peer has read + */ + unsigned int bytes_read; +}; + +static struct GNUNET_OS_Process *arm_pid; +static struct PeerData peer1; +static struct PeerData peer2; +static struct GNUNET_STREAM_ListenSocket *peer2_listen_socket; + +static GNUNET_SCHEDULER_TaskIdentifier abort_task; +static GNUNET_SCHEDULER_TaskIdentifier test_task; +static GNUNET_SCHEDULER_TaskIdentifier read_task; + +static char *data = "ABCD"; +static int result; + +/** + * Shutdown nicely + */ +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_STREAM_close (peer1.socket); + GNUNET_STREAM_close (peer2.socket); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n"); + if (0 != abort_task) + { + GNUNET_SCHEDULER_cancel (abort_task); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: arm\n"); + if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n"); + GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (arm_pid)); + GNUNET_OS_process_close (arm_pid); +} + + +/** + * Something went wrong and timed out. Kill everything and set error flag + */ +static void +do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n"); + if (0 != test_task) + { + GNUNET_SCHEDULER_cancel (test_task); + } + if (0 != read_task) + { + GNUNET_SCHEDULER_cancel (read_task); + } + result = GNUNET_SYSERR; + abort_task = 0; + do_shutdown (cls, tc); +} + + +/** + * The write completion function; called upon writing some data to stream or + * upon error + * + * @param cls the closure from GNUNET_STREAM_write/read + * @param status the status of the stream at the time this function is called + * @param size the number of bytes read or written + */ +static void +write_completion (void *cls, + enum GNUNET_STREAM_Status status, + size_t size) +{ + struct PeerData *peer; + + peer = (struct PeerData *) cls; + GNUNET_assert (GNUNET_STREAM_OK == status); + GNUNET_assert (size < strlen (data)); + peer->bytes_wrote += size; + + if (peer->bytes_wrote < strlen(data)) /* Have more data to send */ + { + peer->io_handle = GNUNET_STREAM_write (peer->socket, + (void *) data, + strlen(data) - peer->bytes_wrote, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + &write_completion, + cls); + GNUNET_assert (NULL != peer->io_handle); + } + else + { + if (&peer1 == peer) /* Peer1 has finished writing; should read now */ + { + peer->io_handle = GNUNET_STREAM_read ((struct GNUNET_STREAM_Socket *) + peer->socket, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + &input_processor, + cls); + GNUNET_assert (NULL!=peer->io_handle); + } + } +} + + +/** + * Function executed after stream has been established + * + * @param cls the closure from GNUNET_STREAM_open + * @param socket socket to use to communicate with the other side (read/write) + */ +static void +stream_open_cb (void *cls, + struct GNUNET_STREAM_Socket *socket) +{ + struct PeerData *peer; + + peer = (struct PeerData *) cls; + peer->bytes_wrote = 0; + GNUNET_assert (socket == peer1.socket); + GNUNET_assert (socket == peer->socket); + peer->io_handle = GNUNET_STREAM_write (peer->socket, /* socket */ + (void *) data, /* data */ + strlen(data), + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + &write_completion, + cls); + GNUNET_assert (NULL != peer->io_handle); +} + + +/** + * Input processor + * + * @param cls the closure from GNUNET_STREAM_write/read + * @param status the status of the stream at the time this function is called + * @param data traffic from the other side + * @param size the number of bytes available in data read + * @return number of bytes of processed from 'data' (any data remaining should be + * given to the next time the read processor is called). + */ +static size_t +input_processor (void *cls, + enum GNUNET_STREAM_Status status, + const void *input_data, + size_t size) +{ + struct PeerData *peer; + + peer = (struct PeerData *) cls; + + GNUNET_assert (GNUNET_STERAM_OK == status); + GNUNET_assert (size < strlen (data)); + GNUNET_assert (strncmp ((const char *) data + peer->bytes_read, + (const char *) input_data, + size)); + peer->bytes_read += size; + + if (peer->bytes_read < strlen (data)) + { + peer->io_handle = GNUNET_STREAM_read ((struct GNUNET_STREAM_Socket *) + peer->socket, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + &input_processor, + cls); + GNUNET_assert (NULL != peer->io_handle); + } + else + { + if (&peer2 == peer) /* Peer2 has completed reading; should write */ + { + peer->bytes_wrote = 0; + peer->io_handle = GNUNET_STREAM_write ((struct GNUNET_STREAM_Socket *) + peer->socket, + (void *) data, + strlen(data), + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + &write_completion, + cls); + } + else /* Peer1 has completed reading. End of tests */ + { + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + } + } + return size; +} + + +/** + * Scheduler call back; to be executed when a new stream is connected + * Called from listen connect for peer2 + */ +static void +stream_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + read_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (NULL != cls); + peer2.bytes_read = 0; + GNUNET_STREAM_listen_close (peer2_listen_socket); /* Close listen socket */ + peer2.io_handle = GNUNET_STREAM_read ((struct GNUNET_STREAM_Socket *) cls, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), + &input_processor, + (void *) &peer2); + GNUNET_assert (NULL != peer2.io_handle); +} + + +/** + * Functions of this type are called upon new stream connection from other peers + * + * @param cls the closure from GNUNET_STREAM_listen + * @param socket the socket representing the stream + * @param initiator the identity of the peer who wants to establish a stream + * with us + * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the + * stream (the socket will be invalid after the call) + */ +static int +stream_listen_cb (void *cls, + struct GNUNET_STREAM_Socket *socket, + const struct GNUNET_PeerIdentity *initiator) +{ + GNUNET_assert (NULL != socket); + GNUNET_assert (NULL == initiator); /* Local peer=NULL? */ + GNUNET_assert (socket != peer1.socket); + + peer2.socket = socket; + read_task = GNUNET_SCHEDULER_add_now (&stream_read, (void *) socket); + return GNUNET_OK; +} + + +/** + * Testing function + */ +static void +test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + test_task = GNUNET_SCHEDULER_NO_TASK; + + /* Connect to stream library */ + peer1.socket = GNUNET_STREAM_open (NULL, /* Null for local peer? */ + 10, /* App port */ + &stream_open_cb, + (void *) &peer1); + GNUNET_assert (NULL != peer1.socket); + peer2_listen_socket = GNUNET_STREAM_listen (10 /* App port */ + &stream_listen_cb, + NULL); + GNUNET_assert (NULL != peer2_listen_socket); + +} + +/** + * Initialize framework and start test + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_log_setup ("test_stream_local", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + arm_pid = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE_ARM + "-L", "DEBUG", +#endif + "-c", "test_stream_local.conf", NULL); + + abort_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort, + NULL); + + test_task = GNUNET_SCHEDULER_add_now (&test, (void *) cfg); + +} + +/** + * Main function + */ +int main (int argc, char **argv) +{ + int ret; + + char *const argv2[] = { "test-stream-local", + "-c", "test_stream.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + ret = + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test-stream-local", "nohelp", options, &run, NULL); + + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", + ret); + return 1; + } + if (GNUNET_SYSERR == result) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); + return 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test ok\n"); + return 0; +} diff --git a/src/stream/test_stream_local.conf b/src/stream/test_stream_local.conf new file mode 100644 index 0000000..3d955f0 --- /dev/null +++ b/src/stream/test_stream_local.conf @@ -0,0 +1,69 @@ +[fs] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO + +[mesh] +DEBUG = YES +AUTOSTART = YES +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 10511 +# PREFIX = valgrind --leak-check=full +# PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 2100 + +[block] +plugins = dht test + +[dhtcache] +QUOTA = 1 MB +DATABASE = sqlite + +[transport] +PLUGINS = tcp +DEBUG = NO +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +NEIGHBOUR_LIMIT = 50 +PORT = 12365 + +[ats] +WAN_QUOTA_OUT = 3932160 +WAN_QUOTA_IN = 3932160 + +[core] +PORT = 12092 + +[arm] +DEFAULTSERVICES = core +PORT = 12366 +DEBUG = NO + +[transport-tcp] +TIMEOUT = 300 s +PORT = 12368 + +[TESTING] +WEAKRANDOM = YES + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[PATHS] +DEFAULTCONFIG = test_mesh.conf +SERVICEHOME = /tmp/test-mesh/ + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO diff --git a/src/template/Makefile.am b/src/template/Makefile.am new file mode 100644 index 0000000..1769191 --- /dev/null +++ b/src/template/Makefile.am @@ -0,0 +1,44 @@ +INCLUDES = -I$(top_srcdir)/src/include + +pkgcfgdir= $(pkgdatadir)/config.d/ + +dist_pkgcfg_DATA = \ + template.conf + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + +bin_PROGRAMS = \ + gnunet-template \ + gnunet-service-template + +gnunet_template_SOURCES = \ + gnunet-template.c +gnunet_template_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_service_template_SOURCES = \ + gnunet-service-template.c +gnunet_service_template_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + + +check_PROGRAMS = \ + test_template_api + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_template_api_SOURCES = \ + test_template_api.c +test_template_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + diff --git a/src/template/Makefile.in b/src/template/Makefile.in new file mode 100644 index 0000000..de11cdc --- /dev/null +++ b/src/template/Makefile.in @@ -0,0 +1,831 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-template$(EXEEXT) \ + gnunet-service-template$(EXEEXT) +check_PROGRAMS = test_template_api$(EXEEXT) +subdir = src/template +DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_service_template_OBJECTS = \ + gnunet-service-template.$(OBJEXT) +gnunet_service_template_OBJECTS = \ + $(am_gnunet_service_template_OBJECTS) +am__DEPENDENCIES_1 = +gnunet_service_template_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am_gnunet_template_OBJECTS = gnunet-template.$(OBJEXT) +gnunet_template_OBJECTS = $(am_gnunet_template_OBJECTS) +gnunet_template_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_test_template_api_OBJECTS = test_template_api.$(OBJEXT) +test_template_api_OBJECTS = $(am_test_template_api_OBJECTS) +test_template_api_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(gnunet_service_template_SOURCES) \ + $(gnunet_template_SOURCES) $(test_template_api_SOURCES) +DIST_SOURCES = $(gnunet_service_template_SOURCES) \ + $(gnunet_template_SOURCES) $(test_template_api_SOURCES) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +DATA = $(dist_pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +pkgcfgdir = $(pkgdatadir)/config.d/ +dist_pkgcfg_DATA = \ + template.conf + +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage +gnunet_template_SOURCES = \ + gnunet-template.c + +gnunet_template_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_service_template_SOURCES = \ + gnunet-service-template.c + +gnunet_service_template_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_template_api_SOURCES = \ + test_template_api.c + +test_template_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/template/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/template/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-service-template$(EXEEXT): $(gnunet_service_template_OBJECTS) $(gnunet_service_template_DEPENDENCIES) + @rm -f gnunet-service-template$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_template_OBJECTS) $(gnunet_service_template_LDADD) $(LIBS) +gnunet-template$(EXEEXT): $(gnunet_template_OBJECTS) $(gnunet_template_DEPENDENCIES) + @rm -f gnunet-template$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_template_OBJECTS) $(gnunet_template_LDADD) $(LIBS) +test_template_api$(EXEEXT): $(test_template_api_OBJECTS) $(test_template_api_DEPENDENCIES) + @rm -f test_template_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_template_api_OBJECTS) $(test_template_api_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-template.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-template.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_template_api.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-dist_pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am \ + install-dist_pkgcfgDATA install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-dist_pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/template/gnunet-service-template.c b/src/template/gnunet-service-template.c new file mode 100644 index 0000000..54b7ecc --- /dev/null +++ b/src/template/gnunet-service-template.c @@ -0,0 +1,81 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file template/gnunet-service-template.c + * @brief program that tracks template + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_service_lib.h" + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + /* FIXME: do clean up here */ +} + + +/** + * Process template requests. + * + * @param cls closure + * @param server the initialized server + * @param cfg configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + /* FIXME: add handlers here! */ + {NULL, NULL, 0, 0} + }; + /* FIXME: do setup here */ + GNUNET_SERVER_add_handlers (server, handlers); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, + NULL); +} + + +/** + * The main function for the template service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "template", + GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-service-template.c */ diff --git a/src/template/gnunet-template.c b/src/template/gnunet-template.c new file mode 100644 index 0000000..7b1d9df --- /dev/null +++ b/src/template/gnunet-template.c @@ -0,0 +1,72 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file template/gnunet-template.c + * @brief template for writing a tool + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_program_lib.h" +/* #include "gnunet_template_service.h" */ + +/** + * Final status code. + */ +static int ret; + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + /* main code here */ +} + + +/** + * The main function. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + /* FIMXE: add options here */ + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-template", + gettext_noop ("help text"), options, &run, + NULL)) ? ret : 1; +} + +/* end of gnunet-template.c */ diff --git a/src/template/template.conf b/src/template/template.conf new file mode 100644 index 0000000..522721f --- /dev/null +++ b/src/template/template.conf @@ -0,0 +1,21 @@ +[template] +AUTOSTART = NO +PORT = 9999 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-template +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-template.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +# DISABLE_SOCKET_FORWARDING = NO +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = diff --git a/src/template/test_template_api.c b/src/template/test_template_api.c new file mode 100644 index 0000000..b987851 --- /dev/null +++ b/src/template/test_template_api.c @@ -0,0 +1,45 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file template/test_template.c + * @brief testcase for template.c + */ +#include "platform.h" +#include "gnunet_common.h" + +#define VERBOSE GNUNET_NO + +static int +check () +{ + return 0; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + ret = check (); + + return ret; +} + +/* end of test_template.c */ diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am new file mode 100644 index 0000000..050691d --- /dev/null +++ b/src/testing/Makefile.am @@ -0,0 +1,279 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +dist_pkgcfg_DATA = \ + testing.conf + +if HAVE_EXPENSIVE_TESTS + EXPENSIVE_TESTS = \ + test_testing_topology_stability \ + test_testing_topology_clique_random \ + test_testing_topology_clique_minimum \ + test_testing_topology_clique_dfs \ + test_testing_topology_churn \ + test_testing_topology_line + test_testing_topology_blacklist \ + test_testing_group_remote \ + test_testing_topology_ring \ + test_testing_topology_2d_torus \ + test_testing_topology_small_world_ring \ + test_testing_topology_small_world_torus \ + test_testing_topology_erdos_renyi \ + test_testing_topology_internat \ + test_testing_topology_scale_free +endif + +lib_LTLIBRARIES = libgnunettesting.la + +libgnunettesting_la_SOURCES = \ + helper.c \ + testing.c \ + testing_group.c \ + testing_peergroup.c +libgnunettesting_la_LIBADD = $(XLIB) \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + -lm \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunettesting_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:1:0 + +bin_PROGRAMS = \ + gnunet-testing + +check_PROGRAMS = \ + test_testing \ + test_testing_connect \ + test_testing_reconnect \ + test_testing_group \ + test_testing_peergroup \ + test_testing_topology_stability \ + test_testing_topology_clique \ + test_testing_topology_clique_random \ + test_testing_topology_clique_minimum \ + test_testing_topology_clique_dfs \ + test_testing_topology_churn \ + test_testing_topology_line \ + test_testing_topology_blacklist \ + test_testing_group_remote \ + test_testing_2dtorus \ + test_testing_topology_ring \ + test_testing_topology_2d_torus \ + test_testing_topology_small_world_ring \ + test_testing_topology_small_world_torus \ + test_testing_topology_erdos_renyi \ + test_testing_topology_internat \ + test_testing_topology_none \ + test_testing_topology_scale_free + +if ENABLE_TEST_RUN +TESTS = \ + test_testing \ + test_testing_connect \ + test_testing_reconnect \ + test_testing_group \ + test_testing_peergroup \ + test_testing_topology_clique \ + test_testing_2dtorus +endif + +gnunet_testing_SOURCES = \ + gnunet-testing.c +gnunet_testing_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_testing_DEPENDENCIES = \ + libgnunettesting.la + + +test_testing_SOURCES = \ + test_testing.c +test_testing_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_connect_SOURCES = \ + test_testing_connect.c +test_testing_connect_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_reconnect_SOURCES = \ + test_testing_reconnect.c +test_testing_reconnect_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_group_SOURCES = \ + test_testing_group.c +test_testing_group_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_peergroup_SOURCES = \ + test_testing_peergroup.c +test_testing_peergroup_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_SOURCES = \ + test_testing_topology.c +test_testing_topology_clique_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_stability_SOURCES = \ + test_testing_topology.c +test_testing_topology_stability_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_blacklist_SOURCES = \ + test_testing_topology_blacklist.c +test_testing_topology_blacklist_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_churn_SOURCES = \ + test_testing_topology_churn.c +test_testing_topology_churn_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_random_SOURCES = \ + test_testing_topology.c +test_testing_topology_clique_random_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_minimum_SOURCES = \ + test_testing_topology.c +test_testing_topology_clique_minimum_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_dfs_SOURCES = \ + test_testing_topology.c +test_testing_topology_clique_dfs_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_line_SOURCES = \ + test_testing_topology.c +test_testing_topology_line_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + + +test_testing_group_remote_SOURCES = \ + test_testing_group_remote.c +test_testing_group_remote_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_2dtorus_SOURCES = \ + test_testing_2dtorus.c +test_testing_2dtorus_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_ring_SOURCES = \ + test_testing_topology.c +test_testing_topology_ring_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_2d_torus_SOURCES = \ + test_testing_topology.c +test_testing_topology_2d_torus_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_small_world_ring_SOURCES = \ + test_testing_topology.c +test_testing_topology_small_world_ring_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_small_world_torus_SOURCES = \ + test_testing_topology.c +test_testing_topology_small_world_torus_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_internat_SOURCES = \ + test_testing_topology.c +test_testing_topology_internat_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_erdos_renyi_SOURCES = \ + test_testing_topology.c +test_testing_topology_erdos_renyi_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_scale_free_SOURCES = \ + test_testing_topology.c +test_testing_topology_scale_free_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_none_SOURCES = \ + test_testing_topology.c +test_testing_topology_none_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + + +EXTRA_DIST = \ + test_testing_defaults.conf \ + test_testing_data.conf \ + test_testing_connect_peer1.conf \ + test_testing_connect_peer2.conf \ + test_testing_2dtorus.conf \ + test_testing_data_topology_clique.conf \ + test_testing_data_topology_clique_random.conf \ + test_testing_data_topology_clique_minimum.conf \ + test_testing_data_topology_clique_dfs.conf \ + test_testing_data_topology_ring.conf \ + test_testing_data_topology_2d_torus.conf \ + test_testing_data_topology_small_world_ring.conf \ + test_testing_data_topology_small_world_torus.conf \ + test_testing_data_topology_erdos_renyi.conf \ + test_testing_data_topology_internat.conf \ + test_testing_data_topology_scale_free.conf \ + test_testing_data_topology_blacklist.conf \ + test_testing_data_topology_churn.conf \ + test_testing_data_topology_none.conf \ + test_testing_data_remote.conf \ + test_testing_data_topology_stability.conf \ + test_testing_peergroup_data.conf diff --git a/src/testing/Makefile.in b/src/testing/Makefile.in new file mode 100644 index 0000000..544d98d --- /dev/null +++ b/src/testing/Makefile.in @@ -0,0 +1,1401 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-testing$(EXEEXT) +check_PROGRAMS = test_testing$(EXEEXT) test_testing_connect$(EXEEXT) \ + test_testing_reconnect$(EXEEXT) test_testing_group$(EXEEXT) \ + test_testing_peergroup$(EXEEXT) \ + test_testing_topology_stability$(EXEEXT) \ + test_testing_topology_clique$(EXEEXT) \ + test_testing_topology_clique_random$(EXEEXT) \ + test_testing_topology_clique_minimum$(EXEEXT) \ + test_testing_topology_clique_dfs$(EXEEXT) \ + test_testing_topology_churn$(EXEEXT) \ + test_testing_topology_line$(EXEEXT) \ + test_testing_topology_blacklist$(EXEEXT) \ + test_testing_group_remote$(EXEEXT) \ + test_testing_2dtorus$(EXEEXT) \ + test_testing_topology_ring$(EXEEXT) \ + test_testing_topology_2d_torus$(EXEEXT) \ + test_testing_topology_small_world_ring$(EXEEXT) \ + test_testing_topology_small_world_torus$(EXEEXT) \ + test_testing_topology_erdos_renyi$(EXEEXT) \ + test_testing_topology_internat$(EXEEXT) \ + test_testing_topology_none$(EXEEXT) \ + test_testing_topology_scale_free$(EXEEXT) +@ENABLE_TEST_RUN_TRUE@TESTS = test_testing$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_testing_connect$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_testing_reconnect$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_testing_group$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_testing_peergroup$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_testing_topology_clique$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_testing_2dtorus$(EXEEXT) +subdir = src/testing +DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunettesting_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunettesting_la_OBJECTS = helper.lo testing.lo testing_group.lo \ + testing_peergroup.lo +libgnunettesting_la_OBJECTS = $(am_libgnunettesting_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunettesting_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunettesting_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_testing_OBJECTS = gnunet-testing.$(OBJEXT) +gnunet_testing_OBJECTS = $(am_gnunet_testing_OBJECTS) +am_test_testing_OBJECTS = test_testing.$(OBJEXT) +test_testing_OBJECTS = $(am_test_testing_OBJECTS) +test_testing_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_2dtorus_OBJECTS = test_testing_2dtorus.$(OBJEXT) +test_testing_2dtorus_OBJECTS = $(am_test_testing_2dtorus_OBJECTS) +test_testing_2dtorus_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_connect_OBJECTS = test_testing_connect.$(OBJEXT) +test_testing_connect_OBJECTS = $(am_test_testing_connect_OBJECTS) +test_testing_connect_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_group_OBJECTS = test_testing_group.$(OBJEXT) +test_testing_group_OBJECTS = $(am_test_testing_group_OBJECTS) +test_testing_group_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_group_remote_OBJECTS = \ + test_testing_group_remote.$(OBJEXT) +test_testing_group_remote_OBJECTS = \ + $(am_test_testing_group_remote_OBJECTS) +test_testing_group_remote_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_peergroup_OBJECTS = test_testing_peergroup.$(OBJEXT) +test_testing_peergroup_OBJECTS = $(am_test_testing_peergroup_OBJECTS) +test_testing_peergroup_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_reconnect_OBJECTS = test_testing_reconnect.$(OBJEXT) +test_testing_reconnect_OBJECTS = $(am_test_testing_reconnect_OBJECTS) +test_testing_reconnect_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_2d_torus_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_2d_torus_OBJECTS = \ + $(am_test_testing_topology_2d_torus_OBJECTS) +test_testing_topology_2d_torus_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_blacklist_OBJECTS = \ + test_testing_topology_blacklist.$(OBJEXT) +test_testing_topology_blacklist_OBJECTS = \ + $(am_test_testing_topology_blacklist_OBJECTS) +test_testing_topology_blacklist_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_churn_OBJECTS = \ + test_testing_topology_churn.$(OBJEXT) +test_testing_topology_churn_OBJECTS = \ + $(am_test_testing_topology_churn_OBJECTS) +test_testing_topology_churn_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_clique_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_clique_OBJECTS = \ + $(am_test_testing_topology_clique_OBJECTS) +test_testing_topology_clique_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_clique_dfs_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_clique_dfs_OBJECTS = \ + $(am_test_testing_topology_clique_dfs_OBJECTS) +test_testing_topology_clique_dfs_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_clique_minimum_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_clique_minimum_OBJECTS = \ + $(am_test_testing_topology_clique_minimum_OBJECTS) +test_testing_topology_clique_minimum_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_clique_random_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_clique_random_OBJECTS = \ + $(am_test_testing_topology_clique_random_OBJECTS) +test_testing_topology_clique_random_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_erdos_renyi_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_erdos_renyi_OBJECTS = \ + $(am_test_testing_topology_erdos_renyi_OBJECTS) +test_testing_topology_erdos_renyi_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_internat_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_internat_OBJECTS = \ + $(am_test_testing_topology_internat_OBJECTS) +test_testing_topology_internat_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_line_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_line_OBJECTS = \ + $(am_test_testing_topology_line_OBJECTS) +test_testing_topology_line_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_none_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_none_OBJECTS = \ + $(am_test_testing_topology_none_OBJECTS) +test_testing_topology_none_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_ring_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_ring_OBJECTS = \ + $(am_test_testing_topology_ring_OBJECTS) +test_testing_topology_ring_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_scale_free_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_scale_free_OBJECTS = \ + $(am_test_testing_topology_scale_free_OBJECTS) +test_testing_topology_scale_free_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_small_world_ring_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_small_world_ring_OBJECTS = \ + $(am_test_testing_topology_small_world_ring_OBJECTS) +test_testing_topology_small_world_ring_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_small_world_torus_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_small_world_torus_OBJECTS = \ + $(am_test_testing_topology_small_world_torus_OBJECTS) +test_testing_topology_small_world_torus_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_testing_topology_stability_OBJECTS = \ + test_testing_topology.$(OBJEXT) +test_testing_topology_stability_OBJECTS = \ + $(am_test_testing_topology_stability_OBJECTS) +test_testing_topology_stability_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunettesting_la_SOURCES) $(gnunet_testing_SOURCES) \ + $(test_testing_SOURCES) $(test_testing_2dtorus_SOURCES) \ + $(test_testing_connect_SOURCES) $(test_testing_group_SOURCES) \ + $(test_testing_group_remote_SOURCES) \ + $(test_testing_peergroup_SOURCES) \ + $(test_testing_reconnect_SOURCES) \ + $(test_testing_topology_2d_torus_SOURCES) \ + $(test_testing_topology_blacklist_SOURCES) \ + $(test_testing_topology_churn_SOURCES) \ + $(test_testing_topology_clique_SOURCES) \ + $(test_testing_topology_clique_dfs_SOURCES) \ + $(test_testing_topology_clique_minimum_SOURCES) \ + $(test_testing_topology_clique_random_SOURCES) \ + $(test_testing_topology_erdos_renyi_SOURCES) \ + $(test_testing_topology_internat_SOURCES) \ + $(test_testing_topology_line_SOURCES) \ + $(test_testing_topology_none_SOURCES) \ + $(test_testing_topology_ring_SOURCES) \ + $(test_testing_topology_scale_free_SOURCES) \ + $(test_testing_topology_small_world_ring_SOURCES) \ + $(test_testing_topology_small_world_torus_SOURCES) \ + $(test_testing_topology_stability_SOURCES) +DIST_SOURCES = $(libgnunettesting_la_SOURCES) \ + $(gnunet_testing_SOURCES) $(test_testing_SOURCES) \ + $(test_testing_2dtorus_SOURCES) \ + $(test_testing_connect_SOURCES) $(test_testing_group_SOURCES) \ + $(test_testing_group_remote_SOURCES) \ + $(test_testing_peergroup_SOURCES) \ + $(test_testing_reconnect_SOURCES) \ + $(test_testing_topology_2d_torus_SOURCES) \ + $(test_testing_topology_blacklist_SOURCES) \ + $(test_testing_topology_churn_SOURCES) \ + $(test_testing_topology_clique_SOURCES) \ + $(test_testing_topology_clique_dfs_SOURCES) \ + $(test_testing_topology_clique_minimum_SOURCES) \ + $(test_testing_topology_clique_random_SOURCES) \ + $(test_testing_topology_erdos_renyi_SOURCES) \ + $(test_testing_topology_internat_SOURCES) \ + $(test_testing_topology_line_SOURCES) \ + $(test_testing_topology_none_SOURCES) \ + $(test_testing_topology_ring_SOURCES) \ + $(test_testing_topology_scale_free_SOURCES) \ + $(test_testing_topology_small_world_ring_SOURCES) \ + $(test_testing_topology_small_world_torus_SOURCES) \ + $(test_testing_topology_stability_SOURCES) +DATA = $(dist_pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +pkgcfgdir = $(pkgdatadir)/config.d/ +dist_pkgcfg_DATA = \ + testing.conf + +@HAVE_EXPENSIVE_TESTS_TRUE@EXPENSIVE_TESTS = \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_stability \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_clique_random \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_clique_minimum \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_clique_dfs \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_churn \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_line + +lib_LTLIBRARIES = libgnunettesting.la +libgnunettesting_la_SOURCES = \ + helper.c \ + testing.c \ + testing_group.c \ + testing_peergroup.c + +libgnunettesting_la_LIBADD = $(XLIB) \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + -lm \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunettesting_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:1:0 + +gnunet_testing_SOURCES = \ + gnunet-testing.c + +gnunet_testing_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_testing_DEPENDENCIES = \ + libgnunettesting.la + +test_testing_SOURCES = \ + test_testing.c + +test_testing_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_connect_SOURCES = \ + test_testing_connect.c + +test_testing_connect_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_reconnect_SOURCES = \ + test_testing_reconnect.c + +test_testing_reconnect_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_group_SOURCES = \ + test_testing_group.c + +test_testing_group_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_peergroup_SOURCES = \ + test_testing_peergroup.c + +test_testing_peergroup_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_SOURCES = \ + test_testing_topology.c + +test_testing_topology_clique_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_stability_SOURCES = \ + test_testing_topology.c + +test_testing_topology_stability_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_blacklist_SOURCES = \ + test_testing_topology_blacklist.c + +test_testing_topology_blacklist_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_churn_SOURCES = \ + test_testing_topology_churn.c + +test_testing_topology_churn_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_random_SOURCES = \ + test_testing_topology.c + +test_testing_topology_clique_random_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_minimum_SOURCES = \ + test_testing_topology.c + +test_testing_topology_clique_minimum_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_dfs_SOURCES = \ + test_testing_topology.c + +test_testing_topology_clique_dfs_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_line_SOURCES = \ + test_testing_topology.c + +test_testing_topology_line_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_group_remote_SOURCES = \ + test_testing_group_remote.c + +test_testing_group_remote_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_2dtorus_SOURCES = \ + test_testing_2dtorus.c + +test_testing_2dtorus_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_ring_SOURCES = \ + test_testing_topology.c + +test_testing_topology_ring_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_2d_torus_SOURCES = \ + test_testing_topology.c + +test_testing_topology_2d_torus_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_small_world_ring_SOURCES = \ + test_testing_topology.c + +test_testing_topology_small_world_ring_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_small_world_torus_SOURCES = \ + test_testing_topology.c + +test_testing_topology_small_world_torus_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_internat_SOURCES = \ + test_testing_topology.c + +test_testing_topology_internat_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_erdos_renyi_SOURCES = \ + test_testing_topology.c + +test_testing_topology_erdos_renyi_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_scale_free_SOURCES = \ + test_testing_topology.c + +test_testing_topology_scale_free_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_none_SOURCES = \ + test_testing_topology.c + +test_testing_topology_none_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_testing_defaults.conf \ + test_testing_data.conf \ + test_testing_connect_peer1.conf \ + test_testing_connect_peer2.conf \ + test_testing_2dtorus.conf \ + test_testing_data_topology_clique.conf \ + test_testing_data_topology_clique_random.conf \ + test_testing_data_topology_clique_minimum.conf \ + test_testing_data_topology_clique_dfs.conf \ + test_testing_data_topology_ring.conf \ + test_testing_data_topology_2d_torus.conf \ + test_testing_data_topology_small_world_ring.conf \ + test_testing_data_topology_small_world_torus.conf \ + test_testing_data_topology_erdos_renyi.conf \ + test_testing_data_topology_internat.conf \ + test_testing_data_topology_scale_free.conf \ + test_testing_data_topology_blacklist.conf \ + test_testing_data_topology_churn.conf \ + test_testing_data_topology_none.conf \ + test_testing_data_remote.conf \ + test_testing_data_topology_stability.conf \ + test_testing_peergroup_data.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/testing/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/testing/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunettesting.la: $(libgnunettesting_la_OBJECTS) $(libgnunettesting_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunettesting_la_LINK) -rpath $(libdir) $(libgnunettesting_la_OBJECTS) $(libgnunettesting_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-testing$(EXEEXT): $(gnunet_testing_OBJECTS) $(gnunet_testing_DEPENDENCIES) + @rm -f gnunet-testing$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_testing_OBJECTS) $(gnunet_testing_LDADD) $(LIBS) +test_testing$(EXEEXT): $(test_testing_OBJECTS) $(test_testing_DEPENDENCIES) + @rm -f test_testing$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_OBJECTS) $(test_testing_LDADD) $(LIBS) +test_testing_2dtorus$(EXEEXT): $(test_testing_2dtorus_OBJECTS) $(test_testing_2dtorus_DEPENDENCIES) + @rm -f test_testing_2dtorus$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_2dtorus_OBJECTS) $(test_testing_2dtorus_LDADD) $(LIBS) +test_testing_connect$(EXEEXT): $(test_testing_connect_OBJECTS) $(test_testing_connect_DEPENDENCIES) + @rm -f test_testing_connect$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_connect_OBJECTS) $(test_testing_connect_LDADD) $(LIBS) +test_testing_group$(EXEEXT): $(test_testing_group_OBJECTS) $(test_testing_group_DEPENDENCIES) + @rm -f test_testing_group$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_group_OBJECTS) $(test_testing_group_LDADD) $(LIBS) +test_testing_group_remote$(EXEEXT): $(test_testing_group_remote_OBJECTS) $(test_testing_group_remote_DEPENDENCIES) + @rm -f test_testing_group_remote$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_group_remote_OBJECTS) $(test_testing_group_remote_LDADD) $(LIBS) +test_testing_peergroup$(EXEEXT): $(test_testing_peergroup_OBJECTS) $(test_testing_peergroup_DEPENDENCIES) + @rm -f test_testing_peergroup$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_peergroup_OBJECTS) $(test_testing_peergroup_LDADD) $(LIBS) +test_testing_reconnect$(EXEEXT): $(test_testing_reconnect_OBJECTS) $(test_testing_reconnect_DEPENDENCIES) + @rm -f test_testing_reconnect$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_reconnect_OBJECTS) $(test_testing_reconnect_LDADD) $(LIBS) +test_testing_topology_2d_torus$(EXEEXT): $(test_testing_topology_2d_torus_OBJECTS) $(test_testing_topology_2d_torus_DEPENDENCIES) + @rm -f test_testing_topology_2d_torus$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_2d_torus_OBJECTS) $(test_testing_topology_2d_torus_LDADD) $(LIBS) +test_testing_topology_blacklist$(EXEEXT): $(test_testing_topology_blacklist_OBJECTS) $(test_testing_topology_blacklist_DEPENDENCIES) + @rm -f test_testing_topology_blacklist$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_blacklist_OBJECTS) $(test_testing_topology_blacklist_LDADD) $(LIBS) +test_testing_topology_churn$(EXEEXT): $(test_testing_topology_churn_OBJECTS) $(test_testing_topology_churn_DEPENDENCIES) + @rm -f test_testing_topology_churn$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_churn_OBJECTS) $(test_testing_topology_churn_LDADD) $(LIBS) +test_testing_topology_clique$(EXEEXT): $(test_testing_topology_clique_OBJECTS) $(test_testing_topology_clique_DEPENDENCIES) + @rm -f test_testing_topology_clique$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_clique_OBJECTS) $(test_testing_topology_clique_LDADD) $(LIBS) +test_testing_topology_clique_dfs$(EXEEXT): $(test_testing_topology_clique_dfs_OBJECTS) $(test_testing_topology_clique_dfs_DEPENDENCIES) + @rm -f test_testing_topology_clique_dfs$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_clique_dfs_OBJECTS) $(test_testing_topology_clique_dfs_LDADD) $(LIBS) +test_testing_topology_clique_minimum$(EXEEXT): $(test_testing_topology_clique_minimum_OBJECTS) $(test_testing_topology_clique_minimum_DEPENDENCIES) + @rm -f test_testing_topology_clique_minimum$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_clique_minimum_OBJECTS) $(test_testing_topology_clique_minimum_LDADD) $(LIBS) +test_testing_topology_clique_random$(EXEEXT): $(test_testing_topology_clique_random_OBJECTS) $(test_testing_topology_clique_random_DEPENDENCIES) + @rm -f test_testing_topology_clique_random$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_clique_random_OBJECTS) $(test_testing_topology_clique_random_LDADD) $(LIBS) +test_testing_topology_erdos_renyi$(EXEEXT): $(test_testing_topology_erdos_renyi_OBJECTS) $(test_testing_topology_erdos_renyi_DEPENDENCIES) + @rm -f test_testing_topology_erdos_renyi$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_erdos_renyi_OBJECTS) $(test_testing_topology_erdos_renyi_LDADD) $(LIBS) +test_testing_topology_internat$(EXEEXT): $(test_testing_topology_internat_OBJECTS) $(test_testing_topology_internat_DEPENDENCIES) + @rm -f test_testing_topology_internat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_internat_OBJECTS) $(test_testing_topology_internat_LDADD) $(LIBS) +test_testing_topology_line$(EXEEXT): $(test_testing_topology_line_OBJECTS) $(test_testing_topology_line_DEPENDENCIES) + @rm -f test_testing_topology_line$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_line_OBJECTS) $(test_testing_topology_line_LDADD) $(LIBS) +test_testing_topology_none$(EXEEXT): $(test_testing_topology_none_OBJECTS) $(test_testing_topology_none_DEPENDENCIES) + @rm -f test_testing_topology_none$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_none_OBJECTS) $(test_testing_topology_none_LDADD) $(LIBS) +test_testing_topology_ring$(EXEEXT): $(test_testing_topology_ring_OBJECTS) $(test_testing_topology_ring_DEPENDENCIES) + @rm -f test_testing_topology_ring$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_ring_OBJECTS) $(test_testing_topology_ring_LDADD) $(LIBS) +test_testing_topology_scale_free$(EXEEXT): $(test_testing_topology_scale_free_OBJECTS) $(test_testing_topology_scale_free_DEPENDENCIES) + @rm -f test_testing_topology_scale_free$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_scale_free_OBJECTS) $(test_testing_topology_scale_free_LDADD) $(LIBS) +test_testing_topology_small_world_ring$(EXEEXT): $(test_testing_topology_small_world_ring_OBJECTS) $(test_testing_topology_small_world_ring_DEPENDENCIES) + @rm -f test_testing_topology_small_world_ring$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_small_world_ring_OBJECTS) $(test_testing_topology_small_world_ring_LDADD) $(LIBS) +test_testing_topology_small_world_torus$(EXEEXT): $(test_testing_topology_small_world_torus_OBJECTS) $(test_testing_topology_small_world_torus_DEPENDENCIES) + @rm -f test_testing_topology_small_world_torus$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_small_world_torus_OBJECTS) $(test_testing_topology_small_world_torus_LDADD) $(LIBS) +test_testing_topology_stability$(EXEEXT): $(test_testing_topology_stability_OBJECTS) $(test_testing_topology_stability_DEPENDENCIES) + @rm -f test_testing_topology_stability$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_testing_topology_stability_OBJECTS) $(test_testing_topology_stability_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-testing.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helper.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_2dtorus.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_connect.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_group.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_group_remote.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_peergroup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_reconnect.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_topology.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_topology_blacklist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_topology_churn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testing.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testing_group.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testing_peergroup.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-dist_pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA \ + uninstall-libLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dist_pkgcfgDATA install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-dist_pkgcfgDATA uninstall-libLTLIBRARIES + +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_blacklist \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_group_remote \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_ring \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_2d_torus \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_small_world_ring \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_small_world_torus \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_erdos_renyi \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_internat \ +@HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_scale_free + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/testing/gnunet-testing.c b/src/testing/gnunet-testing.c new file mode 100644 index 0000000..0caa28e --- /dev/null +++ b/src/testing/gnunet-testing.c @@ -0,0 +1,291 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file testing/gnunet-testing.c + * @brief tool to use testing functionality from cmd line + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_testing_lib.h" + +#define HOSTKEYFILESIZE 914 + +/** + * Final status code. + */ +static int ret; + +static unsigned int create_hostkey; + +static unsigned int create_cfg; + +static int create_no; + +static char * create_cfg_template; + +static char * create_hostkey_file; + +static int +create_unique_cfgs (const char * template, const unsigned int no) +{ + int fail = GNUNET_NO; + + uint16_t port = 20000; + uint32_t upnum = 1; + uint32_t fdnum = 1; + + if (GNUNET_NO == GNUNET_DISK_file_test(template)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Configuration template `%s': file not found\n", create_cfg_template); + return 1; + } + + int cur = 0; + char * cur_file; + char *service_home = NULL; + char *cur_service_home = NULL; + + struct GNUNET_CONFIGURATION_Handle *cfg_new = NULL; + struct GNUNET_CONFIGURATION_Handle *cfg_tmpl = GNUNET_CONFIGURATION_create(); + + /* load template */ + if ((create_cfg_template != NULL) && (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_tmpl, create_cfg_template))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load template `%s'\n", create_cfg_template); + GNUNET_CONFIGURATION_destroy(cfg_tmpl); + + return 1; + } + /* load defaults */ + else if (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_tmpl, NULL)) + { + GNUNET_break (0); + return 1; + } + + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg_tmpl, "PATHS", "SERVICEHOME", &service_home)) + { + GNUNET_asprintf(&service_home, "%s", "/tmp/testing"); + } + else + { + int s = strlen (service_home); + if (service_home[s-1] == DIR_SEPARATOR) + service_home[s-1] = '\0'; + } + + while (cur < no) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating configuration no. %u \n", cur); + if (create_cfg_template != NULL) + GNUNET_asprintf (&cur_file,"%04u-%s",cur, create_cfg_template); + else + GNUNET_asprintf (&cur_file,"%04u%s",cur, ".conf"); + + + GNUNET_asprintf (&cur_service_home, "%s-%04u%c",service_home, cur, DIR_SEPARATOR); + GNUNET_CONFIGURATION_set_value_string (cfg_tmpl,"PATHS","SERVICEHOME", cur_service_home); + GNUNET_CONFIGURATION_set_value_string (cfg_tmpl,"PATHS","DEFAULTCONFIG", cur_file); + GNUNET_free (cur_service_home); + + cfg_new = GNUNET_TESTING_create_cfg(cfg_tmpl, cur, &port, &upnum, NULL, &fdnum); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing configuration no. %u to file `%s' \n", cur, cur_file); + if (GNUNET_OK != GNUNET_CONFIGURATION_write(cfg_new, cur_file)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write configuration no. %u \n", cur); + fail = GNUNET_YES; + } + + GNUNET_CONFIGURATION_destroy (cfg_new); + GNUNET_free (cur_file); + if (fail == GNUNET_YES) + break; + cur ++; + } + + GNUNET_CONFIGURATION_destroy(cfg_tmpl); + GNUNET_free (service_home); + if (fail == GNUNET_NO) + return 0; + else + return 1; +} + +static int +create_hostkeys (const unsigned int no) +{ + struct GNUNET_DISK_FileHandle *fd; + int cur = 0; + uint64_t fs; + uint64_t total_hostkeys; + char *hostkey_data; + char *hostkey_src_file; + char *hostkey_dest_file; + + /* prepare hostkeys */ + if (create_hostkey_file == NULL) + hostkey_src_file = "../../contrib/testing_hostkeys.dat"; + else + { + hostkey_src_file = create_hostkey_file; + } + + if (GNUNET_YES != GNUNET_DISK_file_test (hostkey_src_file)) + { + if (create_hostkey_file == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read hostkeys file, specify hostkey file with -H!\n")); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Specified hostkey file `%s' not found!\n"), create_hostkey_file); + return 1; + } + else + { + /* Check hostkey file size, read entire thing into memory */ + fd = GNUNET_DISK_file_open (hostkey_src_file, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fd) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkey_src_file); + return 1; + } + + if (GNUNET_YES != GNUNET_DISK_file_size (hostkey_src_file, &fs, GNUNET_YES)) + fs = 0; + + if (0 != (fs % HOSTKEYFILESIZE)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "File size %llu seems incorrect for hostkeys...\n", fs); + } + else + { + total_hostkeys = fs / HOSTKEYFILESIZE; + hostkey_data = GNUNET_malloc_large (fs); + GNUNET_assert (fs == GNUNET_DISK_file_read (fd, hostkey_data, fs)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Read %llu hostkeys from file\n", total_hostkeys); + } + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); + } + + while (cur < no) + { + GNUNET_asprintf (&hostkey_dest_file, "%04u-hostkey",cur); + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_directory_create_for_file (hostkey_dest_file)); + fd = GNUNET_DISK_file_open (hostkey_dest_file, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + GNUNET_assert (fd != NULL); + GNUNET_assert (HOSTKEYFILESIZE == + GNUNET_DISK_file_write (fd, &hostkey_data[cur * HOSTKEYFILESIZE], HOSTKEYFILESIZE)); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Wrote hostkey to file: `%s' \n", hostkey_dest_file); + GNUNET_free (hostkey_dest_file); + cur ++; + } + + GNUNET_free (hostkey_data); + + return 0; +} + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + /* main code here */ + if (create_cfg == GNUNET_YES) + { + if (create_no > 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating %u configuration files based on template `%s'\n", create_no, create_cfg_template); + ret = create_unique_cfgs (create_cfg_template, create_no); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing arguments! \n"); + ret = 1; + } + } + + if (create_hostkey == GNUNET_YES) + { + if (create_no > 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating %u hostkeys \n", create_no); + ret = create_hostkeys (create_no); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing arguments! \n"); + ret = 1; + } + } + + GNUNET_free_non_null (create_cfg_template); +} + + +/** + * The main function. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'C', "cfg", NULL, gettext_noop ("create unique configuration files"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &create_cfg}, + {'k', "key", NULL, gettext_noop ("create hostkey files from pre-computed hostkey list"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &create_hostkey}, + {'H', "hostkeys", NULL, gettext_noop ("host key file"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &create_hostkey_file}, + {'n', "number", NULL, gettext_noop ("number of unique configuration files or hostkeys to create"), + GNUNET_YES, &GNUNET_GETOPT_set_uint, &create_no}, + {'t', "template", NULL, gettext_noop ("configuration template"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &create_cfg_template}, + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-testing", + gettext_noop ("Command line tool to access the testing library"), options, &run, + NULL)) ? ret : 1; +} + +/* end of gnunet-testing.c */ diff --git a/src/testing/helper.c b/src/testing/helper.c new file mode 100644 index 0000000..ebb37eb --- /dev/null +++ b/src/testing/helper.c @@ -0,0 +1,75 @@ +/* + This file is part of GNUnet + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file testing/helper.c + * @brief helper functions for testing + * @author Christian Grothoff + * + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + + + + +/** + * Obtain the peer identity of the peer with the given configuration + * handle. This function reads the private key of the peer, obtains + * the public key and hashes it. + * + * @param cfg configuration of the peer + * @param pid where to store the peer identity + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_TESTING_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_PeerIdentity *pid) +{ + char *keyfile; + struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", + &keyfile)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Peer is lacking HOSTKEY configuration setting.\n")); + return GNUNET_SYSERR; + } + my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_free (keyfile); + if (my_private_key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access hostkey.\n")); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); + GNUNET_CRYPTO_rsa_key_free (my_private_key); + GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), + &pid->hashPubKey); + return GNUNET_OK; +} + + +/* end of helper.c */ diff --git a/src/testing/test_testing.c b/src/testing/test_testing.c new file mode 100644 index 0000000..3e2cd65 --- /dev/null +++ b/src/testing/test_testing.c @@ -0,0 +1,126 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file testing/test_testing.c + * @brief testcase for testing.c + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_YES + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +static int ok; + +static void +end_cb (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); + ok = 1; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon terminated, will now exit.\n"); +#endif + ok = 0; + } +} + + + +void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_Daemon *d = cls; + + GNUNET_TESTING_daemon_stop (d, TIMEOUT, &end_cb, NULL, GNUNET_YES, GNUNET_NO); +} + + +static void +my_cb (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Daemon `%s' started, will now stop it.\n", GNUNET_i2s (id)); +#endif + GNUNET_SCHEDULER_add_now (&do_shutdown, d); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_TESTING_Daemon *d; + + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); +#endif + d = GNUNET_TESTING_daemon_start (cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, + NULL, NULL, &my_cb, NULL); + GNUNET_assert (d != NULL); +} + +static int +check () +{ + char *const argv[] = { "test-testing", + "-c", + "test_testing_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + return ret; +} + +/* end of test_testing.c */ diff --git a/src/testing/test_testing_2dtorus.c b/src/testing/test_testing_2dtorus.c new file mode 100644 index 0000000..7b109bc --- /dev/null +++ b/src/testing/test_testing_2dtorus.c @@ -0,0 +1,372 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file testing/test_testing_2dtorus.c + * + * @brief Test for creating a 2dtorus. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_YES +#define REMOVE_DIR GNUNET_YES + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) + +/** + * Time to wait for stuff that should be rather fast + */ +#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + + +/** + * How many events have happened + */ +static int ok; + +/** + * Be verbose + */ +static int verbose; + +/** + * Total number of peers in the test. + */ +static unsigned long long num_peers; + +/** + * Global configuration file + */ +static struct GNUNET_CONFIGURATION_Handle *testing_cfg; + +/** + * Total number of currently running peers. + */ +static unsigned long long peers_running; + +/** + * Total number of successful connections in the whole network. + */ +static unsigned int total_connections; + +/** + * Total number of counted topo connections + */ +static unsigned int topo_connections; + +/** + * Total number of failed connections in the whole network. + */ +static unsigned int failed_connections; + +/** + * The currently running peer group. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Task called to disconnect peers + */ +static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +/** + * Task called to shutdown test. + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; + + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Shutdown of peers failed!\n"); +#endif + ok--; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: All peers successfully shut down!\n"); +#endif + } +} + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n"); +#endif + + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_CONFIGURATION_destroy (testing_cfg); +} + + +static void +disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: disconnecting peers\n"); + + if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) + { + GNUNET_SCHEDULER_cancel (shutdown_handle); + shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + } +} + + +/** + * Prototype of a callback function indicating that two peers + * are currently connected. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param emsg error message (NULL on success) + */ +void +topo_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, const char *emsg) +{ + topo_connections++; + if (NULL != emsg) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: Error by topo %u: %s\n", + topo_connections, emsg); + } + else + { + if (first == NULL || second == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u NULL\n", + topo_connections); + if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); + } + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u ok\n", + topo_connections); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (first)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (second)); + } +} + + +/** + * peergroup_ready: start test when all peers are connected + * @param cls closure + * @param emsg error message + */ +static void +peergroup_ready (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n", + emsg); + ok--; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "************************************************************\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Peer Group started successfully!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Have %u connections\n", + total_connections); +#endif + + peers_running = GNUNET_TESTING_daemons_running (pg); + if (0 < failed_connections) + { + ok = GNUNET_SYSERR; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: %u connections have FAILED!\n", + failed_connections); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); + + } + else + { + GNUNET_TESTING_get_topology (pg, &topo_cb, NULL); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_peers, NULL); + ok = GNUNET_OK; + } + +} + + +/** + * Function that will be called whenever two daemons are connected by + * the testing library. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param first_cfg config for the first daemon + * @param second_cfg config for the second daemon + * @param first_daemon handle for the first daemon + * @param second_daemon handle for the second daemon + * @param emsg error message (NULL on success) + */ +static void +connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; + } + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Problem with new connection (%s)\n", emsg); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (first)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (second)); + } + +} + + +/** + * run: load configuration options and schedule test to run (start peergroup) + * @param cls closure + * @param args argv + * @param cfgfile configuration file name (can be NULL) + * @param cfg configuration handle + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_TESTING_Host *hosts; + + ok = GNUNET_NO; + total_connections = 0; + failed_connections = 0; + testing_cfg = GNUNET_CONFIGURATION_dup (cfg); + + GNUNET_log_setup ("test_testing_2dtorus", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", "YES"); +#endif + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", + "num_peers", &num_peers)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option TESTING:NUM_PEERS is required!\n"); + return; + } + + hosts = GNUNET_TESTING_hosts_load (testing_cfg); + + pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, + &connect_cb, &peergroup_ready, NULL, + hosts); + GNUNET_assert (pg != NULL); + shutdown_handle = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (), + &shutdown_task, NULL); +} + + +/** + * test_testing_2dtorus command line options + */ +static struct GNUNET_GETOPT_CommandLineOption options[] = { + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END +}; + + +/** + * Main: start test + */ +int +main (int argc, char *argv[]) +{ + char *const argv2[] = { + argv[0], + "-c", + "test_testing_2dtorus.conf", +#if VERBOSE + "-L", + "DEBUG", +#endif + NULL + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Start\n"); + + + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test_testing_2dtorus", + gettext_noop ("Test testing 2d torus."), options, &run, + NULL); +#if REMOVE_DIR + GNUNET_DISK_directory_remove ("/tmp/test_testing_2dtorus"); +#endif + if (GNUNET_OK != ok) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n"); + return 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n"); + return 0; +} + +/* end of test_testing_2dtorus.c */ diff --git a/src/testing/test_testing_2dtorus.conf b/src/testing/test_testing_2dtorus.conf new file mode 100644 index 0000000..ba1db3a --- /dev/null +++ b/src/testing/test_testing_2dtorus.conf @@ -0,0 +1,79 @@ +[PATHS] +SERVICEHOME = /tmp/test_testing_small/ +DEFAULTCONFIG = test_testing_small.conf + +[arm] +PORT = 10010 +DEFAULTSERVICES = core +#DEBUG = YES + +[statistics] +AUTOSTART = YES +PORT = 10000 + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 10001 + +[nse] +WORKBITS = 0 + +[dns] +AUTOSTART = NO +PORT = 10011 + +[transport] +PORT = 10002 +AUTOSTART = YES + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +AUTOSTART = YES +PORT = 10003 + +[peerinfo] +AUTOSTART = YES +PORT = 10004 + +[testing] +NUM_PEERS = 16 +WEAKRANDOM = YES +TOPOLOGY = 2D_TORUS +CONNECT_TOPOLOGY = 2D_TORUS +#TOPOLOGY_FILE = small.dat +CONNECT_TOPOLOGY = 2D_TORUS +#CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM +#CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 +#PERCENTAGE = 3 +#PROBABILITY = .1 +F2F = NO +CONNECT_TIMEOUT = 600 s +CONNECT_ATTEMPTS = 2 +DEBUG = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat +MAX_CONCURRENT_SSH = 10 +USE_PROGRESSBARS = YES +PEERGROUP_TIMEOUT = 2400 s +TOPOLOGY_OUTPUT_FILE = testing_topo_initial +MAX_OUTSTANDING_CONNECTIONS = 75 +#SINGLE_PEERINFO_PER_HOST = YES +#NUM_PEERINFO_PER_HOST = 10 +#SINGLE_STATISTICS_PER_HOST = YES +#NUM_STATISTICS_PER_HOST = 10 +DELETE_FILES = YES diff --git a/src/testing/test_testing_connect.c b/src/testing/test_testing_connect.c new file mode 100644 index 0000000..c69c203 --- /dev/null +++ b/src/testing/test_testing_connect.c @@ -0,0 +1,197 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file testing/test_testing_connect.c + * @brief testcase for functions to connect two peers in testing.c + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_NO + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define CONNECT_ATTEMPTS 3 + +static int ok; + +static struct GNUNET_TESTING_Daemon *d1; + +static struct GNUNET_TESTING_Daemon *d2; + +static struct GNUNET_CONFIGURATION_Handle *c1; + +static struct GNUNET_CONFIGURATION_Handle *c2; + +static struct GNUNET_TESTING_ConnectContext *cc; + +static void +end2_cb (void *cls, const char *emsg) +{ + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); + ok = 1; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Both daemons terminated, will now exit.\n"); +#endif + ok = 0; + } +} + +static void +end1_cb (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping daemon 1 gave: %s\n", + emsg); + ok = 1; + } + else + { + ok = 0; + } + + GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &end2_cb, NULL, GNUNET_YES, + GNUNET_NO); + d2 = NULL; +} + +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &end1_cb, NULL, GNUNET_YES, + GNUNET_NO); + d1 = NULL; +} + +static void +my_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, + unsigned int distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + cc = NULL; + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); +} + + +static void +my_cb2 (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", + GNUNET_i2s (id)); +#endif + cc = GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, CONNECT_ATTEMPTS, + GNUNET_YES, &my_connect_complete, NULL); +} + + +static void +my_cb1 (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", + GNUNET_i2s (id)); +#endif + d2 = GNUNET_TESTING_daemon_start (c2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, + NULL, NULL, &my_cb2, NULL); + GNUNET_assert (d2 != NULL); + +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); +#endif + c1 = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (c1, + "test_testing_connect_peer1.conf")); + c2 = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (c2, + "test_testing_connect_peer2.conf")); + d1 = GNUNET_TESTING_daemon_start (c1, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, + NULL, NULL, &my_cb1, NULL); + GNUNET_assert (d1 != NULL); +} + +static int +check () +{ + char *const argv[] = { "test-testing", + "-c", + "test_testing_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-connect", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing-connect", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + return ret; +} + +/* end of test_testing_connect.c */ diff --git a/src/testing/test_testing_connect_peer1.conf b/src/testing/test_testing_connect_peer1.conf new file mode 100644 index 0000000..cccda5e --- /dev/null +++ b/src/testing/test_testing_connect_peer1.conf @@ -0,0 +1,37 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-testing-connect-peer1/ +DEFAULTCONFIG = test_testing_connect_peer1.conf + +[transport-tcp] +PORT = 12568 + +[arm] +PORT = 12566 +DEFAULTSERVICES = core +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12567 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12564 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12569 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12565 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + +[core] +PORT = 12570 +UNIXPATH = /tmp/gnunet-p1-service-core.sock + +[ats] +PORT = 12571 +UNIXPATH = /tmp/gnunet-p1-service-ats.sock + diff --git a/src/testing/test_testing_connect_peer2.conf b/src/testing/test_testing_connect_peer2.conf new file mode 100644 index 0000000..08ec551 --- /dev/null +++ b/src/testing/test_testing_connect_peer2.conf @@ -0,0 +1,37 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-testing-connect-peer2/ +DEFAULTCONFIG = test_testing_connect_peer2.conf + +[transport-tcp] +PORT = 22568 + +[arm] +PORT = 22566 +DEFAULTSERVICES = core +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 22567 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 22564 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 22569 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 22565 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + +[core] +PORT = 22570 +UNIXPATH = /tmp/gnunet-p2-service-core.sock + +[ats] +PORT = 22571 +UNIXPATH = /tmp/gnunet-p2-service-ats.sock + diff --git a/src/testing/test_testing_data.conf b/src/testing/test_testing_data.conf new file mode 100644 index 0000000..c46cb0d --- /dev/null +++ b/src/testing/test_testing_data.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data.conf + +[arm] +DEFAULTSERVICES = core + diff --git a/src/testing/test_testing_data_remote.conf b/src/testing/test_testing_data_remote.conf new file mode 100644 index 0000000..d58666f --- /dev/null +++ b/src/testing/test_testing_data_remote.conf @@ -0,0 +1,12 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_remote.conf + +[TESTING] +CONTROL_HOST = 127.0.0.1 +HOSTFILE = remote_hosts.txt +MAX_OUTSTANDING_SSH = 5 + +[statistics] +AUTOSTART = NO + diff --git a/src/testing/test_testing_data_topology_2d_torus.conf b/src/testing/test_testing_data_topology_2d_torus.conf new file mode 100644 index 0000000..45fd690 --- /dev/null +++ b/src/testing/test_testing_data_topology_2d_torus.conf @@ -0,0 +1,8 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +NUM_PEERS = 13 +TOPOLOGY = 2D_TORUS + diff --git a/src/testing/test_testing_data_topology_blacklist.conf b/src/testing/test_testing_data_topology_blacklist.conf new file mode 100644 index 0000000..36e378d --- /dev/null +++ b/src/testing/test_testing_data_topology_blacklist.conf @@ -0,0 +1,13 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_blacklist.conf + +[TESTING] +NUM_PEERS = 4 +TOPOLOGY = CLIQUE +BLACKLIST_TOPOLOGY = RING +BLACKLIST_TRANSPORTS = tcp udp http + +[transport-udp] +PORT = 2568 + diff --git a/src/testing/test_testing_data_topology_churn.conf b/src/testing/test_testing_data_topology_churn.conf new file mode 100644 index 0000000..b337165 --- /dev/null +++ b/src/testing/test_testing_data_topology_churn.conf @@ -0,0 +1,10 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_churn.conf + +[TESTING] +NUM_PEERS = 12 + +[arm] +DEFAULTSERVICES = peerinfo transport core + diff --git a/src/testing/test_testing_data_topology_clique.conf b/src/testing/test_testing_data_topology_clique.conf new file mode 100644 index 0000000..69cecb7 --- /dev/null +++ b/src/testing/test_testing_data_topology_clique.conf @@ -0,0 +1,10 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +CONNECT_TIMEOUT = 180 s +CONNECT_ATTEMPTS = 14 +NUM_PEERS = 4 +TOPOLOGY = CLIQUE +SETTLE_TIME = 0 diff --git a/src/testing/test_testing_data_topology_clique_dfs.conf b/src/testing/test_testing_data_topology_clique_dfs.conf new file mode 100644 index 0000000..c7abeae --- /dev/null +++ b/src/testing/test_testing_data_topology_clique_dfs.conf @@ -0,0 +1,13 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +NUM_PEERS = 7 +TOPOLOGY = CLIQUE +CONNECT_TOPOLOGY_OPTION = CONNECT_DFS +CONNECT_TOPOLOGY_OPTION_MODIFIER = 2.0 + +[arm] +DEFAULTSERVICES = peerinfo transport core + diff --git a/src/testing/test_testing_data_topology_clique_minimum.conf b/src/testing/test_testing_data_topology_clique_minimum.conf new file mode 100644 index 0000000..ef95cb1 --- /dev/null +++ b/src/testing/test_testing_data_topology_clique_minimum.conf @@ -0,0 +1,10 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +NUM_PEERS = 20 +TOPOLOGY = CLIQUE +CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM +CONNECT_TOPOLOGY_OPTION_MODIFIER = 2.0 + diff --git a/src/testing/test_testing_data_topology_clique_random.conf b/src/testing/test_testing_data_topology_clique_random.conf new file mode 100644 index 0000000..cd44b65 --- /dev/null +++ b/src/testing/test_testing_data_topology_clique_random.conf @@ -0,0 +1,16 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +NUM_PEERS = 20 +TOPOLOGY = CLIQUE +CONNECT_TOPOLOGY_OPTION = CONNECT_RANDOM_SUBSET +CONNECT_TOPOLOGY_OPTION_MODIFIER = .15 + +[statistics] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO + diff --git a/src/testing/test_testing_data_topology_erdos_renyi.conf b/src/testing/test_testing_data_topology_erdos_renyi.conf new file mode 100644 index 0000000..8e17413 --- /dev/null +++ b/src/testing/test_testing_data_topology_erdos_renyi.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +TOPOLOGY = ERDOS_RENYI + diff --git a/src/testing/test_testing_data_topology_internat.conf b/src/testing/test_testing_data_topology_internat.conf new file mode 100644 index 0000000..af3f62f --- /dev/null +++ b/src/testing/test_testing_data_topology_internat.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +TOPOLOGY = INTERNAT + diff --git a/src/testing/test_testing_data_topology_none.conf b/src/testing/test_testing_data_topology_none.conf new file mode 100644 index 0000000..dbee5d0 --- /dev/null +++ b/src/testing/test_testing_data_topology_none.conf @@ -0,0 +1,37 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +NUM_PEERS = 1000 +TOPOLOGY = NONE +F2F = NO +BLACKLIST_TOPOLOGY = NONE +CONNECT_TOPOLOGY = RING + +[arm] +PORT = 0 + +[statistics] +AUTOSTART = NO +PORT = 0 + +[resolver] +AUTOSTART = NO +PORT = 0 + +[peerinfo] +PORT = 0 + +[transport] +PORT = 0 + +[core] +PORT = 0 + +[topology] +PORT = 0 + +[hostlist] +PORT = 0 + diff --git a/src/testing/test_testing_data_topology_ring.conf b/src/testing/test_testing_data_topology_ring.conf new file mode 100644 index 0000000..6159030 --- /dev/null +++ b/src/testing/test_testing_data_topology_ring.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +TOPOLOGY = RING + diff --git a/src/testing/test_testing_data_topology_scale_free.conf b/src/testing/test_testing_data_topology_scale_free.conf new file mode 100644 index 0000000..7690eac --- /dev/null +++ b/src/testing/test_testing_data_topology_scale_free.conf @@ -0,0 +1,11 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_scale_free.conf + +[TESTING] +NUM_PEERS = 50 +TOPOLOGY = SCALE_FREE + +[arm] +DEFAULTSERVICES = peerinfo transport core + diff --git a/src/testing/test_testing_data_topology_small_world_ring.conf b/src/testing/test_testing_data_topology_small_world_ring.conf new file mode 100644 index 0000000..01931df --- /dev/null +++ b/src/testing/test_testing_data_topology_small_world_ring.conf @@ -0,0 +1,8 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +NUM_PEERS = 25 +TOPOLOGY = SMALL_WORLD_RING + diff --git a/src/testing/test_testing_data_topology_small_world_torus.conf b/src/testing/test_testing_data_topology_small_world_torus.conf new file mode 100644 index 0000000..7c35454 --- /dev/null +++ b/src/testing/test_testing_data_topology_small_world_torus.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +TOPOLOGY = SMALL_WORLD + diff --git a/src/testing/test_testing_data_topology_stability.conf b/src/testing/test_testing_data_topology_stability.conf new file mode 100644 index 0000000..1bfcd1b --- /dev/null +++ b/src/testing/test_testing_data_topology_stability.conf @@ -0,0 +1,9 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING] +SETTLE_TIME = 600 s +NUM_PEERS = 2 +TOPOLOGY = CLIQUE + diff --git a/src/testing/test_testing_defaults.conf b/src/testing/test_testing_defaults.conf new file mode 100644 index 0000000..7b6c4c4 --- /dev/null +++ b/src/testing/test_testing_defaults.conf @@ -0,0 +1,72 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunet-testing/ +DEFAULTCONFIG = test_testing_defaults.conf + +[resolver] +PORT = 2564 + +[transport] +PORT = 2565 +PLUGINS = tcp + +[arm] +PORT = 2566 +DEFAULTSERVICES = + +[statistics] +PORT = 2567 + +[transport-tcp] +PORT = 2568 +BINDTO = 127.0.0.1 + +[peerinfo] +PORT = 2569 + +[core] +PORT = 2570 + +[testing] +NUM_PEERS = 5 +WEAKRANDOM = YES +F2F = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat + +[dht] +AUTOSTART = NO + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[fs] +AUTOSTART = NO + +[dv] +AUTOSTART = NO + +[chat] +AUTOSTART = NO + +[vpn] +AUTOSTART = NO + +[gns] +AUTOSTART = NO diff --git a/src/testing/test_testing_group.c b/src/testing/test_testing_group.c new file mode 100644 index 0000000..f5df45b --- /dev/null +++ b/src/testing/test_testing_group.c @@ -0,0 +1,166 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file testing/test_testing_group.c + * @brief testcase for functions to connect peers in testing.c + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_NO + +#define NUM_PEERS 4 + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +static int ok; + +static int peers_left; + +static int failed_peers; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + + +static void +my_cb (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (id == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Start callback called with error (too long starting peers), aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); + failed_peers++; + if (failed_peers == peers_left) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Too many peers failed, ending test!\n"); + ok = 1; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + } + return; + } + + peers_left--; + if (peers_left == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All peers started successfully, ending test!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 0; + } + else if (failed_peers == peers_left) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Too many peers failed, ending test!\n"); + ok = 1; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); +#endif + peers_left = NUM_PEERS; + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ + peers_left, /* Number of outstanding connections */ + peers_left, /* Number of parallel ssh connections, or peers being started at once */ + TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, + NULL, NULL); + GNUNET_assert (pg != NULL); +} + +static int +check () +{ + char *const argv[] = { "test-testing", + "-c", + "test_testing_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-group", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing-group", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Still need to remove the base testing directory here, + * because group starts will create subdirectories under this + * main dir. However, we no longer need to sleep, as the + * shutdown sequence won't return until everything is cleaned + * up. + */ + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); + return ret; +} + +/* end of test_testing_group.c */ diff --git a/src/testing/test_testing_group_remote.c b/src/testing/test_testing_group_remote.c new file mode 100644 index 0000000..e300f95 --- /dev/null +++ b/src/testing/test_testing_group_remote.c @@ -0,0 +1,263 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file testing/test_testing_group_remote.c + * @brief testcase for testing remote and local starting and connecting + * of hosts from the testing library. The test_testing_data_remote.conf + * file should be modified if this testcase is intended to be used. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_YES + + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define DEFAULT_NUM_PEERS 8; + +static int ok; + +static int peers_left; + +static int peers_failed; + +static struct GNUNET_TESTING_PeerGroup *pg; + +static unsigned long long num_peers; + + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Shutdown of peers failed (error %s)!\n", emsg); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + + +static void +my_cb (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + peers_failed++; + } + + peers_left--; + if (peers_left == 0) + { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 0; + } + else if (peers_failed == peers_left) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Too many peers failed, ending test!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_TESTING_Host *hosts; + struct GNUNET_TESTING_Host *hostpos; + struct GNUNET_TESTING_Host *temphost; + char *hostfile; + struct stat frstat; + char *buf; + char *data; + int count; + int ret; + + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); +#endif + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + GNUNET_assert (num_peers > 0 && num_peers < (unsigned long long) -1); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile", + &hostfile)) + hostfile = NULL; + + hosts = NULL; + data = NULL; + if (hostfile != NULL) + { + if (GNUNET_OK != GNUNET_DISK_file_test (hostfile)) + GNUNET_DISK_fn_write (hostfile, NULL, 0, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not open file specified for host list, ending test!"); + ok = 1119; + GNUNET_free (hostfile); + return; + } + + data = GNUNET_malloc_large (frstat.st_size); + GNUNET_assert (data != NULL); + if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not read file %s specified for host list, ending test!", + hostfile); + GNUNET_free (hostfile); + GNUNET_free (data); + return; + } + + GNUNET_free_non_null (hostfile); + + buf = data; + count = 0; + while (count < frstat.st_size) + { + count++; + if (count >= frstat.st_size) + break; + + /* if (((data[count] == '\n') || (data[count] == '\0')) && (buf != &data[count])) */ + if (((data[count] == '\n')) && (buf != &data[count])) + { + data[count] = '\0'; + temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host)); + ret = + sscanf (buf, "%a[a-zA-Z0-9]@%a[a-zA-Z0-9.]:%hd", + &temphost->username, &temphost->hostname, &temphost->port); + if (3 == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Successfully read host %s, port %d and user %s from file\n", + temphost->hostname, temphost->port, temphost->username); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Error reading line `%s' in hostfile\n", buf); + GNUNET_free (temphost); + buf = &data[count + 1]; + continue; + } + /* temphost->hostname = buf; */ + temphost->next = hosts; + hosts = temphost; + buf = &data[count + 1]; + } + else if ((data[count] == '\n') || (data[count] == '\0')) + buf = &data[count + 1]; + } + } + + peers_left = num_peers; + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ + peers_left, /* Number of outstanding connections */ + peers_left, /* Number of parallel ssh connections, or peers being started at once */ + TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, + NULL, hosts); + hostpos = hosts; + while (hostpos != NULL) + { + temphost = hostpos->next; + GNUNET_free (hostpos->hostname); + GNUNET_free (hostpos->username); + GNUNET_free (hostpos); + hostpos = temphost; + } + GNUNET_free_non_null (data); + GNUNET_assert (pg != NULL); + +} + +static int +check () +{ + char *const argv[] = { "test-testing", + "-c", + "test_testing_data_remote.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-group", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing-group", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Still need to remove the base testing directory here, + * because group starts will create subdirectories under this + * main dir. However, we no longer need to sleep, as the + * shutdown sequence won't return until everything is cleaned + * up. + */ + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); + return ret; +} + +/* end of test_testing_group.c */ diff --git a/src/testing/test_testing_peergroup.c b/src/testing/test_testing_peergroup.c new file mode 100644 index 0000000..061a0ca --- /dev/null +++ b/src/testing/test_testing_peergroup.c @@ -0,0 +1,157 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file testing/test_testing_peergroup.c + * @brief testcase for functions to connect peers in testing_peergroup.c + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_NO + +#define NUM_PEERS 4 + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +static int ok; + +static int peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + ok = 0; + } +} + + +static void +my_cb (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); + ok = 1; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer Group started successfully, ending test!\n"); + /** + * If something is to actually be DONE with the testcase, it should + * be put in here. Usually there will be a struct declared (or global + * variables can be used) to keep track of the state, statistics, + * handles to peers, etc. The example here is the opaque "TestCaseData" + * struct that could be passed into a function "additional_code_for_testing" + * which can be used to perform actions on the peers in the peergroup. + * Also, the GNUNET_TESTING_daemons_stop call would need to be removed, + * and only called once all of the testing is complete. + */ + + /** + * struct TestcaseData *state_closure; + * GNUNET_SCHEDULER_add_now(&additional_code_for_testing, state_closure); + */ + + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_CONFIGURATION_Handle *testing_cfg; + + ok = 1; + testing_cfg = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (testing_cfg, cfgfile)); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", "YES"); +#endif + peers_left = NUM_PEERS; + pg = GNUNET_TESTING_peergroup_start (testing_cfg, peers_left, TIMEOUT, NULL, + &my_cb, NULL, NULL); + GNUNET_assert (pg != NULL); +} + +static int +check () +{ + char *const argv[] = { "test-testing-peergroup", + "-c", + "test_testing_peergroup_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-peergroup", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing-peergroup", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); + return ret; +} + +/* end of test_testing_peergroup.c */ diff --git a/src/testing/test_testing_peergroup_data.conf b/src/testing/test_testing_peergroup_data.conf new file mode 100644 index 0000000..6eadede --- /dev/null +++ b/src/testing/test_testing_peergroup_data.conf @@ -0,0 +1,22 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_peergroup_data.conf + +[TESTING] +CONNECT_ATTEMPTS = 2 +MAX_OUTSTANDING_CONNECTIONS = 20 +MAX_CONCURRENT_SSH = 1 +PEERGROUP_TIMEOUT = 300 s +TOPOLOGY = CLIQUE +PERCENTAGE = 0.5 +PROBABILITY = 0.5 +CONNECT_TOPOLOGY = CLIQUE +CONNECT_TOPOLOGY_OPTION = CONNECT_NONE +CONNECT_TOPOLOGY_OPTION_MODIFIER = 0.0 +BLACKLIST_TOPOLOGY = NONE +BLACKLIST_TRANSPORTS = tcp udp +USE_PROGRESSBARS = NO + +[arm] +DEFAULTSERVICES = core + diff --git a/src/testing/test_testing_reconnect.c b/src/testing/test_testing_reconnect.c new file mode 100644 index 0000000..bcee386 --- /dev/null +++ b/src/testing/test_testing_reconnect.c @@ -0,0 +1,249 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file testing/test_testing_reconnect.c + * @brief testcase for functions to connect two peers in testing.c + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_YES + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define CONNECT_ATTEMPTS 3 + +static int ok; + +static struct GNUNET_TESTING_Daemon *d1; + +static struct GNUNET_TESTING_Daemon *d2; + +static struct GNUNET_CONFIGURATION_Handle *c1; + +static struct GNUNET_CONFIGURATION_Handle *c2; + +static struct GNUNET_TESTING_ConnectContext *cc; + +/** + * How many start-connect-stop iterations should we do? + */ +#define NUM_PHASES 2 + +static int phase; + +/** + * Run the next phase of starting daemons, connecting them and + * stopping them again. + */ +static void +run_phase (void); + +static void +end2_cb (void *cls, const char *emsg) +{ + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); + ok = 1; + } + else + { + if (phase < NUM_PHASES) + { + FPRINTF (stderr, "%s", "."); + run_phase (); + return; + } + FPRINTF (stderr, "%s", ".\n"); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Both daemons terminated, will now exit.\n"); +#endif + ok = 0; + } +} + +static void +end1_cb (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping daemon 1 gave: %s\n", + emsg); + ok = 1; + } + else + { + ok = 0; + } + if (d2 != NULL) + { + GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &end2_cb, NULL, + (phase == NUM_PHASES) ? GNUNET_YES : GNUNET_NO, + GNUNET_NO); + d2 = NULL; + } +} + +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &end1_cb, NULL, + (phase == NUM_PHASES) ? GNUNET_YES : GNUNET_NO, + GNUNET_NO); + d1 = NULL; +} + + +static void +my_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, + unsigned int distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + cc = NULL; +#if VERBOSE + FPRINTF (stderr, "Peer %s ", GNUNET_i2s (first)); + FPRINTF (stderr, "connected to %s\n", GNUNET_i2s (second)); +#endif + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); +} + + + + +static void +my_cb2 (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting daemon 2 gave: %s\n", + emsg); + GNUNET_assert (0); + return; + } + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", + GNUNET_i2s (id)); +#endif + cc = GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, CONNECT_ATTEMPTS, + GNUNET_YES, &my_connect_complete, NULL); +} + + +static void +my_cb1 (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting daemon 1 gave: %s\n", + emsg); + GNUNET_assert (0); + return; + } + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", + GNUNET_i2s (id)); +#endif + d2 = GNUNET_TESTING_daemon_start (c2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, + NULL, NULL, &my_cb2, NULL); + GNUNET_assert (d2 != NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); +#endif + c1 = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (c1, + "test_testing_connect_peer1.conf")); + c2 = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (c2, + "test_testing_connect_peer2.conf")); + run_phase (); +} + +static void +run_phase () +{ + phase++; + d1 = GNUNET_TESTING_daemon_start (c1, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, + NULL, NULL, &my_cb1, NULL); + GNUNET_assert (d1 != NULL); +} + +static int +check () +{ + char *const argv[] = { "test-testing-reconnect", + "-c", + "test_testing_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-reconnect", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing-reconnect", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + return ret; +} + +/* end of test_testing_reconnect.c */ diff --git a/src/testing/test_testing_topology.c b/src/testing/test_testing_topology.c new file mode 100644 index 0000000..ba5e237 --- /dev/null +++ b/src/testing/test_testing_topology.c @@ -0,0 +1,1263 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file testing/test_testing_topology.c + * @brief base testcase for testing all the topologies provided + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_os_lib.h" + +#define VERBOSE GNUNET_NO + +#define PROGRESS_BARS GNUNET_YES + +#define DELAY_FOR_LOGGING GNUNET_NO + +/** + * How long until we fail the whole testcase? + */ +#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 240) + +/** + * How long until we give up on starting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 500) + +#define SECONDS_PER_PEER_START 120 + +#define DEFAULT_NUM_PEERS 4 + +#define MAX_OUTSTANDING_CONNECTIONS 100 + +static float fail_percentage = 0.05; + +static int ok; + +static unsigned long long num_peers; + +struct GNUNET_TIME_Relative connect_timeout; + +static unsigned long long connect_attempts; + +static unsigned int topology_connections; + +static unsigned int total_connections; + +static unsigned int failed_connections; + +static unsigned int total_server_connections; + +static unsigned int total_messages_received; + +static unsigned int expected_messages; + +static unsigned int expected_connections; + +static unsigned long long peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +const struct GNUNET_CONFIGURATION_Handle *main_cfg; + +GNUNET_SCHEDULER_TaskIdentifier die_task; + +static char *dotOutFileName; + +static struct GNUNET_TIME_Relative settle_time; + +static FILE *dotOutFile; + +static char *topology_string; + +static char *blacklist_transports; + +static int transmit_ready_scheduled; + +static int transmit_ready_failed; + +static int transmit_ready_called; + +static unsigned int modnum; + +static unsigned int dotnum; + +static enum GNUNET_TESTING_Topology topology; + +static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ + +static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ + +static enum GNUNET_TESTING_TopologyOption connect_topology_option = + GNUNET_TESTING_TOPOLOGY_OPTION_ALL; + +static double connect_topology_option_modifier = 0.0; + +static char *test_directory; + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct GNUNET_TestMessage +{ + /** + * Header of the message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this message. + */ + uint32_t uid; +}; +GNUNET_NETWORK_STRUCT_END + +struct TestMessageContext +{ + /* This is a linked list */ + struct TestMessageContext *next; + + /* Handle to the sending peer core */ + struct GNUNET_CORE_Handle *peer1handle; + + /* Handle to the receiving peer core */ + struct GNUNET_CORE_Handle *peer2handle; + + /* Handle to the sending peer daemon */ + struct GNUNET_TESTING_Daemon *peer1; + + /* Handle to the receiving peer daemon */ + struct GNUNET_TESTING_Daemon *peer2; + + /* Identifier for this message, so we don't disconnect other peers! */ + uint32_t uid; + + /* Has peer1 been notified already of a connection to peer2? */ + int peer1notified; + + /* Has the core of peer2 been connected already? */ + int peer2connected; + + /* Task for disconnecting cores, allow task to be cancelled on shutdown */ + GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +}; + +static struct TestMessageContext *test_messages; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + +#if DELAY_FOR_LOGGING +static void +gather_log_data () +{ + char *peer_number; + char *connect_number; + struct GNUNET_OS_Process *mem_process; + + GNUNET_asprintf (&peer_number, "%llu", num_peers); + GNUNET_asprintf (&connect_number, "%llu", expected_connections); + mem_process = + GNUNET_OS_start_process (NULL, NULL, "./memsize.pl", "memsize.pl", + "totals.txt", peer_number, connect_number, NULL); + GNUNET_OS_process_wait (mem_process); + GNUNET_OS_process_close (mem_process); + mem_process = NULL; +} + +#endif + +static void +finish_testing () +{ + GNUNET_assert (pg != NULL); + struct TestMessageContext *pos; + struct TestMessageContext *free_pos; + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Called finish testing, stopping daemons.\n"); +#endif + + pos = test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); + } + GNUNET_free (free_pos); + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", + transmit_ready_scheduled, transmit_ready_failed, + transmit_ready_called); +#endif + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); +#endif + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } + + ok = 0; +} + + +static void +disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestMessageContext *pos = cls; + + /* Disconnect from the respective cores */ +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n", + GNUNET_i2s (&pos->peer1->id)); +#endif + if (pos->peer1handle != NULL) + GNUNET_CORE_disconnect (pos->peer1handle); +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); +#endif + if (pos->peer2handle != NULL) + GNUNET_CORE_disconnect (pos->peer2handle); + /* Set handles to NULL so test case can be ended properly */ + pos->peer1handle = NULL; + pos->peer2handle = NULL; + pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK; + /* Decrement total connections so new can be established */ + total_server_connections -= 2; +} + +#if DO_STATS +static void +stats_finished (void *cls, int result) +{ + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); +} + +/** + * Callback function to process statistic values. + * + * @param cls closure + * @param peer the peer the statistics belong to + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +stats_print (void *cls, const struct GNUNET_PeerIdentity *peer, + const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s:%s:%s -- %llu\n", GNUNET_i2s (peer), + subsystem, name, value); + return GNUNET_OK; +} +#endif + +static void +topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, const char *emsg) +{ + FILE *outfile = cls; + + if (first != NULL) + { + if (outfile != NULL) + { + FPRINTF (outfile, "\t\"%s\" -- ", GNUNET_i2s (first)); + FPRINTF (outfile, "\"%s\";\n", GNUNET_i2s (second)); + } + topology_connections++; + } + else + { + FPRINTF (stderr, + "Finished iterating over topology, %d total connections!\n", + topology_connections); + if (outfile != NULL) + { + FPRINTF (outfile, "%s", "}\n"); + FCLOSE (outfile); +#if DO_STATS + GNUNET_TESTING_get_statistics (pg, &stats_finished, &stats_print, NULL); +#endif + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } + } +} + +static int +process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + char *dotOutFileNameFinished; + FILE *dotOutFileFinished; + struct TestMessageContext *pos = cls; + struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message; + + if (pos->uid != ntohl (msg->uid)) + return GNUNET_OK; + +#if PROGRESS_BARS + if ((total_messages_received) % modnum == 0) + { + if (total_messages_received == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) total_messages_received / expected_messages) * + 100)); + + } + else if (total_messages_received % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + + total_messages_received++; + +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), + ntohs (message->type)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total messages received %d, expected %d.\n", + total_messages_received, expected_messages); +#endif + + if (total_messages_received == expected_messages) + { +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "100%%]\n"); +#endif + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_asprintf (&dotOutFileNameFinished, "%s.dot", "final_topology"); + dotOutFileFinished = FOPEN (dotOutFileNameFinished, "w"); + GNUNET_free (dotOutFileNameFinished); + if (dotOutFileFinished != NULL) + { + FPRINTF (dotOutFileFinished, "%s", "strict graph G {\n"); + } + topology_connections = 0; + GNUNET_TESTING_get_topology (pg, &topology_cb, dotOutFileFinished); + //GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } + else + { + pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos); + } + + return GNUNET_OK; +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *msg = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "End badly was called (%s)... stopping daemons.\n", msg); + struct TestMessageContext *pos; + struct TestMessageContext *free_pos; + + pos = test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + GNUNET_free (free_pos); + } + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", + transmit_ready_scheduled, transmit_ready_failed, + transmit_ready_called); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total messages received %d, expected %d.\n", + total_messages_received, expected_messages); +#endif + + if (pg != NULL) + { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 7331; /* Opposite of leet */ + } + else + ok = 401; /* Never got peers started */ + + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } +} + +static size_t +transmit_ready (void *cls, size_t size, void *buf) +{ + struct GNUNET_TestMessage *m; + struct TestMessageContext *pos = cls; + + GNUNET_assert (buf != NULL); + m = (struct GNUNET_TestMessage *) buf; + m->header.type = htons (MTYPE); + m->header.size = htons (sizeof (struct GNUNET_TestMessage)); + m->uid = htonl (pos->uid); + transmit_ready_called++; +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", + GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled, + transmit_ready_called); +#endif + return sizeof (struct GNUNET_TestMessage); +} + + +static struct GNUNET_CORE_MessageHandler no_handlers[] = { + {NULL, 0, 0} +}; + +static struct GNUNET_CORE_MessageHandler handlers[] = { + {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)}, + {NULL, 0, 0} +}; + +static void +init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct TestMessageContext *pos = cls; + + total_server_connections++; + + pos->peer2connected = GNUNET_YES; + if (pos->peer1notified == GNUNET_YES) /* Peer 1 has been notified of connection to peer 2 */ + { +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", + GNUNET_i2s (my_identity), + GNUNET_h2s (&pos->peer1->id.hashPubKey)); +#endif + if (NULL == + GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, + TIMEOUT, &pos->peer2->id, + sizeof (struct GNUNET_TestMessage), + &transmit_ready, pos)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); + transmit_ready_failed++; + } + else + { + transmit_ready_scheduled++; + } + } +} + +/** + * Method called whenever a given peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data for the connection + * @param atsi_count number of records in 'atsi' + */ +static void +connect_notify_peers (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct TestMessageContext *pos = cls; + + if (0 == memcmp (peer, &pos->peer2->id, sizeof (struct GNUNET_PeerIdentity))) + { + pos->peer1notified = GNUNET_YES; +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer `%s' notified of connection to peer `%s'\n", + GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey)); +#endif + } + else + return; + + if (pos->peer2connected == GNUNET_YES) /* Already connected and notified of connection, send message! */ + { +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", + GNUNET_i2s (&pos->peer2->id), + GNUNET_h2s (&pos->peer1->id.hashPubKey)); +#endif + if (NULL == + GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, + TIMEOUT, &pos->peer2->id, + sizeof (struct GNUNET_TestMessage), + &transmit_ready, pos)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); + transmit_ready_failed++; + } + else + { + transmit_ready_scheduled++; + } + } +} + +static void +init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct TestMessageContext *pos = cls; + + total_server_connections++; + +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core connection to `%4s' established, setting up handles\n", + GNUNET_i2s (my_identity)); +#endif + + /* + * Connect to the receiving peer + */ + pos->peer2handle = + GNUNET_CORE_connect (pos->peer2->cfg, 1, pos, &init_notify_peer2, NULL, + NULL, NULL, GNUNET_YES, NULL, GNUNET_YES, handlers); + +} + + +static void +send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestMessageContext *pos = cls; + + if ((pos == test_messages) && (settle_time.rel_value > 0)) + { + topology_connections = 0; + GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); + } + if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL)) + return; + + if (die_task == GNUNET_SCHEDULER_NO_TASK) + { + die_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, + "from send test messages (timeout)"); + } + + if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS) + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), + &send_test_messages, pos); + return; /* Otherwise we'll double schedule messages here! */ + } + + /* + * Connect to the sending peer + */ + pos->peer1handle = + GNUNET_CORE_connect (pos->peer1->cfg, 1, pos, &init_notify_peer1, + &connect_notify_peers, NULL, NULL, GNUNET_NO, NULL, + GNUNET_NO, no_handlers); + + GNUNET_assert (pos->peer1handle != NULL); + + if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS) + { + GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next); + } + else + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), + &send_test_messages, pos->next); + } +} + + +void +topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + struct TestMessageContext *temp_context; + + if (emsg == NULL) + { +#if PROGRESS_BARS + if ((total_connections) % modnum == 0) + { + if (total_connections == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) total_connections / expected_connections) * + 100)); + + } + else if (total_connections % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + total_connections++; +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "connected peer %s to peer %s\n", + first_daemon->shortname, second_daemon->shortname); +#endif + temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); + temp_context->peer1 = first_daemon; + temp_context->peer2 = second_daemon; + temp_context->next = test_messages; + temp_context->uid = total_connections; + temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; + test_messages = temp_context; + + expected_messages++; + if (dotOutFile != NULL) + FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, + second_daemon->shortname); + } +#if VERBOSE + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + } +#endif + + if (total_connections == expected_connections) + { +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "100%%]\n"); +#endif +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number! Calling send messages.\n", + total_connections); +#endif + modnum = expected_messages / 4; + dotnum = (expected_messages / 50) + 1; + if (modnum == 0) + modnum = 1; + if (dotnum == 0) + dotnum = 1; + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; +#if DELAY_FOR_LOGGING + FPRINTF (stdout, "%s", "Sending test messages in 10 seconds.\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 10), + &send_test_messages, test_messages); + gather_log_data (); +#else + if (settle_time.rel_value > 0) + { + GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); + } + GNUNET_SCHEDULER_add_delayed (settle_time, &send_test_messages, + test_messages); +#endif +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "Test message progress: ["); +#endif + + } + else if (total_connections + failed_connections == expected_connections) + { + if (failed_connections < + (unsigned int) (fail_percentage * total_connections)) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); + } + else + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many failed connections)"); + } + } + else + { +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Have %d total connections, %d failed connections, Want %d (at least %d)\n", + total_connections, failed_connections, expected_connections, + expected_connections - + (unsigned int) (fail_percentage * expected_connections)); +#endif + } +} + +static void +topology_creation_finished (void *cls, const char *emsg) +{ +#if VERBOSE + if (emsg == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All topology connections created successfully!\n"); +#endif +} + +static void +connect_topology () +{ + expected_connections = -1; + if ((pg != NULL) && (peers_left == 0)) + { + expected_connections = + GNUNET_TESTING_connect_topology (pg, connection_topology, + connect_topology_option, + connect_topology_option_modifier, + connect_timeout, connect_attempts, + &topology_creation_finished, NULL); +#if PROGRESS_BARS + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Have %d expected connections\n", + expected_connections); +#endif + } + + GNUNET_SCHEDULER_cancel (die_task); + if (expected_connections < 1) + { + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from connect topology (bad return)"); + return; + } + + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + SECONDS_PER_PEER_START * num_peers), + &end_badly, + "from connect topology (timeout)"); + modnum = expected_connections / 4; + dotnum = (expected_connections / 50) + 1; + if (modnum == 0) + modnum = 1; + if (dotnum == 0) + dotnum = 1; +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "Peer connection progress: ["); +#endif +} + +static void +create_topology () +{ + peers_left = num_peers; /* Reset counter */ + if (GNUNET_TESTING_create_topology + (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) + { +#if PROGRESS_BARS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Topology set up, now starting peers!\n"); + FPRINTF (stdout, "%s", "Daemon start progress ["); +#endif + GNUNET_TESTING_daemons_continue_startup (pg); + } + else + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from create topology (bad return)"); + } + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + SECONDS_PER_PEER_START * num_peers), + &end_badly, + "from continue startup (timeout)"); +} + + +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", + (num_peers - peers_left) + 1, num_peers); +#endif +#if PROGRESS_BARS + if ((num_peers - peers_left) % modnum == 0) + { + if (num_peers - peers_left == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) (num_peers - peers_left) / num_peers) * 100)); + + } + else if ((num_peers - peers_left) % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + peers_left--; + if (peers_left == 0) + { +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "100%%]\n"); +#endif +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now connecting peers!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 8), &end_badly, + "from peers_started_callback"); +#if DELAY_FOR_LOGGING + FPRINTF (stdout, "%s", "Connecting topology in 10 seconds\n"); + gather_log_data (); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 10), + &connect_topology, NULL); +#else + connect_topology (); +#endif + ok = 0; + } +} + +/** + * Callback indicating that the hostkey was created for a peer. + * + * @param cls NULL + * @param id the peer identity + * @param d the daemon handle (pretty useless at this point, remove?) + * @param emsg non-null on failure + */ +void +hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Hostkey callback received error: %s\n", emsg); + } + +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left, + num_peers, GNUNET_i2s (id)); +#endif + +#if PROGRESS_BARS + if ((num_peers - peers_left) % modnum == 0) + { + if (num_peers - peers_left == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) (num_peers - peers_left) / num_peers) * 100)); + + } + else if ((num_peers - peers_left) % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + peers_left--; + if (peers_left == 0) + { +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "100%%]\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d hostkeys created, now creating topology!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "from create_topology"); + GNUNET_SCHEDULER_add_now (&create_topology, NULL); + ok = 0; + } +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *topology_str; + char *connect_topology_str; + char *blacklist_topology_str; + char *connect_topology_option_str; + char *connect_topology_option_modifier_string; + unsigned long long max_outstanding_connections; + + ok = 1; + + dotOutFile = FOPEN (dotOutFileName, "w"); + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "strict graph G {\n"); + } + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting daemons based on config file %s\n", cfgfile); +#endif + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", + &topology_str)) && + (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + topology_str, "TESTING", "TOPOLOGY"); + topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ + } + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology", + &connect_topology_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&connection_topology, + connect_topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology `%s' given for section %s option %s\n", + connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); + } + GNUNET_free_non_null (connect_topology_str); + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option", + &connect_topology_option_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_option_get (&connect_topology_option, + connect_topology_option_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology option `%s' given for section %s option %s\n", + connect_topology_option_str, "TESTING", + "CONNECT_TOPOLOGY_OPTION"); + connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ + } + GNUNET_free_non_null (connect_topology_option_str); + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option_modifier", + &connect_topology_option_modifier_string)) + { + if (sscanf + (connect_topology_option_modifier_string, "%lf", + &connect_topology_option_modifier) != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + connect_topology_option_modifier_string, + "connect_topology_option_modifier", "TESTING"); + } + GNUNET_free (connect_topology_option_modifier_string); + } + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_transports", + &blacklist_transports)) + blacklist_transports = NULL; + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_topology", + &blacklist_topology_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&blacklist_topology, + blacklist_topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); + } + GNUNET_free_non_null (topology_str); + GNUNET_free_non_null (blacklist_topology_str); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SETTLE_TIME", + &settle_time)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "SETTLE_TIME"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", + &connect_timeout)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "CONNECT_TIMEOUT"); + return; + } + + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", + &connect_attempts)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "connect_attempts"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", + "max_outstanding_connections", + &max_outstanding_connections)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "max_outstanding_connections"); + return; + } + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + main_cfg = cfg; + + peers_left = num_peers; + modnum = num_peers / 4; + dotnum = (num_peers / 50) + 1; + if (modnum == 0) + modnum = 1; + if (dotnum == 0) + dotnum = 1; +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "Hostkey generation progress: ["); +#endif + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + SECONDS_PER_PEER_START * num_peers), + &end_badly, + "didn't generate all hostkeys within a reasonable amount of time!!!"); + + GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, + max_outstanding_connections, peers_left, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + SECONDS_PER_PEER_START * num_peers), + &hostkey_callback, NULL, + &peers_started_callback, NULL, + &topology_callback, NULL, NULL); + +} + +static int +check () +{ + char *binary_name; + char *config_file_name; + + GNUNET_asprintf (&binary_name, "test-testing-topology-%s", topology_string); + GNUNET_asprintf (&config_file_name, "test_testing_data_topology_%s.conf", + topology_string); + int ret; + + char *const argv[] = { binary_name, + "-c", + config_file_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + binary_name, "nohelp", options, &run, &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-testing-topology-%s': Failed with error code %d\n", + topology_string, ret); + } + GNUNET_free (binary_name); + GNUNET_free (config_file_name); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + char *binary_start_pos; + char *our_binary_name; + char *dotexe; + + binary_start_pos = strchr (argv[0], '/'); + GNUNET_assert (binary_start_pos != NULL); + topology_string = strstr (binary_start_pos, "_topology"); + GNUNET_assert (topology_string != NULL); + topology_string++; + topology_string = strstr (topology_string, "_"); + GNUNET_assert (topology_string != NULL); + topology_string++; + topology_string = GNUNET_strdup (topology_string); + if (NULL != (dotexe = strstr (topology_string, ".exe"))) + dotexe[0] = '\0'; + GNUNET_asprintf (&our_binary_name, "test-testing-topology_%s", + topology_string); + GNUNET_asprintf (&dotOutFileName, "topology_%s.dot", topology_string); + + GNUNET_log_setup (our_binary_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_free (topology_string); + + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + GNUNET_free (our_binary_name); + return ret; +} + +/* end of test_testing_topology.c */ diff --git a/src/testing/test_testing_topology_blacklist.c b/src/testing/test_testing_topology_blacklist.c new file mode 100644 index 0000000..ad39f7d --- /dev/null +++ b/src/testing/test_testing_topology_blacklist.c @@ -0,0 +1,595 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file testing/test_testing_topology_blacklist.c + * @brief base testcase for testing transport level blacklisting + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" + +#define VERBOSE GNUNET_NO + +/** + * How long until we fail the whole testcase? + */ +#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) + +/** + * How long until we give up on starting the peers? (Must be longer than the connect timeout!) + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define DEFAULT_NUM_PEERS 4 + +#define MAX_OUTSTANDING_CONNECTIONS 300 + +static int ok; + +struct GNUNET_TIME_Relative connect_timeout; + +static unsigned long long connect_attempts; + +static unsigned long long num_peers; + +static unsigned int total_connections; + +static unsigned int failed_connections; + +static unsigned int expected_connections; + +static unsigned int expected_failed_connections; + +static unsigned long long peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +const struct GNUNET_CONFIGURATION_Handle *main_cfg; + +GNUNET_SCHEDULER_TaskIdentifier die_task; + +static char *dotOutFileName; + +static FILE *dotOutFile; + +static char *blacklist_transports; + +static enum GNUNET_TESTING_Topology topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Overlay should allow all connections */ + +static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_RING; /* Blacklist underlay into a ring */ + +static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ + +static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Try to connect all possible OVERLAY connections */ + +static double connect_topology_option_modifier = 0.0; + +static char *test_directory; + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct GNUNET_TestMessage +{ + /** + * Header of the message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this message. + */ + uint32_t uid; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + +static void +finish_testing () +{ + GNUNET_assert (pg != NULL); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Called finish testing, stopping daemons.\n"); +#endif + sleep (1); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); +#endif + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); +#endif + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } + + ok = 0; +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *msg = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "End badly was called (%s)... stopping daemons.\n", msg); + + if (pg != NULL) + { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 7331; /* Opposite of leet */ + } + else + ok = 401; /* Never got peers started */ + + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } +} + + + +void +topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n", + first_daemon->shortname, second_daemon->shortname); +#endif + if (dotOutFile != NULL) + FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, + second_daemon->shortname); + } + + else + { + failed_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); +#endif + } + + + if (total_connections == expected_connections) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number (that's bad)!\n", + total_connections); +#endif + + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many successful connections)"); + } + else if (total_connections + failed_connections == expected_connections) + { + if ((failed_connections == expected_failed_connections) && + (total_connections == + expected_connections - expected_failed_connections)) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } + else + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (wrong number of failed connections)"); + } + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Have %d total connections, %d failed connections, Want %d (failed) and %d (successful)\n", + total_connections, failed_connections, + expected_failed_connections, + expected_connections - expected_failed_connections); +#endif + } +} + +static void +connect_topology () +{ + expected_connections = -1; + if ((pg != NULL) && (peers_left == 0)) + { + expected_connections = + GNUNET_TESTING_connect_topology (pg, connection_topology, + connect_topology_option, + connect_topology_option_modifier, + connect_timeout, connect_attempts, + NULL, NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", + expected_connections); +#endif + } + + GNUNET_SCHEDULER_cancel (die_task); + if (expected_connections == GNUNET_SYSERR) + { + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from connect topology (bad return)"); + } + + die_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, + "from connect topology (timeout)"); +} + +static void +create_topology () +{ + peers_left = num_peers; /* Reset counter */ + if (GNUNET_TESTING_create_topology + (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Topology set up, now starting peers!\n"); +#endif + GNUNET_TESTING_daemons_continue_startup (pg); + } + else + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from create topology (bad return)"); + } + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, + "from continue startup (timeout)"); +} + + +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", + (num_peers - peers_left) + 1, num_peers); +#endif + peers_left--; + if (peers_left == 0) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now creating topology!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "from peers_started_callback"); + connect_topology (); + ok = 0; + } +} + +/** + * Callback indicating that the hostkey was created for a peer. + * + * @param cls NULL + * @param id the peer identity + * @param d the daemon handle (pretty useless at this point, remove?) + * @param emsg non-null on failure + */ +void +hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Hostkey callback received error: %s\n", emsg); + } + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostkey created for peer `%s'\n", + GNUNET_i2s (id)); +#endif + peers_left--; + if (peers_left == 0) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d hostkeys created, now creating topology!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "from hostkey_callback"); + GNUNET_SCHEDULER_add_now (&create_topology, NULL); + ok = 0; + } +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + unsigned long long topology_num; + unsigned long long connect_topology_num; + unsigned long long blacklist_topology_num; + unsigned long long connect_topology_option_num; + char *connect_topology_option_modifier_string; + + ok = 1; + + dotOutFile = FOPEN (dotOutFileName, "w"); + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "strict graph G {\n"); + } + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting daemons based on config file %s\n", cfgfile); +#endif + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + if (dotOutFile != NULL) + { + FCLOSE (dotOutFile); + } + return; + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "topology", + &topology_num)) + topology = topology_num; + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_topology", + &connect_topology_num)) + connection_topology = connect_topology_num; + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", + "connect_topology_option", + &connect_topology_option_num)) + connect_topology_option = connect_topology_option_num; + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option_modifier", + &connect_topology_option_modifier_string)) + { + if (sscanf + (connect_topology_option_modifier_string, "%lf", + &connect_topology_option_modifier) != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + connect_topology_option_modifier_string, + "connect_topology_option_modifier", "TESTING"); + GNUNET_free (connect_topology_option_modifier_string); + ok = 707; + if (dotOutFile != NULL) + { + FCLOSE (dotOutFile); + } + return; + } + GNUNET_free (connect_topology_option_modifier_string); + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_transports", + &blacklist_transports)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No transports specified for blacklisting in blacklist testcase (this shouldn't happen!)\n"); + ok = 808; + if (dotOutFile != NULL) + { + FCLOSE (dotOutFile); + } + return; + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", + "blacklist_topology", + &blacklist_topology_num)) + blacklist_topology = blacklist_topology_num; + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", + &connect_timeout)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "CONNECT_TIMEOUT"); + return; + } + + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", + &connect_attempts)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "connect_attempts"); + return; + } + + main_cfg = cfg; + + GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); + peers_left = num_peers; + + /* For this specific test we only really want a CLIQUE topology as the + * overlay allowed topology, and a RING topology as the underlying connection + * allowed topology. So we will expect only num_peers * 2 connections to + * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail. + */ + expected_connections = num_peers * (num_peers - 1); + expected_failed_connections = expected_connections - (num_peers * 2); + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, + TIMEOUT, &hostkey_callback, NULL, + &peers_started_callback, NULL, + &topology_callback, NULL, NULL); + +} + +static int +check () +{ + int ret; + + char *const argv[] = { "test-testing-topology-blacklist", + "-c", + "test_testing_data_topology_blacklist.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-topology-blacklist", "nohelp", options, + &run, &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-testing-topology-blacklist': Failed with error code %d\n", + ret); + } + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test_testing_topology_blacklist", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (test_directory != NULL) + { + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + } + + return ret; +} + +/* end of test_testing_topology_blacklist.c */ diff --git a/src/testing/test_testing_topology_churn.c b/src/testing/test_testing_topology_churn.c new file mode 100644 index 0000000..3612089 --- /dev/null +++ b/src/testing/test_testing_topology_churn.c @@ -0,0 +1,350 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file testing/test_testing_topology_churn.c + * @brief base testcase for testing simple churn functionality + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" + +#define VERBOSE GNUNET_YES + +/** + * How long until we fail the whole testcase? + */ +#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) + +/** + * How long until we give up on starting the peers? (Must be longer than the connect timeout!) + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define DEFAULT_NUM_PEERS 4 + +static int ok; + +static unsigned long long num_peers; + +static unsigned int expected_connections; + +static unsigned int expected_failed_connections; + +static unsigned long long peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +const struct GNUNET_CONFIGURATION_Handle *main_cfg; + +GNUNET_SCHEDULER_TaskIdentifier die_task; + +static char *test_directory; + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct GNUNET_TestMessage +{ + /** + * Header of the message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this message. + */ + uint32_t uid; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + +static void +finish_testing () +{ + GNUNET_assert (pg != NULL); + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Called finish testing, stopping daemons.\n"); +#endif + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); +#endif + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); +#endif + + ok = 0; +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *msg = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "End badly was called (%s)... stopping daemons.\n", msg); + + if (pg != NULL) + { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 7331; /* Opposite of leet */ + } + else + ok = 401; /* Never got peers started */ + +} + +struct ChurnTestContext +{ + GNUNET_SCHEDULER_Task next_task; + +}; + +static struct ChurnTestContext churn_ctx; + +/** + * Churn callback, report on success or failure of churn operation. + * + * @param cls closure + * @param emsg NULL on success + */ +void +churn_callback (void *cls, const char *emsg) +{ + if (emsg == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Successfully churned peers!\n", + emsg); + GNUNET_SCHEDULER_add_now (churn_ctx.next_task, NULL); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to churn peers with error `%s'\n", emsg); + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + } +} + + +static void +churn_peers_both () +{ + churn_ctx.next_task = &finish_testing; + GNUNET_TESTING_daemons_churn (pg, NULL, 1, 1, TIMEOUT, &churn_callback, NULL); +} + +static void +churn_peers_off_again () +{ + churn_ctx.next_task = &churn_peers_both; + GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL); +} + +static void +churn_peers_on () +{ + churn_ctx.next_task = &churn_peers_off_again; + GNUNET_TESTING_daemons_churn (pg, NULL, 0, 2, TIMEOUT, &churn_callback, NULL); +} + +static void +churn_peers_off () +{ + churn_ctx.next_task = &churn_peers_on; + GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL); +} + +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", + (num_peers - peers_left) + 1, num_peers); +#endif + peers_left--; + if (peers_left == 0) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now testing churn!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "from peers_started_callback"); + churn_peers_off (); + ok = 0; + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + ok = 1; + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting daemons based on config file %s\n", cfgfile); +#endif + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + main_cfg = cfg; + + peers_left = num_peers; + GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); + + /* For this specific test we only really want a CLIQUE topology as the + * overlay allowed topology, and a RING topology as the underlying connection + * allowed topology. So we will expect only num_peers * 2 connections to + * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail. + */ + expected_connections = num_peers * (num_peers - 1); + expected_failed_connections = expected_connections - (num_peers * 2); + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, + TIMEOUT, NULL, NULL, + &peers_started_callback, NULL, NULL, NULL, + NULL); + +} + +static int +check () +{ + int ret; + + char *const argv[] = { "test-testing-topology-churn", + "-c", + "test_testing_data_topology_churn.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-topology-churn", "nohelp", options, + &run, &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-testing-topology-churn': Failed with error code %d\n", + ret); + } + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test_testing_topology_churn", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (test_directory != NULL) + { + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + } + + return ret; +} + +/* end of test_testing_topology_churn.c */ diff --git a/src/testing/testing.c b/src/testing/testing.c new file mode 100644 index 0000000..16cee90 --- /dev/null +++ b/src/testing/testing.c @@ -0,0 +1,2215 @@ +/* + This file is part of GNUnet + (C) 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file testing/testing.c + * @brief convenience API for writing testcases for GNUnet + * Many testcases need to start and stop gnunetd, + * and this library is supposed to make that easier + * for TESTCASES. Normal programs should always + * use functions from gnunet_{util,arm}_lib.h. This API is + * ONLY for writing testcases! + * @author Christian Grothoff + * + */ +#include "platform.h" +#include "gnunet_arm_service.h" +#include "gnunet_core_service.h" +#include "gnunet_constants.h" +#include "gnunet_testing_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_hello_lib.h" + +#define DEBUG_TESTING GNUNET_EXTRA_LOGGING + +#define DEBUG_TESTING_RECONNECT GNUNET_EXTRA_LOGGING + +/** + * Hack to deal with initial HELLO's being often devoid of addresses. + * This hack causes 'process_hello' to ignore HELLOs without addresses. + * The correct implementation would continue with 'process_hello' until + * the connection could be established... + */ +#define EMPTY_HACK GNUNET_YES + +/** + * How long do we wait after starting gnunet-service-arm + * for the core service to be alive? + */ +#define ARM_START_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * How many times are we willing to try to wait for "scp" or + * "gnunet-service-arm" to complete (waitpid) before giving up? + */ +#define MAX_EXEC_WAIT_RUNS 250 + +static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} }; + +#if EMPTY_HACK +static int +test_address (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + int *empty = cls; + + *empty = GNUNET_NO; + return GNUNET_OK; +} +#endif + +/** + * Receive the HELLO from one peer, give it to the other + * and ask them to connect. + * + * @param cls Closure (daemon whose hello is this). + * @param message HELLO message of peer + */ +static void +process_hello (void *cls, const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_TESTING_Daemon *daemon = cls; + int msize; + +#if EMPTY_HACK + int empty; + + empty = GNUNET_YES; + GNUNET_assert (message != NULL); + GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *) message, + GNUNET_NO, &test_address, &empty); + if (GNUNET_YES == empty) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Skipping empty HELLO address of peer %s\n", + GNUNET_i2s (&daemon->id)); + return; + } +#endif + GNUNET_assert (daemon->phase == SP_GET_HELLO || + daemon->phase == SP_START_DONE); + daemon->cb = NULL; // FIXME: why??? (see fsm:SP_START_CORE, notify_daemon_started) + if (daemon->task != GNUNET_SCHEDULER_NO_TASK) /* Assertion here instead? */ + GNUNET_SCHEDULER_cancel (daemon->task); + + if (daemon->server != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received `%s' from transport service of `%4s', disconnecting core!\n", + "HELLO", GNUNET_i2s (&daemon->id)); + GNUNET_CORE_disconnect (daemon->server); + daemon->server = NULL; + } + + msize = ntohs (message->size); + if (msize < 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "HELLO message of peer %s is of size 0\n", + GNUNET_i2s (&daemon->id)); + return; + } + if (daemon->ghh != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (daemon->ghh); + daemon->ghh = NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received `%s' from transport service of `%4s'\n", "HELLO", + GNUNET_i2s (&daemon->id)); + GNUNET_free_non_null (daemon->hello); + daemon->hello = GNUNET_malloc (msize); + memcpy (daemon->hello, message, msize); + + if (daemon->th != NULL) + { + GNUNET_TRANSPORT_disconnect (daemon->th); + daemon->th = NULL; + } + daemon->phase = SP_START_DONE; +} + + +/** + * Notify of a peer being up and running. Scheduled as a task + * so that variables which may need to be set are set before + * the connect callback can set up new operations. + * FIXME: what variables?????? where from???? + * + * @param cls the testing daemon + * @param tc task scheduler context + */ +static void +notify_daemon_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_Daemon *d = cls; + GNUNET_TESTING_NotifyDaemonRunning cb; + + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, &d->id, d->cfg, d, NULL); +} + + +/** + * Finite-state machine for starting GNUnet. + * + * @param cls our "struct GNUNET_TESTING_Daemon" + * @param tc unused + */ +static void +start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_Daemon *d = cls; + GNUNET_TESTING_NotifyDaemonRunning cb; + enum GNUNET_OS_ProcessStatusType type; + unsigned long code; + char *dst; + int bytes_read; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %s FSM is in phase %u.\n", + GNUNET_i2s (&d->id), d->phase); + d->task = GNUNET_SCHEDULER_NO_TASK; + switch (d->phase) + { + case SP_COPYING: + /* confirm copying complete */ + if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + _ + ("`scp' does not seem to terminate (timeout copying config).\n")); + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, _("`scp' did not complete cleanly.\n")); + return; + } + GNUNET_OS_process_close (d->proc); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully copied configuration file.\n"); + d->phase = SP_COPIED; + /* fall-through */ + case SP_COPIED: + /* Start create hostkey process if we don't already know the peer identity! */ + if (GNUNET_NO == d->have_hostkey) + { + d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_YES); + if (d->pipe_stdout == NULL) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? + _("Failed to create pipe for `gnunet-peerinfo' process.\n") : + _("Failed to create pipe for `ssh' process.\n")); + return; + } + if (NULL == d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting `%s', with command `%s %s %s %s'.\n", + "gnunet-peerinfo", "gnunet-peerinfo", "-c", d->cfgfile, + "-sq"); + d->proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, d->pipe_stdout, "gnunet-peerinfo", + "gnunet-peerinfo", "-c", d->cfgfile, "-sq", + NULL); + GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); + } + else + { + if (d->username != NULL) + GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname); + else + dst = GNUNET_strdup (d->hostname); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting `%s', with command `%s %s %s %s %s %s'.\n", + "gnunet-peerinfo", "ssh", dst, "gnunet-peerinfo", "-c", + d->cfgfile, "-sq"); + if (d->ssh_port_str == NULL) + { + d->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, d->pipe_stdout, "ssh", "ssh", +#if !DEBUG_TESTING + "-q", +#endif + dst, "gnunet-peerinfo", "-c", + d->cfgfile, "-sq", NULL); + } + else + { + d->proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, d->pipe_stdout, "ssh", "ssh", "-p", + d->ssh_port_str, +#if !DEBUG_TESTING + "-q", +#endif + dst, "gnunet-peerinfo", "-c", d->cfgfile, + "-sq", NULL); + } + GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); + GNUNET_free (dst); + } + if (NULL == d->proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not start `%s' process to create hostkey.\n"), + (NULL == d->hostname) ? "gnunet-peerinfo" : "ssh"); + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? _("Failed to start `gnunet-peerinfo' process.\n") + : _("Failed to start `ssh' process.\n")); + GNUNET_DISK_pipe_close (d->pipe_stdout); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Started `%s', waiting for hostkey.\n", "gnunet-peerinfo"); + d->phase = SP_HOSTKEY_CREATE; + d->task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining + (d->max_timeout), + GNUNET_DISK_pipe_handle + (d->pipe_stdout, + GNUNET_DISK_PIPE_END_READ), + &start_fsm, d); + } + else /* Already have a hostkey! */ + { + if (d->hostkey_callback != NULL) + { + d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL); + d->hostkey_callback = NULL; + d->phase = SP_HOSTKEY_CREATED; + } + else + d->phase = SP_TOPOLOGY_SETUP; + + /* wait some more */ + d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); + } + break; + case SP_HOSTKEY_CREATE: + bytes_read = + GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle + (d->pipe_stdout, GNUNET_DISK_PIPE_END_READ), + &d->hostkeybuf[d->hostkeybufpos], + sizeof (d->hostkeybuf) - d->hostkeybufpos); + if (bytes_read > 0) + d->hostkeybufpos += bytes_read; + + if ((d->hostkeybufpos < 104) && (bytes_read > 0)) + { + /* keep reading */ + d->task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining + (d->max_timeout), + GNUNET_DISK_pipe_handle + (d->pipe_stdout, + GNUNET_DISK_PIPE_END_READ), + &start_fsm, d); + return; + } + d->hostkeybuf[103] = '\0'; + + if ((bytes_read < 0) || + (GNUNET_OK != + GNUNET_CRYPTO_hash_from_string (d->hostkeybuf, &d->id.hashPubKey))) + { + /* error */ + if (bytes_read < 0) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Error reading from gnunet-peerinfo: %s\n"), + STRERROR (errno)); + else + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Malformed output from gnunet-peerinfo!\n")); + cb = d->cb; + d->cb = NULL; + GNUNET_DISK_pipe_close (d->pipe_stdout); + d->pipe_stdout = NULL; + (void) GNUNET_OS_process_kill (d->proc, SIGKILL); + GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc)); + GNUNET_OS_process_close (d->proc); + d->proc = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, _("Failed to get hostkey!\n")); + return; + } + d->shortname = GNUNET_strdup (GNUNET_i2s (&d->id)); + GNUNET_DISK_pipe_close (d->pipe_stdout); + d->pipe_stdout = NULL; + (void) GNUNET_OS_process_kill (d->proc, SIGKILL); + GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc)); + GNUNET_OS_process_close (d->proc); + d->proc = NULL; + d->have_hostkey = GNUNET_YES; + if (d->hostkey_callback != NULL) + { + d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL); + d->hostkey_callback = NULL; + d->phase = SP_HOSTKEY_CREATED; + } + else + { + d->phase = SP_TOPOLOGY_SETUP; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully got hostkey!\n"); + /* Fall through */ + case SP_HOSTKEY_CREATED: + /* wait for topology finished */ + if ((GNUNET_YES == d->dead) || + (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + _("`Failed while waiting for topology setup!\n")); + return; + } + + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + break; + case SP_TOPOLOGY_SETUP: /* Indicates topology setup has completed! */ + /* start GNUnet on remote host */ + if (NULL == d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting `%s', with command `%s %s %s %s %s %s'.\n", + "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, "-L", "DEBUG", + "-s"); + d->proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", "-c", + d->cfgfile, + "-L", "DEBUG", + "-s", "-q", "-T", + GNUNET_TIME_relative_to_string + (GNUNET_TIME_absolute_get_remaining + (d->max_timeout)), NULL); + } + else + { + if (d->username != NULL) + GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname); + else + dst = GNUNET_strdup (d->hostname); + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Starting `%s', with command `%s %s %s %s %s %s %s %s'.\n", + "gnunet-arm", "ssh", dst, "gnunet-arm", "-c", d->cfgfile, + "-L", "DEBUG", "-s", "-q"); + if (d->ssh_port_str == NULL) + { + d->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", +#if !DEBUG_TESTING + "-q", +#endif + dst, "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-s", "-q", "-T", + GNUNET_TIME_relative_to_string + (GNUNET_TIME_absolute_get_remaining + (d->max_timeout)), NULL); + } + else + { + + d->proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-p", + d->ssh_port_str, +#if !DEBUG_TESTING + "-q", +#endif + dst, "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-s", "-q", "-T", + GNUNET_TIME_relative_to_string + (GNUNET_TIME_absolute_get_remaining + (d->max_timeout)), NULL); + } + GNUNET_free (dst); + } + if (NULL == d->proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not start `%s' process to start GNUnet.\n"), + (NULL == d->hostname) ? "gnunet-arm" : "ssh"); + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? _("Failed to start `gnunet-arm' process.\n") : + _("Failed to start `ssh' process.\n")); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Started `%s', waiting for `%s' to be up.\n", "gnunet-arm", + "gnunet-service-core"); + d->phase = SP_START_ARMING; + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + break; + case SP_START_ARMING: + if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : + _("`ssh' does not seem to terminate.\n")); + if (d->cfg != NULL) + { + GNUNET_CONFIGURATION_destroy (d->cfg); + d->cfg = NULL; + } + if (d->cfgfile != NULL) + { + GNUNET_free (d->cfgfile); + d->cfgfile = NULL; + } + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + GNUNET_free (d->proc); +// GNUNET_free (d); // FIXME (could this leak) + d->hostname = NULL; // Quick hack to avoid crashing (testing need to be + d->cfg = NULL; // overhauled anyway, and the error managing is + // pretty broken anyway. + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully started `%s'.\n", + "gnunet-arm"); + GNUNET_free (d->proc); + d->phase = SP_START_CORE; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling CORE_connect\n"); + /* Fall through */ + case SP_START_CORE: + if (d->server != NULL) + GNUNET_CORE_disconnect (d->server); + + d->th = GNUNET_TRANSPORT_connect (d->cfg, &d->id, d, NULL, NULL, NULL); + if (d->th == NULL) + { + if (GNUNET_YES == d->dead) + GNUNET_TESTING_daemon_stop (d, + GNUNET_TIME_absolute_get_remaining + (d->max_timeout), d->dead_cb, + d->dead_cb_cls, GNUNET_YES, GNUNET_NO); + else if (NULL != d->cb) + d->cb (d->cb_cls, &d->id, d->cfg, d, + _("Failed to connect to transport service!\n")); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected to transport service `%s', getting HELLO\n", + GNUNET_i2s (&d->id)); + d->ghh = GNUNET_TRANSPORT_get_hello (d->th, &process_hello, d); + /* FIXME: store task ID somewhere! */ + GNUNET_SCHEDULER_add_now (¬ify_daemon_started, d); + /*cb = d->cb; + * d->cb = NULL; + * if (NULL != cb) + * cb (d->cb_cls, &d->id, d->cfg, d, NULL); */ + d->running = GNUNET_YES; + d->phase = SP_GET_HELLO; + break; + case SP_GET_HELLO: + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + if (d->server != NULL) + GNUNET_CORE_disconnect (d->server); + if (d->th != NULL) + GNUNET_TRANSPORT_disconnect (d->th); + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, _("Unable to get HELLO for peer!\n")); + GNUNET_CONFIGURATION_destroy (d->cfg); + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + GNUNET_free (d); + return; + } + if (d->hello != NULL) + return; + GNUNET_assert (d->task == GNUNET_SCHEDULER_NO_TASK); + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_CONSTANTS_SERVICE_RETRY, 2), + &start_fsm, d); + break; + case SP_START_DONE: + GNUNET_break (0); + break; + case SP_SERVICE_START: + /* confirm gnunet-arm exited */ + if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : + _("`ssh' does not seem to terminate.\n")); + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } +#if EXTRA_CHECKS + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? + _ + ("`gnunet-arm' terminated with non-zero exit status (or timed out)!\n") + : _("`ssh' does not seem to terminate.\n")); + return; + } +#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service startup complete!\n"); + cb = d->cb; + d->cb = NULL; + d->phase = SP_START_DONE; + if (NULL != cb) + cb (d->cb_cls, &d->id, d->cfg, d, NULL); + break; + case SP_SERVICE_SHUTDOWN_START: + /* confirm copying complete */ + if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, + _ + ("either `gnunet-arm' or `ssh' does not seem to terminate.\n")); + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } +#if EXTRA_CHECKS + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + { + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, + _ + ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n")); + return; + } +#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n"); + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, NULL); + break; + case SP_SHUTDOWN_START: + /* confirm copying complete */ + if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, + _ + ("either `gnunet-arm' or `ssh' does not seem to terminate.\n")); + if (d->th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (d->ghh); + d->ghh = NULL; + GNUNET_TRANSPORT_disconnect (d->th); + d->th = NULL; + } + if (d->cfg != NULL) + { + GNUNET_CONFIGURATION_destroy (d->cfg); + d->cfg = NULL; + } + if (d->cfgfile != NULL) + { + GNUNET_free (d->cfgfile); + d->cfgfile = NULL; + } + GNUNET_free_non_null (d->hello); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + GNUNET_free_non_null (d->shortname); + GNUNET_free_non_null (d->proc); + d->proc = NULL; + GNUNET_free (d); + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + { + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, + _ + ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n")); + if (d->th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (d->ghh); + d->ghh = NULL; + GNUNET_TRANSPORT_disconnect (d->th); + d->th = NULL; + } + if (d->server != NULL) + { + GNUNET_CORE_disconnect (d->server); + d->server = NULL; + } + GNUNET_CONFIGURATION_destroy (d->cfg); + d->cfg = NULL; + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hello); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + GNUNET_free_non_null (d->shortname); + GNUNET_free_non_null (d->proc); + d->proc = NULL; + GNUNET_free (d); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer shutdown complete.\n"); + if (d->server != NULL) + { + GNUNET_CORE_disconnect (d->server); + d->server = NULL; + } + + if (d->th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (d->ghh); + d->ghh = NULL; + GNUNET_TRANSPORT_disconnect (d->th); + d->th = NULL; + } + + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, NULL); + + /* state clean up and notifications */ + if (d->churn == GNUNET_NO) + { + GNUNET_CONFIGURATION_destroy (d->cfg); + d->cfg = NULL; + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + } + + GNUNET_free_non_null (d->hello); + d->hello = NULL; + GNUNET_free_non_null (d->shortname); + GNUNET_free_non_null (d->proc); + d->proc = NULL; + d->shortname = NULL; + if (d->churn == GNUNET_NO) + GNUNET_free (d); + + break; + case SP_CONFIG_UPDATE: + /* confirm copying complete */ + if (GNUNET_OK != GNUNET_OS_process_status (d->proc, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) /* FIXME: config update should take timeout parameter! */ + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + _("`scp' does not seem to terminate.\n")); + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + { + if (NULL != d->update_cb) + d->update_cb (d->update_cb_cls, _("`scp' did not complete cleanly.\n")); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully copied configuration file.\n"); + if (NULL != d->update_cb) + d->update_cb (d->update_cb_cls, NULL); + d->phase = SP_START_DONE; + break; + } +} + +/** + * Continues GNUnet daemon startup when user wanted to be notified + * once a hostkey was generated (for creating friends files, blacklists, + * etc.). + * + * @param daemon the daemon to finish starting + */ +void +GNUNET_TESTING_daemon_continue_startup (struct GNUNET_TESTING_Daemon *daemon) +{ + GNUNET_assert (daemon->phase == SP_HOSTKEY_CREATED); + daemon->phase = SP_TOPOLOGY_SETUP; +} + +/** + * Check whether the given daemon is running. + * + * @param daemon the daemon to check + * + * @return GNUNET_YES if the daemon is up, GNUNET_NO if the + * daemon is down, GNUNET_SYSERR on error. + */ +int +GNUNET_TESTING_test_daemon_running (struct GNUNET_TESTING_Daemon *daemon) +{ + if (daemon == NULL) + return GNUNET_SYSERR; + + if (daemon->running == GNUNET_YES) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Starts a GNUnet daemon service which has been previously stopped. + * + * @param d the daemon for which the service should be started + * @param service the name of the service to start + * @param timeout how long to wait for process for shutdown to complete + * @param cb function called once the service starts + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_start_stopped_service (struct GNUNET_TESTING_Daemon *d, + char *service, + struct GNUNET_TIME_Relative + timeout, + GNUNET_TESTING_NotifyDaemonRunning + cb, void *cb_cls) +{ + char *arg; + + d->cb = cb; + d->cb_cls = cb_cls; + + GNUNET_assert (d->running == GNUNET_YES); + + if (d->phase == SP_CONFIG_UPDATE) + { + GNUNET_SCHEDULER_cancel (d->task); + d->phase = SP_START_DONE; + } + + if (d->churned_services == NULL) + { + d->cb (d->cb_cls, &d->id, d->cfg, d, + "No service has been churned off yet!!"); + return; + } + d->phase = SP_SERVICE_START; + GNUNET_free (d->churned_services); + d->churned_services = NULL; + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + /* Check if this is a local or remote process */ + if (NULL != d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with config `%s' on host `%s'.\n", + d->cfgfile, d->hostname); + if (d->username != NULL) + GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); + else + arg = GNUNET_strdup (d->hostname); + + d->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", +#if !DEBUG_TESTING + "-q", +#endif + arg, "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-i", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q\n", + arg, "gnunet-arm", d->cfgfile, service); + GNUNET_free (arg); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile); + d->proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-i", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + } + + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); +} + +/** + * Starts a GNUnet daemon's service. + * + * @param d the daemon for which the service should be started + * @param service the name of the service to start + * @param timeout how long to wait for process for startup + * @param cb function called once gnunet-arm returns + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_start_service (struct GNUNET_TESTING_Daemon *d, + const char *service, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls) +{ + char *arg; + + d->cb = cb; + d->cb_cls = cb_cls; + + GNUNET_assert (service != NULL); + GNUNET_assert (d->running == GNUNET_YES); + GNUNET_assert (d->phase == SP_START_DONE); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Starting service %s for peer `%4s'\n"), service, + GNUNET_i2s (&d->id)); + d->phase = SP_SERVICE_START; + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + /* Check if this is a local or remote process */ + if (NULL != d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with config `%s' on host `%s'.\n", + d->cfgfile, d->hostname); + if (d->username != NULL) + GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); + else + arg = GNUNET_strdup (d->hostname); + + d->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", +#if !DEBUG_TESTING + "-q", +#endif + arg, "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-i", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q -T %s\n", + arg, "gnunet-arm", d->cfgfile, service, + GNUNET_TIME_relative_to_string (timeout)); + GNUNET_free (arg); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile); + d->proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-i", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with command %s -c %s -i %s -q -T %s\n", + "gnunet-arm", d->cfgfile, service, + GNUNET_TIME_relative_to_string (timeout)); + } + + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); +} + +/** + * Start a peer that has previously been stopped using the daemon_stop + * call (and files weren't deleted and the allow restart flag) + * + * @param daemon the daemon to start (has been previously stopped) + * @param timeout how long to wait for restart + * @param cb the callback for notification when the peer is running + * @param cb_cls closure for the callback + */ +void +GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls) +{ + if (daemon->running == GNUNET_YES) + { + cb (cb_cls, &daemon->id, daemon->cfg, daemon, + "Daemon already running, can't restart!"); + return; + } + + daemon->cb = cb; + daemon->cb_cls = cb_cls; + daemon->phase = SP_TOPOLOGY_SETUP; + daemon->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + /* FIXME: why add_continuation? */ + GNUNET_SCHEDULER_add_continuation (&start_fsm, daemon, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + +/** + * Starts a GNUnet daemon. GNUnet must be installed on the target + * system and available in the PATH. The machine must furthermore be + * reachable via "ssh" (unless the hostname is "NULL") without the + * need to enter a password. + * + * @param cfg configuration to use + * @param timeout how long to wait starting up peers + * @param pretend GNUNET_YES to set up files but not start peer GNUNET_NO + * to really start the peer (default) + * @param hostname name of the machine where to run GNUnet + * (use NULL for localhost). + * @param ssh_username ssh username to use when connecting to hostname + * @param sshport port to pass to ssh process when connecting to hostname + * @param hostkey pointer to a hostkey to be written to disk (instead of being generated) + * @param hostkey_callback function to call once the hostkey has been + * generated for this peer, but it hasn't yet been started + * (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start) + * @param hostkey_cls closure for hostkey callback + * @param cb function to call once peer is up, or failed to start + * @param cb_cls closure for cb + * @return handle to the daemon (actual start will be completed asynchronously) + */ +struct GNUNET_TESTING_Daemon * +GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TIME_Relative timeout, int pretend, + const char *hostname, const char *ssh_username, + uint16_t sshport, const char *hostkey, + GNUNET_TESTING_NotifyHostkeyCreated + hostkey_callback, void *hostkey_cls, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls) +{ + struct GNUNET_TESTING_Daemon *ret; + char *arg; + char *username; + char *servicehome; + char *baseservicehome; + char *slash; + char *hostkeyfile; + char *temp_file_name; + struct GNUNET_DISK_FileHandle *fn; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + struct GNUNET_CRYPTO_RsaPrivateKey *private_key; + + ret = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Daemon)); + ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname); + if (sshport != 0) + { + GNUNET_asprintf (&ret->ssh_port_str, "%d", sshport); + } + else + ret->ssh_port_str = NULL; + + /* Find service home and base service home directories, create it if it doesn't exist */ + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", + "SERVICEHOME", + &servicehome)); + + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create (servicehome)); + GNUNET_asprintf (&temp_file_name, "%s/gnunet-testing-config", servicehome); + ret->cfgfile = GNUNET_DISK_mktemp (temp_file_name); + GNUNET_free (temp_file_name); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setting up peer with configuration file `%s'.\n", ret->cfgfile); + if (NULL == ret->cfgfile) + { + GNUNET_free_non_null (ret->ssh_port_str); + GNUNET_free_non_null (ret->hostname); + GNUNET_free (ret); + return NULL; + } + ret->hostkey_callback = hostkey_callback; + ret->hostkey_cls = hostkey_cls; + ret->cb = cb; + ret->cb_cls = cb_cls; + ret->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + ret->cfg = GNUNET_CONFIGURATION_dup (cfg); + GNUNET_CONFIGURATION_set_value_string (ret->cfg, "PATHS", "DEFAULTCONFIG", + ret->cfgfile); + + if (hostkey != NULL) /* Get the peer identity from the hostkey */ + { + private_key = GNUNET_CRYPTO_rsa_decode_key (hostkey, HOSTKEYFILESIZE); + GNUNET_assert (private_key != NULL); + GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key); + GNUNET_CRYPTO_hash (&public_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &ret->id.hashPubKey); + ret->shortname = GNUNET_strdup (GNUNET_i2s (&ret->id)); + ret->have_hostkey = GNUNET_YES; + GNUNET_CRYPTO_rsa_key_free (private_key); + } + + /* Write hostkey to file, if we were given one */ + hostkeyfile = NULL; + if (hostkey != NULL) + { + GNUNET_asprintf (&hostkeyfile, "%s/.hostkey", servicehome); + fn = GNUNET_DISK_file_open (hostkeyfile, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + GNUNET_assert (fn != NULL); + GNUNET_assert (HOSTKEYFILESIZE == + GNUNET_DISK_file_write (fn, hostkey, HOSTKEYFILESIZE)); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fn)); + } + + /* write configuration to temporary file */ + if (GNUNET_OK != GNUNET_CONFIGURATION_write (ret->cfg, ret->cfgfile)) + { + if (0 != UNLINK (ret->cfgfile)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", + ret->cfgfile); + GNUNET_CONFIGURATION_destroy (ret->cfg); + GNUNET_free_non_null (ret->hostname); + GNUNET_free (ret->cfgfile); + GNUNET_free (ret); + return NULL; + } + if (ssh_username != NULL) + username = GNUNET_strdup (ssh_username); + if ((ssh_username == NULL) && + (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "USERNAME", + &username))) + { + if (NULL != getenv ("USER")) + username = GNUNET_strdup (getenv ("USER")); + else + username = NULL; + } + ret->username = username; + + if (GNUNET_NO == pretend) /* Copy files, enter finite state machine */ + { + /* copy directory to remote host */ + if (NULL != hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copying configuration directory to host `%s'.\n", hostname); + baseservicehome = GNUNET_strdup (servicehome); + /* Remove trailing /'s */ + while (baseservicehome[strlen (baseservicehome) - 1] == '/') + baseservicehome[strlen (baseservicehome) - 1] = '\0'; + /* Find next directory /, jump one ahead */ + slash = strrchr (baseservicehome, '/'); + if (slash != NULL) + *(++slash) = '\0'; + + ret->phase = SP_COPYING; + if (NULL != username) + GNUNET_asprintf (&arg, "%s@%s:%s", username, hostname, baseservicehome); + else + GNUNET_asprintf (&arg, "%s:%s", hostname, baseservicehome); + GNUNET_free (baseservicehome); + if (ret->ssh_port_str == NULL) + { + ret->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-r", +#if !DEBUG_TESTING + "-q", +#endif + servicehome, arg, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "copying directory with command scp -r %s %s\n", + servicehome, arg); + } + else + { + ret->proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-r", "-P", + ret->ssh_port_str, +#if !DEBUG_TESTING + "-q", +#endif + servicehome, arg, NULL); + } + GNUNET_free (arg); + if (NULL == ret->proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Could not start `%s' process to copy configuration directory.\n"), + "scp"); + if (0 != UNLINK (ret->cfgfile)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", + ret->cfgfile); + GNUNET_CONFIGURATION_destroy (ret->cfg); + GNUNET_free_non_null (ret->hostname); + GNUNET_free_non_null (ret->username); + GNUNET_free (ret->cfgfile); + GNUNET_free (ret); + if ((hostkey != NULL) && (0 != UNLINK (hostkeyfile))) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", + hostkeyfile); + GNUNET_free_non_null (hostkeyfile); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (servicehome)); + GNUNET_free (servicehome); + return NULL; + } + + ret->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + ret); + GNUNET_free_non_null (hostkeyfile); + GNUNET_free (servicehome); + return ret; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No need to copy configuration file since we are running locally.\n"); + ret->phase = SP_COPIED; + /* FIXME: why add_cont? */ + GNUNET_SCHEDULER_add_continuation (&start_fsm, ret, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + } + GNUNET_free_non_null (hostkeyfile); + GNUNET_free (servicehome); + return ret; +} + + +/** + * Restart (stop and start) a GNUnet daemon. + * + * @param d the daemon that should be restarted + * @param cb function called once the daemon is (re)started + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls) +{ + char *arg; + char *del_arg; + + del_arg = NULL; + if (NULL != d->cb) + { + d->dead = GNUNET_YES; + return; + } + + d->cb = cb; + d->cb_cls = cb_cls; + + if (d->phase == SP_CONFIG_UPDATE) + { + GNUNET_SCHEDULER_cancel (d->task); + d->phase = SP_START_DONE; + } + if (d->server != NULL) + { + GNUNET_CORE_disconnect (d->server); + d->server = NULL; + } + + if (d->th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (d->ghh); + d->ghh = NULL; + GNUNET_TRANSPORT_disconnect (d->th); + d->th = NULL; + } + /* state clean up and notifications */ + GNUNET_free_non_null (d->hello); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"), + GNUNET_i2s (&d->id)); + d->phase = SP_START_ARMING; + + /* Check if this is a local or remote process */ + if (NULL != d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' on host `%s'.\n", + d->cfgfile, d->hostname); + if (d->username != NULL) + GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); + else + arg = GNUNET_strdup (d->hostname); + + d->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", +#if !DEBUG_TESTING + "-q", +#endif + arg, "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-e", "-r", NULL); + /* Use -r to restart arm and all services */ + + GNUNET_free (arg); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); + d->proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-e", "-r", NULL); + } + + GNUNET_free_non_null (del_arg); + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); + +} + + +/** + * Stops a GNUnet daemon. + * + * @param d the daemon that should be stopped + * @param service the name of the service to stop + * @param timeout how long to wait for process for shutdown to complete + * @param cb function called once the daemon was stopped + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_stop_service (struct GNUNET_TESTING_Daemon *d, + const char *service, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, + void *cb_cls) +{ + char *arg; + + d->dead_cb = cb; + d->dead_cb_cls = cb_cls; + + GNUNET_assert (d->running == GNUNET_YES); + + if (d->phase == SP_CONFIG_UPDATE) + { + GNUNET_SCHEDULER_cancel (d->task); + d->phase = SP_START_DONE; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"), + GNUNET_i2s (&d->id)); + if (d->churned_services != NULL) + { + d->dead_cb (d->dead_cb_cls, "A service has already been turned off!!"); + return; + } + d->phase = SP_SERVICE_SHUTDOWN_START; + d->churned_services = GNUNET_strdup (service); + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + /* Check if this is a local or remote process */ + if (NULL != d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' on host `%s'.\n", + d->cfgfile, d->hostname); + if (d->username != NULL) + GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); + else + arg = GNUNET_strdup (d->hostname); + + d->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", +#if !DEBUG_TESTING + "-q", +#endif + arg, "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-k", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -k %s -q\n", + arg, "gnunet-arm", d->cfgfile, service); + GNUNET_free (arg); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); + d->proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-k", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + } + + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); +} + + +/** + * Stops a GNUnet daemon. + * + * @param d the daemon that should be stopped + * @param timeout how long to wait for process for shutdown to complete + * @param cb function called once the daemon was stopped + * @param cb_cls closure for cb + * @param delete_files GNUNET_YES to remove files, GNUNET_NO + * to leave them + * @param allow_restart GNUNET_YES to restart peer later (using this API) + * GNUNET_NO to kill off and clean up for good + */ +void +GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls, + int delete_files, int allow_restart) +{ + char *arg; + char *del_arg; + + d->dead_cb = cb; + d->dead_cb_cls = cb_cls; + + if (NULL != d->cb) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Setting d->dead on peer `%4s'\n"), + GNUNET_i2s (&d->id)); + d->dead = GNUNET_YES; + return; + } + + if ((d->running == GNUNET_NO) && (d->churn == GNUNET_YES)) /* Peer has already been stopped in churn context! */ + { + /* Free what was left from churning! */ + GNUNET_assert (d->cfg != NULL); + GNUNET_CONFIGURATION_destroy (d->cfg); + if (delete_files == GNUNET_YES) + { + if (0 != UNLINK (d->cfgfile)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "unlink"); + } + } + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, NULL); + GNUNET_free (d); + return; + } + + del_arg = NULL; + if (delete_files == GNUNET_YES) + { + GNUNET_asprintf (&del_arg, "-d"); + } + + if (d->phase == SP_CONFIG_UPDATE) + { + GNUNET_SCHEDULER_cancel (d->task); + d->phase = SP_START_DONE; + } + /** Move this call to scheduled shutdown as fix for CORE_connect calling daemon_stop? + if (d->server != NULL) + { + GNUNET_CORE_disconnect (d->server); + d->server = NULL; + } + */ + /* shutdown ARM process (will terminate others) */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Terminating peer `%4s'\n" , + GNUNET_i2s (&d->id)); + d->phase = SP_SHUTDOWN_START; + d->running = GNUNET_NO; + if (allow_restart == GNUNET_YES) + d->churn = GNUNET_YES; + if (d->th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (d->ghh); + d->ghh = NULL; + GNUNET_TRANSPORT_disconnect (d->th); + d->th = NULL; + } + /* Check if this is a local or remote process */ + if (NULL != d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' on host `%s'.\n", + d->cfgfile, d->hostname); + if (d->username != NULL) + GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); + else + arg = GNUNET_strdup (d->hostname); + + d->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", +#if !DEBUG_TESTING + "-q", +#endif + arg, "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-e", "-q", "-T", + GNUNET_TIME_relative_to_string (timeout), + del_arg, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -e -q %s\n", + arg, "gnunet-arm", d->cfgfile, del_arg); + /* Use -e to end arm, and -d to remove temp files */ + GNUNET_free (arg); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); + d->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "gnunet-arm", "gnunet-arm", +#if DEBUG_TESTING + "-L", "DEBUG", +#endif + "-c", d->cfgfile, "-e", "-q", "-T", + GNUNET_TIME_relative_to_string (timeout), + del_arg, NULL); + GNUNET_assert (NULL != d->proc); + } + + GNUNET_free_non_null (del_arg); + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + if (GNUNET_SCHEDULER_NO_TASK != d->task) + GNUNET_SCHEDULER_cancel(d->task); + d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); +} + + +/** + * Changes the configuration of a GNUnet daemon. + * + * @param d the daemon that should be modified + * @param cfg the new configuration for the daemon + * @param cb function called once the configuration was changed + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d, + struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_TESTING_NotifyCompletion cb, + void *cb_cls) +{ + char *arg; + + if (d->phase != SP_START_DONE) + { + if (NULL != cb) + cb (cb_cls, + _ + ("Peer not yet running, can not change configuration at this point.")); + return; + } + + /* 1) write configuration to temporary file */ + if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile)) + { + if (NULL != cb) + cb (cb_cls, _("Failed to write new configuration to disk.")); + return; + } + + /* 2) copy file to remote host (if necessary) */ + if (NULL == d->hostname) + { + /* signal success */ + if (NULL != cb) + cb (cb_cls, NULL); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copying updated configuration file to remote host `%s'.\n", + d->hostname); + d->phase = SP_CONFIG_UPDATE; + if (NULL != d->username) + GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile); + else + GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile); + d->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", +#if !DEBUG_TESTING + "-q", +#endif + d->cfgfile, arg, NULL); + GNUNET_free (arg); + if (NULL == d->proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not start `%s' process to copy configuration file.\n"), + "scp"); + if (NULL != cb) + cb (cb_cls, _("Failed to copy new configuration to remote machine.")); + d->phase = SP_START_DONE; + return; + } + d->update_cb = cb; + d->update_cb_cls = cb_cls; + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); +} + + +/** + * Data kept for each pair of peers that we try + * to connect. + */ +struct GNUNET_TESTING_ConnectContext +{ + /** + * Testing handle to the first daemon. + */ + struct GNUNET_TESTING_Daemon *d1; + + /** + * Handle to core of first daemon (to check connect) + */ + struct GNUNET_CORE_Handle *d1core; + + /** + * Have we actually connected to the core of the first daemon yet? + */ + int d1core_ready; + + /** + * Testing handle to the second daemon. + */ + struct GNUNET_TESTING_Daemon *d2; + + /** + * Transport handle to the first daemon (to offer the HELLO of the second daemon to). + */ + struct GNUNET_TRANSPORT_Handle *d1th; + + /** + * Function to call once we are done (or have timed out). + */ + GNUNET_TESTING_NotifyConnection cb; + + /** + * Closure for "nb". + */ + void *cb_cls; + + /** + * The relative timeout from whence this connect attempt was + * started. Allows for reconnect attempts. + */ + struct GNUNET_TIME_Relative relative_timeout; + + /** + * Maximum number of connect attempts, will retry connection + * this number of times on failures. + */ + unsigned int connect_attempts; + + /** + * Hello timeout task + */ + GNUNET_SCHEDULER_TaskIdentifier hello_send_task; + + /** + * Connect timeout task + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * When should this operation be complete (or we must trigger + * a timeout). + */ + struct GNUNET_TIME_Relative timeout_hello; + + /** + * Was the connection attempt successful? + */ + int connected; + + /** + * When connecting, do we need to send the HELLO? + */ + int send_hello; + + /** + * The distance between the two connected peers + */ + uint32_t distance; +}; + + +/** Forward declaration **/ +static void +reattempt_daemons_connect (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Notify callback about success or failure of the attempt + * to connect the two peers + * + * @param cls our "struct GNUNET_TESTING_ConnectContext" (freed) + * @param tc reason tells us if we succeeded or failed + */ +static void +notify_connect_result (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_ConnectContext *ctx = cls; + + ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; + if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ctx->hello_send_task); + ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (ctx->d1th != NULL) + GNUNET_TRANSPORT_disconnect (ctx->d1th); + ctx->d1th = NULL; + if (ctx->d1core != NULL) + GNUNET_CORE_disconnect (ctx->d1core); + ctx->d1core = NULL; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + GNUNET_free (ctx); + return; + } + + if (ctx->connected == GNUNET_YES) + { + if (ctx->cb != NULL) + { + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->distance, + ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL); + } + } + else if (ctx->connect_attempts > 0) + { + ctx->d1core_ready = GNUNET_NO; + ctx->timeout_task = + GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx); + return; + } + else + { + if (ctx->cb != NULL) + { + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, + ctx->d2->cfg, ctx->d1, ctx->d2, _("Peers failed to connect")); + } + } + GNUNET_free (ctx); +} + + +/** + * Success, connection is up. Signal client our success. + * + * @param cls our "struct GNUNET_TESTING_ConnectContext" + * @param peer identity of the peer that has connected + * @param atsi performance information + * @param atsi_count number of records in 'atsi' + * + */ +static void +connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_TESTING_ConnectContext *ctx = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to peer %s\n", + ctx->d1->shortname, GNUNET_i2s (peer)); + if (0 != memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + ctx->connected = GNUNET_YES; + ctx->distance = 0; /* FIXME: distance */ + if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ctx->hello_send_task); + ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_SCHEDULER_cancel (ctx->timeout_task); + ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); +} + + +static void +send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_ConnectContext *ctx = cls; + struct GNUNET_MessageHeader *hello; + + ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + if ((ctx->d1core_ready == GNUNET_YES) && (ctx->d2->hello != NULL) && + (NULL != GNUNET_HELLO_get_header (ctx->d2->hello)) && + (ctx->d1->phase == SP_START_DONE) && (ctx->d2->phase == SP_START_DONE)) + { + hello = GNUNET_HELLO_get_header (ctx->d2->hello); + GNUNET_assert (hello != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Offering hello of %s to %s\n", + ctx->d2->shortname, ctx->d1->shortname); + GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL); + GNUNET_assert (ctx->d1core != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending connect request to TRANSPORT of %s for peer %s\n", + GNUNET_i2s (&ctx->d1->id), + GNUNET_h2s (&ctx->d2->id.hashPubKey)); + GNUNET_TRANSPORT_try_connect (ctx->d1th, &ctx->d2->id); + ctx->timeout_hello = + GNUNET_TIME_relative_add (ctx->timeout_hello, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 500)); + } + ctx->hello_send_task = + GNUNET_SCHEDULER_add_delayed (ctx->timeout_hello, &send_hello, ctx); +} + +/** + * Notify of a successful connection to the core service. + * + * @param cls a ConnectContext + * @param server handle to the core service + * @param my_identity the peer identity of this peer + */ +void +core_init_notify (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct GNUNET_TESTING_ConnectContext *connect_ctx = cls; + + connect_ctx->d1core_ready = GNUNET_YES; + + if (connect_ctx->send_hello == GNUNET_NO) + { + GNUNET_TRANSPORT_try_connect (connect_ctx->d1th, &connect_ctx->d2->id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending connect request to TRANSPORT of %s for peer %s\n", + connect_ctx->d1->shortname, connect_ctx->d2->shortname); + } +} + + +/** + * Try to connect again some peers that failed in an earlier attempt. This will + * be tried as many times as connection_attempts in the configuration file. + * + * @param cls Closure (connection context between the two peers). + * @param tc TaskContext. + */ +static void +reattempt_daemons_connect (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_ConnectContext *ctx = cls; + + ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "re-attempting connect of peer %s to peer %s\n", + ctx->d1->shortname, ctx->d2->shortname); + ctx->connect_attempts--; + GNUNET_assert (ctx->d1core == NULL); + ctx->d1core_ready = GNUNET_NO; + ctx->d1core = + GNUNET_CORE_connect (ctx->d1->cfg, 1, ctx, &core_init_notify, + &connect_notify, NULL, NULL, GNUNET_NO, NULL, + GNUNET_NO, no_handlers); + if (ctx->d1core == NULL) + { + if (NULL != ctx->cb) + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, + ctx->d2->cfg, ctx->d1, ctx->d2, + _("Failed to connect to core service of first peer!\n")); + GNUNET_free (ctx); + return; + } + + /* Don't know reason for initial connect failure, update the HELLO for the second peer */ + if (NULL != ctx->d2->hello) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "updating %s's HELLO\n", + ctx->d2->shortname); + GNUNET_free (ctx->d2->hello); + ctx->d2->hello = NULL; + if (NULL != ctx->d2->th) + { + GNUNET_TRANSPORT_get_hello_cancel (ctx->d2->ghh); + ctx->d2->ghh = NULL; + GNUNET_TRANSPORT_disconnect (ctx->d2->th); + } + ctx->d2->th = + GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, + NULL); + GNUNET_assert (ctx->d2->th != NULL); + ctx->d2->ghh = + GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "didn't have %s's HELLO\n", + ctx->d2->shortname); + } + + if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "didn't have %s's HELLO, trying to get it now\n", + ctx->d2->shortname); + ctx->d2->th = + GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, + NULL); + if (NULL == ctx->d2->th) + { + GNUNET_CORE_disconnect (ctx->d1core); + GNUNET_free (ctx); + if (NULL != ctx->cb) + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, + ctx->d2->cfg, ctx->d1, ctx->d2, + _("Failed to connect to transport service!\n")); + return; + } + ctx->d2->ghh = + GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); + } + else + { + if (NULL == ctx->d2->hello) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "didn't have %s's HELLO but th wasn't NULL, not trying!!\n", + ctx->d2->shortname); + } + } + + if (ctx->send_hello == GNUNET_YES) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending %s's HELLO to %s\n", + ctx->d1->shortname, ctx->d2->shortname); + ctx->d1th = + GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL, + NULL, NULL); + if (ctx->d1th == NULL) + { + GNUNET_CORE_disconnect (ctx->d1core); + GNUNET_free (ctx); + if (NULL != ctx->cb) + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, + ctx->d2->cfg, ctx->d1, ctx->d2, + _("Failed to connect to transport service!\n")); + return; + } + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task); + ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to reconnect %s to %s\n", + ctx->d1->shortname, ctx->d2->shortname); + GNUNET_TRANSPORT_try_connect (ctx->d1th, &ctx->d2->id); + } + ctx->timeout_task = + GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, + ¬ify_connect_result, ctx); +} + +/** + * Iterator for currently known peers, to ensure + * that we don't try to send duplicate connect + * requests to core. + * + * @param cls our "struct GNUNET_TESTING_ConnectContext" + * @param peer identity of the peer that has connected, + * NULL when iteration has finished + * @param atsi performance information + * @param atsi_count number of records in 'atsi' + * + */ +static void +core_initial_iteration (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_TESTING_ConnectContext *ctx = cls; + + if ((peer != NULL) && + (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)))) + { + ctx->connected = GNUNET_YES; + ctx->distance = 0; /* FIXME: distance */ + return; + } + if (peer != NULL) + return; /* ignore other peers */ + /* peer == NULL: End of iteration over peers */ + + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->timeout_task); + if (ctx->connected == GNUNET_YES) + { + ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); + return; + } + + /* Peer not already connected, need to schedule connect request! */ + if (ctx->d1core == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peers are NOT connected, connecting to core!\n"); + ctx->d1core = + GNUNET_CORE_connect (ctx->d1->cfg, 1, ctx, &core_init_notify, + &connect_notify, NULL, NULL, GNUNET_NO, NULL, + GNUNET_NO, no_handlers); + } + + if (ctx->d1core == NULL) + { + ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); + return; + } + + if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL)) /* Do not yet have the second peer's hello, set up a task to get it */ + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Don't have d2's HELLO, trying to get it!\n"); + ctx->d2->th = + GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, + NULL); + if (ctx->d2->th == NULL) + { + GNUNET_CORE_disconnect (ctx->d1core); + ctx->d1core = NULL; + ctx->timeout_task = + GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); + return; + } + ctx->d2->ghh = + GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); + } + + if (ctx->send_hello == GNUNET_YES) + { + ctx->d1th = + GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL, + NULL, NULL); + if (ctx->d1th == NULL) + { + GNUNET_CORE_disconnect (ctx->d1core); + ctx->d1core = NULL; + ctx->timeout_task = + GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); + return; + } + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task); + ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); + } + + ctx->timeout_task = + GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, + ¬ify_connect_result, ctx); + +} + + +/** + * Establish a connection between two GNUnet daemons. The daemons + * must both be running and not be stopped until either the + * 'cb' callback is called OR the connection request has been + * explicitly cancelled. + * + * @param d1 handle for the first daemon + * @param d2 handle for the second daemon + * @param timeout how long is the connection attempt + * allowed to take? + * @param max_connect_attempts how many times should we try to reconnect + * (within timeout) + * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume + * the HELLO has already been exchanged + * @param cb function to call at the end + * @param cb_cls closure for cb + * @return handle to cancel the request + */ +struct GNUNET_TESTING_ConnectContext * +GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, + struct GNUNET_TESTING_Daemon *d2, + struct GNUNET_TIME_Relative timeout, + unsigned int max_connect_attempts, + int send_hello, + GNUNET_TESTING_NotifyConnection cb, + void *cb_cls) +{ + struct GNUNET_TESTING_ConnectContext *ctx; + + if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO)) + { + if (NULL != cb) + cb (cb_cls, &d1->id, &d2->id, 0, d1->cfg, d2->cfg, d1, d2, + _("Peers are not fully running yet, can not connect!\n")); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peers are not up!\n"); + return NULL; + } + + ctx = GNUNET_malloc (sizeof (struct GNUNET_TESTING_ConnectContext)); + ctx->d1 = d1; + ctx->d2 = d2; + ctx->timeout_hello = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500); + ctx->relative_timeout = + GNUNET_TIME_relative_divide (timeout, max_connect_attempts); + ctx->cb = cb; + ctx->cb_cls = cb_cls; + ctx->connect_attempts = max_connect_attempts; + ctx->connected = GNUNET_NO; + ctx->send_hello = send_hello; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to connect peer %s to peer %s\n", + d1->shortname, d2->shortname); + /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */ + GNUNET_assert (GNUNET_OK == + GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id, + &core_initial_iteration, ctx)); + return ctx; +} + + +/** + * Cancel an attempt to connect two daemons. + * + * @param cc connect context + */ +void +GNUNET_TESTING_daemons_connect_cancel (struct GNUNET_TESTING_ConnectContext *cc) +{ + if (GNUNET_SCHEDULER_NO_TASK != cc->timeout_task) + { + GNUNET_SCHEDULER_cancel (cc->timeout_task); + cc->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != cc->hello_send_task) + { + GNUNET_SCHEDULER_cancel (cc->hello_send_task); + cc->hello_send_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != cc->d1core) + { + GNUNET_CORE_disconnect (cc->d1core); + cc->d1core = NULL; + } + if (NULL != cc->d1th) + { + GNUNET_TRANSPORT_disconnect (cc->d1th); + cc->d1th = NULL; + } + GNUNET_free (cc); +} + + +/* end of testing.c */ diff --git a/src/testing/testing.conf b/src/testing/testing.conf new file mode 100644 index 0000000..7e25f8c --- /dev/null +++ b/src/testing/testing.conf @@ -0,0 +1,11 @@ +[TESTING] +# How long before failing a connection? +CONNECT_TIMEOUT = 30 s +# How many connect attempts should we make? +CONNECT_ATTEMPTS = 3 +# How many connections can happen simultaneously? +MAX_OUTSTANDING_CONNECTIONS = 50 + +# Should we clean up the files on peer group shutdown? +DELETE_FILES = YES + diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c new file mode 100644 index 0000000..2d0e9ef --- /dev/null +++ b/src/testing/testing_group.c @@ -0,0 +1,7170 @@ +/* + This file is part of GNUnet + (C) 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file testing/testing_group.c + * @brief convenience API for writing testcases for GNUnet + * @author Nathan Evans + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" + +#define VERBOSE_TESTING GNUNET_NO + +#define VERBOSE_TOPOLOGY GNUNET_NO + +#define DEBUG_CHURN GNUNET_EXTRA_LOGGING + +#define USE_START_HELPER GNUNET_YES + +#define OLD 1 + +/* Before connecting peers, send all of the HELLOs */ +#define USE_SEND_HELLOS GNUNET_NO + +#define TOPOLOGY_HACK GNUNET_YES + + +/** + * Lowest port used for GNUnet testing. Should be high enough to not + * conflict with other applications running on the hosts but be low + * enough to not conflict with client-ports (typically starting around + * 32k). + */ +#define LOW_PORT 12000 + +/** + * Highest port used for GNUnet testing. Should be low enough to not + * conflict with the port range for "local" ports (client apps; see + * /proc/sys/net/ipv4/ip_local_port_range on Linux for example). + */ +#define HIGH_PORT 56000 + +/* Maximum time to delay connect attempt */ +#define MAX_CONNECT_DELAY 300 + +/** + * Which list of peers do we need to modify? + */ +enum PeerLists +{ + /** Modify allowed peers */ + ALLOWED, + + /** Modify connect peers */ + CONNECT, + + /** Modify blacklist peers */ + BLACKLIST, + + /** Modify workingset peers */ + WORKING_SET +}; + +/** + * Prototype of a function called whenever two peers would be connected + * in a certain topology. + */ +typedef unsigned int (*GNUNET_TESTING_ConnectionProcessor) (struct + GNUNET_TESTING_PeerGroup + * pg, + unsigned int first, + unsigned int second, + enum PeerLists list, + unsigned int check); + +/** + * Context for handling churning a peer group + */ +struct ChurnContext +{ + /** + * The peergroup we are dealing with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Name of the service to churn on/off, NULL + * to churn entire peer. + */ + char *service; + + /** + * Callback used to notify of churning finished + */ + GNUNET_TESTING_NotifyCompletion cb; + + /** + * Closure for callback + */ + void *cb_cls; + + /** + * Number of peers that still need to be started + */ + unsigned int num_to_start; + + /** + * Number of peers that still need to be stopped + */ + unsigned int num_to_stop; + + /** + * Number of peers that failed to start + */ + unsigned int num_failed_start; + + /** + * Number of peers that failed to stop + */ + unsigned int num_failed_stop; +}; + +struct RestartContext +{ + /** + * The group of peers being restarted + */ + struct GNUNET_TESTING_PeerGroup *peer_group; + + /** + * How many peers have been restarted thus far + */ + unsigned int peers_restarted; + + /** + * How many peers got an error when restarting + */ + unsigned int peers_restart_failed; + + /** + * The function to call once all peers have been restarted + */ + GNUNET_TESTING_NotifyCompletion callback; + + /** + * Closure for callback function + */ + void *callback_cls; + +}; + +struct SendHelloContext +{ + /** + * Global handle to the peer group. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * The data about this specific peer. + */ + struct PeerData *peer; + + /** + * The next HELLO that needs sent to this peer. + */ + struct PeerConnection *peer_pos; + + /** + * Are we connected to CORE yet? + */ + unsigned int core_ready; + + /** + * How many attempts should we make for failed connections? + */ + unsigned int connect_attempts; + + /** + * Task for scheduling core connect requests to be sent. + */ + GNUNET_SCHEDULER_TaskIdentifier core_connect_task; +}; + +struct ShutdownContext +{ + struct GNUNET_TESTING_PeerGroup *pg; + /** + * Total peers to wait for + */ + unsigned int total_peers; + + /** + * Number of peers successfully shut down + */ + unsigned int peers_down; + + /** + * Number of peers failed to shut down + */ + unsigned int peers_failed; + + /** + * Number of peers we have started shutting + * down. If too many, wait on them. + */ + unsigned int outstanding; + + /** + * Timeout for shutdown. + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Callback to call when all peers either + * shutdown or failed to shutdown + */ + GNUNET_TESTING_NotifyCompletion cb; + + /** + * Closure for cb + */ + void *cb_cls; + + /** + * Should we delete all of the files from the peers? + */ + int delete_files; +}; + +/** + * Individual shutdown context for a particular peer. + */ +struct PeerShutdownContext +{ + /** + * Pointer to the high level shutdown context. + */ + struct ShutdownContext *shutdown_ctx; + + /** + * The daemon handle for the peer to shut down. + */ + struct GNUNET_TESTING_Daemon *daemon; +}; + +/** + * Individual shutdown context for a particular peer. + */ +struct PeerRestartContext +{ + /** + * Pointer to the high level restart context. + */ + struct ChurnRestartContext *churn_restart_ctx; + + /** + * The daemon handle for the peer to shut down. + */ + struct GNUNET_TESTING_Daemon *daemon; +}; + +struct ServiceStartContext +{ + struct GNUNET_TESTING_PeerGroup *pg; + unsigned int remaining; + GNUNET_TESTING_NotifyCompletion cb; + unsigned int outstanding; + char *service; + struct GNUNET_TIME_Relative timeout; + void *cb_cls; +}; + +/** + * Individual shutdown context for a particular peer. + */ +struct PeerServiceStartContext +{ + /** + * Pointer to the high level start context. + */ + struct ServiceStartContext *start_ctx; + + /** + * The daemon handle for the peer to start the service on. + */ + struct GNUNET_TESTING_Daemon *daemon; +}; + +struct CreateTopologyContext +{ + + /** + * Function to call with number of connections + */ + GNUNET_TESTING_NotifyConnections cont; + + /** + * Closure for connection notification + */ + void *cls; +}; + +enum States +{ + /** Waiting to read number of peers */ + NUM_PEERS, + + /** Should find next peer index */ + PEER_INDEX, + + /** Should find colon */ + COLON, + + /** Should read other peer index, space, or endline */ + OTHER_PEER_INDEX +}; + +#if OLD +struct PeerConnection +{ + /** + * Doubly Linked list + */ + struct PeerConnection *prev; + + /* + * Doubly Linked list + */ + struct PeerConnection *next; + + /* + * Index of daemon in pg->peers + */ + uint32_t index; + +}; +#endif + +struct InternalStartContext +{ + /** + * Pointer to peerdata + */ + struct PeerData *peer; + + /** + * Timeout for peer startup + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Client callback for hostkey notification + */ + GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback; + + /** + * Closure for hostkey_callback + */ + void *hostkey_cls; + + /** + * Client callback for peer start notification + */ + GNUNET_TESTING_NotifyDaemonRunning start_cb; + + /** + * Closure for cb + */ + void *start_cb_cls; + + /** + * Hostname, where to start the peer + */ + const char *hostname; + + /** + * Username to use when connecting to the + * host via ssh. + */ + const char *username; + + /** + * Pointer to starting memory location of a hostkey + */ + const char *hostkey; + + /** + * Port to use for ssh. + */ + uint16_t sshport; + +}; + +struct ChurnRestartContext +{ + /** + * PeerGroup that we are working with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Number of restarts currently in flight. + */ + unsigned int outstanding; + + /** + * Handle to the underlying churn context. + */ + struct ChurnContext *churn_ctx; + + /** + * How long to allow the operation to take. + */ + struct GNUNET_TIME_Relative timeout; +}; + +struct OutstandingSSH +{ + struct OutstandingSSH *next; + + struct OutstandingSSH *prev; + + /** + * Number of current ssh connections. + */ + uint32_t outstanding; + + /** + * The hostname of this peer. + */ + const char *hostname; +}; + +/** + * Data we keep per peer. + */ +struct PeerData +{ + /** + * (Initial) configuration of the host. + * (initial because clients could change + * it and we would not know about those + * updates). + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Handle for controlling the daemon. + */ + struct GNUNET_TESTING_Daemon *daemon; + + /** + * The peergroup this peer belongs to. + */ + struct GNUNET_TESTING_PeerGroup *pg; + +#if OLD + /** + * Linked list of allowed peer connections. + */ + struct PeerConnection *allowed_peers_head; + + /** + * Linked list of allowed peer connections. + */ + struct PeerConnection *allowed_peers_tail; + + /** + * Linked list of blacklisted peer connections. + */ + struct PeerConnection *blacklisted_peers_head; + + /** + * Linked list of blacklisted peer connections. + */ + struct PeerConnection *blacklisted_peers_tail; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_head; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_tail; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_working_set_head; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_working_set_tail; + +#else + /** + * Hash map of allowed peer connections (F2F created topology) + */ + struct GNUNET_CONTAINER_MultiHashMap *allowed_peers; + + /** + * Hash map of blacklisted peers + */ + struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers; + + /** + * Hash map of peer connections + */ + struct GNUNET_CONTAINER_MultiHashMap *connect_peers; + + /** + * Temporary hash map of peer connections + */ + struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set; +#endif + + /** + * Temporary variable for topology creation, should be reset before + * creating any topology so the count is valid once finished. + */ + int num_connections; + + /** + * Context to keep track of peers being started, to + * stagger hostkey generation and peer startup. + */ + struct InternalStartContext internal_context; + + /** + * Task ID for the queued internal_continue_startup task + */ + GNUNET_SCHEDULER_TaskIdentifier startup_task; + +}; + +/** + * Linked list of per-host data. + */ +struct HostData +{ + /** + * Name of the host. + */ + char *hostname; + + /** + * SSH username to use when connecting to this host. + */ + char *username; + + /** + * SSH port to use when connecting to this host. + */ + uint16_t sshport; + + /** + * Lowest port that we have not yet used + * for GNUnet. + */ + uint16_t minport; +}; + +struct TopologyIterateContext +{ + /** + * The peergroup we are working with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Callback for notifying of two connected peers. + */ + GNUNET_TESTING_NotifyTopology topology_cb; + + /** + * Closure for topology_cb + */ + void *cls; + + /** + * Number of peers currently connected to. + */ + unsigned int connected; + + /** + * Number of peers we have finished iterating. + */ + unsigned int completed; + + /** + * Number of peers total. + */ + unsigned int total; +}; + +struct StatsIterateContext +{ + /** + * The peergroup that we are dealing with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Continuation to call once all stats information has been retrieved. + */ + GNUNET_STATISTICS_Callback cont; + + /** + * Proc function to call on each value received. + */ + GNUNET_TESTING_STATISTICS_Iterator proc; + + /** + * Closure for topology_cb + */ + void *cls; + + /** + * Number of peers currently connected to. + */ + unsigned int connected; + + /** + * Number of peers we have finished iterating. + */ + unsigned int completed; + + /** + * Number of peers total. + */ + unsigned int total; +}; + +struct CoreContext +{ + void *iter_context; + struct GNUNET_TESTING_Daemon *daemon; +}; + +struct StatsCoreContext +{ + void *iter_context; + struct GNUNET_TESTING_Daemon *daemon; + /** + * Handle to the statistics service. + */ + struct GNUNET_STATISTICS_Handle *stats_handle; + + /** + * Handle for getting statistics. + */ + struct GNUNET_STATISTICS_GetHandle *stats_get_handle; +}; + +struct ConnectTopologyContext +{ + /** + * How many connections are left to create. + */ + unsigned int remaining_connections; + + /** + * Handle to group of peers. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * How long to try this connection before timing out. + */ + struct GNUNET_TIME_Relative connect_timeout; + + /** + * How many times to retry connecting the two peers. + */ + unsigned int connect_attempts; + + /** + * Temp value set for each iteration. + */ + //struct PeerData *first; + + /** + * Notification that all peers are connected. + */ + GNUNET_TESTING_NotifyCompletion notify_connections_done; + + /** + * Closure for notify. + */ + void *notify_cls; +}; + +struct ConnectContext; + +/** + * Handle to a group of GNUnet peers. + */ +struct GNUNET_TESTING_PeerGroup +{ + /** + * Configuration template. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + struct ConnectContext *cc_head; + + struct ConnectContext *cc_tail; + + /** + * Function to call on each started daemon. + */ + //GNUNET_TESTING_NotifyDaemonRunning cb; + + /** + * Closure for cb. + */ + //void *cb_cls; + + /* + * Function to call on each topology connection created + */ + GNUNET_TESTING_NotifyConnection notify_connection; + + /* + * Callback for notify_connection + */ + void *notify_connection_cls; + + /** + * Array of information about hosts. + */ + struct HostData *hosts; + + /** + * Number of hosts (size of HostData) + */ + unsigned int num_hosts; + + /** + * Array of "total" peers. + */ + struct PeerData *peers; + + /** + * Number of peers in this group. + */ + unsigned int total; + + /** + * At what time should we fail the peer startup process? + */ + struct GNUNET_TIME_Absolute max_timeout; + + /** + * How many peers are being started right now? + */ + unsigned int starting; + + /** + * How many peers have already been started? + */ + unsigned int started; + + /** + * Number of possible connections to peers + * at a time. + */ + unsigned int max_outstanding_connections; + + /** + * Number of ssh connections to peers (max). + */ + unsigned int max_concurrent_ssh; + + /** + * Number of connects we are waiting on, allows us to rate limit + * connect attempts. + */ + unsigned int outstanding_connects; + + /** + * Number of HELLOs we have yet to send. + */ + unsigned int remaining_hellos; + + /** + * How many connects have already been scheduled? + */ + unsigned int total_connects_scheduled; + + /** + * Hostkeys loaded from a file. + */ + char *hostkey_data; + + /** + * Head of DLL to keep track of the number of outstanding + * ssh connections per peer. + */ + struct OutstandingSSH *ssh_head; + + /** + * Tail of DLL to keep track of the number of outstanding + * ssh connections per peer. + */ + struct OutstandingSSH *ssh_tail; + + /** + * Stop scheduling peers connecting. + */ + unsigned int stop_connects; + + /** + * Connection context for peer group. + */ + struct ConnectTopologyContext ct_ctx; +}; + +struct UpdateContext +{ + /** + * The altered configuration. + */ + struct GNUNET_CONFIGURATION_Handle *ret; + + /** + * The original configuration to alter. + */ + const struct GNUNET_CONFIGURATION_Handle *orig; + + /** + * The hostname that this peer will run on. + */ + const char *hostname; + + /** + * The next possible port to assign. + */ + unsigned int nport; + + /** + * Unique number for unix domain sockets. + */ + unsigned int upnum; + + /** + * Unique number for this peer/host to offset + * things that are grouped by host. + */ + unsigned int fdnum; +}; + +struct ConnectContext +{ + + struct ConnectContext *next; + + struct ConnectContext *prev; + + /** + * Index of peer to connect second to. + */ + uint32_t first_index; + + /** + * Index of peer to connect first to. + */ + uint32_t second_index; + + /** + * Task associated with the attempt to connect. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Context in 'testing.c', to cancel connection attempt. + */ + struct GNUNET_TESTING_ConnectContext *cc; + + /** + * Higher level topology connection context. + */ + struct ConnectTopologyContext *ct_ctx; + + /** + * Whether this connection has been accounted for in the schedule_connect call. + */ + int counted; +}; + +struct UnblacklistContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; +}; + +struct RandomContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; + + /** + * Peer data for first peer. + */ + struct PeerData *first; + + /** + * Random percentage to use + */ + double percentage; +}; + +struct MinimumContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; + + /** + * Peer data for first peer. + */ + struct PeerData *first; + + /** + * Number of conns per peer + */ + unsigned int num_to_add; + + /** + * Permuted array of all possible connections. Only add the Nth + * peer if it's in the Nth position. + */ + unsigned int *pg_array; + + /** + * What number is the current element we are iterating over? + */ + unsigned int current; +}; + +struct DFSContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; + + /** + * uid of the second peer + */ + uint32_t second_uid; + + /** + * Peer data for first peer. + */ + struct PeerData *first; + + /** + * Which peer has been chosen as the one to add? + */ + unsigned int chosen; + + /** + * What number is the current element we are iterating over? + */ + unsigned int current; +}; + +/** + * Simple struct to keep track of progress, and print a + * nice little percentage meter for long running tasks. + */ +struct ProgressMeter +{ + unsigned int total; + + unsigned int modnum; + + unsigned int dotnum; + + unsigned int completed; + + int print; + + char *startup_string; +}; + +#if !OLD +/** + * Convert unique ID to hash code. + * + * @param uid unique ID to convert + * @param hash set to uid (extended with zeros) + */ +static void +hash_from_uid (uint32_t uid, GNUNET_HashCode * hash) +{ + memset (hash, 0, sizeof (GNUNET_HashCode)); + *((uint32_t *) hash) = uid; +} + +/** + * Convert hash code to unique ID. + * + * @param uid unique ID to convert + * @param hash set to uid (extended with zeros) + */ +static void +uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid) +{ + memcpy (uid, hash, sizeof (uint32_t)); +} +#endif + +#if USE_SEND_HELLOS +static struct GNUNET_CORE_MessageHandler no_handlers[] = { + {NULL, 0, 0} +}; +#endif + +/** + * Create a meter to keep track of the progress of some task. + * + * @param total the total number of items to complete + * @param start_string a string to prefix the meter with (if printing) + * @param print GNUNET_YES to print the meter, GNUNET_NO to count + * internally only + * + * @return the progress meter + */ +static struct ProgressMeter * +create_meter (unsigned int total, char *start_string, int print) +{ + struct ProgressMeter *ret; + + ret = GNUNET_malloc (sizeof (struct ProgressMeter)); + ret->print = print; + ret->total = total; + ret->modnum = total / 4; + if (ret->modnum == 0) /* Divide by zero check */ + ret->modnum = 1; + ret->dotnum = (total / 50) + 1; + if (start_string != NULL) + ret->startup_string = GNUNET_strdup (start_string); + else + ret->startup_string = GNUNET_strdup (""); + + return ret; +} + +/** + * Update progress meter (increment by one). + * + * @param meter the meter to update and print info for + * + * @return GNUNET_YES if called the total requested, + * GNUNET_NO if more items expected + */ +static int +update_meter (struct ProgressMeter *meter) +{ + if (meter->print == GNUNET_YES) + { + if (meter->completed % meter->modnum == 0) + { + if (meter->completed == 0) + { + FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); + } + else + FPRINTF (stdout, "%d%%", + (int) (((float) meter->completed / meter->total) * 100)); + } + else if (meter->completed % meter->dotnum == 0) + FPRINTF (stdout, "%s", "."); + + if (meter->completed + 1 == meter->total) + FPRINTF (stdout, "%d%%]\n", 100); + fflush (stdout); + } + meter->completed++; + + if (meter->completed == meter->total) + return GNUNET_YES; + if (meter->completed > meter->total) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Progress meter overflow!!\n"); + return GNUNET_NO; +} + +/** + * Reset progress meter. + * + * @param meter the meter to reset + * + * @return GNUNET_YES if meter reset, + * GNUNET_SYSERR on error + */ +static int +reset_meter (struct ProgressMeter *meter) +{ + if (meter == NULL) + return GNUNET_SYSERR; + + meter->completed = 0; + return GNUNET_YES; +} + +/** + * Release resources for meter + * + * @param meter the meter to free + */ +static void +free_meter (struct ProgressMeter *meter) +{ + GNUNET_free_non_null (meter->startup_string); + GNUNET_free (meter); +} + +/** + * Get a topology from a string input. + * + * @param topology where to write the retrieved topology + * @param topology_string The string to attempt to + * get a configuration value from + * @return GNUNET_YES if topology string matched a + * known topology, GNUNET_NO if not + */ +int +GNUNET_TESTING_topology_get (enum GNUNET_TESTING_Topology *topology, + const char *topology_string) +{ + /** + * Strings representing topologies in enum + */ + static const char *topology_strings[] = { + /** + * A clique (everyone connected to everyone else). + */ + "CLIQUE", + + /** + * Small-world network (2d torus plus random links). + */ + "SMALL_WORLD", + + /** + * Small-world network (ring plus random links). + */ + "SMALL_WORLD_RING", + + /** + * Ring topology. + */ + "RING", + + /** + * 2-d torus. + */ + "2D_TORUS", + + /** + * Random graph. + */ + "ERDOS_RENYI", + + /** + * Certain percentage of peers are unable to communicate directly + * replicating NAT conditions + */ + "INTERNAT", + + /** + * Scale free topology. + */ + "SCALE_FREE", + + /** + * Straight line topology. + */ + "LINE", + + /** + * All peers are disconnected. + */ + "NONE", + + /** + * Read the topology from a file. + */ + "FROM_FILE", + + NULL + }; + + int curr = 0; + + if (topology_string == NULL) + return GNUNET_NO; + while (topology_strings[curr] != NULL) + { + if (strcasecmp (topology_strings[curr], topology_string) == 0) + { + *topology = curr; + return GNUNET_YES; + } + curr++; + } + *topology = GNUNET_TESTING_TOPOLOGY_NONE; + return GNUNET_NO; +} + +/** + * Get connect topology option from string input. + * + * @param topology_option where to write the retrieved topology + * @param topology_string The string to attempt to + * get a configuration value from + * @return GNUNET_YES if string matched a known + * topology option, GNUNET_NO if not + */ +int +GNUNET_TESTING_topology_option_get (enum GNUNET_TESTING_TopologyOption + *topology_option, + const char *topology_string) +{ + /** + * Options for connecting a topology as strings. + */ + static const char *topology_option_strings[] = { + /** + * Try to connect all peers specified in the topology. + */ + "CONNECT_ALL", + + /** + * Choose a random subset of connections to create. + */ + "CONNECT_RANDOM_SUBSET", + + /** + * Create at least X connections for each peer. + */ + "CONNECT_MINIMUM", + + /** + * Using a depth first search, create one connection + * per peer. If any are missed (graph disconnected) + * start over at those peers until all have at least one + * connection. + */ + "CONNECT_DFS", + + /** + * Find the N closest peers to each allowed peer in the + * topology and make sure a connection to those peers + * exists in the connect topology. + */ + "CONNECT_CLOSEST", + + /** + * No options specified. + */ + "CONNECT_NONE", + + NULL + }; + int curr = 0; + + if (topology_string == NULL) + return GNUNET_NO; + while (NULL != topology_option_strings[curr]) + { + if (strcasecmp (topology_option_strings[curr], topology_string) == 0) + { + *topology_option = curr; + return GNUNET_YES; + } + curr++; + } + *topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_NONE; + return GNUNET_NO; +} + +/** + * Function to iterate over options. Copies + * the options to the target configuration, + * updating PORT values as needed. + * + * @param cls closure + * @param section name of the section + * @param option name of the option + * @param value value of the option + */ +static void +update_config (void *cls, const char *section, const char *option, + const char *value) +{ + struct UpdateContext *ctx = cls; + unsigned int ival; + char cval[12]; + char uval[128]; + char *single_variable; + char *per_host_variable; + unsigned long long num_per_host; + + GNUNET_asprintf (&single_variable, "single_%s_per_host", section); + GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section); + + if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival))) + { + if ((ival != 0) && + (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", + single_variable))) + { + GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++); + value = cval; + } + else if ((ival != 0) && + (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", + single_variable)) && + GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing", + per_host_variable, + &num_per_host)) + { + GNUNET_snprintf (cval, sizeof (cval), "%u", + ival + ctx->fdnum % num_per_host); + value = cval; + } + + /* FIXME: REMOVE FOREVER HACK HACK HACK */ + if (0 == strcasecmp (section, "transport-tcp")) + GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, + "ADVERTISED_PORT", value); + } + + if (0 == strcmp (option, "UNIXPATH")) + { + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", + single_variable)) + { + GNUNET_snprintf (uval, sizeof (uval), "/tmp/test-service-%s-%u", section, + ctx->upnum++); + value = uval; + } + else if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing", + per_host_variable, + &num_per_host)) && + (num_per_host > 0)) + + { + GNUNET_snprintf (uval, sizeof (uval), "/tmp/test-service-%s-%u", section, + ctx->fdnum % num_per_host); + value = uval; + } + } + + if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL)) + { + value = ctx->hostname; + } + GNUNET_free (single_variable); + GNUNET_free (per_host_variable); + GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value); +} + +/** + * Create a new configuration using the given configuration + * as a template; however, each PORT in the existing cfg + * must be renumbered by incrementing "*port". If we run + * out of "*port" numbers, return NULL. + * + * @param cfg template configuration + * @param off the current peer offset + * @param port port numbers to use, update to reflect + * port numbers that were used + * @param upnum number to make unix domain socket names unique + * @param hostname hostname of the controlling host, to allow control connections from + * @param fdnum number used to offset the unix domain socket for grouped processes + * (such as statistics or peerinfo, which can be shared among others) + * + * @return new configuration, NULL on error + */ +struct GNUNET_CONFIGURATION_Handle * +GNUNET_TESTING_create_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t off, + uint16_t * port, uint32_t * upnum, const char *hostname, + uint32_t * fdnum) +{ + struct UpdateContext uc; + uint16_t orig; + char *control_host; + char *allowed_hosts; + unsigned long long skew_variance; + unsigned long long skew_offset; + long long actual_offset; + + orig = *port; + uc.nport = *port; + uc.upnum = *upnum; + uc.fdnum = *fdnum; + uc.ret = GNUNET_CONFIGURATION_create (); + uc.hostname = hostname; + uc.orig = cfg; + + GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc); + if (uc.nport >= HIGH_PORT) + { + *port = orig; + GNUNET_CONFIGURATION_destroy (uc.ret); + return NULL; + } + + if ((GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "skew_variance", + &skew_variance)) && + (skew_variance > 0)) + { + skew_offset = + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + skew_variance + 1); + actual_offset = + skew_offset - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + skew_variance + 1); + /* Min is -skew_variance, Max is skew_variance */ + skew_offset = skew_variance + actual_offset; /* Normal distribution around 0 */ + GNUNET_CONFIGURATION_set_value_number (uc.ret, "testing", "skew_offset", + skew_offset); + } + + if (GNUNET_CONFIGURATION_get_value_string + (cfg, "testing", "control_host", &control_host) == GNUNET_OK) + { + if (hostname != NULL) + GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1; %s;", control_host, + hostname); + else + GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", control_host); + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "ACCEPT_FROM", + allowed_hosts); + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "ACCEPT_FROM", + allowed_hosts); + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "ACCEPT_FROM", + allowed_hosts); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "ACCEPT_FROM", + allowed_hosts); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "ACCEPT_FROM", + allowed_hosts); + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "UNIXPATH", ""); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "UNIXPATH", ""); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH", ""); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH", + ""); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "UNIXPATH", ""); + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp", + "USE_LOCALADDR", "YES"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp", + "USE_LOCALADDR", "YES"); + GNUNET_free_non_null (control_host); + GNUNET_free (allowed_hosts); + } + + /* arm needs to know to allow connections from the host on which it is running, + * otherwise gnunet-arm is unable to connect to it in some instances */ + if (hostname != NULL) + { + GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", hostname); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO", hostname); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS", + hostname); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS", + hostname); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "disablev6", "BINDTO", + "YES"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp", + "USE_LOCALADDR", "YES"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp", + "USE_LOCALADDR", "YES"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "arm", "ACCEPT_FROM", + allowed_hosts); + GNUNET_free (allowed_hosts); + } + else + { + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp", + "USE_LOCALADDR", "YES"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp", + "USE_LOCALADDR", "YES"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO", + "127.0.0.1"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS", + "127.0.0.1"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS", + "127.0.0.1"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "disablev6", + "YES"); + } + + *port = (uint16_t) uc.nport; + *upnum = uc.upnum; + uc.fdnum++; + *fdnum = uc.fdnum; + return uc.ret; +} + +/* + * Remove entries from the peer connection list + * + * @param pg the peer group we are working with + * @param first index of the first peer + * @param second index of the second peer + * @param list the peer list to use + * @param check UNUSED + * + * @return the number of connections added (can be 0, 1 or 2) + * + */ +static unsigned int +remove_connections (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, + unsigned int second, enum PeerLists list, + unsigned int check) +{ + int removed; + +#if OLD + struct PeerConnection **first_list; + struct PeerConnection **second_list; + struct PeerConnection *first_iter; + struct PeerConnection *second_iter; + struct PeerConnection **first_tail; + struct PeerConnection **second_tail; + +#else + GNUNET_HashCode hash_first; + GNUNET_HashCode hash_second; + + hash_from_uid (first, &hash_first); + hash_from_uid (second, &hash_second); +#endif + + removed = 0; +#if OLD + switch (list) + { + case ALLOWED: + first_list = &pg->peers[first].allowed_peers_head; + second_list = &pg->peers[second].allowed_peers_head; + first_tail = &pg->peers[first].allowed_peers_tail; + second_tail = &pg->peers[second].allowed_peers_tail; + break; + case CONNECT: + first_list = &pg->peers[first].connect_peers_head; + second_list = &pg->peers[second].connect_peers_head; + first_tail = &pg->peers[first].connect_peers_tail; + second_tail = &pg->peers[second].connect_peers_tail; + break; + case BLACKLIST: + first_list = &pg->peers[first].blacklisted_peers_head; + second_list = &pg->peers[second].blacklisted_peers_head; + first_tail = &pg->peers[first].blacklisted_peers_tail; + second_tail = &pg->peers[second].blacklisted_peers_tail; + break; + case WORKING_SET: + first_list = &pg->peers[first].connect_peers_working_set_head; + second_list = &pg->peers[second].connect_peers_working_set_head; + first_tail = &pg->peers[first].connect_peers_working_set_tail; + second_tail = &pg->peers[second].connect_peers_working_set_tail; + break; + default: + GNUNET_break (0); + return 0; + } + + first_iter = *first_list; + while (first_iter != NULL) + { + if (first_iter->index == second) + { + GNUNET_CONTAINER_DLL_remove (*first_list, *first_tail, first_iter); + GNUNET_free (first_iter); + removed++; + break; + } + first_iter = first_iter->next; + } + + second_iter = *second_list; + while (second_iter != NULL) + { + if (second_iter->index == first) + { + GNUNET_CONTAINER_DLL_remove (*second_list, *second_tail, second_iter); + GNUNET_free (second_iter); + removed++; + break; + } + second_iter = second_iter->next; + } +#else + if (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (pg-> + peers[first].blacklisted_peers, + &hash_second)) + { + GNUNET_CONTAINER_multihashmap_remove_all (pg-> + peers[first].blacklisted_peers, + &hash_second); + } + + if (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (pg-> + peers[second].blacklisted_peers, + &hash_first)) + { + GNUNET_CONTAINER_multihashmap_remove_all (pg-> + peers[second].blacklisted_peers, + &hash_first); + } +#endif + + return removed; +} + +/** + * Add entries to the some list + * + * @param pg the peer group we are working with + * @param first index of the first peer + * @param second index of the second peer + * @param list the list type that we should modify + * @param check GNUNET_YES to check lists before adding + * GNUNET_NO to force add + * + * @return the number of connections added (can be 0, 1 or 2) + * + */ +static unsigned int +add_connections (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, + unsigned int second, enum PeerLists list, unsigned int check) +{ + int added; + int add_first; + int add_second; + + struct PeerConnection **first_list; + struct PeerConnection **second_list; + struct PeerConnection *first_iter; + struct PeerConnection *second_iter; + struct PeerConnection *new_first; + struct PeerConnection *new_second; + struct PeerConnection **first_tail; + struct PeerConnection **second_tail; + + switch (list) + { + case ALLOWED: + first_list = &pg->peers[first].allowed_peers_head; + second_list = &pg->peers[second].allowed_peers_head; + first_tail = &pg->peers[first].allowed_peers_tail; + second_tail = &pg->peers[second].allowed_peers_tail; + break; + case CONNECT: + first_list = &pg->peers[first].connect_peers_head; + second_list = &pg->peers[second].connect_peers_head; + first_tail = &pg->peers[first].connect_peers_tail; + second_tail = &pg->peers[second].connect_peers_tail; + break; + case BLACKLIST: + first_list = &pg->peers[first].blacklisted_peers_head; + second_list = &pg->peers[second].blacklisted_peers_head; + first_tail = &pg->peers[first].blacklisted_peers_tail; + second_tail = &pg->peers[second].blacklisted_peers_tail; + break; + case WORKING_SET: + first_list = &pg->peers[first].connect_peers_working_set_head; + second_list = &pg->peers[second].connect_peers_working_set_head; + first_tail = &pg->peers[first].connect_peers_working_set_tail; + second_tail = &pg->peers[second].connect_peers_working_set_tail; + break; + default: + GNUNET_break (0); + return 0; + } + + add_first = GNUNET_YES; + add_second = GNUNET_YES; + + if (check == GNUNET_YES) + { + first_iter = *first_list; + while (first_iter != NULL) + { + if (first_iter->index == second) + { + add_first = GNUNET_NO; + break; + } + first_iter = first_iter->next; + } + + second_iter = *second_list; + while (second_iter != NULL) + { + if (second_iter->index == first) + { + add_second = GNUNET_NO; + break; + } + second_iter = second_iter->next; + } + } + + added = 0; + if (add_first) + { + new_first = GNUNET_malloc (sizeof (struct PeerConnection)); + new_first->index = second; + GNUNET_CONTAINER_DLL_insert (*first_list, *first_tail, new_first); + pg->peers[first].num_connections++; + added++; + } + + if (add_second) + { + new_second = GNUNET_malloc (sizeof (struct PeerConnection)); + new_second->index = first; + GNUNET_CONTAINER_DLL_insert (*second_list, *second_tail, new_second); + pg->peers[second].num_connections++; + added++; + } + + return added; +} + +/** + * Scale free network construction as described in: + * + * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999. + * + * Start with a network of "one" peer, then progressively add + * peers up to the total number. At each step, iterate over + * all possible peers and connect new peer based on number of + * existing connections of the target peer. + * + * @param pg the peer group we are dealing with + * @param proc the connection processor to use + * @param list the peer list to use + * + * @return the number of connections created + */ +static unsigned int +create_scale_free (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ + + unsigned int total_connections; + unsigned int outer_count; + unsigned int i; + unsigned int previous_total_connections; + double random; + double probability; + + GNUNET_assert (pg->total > 1); + + /* Add a connection between the first two nodes */ + total_connections = proc (pg, 0, 1, list, GNUNET_YES); + + for (outer_count = 1; outer_count < pg->total; outer_count++) + { + previous_total_connections = total_connections; + for (i = 0; i < outer_count; i++) + { + probability = + pg->peers[i].num_connections / (double) previous_total_connections; + random = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Considering connecting peer %d to peer %d\n", outer_count, + i); +#endif + if (random < probability) + { +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + outer_count, i); +#endif + total_connections += proc (pg, outer_count, i, list, GNUNET_YES); + } + } + } + + return total_connections; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. Creates a small world topology + * according to the rewired ring construction. The basic + * behavior is that a ring topology is created, but with some + * probability instead of connecting a peer to the next + * neighbor in the ring a connection will be created to a peer + * selected uniformly at random. We use the TESTING + * PERCENTAGE option to specify what number of + * connections each peer should have. Default is 2, + * which makes the ring, any given number is multiplied by + * the log of the network size; i.e. a PERCENTAGE of 2 makes + * each peer have on average 2logn connections. The additional + * connections are made at increasing distance around the ring + * from the original peer, or to random peers based on the re- + * wiring probability. The TESTING + * PROBABILITY option is used as the probability that a given + * connection is rewired. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_small_world_ring (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, + enum PeerLists list) +{ + unsigned int i, j; + int nodeToConnect; + unsigned int natLog; + unsigned int randomPeer; + double random, logNModifier, probability; + unsigned int smallWorldConnections; + int connsPerPeer; + char *p_string; + int max; + int min; + unsigned int useAnd; + int connect_attempts; + + logNModifier = 0.5; /* FIXME: default value? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", + &p_string)) + { + if (sscanf (p_string, "%lf", &logNModifier) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "LOGNMODIFIER", "TESTING"); + GNUNET_free (p_string); + } + probability = 0.5; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", + &p_string)) + { + if (sscanf (p_string, "%lf", &probability) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PERCENTAGE", "TESTING"); + GNUNET_free (p_string); + } + natLog = log (pg->total); + connsPerPeer = ceil (natLog * logNModifier); + + if (connsPerPeer % 2 == 1) + connsPerPeer += 1; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Target is %d connections per peer."), + connsPerPeer); + + smallWorldConnections = 0; + connect_attempts = 0; + for (i = 0; i < pg->total; i++) + { + useAnd = 0; + max = i + connsPerPeer / 2; + min = i - connsPerPeer / 2; + + if (max > pg->total - 1) + { + max = max - pg->total; + useAnd = 1; + } + + if (min < 0) + { + min = pg->total - 1 + min; + useAnd = 1; + } + + for (j = 0; j < connsPerPeer / 2; j++) + { + random = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX) / ((double) UINT64_MAX)); + if (random < probability) + { + /* Connect to uniformly selected random peer */ + randomPeer = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); + while ((((randomPeer < max) && (randomPeer > min)) && (useAnd == 0)) || + (((randomPeer > min) || (randomPeer < max)) && (useAnd == 1))) + { + randomPeer = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); + } + smallWorldConnections += proc (pg, i, randomPeer, list, GNUNET_YES); + } + else + { + nodeToConnect = i + j + 1; + if (nodeToConnect > pg->total - 1) + { + nodeToConnect = nodeToConnect - pg->total; + } + connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); + } + } + + } + + connect_attempts += smallWorldConnections; + + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, + enum PeerLists list) +{ + unsigned int outer_count, inner_count; + unsigned int cutoff; + int connect_attempts; + double nat_percentage; + char *p_string; + + nat_percentage = 0.6; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", + &p_string)) + { + if (sscanf (p_string, "%lf", &nat_percentage) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PERCENTAGE", "TESTING"); + GNUNET_free (p_string); + } + + cutoff = (unsigned int) (nat_percentage * pg->total); + connect_attempts = 0; + for (outer_count = 0; outer_count < pg->total - 1; outer_count++) + { + for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) + { + if ((outer_count > cutoff) || (inner_count > cutoff)) + { +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + outer_count, inner_count); +#endif + connect_attempts += + proc (pg, outer_count, inner_count, list, GNUNET_YES); + } + } + } + return connect_attempts; +} + +#if TOPOLOGY_HACK +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_nated_internet_copy (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, + enum PeerLists list) +{ + unsigned int outer_count, inner_count; + unsigned int cutoff; + int connect_attempts; + double nat_percentage; + char *p_string; + unsigned int count; + struct ProgressMeter *conn_meter; + + nat_percentage = 0.6; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", + &p_string)) + { + if (sscanf (p_string, "%lf", &nat_percentage) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PERCENTAGE", "TESTING"); + GNUNET_free (p_string); + } + + cutoff = (unsigned int) (nat_percentage * pg->total); + count = 0; + for (outer_count = 0; outer_count < pg->total - 1; outer_count++) + { + for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) + { + if ((outer_count > cutoff) || (inner_count > cutoff)) + { + count++; + } + } + } + conn_meter = create_meter (count, "NAT COPY", GNUNET_YES); + connect_attempts = 0; + for (outer_count = 0; outer_count < pg->total - 1; outer_count++) + { + for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) + { + if ((outer_count > cutoff) || (inner_count > cutoff)) + { +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + outer_count, inner_count); +#endif + connect_attempts += + proc (pg, outer_count, inner_count, list, GNUNET_YES); + add_connections (pg, outer_count, inner_count, ALLOWED, GNUNET_NO); + update_meter (conn_meter); + } + } + } + free_meter (conn_meter); + + return connect_attempts; +} +#endif + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_small_world (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, + enum PeerLists list) +{ + unsigned int i, j, k; + unsigned int square; + unsigned int rows; + unsigned int cols; + unsigned int toggle = 1; + unsigned int nodeToConnect; + unsigned int natLog; + unsigned int node1Row; + unsigned int node1Col; + unsigned int node2Row; + unsigned int node2Col; + unsigned int distance; + double probability, random, percentage; + unsigned int smallWorldConnections; + unsigned int small_world_it; + char *p_string; + int connect_attempts; + + square = floor (sqrt (pg->total)); + rows = square; + cols = square; + + percentage = 0.5; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", + &p_string)) + { + if (sscanf (p_string, "%lf", &percentage) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PERCENTAGE", "TESTING"); + GNUNET_free (p_string); + } + if (percentage < 0.0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': got %f, needed value greater than 0\n"), + "PERCENTAGE", "TESTING", percentage); + percentage = 0.5; + } + probability = 0.5; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", + &p_string)) + { + if (sscanf (p_string, "%lf", &probability) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PROBABILITY", "TESTING"); + GNUNET_free (p_string); + } + if (square * square != pg->total) + { + while (rows * cols < pg->total) + { + if (toggle % 2 == 0) + rows++; + else + cols++; + + toggle++; + } + } +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Connecting nodes in 2d torus topology: %u rows %u columns\n"), + rows, cols); +#endif + + connect_attempts = 0; + /* Rows and columns are all sorted out, now iterate over all nodes and connect each + * to the node to its right and above. Once this is over, we'll have our torus! + * Special case for the last node (if the rows and columns are not equal), connect + * to the first in the row to maintain topology. + */ + for (i = 0; i < pg->total; i++) + { + /* First connect to the node to the right */ + if (((i + 1) % cols != 0) && (i + 1 != pg->total)) + nodeToConnect = i + 1; + else if (i + 1 == pg->total) + nodeToConnect = rows * cols - cols; + else + nodeToConnect = i - cols + 1; + + connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); + + if (i < cols) + { + nodeToConnect = (rows * cols) - cols + i; + if (nodeToConnect >= pg->total) + nodeToConnect -= cols; + } + else + nodeToConnect = i - cols; + + if (nodeToConnect < pg->total) + connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); + } + natLog = log (pg->total); +#if VERBOSE_TESTING > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("natural log of %d is %d, will run %d iterations\n"), pg->total, + natLog, (int) (natLog * percentage)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Total connections added thus far: %u!\n"), connect_attempts); +#endif + smallWorldConnections = 0; + small_world_it = (unsigned int) (natLog * percentage); + if (small_world_it < 1) + small_world_it = 1; + GNUNET_assert (small_world_it > 0 && small_world_it < (unsigned int) -1); + for (i = 0; i < small_world_it; i++) + { + for (j = 0; j < pg->total; j++) + { + /* Determine the row and column of node at position j on the 2d torus */ + node1Row = j / cols; + node1Col = j - (node1Row * cols); + for (k = 0; k < pg->total; k++) + { + /* Determine the row and column of node at position k on the 2d torus */ + node2Row = k / cols; + node2Col = k - (node2Row * cols); + /* Simple Cartesian distance */ + distance = abs (node1Row - node2Row) + abs (node1Col - node2Col); + if (distance > 1) + { + /* Calculate probability as 1 over the square of the distance */ + probability = 1.0 / (distance * distance); + /* Choose a random value between 0 and 1 */ + random = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); + /* If random < probability, then connect the two nodes */ + if (random < probability) + smallWorldConnections += proc (pg, j, k, list, GNUNET_YES); + + } + } + } + } + connect_attempts += smallWorldConnections; +#if VERBOSE_TESTING > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Total connections added for small world: %d!\n"), + smallWorldConnections); +#endif + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, + enum PeerLists list) +{ + double temp_rand; + unsigned int outer_count; + unsigned int inner_count; + int connect_attempts; + double probability; + char *p_string; + + probability = 0.5; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", + &p_string)) + { + if (sscanf (p_string, "%lf", &probability) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PROBABILITY", "TESTING"); + GNUNET_free (p_string); + } + connect_attempts = 0; + for (outer_count = 0; outer_count < pg->total - 1; outer_count++) + { + for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) + { + temp_rand = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("rand is %f probability is %f\n"), + temp_rand, probability); +#endif + if (temp_rand < probability) + { + connect_attempts += + proc (pg, outer_count, inner_count, list, GNUNET_YES); + } + } + } + + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. This particular function creates + * the connections for a 2d-torus, plus additional "closest" + * connections per peer. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ + unsigned int i; + unsigned int square; + unsigned int rows; + unsigned int cols; + unsigned int toggle = 1; + unsigned int nodeToConnect; + int connect_attempts; + + connect_attempts = 0; + + square = floor (sqrt (pg->total)); + rows = square; + cols = square; + + if (square * square != pg->total) + { + while (rows * cols < pg->total) + { + if (toggle % 2 == 0) + rows++; + else + cols++; + + toggle++; + } + } +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Connecting nodes in 2d torus topology: %u rows %u columns\n"), + rows, cols); +#endif + /* Rows and columns are all sorted out, now iterate over all nodes and connect each + * to the node to its right and above. Once this is over, we'll have our torus! + * Special case for the last node (if the rows and columns are not equal), connect + * to the first in the row to maintain topology. + */ + for (i = 0; i < pg->total; i++) + { + /* First connect to the node to the right */ + if (((i + 1) % cols != 0) && (i + 1 != pg->total)) + nodeToConnect = i + 1; + else if (i + 1 == pg->total) + nodeToConnect = rows * cols - cols; + else + nodeToConnect = i - cols + 1; +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", i, + nodeToConnect); +#endif + connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); + + /* Second connect to the node immediately above */ + if (i < cols) + { + nodeToConnect = (rows * cols) - cols + i; + if (nodeToConnect >= pg->total) + nodeToConnect -= cols; + } + else + nodeToConnect = i - cols; + + if (nodeToConnect < pg->total) + { +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", i, + nodeToConnect); +#endif + connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); + } + + } + + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * @param check does the connection processor need to check before + * performing an action on the list? + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_clique (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list, + unsigned int check) +{ + unsigned int outer_count; + unsigned int inner_count; + int connect_attempts; + struct ProgressMeter *conn_meter; + + connect_attempts = 0; + + conn_meter = + create_meter ((((pg->total * pg->total) + pg->total) / 2) - pg->total, + "Create Clique ", GNUNET_NO); + for (outer_count = 0; outer_count < pg->total - 1; outer_count++) + { + for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) + { +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + outer_count, inner_count); +#endif + connect_attempts += proc (pg, outer_count, inner_count, list, check); + update_meter (conn_meter); + } + } + reset_meter (conn_meter); + free_meter (conn_meter); + return connect_attempts; +} + +#if !OLD +/** + * Iterator over hash map entries. + * + * @param cls closure the peer group + * @param key the key stored in the hashmap is the + * index of the peer to connect to + * @param value value in the hash map, handle to the peer daemon + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +unblacklist_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct UnblacklistContext *un_ctx = cls; + uint32_t second_pos; + + uid_from_hash (key, &second_pos); + + unblacklist_connections (un_ctx->pg, un_ctx->first_uid, second_pos); + + return GNUNET_YES; +} +#endif + +#if !OLD +/** + * Create a blacklist topology based on the allowed topology + * which disallows any connections not in the allowed topology + * at the transport level. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to allow + * up connections between two peers + * + * @return the number of connections that were set up + * + */ +static unsigned int +copy_allowed (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc) +{ + unsigned int count; + unsigned int total; + struct PeerConnection *iter; + +#if !OLD + struct UnblacklistContext un_ctx; + + un_ctx.pg = pg; +#endif + total = 0; + for (count = 0; count < pg->total - 1; count++) + { +#if OLD + iter = pg->peers[count].allowed_peers_head; + while (iter != NULL) + { + remove_connections (pg, count, iter->index, BLACKLIST, GNUNET_YES); + //unblacklist_connections(pg, count, iter->index); + iter = iter->next; + } +#else + un_ctx.first_uid = count; + total += + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[count].allowed_peers, + &unblacklist_iterator, &un_ctx); +#endif + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unblacklisted %u peers\n", total); + return total; +} +#endif + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list which list should be modified + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_line (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ + unsigned int count; + unsigned int connect_attempts; + + connect_attempts = 0; + /* Connect each peer to the next highest numbered peer */ + for (count = 0; count < pg->total - 1; count++) + { +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + count, count + 1); +#endif + connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES); + } + + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param filename the file to read topology information from + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_from_file (struct GNUNET_TESTING_PeerGroup *pg, char *filename, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ + int connect_attempts; + unsigned int first_peer_index; + unsigned int second_peer_index; + struct stat frstat; + int count; + char *data; + const char *buf; + unsigned int total_peers; + enum States curr_state; + + connect_attempts = 0; + if (GNUNET_OK != GNUNET_DISK_file_test (filename)) + GNUNET_DISK_fn_write (filename, NULL, 0, GNUNET_DISK_PERM_USER_READ); + + if ((0 != STAT (filename, &frstat)) || (frstat.st_size == 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not open file `%s' specified for topology!", filename); + return connect_attempts; + } + + data = GNUNET_malloc_large (frstat.st_size); + GNUNET_assert (data != NULL); + if (frstat.st_size != GNUNET_DISK_fn_read (filename, data, frstat.st_size)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not read file %s specified for host list, ending test!", + filename); + GNUNET_free (data); + return connect_attempts; + } + + buf = data; + count = 0; + first_peer_index = 0; + /* First line should contain a single integer, specifying the number of peers */ + /* Each subsequent line should contain this format PEER_INDEX:OTHER_PEER_INDEX[,...] */ + curr_state = NUM_PEERS; + while (count < frstat.st_size - 1) + { + if ((buf[count] == '\n') || (buf[count] == ' ')) + { + count++; + continue; + } + + switch (curr_state) + { + case NUM_PEERS: + errno = 0; + total_peers = strtoul (&buf[count], NULL, 10); + if (errno != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to read number of peers from topology file!\n"); + GNUNET_free (data); + return connect_attempts; + } +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u total peers in topology\n", + total_peers); +#endif + GNUNET_assert (total_peers == pg->total); + curr_state = PEER_INDEX; + while ((buf[count] != '\n') && (count < frstat.st_size - 1)) + count++; + count++; + break; + case PEER_INDEX: + errno = 0; + first_peer_index = strtoul (&buf[count], NULL, 10); + if (errno != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to read peer index from topology file!\n"); + GNUNET_free (data); + return connect_attempts; + } + while ((buf[count] != ':') && (count < frstat.st_size - 1)) + count++; + count++; + curr_state = OTHER_PEER_INDEX; + break; + case COLON: + if (1 == sscanf (&buf[count], ":")) + curr_state = OTHER_PEER_INDEX; + count++; + break; + case OTHER_PEER_INDEX: + errno = 0; + second_peer_index = strtoul (&buf[count], NULL, 10); + if (errno != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to peer index from topology file!\n"); + GNUNET_free (data); + return connect_attempts; + } + /* Assume file is written with first peer 1, but array index is 0 */ + connect_attempts += + proc (pg, first_peer_index - 1, second_peer_index - 1, list, + GNUNET_YES); + while ((buf[count] != '\n') && (buf[count] != ',') && + (count < frstat.st_size - 1)) + count++; + if (buf[count] == '\n') + { + curr_state = PEER_INDEX; + } + else if (buf[count] != ',') + { + curr_state = OTHER_PEER_INDEX; + } + count++; + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Found bad data in topology file while in state %d!\n", + curr_state); + GNUNET_break (0); + GNUNET_free (data); + return connect_attempts; + } + } + GNUNET_free (data); + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_ring (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ + unsigned int count; + int connect_attempts; + + connect_attempts = 0; + + /* Connect each peer to the next highest numbered peer */ + for (count = 0; count < pg->total - 1; count++) + { +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + count, count + 1); +#endif + connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES); + } + + /* Connect the last peer to the first peer */ + connect_attempts += proc (pg, pg->total - 1, 0, list, GNUNET_YES); + + return connect_attempts; +} + +#if !OLD +/** + * Iterator for writing friends of a peer to a file. + * + * @param cls closure, an open writable file handle + * @param key the key the daemon was stored under + * @param value the GNUNET_TESTING_Daemon that needs to be written. + * + * @return GNUNET_YES to continue iteration + * + * TODO: Could replace friend_file_iterator and blacklist_file_iterator + * with a single file_iterator that takes a closure which contains + * the prefix to write before the peer. Then this could be used + * for blacklisting multiple transports and writing the friend + * file. I'm sure *someone* will complain loudly about other + * things that negate these functions even existing so no point in + * "fixing" now. + */ +static int +friend_file_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + FILE *temp_friend_handle = cls; + struct GNUNET_TESTING_Daemon *peer = value; + struct GNUNET_PeerIdentity *temppeer; + struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; + + temppeer = &peer->id; + GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc); + FPRINTF (temp_friend_handle, "%s\n", (char *) &peer_enc); + + return GNUNET_YES; +} + +struct BlacklistContext +{ + /* + * The (open) file handle to write to + */ + FILE *temp_file_handle; + + /* + * The transport that this peer will be blacklisted on. + */ + char *transport; +}; + +/** + * Iterator for writing blacklist data to appropriate files. + * + * @param cls closure, an open writable file handle + * @param key the key the daemon was stored under + * @param value the GNUNET_TESTING_Daemon that needs to be written. + * + * @return GNUNET_YES to continue iteration + */ +static int +blacklist_file_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct BlacklistContext *blacklist_ctx = cls; + struct GNUNET_TESTING_Daemon *peer = value; + struct GNUNET_PeerIdentity *temppeer; + struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; + + temppeer = &peer->id; + GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing entry %s:%s to file\n", + blacklist_ctx->transport, (char *) &peer_enc); + FPRINTF (blacklist_ctx->temp_file_handle, "%s:%s\n", blacklist_ctx->transport, + (char *) &peer_enc); + + return GNUNET_YES; +} +#endif + +/* + * Create the friend files based on the PeerConnection's + * of each peer in the peer group, and copy the files + * to the appropriate place + * + * @param pg the peer group we are dealing with + */ +static int +create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg) +{ + FILE *temp_friend_handle; + unsigned int pg_iter; + char *temp_service_path; + struct GNUNET_OS_Process **procarr; + char *arg; + char *mytemp; + +#if NOT_STUPID + enum GNUNET_OS_ProcessStatusType type; + unsigned long return_code; + int count; + int max_wait = 10; +#endif + int ret; + + ret = GNUNET_OK; +#if OLD + struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; + struct PeerConnection *conn_iter; +#endif + procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total); + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + mytemp = GNUNET_DISK_mktemp ("friends"); + GNUNET_assert (mytemp != NULL); + temp_friend_handle = FOPEN (mytemp, "wt"); + GNUNET_assert (temp_friend_handle != NULL); +#if OLD + conn_iter = pg->peers[pg_iter].allowed_peers_head; + while (conn_iter != NULL) + { + GNUNET_CRYPTO_hash_to_enc (&pg->peers[conn_iter->index].daemon-> + id.hashPubKey, &peer_enc); + FPRINTF (temp_friend_handle, "%s\n", (char *) &peer_enc); + conn_iter = conn_iter->next; + } +#else + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, + &friend_file_iterator, + temp_friend_handle); +#endif + FCLOSE (temp_friend_handle); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].daemon->cfg, + "PATHS", "SERVICEHOME", + &temp_service_path)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"), + "SERVICEHOME", "PATHS"); + if (UNLINK (mytemp) != 0) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp); + GNUNET_free (mytemp); + break; + } + + if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */ + { + GNUNET_asprintf (&arg, "%s/friends", temp_service_path); + procarr[pg_iter] = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "mv", "mv", mytemp, arg, NULL); + GNUNET_assert (procarr[pg_iter] != NULL); +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copying file with command cp %s %s\n", mytemp, arg); +#endif + ret = GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: schedule this, throttle! */ + GNUNET_OS_process_close (procarr[pg_iter]); + GNUNET_free (arg); + } + else /* Remote, scp the file to the correct place */ + { + if (NULL != pg->peers[pg_iter].daemon->username) + GNUNET_asprintf (&arg, "%s@%s:%s/friends", + pg->peers[pg_iter].daemon->username, + pg->peers[pg_iter].daemon->hostname, + temp_service_path); + else + GNUNET_asprintf (&arg, "%s:%s/friends", + pg->peers[pg_iter].daemon->hostname, + temp_service_path); + procarr[pg_iter] = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", mytemp, arg, NULL); + GNUNET_assert (procarr[pg_iter] != NULL); + ret = GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: schedule this, throttle! */ + GNUNET_OS_process_close (procarr[pg_iter]); + if (ret != GNUNET_OK) + { + /* FIXME: free contents of 'procarr' array */ + GNUNET_free (procarr); + GNUNET_free (temp_service_path); + GNUNET_free (mytemp); + GNUNET_free (arg); + return ret; + } + procarr[pg_iter] = NULL; +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copying file with command scp %s %s\n", mytemp, arg); +#endif + GNUNET_free (arg); + } + GNUNET_free (temp_service_path); + GNUNET_free (mytemp); + } + +#if NOT_STUPID + count = 0; + ret = GNUNET_SYSERR; + while ((count < max_wait) && (ret != GNUNET_OK)) + { + ret = GNUNET_OK; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking copy status of file %d\n", + pg_iter); +#endif + if (procarr[pg_iter] != NULL) /* Check for already completed! */ + { + if (GNUNET_OS_process_status (procarr[pg_iter], &type, &return_code) != + GNUNET_OK) + { + ret = GNUNET_SYSERR; + } + else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0)) + { + ret = GNUNET_SYSERR; + } + else + { + GNUNET_OS_process_close (procarr[pg_iter]); + procarr[pg_iter] = NULL; +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File %d copied\n", pg_iter); +#endif + } + } + } + count++; + if (ret == GNUNET_SYSERR) + { + /* FIXME: why sleep here? -CG */ + sleep (1); + } + } + +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Finished copying all friend files!\n")); +#endif +#endif + GNUNET_free (procarr); + return ret; +} + +/* + * Create the blacklist files based on the PeerConnection's + * of each peer in the peer group, and copy the files + * to the appropriate place. + * + * @param pg the peer group we are dealing with + * @param transports space delimited list of transports to blacklist + */ +static int +create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg, + const char *transports) +{ + FILE *temp_file_handle; + unsigned int pg_iter; + char *temp_service_path; + struct GNUNET_OS_Process **procarr; + char *arg; + char *mytemp; + enum GNUNET_OS_ProcessStatusType type; + unsigned long return_code; + int count; + int ret; + int max_wait = 10; + int transport_len; + unsigned int i; + char *pos; + char *temp_transports; + +#if OLD + struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; + struct PeerConnection *conn_iter; +#else + static struct BlacklistContext blacklist_ctx; +#endif + + procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total); + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + mytemp = GNUNET_DISK_mktemp ("blacklist"); + GNUNET_assert (mytemp != NULL); + temp_file_handle = FOPEN (mytemp, "wt"); + GNUNET_assert (temp_file_handle != NULL); + temp_transports = GNUNET_strdup (transports); +#if !OLD + blacklist_ctx.temp_file_handle = temp_file_handle; +#endif + transport_len = strlen (temp_transports) + 1; + pos = NULL; + + for (i = 0; i < transport_len; i++) + { + if ((temp_transports[i] == ' ') && (pos == NULL)) + continue; /* At start of string (whitespace) */ + else if ((temp_transports[i] == ' ') || (temp_transports[i] == '\0')) /* At end of string */ + { + temp_transports[i] = '\0'; +#if OLD + conn_iter = pg->peers[pg_iter].blacklisted_peers_head; + while (conn_iter != NULL) + { + GNUNET_CRYPTO_hash_to_enc (&pg->peers[conn_iter->index].daemon-> + id.hashPubKey, &peer_enc); + FPRINTF (temp_file_handle, "%s:%s\n", pos, (char *) &peer_enc); + conn_iter = conn_iter->next; + } +#else + blacklist_ctx.transport = pos; + (void) GNUNET_CONTAINER_multihashmap_iterate (pg-> + peers + [pg_iter].blacklisted_peers, + &blacklist_file_iterator, + &blacklist_ctx); +#endif + pos = NULL; + } /* At beginning of actual string */ + else if (pos == NULL) + { + pos = &temp_transports[i]; + } + } + + GNUNET_free (temp_transports); + FCLOSE (temp_file_handle); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].daemon->cfg, + "PATHS", "SERVICEHOME", + &temp_service_path)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"), + "SERVICEHOME", "PATHS"); + if (UNLINK (mytemp) != 0) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp); + GNUNET_free (mytemp); + break; + } + + if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */ + { + GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path); + procarr[pg_iter] = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "mv", "mv", mytemp, arg, NULL); +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Copying file with command cp %s %s\n"), mytemp, arg); +#endif + + GNUNET_free (arg); + } + else /* Remote, scp the file to the correct place */ + { + if (NULL != pg->peers[pg_iter].daemon->username) + GNUNET_asprintf (&arg, "%s@%s:%s/blacklist", + pg->peers[pg_iter].daemon->username, + pg->peers[pg_iter].daemon->hostname, + temp_service_path); + else + GNUNET_asprintf (&arg, "%s:%s/blacklist", + pg->peers[pg_iter].daemon->hostname, + temp_service_path); + procarr[pg_iter] = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", mytemp, arg, NULL); + GNUNET_assert (procarr[pg_iter] != NULL); + GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: add scheduled blacklist file copy that parallelizes file copying! */ + +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Copying file with command scp %s %s\n"), mytemp, arg); +#endif + GNUNET_free (arg); + } + GNUNET_free (temp_service_path); + GNUNET_free (mytemp); + } + + count = 0; + ret = GNUNET_SYSERR; + while ((count < max_wait) && (ret != GNUNET_OK)) + { + ret = GNUNET_OK; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Checking copy status of file %d\n"), pg_iter); +#endif + if (procarr[pg_iter] != NULL) /* Check for already completed! */ + { + if (GNUNET_OS_process_status (procarr[pg_iter], &type, &return_code) != + GNUNET_OK) + { + ret = GNUNET_SYSERR; + } + else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0)) + { + ret = GNUNET_SYSERR; + } + else + { + GNUNET_OS_process_close (procarr[pg_iter]); + procarr[pg_iter] = NULL; +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("File %d copied\n"), pg_iter); +#endif + } + } + } + count++; + if (ret == GNUNET_SYSERR) + { + /* FIXME: why sleep here? -CG */ + sleep (1); + } + } + +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Finished copying all blacklist files!\n")); +#endif + GNUNET_free (procarr); + return ret; +} + +/* Forward Declaration */ +static void +schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Choose a random peer's next connection to create, and + * call schedule_connect to set up the connect task. + * + * @param pg the peer group to connect + */ +static void +preschedule_connect (struct GNUNET_TESTING_PeerGroup *pg) +{ + struct ConnectTopologyContext *ct_ctx = &pg->ct_ctx; + struct PeerConnection *connection_iter; + struct ConnectContext *connect_context; + uint32_t random_peer; + + if (ct_ctx->remaining_connections == 0) + return; + random_peer = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); + while (pg->peers[random_peer].connect_peers_head == NULL) + random_peer = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); + + connection_iter = pg->peers[random_peer].connect_peers_head; + connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); + connect_context->first_index = random_peer; + connect_context->second_index = connection_iter->index; + connect_context->ct_ctx = ct_ctx; + connect_context->task = + GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); + GNUNET_CONTAINER_DLL_insert (pg->cc_head, pg->cc_tail, connect_context); + GNUNET_CONTAINER_DLL_remove (pg->peers[random_peer].connect_peers_head, + pg->peers[random_peer].connect_peers_tail, + connection_iter); + GNUNET_free (connection_iter); + ct_ctx->remaining_connections--; +} + +#if USE_SEND_HELLOS +/* Forward declaration */ +static void +schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Close connections and free the hello context. + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +free_hello_context (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + + if (send_hello_context->peer->daemon->server != NULL) + { + GNUNET_CORE_disconnect (send_hello_context->peer->daemon->server); + send_hello_context->peer->daemon->server = NULL; + } + if (send_hello_context->peer->daemon->th != NULL) + { + GNUNET_TRANSPORT_disconnect (send_hello_context->peer->daemon->th); + send_hello_context->peer->daemon->th = NULL; + } + if (send_hello_context->core_connect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (send_hello_context->core_connect_task); + send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; + } + send_hello_context->pg->outstanding_connects--; + GNUNET_free (send_hello_context); +} + +/** + * For peers that haven't yet connected, notify + * the caller that they have failed (timeout). + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +notify_remaining_connections_failed (void *cls, + const struct GNUNET_SCHEDULER_TaskContext + *tc) +{ + struct SendHelloContext *send_hello_context = cls; + struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; + struct PeerConnection *connection; + + GNUNET_CORE_disconnect (send_hello_context->peer->daemon->server); + send_hello_context->peer->daemon->server = NULL; + + connection = send_hello_context->peer->connect_peers_head; + + while (connection != NULL) + { + if (pg->notify_connection != NULL) + { + pg->notify_connection (pg->notify_connection_cls, &send_hello_context->peer->daemon->id, &pg->peers[connection->index].daemon->id, 0, /* FIXME */ + send_hello_context->peer->daemon->cfg, + pg->peers[connection->index].daemon->cfg, + send_hello_context->peer->daemon, + pg->peers[connection->index].daemon, + "Peers failed to connect (timeout)"); + } + GNUNET_CONTAINER_DLL_remove (send_hello_context->peer->connect_peers_head, + send_hello_context->peer->connect_peers_tail, + connection); + GNUNET_free (connection); + connection = connection->next; + } + GNUNET_SCHEDULER_add_now (&free_hello_context, send_hello_context); +#if BAD + other_peer = &pg->peers[connection->index]; +#endif +} + +/** + * For peers that haven't yet connected, send + * CORE connect requests. + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +send_core_connect_requests (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + struct PeerConnection *conn; + + GNUNET_assert (send_hello_context->peer->daemon->server != NULL); + + send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; + + send_hello_context->connect_attempts++; + if (send_hello_context->connect_attempts < + send_hello_context->pg->ct_ctx.connect_attempts) + { + conn = send_hello_context->peer->connect_peers_head; + while (conn != NULL) + { + GNUNET_TRANSPORT_try_connect (send_hello_context->peer->daemon->th, + &send_hello_context->pg->peers[conn-> + index].daemon-> + id); + conn = conn->next; + } + send_hello_context->core_connect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide + (send_hello_context->pg-> + ct_ctx.connect_timeout, + send_hello_context->pg-> + ct_ctx.connect_attempts), + &send_core_connect_requests, + send_hello_context); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Timeout before all connections created, marking rest as failed!\n"); + GNUNET_SCHEDULER_add_now (¬ify_remaining_connections_failed, + send_hello_context); + } + +} + +/** + * Success, connection is up. Signal client our success. + * + * @param cls our "struct SendHelloContext" + * @param peer identity of the peer that has connected + * @param atsi performance information + * + * FIXME: remove peers from BOTH lists, call notify twice, should + * double the speed of connections as long as the list iteration + * doesn't take too long! + */ +static void +core_connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi) +{ + struct SendHelloContext *send_hello_context = cls; + struct PeerConnection *connection; + struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; + +#if BAD + struct PeerData *other_peer; +#endif +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to peer %s\n", + ctx->d1->shortname, GNUNET_i2s (peer)); +#endif + + if (0 == + memcmp (&send_hello_context->peer->daemon->id, peer, + sizeof (struct GNUNET_PeerIdentity))) + return; + + connection = send_hello_context->peer->connect_peers_head; +#if BAD + other_peer = NULL; +#endif + + while ((connection != NULL) && + (0 != + memcmp (&pg->peers[connection->index].daemon->id, peer, + sizeof (struct GNUNET_PeerIdentity)))) + { + connection = connection->next; + } + + if (connection == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected peer %s to %s, not in list (no problem(?))\n", + GNUNET_i2s (peer), send_hello_context->peer->daemon->shortname); + } + else + { +#if BAD + other_peer = &pg->peers[connection->index]; +#endif + if (pg->notify_connection != NULL) + { + pg->notify_connection (pg->notify_connection_cls, &send_hello_context->peer->daemon->id, peer, 0, /* FIXME */ + send_hello_context->peer->daemon->cfg, + pg->peers[connection->index].daemon->cfg, + send_hello_context->peer->daemon, + pg->peers[connection->index].daemon, NULL); + } + GNUNET_CONTAINER_DLL_remove (send_hello_context->peer->connect_peers_head, + send_hello_context->peer->connect_peers_tail, + connection); + GNUNET_free (connection); + } + +#if BAD + /* Notify of reverse connection and remove from other peers list of outstanding */ + if (other_peer != NULL) + { + connection = other_peer->connect_peers_head; + while ((connection != NULL) && + (0 != + memcmp (&send_hello_context->peer->daemon->id, + &pg->peers[connection->index].daemon->id, + sizeof (struct GNUNET_PeerIdentity)))) + { + connection = connection->next; + } + if (connection != NULL) + { + if (pg->notify_connection != NULL) + { + pg->notify_connection (pg->notify_connection_cls, peer, &send_hello_context->peer->daemon->id, 0, /* FIXME */ + pg->peers[connection->index].daemon->cfg, + send_hello_context->peer->daemon->cfg, + pg->peers[connection->index].daemon, + send_hello_context->peer->daemon, NULL); + } + + GNUNET_CONTAINER_DLL_remove (other_peer->connect_peers_head, + other_peer->connect_peers_tail, connection); + GNUNET_free (connection); + } + } +#endif + + if (send_hello_context->peer->connect_peers_head == NULL) + { + GNUNET_SCHEDULER_add_now (&free_hello_context, send_hello_context); + } +} + +/** + * Notify of a successful connection to the core service. + * + * @param cls a struct SendHelloContext * + * @param server handle to the core service + * @param my_identity the peer identity of this peer + */ +void +core_init (void *cls, struct GNUNET_CORE_Handle *server, + struct GNUNET_PeerIdentity *my_identity) +{ + struct SendHelloContext *send_hello_context = cls; + + send_hello_context->core_ready = GNUNET_YES; +} + +/** + * Function called once a hello has been sent + * to the transport, move on to the next one + * or go away forever. + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +hello_sent_callback (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + + //unsigned int pg_iter; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + GNUNET_free (send_hello_context); + return; + } + + send_hello_context->pg->remaining_hellos--; +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent HELLO, have %d remaining!\n", + send_hello_context->pg->remaining_hellos); +#endif + if (send_hello_context->peer_pos == NULL) /* All HELLOs (for this peer!) have been transmitted! */ + { +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All hellos for this peer sent, disconnecting transport!\n"); +#endif + GNUNET_assert (send_hello_context->peer->daemon->th != NULL); + GNUNET_TRANSPORT_disconnect (send_hello_context->peer->daemon->th); + send_hello_context->peer->daemon->th = NULL; + GNUNET_assert (send_hello_context->peer->daemon->server == NULL); + send_hello_context->peer->daemon->server = + GNUNET_CORE_connect (send_hello_context->peer->cfg, 1, + send_hello_context, &core_init, + &core_connect_notify, NULL, NULL, NULL, GNUNET_NO, + NULL, GNUNET_NO, no_handlers); + + send_hello_context->core_connect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide + (send_hello_context->pg-> + ct_ctx.connect_timeout, + send_hello_context->pg-> + ct_ctx.connect_attempts), + &send_core_connect_requests, + send_hello_context); + } + else + GNUNET_SCHEDULER_add_now (&schedule_send_hellos, send_hello_context); +} + +/** + * Connect to a peer, give it all the HELLO's of those peers + * we will later ask it to connect to. + * + * @param ct_ctx the overall connection context + */ +static void +schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + GNUNET_free (send_hello_context); + return; + } + + GNUNET_assert (send_hello_context->peer_pos != NULL); /* All of the HELLO sends to be scheduled have been scheduled! */ + + if (((send_hello_context->peer->daemon->th == NULL) && + (pg->outstanding_connects > pg->max_outstanding_connections)) || + (pg->stop_connects == GNUNET_YES)) + { +#if VERBOSE_TESTING > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ + ("Delaying connect, we have too many outstanding connections!\n")); +#endif + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_send_hellos, send_hello_context); + } + else + { +#if VERBOSE_TESTING > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating connection, outstanding_connections is %d\n"), + outstanding_connects); +#endif + if (send_hello_context->peer->daemon->th == NULL) + { + pg->outstanding_connects++; /* Actual TRANSPORT, CORE connections! */ + send_hello_context->peer->daemon->th = + GNUNET_TRANSPORT_connect (send_hello_context->peer->cfg, NULL, + send_hello_context, NULL, NULL, NULL); + } +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Offering HELLO of peer %s to peer %s\n"), + send_hello_context->peer->daemon->shortname, + pg->peers[send_hello_context->peer_pos->index]. + daemon->shortname); +#endif + GNUNET_TRANSPORT_offer_hello (send_hello_context->peer->daemon->th, + (const struct GNUNET_MessageHeader *) + pg->peers[send_hello_context->peer_pos-> + index].daemon->hello, + &hello_sent_callback, send_hello_context); + send_hello_context->peer_pos = send_hello_context->peer_pos->next; + GNUNET_assert (send_hello_context->peer->daemon->th != NULL); + } +} +#endif + +/** + * Internal notification of a connection, kept so that we can ensure some connections + * happen instead of flooding all testing daemons with requests to connect. + */ +static void +internal_connect_notify (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, + uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + struct ConnectContext *connect_ctx = cls; + struct ConnectTopologyContext *ct_ctx = connect_ctx->ct_ctx; + struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; + struct PeerConnection *connection; + + GNUNET_assert (NULL != connect_ctx->cc); + connect_ctx->cc = NULL; + GNUNET_assert (0 < pg->outstanding_connects); + pg->outstanding_connects--; + GNUNET_CONTAINER_DLL_remove (pg->cc_head, pg->cc_tail, connect_ctx); + /* + * Check whether the inverse connection has been scheduled yet, + * if not, we can remove it from the other peers list and avoid + * even trying to connect them again! + */ + connection = pg->peers[connect_ctx->second_index].connect_peers_head; +#if BAD + other_peer = NULL; +#endif + + while ((connection != NULL) && + (0 != + memcmp (first, &pg->peers[connection->index].daemon->id, + sizeof (struct GNUNET_PeerIdentity)))) + connection = connection->next; + + if (connection != NULL) /* Can safely remove! */ + { + GNUNET_assert (0 < ct_ctx->remaining_connections); + ct_ctx->remaining_connections--; + if (pg->notify_connection != NULL) /* Notify of reverse connection */ + pg->notify_connection (pg->notify_connection_cls, second, first, distance, + second_cfg, first_cfg, second_daemon, first_daemon, + emsg); + + GNUNET_CONTAINER_DLL_remove (pg-> + peers[connect_ctx-> + second_index].connect_peers_head, + pg->peers[connect_ctx-> + second_index].connect_peers_tail, + connection); + GNUNET_free (connection); + } + + if (ct_ctx->remaining_connections == 0) + { + if (ct_ctx->notify_connections_done != NULL) + { + ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL); + ct_ctx->notify_connections_done = NULL; + } + } + else + preschedule_connect (pg); + + if (pg->notify_connection != NULL) + pg->notify_connection (pg->notify_connection_cls, first, second, distance, + first_cfg, second_cfg, first_daemon, second_daemon, + emsg); + GNUNET_free (connect_ctx); +} + +/** + * Either delay a connection (because there are too many outstanding) + * or schedule it for right now. + * + * @param cls a connection context + * @param tc the task runtime context + */ +static void +schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ConnectContext *connect_context = cls; + struct GNUNET_TESTING_PeerGroup *pg = connect_context->ct_ctx->pg; + + connect_context->task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + if ((pg->outstanding_connects > pg->max_outstanding_connections) || + (pg->stop_connects == GNUNET_YES)) + { +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ + ("Delaying connect, we have too many outstanding connections!\n")); +#endif + connect_context->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_connect, connect_context); + return; + } +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ + ("Creating connection, outstanding_connections is %d (max %d)\n"), + pg->outstanding_connects, pg->max_outstanding_connections); +#endif + pg->outstanding_connects++; + pg->total_connects_scheduled++; + GNUNET_assert (NULL == connect_context->cc); + connect_context->cc = + GNUNET_TESTING_daemons_connect (pg-> + peers[connect_context-> + first_index].daemon, + pg->peers[connect_context-> + second_index].daemon, + connect_context->ct_ctx->connect_timeout, + connect_context->ct_ctx->connect_attempts, +#if USE_SEND_HELLOS + GNUNET_NO, +#else + GNUNET_YES, +#endif + &internal_connect_notify, + connect_context); + +} + +#if !OLD +/** + * Iterator for actually scheduling connections to be created + * between two peers. + * + * @param cls closure, a GNUNET_TESTING_Daemon + * @param key the key the second Daemon was stored under + * @param value the GNUNET_TESTING_Daemon that the first is to connect to + * + * @return GNUNET_YES to continue iteration + */ +static int +connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ConnectTopologyContext *ct_ctx = cls; + struct PeerData *first = ct_ctx->first; + struct GNUNET_TESTING_Daemon *second = value; + struct ConnectContext *connect_context; + + connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); + connect_context->first = first->daemon; + connect_context->second = second; + connect_context->ct_ctx = ct_ctx; + connect_context->task = + GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); + GNUNET_CONTAINER_DLL_insert (ct_ctx->pg->cc_head, ct_ctx->pg->cc_tail, + connect_context); + return GNUNET_YES; +} +#endif + +#if !OLD +/** + * Iterator for copying all entries in the allowed hashmap to the + * connect hashmap. + * + * @param cls closure, a GNUNET_TESTING_Daemon + * @param key the key the second Daemon was stored under + * @param value the GNUNET_TESTING_Daemon that the first is to connect to + * + * @return GNUNET_YES to continue iteration + */ +static int +copy_topology_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct PeerData *first = cls; + + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (first->connect_peers, key, + value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + + return GNUNET_YES; +} +#endif + +/** + * Make the peers to connect the same as those that are allowed to be + * connected. + * + * @param pg the peer group + */ +static int +copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg) +{ + unsigned int pg_iter; + int ret; + int total; + +#if OLD + struct PeerConnection *iter; +#endif + total = 0; + ret = 0; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if OLD + iter = pg->peers[pg_iter].allowed_peers_head; + while (iter != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating connection between %d and %d\n", pg_iter, + iter->index); + total += add_connections (pg, pg_iter, iter->index, CONNECT, GNUNET_YES); + //total += add_actual_connections(pg, pg_iter, iter->index); + iter = iter->next; + } +#else + ret = + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, + ©_topology_iterator, + &pg->peers[pg_iter]); +#endif + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; + + total = total + ret; + } + + return total; +} + +/** + * Connect the topology as specified by the PeerConnection's + * of each peer in the peer group + * + * @param pg the peer group we are dealing with + * @param connect_timeout how long try connecting two peers + * @param connect_attempts how many times (max) to attempt + * @param notify_callback callback to notify when finished + * @param notify_cls closure for notify callback + * + * @return the number of connections that will be attempted + */ +static int +connect_topology (struct GNUNET_TESTING_PeerGroup *pg, + struct GNUNET_TIME_Relative connect_timeout, + unsigned int connect_attempts, + GNUNET_TESTING_NotifyCompletion notify_callback, + void *notify_cls) +{ + unsigned int pg_iter; + unsigned int total; + +#if OLD + struct PeerConnection *connection_iter; +#endif +#if USE_SEND_HELLOS + struct SendHelloContext *send_hello_context; +#endif + + total = 0; + pg->ct_ctx.notify_connections_done = notify_callback; + pg->ct_ctx.notify_cls = notify_cls; + pg->ct_ctx.pg = pg; + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if OLD + connection_iter = pg->peers[pg_iter].connect_peers_head; + while (connection_iter != NULL) + { + connection_iter = connection_iter->next; + total++; + } +#else + total += + GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers); +#endif + } + + if (total == 0) + return total; + + pg->ct_ctx.connect_timeout = connect_timeout; + pg->ct_ctx.connect_attempts = connect_attempts; + pg->ct_ctx.remaining_connections = total; + +#if USE_SEND_HELLOS + /* First give all peers the HELLO's of other peers (connect to first peer's transport service, give HELLO's of other peers, continue...) */ + pg->remaining_hellos = total; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + send_hello_context = GNUNET_malloc (sizeof (struct SendHelloContext)); + send_hello_context->peer = &pg->peers[pg_iter]; + send_hello_context->peer_pos = pg->peers[pg_iter].connect_peers_head; + send_hello_context->pg = pg; + GNUNET_SCHEDULER_add_now (&schedule_send_hellos, send_hello_context); + } +#else + for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++) + { + preschedule_connect (pg); + } +#endif + return total; + +} + +/** + * Takes a peer group and creates a topology based on the + * one specified. Creates a topology means generates friend + * files for the peers so they can only connect to those allowed + * by the topology. This will only have an effect once peers + * are started if the FRIENDS_ONLY option is set in the base + * config. Also takes an optional restrict topology which + * disallows connections based on particular transports + * UNLESS they are specified in the restricted topology. + * + * @param pg the peer group struct representing the running peers + * @param topology which topology to connect the peers in + * @param restrict_topology disallow restrict_transports transport + * connections to peers NOT in this topology + * use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions + * @param restrict_transports space delimited list of transports to blacklist + * to create restricted topology + * + * @return the maximum number of connections were all allowed peers + * connected to each other + */ +unsigned int +GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg, + enum GNUNET_TESTING_Topology topology, + enum GNUNET_TESTING_Topology restrict_topology, + const char *restrict_transports) +{ + int ret; + + unsigned int num_connections; + int unblacklisted_connections; + char *filename; + struct PeerConnection *conn_iter; + struct PeerConnection *temp_conn; + unsigned int off; + +#if !OLD + unsigned int i; + + for (i = 0; i < pg->total; i++) + { + pg->peers[i].allowed_peers = GNUNET_CONTAINER_multihashmap_create (100); + pg->peers[i].connect_peers = GNUNET_CONTAINER_multihashmap_create (100); + pg->peers[i].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create (100); + pg->peers[i].pg = pg; + } +#endif + + switch (topology) + { + case GNUNET_TESTING_TOPOLOGY_CLIQUE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating clique topology\n")); + num_connections = create_clique (pg, &add_connections, ALLOWED, GNUNET_NO); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating small world (ring) topology\n")); + num_connections = create_small_world_ring (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating small world (2d-torus) topology\n")); + num_connections = create_small_world (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_RING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating ring topology\n")); + num_connections = create_ring (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_2D_TORUS: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating 2d torus topology\n")); + num_connections = create_2d_torus (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating Erdos-Renyi topology\n")); + num_connections = create_erdos_renyi (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_INTERNAT: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating InterNAT topology\n")); + num_connections = create_nated_internet (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating Scale Free topology\n")); + num_connections = create_scale_free (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_LINE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating straight line topology\n")); + num_connections = create_line (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_FROM_FILE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating topology from file!\n")); + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "testing", + "topology_file", &filename)) + num_connections = + create_from_file (pg, filename, &add_connections, ALLOWED); + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Missing configuration option TESTING:TOPOLOGY_FILE for creating topology from file!\n"); + num_connections = 0; + } + break; + case GNUNET_TESTING_TOPOLOGY_NONE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ + ("Creating no allowed topology (all peers can connect at core level)\n")); + num_connections = pg->total * pg->total; /* Clique is allowed! */ + break; + default: + num_connections = 0; + break; + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F")) + { + ret = create_and_copy_friend_files (pg); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Failed during friend file copying!\n")); + return GNUNET_SYSERR; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Friend files created/copied successfully!\n")); + } + } + + /* Use the create clique method to initially set all connections as blacklisted. */ + if ((restrict_topology != GNUNET_TESTING_TOPOLOGY_NONE) && + (restrict_topology != GNUNET_TESTING_TOPOLOGY_FROM_FILE)) + create_clique (pg, &add_connections, BLACKLIST, GNUNET_NO); + else + return num_connections; + + unblacklisted_connections = 0; + /* Un-blacklist connections as per the topology specified */ + switch (restrict_topology) + { + case GNUNET_TESTING_TOPOLOGY_CLIQUE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Blacklisting all but clique topology\n")); + unblacklisted_connections = + create_clique (pg, &remove_connections, BLACKLIST, GNUNET_NO); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Blacklisting all but small world (ring) topology\n")); + unblacklisted_connections = + create_small_world_ring (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Blacklisting all but small world (2d-torus) topology\n")); + unblacklisted_connections = + create_small_world (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_RING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Blacklisting all but ring topology\n")); + unblacklisted_connections = + create_ring (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_2D_TORUS: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Blacklisting all but 2d torus topology\n")); + unblacklisted_connections = + create_2d_torus (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Blacklisting all but Erdos-Renyi topology\n")); + unblacklisted_connections = + create_erdos_renyi (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_INTERNAT: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Blacklisting all but InterNAT topology\n")); + +#if TOPOLOGY_HACK + for (off = 0; off < pg->total; off++) + { + conn_iter = pg->peers[off].allowed_peers_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].allowed_peers_head = NULL; + pg->peers[off].allowed_peers_tail = NULL; + + conn_iter = pg->peers[off].connect_peers_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].connect_peers_head = NULL; + pg->peers[off].connect_peers_tail = NULL; + } + unblacklisted_connections = + create_nated_internet_copy (pg, &remove_connections, BLACKLIST); +#else + unblacklisted_connections = + create_nated_internet (pg, &remove_connections, BLACKLIST); +#endif + + break; + case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Blacklisting all but Scale Free topology\n")); + unblacklisted_connections = + create_scale_free (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_LINE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Blacklisting all but straight line topology\n")); + unblacklisted_connections = + create_line (pg, &remove_connections, BLACKLIST); + default: + break; + } + + if ((unblacklisted_connections > 0) && (restrict_transports != NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating blacklist with `%s'\n", + restrict_transports); + ret = create_and_copy_blacklist_files (pg, restrict_transports); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Failed during blacklist file copying!\n")); + return 0; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Blacklist files created/copied successfully!\n")); + } + } + return num_connections; +} + +#if !OLD +/** + * Iterator for choosing random peers to connect. + * + * @param cls closure, a RandomContext + * @param key the key the second Daemon was stored under + * @param value the GNUNET_TESTING_Daemon that the first is to connect to + * + * @return GNUNET_YES to continue iteration + */ +static int +random_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct RandomContext *random_ctx = cls; + double random_number; + uint32_t second_pos; + GNUNET_HashCode first_hash; + + random_number = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); + if (random_number < random_ctx->percentage) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (random_ctx-> + first->connect_peers_working_set, + key, value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + } + + /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */ + uid_from_hash (key, &second_pos); + hash_from_uid (random_ctx->first_uid, &first_hash); + GNUNET_assert (random_ctx->pg->total > second_pos); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (random_ctx-> + pg->peers + [second_pos].connect_peers, + &first_hash, + random_ctx-> + first->daemon)); + + return GNUNET_YES; +} + +/** + * Iterator for adding at least X peers to a peers connection set. + * + * @param cls closure, MinimumContext + * @param key the key the second Daemon was stored under + * @param value the GNUNET_TESTING_Daemon that the first is to connect to + * + * @return GNUNET_YES to continue iteration + */ +static int +minimum_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct MinimumContext *min_ctx = cls; + uint32_t second_pos; + GNUNET_HashCode first_hash; + unsigned int i; + + if (GNUNET_CONTAINER_multihashmap_size + (min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add) + { + for (i = 0; i < min_ctx->num_to_add; i++) + { + if (min_ctx->pg_array[i] == min_ctx->current) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (min_ctx-> + first->connect_peers_working_set, + key, value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + uid_from_hash (key, &second_pos); + hash_from_uid (min_ctx->first_uid, &first_hash); + GNUNET_assert (min_ctx->pg->total > second_pos); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (min_ctx-> + pg->peers + [second_pos].connect_peers_working_set, + &first_hash, + min_ctx->first-> + daemon, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */ + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (min_ctx-> + pg->peers + [second_pos].connect_peers, + &first_hash, + min_ctx-> + first->daemon)); + } + } + min_ctx->current++; + return GNUNET_YES; + } + else + return GNUNET_NO; /* We can stop iterating, we have enough peers! */ + +} + +/** + * Iterator for adding peers to a connection set based on a depth first search. + * + * @param cls closure, MinimumContext + * @param key the key the second daemon was stored under + * @param value the GNUNET_TESTING_Daemon that the first is to connect to + * + * @return GNUNET_YES to continue iteration + */ +static int +dfs_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct DFSContext *dfs_ctx = cls; + GNUNET_HashCode first_hash; + + if (dfs_ctx->current == dfs_ctx->chosen) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (dfs_ctx-> + first->connect_peers_working_set, + key, value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + uid_from_hash (key, &dfs_ctx->second_uid); + hash_from_uid (dfs_ctx->first_uid, &first_hash); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (dfs_ctx-> + pg->peers[dfs_ctx-> + second_uid].connect_peers_working_set, + &first_hash, + dfs_ctx->first->daemon, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (dfs_ctx-> + pg->peers + [dfs_ctx->second_uid].connect_peers, + &first_hash, + dfs_ctx-> + first->daemon)); + /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */ + return GNUNET_NO; /* We have found our peer, don't iterate more */ + } + + dfs_ctx->current++; + return GNUNET_YES; +} +#endif + +/** + * From the set of connections possible, choose percentage percent of connections + * to actually connect. + * + * @param pg the peergroup we are dealing with + * @param percentage what percent of total connections to make + */ +void +choose_random_connections (struct GNUNET_TESTING_PeerGroup *pg, + double percentage) +{ + uint32_t pg_iter; + +#if OLD + struct PeerConnection *conn_iter; + double random_number; +#else + struct RandomContext random_ctx; +#endif + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if OLD + conn_iter = pg->peers[pg_iter].connect_peers_head; + while (conn_iter != NULL) + { + random_number = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); + if (random_number < percentage) + { + add_connections (pg, pg_iter, conn_iter->index, WORKING_SET, + GNUNET_YES); + } + conn_iter = conn_iter->next; + } +#else + random_ctx.first_uid = pg_iter; + random_ctx.first = &pg->peers[pg_iter]; + random_ctx.percentage = percentage; + random_ctx.pg = pg; + pg->peers[pg_iter].connect_peers_working_set = + GNUNET_CONTAINER_multihashmap_create (pg->total); + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers, + &random_connect_iterator, + &random_ctx); + /* Now remove the old connections */ + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); + /* And replace with the random set */ + pg->peers[pg_iter].connect_peers = + pg->peers[pg_iter].connect_peers_working_set; +#endif + } + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + conn_iter = pg->peers[pg_iter].connect_peers_head; + while (pg->peers[pg_iter].connect_peers_head != NULL) + remove_connections (pg, pg_iter, + pg->peers[pg_iter].connect_peers_head->index, CONNECT, + GNUNET_YES); + + pg->peers[pg_iter].connect_peers_head = + pg->peers[pg_iter].connect_peers_working_set_head; + pg->peers[pg_iter].connect_peers_tail = + pg->peers[pg_iter].connect_peers_working_set_tail; + pg->peers[pg_iter].connect_peers_working_set_head = NULL; + pg->peers[pg_iter].connect_peers_working_set_tail = NULL; + } +} + +/** + * Count the number of connections in a linked list of connections. + * + * @param conn_list the connection list to get the count of + * + * @return the number of elements in the list + */ +static unsigned int +count_connections (struct PeerConnection *conn_list) +{ + struct PeerConnection *iter; + unsigned int count; + + count = 0; + iter = conn_list; + while (iter != NULL) + { + iter = iter->next; + count++; + } + return count; +} + +static unsigned int +count_workingset_connections (struct GNUNET_TESTING_PeerGroup *pg) +{ + unsigned int count; + unsigned int pg_iter; + +#if OLD + struct PeerConnection *conn_iter; +#endif + count = 0; + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if OLD + conn_iter = pg->peers[pg_iter].connect_peers_working_set_head; + while (conn_iter != NULL) + { + count++; + conn_iter = conn_iter->next; + } +#else + count += + GNUNET_CONTAINER_multihashmap_size (pg-> + peers + [pg_iter].connect_peers_working_set); +#endif + } + + return count; +} + +static unsigned int +count_allowed_connections (struct GNUNET_TESTING_PeerGroup *pg) +{ + unsigned int count; + unsigned int pg_iter; + +#if OLD + struct PeerConnection *conn_iter; +#endif + + count = 0; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if OLD + conn_iter = pg->peers[pg_iter].allowed_peers_head; + while (conn_iter != NULL) + { + count++; + conn_iter = conn_iter->next; + } +#else + count += + GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].allowed_peers); +#endif + } + + return count; +} + +/** + * From the set of connections possible, choose at least num connections per + * peer. + * + * @param pg the peergroup we are dealing with + * @param num how many connections at least should each peer have (if possible)? + */ +static void +choose_minimum (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num) +{ +#if !OLD + struct MinimumContext minimum_ctx; +#else + struct PeerConnection *conn_iter; + unsigned int temp_list_size; + unsigned int i; + unsigned int count; + uint32_t random; /* Random list entry to connect peer to */ +#endif + uint32_t pg_iter; + +#if OLD + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + temp_list_size = count_connections (pg->peers[pg_iter].connect_peers_head); + if (temp_list_size == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peer %d has 0 connections!?!?\n", + pg_iter); + break; + } + for (i = 0; i < num; i++) + { + random = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, temp_list_size); + conn_iter = pg->peers[pg_iter].connect_peers_head; + for (count = 0; count < random; count++) + conn_iter = conn_iter->next; + /* We now have a random connection, connect it! */ + GNUNET_assert (conn_iter != NULL); + add_connections (pg, pg_iter, conn_iter->index, WORKING_SET, GNUNET_YES); + } + } +#else + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + pg->peers[pg_iter].connect_peers_working_set = + GNUNET_CONTAINER_multihashmap_create (num); + } + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + minimum_ctx.first_uid = pg_iter; + minimum_ctx.pg_array = + GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, + GNUNET_CONTAINER_multihashmap_size + (pg->peers[pg_iter].connect_peers)); + minimum_ctx.first = &pg->peers[pg_iter]; + minimum_ctx.pg = pg; + minimum_ctx.num_to_add = num; + minimum_ctx.current = 0; + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers, + &minimum_connect_iterator, + &minimum_ctx); + } + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + /* Remove the "old" connections */ + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); + /* And replace with the working set */ + pg->peers[pg_iter].connect_peers = + pg->peers[pg_iter].connect_peers_working_set; + } +#endif + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + while (pg->peers[pg_iter].connect_peers_head != NULL) + { + conn_iter = pg->peers[pg_iter].connect_peers_head; + GNUNET_CONTAINER_DLL_remove (pg->peers[pg_iter].connect_peers_head, + pg->peers[pg_iter].connect_peers_tail, + conn_iter); + GNUNET_free (conn_iter); + /*remove_connections(pg, pg_iter, pg->peers[pg_iter].connect_peers_head->index, CONNECT, GNUNET_YES); */ + } + + pg->peers[pg_iter].connect_peers_head = + pg->peers[pg_iter].connect_peers_working_set_head; + pg->peers[pg_iter].connect_peers_tail = + pg->peers[pg_iter].connect_peers_working_set_tail; + pg->peers[pg_iter].connect_peers_working_set_head = NULL; + pg->peers[pg_iter].connect_peers_working_set_tail = NULL; + } +} + +#if !OLD +struct FindClosestContext +{ + /** + * The currently known closest peer. + */ + struct GNUNET_TESTING_Daemon *closest; + + /** + * The info for the peer we are adding connections for. + */ + struct PeerData *curr_peer; + + /** + * The distance (bits) between the current + * peer and the currently known closest. + */ + unsigned int closest_dist; + + /** + * The offset of the closest known peer in + * the peer group. + */ + unsigned int closest_num; +}; + +/** + * Iterator over hash map entries of the allowed + * peer connections. Find the closest, not already + * connected peer and return it. + * + * @param cls closure (struct FindClosestContext) + * @param key current key code (hash of offset in pg) + * @param value value in the hash map - a GNUNET_TESTING_Daemon + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +find_closest_peers (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct FindClosestContext *closest_ctx = cls; + struct GNUNET_TESTING_Daemon *daemon = value; + + if (((closest_ctx->closest == NULL) || + (GNUNET_CRYPTO_hash_matching_bits + (&daemon->id.hashPubKey, + &closest_ctx->curr_peer->daemon->id.hashPubKey) > + closest_ctx->closest_dist)) && + (GNUNET_YES != + GNUNET_CONTAINER_multihashmap_contains (closest_ctx-> + curr_peer->connect_peers, key))) + { + closest_ctx->closest_dist = + GNUNET_CRYPTO_hash_matching_bits (&daemon->id.hashPubKey, + &closest_ctx->curr_peer->daemon-> + id.hashPubKey); + closest_ctx->closest = daemon; + uid_from_hash (key, &closest_ctx->closest_num); + } + return GNUNET_YES; +} + +/** + * From the set of connections possible, choose at num connections per + * peer based on depth which are closest out of those allowed. Guaranteed + * to add num peers to connect to, provided there are that many peers + * in the underlay topology to connect to. + * + * @param pg the peergroup we are dealing with + * @param num how many connections at least should each peer have (if possible)? + * @param proc processor to actually add the connections + * @param list the peer list to use + */ +void +add_closest (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ +#if OLD + +#else + struct FindClosestContext closest_ctx; +#endif + uint32_t pg_iter; + uint32_t i; + + for (i = 0; i < num; i++) /* Each time find a closest peer (from those available) */ + { + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + closest_ctx.curr_peer = &pg->peers[pg_iter]; + closest_ctx.closest = NULL; + closest_ctx.closest_dist = 0; + closest_ctx.closest_num = 0; + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, + &find_closest_peers, &closest_ctx); + if (closest_ctx.closest != NULL) + { + GNUNET_assert (closest_ctx.closest_num < pg->total); + proc (pg, pg_iter, closest_ctx.closest_num, list); + } + } + } +} +#endif + +/** + * From the set of connections possible, choose at least num connections per + * peer based on depth first traversal of peer connections. If DFS leaves + * peers unconnected, ensure those peers get connections. + * + * @param pg the peergroup we are dealing with + * @param num how many connections at least should each peer have (if possible)? + */ +void +perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num) +{ + uint32_t pg_iter; + uint32_t dfs_count; + uint32_t starting_peer; + uint32_t least_connections; + uint32_t random_connection; + +#if OLD + unsigned int temp_count; + struct PeerConnection *peer_iter; +#else + struct DFSContext dfs_ctx; + GNUNET_HashCode second_hash; +#endif + +#if OLD + starting_peer = 0; + dfs_count = 0; + while ((count_workingset_connections (pg) < num * pg->total) && + (count_allowed_connections (pg) > 0)) + { + if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */ + { + least_connections = -1; /* Set to very high number */ + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + temp_count = + count_connections (pg-> + peers[pg_iter].connect_peers_working_set_head); + if (temp_count < least_connections) + { + starting_peer = pg_iter; + least_connections = temp_count; + } + } + } + + temp_count = + count_connections (pg->peers[starting_peer].connect_peers_head); + if (temp_count == 0) + continue; /* FIXME: infinite loop? */ + + random_connection = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, temp_count); + temp_count = 0; + peer_iter = pg->peers[starting_peer].connect_peers_head; + while (temp_count < random_connection) + { + peer_iter = peer_iter->next; + temp_count++; + } + GNUNET_assert (peer_iter != NULL); + add_connections (pg, starting_peer, peer_iter->index, WORKING_SET, + GNUNET_NO); + remove_connections (pg, starting_peer, peer_iter->index, CONNECT, + GNUNET_YES); + starting_peer = peer_iter->index; + dfs_count++; + } + +#else + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + pg->peers[pg_iter].connect_peers_working_set = + GNUNET_CONTAINER_multihashmap_create (num); + } + + starting_peer = 0; + dfs_count = 0; + while ((count_workingset_connections (pg) < num * pg->total) && + (count_allowed_connections (pg) > 0)) + { + if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */ + { + least_connections = -1; /* Set to very high number */ + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + if (GNUNET_CONTAINER_multihashmap_size + (pg->peers[pg_iter].connect_peers_working_set) < least_connections) + { + starting_peer = pg_iter; + least_connections = + GNUNET_CONTAINER_multihashmap_size (pg-> + peers + [pg_iter].connect_peers_working_set); + } + } + } + + if (GNUNET_CONTAINER_multihashmap_size (pg->peers[starting_peer].connect_peers) == 0) /* Ensure there is at least one peer left to connect! */ + { + dfs_count = 0; + continue; + } + + /* Choose a random peer from the chosen peers set of connections to add */ + dfs_ctx.chosen = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + GNUNET_CONTAINER_multihashmap_size (pg->peers + [starting_peer].connect_peers)); + dfs_ctx.first_uid = starting_peer; + dfs_ctx.first = &pg->peers[starting_peer]; + dfs_ctx.pg = pg; + dfs_ctx.current = 0; + + GNUNET_CONTAINER_multihashmap_iterate (pg-> + peers[starting_peer].connect_peers, + &dfs_connect_iterator, &dfs_ctx); + /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */ + hash_from_uid (dfs_ctx.second_uid, &second_hash); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (pg->peers + [starting_peer].connect_peers, + &second_hash, + pg-> + peers + [dfs_ctx.second_uid].daemon)); + starting_peer = dfs_ctx.second_uid; + } + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + /* Remove the "old" connections */ + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); + /* And replace with the working set */ + pg->peers[pg_iter].connect_peers = + pg->peers[pg_iter].connect_peers_working_set; + } +#endif +} + +/** + * Internal callback for topology information for a particular peer. + */ +static void +internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct CoreContext *core_ctx = cls; + struct TopologyIterateContext *iter_ctx = core_ctx->iter_context; + + if (peer == NULL) /* Either finished, or something went wrong */ + { + iter_ctx->completed++; + iter_ctx->connected--; + /* One core context allocated per iteration, must free! */ + GNUNET_free (core_ctx); + } + else + { + iter_ctx->topology_cb (iter_ctx->cls, &core_ctx->daemon->id, peer, NULL); + } + + if (iter_ctx->completed == iter_ctx->total) + { + iter_ctx->topology_cb (iter_ctx->cls, NULL, NULL, NULL); + /* Once all are done, free the iteration context */ + GNUNET_free (iter_ctx); + } +} + +/** + * Check running topology iteration tasks, if below max start a new one, otherwise + * schedule for some time in the future. + */ +static void +schedule_get_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CoreContext *core_context = cls; + struct TopologyIterateContext *topology_context = + (struct TopologyIterateContext *) core_context->iter_context; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + if (topology_context->connected > + topology_context->pg->max_outstanding_connections) + { +#if VERBOSE_TESTING > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ + ("Delaying connect, we have too many outstanding connections!\n")); +#endif + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_get_topology, core_context); + } + else + { +#if VERBOSE_TESTING > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating connection, outstanding_connections is %d\n"), + outstanding_connects); +#endif + topology_context->connected++; + + if (GNUNET_OK != + GNUNET_CORE_iterate_peers (core_context->daemon->cfg, + &internal_topology_callback, core_context)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Topology iteration failed.\n"); + internal_topology_callback (core_context, NULL, NULL, 0); + } + } +} + +/** + * Iterate over all (running) peers in the peer group, retrieve + * all connections that each currently has. + */ +void +GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_NotifyTopology cb, void *cls) +{ + struct TopologyIterateContext *topology_context; + struct CoreContext *core_ctx; + unsigned int i; + unsigned int total_count; + + /* Allocate a single topology iteration context */ + topology_context = GNUNET_malloc (sizeof (struct TopologyIterateContext)); + topology_context->topology_cb = cb; + topology_context->cls = cls; + topology_context->pg = pg; + total_count = 0; + for (i = 0; i < pg->total; i++) + { + if (pg->peers[i].daemon->running == GNUNET_YES) + { + /* Allocate one core context per core we need to connect to */ + core_ctx = GNUNET_malloc (sizeof (struct CoreContext)); + core_ctx->daemon = pg->peers[i].daemon; + /* Set back pointer to topology iteration context */ + core_ctx->iter_context = topology_context; + GNUNET_SCHEDULER_add_now (&schedule_get_topology, core_ctx); + total_count++; + } + } + if (total_count == 0) + { + cb (cls, NULL, NULL, "Cannot iterate over topology, no running peers!"); + GNUNET_free (topology_context); + } + else + topology_context->total = total_count; + return; +} + +/** + * Callback function to process statistic values. + * This handler is here only really to insert a peer + * identity (or daemon) so the statistics can be uniquely + * tied to a single running peer. + * + * @param cls closure + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +internal_stats_callback (void *cls, const char *subsystem, const char *name, + uint64_t value, int is_persistent) +{ + struct StatsCoreContext *core_context = cls; + struct StatsIterateContext *stats_context = + (struct StatsIterateContext *) core_context->iter_context; + + return stats_context->proc (stats_context->cls, &core_context->daemon->id, + subsystem, name, value, is_persistent); +} + +/** + * Internal continuation call for statistics iteration. + * + * @param cls closure, the CoreContext for this iteration + * @param success whether or not the statistics iterations + * was canceled or not (we don't care) + */ +static void +internal_stats_cont (void *cls, int success) +{ + struct StatsCoreContext *core_context = cls; + struct StatsIterateContext *stats_context = + (struct StatsIterateContext *) core_context->iter_context; + + stats_context->connected--; + stats_context->completed++; + + if (stats_context->completed == stats_context->total) + { + stats_context->cont (stats_context->cls, GNUNET_YES); + GNUNET_free (stats_context); + } + + if (core_context->stats_handle != NULL) + GNUNET_STATISTICS_destroy (core_context->stats_handle, GNUNET_NO); + + GNUNET_free (core_context); +} + +/** + * Check running topology iteration tasks, if below max start a new one, otherwise + * schedule for some time in the future. + */ +static void +schedule_get_statistics (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct StatsCoreContext *core_context = cls; + struct StatsIterateContext *stats_context = + (struct StatsIterateContext *) core_context->iter_context; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + if (stats_context->connected > stats_context->pg->max_outstanding_connections) + { +#if VERBOSE_TESTING > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ + ("Delaying connect, we have too many outstanding connections!\n")); +#endif + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_get_statistics, core_context); + } + else + { +#if VERBOSE_TESTING > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating connection, outstanding_connections is %d\n"), + outstanding_connects); +#endif + + stats_context->connected++; + core_context->stats_handle = + GNUNET_STATISTICS_create ("testing", core_context->daemon->cfg); + if (core_context->stats_handle == NULL) + { + internal_stats_cont (core_context, GNUNET_NO); + return; + } + + core_context->stats_get_handle = + GNUNET_STATISTICS_get (core_context->stats_handle, NULL, NULL, + GNUNET_TIME_relative_get_forever (), + &internal_stats_cont, &internal_stats_callback, + core_context); + if (core_context->stats_get_handle == NULL) + internal_stats_cont (core_context, GNUNET_NO); + + } +} + +struct DuplicateStats +{ + /** + * Next item in the list + */ + struct DuplicateStats *next; + + /** + * Nasty string, concatenation of relevant information. + */ + char *unique_string; +}; + +/** + * Check whether the combination of port/host/unix domain socket + * already exists in the list of peers being checked for statistics. + * + * @param pg the peergroup in question + * @param specific_peer the peer we're concerned with + * @param stats_list the list to return to the caller + * + * @return GNUNET_YES if the statistics instance has been seen already, + * GNUNET_NO if not (and we may have added it to the list) + */ +static int +stats_check_existing (struct GNUNET_TESTING_PeerGroup *pg, + struct PeerData *specific_peer, + struct DuplicateStats **stats_list) +{ + struct DuplicateStats *pos; + char *unix_domain_socket; + unsigned long long port; + char *to_match; + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "testing", + "single_statistics_per_host")) + return GNUNET_NO; /* Each peer has its own statistics instance, do nothing! */ + + pos = *stats_list; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (specific_peer->cfg, "statistics", + "unixpath", &unix_domain_socket)) + return GNUNET_NO; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (specific_peer->cfg, "statistics", + "port", &port)) + { + GNUNET_free (unix_domain_socket); + return GNUNET_NO; + } + + if (specific_peer->daemon->hostname != NULL) + GNUNET_asprintf (&to_match, "%s%s%llu", specific_peer->daemon->hostname, + unix_domain_socket, port); + else + GNUNET_asprintf (&to_match, "%s%llu", unix_domain_socket, port); + + while (pos != NULL) + { + if (0 == strcmp (to_match, pos->unique_string)) + { + GNUNET_free (unix_domain_socket); + GNUNET_free (to_match); + return GNUNET_YES; + } + pos = pos->next; + } + pos = GNUNET_malloc (sizeof (struct DuplicateStats)); + pos->unique_string = to_match; + pos->next = *stats_list; + *stats_list = pos; + GNUNET_free (unix_domain_socket); + return GNUNET_NO; +} + +/** + * Iterate over all (running) peers in the peer group, retrieve + * all statistics from each. + * + * @param pg the peergroup to iterate statistics of + * @param cont continuation to call once all stats have been retrieved + * @param proc processing function for each statistic from each peer + * @param cls closure to pass to proc + * + */ +void +GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_STATISTICS_Callback cont, + GNUNET_TESTING_STATISTICS_Iterator proc, + void *cls) +{ + struct StatsIterateContext *stats_context; + struct StatsCoreContext *core_ctx; + unsigned int i; + unsigned int total_count; + struct DuplicateStats *stats_list; + struct DuplicateStats *pos; + + stats_list = NULL; + + /* Allocate a single stats iteration context */ + stats_context = GNUNET_malloc (sizeof (struct StatsIterateContext)); + stats_context->cont = cont; + stats_context->proc = proc; + stats_context->cls = cls; + stats_context->pg = pg; + total_count = 0; + + for (i = 0; i < pg->total; i++) + { + if ((pg->peers[i].daemon->running == GNUNET_YES) && + (GNUNET_NO == stats_check_existing (pg, &pg->peers[i], &stats_list))) + { + /* Allocate one core context per core we need to connect to */ + core_ctx = GNUNET_malloc (sizeof (struct StatsCoreContext)); + core_ctx->daemon = pg->peers[i].daemon; + /* Set back pointer to topology iteration context */ + core_ctx->iter_context = stats_context; + GNUNET_SCHEDULER_add_now (&schedule_get_statistics, core_ctx); + total_count++; + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Retrieving stats from %u total instances.\n", total_count); + if (0 != total_count) + stats_context->total = total_count; + else + GNUNET_free (stats_context); + if (stats_list != NULL) + { + pos = stats_list; + while (pos != NULL) + { + GNUNET_free (pos->unique_string); + stats_list = pos->next; + GNUNET_free (pos); + pos = stats_list->next; + } + } + return; +} + +/** + * Stop the connection process temporarily. + * + * @param pg the peer group to stop connecting + */ +void +GNUNET_TESTING_stop_connections (struct GNUNET_TESTING_PeerGroup *pg) +{ + pg->stop_connects = GNUNET_YES; +} + +/** + * Resume the connection process temporarily. + * + * @param pg the peer group to resume connecting + */ +void +GNUNET_TESTING_resume_connections (struct GNUNET_TESTING_PeerGroup *pg) +{ + pg->stop_connects = GNUNET_NO; +} + +/** + * There are many ways to connect peers that are supported by this function. + * To connect peers in the same topology that was created via the + * GNUNET_TESTING_create_topology, the topology variable must be set to + * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified, + * a new instance of that topology will be generated and attempted to be + * connected. This could result in some connections being impossible, + * because some topologies are non-deterministic. + * + * @param pg the peer group struct representing the running peers + * @param topology which topology to connect the peers in + * @param options options for connecting the topology + * @param option_modifier modifier for options that take a parameter + * @param connect_timeout how long to wait before giving up on connecting + * two peers + * @param connect_attempts how many times to attempt to connect two peers + * over the connect_timeout duration + * @param notify_callback notification to be called once all connections completed + * @param notify_cls closure for notification callback + * + * @return the number of connections that will be attempted, GNUNET_SYSERR on error + */ +int +GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg, + enum GNUNET_TESTING_Topology topology, + enum GNUNET_TESTING_TopologyOption options, + double option_modifier, + struct GNUNET_TIME_Relative connect_timeout, + unsigned int connect_attempts, + GNUNET_TESTING_NotifyCompletion + notify_callback, void *notify_cls) +{ + switch (topology) + { + case GNUNET_TESTING_TOPOLOGY_CLIQUE: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating clique CONNECT topology\n")); +#endif + create_clique (pg, &add_connections, CONNECT, GNUNET_NO); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating small world (ring) CONNECT topology\n")); +#endif + create_small_world_ring (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating small world (2d-torus) CONNECT topology\n")); +#endif + create_small_world (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_RING: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating ring CONNECT topology\n")); +#endif + create_ring (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_2D_TORUS: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating 2d torus CONNECT topology\n")); +#endif + create_2d_torus (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating Erdos-Renyi CONNECT topology\n")); +#endif + create_erdos_renyi (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_INTERNAT: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating InterNAT CONNECT topology\n")); +#endif + create_nated_internet (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating Scale Free CONNECT topology\n")); +#endif + create_scale_free (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_LINE: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating straight line CONNECT topology\n")); +#endif + create_line (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_NONE: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating no CONNECT topology\n")); +#endif + copy_allowed_topology (pg); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Unknown topology specification, can't connect peers!\n")); + return GNUNET_SYSERR; + } + + switch (options) + { + case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ + ("Connecting random subset (%'.2f percent) of possible peers\n"), + 100 * option_modifier); +#endif + choose_random_connections (pg, option_modifier); + break; + case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Connecting a minimum of %u peers each (if possible)\n"), + (unsigned int) option_modifier); +#endif + choose_minimum (pg, (unsigned int) option_modifier); + break; + case GNUNET_TESTING_TOPOLOGY_OPTION_DFS: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ + ("Using DFS to connect a minimum of %u peers each (if possible)\n"), + (unsigned int) option_modifier); +#endif +#if FIXME + perform_dfs (pg, (int) option_modifier); +#endif + break; + case GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST: +#if VERBOSE_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Finding additional %u closest peers each (if possible)\n"), + (unsigned int) option_modifier); +#endif +#if FIXME + add_closest (pg, (unsigned int) option_modifier, &add_connections, CONNECT); +#endif + break; + case GNUNET_TESTING_TOPOLOGY_OPTION_NONE: + break; + case GNUNET_TESTING_TOPOLOGY_OPTION_ALL: + break; + default: + break; + } + + return connect_topology (pg, connect_timeout, connect_attempts, + notify_callback, notify_cls); +} + +/** + * Lookup and return the number of SSH connections to a host. + * + * @param hostname the hostname to lookup in the list + * @param pg the peergroup that the host belongs to + * + * @return the number of current ssh connections to the host + */ +static unsigned int +count_outstanding_at_host (const char *hostname, + struct GNUNET_TESTING_PeerGroup *pg) +{ + struct OutstandingSSH *pos; + + pos = pg->ssh_head; + while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) + pos = pos->next; + GNUNET_assert (pos != NULL); + return pos->outstanding; +} + +/** + * Increment the number of SSH connections to a host by one. + * + * @param hostname the hostname to lookup in the list + * @param pg the peergroup that the host belongs to + * + */ +static void +increment_outstanding_at_host (const char *hostname, + struct GNUNET_TESTING_PeerGroup *pg) +{ + struct OutstandingSSH *pos; + + pos = pg->ssh_head; + while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) + pos = pos->next; + GNUNET_assert (pos != NULL); + pos->outstanding++; +} + +/** + * Decrement the number of SSH connections to a host by one. + * + * @param hostname the hostname to lookup in the list + * @param pg the peergroup that the host belongs to + * + */ +static void +decrement_outstanding_at_host (const char *hostname, + struct GNUNET_TESTING_PeerGroup *pg) +{ + struct OutstandingSSH *pos; + + pos = pg->ssh_head; + while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) + pos = pos->next; + GNUNET_assert (pos != NULL); + pos->outstanding--; +} + +/** + * Callback that is called whenever a hostkey is generated + * for a peer. Call the real callback and decrement the + * starting counter for the peergroup. + * + * @param cls closure + * @param id identifier for the daemon, NULL on error + * @param d handle for the daemon + * @param emsg error message (NULL on success) + */ +static void +internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct InternalStartContext *internal_context = cls; + + internal_context->peer->pg->starting--; + internal_context->peer->pg->started++; + if (internal_context->hostname != NULL) + decrement_outstanding_at_host (internal_context->hostname, + internal_context->peer->pg); + if (internal_context->hostkey_callback != NULL) + internal_context->hostkey_callback (internal_context->hostkey_cls, id, d, + emsg); + else if (internal_context->peer->pg->started == + internal_context->peer->pg->total) + { + internal_context->peer->pg->started = 0; /* Internal startup may use this counter! */ + GNUNET_TESTING_daemons_continue_startup (internal_context->peer->pg); + } +} + +/** + * Callback that is called whenever a peer has finished starting. + * Call the real callback and decrement the starting counter + * for the peergroup. + * + * @param cls closure + * @param id identifier for the daemon, NULL on error + * @param cfg config + * @param d handle for the daemon + * @param emsg error message (NULL on success) + */ +static void +internal_startup_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct InternalStartContext *internal_context = cls; + + internal_context->peer->pg->starting--; + if (internal_context->hostname != NULL) + decrement_outstanding_at_host (internal_context->hostname, + internal_context->peer->pg); + if (internal_context->start_cb != NULL) + internal_context->start_cb (internal_context->start_cb_cls, id, cfg, d, + emsg); +} + + +/** + * Calls GNUNET_TESTING_daemon_continue_startup to set the daemon's state + * from HOSTKEY_CREATED to TOPOLOGY_SETUP. Makes sure not to saturate a host + * with requests delaying them when needed. + * + * @param cls closure: internal context of the daemon. + * @param tc TaskContext + */ +static void +internal_continue_startup (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct InternalStartContext *internal_context = cls; + + internal_context->peer->startup_task = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + return; + } + + if ((internal_context->peer->pg->starting < + internal_context->peer->pg->max_concurrent_ssh) || + ((internal_context->hostname != NULL) && + (count_outstanding_at_host + (internal_context->hostname, + internal_context->peer->pg) < + internal_context->peer->pg->max_concurrent_ssh))) + { + if (internal_context->hostname != NULL) + increment_outstanding_at_host (internal_context->hostname, + internal_context->peer->pg); + internal_context->peer->pg->starting++; + GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon); + } + else + { + internal_context->peer->startup_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &internal_continue_startup, + internal_context); + } +} + +/** + * Callback for informing us about a successful + * or unsuccessful churn start call. + * + * @param cls a ChurnContext + * @param id the peer identity of the started peer + * @param cfg the handle to the configuration of the peer + * @param d handle to the daemon for the peer + * @param emsg NULL on success, non-NULL on failure + * + */ +void +churn_start_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct ChurnRestartContext *startup_ctx = cls; + struct ChurnContext *churn_ctx = startup_ctx->churn_ctx; + + unsigned int total_left; + char *error_message; + + error_message = NULL; + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Churn stop callback failed with error `%s'\n", emsg); + churn_ctx->num_failed_start++; + } + else + { + churn_ctx->num_to_start--; + } + + total_left = + (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + + (churn_ctx->num_to_start - churn_ctx->num_failed_start); + + if (total_left == 0) + { + if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0)) + GNUNET_asprintf (&error_message, + "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", + churn_ctx->num_failed_start, churn_ctx->num_failed_stop); + churn_ctx->cb (churn_ctx->cb_cls, error_message); + GNUNET_free_non_null (error_message); + GNUNET_free (churn_ctx); + GNUNET_free (startup_ctx); + } +} + +static void +schedule_churn_restart (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerRestartContext *peer_restart_ctx = cls; + struct ChurnRestartContext *startup_ctx = peer_restart_ctx->churn_restart_ctx; + + if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh) + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_churn_restart, peer_restart_ctx); + else + { + if (startup_ctx->churn_ctx->service != NULL) + GNUNET_TESTING_daemon_start_stopped_service (peer_restart_ctx->daemon, + startup_ctx-> + churn_ctx->service, + startup_ctx->timeout, + &churn_start_callback, + startup_ctx); + else + GNUNET_TESTING_daemon_start_stopped (peer_restart_ctx->daemon, + startup_ctx->timeout, + &churn_start_callback, startup_ctx); + GNUNET_free (peer_restart_ctx); + } +} + +/** + * Callback for informing us about a successful + * or unsuccessful churn start call. + * + * @param cls a struct ServiceStartContext *startup_ctx + * @param id the peer identity of the started peer + * @param cfg the handle to the configuration of the peer + * @param d handle to the daemon for the peer + * @param emsg NULL on success, non-NULL on failure + * + */ +void +service_start_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct ServiceStartContext *startup_ctx = (struct ServiceStartContext *) cls; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Service start failed with error `%s'\n", emsg); + } + + startup_ctx->outstanding--; + startup_ctx->remaining--; + + if (startup_ctx->remaining == 0) + { + startup_ctx->cb (startup_ctx->cb_cls, NULL); + GNUNET_free (startup_ctx->service); + GNUNET_free (startup_ctx); + } +} + +static void +schedule_service_start (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerServiceStartContext *peer_ctx = cls; + struct ServiceStartContext *startup_ctx = peer_ctx->start_ctx; + + if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh) + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_service_start, peer_ctx); + else + { + + GNUNET_TESTING_daemon_start_service (peer_ctx->daemon, startup_ctx->service, + startup_ctx->timeout, + &service_start_callback, startup_ctx); + GNUNET_free (peer_ctx); + } +} + + +static void +internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct InternalStartContext *internal_context = cls; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + return; + } + + if ((internal_context->peer->pg->starting < + internal_context->peer->pg->max_concurrent_ssh) || + ((internal_context->hostname != NULL) && + (count_outstanding_at_host + (internal_context->hostname, + internal_context->peer->pg) < + internal_context->peer->pg->max_concurrent_ssh))) + { + if (internal_context->hostname != NULL) + increment_outstanding_at_host (internal_context->hostname, + internal_context->peer->pg); + internal_context->peer->pg->starting++; + internal_context->peer->daemon = + GNUNET_TESTING_daemon_start (internal_context->peer->cfg, + internal_context->timeout, GNUNET_NO, + internal_context->hostname, + internal_context->username, + internal_context->sshport, + internal_context->hostkey, + &internal_hostkey_callback, + internal_context, + &internal_startup_callback, + internal_context); + } + else + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &internal_start, internal_context); + } +} + +#if USE_START_HELPER + +struct PeerStartHelperContext +{ + struct GNUNET_TESTING_PeerGroup *pg; + + struct HostData *host; + + struct GNUNET_OS_Process *proc; +}; + +static void +check_peers_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerStartHelperContext *helper = cls; + enum GNUNET_OS_ProcessStatusType type; + unsigned long code; + unsigned int i; + GNUNET_TESTING_NotifyDaemonRunning cb; + + if (GNUNET_NO == GNUNET_OS_process_status (helper->proc, &type, &code)) /* Still running, wait some more! */ + { + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, + &check_peers_started, helper); + return; + } + + helper->pg->starting--; + if (helper->pg->starting == 0) /* All peers have finished starting! */ + { + /* Call the peer started callback for each peer, set proper FSM state (?) */ + for (i = 0; i < helper->pg->total; i++) + { + cb = helper->pg->peers[i].daemon->cb; + helper->pg->peers[i].daemon->cb = NULL; + helper->pg->peers[i].daemon->running = GNUNET_YES; + helper->pg->peers[i].daemon->phase = SP_START_DONE; + if (NULL != cb) + { + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + cb (helper->pg->peers[i].daemon->cb_cls, + &helper->pg->peers[i].daemon->id, + helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon, + "Failed to execute peerStartHelper.pl, or return code bad!"); + else + cb (helper->pg->peers[i].daemon->cb_cls, + &helper->pg->peers[i].daemon->id, + helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon, + NULL); + + } + + } + } + GNUNET_OS_process_close (helper->proc); +} + +static void +start_peer_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerStartHelperContext *helper = cls; + char *baseservicehome; + char *tempdir; + char *arg; + + /* ssh user@host peerStartHelper /path/to/basedirectory */ + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (helper->pg->cfg, + "PATHS", "SERVICEHOME", + &baseservicehome)); + GNUNET_asprintf (&tempdir, "%s/%s/", baseservicehome, helper->host->hostname); + if (NULL != helper->host->username) + GNUNET_asprintf (&arg, "%s@%s", helper->host->username, + helper->host->hostname); + else + GNUNET_asprintf (&arg, "%s", helper->host->hostname); + + /* FIXME: Doesn't support ssh_port option! */ + helper->proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", arg, + "peerStartHelper.pl", tempdir, NULL); + GNUNET_assert (helper->proc != NULL); +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting peers with cmd ssh %s %s %s\n", + arg, "peerStartHelper.pl", tempdir); +#endif + GNUNET_SCHEDULER_add_now (&check_peers_started, helper); + GNUNET_free (tempdir); + GNUNET_free (baseservicehome); + GNUNET_free (arg); +} +#endif + +/** + * Function which continues a peer group starting up + * after successfully generating hostkeys for each peer. + * + * @param pg the peer group to continue starting + * + */ +void +GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg) +{ + unsigned int i; + +#if USE_START_HELPER + if ((pg->num_hosts > 0) && (pg->hostkey_data != NULL)) + { + struct PeerStartHelperContext *helper; + + pg->starting = pg->num_hosts; + for (i = 0; i < pg->num_hosts; i++) + { + helper = GNUNET_malloc (sizeof (struct PeerStartHelperContext)); + helper->pg = pg; + helper->host = &pg->hosts[i]; + GNUNET_SCHEDULER_add_now (&start_peer_helper, helper); + } + } + else + { + pg->starting = 0; + for (i = 0; i < pg->total; i++) + { + pg->peers[i].startup_task = + GNUNET_SCHEDULER_add_now (&internal_continue_startup, + &pg->peers[i].internal_context); + } + } +#else + pg->starting = 0; + for (i = 0; i < pg->total; i++) + { + pg->peers[i].startup_task = + GNUNET_SCHEDULER_add_now (&internal_continue_startup, + &pg->peers[i].internal_context); + } +#endif +} + +#if USE_START_HELPER +static void +call_hostkey_callbacks (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_PeerGroup *pg = cls; + unsigned int i; + + for (i = 0; i < pg->total; i++) + { + if (pg->peers[i].internal_context.hostkey_callback != NULL) + pg->peers[i].internal_context.hostkey_callback (pg->peers[i]. + internal_context.hostkey_cls, + &pg->peers[i].daemon->id, + pg->peers[i].daemon, + NULL); + } + + if (pg->peers[0].internal_context.hostkey_callback == NULL) + GNUNET_TESTING_daemons_continue_startup (pg); +} +#endif + +/** + * Start count gnunet instances with the same set of transports and + * applications. The port numbers (any option called "PORT") will be + * adjusted to ensure that no two peers running on the same system + * have the same port(s) in their respective configurations. + * + * @param cfg configuration template to use + * @param total number of daemons to start + * @param max_concurrent_connections for testing, how many peers can + * we connect to simultaneously + * @param max_concurrent_ssh when starting with ssh, how many ssh + * connections will we allow at once (based on remote hosts allowed!) + * @param timeout total time allowed for peers to start + * @param hostkey_callback function to call on each peers hostkey generation + * if NULL, peers will be started by this call, if non-null, + * GNUNET_TESTING_daemons_continue_startup must be called after + * successful hostkey generation + * @param hostkey_cls closure for hostkey callback + * @param cb function to call on each daemon that was started + * @param cb_cls closure for cb + * @param connect_callback function to call each time two hosts are connected + * @param connect_callback_cls closure for connect_callback + * @param hostnames linked list of host structs to use to start peers on + * (NULL to run on localhost only) + * + * @return NULL on error, otherwise handle to control peer group + */ +struct GNUNET_TESTING_PeerGroup * +GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int total, + unsigned int max_concurrent_connections, + unsigned int max_concurrent_ssh, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyHostkeyCreated + hostkey_callback, void *hostkey_cls, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls, + GNUNET_TESTING_NotifyConnection connect_callback, + void *connect_callback_cls, + const struct GNUNET_TESTING_Host *hostnames) +{ + struct GNUNET_TESTING_PeerGroup *pg; + const struct GNUNET_TESTING_Host *hostpos; + const char *hostname; + const char *username; + char *baseservicehome; + char *newservicehome; + char *tmpdir; + char *hostkeys_file; + char *arg; + char *ssh_port_str; + struct GNUNET_DISK_FileHandle *fd; + struct GNUNET_CONFIGURATION_Handle *pcfg; + unsigned int off; + struct OutstandingSSH *ssh_entry; + unsigned int hostcnt; + unsigned int i; + uint16_t minport; + uint16_t sshport; + uint32_t upnum; + uint32_t fdnum; + uint64_t fs; + uint64_t total_hostkeys; + struct GNUNET_OS_Process *proc; + + username = NULL; + if (0 == total) + { + GNUNET_break (0); + return NULL; + } + + upnum = 0; + fdnum = 0; + pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup)); + pg->cfg = cfg; + pg->notify_connection = connect_callback; + pg->notify_connection_cls = connect_callback_cls; + pg->total = total; + pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + pg->peers = GNUNET_malloc (total * sizeof (struct PeerData)); + pg->max_outstanding_connections = max_concurrent_connections; + pg->max_concurrent_ssh = max_concurrent_ssh; + if (NULL != hostnames) + { + off = 0; + hostpos = hostnames; + while (hostpos != NULL) + { + hostpos = hostpos->next; + off++; + } + pg->hosts = GNUNET_malloc (off * sizeof (struct HostData)); + off = 0; + + hostpos = hostnames; + while (hostpos != NULL) + { + pg->hosts[off].minport = LOW_PORT; + pg->hosts[off].hostname = GNUNET_strdup (hostpos->hostname); + if (hostpos->username != NULL) + pg->hosts[off].username = GNUNET_strdup (hostpos->username); + pg->hosts[off].sshport = hostpos->port; + hostpos = hostpos->next; + off++; + } + + if (off == 0) + { + pg->hosts = NULL; + } + hostcnt = off; + minport = 0; + pg->num_hosts = off; + } + else + { + hostcnt = 0; + minport = LOW_PORT; + } + + /* Create the servicehome directory for each remote peer */ + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", + "SERVICEHOME", + &baseservicehome)); + for (i = 0; i < pg->num_hosts; i++) + { + ssh_entry = GNUNET_malloc (sizeof (struct OutstandingSSH)); + ssh_entry->hostname = pg->hosts[i].hostname; /* Don't free! */ + GNUNET_CONTAINER_DLL_insert (pg->ssh_head, pg->ssh_tail, ssh_entry); + GNUNET_asprintf (&tmpdir, "%s/%s", baseservicehome, pg->hosts[i].hostname); + if (NULL != pg->hosts[i].username) + GNUNET_asprintf (&arg, "%s@%s", pg->hosts[i].username, + pg->hosts[i].hostname); + else + GNUNET_asprintf (&arg, "%s", pg->hosts[i].hostname); + if (pg->hosts[i].sshport != 0) + { + GNUNET_asprintf (&ssh_port_str, "%d", pg->hosts[i].sshport); + proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-P", ssh_port_str, +#if !DEBUG_TESTING + "-q", +#endif + arg, "mkdir -p", tmpdir, NULL); + } + else + proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", arg, "mkdir -p", + tmpdir, NULL); + GNUNET_assert (proc != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating remote dir with command ssh %s %s %s\n", arg, + " mkdir -p ", tmpdir); + GNUNET_free (tmpdir); + GNUNET_free (arg); + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + } + GNUNET_free (baseservicehome); + baseservicehome = NULL; + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "HOSTKEYSFILE", + &hostkeys_file)) + { + if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Could not read hostkeys file!\n")); + else + { + /* Check hostkey file size, read entire thing into memory */ + fd = GNUNET_DISK_file_open (hostkeys_file, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fd) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", + hostkeys_file); + GNUNET_free (hostkeys_file); + for (i = 0; i < pg->num_hosts; i++) + { + GNUNET_free (pg->hosts[i].hostname); + GNUNET_free_non_null (pg->hosts[i].username); + } + GNUNET_free (pg->peers); + GNUNET_free (pg->hosts); + GNUNET_free (pg); + return NULL; + } + + if (GNUNET_YES != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES)) + fs = 0; +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found file size %llu for hostkeys\n", fs); +#endif + if (0 != (fs % HOSTKEYFILESIZE)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "File size %llu seems incorrect for hostkeys...\n", fs); + } + else + { + total_hostkeys = fs / HOSTKEYFILESIZE; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Will read %llu hostkeys from file\n", total_hostkeys); + pg->hostkey_data = GNUNET_malloc_large (fs); + GNUNET_assert (fs == GNUNET_DISK_file_read (fd, pg->hostkey_data, fs)); + } + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); + } + GNUNET_free (hostkeys_file); + } + + for (off = 0; off < total; off++) + { + if (hostcnt > 0) + { + hostname = pg->hosts[off % hostcnt].hostname; + username = pg->hosts[off % hostcnt].username; + sshport = pg->hosts[off % hostcnt].sshport; + pcfg = + GNUNET_TESTING_create_cfg (cfg, off, &pg->hosts[off % hostcnt].minport, &upnum, + hostname, &fdnum); + } + else + { + hostname = NULL; + username = NULL; + sshport = 0; + pcfg = GNUNET_TESTING_create_cfg (cfg, off, &minport, &upnum, hostname, &fdnum); + } + + if (NULL == pcfg) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Could not create configuration for peer number %u on `%s'!\n"), + off, hostname == NULL ? "localhost" : hostname); + continue; + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME", + &baseservicehome)) + { + if (hostname != NULL) + GNUNET_asprintf (&newservicehome, "%s/%s/%d/", baseservicehome, + hostname, off); + else + GNUNET_asprintf (&newservicehome, "%s/%d/", baseservicehome, off); + GNUNET_free (baseservicehome); + baseservicehome = NULL; + } + else + { + tmpdir = getenv ("TMPDIR"); + tmpdir = tmpdir ? tmpdir : "/tmp"; + if (hostname != NULL) + GNUNET_asprintf (&newservicehome, "%s/%s/%s/%d/", tmpdir, hostname, + "gnunet-testing-test-test", off); + else + GNUNET_asprintf (&newservicehome, "%s/%s/%d/", tmpdir, + "gnunet-testing-test-test", off); + } + GNUNET_CONFIGURATION_set_value_string (pcfg, "PATHS", "SERVICEHOME", + newservicehome); + GNUNET_free (newservicehome); + pg->peers[off].cfg = pcfg; + pg->peers[off].pg = pg; + pg->peers[off].internal_context.peer = &pg->peers[off]; + pg->peers[off].internal_context.timeout = timeout; + pg->peers[off].internal_context.hostname = hostname; + pg->peers[off].internal_context.username = username; + pg->peers[off].internal_context.sshport = sshport; + if (pg->hostkey_data != NULL) + pg->peers[off].internal_context.hostkey = + &pg->hostkey_data[off * HOSTKEYFILESIZE]; + pg->peers[off].internal_context.hostkey_callback = hostkey_callback; + pg->peers[off].internal_context.hostkey_cls = hostkey_cls; + pg->peers[off].internal_context.start_cb = cb; + pg->peers[off].internal_context.start_cb_cls = cb_cls; +#if !USE_START_HELPER + GNUNET_SCHEDULER_add_now (&internal_start, + &pg->peers[off].internal_context); +#else + if ((pg->hostkey_data != NULL) && (hostcnt > 0)) + { + pg->peers[off].daemon = + GNUNET_TESTING_daemon_start (pcfg, timeout, GNUNET_YES, hostname, + username, sshport, + pg->peers[off].internal_context.hostkey, + &internal_hostkey_callback, + &pg->peers[off].internal_context, + &internal_startup_callback, + &pg->peers[off].internal_context); + /** + * At this point, given that we had a hostkeyfile, + * we can call the hostkey callback! + * But first, we should copy (rsync) all of the configs + * and hostkeys to the remote peers. Then let topology + * creation happen, then call the peer start helper processes, + * then set pg->whatever_phase for each peer and let them + * enter the fsm to get the HELLO's for peers and start connecting. + */ + } + else + { + GNUNET_SCHEDULER_add_now (&internal_start, + &pg->peers[off].internal_context); + } + +#endif + } + +#if USE_START_HELPER /* Now the peergroup has been set up, hostkeys and configs written to files. */ + if ((pg->hostkey_data != NULL) && (hostcnt > 0)) + { + for (off = 0; off < hostcnt; off++) + { + + if (hostcnt > 0) + { + hostname = pg->hosts[off % hostcnt].hostname; + username = pg->hosts[off % hostcnt].username; + sshport = pg->hosts[off % hostcnt].sshport; + } + else + { + hostname = NULL; + username = NULL; + sshport = 0; + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "SERVICEHOME", + &baseservicehome)) + { +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "baseservice home is %s\n", + baseservicehome); +#endif + if (hostname != NULL) + GNUNET_asprintf (&newservicehome, "%s/%s/", baseservicehome, + hostname); + else + GNUNET_asprintf (&newservicehome, "%s/", baseservicehome); + GNUNET_free (baseservicehome); + baseservicehome = NULL; + } + else + { + tmpdir = getenv ("TMPDIR"); + tmpdir = tmpdir ? tmpdir : "/tmp"; + if (hostname != NULL) + GNUNET_asprintf (&newservicehome, "%s/%s/%s/", tmpdir, hostname, + "gnunet-testing-test-test"); + else + GNUNET_asprintf (&newservicehome, "%s/%s/", tmpdir, + "gnunet-testing-test-test", off); + } + + if (NULL != username) + GNUNET_asprintf (&arg, "%s@%s:%s", username, pg->hosts[off].hostname, + newservicehome); + else + GNUNET_asprintf (&arg, "%s:%s", pg->hosts[off].hostname, + newservicehome); + + /* FIXME: Doesn't support ssh_port option! */ + proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "rsync", "rsync", "-r", + newservicehome, arg, NULL); +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "copying directory with command rsync -r %s %s\n", + newservicehome, arg); +#endif + GNUNET_free (newservicehome); + GNUNET_free (arg); + if (NULL == proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Could not start `%s' process to copy configuration directory.\n"), + "scp"); + GNUNET_assert (0); + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + } + /* Now all the configuration files and hostkeys are copied to the remote host. Call the hostkey callback for each peer! */ + GNUNET_SCHEDULER_add_now (&call_hostkey_callbacks, pg); + } +#endif + return pg; +} + +/* + * Get a daemon by number, so callers don't have to do nasty + * offsetting operation. + */ +struct GNUNET_TESTING_Daemon * +GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, + unsigned int position) +{ + if (position < pg->total) + return pg->peers[position].daemon; + return NULL; +} + +/* + * Get a daemon by peer identity, so callers can + * retrieve the daemon without knowing it's offset. + * + * @param pg the peer group to retrieve the daemon from + * @param peer_id the peer identity of the daemon to retrieve + * + * @return the daemon on success, or NULL if no such peer identity is found + */ +struct GNUNET_TESTING_Daemon * +GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg, + const struct GNUNET_PeerIdentity *peer_id) +{ + unsigned int i; + + for (i = 0; i < pg->total; i++) + { + if (0 == + memcmp (&pg->peers[i].daemon->id, peer_id, + sizeof (struct GNUNET_PeerIdentity))) + return pg->peers[i].daemon; + } + return NULL; +} + +/** + * Prototype of a function that will be called when a + * particular operation was completed the testing library. + * + * @param cls closure (a struct RestartContext) + * @param id id of the peer that was restarted + * @param cfg handle to the configuration of the peer + * @param d handle to the daemon that was restarted + * @param emsg NULL on success + */ +static void +restart_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct RestartContext *restart_context = cls; + + if (emsg == NULL) + { + restart_context->peers_restarted++; + } + else + { + restart_context->peers_restart_failed++; + } + + if (restart_context->peers_restarted == restart_context->peer_group->total) + { + restart_context->callback (restart_context->callback_cls, NULL); + GNUNET_free (restart_context); + } + else if (restart_context->peers_restart_failed + + restart_context->peers_restarted == + restart_context->peer_group->total) + { + restart_context->callback (restart_context->callback_cls, + "Failed to restart peers!"); + GNUNET_free (restart_context); + } + +} + +/** + * Callback for informing us about a successful + * or unsuccessful churn stop call. + * + * @param cls a ChurnContext + * @param emsg NULL on success, non-NULL on failure + * + */ +static void +churn_stop_callback (void *cls, const char *emsg) +{ + struct ShutdownContext *shutdown_ctx = cls; + struct ChurnContext *churn_ctx = shutdown_ctx->cb_cls; + unsigned int total_left; + char *error_message; + + error_message = NULL; + shutdown_ctx->outstanding--; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Churn stop callback failed with error `%s'\n", emsg); + churn_ctx->num_failed_stop++; + } + else + { + churn_ctx->num_to_stop--; + } + + total_left = + (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + + (churn_ctx->num_to_start - churn_ctx->num_failed_start); + + if (total_left == 0) + { + if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0)) + { + GNUNET_asprintf (&error_message, + "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", + churn_ctx->num_failed_start, churn_ctx->num_failed_stop); + } + churn_ctx->cb (churn_ctx->cb_cls, error_message); + GNUNET_free_non_null (error_message); + GNUNET_free (churn_ctx); + GNUNET_free (shutdown_ctx); + } +} + +/** + * Count the number of running peers. + * + * @param pg handle for the peer group + * + * @return the number of currently running peers in the peer group + */ +unsigned int +GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg) +{ + unsigned int i; + unsigned int running = 0; + + for (i = 0; i < pg->total; i++) + { + if (pg->peers[i].daemon->running == GNUNET_YES) + { + GNUNET_assert (running != -1); + running++; + } + } + return running; +} + +/** + * Task to rate limit the number of outstanding peer shutdown + * requests. This is necessary for making sure we don't do + * too many ssh connections at once, but is generally nicer + * to any system as well (graduated task starts, as opposed + * to calling gnunet-arm N times all at once). + */ +static void +schedule_churn_shutdown_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerShutdownContext *peer_shutdown_ctx = cls; + struct ShutdownContext *shutdown_ctx; + struct ChurnContext *churn_ctx; + + GNUNET_assert (peer_shutdown_ctx != NULL); + shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; + GNUNET_assert (shutdown_ctx != NULL); + churn_ctx = (struct ChurnContext *) shutdown_ctx->cb_cls; + if (shutdown_ctx->outstanding > churn_ctx->pg->max_concurrent_ssh) + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_churn_shutdown_task, + peer_shutdown_ctx); + else + { + shutdown_ctx->outstanding++; + if (churn_ctx->service != NULL) + GNUNET_TESTING_daemon_stop_service (peer_shutdown_ctx->daemon, + churn_ctx->service, + shutdown_ctx->timeout, + shutdown_ctx->cb, shutdown_ctx); + else + GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon, + shutdown_ctx->timeout, shutdown_ctx->cb, + shutdown_ctx, GNUNET_NO, GNUNET_YES); + GNUNET_free (peer_shutdown_ctx); + } +} + + +/** + * Simulate churn by stopping some peers (and possibly + * re-starting others if churn is called multiple times). This + * function can only be used to create leave-join churn (peers "never" + * leave for good). First "voff" random peers that are currently + * online will be taken offline; then "von" random peers that are then + * offline will be put back online. No notifications will be + * generated for any of these operations except for the callback upon + * completion. + * + * @param pg handle for the peer group + * @param service the service to churn off/on, NULL to churn peer + * @param voff number of peers that should go offline + * @param von number of peers that should come back online; + * must be zero on first call (since "testbed_start" + * always starts all of the peers) + * @param timeout how long to wait for operations to finish before + * giving up + * @param cb function to call at the end + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg, + char *service, unsigned int voff, + unsigned int von, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) +{ + struct ChurnContext *churn_ctx; + struct ShutdownContext *shutdown_ctx; + struct PeerShutdownContext *peer_shutdown_ctx; + struct PeerRestartContext *peer_restart_ctx; + struct ChurnRestartContext *churn_startup_ctx; + + unsigned int running; + unsigned int stopped; + unsigned int total_running; + unsigned int total_stopped; + unsigned int i; + unsigned int *running_arr; + unsigned int *stopped_arr; + unsigned int *running_permute; + unsigned int *stopped_permute; + char *pos; + + shutdown_ctx = NULL; + peer_shutdown_ctx = NULL; + peer_restart_ctx = NULL; + churn_startup_ctx = NULL; + + running = 0; + stopped = 0; + + if ((von == 0) && (voff == 0)) /* No peers at all? */ + { + cb (cb_cls, NULL); + return; + } + + for (i = 0; i < pg->total; i++) + { + if (service == NULL) + { + if (pg->peers[i].daemon->running == GNUNET_YES) + { + GNUNET_assert (running != -1); + running++; + } + else + { + GNUNET_assert (stopped != -1); + stopped++; + } + } + else + { + /* FIXME: make churned services a list! */ + pos = pg->peers[i].daemon->churned_services; + /* FIXME: while (pos != NULL) */ + if (pos != NULL) + { +#if FIXME + if (0 == strcasecmp (pos, service)) + { + + break; + } +#endif + GNUNET_assert (stopped != -1); + stopped++; + /* FIXME: pos = pos->next; */ + } + if (pos == NULL) + { + GNUNET_assert (running != -1); + running++; + } + } + } + + if (voff > running) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Trying to stop more peers (%d) than are currently running (%d)!\n", + voff, running); + cb (cb_cls, "Trying to stop more peers than are currently running!"); + return; + } + + if (von > stopped) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Trying to start more peers (%d) than are currently stopped (%d)!\n", + von, stopped); + cb (cb_cls, "Trying to start more peers than are currently stopped!"); + return; + } + + churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); + + if (service != NULL) + churn_ctx->service = GNUNET_strdup (service); + running_arr = NULL; + if (running > 0) + running_arr = GNUNET_malloc (running * sizeof (unsigned int)); + + stopped_arr = NULL; + if (stopped > 0) + stopped_arr = GNUNET_malloc (stopped * sizeof (unsigned int)); + + running_permute = NULL; + stopped_permute = NULL; + + if (running > 0) + running_permute = + GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, running); + if (stopped > 0) + stopped_permute = + GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, stopped); + + total_running = running; + total_stopped = stopped; + running = 0; + stopped = 0; + + churn_ctx->num_to_start = von; + churn_ctx->num_to_stop = voff; + churn_ctx->cb = cb; + churn_ctx->cb_cls = cb_cls; + churn_ctx->pg = pg; + + for (i = 0; i < pg->total; i++) + { + if (service == NULL) + { + if (pg->peers[i].daemon->running == GNUNET_YES) + { + GNUNET_assert ((running_arr != NULL) && (total_running > running)); + running_arr[running] = i; + running++; + } + else + { + GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped)); + stopped_arr[stopped] = i; + stopped++; + } + } + else + { + /* FIXME: make churned services a list! */ + pos = pg->peers[i].daemon->churned_services; + /* FIXME: while (pos != NULL) */ + if (pos != NULL) + { + GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped)); + stopped_arr[stopped] = i; + stopped++; + /* FIXME: pos = pos->next; */ + } + if (pos == NULL) + { + GNUNET_assert ((running_arr != NULL) && (total_running > running)); + running_arr[running] = i; + running++; + } + } + } + + GNUNET_assert (running >= voff); + if (voff > 0) + { + shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); + shutdown_ctx->cb = &churn_stop_callback; + shutdown_ctx->cb_cls = churn_ctx; + shutdown_ctx->total_peers = voff; + shutdown_ctx->timeout = timeout; + } + + for (i = 0; i < voff; i++) + { +#if DEBUG_CHURN + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peer %d!\n", + running_arr[running_permute[i]]); +#endif + GNUNET_assert (running_arr != NULL); + peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext)); + peer_shutdown_ctx->daemon = + pg->peers[running_arr[running_permute[i]]].daemon; + peer_shutdown_ctx->shutdown_ctx = shutdown_ctx; + GNUNET_SCHEDULER_add_now (&schedule_churn_shutdown_task, peer_shutdown_ctx); + } + + GNUNET_assert (stopped >= von); + if (von > 0) + { + churn_startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); + churn_startup_ctx->churn_ctx = churn_ctx; + churn_startup_ctx->timeout = timeout; + churn_startup_ctx->pg = pg; + } + for (i = 0; i < von; i++) + { +#if DEBUG_CHURN + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting up peer %d!\n", + stopped_arr[stopped_permute[i]]); +#endif + GNUNET_assert (stopped_arr != NULL); + peer_restart_ctx = GNUNET_malloc (sizeof (struct PeerRestartContext)); + peer_restart_ctx->churn_restart_ctx = churn_startup_ctx; + peer_restart_ctx->daemon = + pg->peers[stopped_arr[stopped_permute[i]]].daemon; + GNUNET_SCHEDULER_add_now (&schedule_churn_restart, peer_restart_ctx); + } + + GNUNET_free_non_null (running_arr); + GNUNET_free_non_null (stopped_arr); + GNUNET_free_non_null (running_permute); + GNUNET_free_non_null (stopped_permute); +} + +/* + * Start a given service for each of the peers in the peer group. + * + * @param pg handle for the peer group + * @param service the service to start + * @param timeout how long to wait for operations to finish before + * giving up + * @param cb function to call once finished + * @param cb_cls closure for cb + * + */ +void +GNUNET_TESTING_daemons_start_service (struct GNUNET_TESTING_PeerGroup *pg, + char *service, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, + void *cb_cls) +{ + struct ServiceStartContext *start_ctx; + struct PeerServiceStartContext *peer_start_ctx; + unsigned int i; + + GNUNET_assert (service != NULL); + + start_ctx = GNUNET_malloc (sizeof (struct ServiceStartContext)); + start_ctx->pg = pg; + start_ctx->remaining = pg->total; + start_ctx->cb = cb; + start_ctx->cb_cls = cb_cls; + start_ctx->service = GNUNET_strdup (service); + start_ctx->timeout = timeout; + + for (i = 0; i < pg->total; i++) + { +#if DEBUG_START + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting up service %s on peer %d!\n", + service, stopped_arr[stopped_permute[i]]); +#endif + peer_start_ctx = GNUNET_malloc (sizeof (struct PeerServiceStartContext)); + peer_start_ctx->start_ctx = start_ctx; + peer_start_ctx->daemon = pg->peers[i].daemon; + GNUNET_SCHEDULER_add_now (&schedule_service_start, peer_start_ctx); + } +} + +/** + * Restart all peers in the given group. + * + * @param pg the handle to the peer group + * @param callback function to call on completion (or failure) + * @param callback_cls closure for the callback function + */ +void +GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_NotifyCompletion callback, + void *callback_cls) +{ + struct RestartContext *restart_context; + unsigned int off; + + if (pg->total > 0) + { + restart_context = GNUNET_malloc (sizeof (struct RestartContext)); + restart_context->peer_group = pg; + restart_context->peers_restarted = 0; + restart_context->callback = callback; + restart_context->callback_cls = callback_cls; + + for (off = 0; off < pg->total; off++) + { + GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, + restart_context); + } + } +} + + +/** + * Start or stop an individual peer from the given group. + * + * @param pg handle to the peer group + * @param offset which peer to start or stop + * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it + * @param timeout how long to wait for shutdown + * @param cb function to call at the end + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, + unsigned int offset, int desired_status, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) +{ + struct ShutdownContext *shutdown_ctx; + struct ChurnRestartContext *startup_ctx; + struct ChurnContext *churn_ctx; + + if (GNUNET_NO == desired_status) + { + if (NULL != pg->peers[offset].daemon) + { + shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); + churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); + churn_ctx->num_to_start = 0; + churn_ctx->num_to_stop = 1; + churn_ctx->cb = cb; + churn_ctx->cb_cls = cb_cls; + shutdown_ctx->cb_cls = churn_ctx; + GNUNET_TESTING_daemon_stop (pg->peers[offset].daemon, timeout, + &churn_stop_callback, shutdown_ctx, GNUNET_NO, + GNUNET_YES); + } + } + else if (GNUNET_YES == desired_status) + { + if (NULL == pg->peers[offset].daemon) + { + startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); + churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); + churn_ctx->num_to_start = 1; + churn_ctx->num_to_stop = 0; + churn_ctx->cb = cb; + churn_ctx->cb_cls = cb_cls; + startup_ctx->churn_ctx = churn_ctx; + GNUNET_TESTING_daemon_start_stopped (pg->peers[offset].daemon, timeout, + &churn_start_callback, startup_ctx); + } + } + else + GNUNET_break (0); +} + + +/** + * Callback for shutting down peers in a peer group. + * + * @param cls closure (struct ShutdownContext) + * @param emsg NULL on success + */ +static void +internal_shutdown_callback (void *cls, const char *emsg) +{ + struct PeerShutdownContext *peer_shutdown_ctx = cls; + struct ShutdownContext *shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; + unsigned int off; + int i; + struct OutstandingSSH *ssh_pos; + + shutdown_ctx->outstanding--; + if (peer_shutdown_ctx->daemon->hostname != NULL) + decrement_outstanding_at_host (peer_shutdown_ctx->daemon->hostname, + shutdown_ctx->pg); + + if (emsg == NULL) + { + shutdown_ctx->peers_down++; + } + else + { +#if VERBOSE_TESTING + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "internal_shutdown_callback", + "Failed to stop a peer: %s\n", emsg); +#endif + shutdown_ctx->peers_failed++; + } + + if ((shutdown_ctx->cb != NULL) && + (shutdown_ctx->peers_down + shutdown_ctx->peers_failed == + shutdown_ctx->total_peers)) + { + if (shutdown_ctx->peers_failed > 0) + shutdown_ctx->cb (shutdown_ctx->cb_cls, + "Not all peers successfully shut down!"); + else + shutdown_ctx->cb (shutdown_ctx->cb_cls, NULL); + + for (i = 0; i < shutdown_ctx->pg->total; i++) + { + if (shutdown_ctx->pg->peers[i].startup_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (shutdown_ctx->pg->peers[i].startup_task); + } + GNUNET_free (shutdown_ctx->pg->peers); + GNUNET_free_non_null (shutdown_ctx->pg->hostkey_data); + for (off = 0; off < shutdown_ctx->pg->num_hosts; off++) + { + GNUNET_free (shutdown_ctx->pg->hosts[off].hostname); + GNUNET_free_non_null (shutdown_ctx->pg->hosts[off].username); + } + GNUNET_free_non_null (shutdown_ctx->pg->hosts); + while (NULL != (ssh_pos = shutdown_ctx->pg->ssh_head)) + { + GNUNET_CONTAINER_DLL_remove (shutdown_ctx->pg->ssh_head, + shutdown_ctx->pg->ssh_tail, ssh_pos); + GNUNET_free (ssh_pos); + } + GNUNET_free (shutdown_ctx->pg); + GNUNET_free (shutdown_ctx); + } + GNUNET_free (peer_shutdown_ctx); +} + + +/** + * Task to rate limit the number of outstanding peer shutdown + * requests. This is necessary for making sure we don't do + * too many ssh connections at once, but is generally nicer + * to any system as well (graduated task starts, as opposed + * to calling gnunet-arm N times all at once). + */ +static void +schedule_shutdown_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerShutdownContext *peer_shutdown_ctx = cls; + struct ShutdownContext *shutdown_ctx; + + GNUNET_assert (peer_shutdown_ctx != NULL); + shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; + GNUNET_assert (shutdown_ctx != NULL); + + if ((shutdown_ctx->outstanding < shutdown_ctx->pg->max_concurrent_ssh) || + ((peer_shutdown_ctx->daemon->hostname != NULL) && + (count_outstanding_at_host + (peer_shutdown_ctx->daemon->hostname, + shutdown_ctx->pg) < shutdown_ctx->pg->max_concurrent_ssh))) + { + if (peer_shutdown_ctx->daemon->hostname != NULL) + increment_outstanding_at_host (peer_shutdown_ctx->daemon->hostname, + shutdown_ctx->pg); + shutdown_ctx->outstanding++; + GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon, + shutdown_ctx->timeout, + &internal_shutdown_callback, peer_shutdown_ctx, + shutdown_ctx->delete_files, GNUNET_NO); + } + else + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_shutdown_task, peer_shutdown_ctx); + +} + +/** + * Read a testing hosts file based on a configuration. + * Returns a DLL of hosts (caller must free!) on success + * or NULL on failure. + * + * @param cfg a configuration with a testing section + * + * @return DLL of hosts on success, NULL on failure + */ +struct GNUNET_TESTING_Host * +GNUNET_TESTING_hosts_load (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_TESTING_Host *hosts; + struct GNUNET_TESTING_Host *temphost; + char *data; + char *buf; + char *hostfile; + struct stat frstat; + int count; + int ret; + + /* Check for a hostfile containing user@host:port triples */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile", + &hostfile)) + return NULL; + + hosts = NULL; + temphost = NULL; + data = NULL; + if (hostfile != NULL) + { + if (GNUNET_OK != GNUNET_DISK_file_test (hostfile)) + GNUNET_DISK_fn_write (hostfile, NULL, 0, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not open file specified for host list, ending test!"); + GNUNET_free (hostfile); + return NULL; + } + + data = GNUNET_malloc_large (frstat.st_size); + GNUNET_assert (data != NULL); + if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not read file %s specified for host list, ending test!", + hostfile); + GNUNET_free (hostfile); + GNUNET_free (data); + return NULL; + } + + GNUNET_free_non_null (hostfile); + + buf = data; + count = 0; + while (count < frstat.st_size - 1) + { + count++; + if (((data[count] == '\n')) && (buf != &data[count])) + { + data[count] = '\0'; + temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host)); + ret = + sscanf (buf, "%a[a-zA-Z0-9_]@%a[a-zA-Z0-9.]:%hd", + &temphost->username, &temphost->hostname, &temphost->port); + if (3 == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully read host %s, port %d and user %s from file\n", + temphost->hostname, temphost->port, temphost->username); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Error reading line `%s' in hostfile\n", buf); + GNUNET_free (temphost); + buf = &data[count + 1]; + continue; + } + temphost->next = hosts; + hosts = temphost; + buf = &data[count + 1]; + } + else if ((data[count] == '\n') || (data[count] == '\0')) + buf = &data[count + 1]; + } + } + GNUNET_free_non_null (data); + + return hosts; +} + +/** + * Shutdown all peers started in the given group. + * + * @param pg handle to the peer group + * @param timeout how long to wait for shutdown + * @param cb callback to notify upon success or failure + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) +{ + unsigned int off; + struct ShutdownContext *shutdown_ctx; + struct PeerShutdownContext *peer_shutdown_ctx; + +#if OLD + struct PeerConnection *conn_iter; + struct PeerConnection *temp_conn; +#endif + struct ConnectContext *cc; + + GNUNET_assert (pg->total > 0); + while (NULL != (cc = pg->cc_head)) + { + GNUNET_CONTAINER_DLL_remove (pg->cc_head, pg->cc_tail, cc); + if (GNUNET_SCHEDULER_NO_TASK != cc->task) + GNUNET_SCHEDULER_cancel (cc->task); + if (NULL != cc->cc) + GNUNET_TESTING_daemons_connect_cancel (cc->cc); + GNUNET_free (cc); + } + + shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); + shutdown_ctx->delete_files = + GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "DELETE_FILES"); + shutdown_ctx->cb = cb; + shutdown_ctx->cb_cls = cb_cls; + shutdown_ctx->total_peers = pg->total; + shutdown_ctx->timeout = timeout; + shutdown_ctx->pg = pg; + + for (off = 0; off < pg->total; off++) + { + GNUNET_assert (NULL != pg->peers[off].daemon); + peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext)); + peer_shutdown_ctx->daemon = pg->peers[off].daemon; + peer_shutdown_ctx->shutdown_ctx = shutdown_ctx; + GNUNET_SCHEDULER_add_now (&schedule_shutdown_task, peer_shutdown_ctx); + + if (NULL != pg->peers[off].cfg) + { + GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg); + pg->peers[off].cfg = NULL; + } +#if OLD +// FIXME Do DLL remove for all pg->peers[off].LIST + conn_iter = pg->peers[off].allowed_peers_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].allowed_peers_head = NULL; + + conn_iter = pg->peers[off].connect_peers_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].connect_peers_head = NULL; + + conn_iter = pg->peers[off].blacklisted_peers_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].blacklisted_peers_head = NULL; + + conn_iter = pg->peers[off].connect_peers_working_set_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].connect_peers_working_set_head = NULL; +#else + if (pg->peers[off].allowed_peers != NULL) + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].allowed_peers); + if (pg->peers[off].connect_peers != NULL) + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].connect_peers); + if (pg->peers[off].blacklisted_peers != NULL) + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].blacklisted_peers); +#endif + } +} + +/* end of testing_group.c */ diff --git a/src/testing/testing_peergroup.c b/src/testing/testing_peergroup.c new file mode 100644 index 0000000..0119d66 --- /dev/null +++ b/src/testing/testing_peergroup.c @@ -0,0 +1,1007 @@ +/* + This file is part of GNUnet + (C) 2008-2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file testing/testing_peergroup.c + * @brief API implementation for easy peer group creation + * @author Nathan Evans + * @author Christian Grothoff + * + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_disk_lib.h" + +/** Globals **/ +#define DEFAULT_CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + +#define DEFAULT_CONNECT_ATTEMPTS 2 + +/** Struct definitions **/ + +struct PeerGroupStartupContext +{ + struct GNUNET_TESTING_PeerGroup *pg; + const struct GNUNET_CONFIGURATION_Handle *cfg; + unsigned int total; + unsigned int peers_left; + unsigned long long max_concurrent_connections; + + /** + * Maximum attemps to connect two daemons. + */ + unsigned long long connect_attempts; + + /** + * How long to spend trying to establish all the connections? + */ + struct GNUNET_TIME_Relative connect_timeout; + + unsigned long long max_concurrent_ssh; + struct GNUNET_TIME_Absolute timeout; + GNUNET_TESTING_NotifyConnection connect_cb; + GNUNET_TESTING_NotifyCompletion peergroup_cb; + + /** + * Closure for all peergroup callbacks. + */ + void *cls; + + const struct GNUNET_TESTING_Host *hostnames; + + /** + * FIXME document + */ + enum GNUNET_TESTING_Topology topology; + + float topology_percentage; + + float topology_probability; + + /** + * FIXME document + */ + enum GNUNET_TESTING_Topology restrict_topology; + + /** + * FIXME document + */ + char *restrict_transports; + + /** + * Initial connections + */ + enum GNUNET_TESTING_Topology connect_topology; + enum GNUNET_TESTING_TopologyOption connect_topology_option; + double connect_topology_option_modifier; + int verbose; + + struct ProgressMeter *hostkey_meter; + struct ProgressMeter *peer_start_meter; + struct ProgressMeter *connect_meter; + + /** + * Task used to kill the peergroup. + */ + GNUNET_SCHEDULER_TaskIdentifier die_task; + + char *fail_reason; + + /** + * Variable used to store the number of connections we should wait for. + */ + unsigned int expected_connections; + + /** + * Time when the connecting peers was started. + */ + struct GNUNET_TIME_Absolute connect_start_time; + + /** + * The total number of connections that have been created so far. + */ + unsigned int total_connections; + + /** + * The total number of connections that have failed so far. + */ + unsigned int failed_connections; + + /** + * File handle to write out topology in dot format. + */ + struct GNUNET_DISK_FileHandle *topology_output_file; +}; + +struct TopologyOutputContext +{ + struct GNUNET_DISK_FileHandle *file; + GNUNET_TESTING_NotifyCompletion notify_cb; + void *notify_cb_cls; +}; + +/** + * Simple struct to keep track of progress, and print a + * percentage meter for long running tasks. + */ +struct ProgressMeter +{ + /** + * Total number of tasks to complete. + */ + unsigned int total; + + /** + * Print percentage done after modnum tasks. + */ + unsigned int modnum; + + /** + * Print a . each dotnum tasks. + */ + unsigned int dotnum; + + /** + * Total number completed thus far. + */ + unsigned int completed; + + /** + * Whether or not to print. + */ + int print; + + /** + * Startup string for progress meter. + */ + char *startup_string; +}; + + +/** Utility functions **/ + +/** + * Create a meter to keep track of the progress of some task. + * + * @param total the total number of items to complete + * @param start_string a string to prefix the meter with (if printing) + * @param print GNUNET_YES to print the meter, GNUNET_NO to count + * internally only + * + * @return the progress meter + */ +static struct ProgressMeter * +create_meter (unsigned int total, char *start_string, int print) +{ + struct ProgressMeter *ret; + + ret = GNUNET_malloc (sizeof (struct ProgressMeter)); + ret->print = print; + ret->total = total; + ret->modnum = (total / 4 == 0) ? 1 : (total / 4); + ret->dotnum = (total / 50) + 1; + if (start_string != NULL) + ret->startup_string = GNUNET_strdup (start_string); + else + ret->startup_string = GNUNET_strdup (""); + + return ret; +} + +/** + * Update progress meter (increment by one). + * + * @param meter the meter to update and print info for + * + * @return GNUNET_YES if called the total requested, + * GNUNET_NO if more items expected + */ +static int +update_meter (struct ProgressMeter *meter) +{ + if (meter->print == GNUNET_YES) + { + if (meter->completed % meter->modnum == 0) + { + if (meter->completed == 0) + { + FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); + } + else + FPRINTF (stdout, "%d%%", + (int) (((float) meter->completed / meter->total) * 100)); + } + else if (meter->completed % meter->dotnum == 0) + FPRINTF (stdout, "%s", "."); + + if (meter->completed + 1 == meter->total) + FPRINTF (stdout, "%d%%]\n", 100); + fflush (stdout); + } + meter->completed++; + + if (meter->completed == meter->total) + return GNUNET_YES; + return GNUNET_NO; +} + +/** + * Reset progress meter. + * + * @param meter the meter to reset + * + * @return GNUNET_YES if meter reset, + * GNUNET_SYSERR on error + */ +static int +reset_meter (struct ProgressMeter *meter) +{ + if (meter == NULL) + return GNUNET_SYSERR; + + meter->completed = 0; + return GNUNET_YES; +} + +/** + * Release resources for meter + * + * @param meter the meter to free + */ +static void +free_meter (struct ProgressMeter *meter) +{ + GNUNET_free_non_null (meter->startup_string); + GNUNET_free (meter); +} + + +/** Functions for creating, starting and connecting the peergroup **/ + +/** + * Check whether peers successfully shut down. + */ +static void +internal_shutdown_callback (void *cls, const char *emsg) +{ + struct PeerGroupStartupContext *pg_start_ctx = cls; + + if (emsg != NULL) + pg_start_ctx->peergroup_cb (pg_start_ctx->cls, emsg); + else + pg_start_ctx->peergroup_cb (pg_start_ctx->cls, pg_start_ctx->fail_reason); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerGroupStartupContext *pg_start_ctx = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failing peer group startup with error: `%s'!\n", + pg_start_ctx->fail_reason); + + GNUNET_TESTING_daemons_stop (pg_start_ctx->pg, + GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), + &internal_shutdown_callback, pg_start_ctx); + + if (pg_start_ctx->hostkey_meter != NULL) + { + free_meter (pg_start_ctx->hostkey_meter); + pg_start_ctx->hostkey_meter = NULL; + } + if (pg_start_ctx->peer_start_meter != NULL) + { + free_meter (pg_start_ctx->peer_start_meter); + pg_start_ctx->peer_start_meter = NULL; + } + if (pg_start_ctx->connect_meter != NULL) + { + free_meter (pg_start_ctx->connect_meter); + pg_start_ctx->connect_meter = NULL; + } +} + +/** + * This function is called whenever a connection attempt is finished between two of + * the started peers (started with GNUNET_TESTING_daemons_start). The total + * number of times this function is called should equal the number returned + * from the GNUNET_TESTING_connect_topology call. + * + * The emsg variable is NULL on success (peers connected), and non-NULL on + * failure (peers failed to connect). + */ +static void +internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, + uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle + *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + struct PeerGroupStartupContext *pg_start_ctx = cls; + char *temp_str; + char *second_str; + int temp; + +#if TIMING + unsigned long long duration; + unsigned long long total_duration; + unsigned int new_connections; + unsigned int new_failed_connections; + double conns_per_sec_recent; + double conns_per_sec_total; + double failed_conns_per_sec_recent; + double failed_conns_per_sec_total; +#endif + +#if TIMING + if (GNUNET_TIME_absolute_get_difference + (connect_last_time, + GNUNET_TIME_absolute_get ()).rel_value > + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, + CONN_UPDATE_DURATION).rel_value) + { + /* Get number of new connections */ + new_connections = total_connections - previous_connections; + + /* Get number of new FAILED connections */ + new_failed_connections = failed_connections - previous_failed_connections; + + /* Get duration in seconds */ + duration = + GNUNET_TIME_absolute_get_difference (connect_last_time, + GNUNET_TIME_absolute_get + ()).rel_value / 1000; + total_duration = + GNUNET_TIME_absolute_get_difference (connect_start_time, + GNUNET_TIME_absolute_get + ()).rel_value / 1000; + + failed_conns_per_sec_recent = (double) new_failed_connections / duration; + failed_conns_per_sec_total = (double) failed_connections / total_duration; + conns_per_sec_recent = (double) new_connections / duration; + conns_per_sec_total = (double) total_connections / total_duration; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n", + conns_per_sec_recent, CONN_UPDATE_DURATION, conns_per_sec_total, + failed_conns_per_sec_recent, failed_conns_per_sec_total); + connect_last_time = GNUNET_TIME_absolute_get (); + previous_connections = total_connections; + previous_failed_connections = failed_connections; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "have %u total_connections, %u failed\n", total_connections, + failed_connections); + } +#endif + + + if (emsg == NULL) + { + pg_start_ctx->total_connections++; +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connected peer %s to peer %s, distance %u\n", + first_daemon->shortname, second_daemon->shortname, distance); +#endif + if (pg_start_ctx->topology_output_file != NULL) + { + second_str = GNUNET_strdup (GNUNET_i2s (second)); + temp = + GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", + GNUNET_i2s (first), second_str); + GNUNET_free (second_str); + if (temp > 0) + GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, + temp); + GNUNET_free (temp_str); + } + } + else + { + pg_start_ctx->failed_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); +#endif + } + + GNUNET_assert (pg_start_ctx->connect_meter != NULL); + if (pg_start_ctx->connect_cb != NULL) + pg_start_ctx->connect_cb (pg_start_ctx->cls, first, second, distance, + first_cfg, second_cfg, first_daemon, + second_daemon, emsg); + if (GNUNET_YES == update_meter (pg_start_ctx->connect_meter)) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number! Starting next phase of testing.\n", + pg_start_ctx->total_connections); +#endif + +#if TIMING + total_duration = + GNUNET_TIME_absolute_get_difference (connect_start_time, + GNUNET_TIME_absolute_get + ()).rel_value / 1000; + failed_conns_per_sec_total = (double) failed_connections / total_duration; + conns_per_sec_total = (double) total_connections / total_duration; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Overall connection info --- Total: %u, Total Failed %u/s\n", + total_connections, failed_connections); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n", + conns_per_sec_total, failed_conns_per_sec_total); +#endif + + GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK); + GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); + + /* Call final callback, signifying that the peer group has been started and connected */ + if (pg_start_ctx->peergroup_cb != NULL) + pg_start_ctx->peergroup_cb (pg_start_ctx->cls, NULL); + + if (pg_start_ctx->topology_output_file != NULL) + { + temp = GNUNET_asprintf (&temp_str, "}\n"); + if (temp > 0) + GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, + temp); + GNUNET_free (temp_str); + GNUNET_DISK_file_close (pg_start_ctx->topology_output_file); + } + } +} + + +/** + * Callback called for each started daemon. + * + * @param cls Clause (PG Context). + * @param id PeerIdentidy of started daemon. + * @param cfg Configuration used by the daemon. + * @param d Handle for the daemon. + * @param emsg Error message, NULL on success. + */ +static void +internal_peers_started_callback (void *cls, + const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, + const char *emsg) +{ + struct PeerGroupStartupContext *pg_start_ctx = cls; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); + +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", + (pg_start_ctx->total - pg_start_ctx->peers_left) + 1, + pg_start_ctx->total); +#endif + + pg_start_ctx->peers_left--; + + if (NULL == pg_start_ctx->peer_start_meter) + { + /* Cancelled Ctrl-C or error */ + return; + } + if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter)) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now connecting peers!\n", + pg_start_ctx->total); +#endif + GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK); + GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); + + pg_start_ctx->expected_connections = UINT_MAX; + // FIXME: why whould peers_left be != 0?? Or pg NULL? + if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0)) + { + pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get (); + pg_start_ctx->expected_connections = + GNUNET_TESTING_connect_topology (pg_start_ctx->pg, + pg_start_ctx->connect_topology, + pg_start_ctx->connect_topology_option, + pg_start_ctx->connect_topology_option_modifier, + pg_start_ctx->connect_timeout, + pg_start_ctx->connect_attempts, NULL, + NULL); + + pg_start_ctx->connect_meter = + create_meter (pg_start_ctx->expected_connections, "Peer connection ", + pg_start_ctx->verbose); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", + pg_start_ctx->expected_connections); + } + + if (pg_start_ctx->expected_connections == 0) + { + GNUNET_free_non_null (pg_start_ctx->fail_reason); + pg_start_ctx->fail_reason = + GNUNET_strdup ("from connect topology (bad return)"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx); + return; + } + + GNUNET_free_non_null (pg_start_ctx->fail_reason); + pg_start_ctx->fail_reason = + GNUNET_strdup ("from connect topology (timeout)"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), &end_badly, + pg_start_ctx); + } +} + +/** + * Callback indicating that the hostkey was created for a peer. + * + * @param cls NULL + * @param id the peer identity + * @param d the daemon handle (pretty useless at this point, remove?) + * @param emsg non-null on failure + */ +static void +internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct PeerGroupStartupContext *pg_start_ctx = cls; + unsigned int create_expected_connections; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Hostkey callback received error: %s\n", emsg); + } + +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Hostkey (%d/%d) created for peer `%s'\n", + pg_start_ctx->total - pg_start_ctx->peers_left + 1, + pg_start_ctx->total, GNUNET_i2s (id)); +#endif + + pg_start_ctx->peers_left--; + if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter)) + { + GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); + GNUNET_free_non_null (pg_start_ctx->fail_reason); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + pg_start_ctx->fail_reason = GNUNET_strdup ("from create_topology"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), &end_badly, + pg_start_ctx); + pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */ + create_expected_connections = + GNUNET_TESTING_create_topology (pg_start_ctx->pg, + pg_start_ctx->topology, + pg_start_ctx->restrict_topology, + pg_start_ctx->restrict_transports); + if (create_expected_connections > 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Topology set up, have %u expected connections, now starting peers!\n", + create_expected_connections); + GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg); + } + else + { + GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); + GNUNET_free_non_null (pg_start_ctx->fail_reason); + pg_start_ctx->fail_reason = + GNUNET_strdup ("from create topology (bad return)"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx); + return; + } + + GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); + GNUNET_free_non_null (pg_start_ctx->fail_reason); + pg_start_ctx->fail_reason = + GNUNET_strdup ("from continue startup (timeout)"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), &end_badly, + pg_start_ctx); + } +} + + +/** + * Prototype of a callback function indicating that two peers + * are currently connected. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param emsg error message (NULL on success) + */ +void +write_topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, const char *emsg) +{ + struct TopologyOutputContext *topo_ctx; + int temp; + char *temp_str; + char *temp_pid2; + + topo_ctx = (struct TopologyOutputContext *) cls; + GNUNET_assert (topo_ctx->file != NULL); + if ((emsg == NULL) && (first != NULL) && (second != NULL)) + { + GNUNET_assert (first != NULL); + GNUNET_assert (second != NULL); + temp_pid2 = GNUNET_strdup (GNUNET_i2s (second)); + temp = + GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", GNUNET_i2s (first), + temp_pid2); + GNUNET_free (temp_pid2); + GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); + } + else if ((emsg == NULL) && (first == NULL) && (second == NULL)) + { + temp = GNUNET_asprintf (&temp_str, "}\n"); + GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); + GNUNET_DISK_file_close (topo_ctx->file); + topo_ctx->notify_cb (topo_ctx->notify_cb_cls, NULL); + GNUNET_free (topo_ctx); + } + else + { + temp = GNUNET_asprintf (&temp_str, "}\n"); + GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); + GNUNET_DISK_file_close (topo_ctx->file); + topo_ctx->notify_cb (topo_ctx->notify_cb_cls, emsg); + GNUNET_free (topo_ctx); + } +} + +/** + * Print current topology to a graphviz readable file. + * + * @param pg a currently running peergroup to print to file + * @param output_filename the file to write the topology to + * @param notify_cb callback to call upon completion or failure + * @param notify_cb_cls closure for notify_cb + * + */ +void +GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg, + const char *output_filename, + GNUNET_TESTING_NotifyCompletion + notify_cb, void *notify_cb_cls) +{ + struct TopologyOutputContext *topo_ctx; + int temp; + char *temp_str; + + topo_ctx = GNUNET_malloc (sizeof (struct TopologyOutputContext)); + + topo_ctx->notify_cb = notify_cb; + topo_ctx->notify_cb_cls = notify_cb_cls; + topo_ctx->file = + GNUNET_DISK_file_open (output_filename, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (topo_ctx->file == NULL) + { + notify_cb (notify_cb_cls, "Failed to open output file!"); + GNUNET_free (topo_ctx); + return; + } + + temp = GNUNET_asprintf (&temp_str, "strict graph G {\n"); + if (temp > 0) + GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); + GNUNET_free_non_null (temp_str); + GNUNET_TESTING_get_topology (pg, &write_topology_cb, topo_ctx); +} + +/** + * Start a peer group with a given number of peers. Notify + * on completion of peer startup and connection based on given + * topological constraints. Optionally notify on each + * established connection. + * + * @param cfg configuration template to use + * @param total number of daemons to start + * @param timeout total time allowed for peers to start + * @param connect_cb function to call each time two daemons are connected + * @param peergroup_cb function to call once all peers are up and connected + * @param peergroup_cls closure for peergroup callbacks + * @param hostnames linked list of host structs to use to start peers on + * (NULL to run on localhost only) + * + * @return NULL on error, otherwise handle to control peer group + */ +struct GNUNET_TESTING_PeerGroup * +GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int total, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyConnection connect_cb, + GNUNET_TESTING_NotifyCompletion peergroup_cb, + void *peergroup_cls, + const struct GNUNET_TESTING_Host *hostnames) +{ + struct PeerGroupStartupContext *pg_start_ctx; + char *temp_str; + int temp; + struct GNUNET_TIME_Relative rtimeout; + + GNUNET_assert (total > 0); + GNUNET_assert (cfg != NULL); + + pg_start_ctx = GNUNET_malloc (sizeof (struct PeerGroupStartupContext)); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", + &pg_start_ctx->connect_attempts)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "connect_attempts"); + GNUNET_free (pg_start_ctx); + return NULL; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", + &pg_start_ctx->connect_timeout)) + { + pg_start_ctx->connect_timeout = DEFAULT_CONNECT_TIMEOUT; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", + "max_outstanding_connections", + &pg_start_ctx->max_concurrent_connections)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "max_outstanding_connections"); + GNUNET_free (pg_start_ctx); + return NULL; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", + "max_concurrent_ssh", + &pg_start_ctx->max_concurrent_ssh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "max_concurrent_ssh"); + GNUNET_free (pg_start_ctx); + return NULL; + } + + if (GNUNET_SYSERR == + (pg_start_ctx->verbose = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing", + "use_progressbars"))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "use_progressbars"); + GNUNET_free (pg_start_ctx); + return NULL; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "PEERGROUP_TIMEOUT", + &rtimeout)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "PEERGROUP_TIMEOUT"); + GNUNET_free (pg_start_ctx); + return NULL; + } + pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute (rtimeout); + + + /* Read topology related options from the configuration file */ + temp_str = NULL; + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", + &temp_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + temp_str, "TESTING", "TOPOLOGY"); + pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ + } + GNUNET_free_non_null (temp_str); + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "topology_output_file", &temp_str)) + { + pg_start_ctx->topology_output_file = + GNUNET_DISK_file_open (temp_str, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (pg_start_ctx->topology_output_file != NULL) + { + GNUNET_free (temp_str); + temp = GNUNET_asprintf (&temp_str, "strict graph G {\n"); + if (temp > 0) + GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, + temp); + } + GNUNET_free (temp_str); + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage", + &temp_str)) + pg_start_ctx->topology_percentage = 0.5; + else + { + pg_start_ctx->topology_percentage = atof (temp_str); + GNUNET_free (temp_str); + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability", + &temp_str)) + pg_start_ctx->topology_probability = 0.5; + else + { + pg_start_ctx->topology_probability = atof (temp_str); + GNUNET_free (temp_str); + } + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology", &temp_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology, temp_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology `%s' given for section %s option %s\n", + temp_str, "TESTING", "CONNECT_TOPOLOGY"); + } + GNUNET_free_non_null (temp_str); + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option", + &temp_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_option_get + (&pg_start_ctx->connect_topology_option, temp_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology option `%s' given for section %s option %s\n", + temp_str, "TESTING", "CONNECT_TOPOLOGY_OPTION"); + pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ + } + GNUNET_free_non_null (temp_str); + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option_modifier", + &temp_str)) + { + if (sscanf + (temp_str, "%lf", &pg_start_ctx->connect_topology_option_modifier) != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + temp_str, "connect_topology_option_modifier", "TESTING"); + GNUNET_free (temp_str); + GNUNET_free (pg_start_ctx); + return NULL; + } + GNUNET_free (temp_str); + } + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_transports", + &pg_start_ctx->restrict_transports)) + pg_start_ctx->restrict_transports = NULL; + + pg_start_ctx->restrict_topology = GNUNET_TESTING_TOPOLOGY_NONE; + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_topology", &temp_str)) + && (GNUNET_NO == + GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology, + temp_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + temp_str, "TESTING", "BLACKLIST_TOPOLOGY"); + } + + GNUNET_free_non_null (temp_str); + + pg_start_ctx->cfg = cfg; + pg_start_ctx->total = total; + pg_start_ctx->peers_left = total; + pg_start_ctx->connect_cb = connect_cb; + pg_start_ctx->peergroup_cb = peergroup_cb; + pg_start_ctx->cls = peergroup_cls; + pg_start_ctx->hostnames = hostnames; + pg_start_ctx->hostkey_meter = + create_meter (pg_start_ctx->peers_left, "Hostkeys created ", + pg_start_ctx->verbose); + pg_start_ctx->peer_start_meter = + create_meter (pg_start_ctx->peers_left, "Peers started ", + pg_start_ctx->verbose); + /* Make compilers happy */ + reset_meter (pg_start_ctx->peer_start_meter); + pg_start_ctx->fail_reason = + GNUNET_strdup + ("didn't generate all hostkeys within allowed startup time!"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), &end_badly, + pg_start_ctx); + + pg_start_ctx->pg = + GNUNET_TESTING_daemons_start (pg_start_ctx->cfg, pg_start_ctx->peers_left, + pg_start_ctx->max_concurrent_connections, + pg_start_ctx->max_concurrent_ssh, + GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), + &internal_hostkey_callback, pg_start_ctx, + &internal_peers_started_callback, + pg_start_ctx, &internal_topology_callback, + pg_start_ctx, pg_start_ctx->hostnames); + + return pg_start_ctx->pg; +} + +/* end of testing_peergroup.c */ diff --git a/src/topology/Makefile.am b/src/topology/Makefile.am new file mode 100644 index 0000000..261be86 --- /dev/null +++ b/src/topology/Makefile.am @@ -0,0 +1,43 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +dist_pkgcfg_DATA = \ + topology.conf + + +bin_PROGRAMS = \ + gnunet-daemon-topology + +gnunet_daemon_topology_SOURCES = \ + gnunet-daemon-topology.c +gnunet_daemon_topology_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + + + +check_PROGRAMS = \ + test_gnunet_daemon_topology + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_gnunet_daemon_topology_SOURCES = \ + test_gnunet_daemon_topology.c +test_gnunet_daemon_topology_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_gnunet_daemon_topology_data.conf diff --git a/src/topology/Makefile.in b/src/topology/Makefile.in new file mode 100644 index 0000000..a7ae50d --- /dev/null +++ b/src/topology/Makefile.in @@ -0,0 +1,828 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = gnunet-daemon-topology$(EXEEXT) +check_PROGRAMS = test_gnunet_daemon_topology$(EXEEXT) +subdir = src/topology +DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_daemon_topology_OBJECTS = gnunet-daemon-topology.$(OBJEXT) +gnunet_daemon_topology_OBJECTS = $(am_gnunet_daemon_topology_OBJECTS) +am__DEPENDENCIES_1 = +gnunet_daemon_topology_DEPENDENCIES = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am_test_gnunet_daemon_topology_OBJECTS = \ + test_gnunet_daemon_topology.$(OBJEXT) +test_gnunet_daemon_topology_OBJECTS = \ + $(am_test_gnunet_daemon_topology_OBJECTS) +test_gnunet_daemon_topology_DEPENDENCIES = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(gnunet_daemon_topology_SOURCES) \ + $(test_gnunet_daemon_topology_SOURCES) +DIST_SOURCES = $(gnunet_daemon_topology_SOURCES) \ + $(test_gnunet_daemon_topology_SOURCES) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +DATA = $(dist_pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +pkgcfgdir = $(pkgdatadir)/config.d/ +dist_pkgcfg_DATA = \ + topology.conf + +gnunet_daemon_topology_SOURCES = \ + gnunet-daemon-topology.c + +gnunet_daemon_topology_LDADD = \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_gnunet_daemon_topology_SOURCES = \ + test_gnunet_daemon_topology.c + +test_gnunet_daemon_topology_LDADD = \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_gnunet_daemon_topology_data.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/topology/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/topology/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-daemon-topology$(EXEEXT): $(gnunet_daemon_topology_OBJECTS) $(gnunet_daemon_topology_DEPENDENCIES) + @rm -f gnunet-daemon-topology$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_daemon_topology_OBJECTS) $(gnunet_daemon_topology_LDADD) $(LIBS) +test_gnunet_daemon_topology$(EXEEXT): $(test_gnunet_daemon_topology_OBJECTS) $(test_gnunet_daemon_topology_DEPENDENCIES) + @rm -f test_gnunet_daemon_topology$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_topology_OBJECTS) $(test_gnunet_daemon_topology_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-daemon-topology.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_topology.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-dist_pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am \ + install-dist_pkgcfgDATA install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-dist_pkgcfgDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/topology/gnunet-daemon-topology.c b/src/topology/gnunet-daemon-topology.c new file mode 100644 index 0000000..38a648a --- /dev/null +++ b/src/topology/gnunet-daemon-topology.c @@ -0,0 +1,1328 @@ +/* + This file is part of GNUnet. + (C) 2007, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file topology/gnunet-daemon-topology.c + * @brief code for maintaining the mesh topology + * @author Christian Grothoff + */ + +#include +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_core_service.h" +#include "gnunet_protocols.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_util_lib.h" + + +#define DEBUG_TOPOLOGY GNUNET_YES + +/** + * For how long do we blacklist a peer after a failed connection + * attempt? + */ +#define GREYLIST_AFTER_ATTEMPT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +/** + * For how long do we blacklist a friend after a failed connection + * attempt? + */ +#define GREYLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) + +/** + * For how long do we blacklist anyone under any cirumstances after a failed connection + * attempt? + */ +#define GREYLIST_AFTER_ATTEMPT_MIN GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) + +/** + * For how long do we blacklist anyone under any cirumstances after a failed connection + * attempt? + */ +#define GREYLIST_AFTER_ATTEMPT_MAX GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1) + +/** + * How often do we at most advertise any HELLO to a peer? + */ +#define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4) + +/** + * How often do we at most advertise the same HELLO to the same peer? + */ +#define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4) + + +/** + * Record for neighbours, friends and blacklisted peers. + */ +struct Peer +{ + /** + * Which peer is this entry about? + */ + struct GNUNET_PeerIdentity pid; + + /** + * Our handle for the request to transmit HELLOs to this peer; NULL + * if no such request is pending. + */ + struct GNUNET_CORE_TransmitHandle *hello_req; + + /** + * Pointer to the HELLO message of this peer; can be NULL. + */ + struct GNUNET_HELLO_Message *hello; + + /** + * Bloom filter used to mark which peers already got the HELLO + * from this peer. + */ + struct GNUNET_CONTAINER_BloomFilter *filter; + + /** + * Until what time should we not try to connect again + * to this peer? + */ + struct GNUNET_TIME_Absolute greylisted_until; + + /** + * Next time we are allowed to transmit a HELLO to this peer? + */ + struct GNUNET_TIME_Absolute next_hello_allowed; + + /** + * When should we reset the bloom filter of this entry? + */ + struct GNUNET_TIME_Absolute filter_expiration; + + /** + * ID of task we use to wait for the time to send the next HELLO + * to this peer. + */ + GNUNET_SCHEDULER_TaskIdentifier hello_delay_task; + + /** + * ID of task we use to clear peers from the greylist. + */ + GNUNET_SCHEDULER_TaskIdentifier greylist_clean_task; + + /** + * How often have we tried so far? + */ + unsigned int connect_attempts; + + /** + * Is this peer listed here because he is a friend? + */ + int is_friend; + + /** + * Are we connected to this peer right now? + */ + int is_connected; + +}; + + +/** + * Our peerinfo notification context. We use notification + * to instantly learn about new peers as they are discovered. + */ +static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify; + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Handle to the core API. + */ +static struct GNUNET_CORE_Handle *handle; + +/** + * Handle to the transport API. + */ +static struct GNUNET_TRANSPORT_Handle *transport; + +/** + * Identity of this peer. + */ +static struct GNUNET_PeerIdentity my_identity; + +/** + * All of our friends, all of our current neighbours and all peers for + * which we have HELLOs. So pretty much everyone. Maps peer identities + * to 'struct Peer *' values. + */ +static struct GNUNET_CONTAINER_MultiHashMap *peers; + +/** + * Handle for reporting statistics. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * Blacklist (NULL if we have none). + */ +static struct GNUNET_TRANSPORT_Blacklist *blacklist; + +/** + * Task scheduled to try to add peers. + */ +static GNUNET_SCHEDULER_TaskIdentifier add_task; + +/** + * Flag to disallow non-friend connections (pure F2F mode). + */ +static int friends_only; + +/** + * Minimum number of friends to have in the + * connection set before we allow non-friends. + */ +static unsigned int minimum_friend_count; + +/** + * Number of peers (friends and others) that we are currently connected to. + */ +static unsigned int connection_count; + +/** + * Target number of connections. + */ +static unsigned int target_connection_count; + +/** + * Number of friends that we are currently connected to. + */ +static unsigned int friend_count; + +/** + * Should the topology daemon try to establish connections? + */ +static int autoconnect; + + +/** + * Function that decides if a connection is acceptable or not. + * If we have a blacklist, only friends are allowed, so the check + * is rather simple. + * + * @param cls closure + * @param pid peer to approve or disapproave + * @return GNUNET_OK if the connection is allowed + */ +static int +blacklist_check (void *cls, const struct GNUNET_PeerIdentity *pid) +{ + struct Peer *pos; + + pos = GNUNET_CONTAINER_multihashmap_get (peers, &pid->hashPubKey); + if ((pos != NULL) && (pos->is_friend == GNUNET_YES)) + return GNUNET_OK; + GNUNET_STATISTICS_update (stats, gettext_noop ("# peers blacklisted"), 1, + GNUNET_NO); + return GNUNET_SYSERR; +} + + +/** + * Whitelist all peers that we blacklisted; we've passed + * the minimum number of friends. + */ +static void +whitelist_peers () +{ + if (blacklist != NULL) + { + GNUNET_TRANSPORT_blacklist_cancel (blacklist); + blacklist = NULL; + } +} + + +/** + * Check if an additional connection from the given peer is allowed. + * + * @param peer connection to check + * @return GNUNET_OK if the connection is allowed + */ +static int +is_connection_allowed (struct Peer *peer) +{ + if (0 == + memcmp (&my_identity, &peer->pid, sizeof (struct GNUNET_PeerIdentity))) + return GNUNET_SYSERR; /* disallow connections to self */ + if (peer->is_friend) + return GNUNET_OK; + if (GNUNET_YES == friends_only) + { +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Determined that `%s' is not allowed to connect (not a friend)\n", + GNUNET_i2s (&peer->pid)); +#endif + return GNUNET_SYSERR; + } + if (friend_count >= minimum_friend_count) + return GNUNET_OK; +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Determined that `%s' is not allowed to connect (not enough connected friends)\n", + GNUNET_i2s (&peer->pid)); +#endif + return GNUNET_SYSERR; +} + + +/** + * Free all resources associated with the given peer. + * + * @param cls closure (not used) + * @param pid identity of the peer + * @param value peer to free + * @return GNUNET_YES (always: continue to iterate) + */ +static int +free_peer (void *cls, const GNUNET_HashCode * pid, void *value) +{ + struct Peer *pos = value; + + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (peers, pid, pos)); + if (pos->hello_req != NULL) + GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req); + if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (pos->hello_delay_task); + if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (pos->greylist_clean_task); + GNUNET_free_non_null (pos->hello); + if (pos->filter != NULL) + GNUNET_CONTAINER_bloomfilter_free (pos->filter); + GNUNET_free (pos); + return GNUNET_YES; +} + + +/** + * Discard peer entries for greylisted peers + * where the greylisting has expired. + * + * @param cls 'struct Peer' to greylist + * @param tc scheduler context + */ +static void +remove_from_greylist (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Try to connect to the specified peer. + * + * @param pos peer to connect to + */ +static void +attempt_connect (struct Peer *pos) +{ + struct GNUNET_TIME_Relative rem; + + if ((connection_count >= target_connection_count) && + (friend_count >= minimum_friend_count)) + return; + if (GNUNET_YES == pos->is_connected) + return; + if (GNUNET_OK != is_connection_allowed (pos)) + return; + if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value > 0) + return; + if (GNUNET_YES == pos->is_friend) + rem = GREYLIST_AFTER_ATTEMPT_FRIEND; + else + rem = GREYLIST_AFTER_ATTEMPT; + rem = GNUNET_TIME_relative_multiply (rem, connection_count); + rem = GNUNET_TIME_relative_divide (rem, target_connection_count); + if (pos->connect_attempts > 30) + pos->connect_attempts = 30; + rem = GNUNET_TIME_relative_multiply (rem, 1 << (++pos->connect_attempts)); + rem = GNUNET_TIME_relative_max (rem, GREYLIST_AFTER_ATTEMPT_MIN); + rem = GNUNET_TIME_relative_min (rem, GREYLIST_AFTER_ATTEMPT_MAX); + pos->greylisted_until = GNUNET_TIME_relative_to_absolute (rem); + if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (pos->greylist_clean_task); + pos->greylist_clean_task = + GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos); +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to connect to `%s'\n", + GNUNET_i2s (&pos->pid)); +#endif + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# connect requests issued to transport"), 1, + GNUNET_NO); + GNUNET_TRANSPORT_try_connect (transport, &pos->pid); +} + + +/** + * Discard peer entries for greylisted peers + * where the greylisting has expired. + * + * @param cls 'struct Peer' to greylist + * @param tc scheduler context + */ +static void +remove_from_greylist (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Peer *pos = cls; + struct GNUNET_TIME_Relative rem; + + pos->greylist_clean_task = GNUNET_SCHEDULER_NO_TASK; + rem = GNUNET_TIME_absolute_get_remaining (pos->greylisted_until); + if (rem.rel_value == 0) + { + attempt_connect (pos); + } + else + { + pos->greylist_clean_task = + GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos); + } + if ((GNUNET_NO == pos->is_friend) && (GNUNET_NO == pos->is_connected) && + (NULL == pos->hello)) + { + free_peer (NULL, &pos->pid.hashPubKey, pos); + return; + } +} + + +/** + * Create a new entry in the peer list. + * + * @param peer identity of the new entry + * @param hello hello message, can be NULL + * @param is_friend is the new entry for a friend? + * @return the new entry + */ +static struct Peer * +make_peer (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, int is_friend) +{ + struct Peer *ret; + + ret = GNUNET_malloc (sizeof (struct Peer)); + ret->pid = *peer; + ret->is_friend = is_friend; + if (hello != NULL) + { + ret->hello = GNUNET_malloc (GNUNET_HELLO_size (hello)); + memcpy (ret->hello, hello, GNUNET_HELLO_size (hello)); + } + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey, + ret, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + return ret; +} + + +/** + * Setup bloom filter for the given peer entry. + * + * @param peer entry to initialize + */ +static void +setup_filter (struct Peer *peer) +{ + /* 2^{-5} chance of not sending a HELLO to a peer is + * acceptably small (if the filter is 50% full); + * 64 bytes of memory are small compared to the rest + * of the data structure and would only really become + * "useless" once a HELLO has been passed on to ~100 + * other peers, which is likely more than enough in + * any case; hence 64, 5 as bloomfilter parameters. */ + peer->filter = GNUNET_CONTAINER_bloomfilter_init (NULL, 64, 5); + peer->filter_expiration = + GNUNET_TIME_relative_to_absolute + (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY); + /* never send a peer its own HELLO */ + GNUNET_CONTAINER_bloomfilter_add (peer->filter, &peer->pid.hashPubKey); +} + + +/** + * Function to fill send buffer with HELLO. + * + * @param cls 'struct Peer' of the target peer + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +hello_advertising_ready (void *cls, size_t size, void *buf); + + +/** + * Closure for 'find_advertisable_hello'. + */ +struct FindAdvHelloContext +{ + + /** + * Peer we want to advertise to. + */ + struct Peer *peer; + + /** + * Where to store the result (peer selected for advertising). + */ + struct Peer *result; + + /** + * Maximum HELLO size we can use right now. + */ + size_t max_size; + + struct GNUNET_TIME_Relative next_adv; +}; + + +/** + * Find a peer that would be reasonable for advertising. + * + * @param cls closure + * @param pid identity of a peer + * @param value 'struct Peer*' for the peer we are considering + * @return GNUNET_YES (continue iteration) + */ +static int +find_advertisable_hello (void *cls, const GNUNET_HashCode * pid, void *value) +{ + struct FindAdvHelloContext *fah = cls; + struct Peer *pos = value; + struct GNUNET_TIME_Relative rst_time; + size_t hs; + + if (pos == fah->peer) + return GNUNET_YES; + if (pos->hello == NULL) + return GNUNET_YES; + rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration); + if (0 == rst_time.rel_value) + { + /* time to discard... */ + GNUNET_CONTAINER_bloomfilter_free (pos->filter); + setup_filter (pos); + } + fah->next_adv = GNUNET_TIME_relative_min (rst_time, fah->next_adv); + hs = GNUNET_HELLO_size (pos->hello); + if (hs > fah->max_size) + return GNUNET_YES; + if (GNUNET_NO == + GNUNET_CONTAINER_bloomfilter_test (pos->filter, + &fah->peer->pid.hashPubKey)) + fah->result = pos; + return GNUNET_YES; +} + + +/** + * Calculate when we would like to send the next HELLO to this + * peer and ask for it. + * + * @param cls for which peer to schedule the HELLO + * @param tc task context + */ +static void +schedule_next_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Peer *pl = cls; + struct FindAdvHelloContext fah; + size_t next_want; + struct GNUNET_TIME_Relative delay; + + pl->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (GNUNET_YES == pl->is_connected); + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; /* we're out of here */ + if (pl->hello_req != NULL) + return; /* did not finish sending the previous one */ + /* find applicable HELLOs */ + fah.peer = pl; + fah.result = NULL; + fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1; + fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_CONTAINER_multihashmap_iterate (peers, &find_advertisable_hello, &fah); + pl->hello_delay_task = + GNUNET_SCHEDULER_add_delayed (fah.next_adv, &schedule_next_hello, pl); + if (fah.result == NULL) + return; + next_want = GNUNET_HELLO_size (fah.result->hello); + delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed); + if (delay.rel_value == 0) + { + /* now! */ + pl->hello_req = + GNUNET_CORE_notify_transmit_ready (handle, GNUNET_YES, 0, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, + &pl->pid, next_want, + &hello_advertising_ready, pl); + } +} + + +/** + * Cancel existing requests for sending HELLOs to this peer + * and recalculate when we should send HELLOs to it based + * on our current state (something changed!). + * + * @param cls closure, 'struct Peer' to skip, or NULL + * @param pid identity of a peer + * @param value 'struct Peer*' for the peer + * @return GNUNET_YES (always) + */ +static int +reschedule_hellos (void *cls, const GNUNET_HashCode * pid, void *value) +{ + struct Peer *peer = value; + struct Peer *skip = cls; + + if (skip == peer) + return GNUNET_YES; + if (!peer->is_connected) + return GNUNET_YES; + if (peer->hello_req != NULL) + { + GNUNET_CORE_notify_transmit_ready_cancel (peer->hello_req); + peer->hello_req = NULL; + } + if (peer->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (peer->hello_delay_task); + peer->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; + } + peer->hello_delay_task = + GNUNET_SCHEDULER_add_now (&schedule_next_hello, peer); + return GNUNET_YES; +} + + +/** + * Method called whenever a peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + */ +static void +connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct Peer *pos; + +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core told us that we are connecting to `%s'\n", + GNUNET_i2s (peer)); +#endif + if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + + connection_count++; + GNUNET_STATISTICS_set (stats, gettext_noop ("# peers connected"), + connection_count, GNUNET_NO); + pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); + if (pos == NULL) + { + pos = make_peer (peer, NULL, GNUNET_NO); + GNUNET_break (GNUNET_OK == is_connection_allowed (pos)); + } + else + { + GNUNET_assert (GNUNET_NO == pos->is_connected); + pos->greylisted_until.abs_value = 0; /* remove greylisting */ + } + pos->is_connected = GNUNET_YES; + pos->connect_attempts = 0; /* re-set back-off factor */ + if (pos->is_friend) + { + if ((friend_count == minimum_friend_count - 1) && + (GNUNET_YES != friends_only)) + whitelist_peers (); + friend_count++; + GNUNET_STATISTICS_set (stats, gettext_noop ("# friends connected"), + friend_count, GNUNET_NO); + } + reschedule_hellos (NULL, &peer->hashPubKey, pos); +} + + +/** + * Try to add more peers to our connection set. + * + * @param cls closure, not used + * @param pid identity of a peer + * @param value 'struct Peer*' for the peer + * @return GNUNET_YES (continue to iterate) + */ +static int +try_add_peers (void *cls, const GNUNET_HashCode * pid, void *value) +{ + struct Peer *pos = value; + + attempt_connect (pos); + return GNUNET_YES; +} + + +/** + * Last task run during shutdown. Disconnects us from + * the transport and core. + * + * @param cls unused, NULL + * @param tc scheduler context + */ +static void +add_peer_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + add_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_CONTAINER_multihashmap_iterate (peers, &try_add_peers, NULL); +} + +/** + * Method called whenever a peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct Peer *pos; + + if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) + return; +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core told us that we disconnected from `%s'\n", + GNUNET_i2s (peer)); +#endif + pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); + if (pos == NULL) + { + GNUNET_break (0); + return; + } + if (pos->is_connected != GNUNET_YES) + { + GNUNET_break (0); + return; + } + pos->is_connected = GNUNET_NO; + connection_count--; + if (NULL != pos->hello_req) + { + GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req); + pos->hello_req = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != pos->hello_delay_task) + { + GNUNET_SCHEDULER_cancel (pos->hello_delay_task); + pos->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_STATISTICS_set (stats, gettext_noop ("# peers connected"), + connection_count, GNUNET_NO); + if (pos->is_friend) + { + friend_count--; + GNUNET_STATISTICS_set (stats, gettext_noop ("# friends connected"), + friend_count, GNUNET_NO); + } + if (((connection_count < target_connection_count) || + (friend_count < minimum_friend_count)) && + (GNUNET_SCHEDULER_NO_TASK == add_task)) + add_task = GNUNET_SCHEDULER_add_now (&add_peer_task, NULL); + if ((friend_count < minimum_friend_count) && (blacklist == NULL)) + blacklist = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_check, NULL); +} + + +/** + * Iterator called on each address. + * + * @param cls flag that we will set if we see any addresses + * @param address the address of the peer + * @param expiration when will the given address expire + * @return GNUNET_SYSERR always, to terminate iteration + */ +static int +address_iterator (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + int *flag = cls; + + *flag = GNUNET_YES; + return GNUNET_SYSERR; +} + + +/** + * We've gotten a HELLO from another peer. Consider it for + * advertising. + * + * @param hello the HELLO we got + */ +static void +consider_for_advertising (const struct GNUNET_HELLO_Message *hello) +{ + int have_address; + struct GNUNET_PeerIdentity pid; + struct GNUNET_TIME_Absolute dt; + struct GNUNET_HELLO_Message *nh; + struct Peer *peer; + uint16_t size; + + if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) + { + GNUNET_break (0); + return; + } + if (0 == memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity))) + return; /* that's me! */ + have_address = GNUNET_NO; + GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &address_iterator, + &have_address); + if (GNUNET_NO == have_address) + return; /* no point in advertising this one... */ + peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey); + if (peer == NULL) + { + peer = make_peer (&pid, hello, GNUNET_NO); + } + else if (peer->hello != NULL) + { + dt = GNUNET_HELLO_equals (peer->hello, hello, GNUNET_TIME_absolute_get ()); + if (dt.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) + return; /* nothing new here */ + } +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found `%s' from peer `%s' for advertising\n", "HELLO", + GNUNET_i2s (&pid)); +#endif + if (peer->hello != NULL) + { + nh = GNUNET_HELLO_merge (peer->hello, hello); + GNUNET_free (peer->hello); + peer->hello = nh; + } + else + { + size = GNUNET_HELLO_size (hello); + peer->hello = GNUNET_malloc (size); + memcpy (peer->hello, hello, size); + } + if (peer->filter != NULL) + GNUNET_CONTAINER_bloomfilter_free (peer->filter); + setup_filter (peer); + /* since we have a new HELLO to pick from, re-schedule all + * HELLO requests that are not bound by the HELLO send rate! */ + GNUNET_CONTAINER_multihashmap_iterate (peers, &reschedule_hellos, peer); +} + + +/** + * PEERINFO calls this function to let us know about a possible peer + * that we might want to connect to. + * + * @param cls closure (not used) + * @param peer potential peer to connect to + * @param hello HELLO for this peer (or NULL) + * @param err_msg NULL if successful, otherwise contains error message + */ +static void +process_peer (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, const char *err_msg) +{ + struct Peer *pos; + + if (err_msg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Error in communication with PEERINFO service: %s\n"), + err_msg); + GNUNET_PEERINFO_notify_cancel (peerinfo_notify); + peerinfo_notify = GNUNET_PEERINFO_notify (cfg, &process_peer, NULL); + return; + } + GNUNET_assert (peer != NULL); + if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) + return; /* that's me! */ + if (hello == NULL) + { + /* free existing HELLO, if any */ + pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); + if (NULL != pos) + { + GNUNET_free_non_null (pos->hello); + pos->hello = NULL; + if (pos->filter != NULL) + { + GNUNET_CONTAINER_bloomfilter_free (pos->filter); + pos->filter = NULL; + } + if ((!pos->is_connected) && (!pos->is_friend) && + (0 == + GNUNET_TIME_absolute_get_remaining (pos-> + greylisted_until).rel_value)) + free_peer (NULL, &pos->pid.hashPubKey, pos); + } + return; + } + consider_for_advertising (hello); + pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); + if (pos == NULL) + pos = make_peer (peer, hello, GNUNET_NO); + GNUNET_assert (NULL != pos); + if (GNUNET_YES == pos->is_connected) + { +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already connected to peer `%s'\n", + GNUNET_i2s (peer)); +#endif + return; + } + if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value > 0) + { +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already tried peer `%s' recently\n", + GNUNET_i2s (peer)); +#endif + return; /* peer still greylisted */ + } +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering connecting to peer `%s'\n", + GNUNET_i2s (peer)); +#endif + attempt_connect (pos); +} + + +/** + * Function called after GNUNET_CORE_connect has succeeded + * (or failed for good). + * + * @param cls closure + * @param server handle to the server, NULL if we failed + * @param my_id ID of this peer, NULL if we failed + */ +static void +core_init (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_id) +{ + if (server == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Failed to connect to core service, can not manage topology!\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + handle = server; + my_identity = *my_id; +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I am peer `%s'\n", GNUNET_i2s (my_id)); +#endif + peerinfo_notify = GNUNET_PEERINFO_notify (cfg, &process_peer, NULL); +} + + +/** + * Read the friends file. + */ +static void +read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *fn; + char *data; + size_t pos; + struct GNUNET_PeerIdentity pid; + struct stat frstat; + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + unsigned int entries_found; + struct Peer *fl; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "TOPOLOGY", "FRIENDS", &fn)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Option `%s' in section `%s' not specified!\n"), "FRIENDS", + "TOPOLOGY"); + return; + } + if (GNUNET_OK != GNUNET_DISK_file_test (fn)) + GNUNET_DISK_fn_write (fn, NULL, 0, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (0 != STAT (fn, &frstat)) + { + if ((friends_only) || (minimum_friend_count > 0)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not read friends list `%s'\n"), fn); + GNUNET_free (fn); + return; + } + if (frstat.st_size == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Friends file `%s' is empty.\n"), + fn); + GNUNET_free (fn); + return; + } + data = GNUNET_malloc_large (frstat.st_size); + if (data == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to read friends list from `%s': out of memory\n"), + fn); + GNUNET_free (fn); + return; + } + if (frstat.st_size != GNUNET_DISK_fn_read (fn, data, frstat.st_size)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to read friends list from `%s'\n"), fn); + GNUNET_free (fn); + GNUNET_free (data); + return; + } + entries_found = 0; + pos = 0; + while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos])) + pos++; + while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) && + (pos <= + frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))) + { + memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + if (!isspace + ((unsigned char) + enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1])) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Syntax error in topology specification at offset %llu, skipping bytes.\n"), + (unsigned long long) pos); + pos++; + while ((pos < frstat.st_size) && (!isspace ((unsigned char) data[pos]))) + pos++; + continue; + } + enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + if (GNUNET_OK != + GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"), + (unsigned long long) pos, &enc); + } + else + { + if (0 != memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity))) + { + entries_found++; + fl = make_peer (&pid, NULL, GNUNET_YES); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Found friend `%s' in configuration\n"), + GNUNET_i2s (&fl->pid)); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Found myself `%s' in friend list (useless, ignored)\n"), + GNUNET_i2s (&pid)); + } + } + pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded); + while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos])) + pos++; + } + GNUNET_free (data); + GNUNET_free (fn); + GNUNET_STATISTICS_update (stats, gettext_noop ("# friends in configuration"), + entries_found, GNUNET_NO); + if ((minimum_friend_count > entries_found) && (friends_only == GNUNET_NO)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n")); + } + if ((minimum_friend_count > target_connection_count) && + (friends_only == GNUNET_NO)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("More friendly connections required than target total number of connections.\n")); + } +} + + +/** + * This function is called whenever an encrypted HELLO message is + * received. + * + * @param cls closure + * @param other the other peer involved (sender or receiver, NULL + * for loopback messages where we are both sender and receiver) + * @param message the actual HELLO message + * @param atsi performance data + * @param atsi_count number of records in 'atsi' + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_encrypted_hello (void *cls, const struct GNUNET_PeerIdentity *other, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct Peer *peer; + struct GNUNET_PeerIdentity pid; + +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received encrypted `%s' from peer `%s'", + "HELLO", GNUNET_i2s (other)); +#endif + if (GNUNET_OK != + GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message, &pid)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages received"), + 1, GNUNET_NO); + peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey); + if (peer == NULL) + { + if ((GNUNET_YES == friends_only) || (friend_count < minimum_friend_count)) + return GNUNET_OK; + } + else + { + if ((GNUNET_YES != peer->is_friend) && (GNUNET_YES == friends_only)) + return GNUNET_OK; + if ((GNUNET_YES != peer->is_friend) && + (friend_count < minimum_friend_count)) + return GNUNET_OK; + } + if (transport != NULL) + GNUNET_TRANSPORT_offer_hello (transport, message, NULL, NULL); + return GNUNET_OK; +} + + +/** + * Function to fill send buffer with HELLO. + * + * @param cls 'struct Peer' of the target peer + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +hello_advertising_ready (void *cls, size_t size, void *buf) +{ + struct Peer *pl = cls; + struct FindAdvHelloContext fah; + size_t want; + + pl->hello_req = NULL; + GNUNET_assert (GNUNET_YES == pl->is_connected); + /* find applicable HELLOs */ + fah.peer = pl; + fah.result = NULL; + fah.max_size = size; + fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_CONTAINER_multihashmap_iterate (peers, &find_advertisable_hello, &fah); + want = 0; + if (fah.result != NULL) + { + want = GNUNET_HELLO_size (fah.result->hello); + GNUNET_assert (want <= size); + memcpy (buf, fah.result->hello, want); + GNUNET_CONTAINER_bloomfilter_add (fah.result->filter, &pl->pid.hashPubKey); +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' with %u bytes", "HELLO", + (unsigned int) want); +#endif + GNUNET_STATISTICS_update (stats, + gettext_noop ("# HELLO messages gossipped"), 1, + GNUNET_NO); + } + + if (pl->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (pl->hello_delay_task); + pl->next_hello_allowed = + GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY); + pl->hello_delay_task = GNUNET_SCHEDULER_add_now (&schedule_next_hello, pl); + return want; +} + + +/** + * Last task run during shutdown. Disconnects us from + * the transport and core. + * + * @param cls unused, NULL + * @param tc scheduler context + */ +static void +cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != peerinfo_notify) + { + GNUNET_PEERINFO_notify_cancel (peerinfo_notify); + peerinfo_notify = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != add_task) + { + GNUNET_SCHEDULER_cancel (add_task); + add_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_TRANSPORT_disconnect (transport); + transport = NULL; + GNUNET_CONTAINER_multihashmap_iterate (peers, &free_peer, NULL); + GNUNET_CONTAINER_multihashmap_destroy (peers); + if (handle != NULL) + { + GNUNET_CORE_disconnect (handle); + handle = NULL; + } + whitelist_peers (); + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + stats = NULL; + } +} + + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + static struct GNUNET_CORE_MessageHandler handlers[] = { + {&handle_encrypted_hello, GNUNET_MESSAGE_TYPE_HELLO, 0}, + {NULL, 0, 0} + }; + unsigned long long opt; + + cfg = c; + stats = GNUNET_STATISTICS_create ("topology", cfg); + autoconnect = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "TOPOLOGY", "AUTOCONNECT"); + friends_only = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "TOPOLOGY", "FRIENDS-ONLY"); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "TOPOLOGY", "MINIMUM-FRIENDS", + &opt)) + opt = 0; + minimum_friend_count = (unsigned int) opt; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "TOPOLOGY", + "TARGET-CONNECTION-COUNT", &opt)) + opt = 16; + target_connection_count = (unsigned int) opt; + peers = GNUNET_CONTAINER_multihashmap_create (target_connection_count * 2); + + if ((friends_only == GNUNET_YES) || (minimum_friend_count > 0)) + read_friends_file (cfg); +#if DEBUG_TOPOLOGY + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Topology would like %u connections with at least %u friends (%s)\n", + target_connection_count, minimum_friend_count, + autoconnect ? "autoconnect enabled" : "autoconnect disabled"); +#endif + if ((friend_count < minimum_friend_count) && (blacklist == NULL)) + blacklist = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_check, NULL); + transport = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL, NULL, NULL); + handle = + GNUNET_CORE_connect (cfg, 1, NULL, &core_init, &connect_notify, + &disconnect_notify, NULL, GNUNET_NO, NULL, GNUNET_NO, + handlers); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task, + NULL); + if (NULL == transport) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to `%s' service.\n"), "transport"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (NULL == handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to `%s' service.\n"), "core"); + GNUNET_SCHEDULER_shutdown (); + return; + } +} + + +/** + * The main function for the topology daemon. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + int ret; + + ret = + (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-topology", + _ + ("GNUnet topology control (maintaining P2P mesh and F2F constraints)"), + options, &run, NULL)) ? 0 : 1; + return ret; +} + +/* end of gnunet-daemon-topology.c */ diff --git a/src/topology/test_gnunet_daemon_topology.c b/src/topology/test_gnunet_daemon_topology.c new file mode 100644 index 0000000..7592ede --- /dev/null +++ b/src/topology/test_gnunet_daemon_topology.c @@ -0,0 +1,218 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file topology/test_gnunet_daemon_topology.c + * @brief testcase for topology maintenance code + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_NO + +#define NUM_PEERS 2 + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) + +#define CONNECT_ATTEMPTS 3 + + +static int ok; + +static int peers_left; + +static int connect_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +static struct GNUNET_TESTING_Daemon *first; + +static struct GNUNET_TESTING_Daemon *last; + +/** + * Active connection attempt. + */ +struct GNUNET_TESTING_ConnectContext *cc[NUM_PEERS]; + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + + +static void +clean_up_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned int i; + + for (i = 0; i < NUM_PEERS; i++) + { + if (NULL != cc[i]) + { + GNUNET_TESTING_daemons_connect_cancel (cc[i]); + cc[i] = NULL; + } + } + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 0; +} + + +static void +notify_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, + unsigned int distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + struct GNUNET_TESTING_ConnectContext **cc = cls; + unsigned int i; + + *cc = NULL; + if (NULL != emsg) + { + FPRINTF (stderr, "Failed to connect two peers: %s\n", emsg); + for (i = 0; i < NUM_PEERS; i++) + if (NULL != cc[i]) + { + GNUNET_TESTING_daemons_connect_cancel (cc[i]); + cc[i] = NULL; + } + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_assert (0); + return; + } + connect_left--; + if (connect_left == 0) + { + /* FIXME: check that topology adds a few more links + * in addition to those that were seeded */ + GNUNET_SCHEDULER_add_now (&clean_up_task, NULL); + } +} + + +static void +my_cb (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + GNUNET_assert (id != NULL); + peers_left--; + if (first == NULL) + { + connect_left = NUM_PEERS; + first = d; + last = d; + return; + } + cc[peers_left] = + GNUNET_TESTING_daemons_connect (last, d, TIMEOUT, CONNECT_ATTEMPTS, + GNUNET_YES, ¬ify_connect_complete, + &cc[peers_left]); + if (peers_left == 0) + { + /* close circle */ + cc[NUM_PEERS - 1] = + GNUNET_TESTING_daemons_connect (d, first, TIMEOUT, CONNECT_ATTEMPTS, + GNUNET_YES, ¬ify_connect_complete, + &cc[NUM_PEERS - 1]); + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); +#endif + peers_left = NUM_PEERS; + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, + TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, + NULL, NULL); + GNUNET_assert (pg != NULL); +} + + +static int +check () +{ + char *const argv[] = { + "test-gnunet-daemon-topology", + "-c", + "test_gnunet_daemon_topology_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gnunet-daemon-topology", "nohelp", options, &run, + &ok); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gnunet-daemon-topology", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-topology"); + return ret; +} + +/* end of test_gnunet_daemon_topology.c */ diff --git a/src/topology/test_gnunet_daemon_topology_data.conf b/src/topology/test_gnunet_daemon_topology_data.conf new file mode 100644 index 0000000..2bce10d --- /dev/null +++ b/src/topology/test_gnunet_daemon_topology_data.conf @@ -0,0 +1,64 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunet-topology/ + +[resolver] +PORT = 2664 + +[transport] +PORT = 2665 +PLUGINS = tcp +#DEBUG = YES +#PREFIX = xterm -e xterm -T transport -e gdb -x cmd --args +#PREFIX = valgrind --tool=memcheck --log-file=logs%p + +[arm] +PORT = 2666 +DEFAULTSERVICES = topology + +[statistics] +PORT = 2667 + +[transport-tcp] +PORT = 2668 +BINDTO = 127.0.0.1 + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO +USE_HOSTNAME = NO + +[peerinfo] +PORT = 2669 + +[core] +PORT = 2670 +#DEBUG = YES + +[topology] +# DEBUG = YES +#PREFIX = valgrind --tool=memcheck + +[fs] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[testing] +WEAKRANDOM = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat + +[dns] +AUTOSTART = NO + + + +[nse] +AUTOSTART = NO + + diff --git a/src/topology/topology.conf b/src/topology/topology.conf new file mode 100644 index 0000000..39f2921 --- /dev/null +++ b/src/topology/topology.conf @@ -0,0 +1,10 @@ +[topology] +MINIMUM-FRIENDS = 0 +FRIENDS-ONLY = NO +AUTOCONNECT = YES +TARGET-CONNECTION-COUNT = 16 +FRIENDS = $SERVICEHOME/friends +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-daemon-topology + + diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am new file mode 100644 index 0000000..0692450 --- /dev/null +++ b/src/transport/Makefile.am @@ -0,0 +1,811 @@ +INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include + +plugindir = $(libdir)/gnunet + +pkgcfgdir= $(pkgdatadir)/config.d/ + +pkgcfg_DATA = \ + transport.conf + + +if HAVE_MHD + GN_LIBMHD = -lmicrohttpd + HTTP_PLUGIN_LA = libgnunet_plugin_transport_http.la + HTTP_API_TEST = test_transport_api_http + HTTP_NAT_API_TEST = test_transport_api_http_nat + HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http + HTTP_REL_TEST = test_transport_api_reliability_http + HTTP_NAT_REL_TEST = test_transport_api_reliability_http_nat + HTTP_QUOTA_TEST = test_quota_compliance_http \ + test_quota_compliance_http_asymmetric + HTTPS_PLUGIN_LA = libgnunet_plugin_transport_https.la + HTTPS_API_TEST = test_transport_api_https + HTTPS_NAT_API_TEST = test_transport_api_https_nat + HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https + HTTPS_REL_TEST = test_transport_api_reliability_https + HTTPS_NAT_REL_TEST = test_transport_api_reliability_https_nat + HTTPS_QUOTA_TEST = test_quota_compliance_https \ + test_quota_compliance_https_asymmetric +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 +endif + +if LINUX + WLAN_BIN = gnunet-helper-transport-wlan + WLAN_BIN_DUMMY = gnunet-helper-transport-wlan-dummy + WLAN_BIN_SENDER = gnunet-transport-wlan-sender + WLAN_PLUGIN_LA = libgnunet_plugin_transport_wlan.la + WLAN_API_TEST = test_transport_api_wlan + WLAN_REL_TEST = test_transport_api_reliability_wlan + WLAN_UREL_TEST = test_transport_api_unreliability_wlan +endif + + +if LINUX +install-exec-hook: + $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-transport-wlan || true + $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-transport-wlan || true +else +install-exec-hook: +endif + +if !MINGW +UNIX_PLUGIN_LA = libgnunet_plugin_transport_unix.la +UNIX_PLUGIN_TEST = test_transport_api_unix +UNIX_PLUGIN_TIMEOUT_TEST = test_transport_api_timeout_unix +UNIX_REL_TEST = test_transport_api_unreliability_unix +UNIX_QUOTA_TEST = test_quota_compliance_unix \ + test_quota_compliance_unix_asymmetric +endif + +noinst_PROGRAMS = \ + $(WLAN_BIN_DUMMY) \ + $(WLAN_BIN_SENDER) +# gnunet-transport-connect-running-peers + +lib_LTLIBRARIES = \ + libgnunettransport.la \ + libgnunettransporttesting.la + +libgnunettransporttesting_la_SOURCES = \ + transport-testing.c transport-testing.h +libgnunettransporttesting_la_LIBADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +libgnunettransporttesting_la_DEPENDENCIES = \ + libgnunettransport.la +libgnunettransporttesting_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) + +libgnunettransport_la_SOURCES = \ + transport_api.c transport.h \ + transport_api_blacklist.c \ + transport_api_address_to_string.c \ + transport_api_address_lookup.c +libgnunettransport_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +libgnunettransport_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +bin_PROGRAMS = \ + gnunet-transport \ + $(WLAN_BIN) \ + gnunet-service-transport \ + gnunet-transport-certificate-creation + +#bin_SCRIPTS = \ +# gnunet-transport-certificate-creation + +gnunet_transport_certificate_creation_SOURCES = \ + gnunet-transport-certificate-creation.c +gnunet_transport_certificate_creation_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_helper_transport_wlan_SOURCES = \ + gnunet-helper-transport-wlan.c + +gnunet_helper_transport_wlan_dummy_SOURCES = \ + gnunet-helper-transport-wlan-dummy.c +gnunet_helper_transport_wlan_dummy_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_transport_wlan_sender_SOURCES = \ + gnunet-transport-wlan-sender.c +gnunet_transport_wlan_sender_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_transport_SOURCES = \ + gnunet-transport.c +gnunet_transport_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_transport_DEPENDENCIES = \ + libgnunettransport.la + +gnunet_service_transport_SOURCES = \ + gnunet-service-transport.c gnunet-service-transport.h \ + gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \ + gnunet-service-transport_clients.h gnunet-service-transport_clients.c \ + gnunet-service-transport_hello.h gnunet-service-transport_hello.c \ + gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \ + gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \ + gnunet-service-transport_validation.h gnunet-service-transport_validation.c +gnunet_service_transport_LDADD = \ + $(top_builddir)/src/ats/libgnunetats.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_GLPK) \ + $(GN_LIBINTL) + +plugin_LTLIBRARIES = \ + libgnunet_plugin_transport_tcp.la \ + libgnunet_plugin_transport_udp.la \ + $(UNIX_PLUGIN_LA) \ + $(HTTP_PLUGIN_LA) \ + $(HTTPS_PLUGIN_LA) \ + $(WLAN_PLUGIN_LA) \ + libgnunet_plugin_transport_template.la + +libgnunet_plugin_transport_tcp_la_SOURCES = \ + plugin_transport_tcp.c +libgnunet_plugin_transport_tcp_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_transport_tcp_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_template_la_SOURCES = \ + plugin_transport_template.c +libgnunet_plugin_transport_template_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_transport_template_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_wlan_la_SOURCES = \ + plugin_transport_wlan.c plugin_transport_wlan.h +libgnunet_plugin_transport_wlan_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_transport_wlan_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_udp_la_SOURCES = \ + plugin_transport_udp.c plugin_transport_udp.h \ + plugin_transport_udp_broadcasting.c +libgnunet_plugin_transport_udp_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_transport_udp_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_unix_la_SOURCES = \ + plugin_transport_unix.c +libgnunet_plugin_transport_unix_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_transport_unix_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_http_la_SOURCES = \ + plugin_transport_http.c plugin_transport_http.h \ + plugin_transport_http_client.c plugin_transport_http_server.c +libgnunet_plugin_transport_http_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + @LIBCURL@ \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_transport_http_la_LDFLAGS = \ + $(GN_LIBMHD) \ + $(GN_PLUGIN_LDFLAGS) +libgnunet_plugin_transport_http_la_CFLAGS = \ + $(CFLAGS) +libgnunet_plugin_transport_http_la_CPPFLAGS = \ + @LIBCURL_CPPFLAGS@ + +libgnunet_plugin_transport_https_la_SOURCES = \ + plugin_transport_http.c plugin_transport_http.h \ + plugin_transport_http_client.c plugin_transport_http_server.c +libgnunet_plugin_transport_https_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + @LIBCURL@ \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_transport_https_la_LDFLAGS = \ + $(GN_LIBMHD) \ + $(GN_PLUGIN_LDFLAGS) +libgnunet_plugin_transport_https_la_CFLAGS = \ + $(CFLAGS) -DBUILD_HTTPS +libgnunet_plugin_transport_https_la_CPPFLAGS = \ + @LIBCURL_CPPFLAGS@ + + +check_PROGRAMS = \ + test_transport_testing \ + test_transport_startonly \ + test_transport_api_blacklisting \ + test_transport_api_disconnect_tcp \ + test_transport_api_bidirectional_connect \ + test_transport_api_tcp \ + test_transport_api_restart_1peer \ + test_transport_api_restart_2peers \ + test_transport_api_timeout_tcp \ + test_transport_api_limited_sockets_tcp \ + test_transport_api_tcp_nat \ + test_transport_api_udp \ + test_transport_api_timeout_udp \ + $(UNIX_PLUGIN_TEST) \ + $(UNIX_PLUGIN_TIMEOUT_TEST) \ + test_transport_api_udp_nat \ + $(HTTP_API_TEST) \ + $(HTTP_NAT_API_TEST) \ + $(HTTP_API_TIMEOUT_TEST) \ + $(HTTPS_API_TEST) \ + $(HTTPS_NAT_API_TEST) \ + $(HTTPS_API_TIMEOUT_TEST) \ + test_transport_api_multi \ + test_transport_api_reliability_tcp \ + test_transport_api_reliability_tcp_nat \ + test_transport_api_unreliability_udp \ + test_transport_api_unreliability_constant_udp \ + $(UNIX_REL_TEST) \ + $(HTTP_REL_TEST) \ + $(HTTP_NAT_REL_TEST) \ + $(HTTPS_REL_TEST) \ + $(HTTPS_NAT_REL_TEST) \ + test_quota_compliance_tcp \ + test_quota_compliance_tcp_asymmetric \ + test_quota_compliance_udp \ + $(UNIX_QUOTA_TEST) \ + $(HTTP_QUOTA_TEST) \ + $(HTTPS_QUOTA_TEST) \ + $(WLAN_API_TEST) \ + $(WLAN_REL_TEST) \ + $(WLAN_UREL_TEST) + +if ENABLE_TEST_RUN +TESTS = \ + test_transport_testing \ + test_transport_startonly \ + test_transport_api_blacklisting \ + test_transport_api_disconnect_tcp \ + test_transport_api_bidirectional_connect \ + test_transport_api_tcp \ + test_transport_api_restart_1peer \ + test_transport_api_restart_2peers \ + test_transport_api_timeout_tcp \ + test_transport_api_limited_sockets_tcp \ + test_transport_api_tcp_nat \ + test_transport_api_udp \ + test_transport_api_timeout_udp \ + $(UNIX_PLUGIN_TEST) \ + $(UNIX_PLUGIN_TIMEOUT_TEST) \ + test_transport_api_udp_nat \ + $(HTTP_API_TEST) \ + $(HTTP_NAT_API_TEST) \ + $(HTTP_API_TIMEOUT_TEST) \ + $(HTTPS_API_TEST) \ + $(HTTPS_NAT_API_TEST) \ + $(HTTPS_API_TIMEOUT_TEST) \ + test_transport_api_multi \ + test_transport_api_reliability_tcp \ + test_transport_api_reliability_tcp_nat \ + test_transport_api_unreliability_udp \ + test_transport_api_unreliability_constant_udp \ + $(UNIX_REL_TEST) \ + $(HTTP_REL_TEST) \ + $(HTTP_NAT_REL_TEST) \ + $(HTTPS_REL_TEST) \ + $(HTTPS_NAT_REL_TEST) \ + test_quota_compliance_tcp \ + test_quota_compliance_tcp_asymmetric \ + test_quota_compliance_udp \ + $(UNIX_QUOTA_TEST) \ + $(HTTP_QUOTA_TEST) \ + $(HTTPS_QUOTA_TEST) \ + $(WLAN_API_TEST) \ + $(WLAN_REL_TEST) \ + $(WLAN_UREL_TEST) +endif + +test_transport_testing_SOURCES = \ + test_transport_testing.c +test_transport_testing_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +#gnunet_transport_connect_running_peers_SOURCES = \ +# gnunet-transport-connect-running-peers.c +#gnunet_transport_connect_running_peers_LDADD = \ +# $(top_builddir)/src/transport/libgnunettransport.la \ +# $(top_builddir)/src/hello/libgnunethello.la \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_blacklisting_SOURCES = \ + test_transport_api_blacklisting.c +test_transport_api_blacklisting_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_disconnect_tcp_SOURCES = \ + test_transport_api_disconnect.c +test_transport_api_disconnect_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_startonly_SOURCES = \ + test_transport_startonly.c +test_transport_startonly_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_tcp_SOURCES = \ + test_transport_api.c +test_transport_api_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_bidirectional_connect_SOURCES = \ + test_transport_api_bidirectional_connect.c +test_transport_api_bidirectional_connect_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_restart_1peer_SOURCES = \ + test_transport_api_restart_1peer.c +test_transport_api_restart_1peer_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_restart_2peers_SOURCES = \ + test_transport_api_restart_2peers.c +test_transport_api_restart_2peers_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_limited_sockets_tcp_SOURCES = \ + test_transport_api_limited_sockets.c +test_transport_api_limited_sockets_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_tcp_nat_SOURCES = \ + test_transport_api.c +test_transport_api_tcp_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_tcp_SOURCES = \ + test_transport_api_reliability.c +test_transport_api_reliability_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_timeout_tcp_SOURCES = \ + test_transport_api_timeout.c +test_transport_api_timeout_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_timeout_unix_SOURCES = \ + test_transport_api_timeout.c +test_transport_api_timeout_unix_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_timeout_http_SOURCES = \ + test_transport_api_timeout.c +test_transport_api_timeout_http_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_timeout_https_SOURCES = \ + test_transport_api_timeout.c +test_transport_api_timeout_https_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_tcp_nat_SOURCES = \ + test_transport_api_reliability.c +test_transport_api_reliability_tcp_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_wlan_SOURCES = \ + test_transport_api_reliability.c +test_transport_api_reliability_wlan_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_unreliability_wlan_SOURCES = \ + test_transport_api_unreliability.c +test_transport_api_unreliability_wlan_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_udp_SOURCES = \ + test_transport_api.c +test_transport_api_udp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_timeout_udp_SOURCES = \ + test_transport_api_timeout.c +test_transport_api_timeout_udp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_udp_nat_SOURCES = \ + test_transport_api.c +test_transport_api_udp_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_unix_SOURCES = \ + test_transport_api.c +test_transport_api_unix_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_http_SOURCES = \ + test_transport_api.c +test_transport_api_http_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + + test_transport_api_http_nat_SOURCES = \ + test_transport_api.c +test_transport_api_http_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_http_SOURCES = \ + test_transport_api_reliability.c +test_transport_api_reliability_http_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_http_nat_SOURCES = \ + test_transport_api_reliability.c +test_transport_api_reliability_http_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_https_SOURCES = \ + test_transport_api.c +test_transport_api_https_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_https_nat_SOURCES = \ + test_transport_api.c +test_transport_api_https_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_https_SOURCES = \ + test_transport_api_reliability.c +test_transport_api_reliability_https_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_https_nat_SOURCES = \ + test_transport_api_reliability.c +test_transport_api_reliability_https_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_unreliability_unix_SOURCES = \ + test_transport_api_unreliability.c +test_transport_api_unreliability_unix_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_unreliability_udp_SOURCES = \ + test_transport_api_unreliability.c +test_transport_api_unreliability_udp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_unreliability_constant_udp_SOURCES = \ + test_transport_api_unreliability_constant.c +test_transport_api_unreliability_constant_udp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +if LINUX +test_transport_api_wlan_SOURCES = \ + test_transport_api.c +test_transport_api_wlan_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +endif + +test_quota_compliance_tcp_SOURCES = \ + test_quota_compliance.c +test_quota_compliance_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_quota_compliance_tcp_asymmetric_SOURCES = \ + test_quota_compliance.c +test_quota_compliance_tcp_asymmetric_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +#test_quota_compliance_tcp_asymmetric_send_constant_SOURCES = \ +# test_quota_compliance.c +#test_quota_compliance_tcp_asymmetric_send_constant_LDADD = \ +# $(top_builddir)/src/transport/libgnunettransport.la \ +# $(top_builddir)/src/util/libgnunetutil.la + +test_quota_compliance_http_SOURCES = \ + test_quota_compliance.c +test_quota_compliance_http_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + + test_quota_compliance_http_asymmetric_SOURCES = \ + test_quota_compliance.c +test_quota_compliance_http_asymmetric_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +#test_quota_compliance_http_asymmetric_send_constant_SOURCES = \ +# test_quota_compliance.c +#test_quota_compliance_http_asymmetric_send_constant_LDADD = \ +# $(top_builddir)/src/transport/libgnunettransport.la \ +# $(top_builddir)/src/util/libgnunetutil.la + +test_quota_compliance_https_SOURCES = \ + test_quota_compliance.c +test_quota_compliance_https_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + + test_quota_compliance_https_asymmetric_SOURCES = \ + test_quota_compliance.c +test_quota_compliance_https_asymmetric_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +#test_quota_compliance_https_asymmetric_send_constant_SOURCES = \ +# test_quota_compliance.c +#test_quota_compliance_https_asymmetric_send_constant_LDADD = \ +# $(top_builddir)/src/transport/libgnunettransport.la \ +# $(top_builddir)/src/util/libgnunetutil.la + +test_quota_compliance_udp_SOURCES = \ + test_quota_compliance.c +test_quota_compliance_udp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_quota_compliance_unix_SOURCES = \ + test_quota_compliance.c +test_quota_compliance_unix_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_quota_compliance_unix_asymmetric_SOURCES = \ + test_quota_compliance.c +test_quota_compliance_unix_asymmetric_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_multi_SOURCES = \ + test_transport_api.c +test_transport_api_multi_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + + +EXTRA_DIST = \ +gnunet-transport-certificate-creation \ +template_cfg_peer1.conf\ +template_cfg_peer2.conf\ +test_plugin_transport_data.conf\ +test_plugin_transport_data_udp.conf\ +test_quota_compliance_data.conf\ +test_quota_compliance_http_peer1.conf\ +test_quota_compliance_http_peer2.conf\ +test_quota_compliance_https_peer1.conf\ +test_quota_compliance_https_peer2.conf\ +test_quota_compliance_tcp_peer1.conf\ +test_quota_compliance_tcp_peer2.conf\ +test_quota_compliance_udp_peer1.conf\ +test_quota_compliance_udp_peer2.conf\ +test_quota_compliance_unix_peer1.conf\ +test_quota_compliance_unix_peer2.conf\ +test_quota_compliance_http_asymmetric_peer1.conf\ +test_quota_compliance_http_asymmetric_peer2.conf\ +test_quota_compliance_https_asymmetric_peer1.conf\ +test_quota_compliance_https_asymmetric_peer2.conf\ +test_quota_compliance_tcp_asymmetric_peer1.conf\ +test_quota_compliance_tcp_asymmetric_peer2.conf\ +test_quota_compliance_unix_asymmetric_peer1.conf\ +test_quota_compliance_unix_asymmetric_peer2.conf\ +test_transport_api_data.conf\ +test_transport_api_http_peer1.conf\ +test_transport_api_http_peer2.conf\ +test_transport_api_https_peer1.conf\ +test_transport_api_https_peer2.conf\ +test_transport_api_limited_sockets_tcp_peer1.conf\ +test_transport_api_limited_sockets_tcp_peer2.conf\ +test_transport_api_timeout_tcp_peer1.conf\ +test_transport_api_timeout_tcp_peer2.conf\ +test_transport_api_multi_peer1.conf\ +test_transport_api_multi_peer2.conf\ +test_transport_api_reliability_http_peer1.conf\ +test_transport_api_reliability_http_peer2.conf\ +test_transport_api_reliability_https_peer1.conf\ +test_transport_api_reliability_https_peer2.conf\ +test_transport_api_reliability_tcp_nat_peer1.conf\ +test_transport_api_reliability_tcp_nat_peer2.conf\ +test_transport_api_reliability_tcp_peer1.conf\ +test_transport_api_reliability_tcp_peer2.conf\ +test_transport_api_reliability_wlan_peer1.conf\ +test_transport_api_reliability_wlan_peer2.conf\ +test_transport_api_bidirectional_connect_peer1.conf\ +test_transport_api_bidirectional_connect_peer2.conf\ +test_transport_api_tcp_nat_peer1.conf\ +test_transport_api_tcp_nat_peer2.conf\ +test_transport_api_tcp_peer1.conf\ +test_transport_api_tcp_peer2.conf\ +test_transport_api_udp_nat_peer1.conf\ +test_transport_api_udp_nat_peer2.conf\ +test_transport_api_udp_peer1.conf\ +test_transport_api_udp_peer2.conf\ +test_transport_api_timeout_udp_peer1.conf\ +test_transport_api_timeout_udp_peer2.conf\ +test_transport_api_unix_peer1.conf\ +test_transport_api_unix_peer2.conf\ +test_transport_api_timeout_unix_peer1.conf\ +test_transport_api_timeout_unix_peer2.conf\ +test_transport_api_unreliability_udp_peer1.conf\ +test_transport_api_unreliability_udp_peer2.conf\ +test_transport_api_unreliability_unix_peer1.conf\ +test_transport_api_unreliability_unix_peer2.conf\ +test_transport_api_unreliability_wlan_peer1.conf\ +test_transport_api_unreliability_wlan_peer2.conf\ +test_transport_api_wlan_peer1.conf\ +test_transport_api_wlan_peer2.conf\ +test_transport_defaults.conf\ +test_transport_startonly.conf\ +test_transport_api_disconnect_tcp_peer1.conf\ +test_transport_api_disconnect_tcp_peer2.conf\ +test_transport_api_http_nat_peer1.conf\ +test_transport_api_http_nat_peer2.conf\ +test_transport_api_https_nat_peer1.conf\ +test_transport_api_https_nat_peer2.conf\ +test_transport_api_reliability_http_nat_peer1.conf\ +test_transport_api_reliability_http_nat_peer2.conf\ +test_transport_api_reliability_https_nat_peer1.conf\ +test_transport_api_reliability_https_nat_peer2.conf\ +test_transport_api_timeout_http_peer1.conf\ +test_transport_api_timeout_http_peer2.conf\ +test_transport_api_timeout_https_peer1.conf\ +test_transport_api_timeout_https_peer2.conf\ +test_transport_api_unreliability_constant_udp_peer1.conf\ +test_transport_api_unreliability_constant_udp_peer2.conf diff --git a/src/transport/Makefile.in b/src/transport/Makefile.in new file mode 100644 index 0000000..36df686 --- /dev/null +++ b/src/transport/Makefile.in @@ -0,0 +1,2648 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +noinst_PROGRAMS = $(am__EXEEXT_21) $(am__EXEEXT_22) +bin_PROGRAMS = gnunet-transport$(EXEEXT) $(am__EXEEXT_1) \ + gnunet-service-transport$(EXEEXT) \ + gnunet-transport-certificate-creation$(EXEEXT) +check_PROGRAMS = test_transport_testing$(EXEEXT) \ + test_transport_startonly$(EXEEXT) \ + test_transport_api_blacklisting$(EXEEXT) \ + test_transport_api_disconnect_tcp$(EXEEXT) \ + test_transport_api_bidirectional_connect$(EXEEXT) \ + test_transport_api_tcp$(EXEEXT) \ + test_transport_api_restart_1peer$(EXEEXT) \ + test_transport_api_restart_2peers$(EXEEXT) \ + test_transport_api_timeout_tcp$(EXEEXT) \ + test_transport_api_limited_sockets_tcp$(EXEEXT) \ + test_transport_api_tcp_nat$(EXEEXT) \ + test_transport_api_udp$(EXEEXT) \ + test_transport_api_timeout_udp$(EXEEXT) $(am__EXEEXT_2) \ + $(am__EXEEXT_3) test_transport_api_udp_nat$(EXEEXT) \ + $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \ + $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \ + test_transport_api_multi$(EXEEXT) \ + test_transport_api_reliability_tcp$(EXEEXT) \ + test_transport_api_reliability_tcp_nat$(EXEEXT) \ + test_transport_api_unreliability_udp$(EXEEXT) \ + test_transport_api_unreliability_constant_udp$(EXEEXT) \ + $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \ + $(am__EXEEXT_13) $(am__EXEEXT_14) \ + test_quota_compliance_tcp$(EXEEXT) \ + test_quota_compliance_tcp_asymmetric$(EXEEXT) \ + test_quota_compliance_udp$(EXEEXT) $(am__EXEEXT_15) \ + $(am__EXEEXT_16) $(am__EXEEXT_17) $(am__EXEEXT_18) \ + $(am__EXEEXT_19) $(am__EXEEXT_20) +@ENABLE_TEST_RUN_TRUE@TESTS = test_transport_testing$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_startonly$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_blacklisting$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_disconnect_tcp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_bidirectional_connect$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_tcp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_restart_1peer$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_restart_2peers$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_timeout_tcp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_limited_sockets_tcp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_tcp_nat$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_udp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_timeout_udp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_2) $(am__EXEEXT_3) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_udp_nat$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_4) $(am__EXEEXT_5) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_6) $(am__EXEEXT_7) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_8) $(am__EXEEXT_9) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_multi$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_reliability_tcp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_reliability_tcp_nat$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_unreliability_udp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_transport_api_unreliability_constant_udp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_10) $(am__EXEEXT_11) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_12) $(am__EXEEXT_13) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_14) \ +@ENABLE_TEST_RUN_TRUE@ test_quota_compliance_tcp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_quota_compliance_tcp_asymmetric$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ test_quota_compliance_udp$(EXEEXT) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_15) $(am__EXEEXT_16) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_17) $(am__EXEEXT_18) \ +@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_19) $(am__EXEEXT_20) +subdir = src/transport +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/transport.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = transport.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) +libgnunet_plugin_transport_http_la_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunet_plugin_transport_http_la_OBJECTS = \ + libgnunet_plugin_transport_http_la-plugin_transport_http.lo \ + libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo \ + libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo +libgnunet_plugin_transport_http_la_OBJECTS = \ + $(am_libgnunet_plugin_transport_http_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_transport_http_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_transport_http_la_LDFLAGS) $(LDFLAGS) -o $@ +@HAVE_MHD_TRUE@am_libgnunet_plugin_transport_http_la_rpath = -rpath \ +@HAVE_MHD_TRUE@ $(plugindir) +libgnunet_plugin_transport_https_la_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunet_plugin_transport_https_la_OBJECTS = \ + libgnunet_plugin_transport_https_la-plugin_transport_http.lo \ + libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo \ + libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo +libgnunet_plugin_transport_https_la_OBJECTS = \ + $(am_libgnunet_plugin_transport_https_la_OBJECTS) +libgnunet_plugin_transport_https_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(libgnunet_plugin_transport_https_la_CFLAGS) \ + $(CFLAGS) $(libgnunet_plugin_transport_https_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@HAVE_MHD_TRUE@am_libgnunet_plugin_transport_https_la_rpath = -rpath \ +@HAVE_MHD_TRUE@ $(plugindir) +libgnunet_plugin_transport_tcp_la_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunet_plugin_transport_tcp_la_OBJECTS = \ + plugin_transport_tcp.lo +libgnunet_plugin_transport_tcp_la_OBJECTS = \ + $(am_libgnunet_plugin_transport_tcp_la_OBJECTS) +libgnunet_plugin_transport_tcp_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_transport_tcp_la_LDFLAGS) $(LDFLAGS) -o $@ +libgnunet_plugin_transport_template_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunet_plugin_transport_template_la_OBJECTS = \ + plugin_transport_template.lo +libgnunet_plugin_transport_template_la_OBJECTS = \ + $(am_libgnunet_plugin_transport_template_la_OBJECTS) +libgnunet_plugin_transport_template_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_transport_template_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +libgnunet_plugin_transport_udp_la_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunet_plugin_transport_udp_la_OBJECTS = \ + plugin_transport_udp.lo plugin_transport_udp_broadcasting.lo +libgnunet_plugin_transport_udp_la_OBJECTS = \ + $(am_libgnunet_plugin_transport_udp_la_OBJECTS) +libgnunet_plugin_transport_udp_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_transport_udp_la_LDFLAGS) $(LDFLAGS) -o $@ +libgnunet_plugin_transport_unix_la_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunet_plugin_transport_unix_la_OBJECTS = \ + plugin_transport_unix.lo +libgnunet_plugin_transport_unix_la_OBJECTS = \ + $(am_libgnunet_plugin_transport_unix_la_OBJECTS) +libgnunet_plugin_transport_unix_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_transport_unix_la_LDFLAGS) $(LDFLAGS) -o $@ +@MINGW_FALSE@am_libgnunet_plugin_transport_unix_la_rpath = -rpath \ +@MINGW_FALSE@ $(plugindir) +libgnunet_plugin_transport_wlan_la_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunet_plugin_transport_wlan_la_OBJECTS = \ + plugin_transport_wlan.lo +libgnunet_plugin_transport_wlan_la_OBJECTS = \ + $(am_libgnunet_plugin_transport_wlan_la_OBJECTS) +libgnunet_plugin_transport_wlan_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgnunet_plugin_transport_wlan_la_LDFLAGS) $(LDFLAGS) -o $@ +@LINUX_TRUE@am_libgnunet_plugin_transport_wlan_la_rpath = -rpath \ +@LINUX_TRUE@ $(plugindir) +am__DEPENDENCIES_1 = +libgnunettransport_la_DEPENDENCIES = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunettransport_la_OBJECTS = transport_api.lo \ + transport_api_blacklist.lo transport_api_address_to_string.lo \ + transport_api_address_lookup.lo +libgnunettransport_la_OBJECTS = $(am_libgnunettransport_la_OBJECTS) +libgnunettransport_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunettransport_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_libgnunettransporttesting_la_OBJECTS = transport-testing.lo +libgnunettransporttesting_la_OBJECTS = \ + $(am_libgnunettransporttesting_la_OBJECTS) +libgnunettransporttesting_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunettransporttesting_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-transport-wlan$(EXEEXT) +@MINGW_FALSE@am__EXEEXT_2 = test_transport_api_unix$(EXEEXT) +@MINGW_FALSE@am__EXEEXT_3 = test_transport_api_timeout_unix$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_4 = test_transport_api_http$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_5 = test_transport_api_http_nat$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_6 = \ +@HAVE_MHD_TRUE@ test_transport_api_timeout_http$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_7 = test_transport_api_https$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_8 = test_transport_api_https_nat$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_9 = \ +@HAVE_MHD_TRUE@ test_transport_api_timeout_https$(EXEEXT) +@MINGW_FALSE@am__EXEEXT_10 = \ +@MINGW_FALSE@ test_transport_api_unreliability_unix$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_11 = \ +@HAVE_MHD_TRUE@ test_transport_api_reliability_http$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_12 = test_transport_api_reliability_http_nat$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_13 = \ +@HAVE_MHD_TRUE@ test_transport_api_reliability_https$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_14 = test_transport_api_reliability_https_nat$(EXEEXT) +@MINGW_FALSE@am__EXEEXT_15 = test_quota_compliance_unix$(EXEEXT) \ +@MINGW_FALSE@ test_quota_compliance_unix_asymmetric$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_16 = test_quota_compliance_http$(EXEEXT) \ +@HAVE_MHD_TRUE@ test_quota_compliance_http_asymmetric$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_17 = test_quota_compliance_https$(EXEEXT) \ +@HAVE_MHD_TRUE@ test_quota_compliance_https_asymmetric$(EXEEXT) +@LINUX_TRUE@am__EXEEXT_18 = test_transport_api_wlan$(EXEEXT) +@LINUX_TRUE@am__EXEEXT_19 = \ +@LINUX_TRUE@ test_transport_api_reliability_wlan$(EXEEXT) +@LINUX_TRUE@am__EXEEXT_20 = \ +@LINUX_TRUE@ test_transport_api_unreliability_wlan$(EXEEXT) +@LINUX_TRUE@am__EXEEXT_21 = \ +@LINUX_TRUE@ gnunet-helper-transport-wlan-dummy$(EXEEXT) +@LINUX_TRUE@am__EXEEXT_22 = gnunet-transport-wlan-sender$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am_gnunet_helper_transport_wlan_OBJECTS = \ + gnunet-helper-transport-wlan.$(OBJEXT) +gnunet_helper_transport_wlan_OBJECTS = \ + $(am_gnunet_helper_transport_wlan_OBJECTS) +gnunet_helper_transport_wlan_LDADD = $(LDADD) +am_gnunet_helper_transport_wlan_dummy_OBJECTS = \ + gnunet-helper-transport-wlan-dummy.$(OBJEXT) +gnunet_helper_transport_wlan_dummy_OBJECTS = \ + $(am_gnunet_helper_transport_wlan_dummy_OBJECTS) +gnunet_helper_transport_wlan_dummy_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_gnunet_service_transport_OBJECTS = \ + gnunet-service-transport.$(OBJEXT) \ + gnunet-service-transport_blacklist.$(OBJEXT) \ + gnunet-service-transport_clients.$(OBJEXT) \ + gnunet-service-transport_hello.$(OBJEXT) \ + gnunet-service-transport_neighbours.$(OBJEXT) \ + gnunet-service-transport_plugins.$(OBJEXT) \ + gnunet-service-transport_validation.$(OBJEXT) +gnunet_service_transport_OBJECTS = \ + $(am_gnunet_service_transport_OBJECTS) +gnunet_service_transport_DEPENDENCIES = \ + $(top_builddir)/src/ats/libgnunetats.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_gnunet_transport_OBJECTS = gnunet-transport.$(OBJEXT) +gnunet_transport_OBJECTS = $(am_gnunet_transport_OBJECTS) +am_gnunet_transport_certificate_creation_OBJECTS = \ + gnunet-transport-certificate-creation.$(OBJEXT) +gnunet_transport_certificate_creation_OBJECTS = \ + $(am_gnunet_transport_certificate_creation_OBJECTS) +gnunet_transport_certificate_creation_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_gnunet_transport_wlan_sender_OBJECTS = \ + gnunet-transport-wlan-sender.$(OBJEXT) +gnunet_transport_wlan_sender_OBJECTS = \ + $(am_gnunet_transport_wlan_sender_OBJECTS) +gnunet_transport_wlan_sender_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_quota_compliance_http_OBJECTS = \ + test_quota_compliance.$(OBJEXT) +test_quota_compliance_http_OBJECTS = \ + $(am_test_quota_compliance_http_OBJECTS) +test_quota_compliance_http_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_quota_compliance_http_asymmetric_OBJECTS = \ + test_quota_compliance.$(OBJEXT) +test_quota_compliance_http_asymmetric_OBJECTS = \ + $(am_test_quota_compliance_http_asymmetric_OBJECTS) +test_quota_compliance_http_asymmetric_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_quota_compliance_https_OBJECTS = \ + test_quota_compliance.$(OBJEXT) +test_quota_compliance_https_OBJECTS = \ + $(am_test_quota_compliance_https_OBJECTS) +test_quota_compliance_https_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_quota_compliance_https_asymmetric_OBJECTS = \ + test_quota_compliance.$(OBJEXT) +test_quota_compliance_https_asymmetric_OBJECTS = \ + $(am_test_quota_compliance_https_asymmetric_OBJECTS) +test_quota_compliance_https_asymmetric_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_quota_compliance_tcp_OBJECTS = \ + test_quota_compliance.$(OBJEXT) +test_quota_compliance_tcp_OBJECTS = \ + $(am_test_quota_compliance_tcp_OBJECTS) +test_quota_compliance_tcp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_quota_compliance_tcp_asymmetric_OBJECTS = \ + test_quota_compliance.$(OBJEXT) +test_quota_compliance_tcp_asymmetric_OBJECTS = \ + $(am_test_quota_compliance_tcp_asymmetric_OBJECTS) +test_quota_compliance_tcp_asymmetric_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_quota_compliance_udp_OBJECTS = \ + test_quota_compliance.$(OBJEXT) +test_quota_compliance_udp_OBJECTS = \ + $(am_test_quota_compliance_udp_OBJECTS) +test_quota_compliance_udp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_quota_compliance_unix_OBJECTS = \ + test_quota_compliance.$(OBJEXT) +test_quota_compliance_unix_OBJECTS = \ + $(am_test_quota_compliance_unix_OBJECTS) +test_quota_compliance_unix_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_quota_compliance_unix_asymmetric_OBJECTS = \ + test_quota_compliance.$(OBJEXT) +test_quota_compliance_unix_asymmetric_OBJECTS = \ + $(am_test_quota_compliance_unix_asymmetric_OBJECTS) +test_quota_compliance_unix_asymmetric_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_bidirectional_connect_OBJECTS = \ + test_transport_api_bidirectional_connect.$(OBJEXT) +test_transport_api_bidirectional_connect_OBJECTS = \ + $(am_test_transport_api_bidirectional_connect_OBJECTS) +test_transport_api_bidirectional_connect_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_blacklisting_OBJECTS = \ + test_transport_api_blacklisting.$(OBJEXT) +test_transport_api_blacklisting_OBJECTS = \ + $(am_test_transport_api_blacklisting_OBJECTS) +test_transport_api_blacklisting_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_disconnect_tcp_OBJECTS = \ + test_transport_api_disconnect.$(OBJEXT) +test_transport_api_disconnect_tcp_OBJECTS = \ + $(am_test_transport_api_disconnect_tcp_OBJECTS) +test_transport_api_disconnect_tcp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_http_OBJECTS = test_transport_api.$(OBJEXT) +test_transport_api_http_OBJECTS = \ + $(am_test_transport_api_http_OBJECTS) +test_transport_api_http_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_http_nat_OBJECTS = test_transport_api.$(OBJEXT) +test_transport_api_http_nat_OBJECTS = \ + $(am_test_transport_api_http_nat_OBJECTS) +test_transport_api_http_nat_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_https_OBJECTS = test_transport_api.$(OBJEXT) +test_transport_api_https_OBJECTS = \ + $(am_test_transport_api_https_OBJECTS) +test_transport_api_https_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_https_nat_OBJECTS = \ + test_transport_api.$(OBJEXT) +test_transport_api_https_nat_OBJECTS = \ + $(am_test_transport_api_https_nat_OBJECTS) +test_transport_api_https_nat_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_limited_sockets_tcp_OBJECTS = \ + test_transport_api_limited_sockets.$(OBJEXT) +test_transport_api_limited_sockets_tcp_OBJECTS = \ + $(am_test_transport_api_limited_sockets_tcp_OBJECTS) +test_transport_api_limited_sockets_tcp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_multi_OBJECTS = test_transport_api.$(OBJEXT) +test_transport_api_multi_OBJECTS = \ + $(am_test_transport_api_multi_OBJECTS) +test_transport_api_multi_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_reliability_http_OBJECTS = \ + test_transport_api_reliability.$(OBJEXT) +test_transport_api_reliability_http_OBJECTS = \ + $(am_test_transport_api_reliability_http_OBJECTS) +test_transport_api_reliability_http_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_reliability_http_nat_OBJECTS = \ + test_transport_api_reliability.$(OBJEXT) +test_transport_api_reliability_http_nat_OBJECTS = \ + $(am_test_transport_api_reliability_http_nat_OBJECTS) +test_transport_api_reliability_http_nat_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_reliability_https_OBJECTS = \ + test_transport_api_reliability.$(OBJEXT) +test_transport_api_reliability_https_OBJECTS = \ + $(am_test_transport_api_reliability_https_OBJECTS) +test_transport_api_reliability_https_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_reliability_https_nat_OBJECTS = \ + test_transport_api_reliability.$(OBJEXT) +test_transport_api_reliability_https_nat_OBJECTS = \ + $(am_test_transport_api_reliability_https_nat_OBJECTS) +test_transport_api_reliability_https_nat_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_reliability_tcp_OBJECTS = \ + test_transport_api_reliability.$(OBJEXT) +test_transport_api_reliability_tcp_OBJECTS = \ + $(am_test_transport_api_reliability_tcp_OBJECTS) +test_transport_api_reliability_tcp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_reliability_tcp_nat_OBJECTS = \ + test_transport_api_reliability.$(OBJEXT) +test_transport_api_reliability_tcp_nat_OBJECTS = \ + $(am_test_transport_api_reliability_tcp_nat_OBJECTS) +test_transport_api_reliability_tcp_nat_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_reliability_wlan_OBJECTS = \ + test_transport_api_reliability.$(OBJEXT) +test_transport_api_reliability_wlan_OBJECTS = \ + $(am_test_transport_api_reliability_wlan_OBJECTS) +test_transport_api_reliability_wlan_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_restart_1peer_OBJECTS = \ + test_transport_api_restart_1peer.$(OBJEXT) +test_transport_api_restart_1peer_OBJECTS = \ + $(am_test_transport_api_restart_1peer_OBJECTS) +test_transport_api_restart_1peer_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_restart_2peers_OBJECTS = \ + test_transport_api_restart_2peers.$(OBJEXT) +test_transport_api_restart_2peers_OBJECTS = \ + $(am_test_transport_api_restart_2peers_OBJECTS) +test_transport_api_restart_2peers_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_tcp_OBJECTS = test_transport_api.$(OBJEXT) +test_transport_api_tcp_OBJECTS = $(am_test_transport_api_tcp_OBJECTS) +test_transport_api_tcp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_tcp_nat_OBJECTS = test_transport_api.$(OBJEXT) +test_transport_api_tcp_nat_OBJECTS = \ + $(am_test_transport_api_tcp_nat_OBJECTS) +test_transport_api_tcp_nat_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_timeout_http_OBJECTS = \ + test_transport_api_timeout.$(OBJEXT) +test_transport_api_timeout_http_OBJECTS = \ + $(am_test_transport_api_timeout_http_OBJECTS) +test_transport_api_timeout_http_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_timeout_https_OBJECTS = \ + test_transport_api_timeout.$(OBJEXT) +test_transport_api_timeout_https_OBJECTS = \ + $(am_test_transport_api_timeout_https_OBJECTS) +test_transport_api_timeout_https_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_timeout_tcp_OBJECTS = \ + test_transport_api_timeout.$(OBJEXT) +test_transport_api_timeout_tcp_OBJECTS = \ + $(am_test_transport_api_timeout_tcp_OBJECTS) +test_transport_api_timeout_tcp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_timeout_udp_OBJECTS = \ + test_transport_api_timeout.$(OBJEXT) +test_transport_api_timeout_udp_OBJECTS = \ + $(am_test_transport_api_timeout_udp_OBJECTS) +test_transport_api_timeout_udp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_timeout_unix_OBJECTS = \ + test_transport_api_timeout.$(OBJEXT) +test_transport_api_timeout_unix_OBJECTS = \ + $(am_test_transport_api_timeout_unix_OBJECTS) +test_transport_api_timeout_unix_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_udp_OBJECTS = test_transport_api.$(OBJEXT) +test_transport_api_udp_OBJECTS = $(am_test_transport_api_udp_OBJECTS) +test_transport_api_udp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_udp_nat_OBJECTS = test_transport_api.$(OBJEXT) +test_transport_api_udp_nat_OBJECTS = \ + $(am_test_transport_api_udp_nat_OBJECTS) +test_transport_api_udp_nat_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_unix_OBJECTS = test_transport_api.$(OBJEXT) +test_transport_api_unix_OBJECTS = \ + $(am_test_transport_api_unix_OBJECTS) +test_transport_api_unix_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_unreliability_constant_udp_OBJECTS = \ + test_transport_api_unreliability_constant.$(OBJEXT) +test_transport_api_unreliability_constant_udp_OBJECTS = \ + $(am_test_transport_api_unreliability_constant_udp_OBJECTS) +test_transport_api_unreliability_constant_udp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_unreliability_udp_OBJECTS = \ + test_transport_api_unreliability.$(OBJEXT) +test_transport_api_unreliability_udp_OBJECTS = \ + $(am_test_transport_api_unreliability_udp_OBJECTS) +test_transport_api_unreliability_udp_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_unreliability_unix_OBJECTS = \ + test_transport_api_unreliability.$(OBJEXT) +test_transport_api_unreliability_unix_OBJECTS = \ + $(am_test_transport_api_unreliability_unix_OBJECTS) +test_transport_api_unreliability_unix_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_api_unreliability_wlan_OBJECTS = \ + test_transport_api_unreliability.$(OBJEXT) +test_transport_api_unreliability_wlan_OBJECTS = \ + $(am_test_transport_api_unreliability_wlan_OBJECTS) +test_transport_api_unreliability_wlan_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am__test_transport_api_wlan_SOURCES_DIST = test_transport_api.c +@LINUX_TRUE@am_test_transport_api_wlan_OBJECTS = \ +@LINUX_TRUE@ test_transport_api.$(OBJEXT) +test_transport_api_wlan_OBJECTS = \ + $(am_test_transport_api_wlan_OBJECTS) +@LINUX_TRUE@test_transport_api_wlan_DEPENDENCIES = $(top_builddir)/src/transport/libgnunettransport.la \ +@LINUX_TRUE@ $(top_builddir)/src/hello/libgnunethello.la \ +@LINUX_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ +@LINUX_TRUE@ $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_startonly_OBJECTS = \ + test_transport_startonly.$(OBJEXT) +test_transport_startonly_OBJECTS = \ + $(am_test_transport_startonly_OBJECTS) +test_transport_startonly_DEPENDENCIES = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +am_test_transport_testing_OBJECTS = test_transport_testing.$(OBJEXT) +test_transport_testing_OBJECTS = $(am_test_transport_testing_OBJECTS) +test_transport_testing_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunet_plugin_transport_http_la_SOURCES) \ + $(libgnunet_plugin_transport_https_la_SOURCES) \ + $(libgnunet_plugin_transport_tcp_la_SOURCES) \ + $(libgnunet_plugin_transport_template_la_SOURCES) \ + $(libgnunet_plugin_transport_udp_la_SOURCES) \ + $(libgnunet_plugin_transport_unix_la_SOURCES) \ + $(libgnunet_plugin_transport_wlan_la_SOURCES) \ + $(libgnunettransport_la_SOURCES) \ + $(libgnunettransporttesting_la_SOURCES) \ + $(gnunet_helper_transport_wlan_SOURCES) \ + $(gnunet_helper_transport_wlan_dummy_SOURCES) \ + $(gnunet_service_transport_SOURCES) \ + $(gnunet_transport_SOURCES) \ + $(gnunet_transport_certificate_creation_SOURCES) \ + $(gnunet_transport_wlan_sender_SOURCES) \ + $(test_quota_compliance_http_SOURCES) \ + $(test_quota_compliance_http_asymmetric_SOURCES) \ + $(test_quota_compliance_https_SOURCES) \ + $(test_quota_compliance_https_asymmetric_SOURCES) \ + $(test_quota_compliance_tcp_SOURCES) \ + $(test_quota_compliance_tcp_asymmetric_SOURCES) \ + $(test_quota_compliance_udp_SOURCES) \ + $(test_quota_compliance_unix_SOURCES) \ + $(test_quota_compliance_unix_asymmetric_SOURCES) \ + $(test_transport_api_bidirectional_connect_SOURCES) \ + $(test_transport_api_blacklisting_SOURCES) \ + $(test_transport_api_disconnect_tcp_SOURCES) \ + $(test_transport_api_http_SOURCES) \ + $(test_transport_api_http_nat_SOURCES) \ + $(test_transport_api_https_SOURCES) \ + $(test_transport_api_https_nat_SOURCES) \ + $(test_transport_api_limited_sockets_tcp_SOURCES) \ + $(test_transport_api_multi_SOURCES) \ + $(test_transport_api_reliability_http_SOURCES) \ + $(test_transport_api_reliability_http_nat_SOURCES) \ + $(test_transport_api_reliability_https_SOURCES) \ + $(test_transport_api_reliability_https_nat_SOURCES) \ + $(test_transport_api_reliability_tcp_SOURCES) \ + $(test_transport_api_reliability_tcp_nat_SOURCES) \ + $(test_transport_api_reliability_wlan_SOURCES) \ + $(test_transport_api_restart_1peer_SOURCES) \ + $(test_transport_api_restart_2peers_SOURCES) \ + $(test_transport_api_tcp_SOURCES) \ + $(test_transport_api_tcp_nat_SOURCES) \ + $(test_transport_api_timeout_http_SOURCES) \ + $(test_transport_api_timeout_https_SOURCES) \ + $(test_transport_api_timeout_tcp_SOURCES) \ + $(test_transport_api_timeout_udp_SOURCES) \ + $(test_transport_api_timeout_unix_SOURCES) \ + $(test_transport_api_udp_SOURCES) \ + $(test_transport_api_udp_nat_SOURCES) \ + $(test_transport_api_unix_SOURCES) \ + $(test_transport_api_unreliability_constant_udp_SOURCES) \ + $(test_transport_api_unreliability_udp_SOURCES) \ + $(test_transport_api_unreliability_unix_SOURCES) \ + $(test_transport_api_unreliability_wlan_SOURCES) \ + $(test_transport_api_wlan_SOURCES) \ + $(test_transport_startonly_SOURCES) \ + $(test_transport_testing_SOURCES) +DIST_SOURCES = $(libgnunet_plugin_transport_http_la_SOURCES) \ + $(libgnunet_plugin_transport_https_la_SOURCES) \ + $(libgnunet_plugin_transport_tcp_la_SOURCES) \ + $(libgnunet_plugin_transport_template_la_SOURCES) \ + $(libgnunet_plugin_transport_udp_la_SOURCES) \ + $(libgnunet_plugin_transport_unix_la_SOURCES) \ + $(libgnunet_plugin_transport_wlan_la_SOURCES) \ + $(libgnunettransport_la_SOURCES) \ + $(libgnunettransporttesting_la_SOURCES) \ + $(gnunet_helper_transport_wlan_SOURCES) \ + $(gnunet_helper_transport_wlan_dummy_SOURCES) \ + $(gnunet_service_transport_SOURCES) \ + $(gnunet_transport_SOURCES) \ + $(gnunet_transport_certificate_creation_SOURCES) \ + $(gnunet_transport_wlan_sender_SOURCES) \ + $(test_quota_compliance_http_SOURCES) \ + $(test_quota_compliance_http_asymmetric_SOURCES) \ + $(test_quota_compliance_https_SOURCES) \ + $(test_quota_compliance_https_asymmetric_SOURCES) \ + $(test_quota_compliance_tcp_SOURCES) \ + $(test_quota_compliance_tcp_asymmetric_SOURCES) \ + $(test_quota_compliance_udp_SOURCES) \ + $(test_quota_compliance_unix_SOURCES) \ + $(test_quota_compliance_unix_asymmetric_SOURCES) \ + $(test_transport_api_bidirectional_connect_SOURCES) \ + $(test_transport_api_blacklisting_SOURCES) \ + $(test_transport_api_disconnect_tcp_SOURCES) \ + $(test_transport_api_http_SOURCES) \ + $(test_transport_api_http_nat_SOURCES) \ + $(test_transport_api_https_SOURCES) \ + $(test_transport_api_https_nat_SOURCES) \ + $(test_transport_api_limited_sockets_tcp_SOURCES) \ + $(test_transport_api_multi_SOURCES) \ + $(test_transport_api_reliability_http_SOURCES) \ + $(test_transport_api_reliability_http_nat_SOURCES) \ + $(test_transport_api_reliability_https_SOURCES) \ + $(test_transport_api_reliability_https_nat_SOURCES) \ + $(test_transport_api_reliability_tcp_SOURCES) \ + $(test_transport_api_reliability_tcp_nat_SOURCES) \ + $(test_transport_api_reliability_wlan_SOURCES) \ + $(test_transport_api_restart_1peer_SOURCES) \ + $(test_transport_api_restart_2peers_SOURCES) \ + $(test_transport_api_tcp_SOURCES) \ + $(test_transport_api_tcp_nat_SOURCES) \ + $(test_transport_api_timeout_http_SOURCES) \ + $(test_transport_api_timeout_https_SOURCES) \ + $(test_transport_api_timeout_tcp_SOURCES) \ + $(test_transport_api_timeout_udp_SOURCES) \ + $(test_transport_api_timeout_unix_SOURCES) \ + $(test_transport_api_udp_SOURCES) \ + $(test_transport_api_udp_nat_SOURCES) \ + $(test_transport_api_unix_SOURCES) \ + $(test_transport_api_unreliability_constant_udp_SOURCES) \ + $(test_transport_api_unreliability_udp_SOURCES) \ + $(test_transport_api_unreliability_unix_SOURCES) \ + $(test_transport_api_unreliability_wlan_SOURCES) \ + $(am__test_transport_api_wlan_SOURCES_DIST) \ + $(test_transport_startonly_SOURCES) \ + $(test_transport_testing_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include +plugindir = $(libdir)/gnunet +pkgcfgdir = $(pkgdatadir)/config.d/ +pkgcfg_DATA = \ + transport.conf + +@HAVE_MHD_TRUE@GN_LIBMHD = -lmicrohttpd +@HAVE_MHD_TRUE@HTTP_PLUGIN_LA = libgnunet_plugin_transport_http.la +@HAVE_MHD_TRUE@HTTP_API_TEST = test_transport_api_http +@HAVE_MHD_TRUE@HTTP_NAT_API_TEST = test_transport_api_http_nat +@HAVE_MHD_TRUE@HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http +@HAVE_MHD_TRUE@HTTP_REL_TEST = test_transport_api_reliability_http +@HAVE_MHD_TRUE@HTTP_NAT_REL_TEST = test_transport_api_reliability_http_nat +@HAVE_MHD_TRUE@HTTP_QUOTA_TEST = test_quota_compliance_http \ +@HAVE_MHD_TRUE@ test_quota_compliance_http_asymmetric + +@HAVE_MHD_TRUE@HTTPS_PLUGIN_LA = libgnunet_plugin_transport_https.la +@HAVE_MHD_TRUE@HTTPS_API_TEST = test_transport_api_https +@HAVE_MHD_TRUE@HTTPS_NAT_API_TEST = test_transport_api_https_nat +@HAVE_MHD_TRUE@HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https +@HAVE_MHD_TRUE@HTTPS_REL_TEST = test_transport_api_reliability_https +@HAVE_MHD_TRUE@HTTPS_NAT_REL_TEST = test_transport_api_reliability_https_nat +@HAVE_MHD_TRUE@HTTPS_QUOTA_TEST = test_quota_compliance_https \ +@HAVE_MHD_TRUE@ test_quota_compliance_https_asymmetric + +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@LINUX_TRUE@WLAN_BIN = gnunet-helper-transport-wlan +@LINUX_TRUE@WLAN_BIN_DUMMY = gnunet-helper-transport-wlan-dummy +@LINUX_TRUE@WLAN_BIN_SENDER = gnunet-transport-wlan-sender +@LINUX_TRUE@WLAN_PLUGIN_LA = libgnunet_plugin_transport_wlan.la +@LINUX_TRUE@WLAN_API_TEST = test_transport_api_wlan +@LINUX_TRUE@WLAN_REL_TEST = test_transport_api_reliability_wlan +@LINUX_TRUE@WLAN_UREL_TEST = test_transport_api_unreliability_wlan +@MINGW_FALSE@UNIX_PLUGIN_LA = libgnunet_plugin_transport_unix.la +@MINGW_FALSE@UNIX_PLUGIN_TEST = test_transport_api_unix +@MINGW_FALSE@UNIX_PLUGIN_TIMEOUT_TEST = test_transport_api_timeout_unix +@MINGW_FALSE@UNIX_REL_TEST = test_transport_api_unreliability_unix +@MINGW_FALSE@UNIX_QUOTA_TEST = test_quota_compliance_unix \ +@MINGW_FALSE@ test_quota_compliance_unix_asymmetric + +# gnunet-transport-connect-running-peers +lib_LTLIBRARIES = \ + libgnunettransport.la \ + libgnunettransporttesting.la + +libgnunettransporttesting_la_SOURCES = \ + transport-testing.c transport-testing.h + +libgnunettransporttesting_la_LIBADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +libgnunettransporttesting_la_DEPENDENCIES = \ + libgnunettransport.la + +libgnunettransporttesting_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) + +libgnunettransport_la_SOURCES = \ + transport_api.c transport.h \ + transport_api_blacklist.c \ + transport_api_address_to_string.c \ + transport_api_address_lookup.c + +libgnunettransport_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +libgnunettransport_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + + +#bin_SCRIPTS = \ +# gnunet-transport-certificate-creation +gnunet_transport_certificate_creation_SOURCES = \ + gnunet-transport-certificate-creation.c + +gnunet_transport_certificate_creation_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_helper_transport_wlan_SOURCES = \ + gnunet-helper-transport-wlan.c + +gnunet_helper_transport_wlan_dummy_SOURCES = \ + gnunet-helper-transport-wlan-dummy.c + +gnunet_helper_transport_wlan_dummy_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_transport_wlan_sender_SOURCES = \ + gnunet-transport-wlan-sender.c + +gnunet_transport_wlan_sender_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_transport_SOURCES = \ + gnunet-transport.c + +gnunet_transport_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_transport_DEPENDENCIES = \ + libgnunettransport.la + +gnunet_service_transport_SOURCES = \ + gnunet-service-transport.c gnunet-service-transport.h \ + gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \ + gnunet-service-transport_clients.h gnunet-service-transport_clients.c \ + gnunet-service-transport_hello.h gnunet-service-transport_hello.c \ + gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \ + gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \ + gnunet-service-transport_validation.h gnunet-service-transport_validation.c + +gnunet_service_transport_LDADD = \ + $(top_builddir)/src/ats/libgnunetats.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_GLPK) \ + $(GN_LIBINTL) + +plugin_LTLIBRARIES = \ + libgnunet_plugin_transport_tcp.la \ + libgnunet_plugin_transport_udp.la \ + $(UNIX_PLUGIN_LA) \ + $(HTTP_PLUGIN_LA) \ + $(HTTPS_PLUGIN_LA) \ + $(WLAN_PLUGIN_LA) \ + libgnunet_plugin_transport_template.la + +libgnunet_plugin_transport_tcp_la_SOURCES = \ + plugin_transport_tcp.c + +libgnunet_plugin_transport_tcp_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_transport_tcp_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_template_la_SOURCES = \ + plugin_transport_template.c + +libgnunet_plugin_transport_template_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_transport_template_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_wlan_la_SOURCES = \ + plugin_transport_wlan.c plugin_transport_wlan.h + +libgnunet_plugin_transport_wlan_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_transport_wlan_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_udp_la_SOURCES = \ + plugin_transport_udp.c plugin_transport_udp.h \ + plugin_transport_udp_broadcasting.c + +libgnunet_plugin_transport_udp_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_transport_udp_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_unix_la_SOURCES = \ + plugin_transport_unix.c + +libgnunet_plugin_transport_unix_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_transport_unix_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_http_la_SOURCES = \ + plugin_transport_http.c plugin_transport_http.h \ + plugin_transport_http_client.c plugin_transport_http_server.c + +libgnunet_plugin_transport_http_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + @LIBCURL@ \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_transport_http_la_LDFLAGS = \ + $(GN_LIBMHD) \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_http_la_CFLAGS = \ + $(CFLAGS) + +libgnunet_plugin_transport_http_la_CPPFLAGS = \ + @LIBCURL_CPPFLAGS@ + +libgnunet_plugin_transport_https_la_SOURCES = \ + plugin_transport_http.c plugin_transport_http.h \ + plugin_transport_http_client.c plugin_transport_http_server.c + +libgnunet_plugin_transport_https_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + @LIBCURL@ \ + $(top_builddir)/src/nat/libgnunetnat.la \ + $(top_builddir)/src/util/libgnunetutil.la + +libgnunet_plugin_transport_https_la_LDFLAGS = \ + $(GN_LIBMHD) \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_transport_https_la_CFLAGS = \ + $(CFLAGS) -DBUILD_HTTPS + +libgnunet_plugin_transport_https_la_CPPFLAGS = \ + @LIBCURL_CPPFLAGS@ + +test_transport_testing_SOURCES = \ + test_transport_testing.c + +test_transport_testing_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + + +#gnunet_transport_connect_running_peers_SOURCES = \ +# gnunet-transport-connect-running-peers.c +#gnunet_transport_connect_running_peers_LDADD = \ +# $(top_builddir)/src/transport/libgnunettransport.la \ +# $(top_builddir)/src/hello/libgnunethello.la \ +# $(top_builddir)/src/util/libgnunetutil.la \ +# $(top_builddir)/src/transport/libgnunettransporttesting.la +test_transport_api_blacklisting_SOURCES = \ + test_transport_api_blacklisting.c + +test_transport_api_blacklisting_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_disconnect_tcp_SOURCES = \ + test_transport_api_disconnect.c + +test_transport_api_disconnect_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_startonly_SOURCES = \ + test_transport_startonly.c + +test_transport_startonly_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_tcp_SOURCES = \ + test_transport_api.c + +test_transport_api_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_bidirectional_connect_SOURCES = \ + test_transport_api_bidirectional_connect.c + +test_transport_api_bidirectional_connect_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_restart_1peer_SOURCES = \ + test_transport_api_restart_1peer.c + +test_transport_api_restart_1peer_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_restart_2peers_SOURCES = \ + test_transport_api_restart_2peers.c + +test_transport_api_restart_2peers_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_limited_sockets_tcp_SOURCES = \ + test_transport_api_limited_sockets.c + +test_transport_api_limited_sockets_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_tcp_nat_SOURCES = \ + test_transport_api.c + +test_transport_api_tcp_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_tcp_SOURCES = \ + test_transport_api_reliability.c + +test_transport_api_reliability_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_timeout_tcp_SOURCES = \ + test_transport_api_timeout.c + +test_transport_api_timeout_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_timeout_unix_SOURCES = \ + test_transport_api_timeout.c + +test_transport_api_timeout_unix_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_timeout_http_SOURCES = \ + test_transport_api_timeout.c + +test_transport_api_timeout_http_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_timeout_https_SOURCES = \ + test_transport_api_timeout.c + +test_transport_api_timeout_https_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_tcp_nat_SOURCES = \ + test_transport_api_reliability.c + +test_transport_api_reliability_tcp_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_wlan_SOURCES = \ + test_transport_api_reliability.c + +test_transport_api_reliability_wlan_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_unreliability_wlan_SOURCES = \ + test_transport_api_unreliability.c + +test_transport_api_unreliability_wlan_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_udp_SOURCES = \ + test_transport_api.c + +test_transport_api_udp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_timeout_udp_SOURCES = \ + test_transport_api_timeout.c + +test_transport_api_timeout_udp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_udp_nat_SOURCES = \ + test_transport_api.c + +test_transport_api_udp_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_unix_SOURCES = \ + test_transport_api.c + +test_transport_api_unix_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_http_SOURCES = \ + test_transport_api.c + +test_transport_api_http_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_http_nat_SOURCES = \ + test_transport_api.c + +test_transport_api_http_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_http_SOURCES = \ + test_transport_api_reliability.c + +test_transport_api_reliability_http_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_http_nat_SOURCES = \ + test_transport_api_reliability.c + +test_transport_api_reliability_http_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_https_SOURCES = \ + test_transport_api.c + +test_transport_api_https_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_https_nat_SOURCES = \ + test_transport_api.c + +test_transport_api_https_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_https_SOURCES = \ + test_transport_api_reliability.c + +test_transport_api_reliability_https_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_reliability_https_nat_SOURCES = \ + test_transport_api_reliability.c + +test_transport_api_reliability_https_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_unreliability_unix_SOURCES = \ + test_transport_api_unreliability.c + +test_transport_api_unreliability_unix_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_unreliability_udp_SOURCES = \ + test_transport_api_unreliability.c + +test_transport_api_unreliability_udp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_unreliability_constant_udp_SOURCES = \ + test_transport_api_unreliability_constant.c + +test_transport_api_unreliability_constant_udp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +@LINUX_TRUE@test_transport_api_wlan_SOURCES = \ +@LINUX_TRUE@ test_transport_api.c + +@LINUX_TRUE@test_transport_api_wlan_LDADD = \ +@LINUX_TRUE@ $(top_builddir)/src/transport/libgnunettransport.la \ +@LINUX_TRUE@ $(top_builddir)/src/hello/libgnunethello.la \ +@LINUX_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ +@LINUX_TRUE@ $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_quota_compliance_tcp_SOURCES = \ + test_quota_compliance.c + +test_quota_compliance_tcp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_quota_compliance_tcp_asymmetric_SOURCES = \ + test_quota_compliance.c + +test_quota_compliance_tcp_asymmetric_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + + +#test_quota_compliance_tcp_asymmetric_send_constant_SOURCES = \ +# test_quota_compliance.c +#test_quota_compliance_tcp_asymmetric_send_constant_LDADD = \ +# $(top_builddir)/src/transport/libgnunettransport.la \ +# $(top_builddir)/src/util/libgnunetutil.la +test_quota_compliance_http_SOURCES = \ + test_quota_compliance.c + +test_quota_compliance_http_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_quota_compliance_http_asymmetric_SOURCES = \ + test_quota_compliance.c + +test_quota_compliance_http_asymmetric_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + + +#test_quota_compliance_http_asymmetric_send_constant_SOURCES = \ +# test_quota_compliance.c +#test_quota_compliance_http_asymmetric_send_constant_LDADD = \ +# $(top_builddir)/src/transport/libgnunettransport.la \ +# $(top_builddir)/src/util/libgnunetutil.la +test_quota_compliance_https_SOURCES = \ + test_quota_compliance.c + +test_quota_compliance_https_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_quota_compliance_https_asymmetric_SOURCES = \ + test_quota_compliance.c + +test_quota_compliance_https_asymmetric_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + + +#test_quota_compliance_https_asymmetric_send_constant_SOURCES = \ +# test_quota_compliance.c +#test_quota_compliance_https_asymmetric_send_constant_LDADD = \ +# $(top_builddir)/src/transport/libgnunettransport.la \ +# $(top_builddir)/src/util/libgnunetutil.la +test_quota_compliance_udp_SOURCES = \ + test_quota_compliance.c + +test_quota_compliance_udp_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_quota_compliance_unix_SOURCES = \ + test_quota_compliance.c + +test_quota_compliance_unix_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_quota_compliance_unix_asymmetric_SOURCES = \ + test_quota_compliance.c + +test_quota_compliance_unix_asymmetric_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +test_transport_api_multi_SOURCES = \ + test_transport_api.c + +test_transport_api_multi_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + +EXTRA_DIST = \ +gnunet-transport-certificate-creation \ +template_cfg_peer1.conf\ +template_cfg_peer2.conf\ +test_plugin_transport_data.conf\ +test_plugin_transport_data_udp.conf\ +test_quota_compliance_data.conf\ +test_quota_compliance_http_peer1.conf\ +test_quota_compliance_http_peer2.conf\ +test_quota_compliance_https_peer1.conf\ +test_quota_compliance_https_peer2.conf\ +test_quota_compliance_tcp_peer1.conf\ +test_quota_compliance_tcp_peer2.conf\ +test_quota_compliance_udp_peer1.conf\ +test_quota_compliance_udp_peer2.conf\ +test_quota_compliance_unix_peer1.conf\ +test_quota_compliance_unix_peer2.conf\ +test_quota_compliance_http_asymmetric_peer1.conf\ +test_quota_compliance_http_asymmetric_peer2.conf\ +test_quota_compliance_https_asymmetric_peer1.conf\ +test_quota_compliance_https_asymmetric_peer2.conf\ +test_quota_compliance_tcp_asymmetric_peer1.conf\ +test_quota_compliance_tcp_asymmetric_peer2.conf\ +test_quota_compliance_unix_asymmetric_peer1.conf\ +test_quota_compliance_unix_asymmetric_peer2.conf\ +test_transport_api_data.conf\ +test_transport_api_http_peer1.conf\ +test_transport_api_http_peer2.conf\ +test_transport_api_https_peer1.conf\ +test_transport_api_https_peer2.conf\ +test_transport_api_limited_sockets_tcp_peer1.conf\ +test_transport_api_limited_sockets_tcp_peer2.conf\ +test_transport_api_timeout_tcp_peer1.conf\ +test_transport_api_timeout_tcp_peer2.conf\ +test_transport_api_multi_peer1.conf\ +test_transport_api_multi_peer2.conf\ +test_transport_api_reliability_http_peer1.conf\ +test_transport_api_reliability_http_peer2.conf\ +test_transport_api_reliability_https_peer1.conf\ +test_transport_api_reliability_https_peer2.conf\ +test_transport_api_reliability_tcp_nat_peer1.conf\ +test_transport_api_reliability_tcp_nat_peer2.conf\ +test_transport_api_reliability_tcp_peer1.conf\ +test_transport_api_reliability_tcp_peer2.conf\ +test_transport_api_reliability_wlan_peer1.conf\ +test_transport_api_reliability_wlan_peer2.conf\ +test_transport_api_bidirectional_connect_peer1.conf\ +test_transport_api_bidirectional_connect_peer2.conf\ +test_transport_api_tcp_nat_peer1.conf\ +test_transport_api_tcp_nat_peer2.conf\ +test_transport_api_tcp_peer1.conf\ +test_transport_api_tcp_peer2.conf\ +test_transport_api_udp_nat_peer1.conf\ +test_transport_api_udp_nat_peer2.conf\ +test_transport_api_udp_peer1.conf\ +test_transport_api_udp_peer2.conf\ +test_transport_api_timeout_udp_peer1.conf\ +test_transport_api_timeout_udp_peer2.conf\ +test_transport_api_unix_peer1.conf\ +test_transport_api_unix_peer2.conf\ +test_transport_api_timeout_unix_peer1.conf\ +test_transport_api_timeout_unix_peer2.conf\ +test_transport_api_unreliability_udp_peer1.conf\ +test_transport_api_unreliability_udp_peer2.conf\ +test_transport_api_unreliability_unix_peer1.conf\ +test_transport_api_unreliability_unix_peer2.conf\ +test_transport_api_unreliability_wlan_peer1.conf\ +test_transport_api_unreliability_wlan_peer2.conf\ +test_transport_api_wlan_peer1.conf\ +test_transport_api_wlan_peer2.conf\ +test_transport_defaults.conf\ +test_transport_startonly.conf\ +test_transport_api_disconnect_tcp_peer1.conf\ +test_transport_api_disconnect_tcp_peer2.conf\ +test_transport_api_http_nat_peer1.conf\ +test_transport_api_http_nat_peer2.conf\ +test_transport_api_https_nat_peer1.conf\ +test_transport_api_https_nat_peer2.conf\ +test_transport_api_reliability_http_nat_peer1.conf\ +test_transport_api_reliability_http_nat_peer2.conf\ +test_transport_api_reliability_https_nat_peer1.conf\ +test_transport_api_reliability_https_nat_peer2.conf\ +test_transport_api_timeout_http_peer1.conf\ +test_transport_api_timeout_http_peer2.conf\ +test_transport_api_timeout_https_peer1.conf\ +test_transport_api_timeout_https_peer2.conf\ +test_transport_api_unreliability_constant_udp_peer1.conf\ +test_transport_api_unreliability_constant_udp_peer2.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/transport/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/transport/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +transport.conf: $(top_builddir)/config.status $(srcdir)/transport.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_transport_http.la: $(libgnunet_plugin_transport_http_la_OBJECTS) $(libgnunet_plugin_transport_http_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_transport_http_la_LINK) $(am_libgnunet_plugin_transport_http_la_rpath) $(libgnunet_plugin_transport_http_la_OBJECTS) $(libgnunet_plugin_transport_http_la_LIBADD) $(LIBS) +libgnunet_plugin_transport_https.la: $(libgnunet_plugin_transport_https_la_OBJECTS) $(libgnunet_plugin_transport_https_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_transport_https_la_LINK) $(am_libgnunet_plugin_transport_https_la_rpath) $(libgnunet_plugin_transport_https_la_OBJECTS) $(libgnunet_plugin_transport_https_la_LIBADD) $(LIBS) +libgnunet_plugin_transport_tcp.la: $(libgnunet_plugin_transport_tcp_la_OBJECTS) $(libgnunet_plugin_transport_tcp_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_transport_tcp_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_tcp_la_OBJECTS) $(libgnunet_plugin_transport_tcp_la_LIBADD) $(LIBS) +libgnunet_plugin_transport_template.la: $(libgnunet_plugin_transport_template_la_OBJECTS) $(libgnunet_plugin_transport_template_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_transport_template_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_template_la_OBJECTS) $(libgnunet_plugin_transport_template_la_LIBADD) $(LIBS) +libgnunet_plugin_transport_udp.la: $(libgnunet_plugin_transport_udp_la_OBJECTS) $(libgnunet_plugin_transport_udp_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_transport_udp_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_udp_la_OBJECTS) $(libgnunet_plugin_transport_udp_la_LIBADD) $(LIBS) +libgnunet_plugin_transport_unix.la: $(libgnunet_plugin_transport_unix_la_OBJECTS) $(libgnunet_plugin_transport_unix_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_transport_unix_la_LINK) $(am_libgnunet_plugin_transport_unix_la_rpath) $(libgnunet_plugin_transport_unix_la_OBJECTS) $(libgnunet_plugin_transport_unix_la_LIBADD) $(LIBS) +libgnunet_plugin_transport_wlan.la: $(libgnunet_plugin_transport_wlan_la_OBJECTS) $(libgnunet_plugin_transport_wlan_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_transport_wlan_la_LINK) $(am_libgnunet_plugin_transport_wlan_la_rpath) $(libgnunet_plugin_transport_wlan_la_OBJECTS) $(libgnunet_plugin_transport_wlan_la_LIBADD) $(LIBS) +libgnunettransport.la: $(libgnunettransport_la_OBJECTS) $(libgnunettransport_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunettransport_la_LINK) -rpath $(libdir) $(libgnunettransport_la_OBJECTS) $(libgnunettransport_la_LIBADD) $(LIBS) +libgnunettransporttesting.la: $(libgnunettransporttesting_la_OBJECTS) $(libgnunettransporttesting_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunettransporttesting_la_LINK) -rpath $(libdir) $(libgnunettransporttesting_la_OBJECTS) $(libgnunettransporttesting_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-helper-transport-wlan$(EXEEXT): $(gnunet_helper_transport_wlan_OBJECTS) $(gnunet_helper_transport_wlan_DEPENDENCIES) + @rm -f gnunet-helper-transport-wlan$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_helper_transport_wlan_OBJECTS) $(gnunet_helper_transport_wlan_LDADD) $(LIBS) +gnunet-helper-transport-wlan-dummy$(EXEEXT): $(gnunet_helper_transport_wlan_dummy_OBJECTS) $(gnunet_helper_transport_wlan_dummy_DEPENDENCIES) + @rm -f gnunet-helper-transport-wlan-dummy$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_helper_transport_wlan_dummy_OBJECTS) $(gnunet_helper_transport_wlan_dummy_LDADD) $(LIBS) +gnunet-service-transport$(EXEEXT): $(gnunet_service_transport_OBJECTS) $(gnunet_service_transport_DEPENDENCIES) + @rm -f gnunet-service-transport$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_transport_OBJECTS) $(gnunet_service_transport_LDADD) $(LIBS) +gnunet-transport$(EXEEXT): $(gnunet_transport_OBJECTS) $(gnunet_transport_DEPENDENCIES) + @rm -f gnunet-transport$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_transport_OBJECTS) $(gnunet_transport_LDADD) $(LIBS) +gnunet-transport-certificate-creation$(EXEEXT): $(gnunet_transport_certificate_creation_OBJECTS) $(gnunet_transport_certificate_creation_DEPENDENCIES) + @rm -f gnunet-transport-certificate-creation$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_transport_certificate_creation_OBJECTS) $(gnunet_transport_certificate_creation_LDADD) $(LIBS) +gnunet-transport-wlan-sender$(EXEEXT): $(gnunet_transport_wlan_sender_OBJECTS) $(gnunet_transport_wlan_sender_DEPENDENCIES) + @rm -f gnunet-transport-wlan-sender$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_transport_wlan_sender_OBJECTS) $(gnunet_transport_wlan_sender_LDADD) $(LIBS) +test_quota_compliance_http$(EXEEXT): $(test_quota_compliance_http_OBJECTS) $(test_quota_compliance_http_DEPENDENCIES) + @rm -f test_quota_compliance_http$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_quota_compliance_http_OBJECTS) $(test_quota_compliance_http_LDADD) $(LIBS) +test_quota_compliance_http_asymmetric$(EXEEXT): $(test_quota_compliance_http_asymmetric_OBJECTS) $(test_quota_compliance_http_asymmetric_DEPENDENCIES) + @rm -f test_quota_compliance_http_asymmetric$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_quota_compliance_http_asymmetric_OBJECTS) $(test_quota_compliance_http_asymmetric_LDADD) $(LIBS) +test_quota_compliance_https$(EXEEXT): $(test_quota_compliance_https_OBJECTS) $(test_quota_compliance_https_DEPENDENCIES) + @rm -f test_quota_compliance_https$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_quota_compliance_https_OBJECTS) $(test_quota_compliance_https_LDADD) $(LIBS) +test_quota_compliance_https_asymmetric$(EXEEXT): $(test_quota_compliance_https_asymmetric_OBJECTS) $(test_quota_compliance_https_asymmetric_DEPENDENCIES) + @rm -f test_quota_compliance_https_asymmetric$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_quota_compliance_https_asymmetric_OBJECTS) $(test_quota_compliance_https_asymmetric_LDADD) $(LIBS) +test_quota_compliance_tcp$(EXEEXT): $(test_quota_compliance_tcp_OBJECTS) $(test_quota_compliance_tcp_DEPENDENCIES) + @rm -f test_quota_compliance_tcp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_quota_compliance_tcp_OBJECTS) $(test_quota_compliance_tcp_LDADD) $(LIBS) +test_quota_compliance_tcp_asymmetric$(EXEEXT): $(test_quota_compliance_tcp_asymmetric_OBJECTS) $(test_quota_compliance_tcp_asymmetric_DEPENDENCIES) + @rm -f test_quota_compliance_tcp_asymmetric$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_quota_compliance_tcp_asymmetric_OBJECTS) $(test_quota_compliance_tcp_asymmetric_LDADD) $(LIBS) +test_quota_compliance_udp$(EXEEXT): $(test_quota_compliance_udp_OBJECTS) $(test_quota_compliance_udp_DEPENDENCIES) + @rm -f test_quota_compliance_udp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_quota_compliance_udp_OBJECTS) $(test_quota_compliance_udp_LDADD) $(LIBS) +test_quota_compliance_unix$(EXEEXT): $(test_quota_compliance_unix_OBJECTS) $(test_quota_compliance_unix_DEPENDENCIES) + @rm -f test_quota_compliance_unix$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_quota_compliance_unix_OBJECTS) $(test_quota_compliance_unix_LDADD) $(LIBS) +test_quota_compliance_unix_asymmetric$(EXEEXT): $(test_quota_compliance_unix_asymmetric_OBJECTS) $(test_quota_compliance_unix_asymmetric_DEPENDENCIES) + @rm -f test_quota_compliance_unix_asymmetric$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_quota_compliance_unix_asymmetric_OBJECTS) $(test_quota_compliance_unix_asymmetric_LDADD) $(LIBS) +test_transport_api_bidirectional_connect$(EXEEXT): $(test_transport_api_bidirectional_connect_OBJECTS) $(test_transport_api_bidirectional_connect_DEPENDENCIES) + @rm -f test_transport_api_bidirectional_connect$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_bidirectional_connect_OBJECTS) $(test_transport_api_bidirectional_connect_LDADD) $(LIBS) +test_transport_api_blacklisting$(EXEEXT): $(test_transport_api_blacklisting_OBJECTS) $(test_transport_api_blacklisting_DEPENDENCIES) + @rm -f test_transport_api_blacklisting$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_blacklisting_OBJECTS) $(test_transport_api_blacklisting_LDADD) $(LIBS) +test_transport_api_disconnect_tcp$(EXEEXT): $(test_transport_api_disconnect_tcp_OBJECTS) $(test_transport_api_disconnect_tcp_DEPENDENCIES) + @rm -f test_transport_api_disconnect_tcp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_disconnect_tcp_OBJECTS) $(test_transport_api_disconnect_tcp_LDADD) $(LIBS) +test_transport_api_http$(EXEEXT): $(test_transport_api_http_OBJECTS) $(test_transport_api_http_DEPENDENCIES) + @rm -f test_transport_api_http$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_http_OBJECTS) $(test_transport_api_http_LDADD) $(LIBS) +test_transport_api_http_nat$(EXEEXT): $(test_transport_api_http_nat_OBJECTS) $(test_transport_api_http_nat_DEPENDENCIES) + @rm -f test_transport_api_http_nat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_http_nat_OBJECTS) $(test_transport_api_http_nat_LDADD) $(LIBS) +test_transport_api_https$(EXEEXT): $(test_transport_api_https_OBJECTS) $(test_transport_api_https_DEPENDENCIES) + @rm -f test_transport_api_https$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_https_OBJECTS) $(test_transport_api_https_LDADD) $(LIBS) +test_transport_api_https_nat$(EXEEXT): $(test_transport_api_https_nat_OBJECTS) $(test_transport_api_https_nat_DEPENDENCIES) + @rm -f test_transport_api_https_nat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_https_nat_OBJECTS) $(test_transport_api_https_nat_LDADD) $(LIBS) +test_transport_api_limited_sockets_tcp$(EXEEXT): $(test_transport_api_limited_sockets_tcp_OBJECTS) $(test_transport_api_limited_sockets_tcp_DEPENDENCIES) + @rm -f test_transport_api_limited_sockets_tcp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_limited_sockets_tcp_OBJECTS) $(test_transport_api_limited_sockets_tcp_LDADD) $(LIBS) +test_transport_api_multi$(EXEEXT): $(test_transport_api_multi_OBJECTS) $(test_transport_api_multi_DEPENDENCIES) + @rm -f test_transport_api_multi$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_multi_OBJECTS) $(test_transport_api_multi_LDADD) $(LIBS) +test_transport_api_reliability_http$(EXEEXT): $(test_transport_api_reliability_http_OBJECTS) $(test_transport_api_reliability_http_DEPENDENCIES) + @rm -f test_transport_api_reliability_http$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_http_OBJECTS) $(test_transport_api_reliability_http_LDADD) $(LIBS) +test_transport_api_reliability_http_nat$(EXEEXT): $(test_transport_api_reliability_http_nat_OBJECTS) $(test_transport_api_reliability_http_nat_DEPENDENCIES) + @rm -f test_transport_api_reliability_http_nat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_http_nat_OBJECTS) $(test_transport_api_reliability_http_nat_LDADD) $(LIBS) +test_transport_api_reliability_https$(EXEEXT): $(test_transport_api_reliability_https_OBJECTS) $(test_transport_api_reliability_https_DEPENDENCIES) + @rm -f test_transport_api_reliability_https$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_https_OBJECTS) $(test_transport_api_reliability_https_LDADD) $(LIBS) +test_transport_api_reliability_https_nat$(EXEEXT): $(test_transport_api_reliability_https_nat_OBJECTS) $(test_transport_api_reliability_https_nat_DEPENDENCIES) + @rm -f test_transport_api_reliability_https_nat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_https_nat_OBJECTS) $(test_transport_api_reliability_https_nat_LDADD) $(LIBS) +test_transport_api_reliability_tcp$(EXEEXT): $(test_transport_api_reliability_tcp_OBJECTS) $(test_transport_api_reliability_tcp_DEPENDENCIES) + @rm -f test_transport_api_reliability_tcp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_tcp_OBJECTS) $(test_transport_api_reliability_tcp_LDADD) $(LIBS) +test_transport_api_reliability_tcp_nat$(EXEEXT): $(test_transport_api_reliability_tcp_nat_OBJECTS) $(test_transport_api_reliability_tcp_nat_DEPENDENCIES) + @rm -f test_transport_api_reliability_tcp_nat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_tcp_nat_OBJECTS) $(test_transport_api_reliability_tcp_nat_LDADD) $(LIBS) +test_transport_api_reliability_wlan$(EXEEXT): $(test_transport_api_reliability_wlan_OBJECTS) $(test_transport_api_reliability_wlan_DEPENDENCIES) + @rm -f test_transport_api_reliability_wlan$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_wlan_OBJECTS) $(test_transport_api_reliability_wlan_LDADD) $(LIBS) +test_transport_api_restart_1peer$(EXEEXT): $(test_transport_api_restart_1peer_OBJECTS) $(test_transport_api_restart_1peer_DEPENDENCIES) + @rm -f test_transport_api_restart_1peer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_restart_1peer_OBJECTS) $(test_transport_api_restart_1peer_LDADD) $(LIBS) +test_transport_api_restart_2peers$(EXEEXT): $(test_transport_api_restart_2peers_OBJECTS) $(test_transport_api_restart_2peers_DEPENDENCIES) + @rm -f test_transport_api_restart_2peers$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_restart_2peers_OBJECTS) $(test_transport_api_restart_2peers_LDADD) $(LIBS) +test_transport_api_tcp$(EXEEXT): $(test_transport_api_tcp_OBJECTS) $(test_transport_api_tcp_DEPENDENCIES) + @rm -f test_transport_api_tcp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_tcp_OBJECTS) $(test_transport_api_tcp_LDADD) $(LIBS) +test_transport_api_tcp_nat$(EXEEXT): $(test_transport_api_tcp_nat_OBJECTS) $(test_transport_api_tcp_nat_DEPENDENCIES) + @rm -f test_transport_api_tcp_nat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_tcp_nat_OBJECTS) $(test_transport_api_tcp_nat_LDADD) $(LIBS) +test_transport_api_timeout_http$(EXEEXT): $(test_transport_api_timeout_http_OBJECTS) $(test_transport_api_timeout_http_DEPENDENCIES) + @rm -f test_transport_api_timeout_http$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_http_OBJECTS) $(test_transport_api_timeout_http_LDADD) $(LIBS) +test_transport_api_timeout_https$(EXEEXT): $(test_transport_api_timeout_https_OBJECTS) $(test_transport_api_timeout_https_DEPENDENCIES) + @rm -f test_transport_api_timeout_https$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_https_OBJECTS) $(test_transport_api_timeout_https_LDADD) $(LIBS) +test_transport_api_timeout_tcp$(EXEEXT): $(test_transport_api_timeout_tcp_OBJECTS) $(test_transport_api_timeout_tcp_DEPENDENCIES) + @rm -f test_transport_api_timeout_tcp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_tcp_OBJECTS) $(test_transport_api_timeout_tcp_LDADD) $(LIBS) +test_transport_api_timeout_udp$(EXEEXT): $(test_transport_api_timeout_udp_OBJECTS) $(test_transport_api_timeout_udp_DEPENDENCIES) + @rm -f test_transport_api_timeout_udp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_udp_OBJECTS) $(test_transport_api_timeout_udp_LDADD) $(LIBS) +test_transport_api_timeout_unix$(EXEEXT): $(test_transport_api_timeout_unix_OBJECTS) $(test_transport_api_timeout_unix_DEPENDENCIES) + @rm -f test_transport_api_timeout_unix$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_unix_OBJECTS) $(test_transport_api_timeout_unix_LDADD) $(LIBS) +test_transport_api_udp$(EXEEXT): $(test_transport_api_udp_OBJECTS) $(test_transport_api_udp_DEPENDENCIES) + @rm -f test_transport_api_udp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_udp_OBJECTS) $(test_transport_api_udp_LDADD) $(LIBS) +test_transport_api_udp_nat$(EXEEXT): $(test_transport_api_udp_nat_OBJECTS) $(test_transport_api_udp_nat_DEPENDENCIES) + @rm -f test_transport_api_udp_nat$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_udp_nat_OBJECTS) $(test_transport_api_udp_nat_LDADD) $(LIBS) +test_transport_api_unix$(EXEEXT): $(test_transport_api_unix_OBJECTS) $(test_transport_api_unix_DEPENDENCIES) + @rm -f test_transport_api_unix$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_unix_OBJECTS) $(test_transport_api_unix_LDADD) $(LIBS) +test_transport_api_unreliability_constant_udp$(EXEEXT): $(test_transport_api_unreliability_constant_udp_OBJECTS) $(test_transport_api_unreliability_constant_udp_DEPENDENCIES) + @rm -f test_transport_api_unreliability_constant_udp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_constant_udp_OBJECTS) $(test_transport_api_unreliability_constant_udp_LDADD) $(LIBS) +test_transport_api_unreliability_udp$(EXEEXT): $(test_transport_api_unreliability_udp_OBJECTS) $(test_transport_api_unreliability_udp_DEPENDENCIES) + @rm -f test_transport_api_unreliability_udp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_udp_OBJECTS) $(test_transport_api_unreliability_udp_LDADD) $(LIBS) +test_transport_api_unreliability_unix$(EXEEXT): $(test_transport_api_unreliability_unix_OBJECTS) $(test_transport_api_unreliability_unix_DEPENDENCIES) + @rm -f test_transport_api_unreliability_unix$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_unix_OBJECTS) $(test_transport_api_unreliability_unix_LDADD) $(LIBS) +test_transport_api_unreliability_wlan$(EXEEXT): $(test_transport_api_unreliability_wlan_OBJECTS) $(test_transport_api_unreliability_wlan_DEPENDENCIES) + @rm -f test_transport_api_unreliability_wlan$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_wlan_OBJECTS) $(test_transport_api_unreliability_wlan_LDADD) $(LIBS) +test_transport_api_wlan$(EXEEXT): $(test_transport_api_wlan_OBJECTS) $(test_transport_api_wlan_DEPENDENCIES) + @rm -f test_transport_api_wlan$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_api_wlan_OBJECTS) $(test_transport_api_wlan_LDADD) $(LIBS) +test_transport_startonly$(EXEEXT): $(test_transport_startonly_OBJECTS) $(test_transport_startonly_DEPENDENCIES) + @rm -f test_transport_startonly$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_startonly_OBJECTS) $(test_transport_startonly_LDADD) $(LIBS) +test_transport_testing$(EXEEXT): $(test_transport_testing_OBJECTS) $(test_transport_testing_DEPENDENCIES) + @rm -f test_transport_testing$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_transport_testing_OBJECTS) $(test_transport_testing_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-transport-wlan-dummy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-transport-wlan.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_blacklist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_clients.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_hello.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_neighbours.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_plugins.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_validation.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-transport-certificate-creation.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-transport-wlan-sender.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-transport.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_tcp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_template.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_udp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_udp_broadcasting.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_wlan.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_quota_compliance.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_bidirectional_connect.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_blacklisting.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_disconnect.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_limited_sockets.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_reliability.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_restart_1peer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_restart_2peers.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_timeout.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_unreliability.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_unreliability_constant.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_startonly.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_testing.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport-testing.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api_address_lookup.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api_address_to_string.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api_blacklist.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libgnunet_plugin_transport_http_la-plugin_transport_http.lo: plugin_transport_http.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_http_la-plugin_transport_http.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Tpo -c -o libgnunet_plugin_transport_http_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Tpo $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http.c' object='libgnunet_plugin_transport_http_la-plugin_transport_http.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_http_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c + +libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo: plugin_transport_http_client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Tpo -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Tpo $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_client.c' object='libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c + +libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo: plugin_transport_http_server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Tpo -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Tpo $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_server.c' object='libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c + +libgnunet_plugin_transport_https_la-plugin_transport_http.lo: plugin_transport_http.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_https_la-plugin_transport_http.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Tpo -c -o libgnunet_plugin_transport_https_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Tpo $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http.c' object='libgnunet_plugin_transport_https_la-plugin_transport_http.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_https_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c + +libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo: plugin_transport_http_client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Tpo -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Tpo $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_client.c' object='libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c + +libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo: plugin_transport_http_server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Tpo -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Tpo $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_server.c' object='libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS \ + clean-pluginLTLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-exec-hook \ + install-html install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-pkgcfgDATA install-pluginLTLIBRARIES install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + + +@LINUX_TRUE@install-exec-hook: +@LINUX_TRUE@ $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-transport-wlan || true +@LINUX_TRUE@ $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-transport-wlan || true +@LINUX_FALSE@install-exec-hook: + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/transport/gnunet-helper-transport-wlan-dummy.c b/src/transport/gnunet-helper-transport-wlan-dummy.c new file mode 100644 index 0000000..6fff758 --- /dev/null +++ b/src/transport/gnunet-helper-transport-wlan-dummy.c @@ -0,0 +1,439 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ +/** + * @file transport/gnunet-helper-transport-wlan-dummy.c + * @brief helper for the testcases for plugin_transport_wlan.c + * @author David Brodski + */ +#include "platform.h" +#include "gnunet_protocols.h" +#include "gnunet_util_lib.h" +#include "plugin_transport_wlan.h" + +#define FIFO_FILE1 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_in" +#define FIFO_FILE2 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_out" + +#define MAXLINE 4096 + +struct sendbuf +{ + unsigned int pos; + unsigned int size; + char buf[MAXLINE * 2]; +}; + +static int first; + +static int closeprog; + +static void +sigfunc (int sig) +{ + closeprog = 1; + (void) unlink (FIFO_FILE1); + (void) unlink (FIFO_FILE2); +} + + +/** + * function to create GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL message for plugin + * @param buffer pointer to buffer for the message + * @param mac pointer to the mac address + * @return number of bytes written + */ +static int +send_mac_to_plugin (char *buffer, struct GNUNET_TRANSPORT_WLAN_MacAddress *mac) +{ + + struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg; + + memcpy (&macmsg.mac, (char *) mac, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); + macmsg.hdr.size = htons (sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)); + macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL); + + memcpy (buffer, &macmsg, sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)); + return sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage); +} + +static void +stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) +{ + struct sendbuf *write_pout = cls; + int sendsize; + struct GNUNET_MessageHeader newheader; + char *to_data; + char *to_radiotap; + char *to_start; + + sendsize = + ntohs (hdr->size) - sizeof (struct Radiotap_Send) + + sizeof (struct Radiotap_rx); + + if (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA != ntohs (hdr->type)) + { + fprintf (stderr, "Function stdin_send: wrong packet type\n"); + exit (1); + } + if ((sendsize + write_pout->size) > MAXLINE * 2) + { + fprintf (stderr, "Function stdin_send: Packet too big for buffer\n"); + exit (1); + } + + newheader.size = htons (sendsize); + newheader.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); + + to_start = write_pout->buf + write_pout->size; + memcpy (to_start, &newheader, sizeof (struct GNUNET_MessageHeader)); + write_pout->size += sizeof (struct GNUNET_MessageHeader); + + to_radiotap = to_start + sizeof (struct GNUNET_MessageHeader); + memset (to_radiotap, 0, sizeof (struct Radiotap_rx)); + write_pout->size += sizeof (struct Radiotap_rx); + + to_data = to_radiotap + sizeof (struct Radiotap_rx); + memcpy (to_data, + ((char *) hdr) + sizeof (struct Radiotap_Send) + + sizeof (struct GNUNET_MessageHeader), + ntohs (hdr->size) - sizeof (struct Radiotap_Send) - + sizeof (struct GNUNET_MessageHeader)); + write_pout->size += + ntohs (hdr->size) - sizeof (struct Radiotap_Send) - + sizeof (struct GNUNET_MessageHeader); +} + + +static void +file_in_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) +{ + struct sendbuf *write_std = cls; + uint16_t sendsize; + + sendsize = ntohs (hdr->size); + + if (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA != ntohs (hdr->type)) + { + fprintf (stderr, "Function file_in_send: wrong packet type\n"); + exit (1); + } + if ((sendsize + write_std->size) > MAXLINE * 2) + { + fprintf (stderr, "Function file_in_send: Packet too big for buffer\n"); + exit (1); + } + + memcpy (write_std->buf + write_std->size, hdr, sendsize); + write_std->size += sendsize; +} + + +int +main (int argc, char *argv[]) +{ + struct stat st; + int erg; + FILE *fpin = NULL; + FILE *fpout = NULL; + int fdpin; + int fdpout; + char readbuf[MAXLINE]; + int readsize = 0; + struct sendbuf write_std; + struct sendbuf write_pout; + int ret = 0; + int maxfd = 0; + fd_set rfds; + fd_set wfds; + struct timeval tv; + int retval; + struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst; + struct GNUNET_SERVER_MessageStreamTokenizer *file_in_mst; + struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr; + + if (2 != argc) + { + fprintf (stderr, + "This program must be started with the operating mode (1 or 2) as the only argument.\n"); + return 1; + } + if ((0 != strstr (argv[1], "1")) && (0 != strstr (argv[1], "2"))) + return 1; + + //make the fifos if needed + if (0 != stat (FIFO_FILE1, &st)) + { + if (0 == stat (FIFO_FILE2, &st)) + { + fprintf (stderr, "FIFO_FILE2 exists, but FIFO_FILE1 not\n"); + exit (1); + } + umask (0); + erg = mkfifo (FIFO_FILE1, 0666); + if (0 != erg) + { + fprintf (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE1, + strerror (errno)); + //exit(1); + } + erg = mkfifo (FIFO_FILE2, 0666); + if (0 != erg) + { + fprintf (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE2, + strerror (errno)); + //exit(1); + } + + } + else + { + if (0 != stat (FIFO_FILE2, &st)) + { + fprintf (stderr, "FIFO_FILE1 exists, but FIFO_FILE2 not\n"); + exit (1); + } + } + + if (strstr (argv[1], "1")) + { + //fprintf(stderr, "First\n"); + first = 1; + fpin = fopen (FIFO_FILE1, "r"); + if (NULL == fpin) + { + fprintf (stderr, "fopen of read FIFO_FILE1\n"); + goto end; + } + fpout = fopen (FIFO_FILE2, "w"); + if (NULL == fpout) + { + fprintf (stderr, "fopen of write FIFO_FILE2\n"); + goto end; + } + + } + else + { + first = 0; + //fprintf(stderr, "Second\n"); + fpout = fopen (FIFO_FILE1, "w"); + if (NULL == fpout) + { + fprintf (stderr, "fopen of write FIFO_FILE1\n"); + goto end; + } + fpin = fopen (FIFO_FILE2, "r"); + if (NULL == fpin) + { + fprintf (stderr, "fopen of read FIFO_FILE2\n"); + goto end; + } + + } + + fdpin = fileno (fpin); + GNUNET_assert (fpin >= 0); + + if (fdpin >= FD_SETSIZE) + { + fprintf (stderr, "File fdpin number too large (%d > %u)\n", fdpin, + (unsigned int) FD_SETSIZE); + goto end; + } + + fdpout = fileno (fpout); + GNUNET_assert (fdpout >= 0); + + if (fdpout >= FD_SETSIZE) + { + fprintf (stderr, "File fdpout number too large (%d > %u)\n", fdpout, + (unsigned int) FD_SETSIZE); + goto end; + + } + + signal (SIGINT, &sigfunc); + signal (SIGTERM, &sigfunc); + + write_std.size = 0; + write_std.pos = 0; + write_pout.size = 0; + write_pout.pos = 0; + stdin_mst = GNUNET_SERVER_mst_create (&stdin_send, &write_pout); + file_in_mst = GNUNET_SERVER_mst_create (&file_in_send, &write_std); + + //Send random mac address + macaddr.mac[0] = 0x13; + macaddr.mac[1] = 0x22; + macaddr.mac[2] = 0x33; + macaddr.mac[3] = 0x44; + macaddr.mac[4] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 256); + macaddr.mac[5] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 256); + write_std.size = send_mac_to_plugin (write_std.buf, &macaddr); + + while (0 == closeprog) + { + maxfd = -1; + //set timeout + tv.tv_sec = 5; + tv.tv_usec = 0; + + FD_ZERO (&rfds); + // if output queue is empty + if (0 == write_pout.size) + { + FD_SET (STDIN_FILENO, &rfds); + maxfd = MAX (STDIN_FILENO, maxfd); + } + if (0 == write_std.size) + { + FD_SET (fdpin, &rfds); + maxfd = MAX (fdpin, maxfd); + } + FD_ZERO (&wfds); + // if there is something to write + if (0 < write_std.size) + { + FD_SET (STDOUT_FILENO, &wfds); + maxfd = MAX (maxfd, STDOUT_FILENO); + } + if (0 < write_pout.size) + { + FD_SET (fdpout, &wfds); + maxfd = MAX (maxfd, fdpout); + } + + retval = select (maxfd + 1, &rfds, &wfds, NULL, &tv); + if ((-1 == retval) && (EINTR == errno)) + continue; + if (0 > retval) + { + fprintf (stderr, "select failed: %s\n", strerror (errno)); + closeprog = 1; + break; + } + + if (FD_ISSET (STDOUT_FILENO, &wfds)) + { + ret = + write (STDOUT_FILENO, write_std.buf + write_std.pos, + write_std.size - write_std.pos); + if (0 > ret) + { + closeprog = 1; + fprintf (stderr, "Write ERROR to STDOUT_FILENO: %s\n", + strerror (errno)); + break; + } + else + { + write_std.pos += ret; + // check if finished + if (write_std.pos == write_std.size) + { + write_std.pos = 0; + write_std.size = 0; + } + } + } + + if (FD_ISSET (fdpout, &wfds)) + { + ret = + write (fdpout, write_pout.buf + write_pout.pos, + write_pout.size - write_pout.pos); + + if (0 > ret) + { + closeprog = 1; + fprintf (stderr, "Write ERROR to fdpout: %s\n", strerror (errno)); + } + else + { + write_pout.pos += ret; + // check if finished + if (write_pout.pos == write_pout.size) + { + write_pout.pos = 0; + write_pout.size = 0; + } + } + } + + if (FD_ISSET (STDIN_FILENO, &rfds)) + { + readsize = read (STDIN_FILENO, readbuf, sizeof (readbuf)); + + if (0 > readsize) + { + closeprog = 1; + fprintf (stderr, "Error reading from STDIN_FILENO: %s\n", + strerror (errno)); + } + else if (0 < readsize) + { + GNUNET_SERVER_mst_receive (stdin_mst, NULL, readbuf, readsize, + GNUNET_NO, GNUNET_NO); + + } + else + { + //eof + closeprog = 1; + } + } + + if (FD_ISSET (fdpin, &rfds)) + { + readsize = read (fdpin, readbuf, sizeof (readbuf)); + if (0 > readsize) + { + closeprog = 1; + fprintf (stderr, "Error reading from fdpin: %s\n", strerror (errno)); + break; + } + else if (0 < readsize) + { + GNUNET_SERVER_mst_receive (file_in_mst, NULL, readbuf, readsize, + GNUNET_NO, GNUNET_NO); + } + else + { + //eof + closeprog = 1; + } + } + } + + //clean up + GNUNET_SERVER_mst_destroy (stdin_mst); + GNUNET_SERVER_mst_destroy (file_in_mst); + +end: + if (fpout != NULL) + fclose (fpout); + if (fpin != NULL) + fclose (fpin); + if (1 == first) + { + (void) unlink (FIFO_FILE1); + (void) unlink (FIFO_FILE2); + } + return 0; +} diff --git a/src/transport/gnunet-helper-transport-wlan.c b/src/transport/gnunet-helper-transport-wlan.c new file mode 100644 index 0000000..582df7c --- /dev/null +++ b/src/transport/gnunet-helper-transport-wlan.c @@ -0,0 +1,1758 @@ +/* + This file is part of GNUnet. + (C) 2010, 2011 Christian Grothoff (and other contributing authors) + Copyright (c) 2007, 2008, Andy Green + Copyright (C) 2009 Thomas d'Otreppe + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file src/transport/gnunet-helper-transport-wlan.c + * @brief wlan layer two server; must run as root (SUID will do) + * This code will work under GNU/Linux only. + * @author David Brodski + * + * This program serves as the mediator between the wlan interface and + * gnunet + */ + +/*- + * we use our local copy of ieee80211_radiotap.h + * + * - since we can't support extensions we don't understand + * - since linux does not include it in userspace headers + * + * Portions of this code were taken from the ieee80211_radiotap.h header, + * which is + * + * Copyright (c) 2003, 2004 David Young. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of David Young may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID + * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +/* + * Modifications to fit into the linux IEEE 802.11 stack, + * Mike Kershaw (dragorn@kismetwireless.net) + */ + +/** + * parts taken from aircrack-ng, parts changend. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gnunet_protocols.h" +#include "plugin_transport_wlan.h" + +#define ARPHRD_IEEE80211 801 +#define ARPHRD_IEEE80211_PRISM 802 +#define ARPHRD_IEEE80211_FULL 803 + +/** + * size of 802.11 address + */ +#define IEEE80211_ADDR_LEN 6 + +/** + * Maximum size of a message allowed in either direction. + */ +#define MAXLINE 4096 + + +#define IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK 0x80000000 + + +/* Name Data type Units + * ---- --------- ----- + * + * IEEE80211_RADIOTAP_TSFT __le64 microseconds + * + * Value in microseconds of the MAC's 64-bit 802.11 Time + * Synchronization Function timer when the first bit of the + * MPDU arrived at the MAC. For received frames, only. + * + * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap + * + * Tx/Rx frequency in MHz, followed by flags (see below). + * + * IEEE80211_RADIOTAP_FHSS __le16 see below + * + * For frequency-hopping radios, the hop set (first byte) + * and pattern (second byte). + * + * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s + * + * Tx/Rx data rate + * + * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from + * one milliwatt (dBm) + * + * RF signal power at the antenna, decibel difference from + * one milliwatt. + * + * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from + * one milliwatt (dBm) + * + * RF noise power at the antenna, decibel difference from one + * milliwatt. + * + * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB) + * + * RF signal power at the antenna, decibel difference from an + * arbitrary, fixed reference. + * + * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB) + * + * RF noise power at the antenna, decibel difference from an + * arbitrary, fixed reference point. + * + * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless + * + * Quality of Barker code lock. Unitless. Monotonically + * nondecreasing with "better" lock strength. Called "Signal + * Quality" in datasheets. (Is there a standard way to measure + * this?) + * + * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless + * + * Transmit power expressed as unitless distance from max + * power set at factory calibration. 0 is max power. + * Monotonically nondecreasing with lower power levels. + * + * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB) + * + * Transmit power expressed as decibel distance from max power + * set at factory calibration. 0 is max power. Monotonically + * nondecreasing with lower power levels. + * + * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from + * one milliwatt (dBm) + * + * Transmit power expressed as dBm (decibels from a 1 milliwatt + * reference). This is the absolute power level measured at + * the antenna port. + * + * IEEE80211_RADIOTAP_FLAGS uint8_t bitmap + * + * Properties of transmitted and received frames. See flags + * defined below. + * + * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index + * + * Unitless indication of the Rx/Tx antenna for this packet. + * The first antenna is antenna 0. + * + * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap + * + * Properties of received frames. See flags defined below. + * + * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap + * + * Properties of transmitted frames. See flags defined below. + * + * IEEE80211_RADIOTAP_RTS_RETRIES uint8_t data + * + * Number of rts retries a transmitted frame used. + * + * IEEE80211_RADIOTAP_DATA_RETRIES uint8_t data + * + * Number of unicast retries a transmitted frame used. + * + */ +enum RadiotapType +{ + IEEE80211_RADIOTAP_TSFT = 0, + IEEE80211_RADIOTAP_FLAGS = 1, + IEEE80211_RADIOTAP_RATE = 2, + IEEE80211_RADIOTAP_CHANNEL = 3, + IEEE80211_RADIOTAP_FHSS = 4, + IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, + IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, + IEEE80211_RADIOTAP_LOCK_QUALITY = 7, + IEEE80211_RADIOTAP_TX_ATTENUATION = 8, + IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, + IEEE80211_RADIOTAP_DBM_TX_POWER = 10, + IEEE80211_RADIOTAP_ANTENNA = 11, + IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, + IEEE80211_RADIOTAP_DB_ANTNOISE = 13, + IEEE80211_RADIOTAP_RX_FLAGS = 14, + IEEE80211_RADIOTAP_TX_FLAGS = 15, + IEEE80211_RADIOTAP_RTS_RETRIES = 16, + IEEE80211_RADIOTAP_DATA_RETRIES = 17, + IEEE80211_RADIOTAP_EXT = 31 +}; + +/* For IEEE80211_RADIOTAP_FLAGS */ +#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received + * during CFP + */ +#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received + * with short + * preamble + */ +#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received + * with WEP encryption + */ +#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received + * with fragmentation + */ +#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ +#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between + * 802.11 header and payload + * (to 32-bit boundary) + */ +/* For IEEE80211_RADIOTAP_RX_FLAGS */ +#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ + +/* For IEEE80211_RADIOTAP_TX_FLAGS */ +#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive + * retries */ +#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ +#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ +#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* frame should not be ACKed */ +#define IEEE80211_RADIOTAP_F_TX_NOSEQ 0x0010 /* sequence number handled + * by userspace */ + + +/** + * A generic radio capture format is desirable. There is one for + * Linux, but it is neither rigidly defined (there were not even + * units given for some fields) nor easily extensible. + * + * I suggest the following extensible radio capture format. It is + * based on a bitmap indicating which fields are present. + * + * I am trying to describe precisely what the application programmer + * should expect in the following, and for that reason I tell the + * units and origin of each measurement (where it applies), or else I + * use sufficiently weaselly language ("is a monotonically nondecreasing + * function of...") that I cannot set false expectations for lawyerly + * readers. + * + * The radio capture header precedes the 802.11 header. + * All data in the header is little endian on all platforms. + */ +struct ieee80211_radiotap_header +{ + /** + * Version 0. Only increases for drastic changes, introduction of + * compatible new fields does not count. + */ + uint8_t it_version; + uint8_t it_pad; + + /** + * length of the whole header in bytes, including it_version, + * it_pad, it_len, and data fields. + */ + uint16_t it_len; + + /** + * A bitmap telling which fields are present. Set bit 31 + * (0x80000000) to extend the bitmap by another 32 bits. Additional + * extensions are made by setting bit 31. + */ + uint32_t it_present; +}; + +/** + * + */ +struct RadioTapheader +{ + /** + * + */ + struct ieee80211_radiotap_header header; + + /** + * + */ + uint8_t rate; + + /** + * + */ + uint8_t pad1; + + /** + * + */ + uint16_t txflags; +}; + + +/** + * IO buffer used for buffering data in transit (to wireless or to stdout). + */ +struct SendBuffer +{ + /** + * How many bytes of data are stored in 'buf' for transmission right now? + * Data always starts at offset 0 and extends to 'size'. + */ + size_t size; + + /** + * How many bytes that were stored in 'buf' did we already write to the + * destination? Always smaller than 'size'. + */ + size_t pos; + + /** + * Buffered data; twice the maximum allowed message size as we add some + * headers. + */ + char buf[MAXLINE * 2]; +}; + +/** + * Buffer for data read from stdin to be transmitted to the wirless card. + */ +static struct SendBuffer write_pout; + +/** + * Buffer for data read from the wireless card to be transmitted to stdout. + */ +static struct SendBuffer write_std; + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * generic definitions for IEEE 802.11 frames + */ +struct ieee80211_frame +{ + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} GNUNET_PACKED; +GNUNET_NETWORK_STRUCT_END + + +/** + * struct for storing the information of the hardware + */ +struct HardwareInfos +{ + + /** + * file descriptor for the raw socket + */ + int fd_raw; + + /** + * Which format has the header that we're getting when receiving packets? + * Some ARPHRD_IEEE80211_XXX-value. + */ + int arptype_in; + + /** + * Name of the interface, not necessarily 0-terminated (!). + */ + char iface[IFNAMSIZ]; + + /** + * MAC address of our own WLAN interface. + */ + struct GNUNET_TRANSPORT_WLAN_MacAddress pl_mac; +}; + + +/** + * struct ieee80211_radiotap_iterator - tracks walk through present radiotap arguments + * in the radiotap header. + */ +struct ieee80211_radiotap_iterator +{ + /** + * pointer to the radiotap header we are walking through + */ + const struct ieee80211_radiotap_header *rtheader; + + /** + * length of radiotap header in cpu byte ordering + */ + size_t max_length; + + /** + * IEEE80211_RADIOTAP_... index of current arg + */ + unsigned int this_arg_index; + + /** + * pointer to current radiotap arg + */ + uint8_t *this_arg; + + /** + * internal next argument index + */ + unsigned int arg_index; + + /** + * internal next argument pointer + */ + uint8_t *arg; + + /** + * internal pointer to next present uint32_t + */ + uint32_t *next_bitmap; + + /** + * internal shifter for curr uint32_t bitmap, b0 set == arg present + */ + uint32_t bitmap_shifter; +}; + + + +/* specialized version of server_mst.c begins here */ + +#define ALIGN_FACTOR 8 + +/** + * Smallest supported message. + */ +#define MIN_BUFFER_SIZE sizeof (struct GNUNET_MessageHeader) + + +/** + * Functions with this signature are called whenever a + * complete message is received by the tokenizer. + * + * @param cls closure + * @param message the actual message + */ +typedef void (*MessageTokenizerCallback) (void *cls, + const struct + GNUNET_MessageHeader * + message); + +/** + * Handle to a message stream tokenizer. + */ +struct MessageStreamTokenizer +{ + + /** + * Function to call on completed messages. + */ + MessageTokenizerCallback cb; + + /** + * Closure for cb. + */ + void *cb_cls; + + /** + * Size of the buffer (starting at 'hdr'). + */ + size_t curr_buf; + + /** + * How many bytes in buffer have we already processed? + */ + size_t off; + + /** + * How many bytes in buffer are valid right now? + */ + size_t pos; + + /** + * Beginning of the buffer. Typed like this to force alignment. + */ + struct GNUNET_MessageHeader *hdr; + +}; + + + +/** + * Create a message stream tokenizer. + * + * @param cb function to call on completed messages + * @param cb_cls closure for cb + * @return handle to tokenizer + */ +static struct MessageStreamTokenizer * +mst_create (MessageTokenizerCallback cb, + void *cb_cls) +{ + struct MessageStreamTokenizer *ret; + + ret = malloc (sizeof (struct MessageStreamTokenizer)); + if (NULL == ret) + exit (1); + ret->hdr = malloc (MIN_BUFFER_SIZE); + if (NULL == ret->hdr) + exit (2); + ret->curr_buf = MIN_BUFFER_SIZE; + ret->cb = cb; + ret->cb_cls = cb_cls; + return ret; +} + + +/** + * Add incoming data to the receive buffer and call the + * callback for all complete messages. + * + * @param mst tokenizer to use + * @param buf input data to add + * @param size number of bytes in buf + * @return GNUNET_OK if we are done processing (need more data) + * GNUNET_SYSERR if the data stream is corrupt + */ +static int +mst_receive (struct MessageStreamTokenizer *mst, + const char *buf, size_t size) +{ + const struct GNUNET_MessageHeader *hdr; + size_t delta; + uint16_t want; + char *ibuf; + int need_align; + unsigned long offset; + int ret; + + ret = GNUNET_OK; + ibuf = (char *) mst->hdr; + while (mst->pos > 0) + { +do_align: + if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) || + (0 != (mst->off % ALIGN_FACTOR))) + { + /* need to align or need more space */ + mst->pos -= mst->off; + memmove (ibuf, &ibuf[mst->off], mst->pos); + mst->off = 0; + } + if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) + { + delta = + GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) - + (mst->pos - mst->off), size); + memcpy (&ibuf[mst->pos], buf, delta); + mst->pos += delta; + buf += delta; + size -= delta; + } + if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) + { + return GNUNET_OK; + } + hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; + want = ntohs (hdr->size); + if (want < sizeof (struct GNUNET_MessageHeader)) + { + // GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (mst->curr_buf - mst->off < want) + { + /* need more space */ + mst->pos -= mst->off; + memmove (ibuf, &ibuf[mst->off], mst->pos); + mst->off = 0; + } + if (want > mst->curr_buf) + { + mst->hdr = realloc (mst->hdr, want); + if (NULL == mst->hdr) + exit (3); + ibuf = (char *) mst->hdr; + mst->curr_buf = want; + } + hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; + if (mst->pos - mst->off < want) + { + delta = GNUNET_MIN (want - (mst->pos - mst->off), size); + memcpy (&ibuf[mst->pos], buf, delta); + mst->pos += delta; + buf += delta; + size -= delta; + } + if (mst->pos - mst->off < want) + { + return GNUNET_OK; + } + mst->cb (mst->cb_cls, hdr); + mst->off += want; + if (mst->off == mst->pos) + { + /* reset to beginning of buffer, it's free right now! */ + mst->off = 0; + mst->pos = 0; + } + } + while (size > 0) + { + if (size < sizeof (struct GNUNET_MessageHeader)) + break; + offset = (unsigned long) buf; + need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO; + if (GNUNET_NO == need_align) + { + /* can try to do zero-copy and process directly from original buffer */ + hdr = (const struct GNUNET_MessageHeader *) buf; + want = ntohs (hdr->size); + if (want < sizeof (struct GNUNET_MessageHeader)) + { + // GNUNET_break_op (0); + mst->off = 0; + return GNUNET_SYSERR; + } + if (size < want) + break; /* or not, buffer incomplete, so copy to private buffer... */ + mst->cb (mst->cb_cls, hdr); + buf += want; + size -= want; + } + else + { + /* need to copy to private buffer to align; + * yes, we go a bit more spagetti than usual here */ + goto do_align; + } + } + if (size > 0) + { + if (size + mst->pos > mst->curr_buf) + { + mst->hdr = realloc (mst->hdr, size + mst->pos); + if (NULL == mst->hdr) + exit (4); + ibuf = (char *) mst->hdr; + mst->curr_buf = size + mst->pos; + } + // GNUNET_assert (mst->pos + size <= mst->curr_buf); + memcpy (&ibuf[mst->pos], buf, size); + mst->pos += size; + } + return ret; +} + + +/** + * Destroys a tokenizer. + * + * @param mst tokenizer to destroy + */ +static void +mst_destroy (struct MessageStreamTokenizer *mst) +{ + free (mst->hdr); + free (mst); +} + +/* end of server_mst.c copy */ + + + + +/** + * Radiotap header iteration + * + * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator + * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) + * then loop calling __ieee80211_radiotap_iterator_next()... it returns -1 + * if there are no more args in the header, or the next argument type index + * that is present. The iterator's this_arg member points to the start of the + * argument associated with the current argument index that is present, + * which can be found in the iterator's this_arg_index member. This arg + * index corresponds to the IEEE80211_RADIOTAP_... defines. + * + * @param iterator iterator to initialize + * @param radiotap_header message to parse + * @param max_length number of valid bytes in radiotap_header + * @return 0 on success, -1 on error + */ +static int +ieee80211_radiotap_iterator_init (struct ieee80211_radiotap_iterator *iterator, + const struct ieee80211_radiotap_header + *radiotap_header, + size_t max_length) +{ + if ( (iterator == NULL) || + (radiotap_header == NULL) ) + return -1; + + /* Linux only supports version 0 radiotap format */ + if (0 != radiotap_header->it_version) + return -1; + + /* sanity check for allowed length and radiotap length field */ + if ( (max_length < sizeof (struct ieee80211_radiotap_header)) || + (max_length < (GNUNET_le16toh (radiotap_header->it_len))) ) + return -1; + + iterator->rtheader = radiotap_header; + iterator->max_length = GNUNET_le16toh (radiotap_header->it_len); + iterator->arg_index = 0; + iterator->bitmap_shifter = GNUNET_le32toh (radiotap_header->it_present); + iterator->arg = + ((uint8_t *) radiotap_header) + sizeof (struct ieee80211_radiotap_header); + iterator->this_arg = 0; + + /* find payload start allowing for extended bitmap(s) */ + if ((iterator->bitmap_shifter & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)) + { + while (GNUNET_le32toh (*((uint32_t *) iterator->arg)) & + IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK) + { + iterator->arg += sizeof (uint32_t); + + /* + * check for insanity where the present bitmaps + * keep claiming to extend up to or even beyond the + * stated radiotap header length + */ + if (iterator->arg - ((uint8_t*) iterator->rtheader) > iterator->max_length) + return -1; + } + iterator->arg += sizeof (uint32_t); + /* + * no need to check again for blowing past stated radiotap + * header length, becuase ieee80211_radiotap_iterator_next + * checks it before it is dereferenced + */ + } + /* we are all initialized happily */ + return 0; +} + + +/** + * @brief ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg + * + * This function returns the next radiotap arg index (IEEE80211_RADIOTAP_...) + * and sets iterator->this_arg to point to the payload for the arg. It takes + * care of alignment handling and extended present fields. interator->this_arg + * can be changed by the caller. The args pointed to are in little-endian + * format. + * + * @param iterator: radiotap_iterator to move to next arg (if any) + * + * @return next present arg index on success or -1 if no more or error + */ +static int +ieee80211_radiotap_iterator_next (struct ieee80211_radiotap_iterator *iterator) +{ + + /* + * small length lookup table for all radiotap types we heard of + * starting from b0 in the bitmap, so we can walk the payload + * area of the radiotap header + * + * There is a requirement to pad args, so that args + * of a given length must begin at a boundary of that length + * -- but note that compound args are allowed (eg, 2 x uint16_t + * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not + * a reliable indicator of alignment requirement. + * + * upper nybble: content alignment for arg + * lower nybble: content length for arg + */ + + static const uint8_t rt_sizes[] = { + [IEEE80211_RADIOTAP_TSFT] = 0x88, + [IEEE80211_RADIOTAP_FLAGS] = 0x11, + [IEEE80211_RADIOTAP_RATE] = 0x11, + [IEEE80211_RADIOTAP_CHANNEL] = 0x24, + [IEEE80211_RADIOTAP_FHSS] = 0x22, + [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, + [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, + [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, + [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, + [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, + [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, + [IEEE80211_RADIOTAP_ANTENNA] = 0x11, + [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, + [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, + [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, + [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, + [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, + [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11 + /* + * add more here as they are defined in + * include/net/ieee80211_radiotap.h + */ + }; + + /* + * for every radiotap entry we can at + * least skip (by knowing the length)... + */ + + while (iterator->arg_index < sizeof (rt_sizes)) + { + int hit = 0; + + if (!(iterator->bitmap_shifter & 1)) + goto next_entry; /* arg not present */ + + /* + * arg is present, account for alignment padding + * 8-bit args can be at any alignment + * 16-bit args must start on 16-bit boundary + * 32-bit args must start on 32-bit boundary + * 64-bit args must start on 64-bit boundary + * + * note that total arg size can differ from alignment of + * elements inside arg, so we use upper nybble of length + * table to base alignment on + * + * also note: these alignments are ** relative to the + * start of the radiotap header **. There is no guarantee + * that the radiotap header itself is aligned on any + * kind of boundary. + */ + + if ((((void *) iterator->arg) - + ((void *) iterator->rtheader)) & ((rt_sizes[iterator->arg_index] >> 4) + - 1)) + iterator->arg_index += + (rt_sizes[iterator->arg_index] >> 4) - + ((((void *) iterator->arg) - + ((void *) iterator->rtheader)) & ((rt_sizes[iterator->arg_index] >> + 4) - 1)); + + /* + * this is what we will return to user, but we need to + * move on first so next call has something fresh to test + */ + + iterator->this_arg_index = iterator->arg_index; + iterator->this_arg = iterator->arg; + hit = 1; + + /* internally move on the size of this arg */ + + iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; + + /* + * check for insanity where we are given a bitmap that + * claims to have more arg content than the length of the + * radiotap section. We will normally end up equalling this + * max_length on the last arg, never exceeding it. + */ + + if ((((void *) iterator->arg) - ((void *) iterator->rtheader)) > + iterator->max_length) + return -1; + +next_entry: + + iterator->arg_index++; + if (((iterator->arg_index & 31) == 0)) + { + /* completed current uint32_t bitmap */ + if (iterator->bitmap_shifter & 1) + { + /* b31 was set, there is more */ + /* move to next uint32_t bitmap */ + iterator->bitmap_shifter = GNUNET_le32toh (*iterator->next_bitmap); + iterator->next_bitmap++; + } + else + { + /* no more bitmaps: end */ + iterator->arg_index = sizeof (rt_sizes); + } + } + else + { /* just try the next bit */ + iterator->bitmap_shifter >>= 1; + } + + /* if we found a valid arg earlier, return it now */ + + if (hit) + return iterator->this_arg_index; + + } + + /* we don't know how to handle any more args, we're done */ + return -1; +} + + +/** + * Return the channel from the frequency (in Mhz) + * @param frequency of the channel + * @return number of the channel + */ +static int +get_channel_from_frequency (int frequency) +{ + if (frequency >= 2412 && frequency <= 2472) + return (frequency - 2407) / 5; + if (frequency == 2484) + return 14; + if (frequency >= 5000 && frequency <= 6100) + return (frequency - 5000) / 5; + return -1; +} + + +/** + * function to calculate the crc, the start of the calculation + * + * @param buf buffer to calc the crc + * @param len len of the buffer + * @return crc sum + */ +static unsigned long +calc_crc_osdep (const unsigned char *buf, size_t len) +{ + static const unsigned long int crc_tbl_osdep[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, + 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, + 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, + 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, + 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, + 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, + 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, + 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, + 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, + 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, + 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, + 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, + 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, + 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, + 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, + 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, + 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, + 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, + 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, + 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, + 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, + 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned long crc = 0xFFFFFFFF; + + for (; len > 0; len--, buf++) + crc = crc_tbl_osdep[(crc ^ *buf) & 0xFF] ^ (crc >> 8); + return (~crc); +} + + +/** + * Function to calculate and check crc of the wlan packet + * + * @param buf buffer of the packet, with len + 4 bytes of data, + * the last 4 bytes being the checksum + * @param len length of the payload in data + * @return 0 on success (checksum matches), 1 on error + */ +static int +check_crc_buf_osdep (const unsigned char *buf, size_t len) +{ + unsigned long crc; + + crc = calc_crc_osdep (buf, len); + buf += len; + if (((crc) & 0xFF) == buf[0] && ((crc >> 8) & 0xFF) == buf[1] && + ((crc >> 16) & 0xFF) == buf[2] && ((crc >> 24) & 0xFF) == buf[3]) + return 0; + return 1; +} + + +/** + * Get the channel used by our WLAN interface. + * + * @param dev pointer to the dev struct of the card + * @return channel number, -1 on error + */ +static int +linux_get_channel (const struct HardwareInfos *dev) +{ + struct iwreq wrq; + int fd; + int frequency; + int chan; + + memset (&wrq, 0, sizeof (struct iwreq)); + strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ); + fd = dev->fd_raw; + if (0 > ioctl (fd, SIOCGIWFREQ, &wrq)) + return -1; + + frequency = wrq.u.freq.m; + if (100000000 < frequency) + frequency /= 100000; + else if (1000000 < frequency) + frequency /= 1000; + if (1000 < frequency) + chan = get_channel_from_frequency (frequency); + else + chan = frequency; + return chan; +} + + +/** + * function to read from a wlan card + * @param dev pointer to the struct of the wlan card + * @param buf buffer to read to + * @param buf_size size of the buffer + * @param ri radiotap_rx info + * @return size read from the buffer + */ +static ssize_t +linux_read (struct HardwareInfos *dev, unsigned char *buf, size_t buf_size, + struct Radiotap_rx *ri) +{ + unsigned char tmpbuf[buf_size]; + ssize_t caplen; + int n, got_signal, got_noise, got_channel, fcs_removed; + + n = got_signal = got_noise = got_channel = fcs_removed = 0; + + caplen = read (dev->fd_raw, tmpbuf, buf_size); + if (0 > caplen) + { + if (EAGAIN == errno) + return 0; + fprintf (stderr, "Failed to read from RAW socket: %s\n", strerror (errno)); + return -1; + } + + memset (buf, 0, buf_size); + memset (ri, 0, sizeof (*ri)); + + switch (dev->arptype_in) + { + case ARPHRD_IEEE80211_PRISM: + { + /* skip the prism header */ + if (tmpbuf[7] == 0x40) + { + /* prism54 uses a different format */ + ri->ri_power = tmpbuf[0x33]; + ri->ri_noise = *(unsigned int *) (tmpbuf + 0x33 + 12); + ri->ri_rate = (*(unsigned int *) (tmpbuf + 0x33 + 24)) * 500000; + got_signal = 1; + got_noise = 1; + n = 0x40; + } + else + { + ri->ri_mactime = *(uint64_t *) (tmpbuf + 0x5C - 48); + ri->ri_channel = *(unsigned int *) (tmpbuf + 0x5C - 36); + ri->ri_power = *(unsigned int *) (tmpbuf + 0x5C); + ri->ri_noise = *(unsigned int *) (tmpbuf + 0x5C + 12); + ri->ri_rate = (*(unsigned int *) (tmpbuf + 0x5C + 24)) * 500000; + got_channel = 1; + got_signal = 1; + got_noise = 1; + n = *(int *) (tmpbuf + 4); + } + + if ( (n < 8) || (n >= caplen) ) + return 0; + } + break; + + case ARPHRD_IEEE80211_FULL: + { + struct ieee80211_radiotap_iterator iterator; + struct ieee80211_radiotap_header *rthdr; + + rthdr = (struct ieee80211_radiotap_header *) tmpbuf; + + if (0 != ieee80211_radiotap_iterator_init (&iterator, rthdr, caplen)) + return 0; + + /* go through the radiotap arguments we have been given + * by the driver + */ + + while (ieee80211_radiotap_iterator_next (&iterator) >= 0) + { + + switch (iterator.this_arg_index) + { + + case IEEE80211_RADIOTAP_TSFT: + ri->ri_mactime = GNUNET_le64toh (*((uint64_t *) iterator.this_arg)); + break; + + case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: + if (!got_signal) + { + if (*iterator.this_arg < 127) + ri->ri_power = *iterator.this_arg; + else + ri->ri_power = *iterator.this_arg - 255; + + got_signal = 1; + } + break; + + case IEEE80211_RADIOTAP_DB_ANTSIGNAL: + if (!got_signal) + { + if (*iterator.this_arg < 127) + ri->ri_power = *iterator.this_arg; + else + ri->ri_power = *iterator.this_arg - 255; + + got_signal = 1; + } + break; + + case IEEE80211_RADIOTAP_DBM_ANTNOISE: + if (!got_noise) + { + if (*iterator.this_arg < 127) + ri->ri_noise = *iterator.this_arg; + else + ri->ri_noise = *iterator.this_arg - 255; + + got_noise = 1; + } + break; + + case IEEE80211_RADIOTAP_DB_ANTNOISE: + if (!got_noise) + { + if (*iterator.this_arg < 127) + ri->ri_noise = *iterator.this_arg; + else + ri->ri_noise = *iterator.this_arg - 255; + + got_noise = 1; + } + break; + + case IEEE80211_RADIOTAP_ANTENNA: + ri->ri_antenna = *iterator.this_arg; + break; + + case IEEE80211_RADIOTAP_CHANNEL: + ri->ri_channel = *iterator.this_arg; + got_channel = 1; + break; + + case IEEE80211_RADIOTAP_RATE: + ri->ri_rate = (*iterator.this_arg) * 500000; + break; + + case IEEE80211_RADIOTAP_FLAGS: + /* is the CRC visible at the end? + * remove + */ + if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) + { + fcs_removed = 1; + caplen -= 4; + } + + if (*iterator.this_arg & IEEE80211_RADIOTAP_F_RX_BADFCS) + return (0); + + break; + } + } + n = GNUNET_le16toh (rthdr->it_len); + if (n <= 0 || n >= caplen) + return 0; + } + break; + case ARPHRD_IEEE80211: + /* do nothing? */ + break; + default: + errno = ENOTSUP; + return -1; + } + + caplen -= n; + + //detect fcs at the end, even if the flag wasn't set and remove it + if ((0 == fcs_removed) && (0 == check_crc_buf_osdep (tmpbuf + n, caplen - 4))) + { + caplen -= 4; + } + memcpy (buf, tmpbuf + n, caplen); + if (!got_channel) + ri->ri_channel = linux_get_channel (dev); + + return caplen; +} + + +/** + * Open the wireless network interface for reading/writing. + * + * @param dev pointer to the device struct + * @return 0 on success + */ +static int +open_device_raw (struct HardwareInfos *dev) +{ + struct ifreq ifr; + struct iwreq wrq; + struct packet_mreq mr; + struct sockaddr_ll sll; + + /* find the interface index */ + memset (&ifr, 0, sizeof (ifr)); + strncpy (ifr.ifr_name, dev->iface, IFNAMSIZ); + if (-1 == ioctl (dev->fd_raw, SIOCGIFINDEX, &ifr)) + { + fprintf (stderr, "ioctl(SIOCGIFINDEX) on interface `%.*s' failed: %s\n", + IFNAMSIZ, dev->iface, strerror (errno)); + return 1; + } + + /* lookup the hardware type */ + memset (&sll, 0, sizeof (sll)); + sll.sll_family = AF_PACKET; + sll.sll_ifindex = ifr.ifr_ifindex; + sll.sll_protocol = htons (ETH_P_ALL); + if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr)) + { + fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n", + IFNAMSIZ, dev->iface, strerror (errno)); + return 1; + } + + /* lookup iw mode */ + memset (&wrq, 0, sizeof (struct iwreq)); + strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ); + if (-1 == ioctl (dev->fd_raw, SIOCGIWMODE, &wrq)) + { + /* most probably not supported (ie for rtap ipw interface) * + * so just assume its correctly set... */ + wrq.u.mode = IW_MODE_MONITOR; + } + + if (((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) && + (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) && + (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)) || + (wrq.u.mode != IW_MODE_MONITOR)) + { + fprintf (stderr, "Error: interface `%.*s' is not in monitor mode\n", + IFNAMSIZ, dev->iface); + return 1; + } + + /* Is interface st to up, broadcast & running ? */ + if ((ifr.ifr_flags | IFF_UP | IFF_BROADCAST | IFF_RUNNING) != ifr.ifr_flags) + { + /* Bring interface up */ + ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_RUNNING; + + if (-1 == ioctl (dev->fd_raw, SIOCSIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl(SIOCSIFFLAGS) on interface `%.*s' failed: %s\n", + IFNAMSIZ, dev->iface, strerror (errno)); + return 1; + } + } + + /* bind the raw socket to the interface */ + if (-1 == bind (dev->fd_raw, (struct sockaddr *) &sll, sizeof (sll))) + { + fprintf (stderr, "Failed to bind interface `%.*s': %s\n", IFNAMSIZ, + dev->iface, strerror (errno)); + return 1; + } + + /* lookup the hardware type */ + if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr)) + { + fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n", + IFNAMSIZ, dev->iface, strerror (errno)); + return 1; + } + + memcpy (&dev->pl_mac, ifr.ifr_hwaddr.sa_data, MAC_ADDR_SIZE); + dev->arptype_in = ifr.ifr_hwaddr.sa_family; + if ((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) && + (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) && + (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)) + { + fprintf (stderr, "Unsupported hardware link type %d on interface `%.*s'\n", + ifr.ifr_hwaddr.sa_family, IFNAMSIZ, dev->iface); + return 1; + } + + /* enable promiscuous mode */ + memset (&mr, 0, sizeof (mr)); + mr.mr_ifindex = sll.sll_ifindex; + mr.mr_type = PACKET_MR_PROMISC; + if (0 != + setsockopt (dev->fd_raw, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, + sizeof (mr))) + { + fprintf (stderr, "Failed to enable promiscuous mode on interface `%.*s'\n", + IFNAMSIZ, dev->iface); + return 1; + } + + return 0; +} + + +/** + * Test if the given interface name really corresponds to a wireless + * device. + * + * @param iface name of the interface + * @return 0 on success, 1 on error + */ +static int +test_wlan_interface (const char *iface) +{ + char strbuf[512]; + struct stat sbuf; + int ret; + + /* mac80211 stack detection */ + ret = + snprintf (strbuf, sizeof (strbuf), "/sys/class/net/%s/phy80211/subsystem", + iface); + if ((ret < 0) || (ret >= sizeof (strbuf)) || (0 != stat (strbuf, &sbuf))) + { + fprintf (stderr, "Did not find 802.11 interface `%s'. Exiting.\n", iface); + return 1; + } + return 0; +} + + +/** + * Function to test incoming packets mac for being our own. + * + * @param uint8_taIeeeHeader buffer of the packet + * @param dev the Hardware_Infos struct + * @return 0 if mac belongs to us, 1 if mac is for another target + */ +static int +mac_test (const struct ieee80211_frame *uint8_taIeeeHeader, + const struct HardwareInfos *dev) +{ + if (0 != memcmp (uint8_taIeeeHeader->i_addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE)) + return 1; + if (0 == memcmp (uint8_taIeeeHeader->i_addr1, &dev->pl_mac, MAC_ADDR_SIZE)) + return 0; + if (0 == memcmp (uint8_taIeeeHeader->i_addr1, &bc_all_mac, MAC_ADDR_SIZE)) + return 0; + return 1; +} + + +/** + * function to set the wlan header to make attacks more difficult + * @param uint8_taIeeeHeader pointer to the header of the packet + * @param dev pointer to the Hardware_Infos struct + */ +static void +mac_set (struct ieee80211_frame *uint8_taIeeeHeader, + const struct HardwareInfos *dev) +{ + uint8_taIeeeHeader->i_fc[0] = 0x08; + uint8_taIeeeHeader->i_fc[1] = 0x00; + memcpy (uint8_taIeeeHeader->i_addr2, &dev->pl_mac, MAC_ADDR_SIZE); + memcpy (uint8_taIeeeHeader->i_addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE); +} + + +/** + * function to process the data from the stdin + * @param cls pointer to the device struct + * @param hdr pointer to the start of the packet + */ +static void +stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr) +{ + struct HardwareInfos *dev = cls; + struct Radiotap_Send *header = (struct Radiotap_Send *) &hdr[1]; + struct ieee80211_frame *wlanheader; + size_t sendsize; + struct RadioTapheader rtheader; + + rtheader.header.it_version = 0; /* radiotap version */ + rtheader.header.it_len = GNUNET_htole16 (0x0c); /* radiotap header length */ + rtheader.header.it_present = GNUNET_le16toh (0x00008004); /* our bitmap */ + rtheader.rate = 0x00; + rtheader.pad1 = 0x00; + rtheader.txflags = + GNUNET_htole16 (IEEE80211_RADIOTAP_F_TX_NOACK | IEEE80211_RADIOTAP_F_TX_NOSEQ); + + sendsize = ntohs (hdr->size); + if (sendsize < + sizeof (struct Radiotap_Send) + sizeof (struct GNUNET_MessageHeader)) + { + fprintf (stderr, "Function stdin_send_hw: malformed packet (too small)\n"); + exit (1); + } + sendsize -= + sizeof (struct Radiotap_Send) + sizeof (struct GNUNET_MessageHeader); + + if (MAXLINE < sendsize) + { + fprintf (stderr, "Function stdin_send_hw: Packet too big for buffer\n"); + exit (1); + } + if (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA != ntohs (hdr->type)) + { + fprintf (stderr, "Function stdin_send_hw: wrong packet type\n"); + exit (1); + } + + rtheader.header.it_len = GNUNET_htole16 (sizeof (rtheader)); + rtheader.rate = header->rate; + memcpy (write_pout.buf, &rtheader, sizeof (rtheader)); + memcpy (write_pout.buf + sizeof (rtheader), &header[1], sendsize); + /* payload contains MAC address, but we don't trust it, so we'll + * overwrite it with OUR MAC address again to prevent mischief */ + wlanheader = (struct ieee80211_frame *) (write_pout.buf + sizeof (rtheader)); + mac_set (wlanheader, dev); + write_pout.size = sendsize + sizeof (rtheader); +} + + +/** + * Main function of the helper. This code accesses a WLAN interface + * in monitoring mode (layer 2) and then forwards traffic in both + * directions between the WLAN interface and stdin/stdout of this + * process. Error messages are written to stdout. + * + * @param argc number of arguments, must be 2 + * @param argv arguments only argument is the name of the interface (i.e. 'mon0') + * @return 0 on success (never happens, as we don't return unless aborted), 1 on error + */ +int +main (int argc, char *argv[]) +{ + struct HardwareInfos dev; + char readbuf[MAXLINE]; + int maxfd; + fd_set rfds; + fd_set wfds; + int stdin_open; + struct MessageStreamTokenizer *stdin_mst; + int raw_eno; + + memset (&dev, 0, sizeof (dev)); + dev.fd_raw = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL)); + raw_eno = errno; /* remember for later */ + + /* drop privs */ + { + uid_t uid = getuid (); +#ifdef HAVE_SETRESUID + if (0 != setresuid (uid, uid, uid)) + { + fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); + if (-1 != dev.fd_raw) + (void) close (dev.fd_raw); + return 1; + } +#else + if (0 != (setuid (uid) | seteuid (uid))) + { + fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); + if (-1 != dev.fd_raw) + (void) close (dev.fd_raw); + return 1; + } + } +#endif + + /* now that we've dropped root rights, we can do error checking */ + if (2 != argc) + { + fprintf (stderr, + "You must specify the name of the interface as the first and only argument to this program.\n"); + if (-1 != dev.fd_raw) + (void) close (dev.fd_raw); + return 1; + } + + if (-1 == dev.fd_raw) + { + fprintf (stderr, "Failed to create raw socket: %s\n", strerror (raw_eno)); + return 1; + } + if (dev.fd_raw >= FD_SETSIZE) + { + fprintf (stderr, "File descriptor too large for select (%d > %d)\n", + dev.fd_raw, FD_SETSIZE); + (void) close (dev.fd_raw); + return 1; + } + if (0 != test_wlan_interface (argv[1])) + { + (void) close (dev.fd_raw); + return 1; + } + strncpy (dev.iface, argv[1], IFNAMSIZ); + if (0 != open_device_raw (&dev)) + { + (void) close (dev.fd_raw); + return 1; + } + + /* send MAC address of the WLAN interface to STDOUT first */ + { + struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg; + + macmsg.hdr.size = htons (sizeof (macmsg)); + macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL); + memcpy (&macmsg.mac, &dev.pl_mac, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); + memcpy (write_std.buf, &macmsg, sizeof (macmsg)); + write_std.size = sizeof (macmsg); + } + + stdin_mst = mst_create (&stdin_send_hw, &dev); + stdin_open = 1; + while (1) + { + maxfd = -1; + FD_ZERO (&rfds); + if ((0 == write_pout.size) && (1 == stdin_open)) + { + FD_SET (STDIN_FILENO, &rfds); + maxfd = MAX (maxfd, STDIN_FILENO); + } + if (0 == write_std.size) + { + FD_SET (dev.fd_raw, &rfds); + maxfd = MAX (maxfd, dev.fd_raw); + } + FD_ZERO (&wfds); + if (0 < write_std.size) + { + FD_SET (STDOUT_FILENO, &wfds); + maxfd = MAX (maxfd, STDOUT_FILENO); + } + if (0 < write_pout.size) + { + FD_SET (dev.fd_raw, &wfds); + maxfd = MAX (maxfd, dev.fd_raw); + } + { + int retval = select (maxfd + 1, &rfds, &wfds, NULL, NULL); + if ((-1 == retval) && (EINTR == errno)) + continue; + if (0 > retval) + { + fprintf (stderr, "select failed: %s\n", strerror (errno)); + break; + } + } + if (FD_ISSET (STDOUT_FILENO, &wfds)) + { + ssize_t ret = + write (STDOUT_FILENO, write_std.buf + write_std.pos, + write_std.size - write_std.pos); + if (0 > ret) + { + fprintf (stderr, "Failed to write to STDOUT: %s\n", strerror (errno)); + break; + } + write_std.pos += ret; + if (write_std.pos == write_std.size) + { + write_std.pos = 0; + write_std.size = 0; + } + } + if (FD_ISSET (dev.fd_raw, &wfds)) + { + ssize_t ret = + write (dev.fd_raw, write_pout.buf + write_std.pos, + write_pout.size - write_pout.pos); + if (0 > ret) + { + fprintf (stderr, "Failed to write to WLAN device: %s\n", + strerror (errno)); + break; + } + write_pout.pos += ret; + if ((write_pout.pos != write_pout.size) && (0 != ret)) + { + /* we should not get partial sends with packet-oriented devices... */ + fprintf (stderr, "Write error, partial send: %u/%u\n", + (unsigned int) write_pout.pos, + (unsigned int) write_pout.size); + break; + } + if (write_pout.pos == write_pout.size) + { + write_pout.pos = 0; + write_pout.size = 0; + } + } + + if (FD_ISSET (STDIN_FILENO, &rfds)) + { + ssize_t ret = + read (STDIN_FILENO, readbuf, sizeof (readbuf)); + if (0 > ret) + { + fprintf (stderr, "Read error from STDIN: %s\n", strerror (errno)); + break; + } + if (0 == ret) + { + /* stop reading... */ + stdin_open = 0; + } + mst_receive (stdin_mst, readbuf, ret); + } + + if (FD_ISSET (dev.fd_raw, &rfds)) + { + struct GNUNET_MessageHeader *header; + struct Radiotap_rx *rxinfo; + struct ieee80211_frame *datastart; + ssize_t ret; + + header = (struct GNUNET_MessageHeader *) write_std.buf; + rxinfo = (struct Radiotap_rx *) &header[1]; + datastart = (struct ieee80211_frame *) &rxinfo[1]; + ret = + linux_read (&dev, (unsigned char *) datastart, + sizeof (write_std.buf) - sizeof (struct Radiotap_rx) - + sizeof (struct GNUNET_MessageHeader), rxinfo); + if (0 > ret) + { + fprintf (stderr, "Read error from raw socket: %s\n", strerror (errno)); + break; + } + if ((0 < ret) && (0 == mac_test (datastart, &dev))) + { + write_std.size = + ret + sizeof (struct GNUNET_MessageHeader) + + sizeof (struct Radiotap_rx); + header->size = htons (write_std.size); + header->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); + } + } + + } + /* Error handling, try to clean up a bit at least */ + mst_destroy (stdin_mst); + (void) close (dev.fd_raw); + return 1; /* we never exit 'normally' */ +} + +/* end of gnunet-helper-transport-wlan.c */ diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c new file mode 100644 index 0000000..cd9bb5c --- /dev/null +++ b/src/transport/gnunet-service-transport.c @@ -0,0 +1,633 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport.c + * @brief + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_ats_service.h" +#include "gnunet-service-transport.h" +#include "gnunet-service-transport_blacklist.h" +#include "gnunet-service-transport_clients.h" +#include "gnunet-service-transport_hello.h" +#include "gnunet-service-transport_neighbours.h" +#include "gnunet-service-transport_plugins.h" +#include "gnunet-service-transport_validation.h" +#include "transport.h" + +/* globals */ + +/** + * Statistics handle. + */ +struct GNUNET_STATISTICS_Handle *GST_stats; + +/** + * Configuration handle. + */ +const struct GNUNET_CONFIGURATION_Handle *GST_cfg; + +/** + * Configuration handle. + */ +struct GNUNET_PeerIdentity GST_my_identity; + +/** + * Handle to peerinfo service. + */ +struct GNUNET_PEERINFO_Handle *GST_peerinfo; + +/** + * Our public key. + */ +struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key; + +/** + * Our private key. + */ +struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key; + +/** + * ATS handle. + */ +struct GNUNET_ATS_SchedulingHandle *GST_ats; + + +/** + * Transmit our HELLO message to the given (connected) neighbour. + * + * @param cls the 'HELLO' message + * @param target a connected neighbour + * @param ats performance information (unused) + * @param ats_count number of records in ats (unused) + * @param address the address + */ +static void +transmit_our_hello (void *cls, const struct GNUNET_PeerIdentity *target, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count, + const struct GNUNET_HELLO_Address *address) +{ + const struct GNUNET_MessageHeader *hello = cls; + + GST_neighbours_send (target, (const char *) hello, ntohs (hello->size), + GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION, NULL, NULL); +} + + +/** + * My HELLO has changed. Tell everyone who should know. + * + * @param cls unused + * @param hello new HELLO + */ +static void +process_hello_update (void *cls, const struct GNUNET_MessageHeader *hello) +{ + GST_clients_broadcast (hello, GNUNET_NO); + GST_neighbours_iterate (&transmit_our_hello, (void *) hello); +} + + + +/** + * We received some payload. Prepare to pass it on to our clients. + * + * @param peer (claimed) identity of the other peer + * @param address the address + * @param session session used + * @param message the message to process + * @param ats performance information + * @param ats_count number of records in ats + * @return how long the plugin should wait until receiving more data + */ +static struct GNUNET_TIME_Relative +process_payload (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + struct GNUNET_TIME_Relative ret; + int do_forward; + struct InboundMessage *im; + size_t msg_size = ntohs (message->size); + size_t size = + sizeof (struct InboundMessage) + msg_size + + sizeof (struct GNUNET_ATS_Information) * (ats_count + 1); + char buf[size]; + struct GNUNET_ATS_Information *ap; + + ret = GNUNET_TIME_UNIT_ZERO; + do_forward = GNUNET_SYSERR; + ret = GST_neighbours_calculate_receive_delay (peer, msg_size, &do_forward); + + if (!GST_neighbours_test_connected (peer)) + { + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Discarded %u bytes type %u payload from peer `%s'\n", msg_size, + ntohs (message->type), GNUNET_i2s (peer)); + + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# bytes payload discarded due to not connected peer "), + msg_size, GNUNET_NO); + return ret; + } + + if (do_forward != GNUNET_YES) + return ret; + im = (struct InboundMessage *) buf; + im->header.size = htons (size); + im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV); + im->ats_count = htonl (ats_count + 1); + im->peer = *peer; + ap = (struct GNUNET_ATS_Information *) &im[1]; + memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information)); + ap[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); + ap[ats_count].value = + htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value); + memcpy (&ap[ats_count + 1], message, ntohs (message->size)); + + GNUNET_ATS_address_update (GST_ats, address, session, ap, ats_count + 1); + GST_clients_broadcast (&im->header, GNUNET_YES); + + return ret; +} + + +/** + * Function called by the transport for each received message. + * This function should also be called with "NULL" for the + * message to signal that the other peer disconnected. + * + * @param cls closure, const char* with the name of the plugin we received the message from + * @param peer (claimed) identity of the other peer + * @param message the message, NULL if we only care about + * learning about the delay until we should receive again -- FIXME! + * @param ats performance information + * @param ats_count number of records in ats + * @param session identifier used for this session (NULL for plugins + * that do not offer bi-directional communication to the sender + * using the same "connection") + * @param sender_address binary address of the sender (if we established the + * connection or are otherwise sure of it; should be NULL + * for inbound TCP/UDP connections since it it not clear + * that we could establish ourselves a connection to that + * IP address and get the same system) + * @param sender_address_len number of bytes in sender_address + * @return how long the plugin should wait until receiving more data + * (plugins that do not support this, can ignore the return value) + */ +static struct GNUNET_TIME_Relative +plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count, struct Session *session, + const char *sender_address, + uint16_t sender_address_len) +{ + const char *plugin_name = cls; + struct GNUNET_TIME_Relative ret; + struct GNUNET_HELLO_Address address; + uint16_t type; + + address.peer = *peer; + address.address = sender_address; + address.address_length = sender_address_len; + address.transport_name = plugin_name; + ret = GNUNET_TIME_UNIT_ZERO; + if (NULL == message) + goto end; + type = ntohs (message->type); +#if DEBUG_TRANSPORT + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received Message with type %u\n", type); +#endif + + switch (type) + { + case GNUNET_MESSAGE_TYPE_HELLO: + GST_validation_handle_hello (message); + return ret; + case GNUNET_MESSAGE_TYPE_TRANSPORT_PING: +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Processing `%s' from `%s'\n", "PING", + (sender_address != + NULL) ? GST_plugins_a2s (&address) : ""); +#endif + GST_validation_handle_ping (peer, message, &address, session); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG: +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Processing `%s' from `%s'\n", "PONG", + (sender_address != + NULL) ? GST_plugins_a2s (&address) : ""); +#endif + GST_validation_handle_pong (peer, message); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT: + GST_neighbours_handle_connect (message, peer, &address, session, ats, + ats_count); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK: + GST_neighbours_handle_connect_ack (message, peer, &address, session, ats, + ats_count); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK: + GST_neighbours_handle_ack (message, peer, &address, session, ats, + ats_count); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT: + GST_neighbours_handle_disconnect_message (peer, message); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE: + GST_neighbours_keepalive (peer); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE: + GST_neighbours_keepalive_response (peer, ats, ats_count); + break; + default: + /* should be payload */ + ret = process_payload (peer, &address, session, message, ats, ats_count); + break; + } +end: +#if 1 + /* FIXME: this should not be needed, and not sure it's good to have it, but without + * this connections seem to go extra-slow */ + GNUNET_ATS_address_update (GST_ats, &address, session, ats, ats_count); +#endif +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Allowing receive from peer %s to continue in %llu ms\n", + GNUNET_i2s (peer), (unsigned long long) ret.rel_value); +#endif + return ret; +} + + +/** + * Function that will be called for each address the transport + * is aware that it might be reachable under. Update our HELLO. + * + * @param cls name of the plugin (const char*) + * @param add_remove should the address added (YES) or removed (NO) from the + * set of valid addresses? + * @param addr one of the addresses of the host + * the specific address format depends on the transport + * @param addrlen length of the address + */ +static void +plugin_env_address_change_notification (void *cls, int add_remove, + const void *addr, size_t addrlen) +{ + const char *plugin_name = cls; + struct GNUNET_HELLO_Address address; + + address.peer = GST_my_identity; + address.transport_name = plugin_name; + address.address = addr; + address.address_length = addrlen; + GST_hello_modify_addresses (add_remove, &address); +} + + +/** + * Function that will be called whenever the plugin internally + * cleans up a session pointer and hence the service needs to + * discard all of those sessions as well. Plugins that do not + * use sessions can simply omit calling this function and always + * use NULL wherever a session pointer is needed. This function + * should be called BEFORE a potential "TransmitContinuation" + * from the "TransmitFunction". + * + * @param cls closure + * @param peer which peer was the session for + * @param session which session is being destoyed + */ +static void +plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, + struct Session *session) +{ + const char *transport_name = cls; + struct GNUNET_HELLO_Address address; + + GNUNET_assert (strlen (transport_name) > 0); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %X to peer `%s' ended \n", + session, GNUNET_i2s (peer)); +#endif + if (NULL != session) + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, + "transport-ats", + "Telling ATS to destroy session %p from peer %s\n", + session, GNUNET_i2s (peer)); + address.peer = *peer; + address.address = NULL; + address.address_length = 0; + address.transport_name = transport_name; + GST_neighbours_session_terminated (peer, session); + GNUNET_ATS_address_destroyed (GST_ats, &address, session); +} + + +/** + * Function that will be called to figure if an address is an loopback, + * LAN, WAN etc. address + * + * @param cls closure + * @param addr binary address + * @param addrlen length of the address + * @return ATS Information containing the network type + */ +static const struct GNUNET_ATS_Information +plugin_env_address_to_type (void *cls, + const struct sockaddr *addr, + size_t addrlen) +{ + struct GNUNET_ATS_Information ats; + ats.type = htonl (GNUNET_ATS_NETWORK_TYPE); + ats.value = htonl (GNUNET_ATS_NET_UNSPECIFIED); + if (GST_ats == NULL) + { + GNUNET_break (0); + return ats; + } + if (((addr->sa_family != AF_INET) && (addrlen != sizeof (struct sockaddr_in))) && + ((addr->sa_family != AF_INET6) && (addrlen != sizeof (struct sockaddr_in6))) && + (addr->sa_family != AF_UNIX)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed address with length %u `%s'\n", + addrlen, + GNUNET_a2s(addr, addrlen)); + GNUNET_break (0); + return (const struct GNUNET_ATS_Information) ats; + } + return GNUNET_ATS_address_get_type(GST_ats, addr, addrlen); +} + + +/** + * Function called by ATS to notify the callee that the + * assigned bandwidth or address for a given peer was changed. If the + * callback is called with address/bandwidth assignments of zero, the + * ATS disconnect function will still be called once the disconnect + * actually happened. + * + * @param cls closure + * @param address address to use (for peer given in address) + * @param session session to use (if available) + * @param bandwidth_out assigned outbound bandwidth for the connection, 0 to disconnect from peer + * @param bandwidth_in assigned inbound bandwidth for the connection, 0 to disconnect from peer + * @param ats ATS information + * @param ats_count number of ATS elements + */ +static void +ats_request_address_change (void *cls, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) +{ + uint32_t bw_in = ntohl (bandwidth_in.value__); + uint32_t bw_out = ntohl (bandwidth_out.value__); + + /* ATS tells me to disconnect from peer */ + if ((bw_in == 0) && (bw_out == 0)) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "ATS tells me to disconnect from peer `%s'\n", + GNUNET_i2s (&address->peer)); +#endif + GST_neighbours_force_disconnect (&address->peer); + return; + } + /* will never return GNUNET_YES since connection is to be established */ + GST_neighbours_switch_to_address (&address->peer, address, session, ats, + ats_count, bandwidth_in, + bandwidth_out); +} + + +/** + * Function called to notify transport users that another + * peer connected to us. + * + * @param cls closure + * @param peer the peer that connected + * @param ats performance data + * @param ats_count number of entries in ats + */ +static void +neighbours_connect_notification (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) +{ + size_t len = + sizeof (struct ConnectInfoMessage) + + ats_count * sizeof (struct GNUNET_ATS_Information); + char buf[len]; + struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf; + struct GNUNET_ATS_Information *ap; + + connect_msg->header.size = htons (sizeof (buf)); + connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT); + connect_msg->ats_count = htonl (ats_count); + connect_msg->id = *peer; + ap = (struct GNUNET_ATS_Information *) &connect_msg[1]; + memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information)); + GST_clients_broadcast (&connect_msg->header, GNUNET_NO); +} + + +/** + * Function called to notify transport users that another + * peer disconnected from us. + * + * @param cls closure + * @param peer the peer that disconnected + */ +static void +neighbours_disconnect_notification (void *cls, + const struct GNUNET_PeerIdentity *peer) +{ + struct DisconnectInfoMessage disconnect_msg; + + disconnect_msg.header.size = htons (sizeof (struct DisconnectInfoMessage)); + disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT); + disconnect_msg.reserved = htonl (0); + disconnect_msg.peer = *peer; + GST_clients_broadcast (&disconnect_msg.header, GNUNET_NO); +} + + +/** + * Function called to notify transport users that a neighbour peer changed its + * active address. + * + * @param cls closure + * @param peer peer this update is about (never NULL) + * @param address address, NULL on disconnect + */ +static void +neighbours_address_notification (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address) +{ + GST_clients_broadcast_address_notification (peer, address); +} + + +/** + * Function called when the service shuts down. Unloads our plugins + * and cancels pending validations. + * + * @param cls closure, unused + * @param tc task context (unused) + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GST_neighbours_stop (); + GST_validation_stop (); + GST_plugins_unload (); + + GNUNET_ATS_scheduling_done (GST_ats); + GST_ats = NULL; + GST_clients_stop (); + GST_blacklist_stop (); + GST_hello_stop (); + + if (GST_peerinfo != NULL) + { + GNUNET_PEERINFO_disconnect (GST_peerinfo); + GST_peerinfo = NULL; + } + if (GST_stats != NULL) + { + GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO); + GST_stats = NULL; + } + if (GST_my_private_key != NULL) + { + GNUNET_CRYPTO_rsa_key_free (GST_my_private_key); + GST_my_private_key = NULL; + } +} + + +/** + * Initiate transport service. + * + * @param cls closure + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + char *keyfile; + + /* setup globals */ + GST_cfg = c; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY", + &keyfile)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Transport service is lacking key configuration settings. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + GST_my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_free (keyfile); + if (GST_my_private_key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Transport service could not access hostkey. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + GST_stats = GNUNET_STATISTICS_create ("transport", c); + GST_peerinfo = GNUNET_PEERINFO_connect (c); + GNUNET_CRYPTO_rsa_key_get_public (GST_my_private_key, &GST_my_public_key); + GNUNET_CRYPTO_hash (&GST_my_public_key, sizeof (GST_my_public_key), + &GST_my_identity.hashPubKey); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + if (GST_peerinfo == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access PEERINFO service. Exiting.\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } + + /* start subsystems */ + GST_hello_start (&process_hello_update, NULL); + GST_blacklist_start (server); + GST_ats = + GNUNET_ATS_scheduling_init (GST_cfg, &ats_request_address_change, NULL); + GST_plugins_load (&plugin_env_receive_callback, + &plugin_env_address_change_notification, + &plugin_env_session_end, + &plugin_env_address_to_type); + GST_neighbours_start (NULL, + &neighbours_connect_notification, + &neighbours_disconnect_notification, + &neighbours_address_notification); + GST_clients_start (server); + GST_validation_start (); +} + + +/** + * The main function for the transport service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "transport", + GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; +} + +/* end of file gnunet-service-transport-new.c */ diff --git a/src/transport/gnunet-service-transport.h b/src/transport/gnunet-service-transport.h new file mode 100644 index 0000000..adc28ba --- /dev/null +++ b/src/transport/gnunet-service-transport.h @@ -0,0 +1,72 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport.h + * @brief globals + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_TRANSPORT_H +#define GNUNET_SERVICE_TRANSPORT_H + +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_util_lib.h" + +#define VERBOSE_VALIDATION GNUNET_YES + +/** + * Statistics handle. + */ +extern struct GNUNET_STATISTICS_Handle *GST_stats; + +/** + * Configuration handle. + */ +extern const struct GNUNET_CONFIGURATION_Handle *GST_cfg; + +/** + * Configuration handle. + */ +extern struct GNUNET_PeerIdentity GST_my_identity; + +/** + * Handle to peerinfo service. + */ +extern struct GNUNET_PEERINFO_Handle *GST_peerinfo; + +/** + * Our public key. + */ +extern struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key; + +/** + * Our private key. + */ +extern struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key; + +/** + * ATS handle. + */ +extern struct GNUNET_ATS_SchedulingHandle *GST_ats; + + +#endif +/* end of file gnunet-service-transport_plugins.h */ diff --git a/src/transport/gnunet-service-transport_blacklist.c b/src/transport/gnunet-service-transport_blacklist.c new file mode 100644 index 0000000..2089949 --- /dev/null +++ b/src/transport/gnunet-service-transport_blacklist.c @@ -0,0 +1,822 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_blacklist.c + * @brief blacklisting implementation + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-transport.h" +#include "gnunet-service-transport_blacklist.h" +#include "gnunet-service-transport_neighbours.h" +#include "transport.h" + + +/** + * Size of the blacklist hash map. + */ +#define TRANSPORT_BLACKLIST_HT_SIZE 64 + + +/** + * Context we use when performing a blacklist check. + */ +struct GST_BlacklistCheck; + + +/** + * Information kept for each client registered to perform + * blacklisting. + */ +struct Blacklisters +{ + /** + * This is a linked list. + */ + struct Blacklisters *next; + + /** + * This is a linked list. + */ + struct Blacklisters *prev; + + /** + * Client responsible for this entry. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Blacklist check that we're currently performing (or NULL + * if we're performing one that has been cancelled). + */ + struct GST_BlacklistCheck *bc; + + /** + * Set to GNUNET_YES if we're currently waiting for a reply. + */ + int waiting_for_reply; + +}; + + + +/** + * Context we use when performing a blacklist check. + */ +struct GST_BlacklistCheck +{ + + /** + * This is a linked list. + */ + struct GST_BlacklistCheck *next; + + /** + * This is a linked list. + */ + struct GST_BlacklistCheck *prev; + + /** + * Peer being checked. + */ + struct GNUNET_PeerIdentity peer; + + /** + * Continuation to call with the result. + */ + GST_BlacklistTestContinuation cont; + + /** + * Closure for cont. + */ + void *cont_cls; + + /** + * Current transmission request handle for this client, or NULL if no + * request is pending. + */ + struct GNUNET_CONNECTION_TransmitHandle *th; + + /** + * Our current position in the blacklisters list. + */ + struct Blacklisters *bl_pos; + + /** + * Current task performing the check. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + +}; + + +/** + * Head of DLL of active blacklisting queries. + */ +static struct GST_BlacklistCheck *bc_head; + +/** + * Tail of DLL of active blacklisting queries. + */ +static struct GST_BlacklistCheck *bc_tail; + +/** + * Head of DLL of blacklisting clients. + */ +static struct Blacklisters *bl_head; + +/** + * Tail of DLL of blacklisting clients. + */ +static struct Blacklisters *bl_tail; + +/** + * Hashmap of blacklisted peers. Values are of type 'char *' (transport names), + * can be NULL if we have no static blacklist. + */ +static struct GNUNET_CONTAINER_MultiHashMap *blacklist; + + +/** + * Perform next action in the blacklist check. + * + * @param cls the 'struct BlacklistCheck*' + * @param tc unused + */ +static void +do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Called whenever a client is disconnected. Frees our + * resources associated with that client. + * + * @param cls closure (unused) + * @param client identification of the client + */ +static void +client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct Blacklisters *bl; + struct GST_BlacklistCheck *bc; + + if (client == NULL) + return; + for (bl = bl_head; bl != NULL; bl = bl->next) + { + if (bl->client != client) + continue; + for (bc = bc_head; bc != NULL; bc = bc->next) + { + if (bc->bl_pos != bl) + continue; + bc->bl_pos = bl->next; + if (bc->th != NULL) + { + GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th); + bc->th = NULL; + } + if (bc->task == GNUNET_SCHEDULER_NO_TASK) + bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); + break; + } + GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl); + GNUNET_SERVER_client_drop (bl->client); + GNUNET_free (bl); + break; + } +} + + +/** + * Read the blacklist file, containing transport:peer entries. + * Provided the transport is loaded, set up hashmap with these + * entries to blacklist peers by transport. + * + */ +static void +read_blacklist_file () +{ + char *fn; + char *data; + size_t pos; + size_t colon_pos; + int tsize; + struct GNUNET_PeerIdentity pid; + struct stat frstat; + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + unsigned int entries_found; + char *transport_name; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (GST_cfg, "TRANSPORT", + "BLACKLIST_FILE", &fn)) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Option `%s' in section `%s' not specified!\n", + "BLACKLIST_FILE", "TRANSPORT"); +#endif + return; + } + if (GNUNET_OK != GNUNET_DISK_file_test (fn)) + GNUNET_DISK_fn_write (fn, NULL, 0, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (0 != STAT (fn, &frstat)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not read blacklist file `%s'\n"), fn); + GNUNET_free (fn); + return; + } + if (frstat.st_size == 0) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Blacklist file `%s' is empty.\n"), + fn); +#endif + GNUNET_free (fn); + return; + } + /* FIXME: use mmap */ + data = GNUNET_malloc_large (frstat.st_size); + GNUNET_assert (data != NULL); + if (frstat.st_size != GNUNET_DISK_fn_read (fn, data, frstat.st_size)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to read blacklist from `%s'\n"), fn); + GNUNET_free (fn); + GNUNET_free (data); + return; + } + entries_found = 0; + pos = 0; + while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos])) + pos++; + while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) && + (pos <= + frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))) + { + colon_pos = pos; + while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && + (!isspace ((unsigned char) data[colon_pos]))) + colon_pos++; + if (colon_pos >= frstat.st_size) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Syntax error in blacklist file at offset %llu, giving up!\n"), + (unsigned long long) colon_pos); + GNUNET_free (fn); + GNUNET_free (data); + return; + } + + if (isspace ((unsigned char) data[colon_pos])) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"), + (unsigned long long) colon_pos); + pos = colon_pos; + while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos])) + pos++; + continue; + } + tsize = colon_pos - pos; + if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || + (tsize == 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Syntax error in blacklist file at offset %llu, giving up!\n"), + (unsigned long long) colon_pos); + GNUNET_free (fn); + GNUNET_free (data); + return; + } + + if (tsize < 1) + continue; + + transport_name = GNUNET_malloc (tsize + 1); + memcpy (transport_name, &data[pos], tsize); + pos = colon_pos + 1; +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Read transport name `%s' in blacklist file.\n", + transport_name); +#endif + memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + if (!isspace + ((unsigned char) + enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1])) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"), + (unsigned long long) pos); + pos++; + while ((pos < frstat.st_size) && (!isspace ((unsigned char) data[pos]))) + pos++; + GNUNET_free_non_null (transport_name); + continue; + } + enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + if (GNUNET_OK != + GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"), + (unsigned long long) pos, &enc); + } + else + { + if (0 != + memcmp (&pid, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity))) + { + entries_found++; + GST_blacklist_add_peer (&pid, transport_name); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Found myself `%s' in blacklist (useless, ignored)\n"), + GNUNET_i2s (&pid)); + } + } + pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded); + GNUNET_free_non_null (transport_name); + while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos])) + pos++; + } + GNUNET_STATISTICS_update (GST_stats, "# Transport entries blacklisted", + entries_found, GNUNET_NO); + GNUNET_free (data); + GNUNET_free (fn); +} + + +/** + * Start blacklist subsystem. + * + * @param server server used to accept clients from + */ +void +GST_blacklist_start (struct GNUNET_SERVER_Handle *server) +{ + read_blacklist_file (); + GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification, + NULL); +} + + +/** + * Free the given entry in the blacklist. + * + * @param cls unused + * @param key host identity (unused) + * @param value the blacklist entry + * @return GNUNET_OK (continue to iterate) + */ +static int +free_blacklist_entry (void *cls, const GNUNET_HashCode * key, void *value) +{ + char *be = value; + + GNUNET_free (be); + return GNUNET_OK; +} + + +/** + * Stop blacklist subsystem. + */ +void +GST_blacklist_stop () +{ + if (NULL != blacklist) + { + GNUNET_CONTAINER_multihashmap_iterate (blacklist, &free_blacklist_entry, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (blacklist); + blacklist = NULL; + } +} + + +/** + * Transmit blacklist query to the client. + * + * @param cls the 'struct GST_BlacklistCheck' + * @param size number of bytes allowed + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +transmit_blacklist_message (void *cls, size_t size, void *buf) +{ + struct GST_BlacklistCheck *bc = cls; + struct Blacklisters *bl; + struct BlacklistMessage bm; + + bc->th = NULL; + if (size == 0) + { + GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK); + bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to send blacklist test for peer `%s' to client\n", + GNUNET_i2s (&bc->peer)); + return 0; + } +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending blacklist test for peer `%s' to client\n", + GNUNET_i2s (&bc->peer)); +#endif + bl = bc->bl_pos; + bm.header.size = htons (sizeof (struct BlacklistMessage)); + bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY); + bm.is_allowed = htonl (0); + bm.peer = bc->peer; + memcpy (buf, &bm, sizeof (bm)); + GNUNET_SERVER_receive_done (bl->client, GNUNET_OK); + bl->waiting_for_reply = GNUNET_YES; + return sizeof (bm); +} + + +/** + * Perform next action in the blacklist check. + * + * @param cls the 'struct GST_BlacklistCheck*' + * @param tc unused + */ +static void +do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GST_BlacklistCheck *bc = cls; + struct Blacklisters *bl; + + bc->task = GNUNET_SCHEDULER_NO_TASK; + bl = bc->bl_pos; + if (bl == NULL) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No other blacklist clients active, will allow neighbour `%s'\n", + GNUNET_i2s (&bc->peer)); +#endif + bc->cont (bc->cont_cls, &bc->peer, GNUNET_OK); + GNUNET_CONTAINER_DLL_remove(bc_head, bc_tail, bc); + GNUNET_free (bc); + return; + } + if ((bl->bc != NULL) || (bl->waiting_for_reply != GNUNET_NO)) + return; /* someone else busy with this client */ + bl->bc = bc; + bc->th = + GNUNET_SERVER_notify_transmit_ready (bl->client, + sizeof (struct BlacklistMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_blacklist_message, bc); +} + + +/** + * Got the result about an existing connection from a new blacklister. + * Shutdown the neighbour if necessary. + * + * @param cls unused + * @param peer the neighbour that was investigated + * @param allowed GNUNET_OK if we can keep it, + * GNUNET_NO if we must shutdown the connection + */ +static void +confirm_or_drop_neighbour (void *cls, const struct GNUNET_PeerIdentity *peer, + int allowed) +{ + if (GNUNET_OK == allowed) + return; /* we're done */ + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# disconnects due to blacklist"), 1, + GNUNET_NO); + GST_neighbours_force_disconnect (peer); +} + + +/** + * Closure for 'test_connection_ok'. + */ +struct TestConnectionContext +{ + /** + * Is this the first neighbour we're checking? + */ + int first; + + /** + * Handle to the blacklisting client we need to ask. + */ + struct Blacklisters *bl; +}; + + +/** + * Test if an existing connection is still acceptable given a new + * blacklisting client. + * + * @param cls the 'struct TestConnectionContest' + * @param neighbour neighbour's identity + * @param ats performance data + * @param ats_count number of entries in ats (excluding 0-termination) + * @param address the address + */ +static void +test_connection_ok (void *cls, const struct GNUNET_PeerIdentity *neighbour, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count, + const struct GNUNET_HELLO_Address *address) +{ + struct TestConnectionContext *tcc = cls; + struct GST_BlacklistCheck *bc; + + bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck)); + GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc); + bc->peer = *neighbour; + bc->cont = &confirm_or_drop_neighbour; + bc->cont_cls = NULL; + bc->bl_pos = tcc->bl; + if (GNUNET_YES == tcc->first) + { + /* all would wait for the same client, no need to + * create more than just the first task right now */ + bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); + tcc->first = GNUNET_NO; + } +} + + + +/** + * Initialize a blacklisting client. We got a blacklist-init + * message from this client, add him to the list of clients + * to query for blacklisting. + * + * @param cls unused + * @param client the client + * @param message the blacklist-init message that was sent + */ +void +GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct Blacklisters *bl; + struct TestConnectionContext tcc; + + bl = bl_head; + while (bl != NULL) + { + if (bl->client == client) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + bl = bl->next; + } + bl = GNUNET_malloc (sizeof (struct Blacklisters)); + bl->client = client; + GNUNET_SERVER_client_keep (client); + GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl); + + /* confirm that all existing connections are OK! */ + tcc.bl = bl; + tcc.first = GNUNET_YES; + GST_neighbours_iterate (&test_connection_ok, &tcc); +} + + +/** + * A blacklisting client has sent us reply. Process it. + * + * @param cls unused + * @param client the client + * @param message the blacklist-init message that was sent + */ +void +GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct BlacklistMessage *msg = + (const struct BlacklistMessage *) message; + struct Blacklisters *bl; + struct GST_BlacklistCheck *bc; + + bl = bl_head; + while ((bl != NULL) && (bl->client != client)) + bl = bl->next; + if (bl == NULL) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n"); +#endif + /* FIXME: other error handling here!? */ + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + bc = bl->bc; + bl->bc = NULL; + bl->waiting_for_reply = GNUNET_NO; + if (NULL != bc) + { + /* only run this if the blacklist check has not been + * cancelled in the meantime... */ + if (ntohl (msg->is_allowed) == GNUNET_SYSERR) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklist check failed, peer not allowed\n"); +#endif + bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc); + GNUNET_free (bc); + } + else + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklist check succeeded, continuing with checks\n"); +#endif + bc->bl_pos = bc->bl_pos->next; + bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); + } + } + /* check if any other bc's are waiting for this blacklister */ + bc = bc_head; + for (bc = bc_head; bc != NULL; bc = bc->next) + if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task)) + { + bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); + break; + } +} + + +/** + * Add the given peer to the blacklist (for the given transport). + * + * @param peer peer to blacklist + * @param transport_name transport to blacklist for this peer, NULL for all + */ +void +GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer, + const char *transport_name) +{ +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding peer `%s' with plugin `%s' to blacklist\n", + GNUNET_i2s (peer), transport_name); +#endif + if (blacklist == NULL) + blacklist = + GNUNET_CONTAINER_multihashmap_create (TRANSPORT_BLACKLIST_HT_SIZE); + GNUNET_CONTAINER_multihashmap_put (blacklist, &peer->hashPubKey, + GNUNET_strdup (transport_name), + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); +} + + +/** + * Test if the given blacklist entry matches. If so, + * abort the iteration. + * + * @param cls the transport name to match (const char*) + * @param key the key (unused) + * @param value the 'char *' (name of a blacklisted transport) + * @return GNUNET_OK if the entry does not match, GNUNET_NO if it matches + */ +static int +test_blacklisted (void *cls, const GNUNET_HashCode * key, void *value) +{ + const char *transport_name = cls; + char *be = value; + + /* blacklist check for specific no specific transport*/ + if (transport_name == NULL) + return GNUNET_NO; + + /* blacklist check for specific transport */ + if (0 == strcmp (transport_name, be)) + return GNUNET_NO; /* abort iteration! */ + return GNUNET_OK; +} + + +/** + * Test if a peer/transport combination is blacklisted. + * + * @param peer the identity of the peer to test + * @param transport_name name of the transport to test, never NULL + * @param cont function to call with result + * @param cont_cls closure for 'cont' + * @return handle to the blacklist check, NULL if the decision + * was made instantly and 'cont' was already called + */ +struct GST_BlacklistCheck * +GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer, + const char *transport_name, + GST_BlacklistTestContinuation cont, void *cont_cls) +{ + struct GST_BlacklistCheck *bc; + + GNUNET_assert (peer != NULL); + + if ((blacklist != NULL) && + (GNUNET_SYSERR == + GNUNET_CONTAINER_multihashmap_get_multiple (blacklist, &peer->hashPubKey, + &test_blacklisted, + (void *) transport_name))) + { + /* disallowed by config, disapprove instantly */ + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# disconnects due to blacklist"), + 1, GNUNET_NO); + if (cont != NULL) + cont (cont_cls, peer, GNUNET_NO); + return NULL; + } + + if (bl_head == NULL) + { + /* no blacklist clients, approve instantly */ + if (cont != NULL) + cont (cont_cls, peer, GNUNET_OK); + return NULL; + } + + /* need to query blacklist clients */ + bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck)); + GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc); + bc->peer = *peer; + bc->cont = cont; + bc->cont_cls = cont_cls; + bc->bl_pos = bl_head; + bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); + return bc; +} + + +/** + * Cancel a blacklist check. + * + * @param bc check to cancel + */ +void +GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc) +{ + GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc); + if (bc->bl_pos != NULL) + { + if (bc->bl_pos->bc == bc) + { + /* we're at the head of the queue, remove us! */ + bc->bl_pos->bc = NULL; + } + } + if (GNUNET_SCHEDULER_NO_TASK != bc->task) + { + GNUNET_SCHEDULER_cancel (bc->task); + bc->task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != bc->th) + { + GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th); + bc->th = NULL; + } + GNUNET_free (bc); +} + + +/* end of file gnunet-service-transport_blacklist.c */ diff --git a/src/transport/gnunet-service-transport_blacklist.h b/src/transport/gnunet-service-transport_blacklist.h new file mode 100644 index 0000000..68da7e4 --- /dev/null +++ b/src/transport/gnunet-service-transport_blacklist.h @@ -0,0 +1,127 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_blacklist.h + * @brief blacklisting API + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_TRANSPORT_BLACKLIST_H +#define GNUNET_SERVICE_TRANSPORT_BLACKLIST_H + +#include "gnunet_statistics_service.h" +#include "gnunet_util_lib.h" + +/** + * Start blacklist subsystem. + * + * @param server server used to accept clients from + */ +void +GST_blacklist_start (struct GNUNET_SERVER_Handle *server); + + +/** + * Stop blacklist subsystem. + */ +void +GST_blacklist_stop (void); + + +/** + * Initialize a blacklisting client. We got a blacklist-init + * message from this client, add him to the list of clients + * to query for blacklisting. + * + * @param cls unused + * @param client the client + * @param message the blacklist-init message that was sent + */ +void +GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + +/** + * A blacklisting client has sent us reply. Process it. + * + * @param cls unused + * @param client the client + * @param message the blacklist-init message that was sent + */ +void +GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + +/** + * Add the given peer to the blacklist (for the given transport). + * + * @param peer peer to blacklist + * @param transport_name transport to blacklist for this peer, NULL for all + */ +void +GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer, + const char *transport_name); + + +/** + * Handle to an active blacklist check. + */ +struct GST_BlacklistCheck; + + +/** + * Continuation called from a blacklist test. + * + * @param cls closure + * @param peer identity of peer that was tested + * @param result GNUNET_OK if the connection is allowed, + * GNUNET_NO if not + */ +typedef void (*GST_BlacklistTestContinuation) (void *cls, + const struct GNUNET_PeerIdentity + * peer, int result); + + +/** + * Test if a peer/transport combination is blacklisted. + * + * @param peer the identity of the peer to test + * @param transport_name name of the transport to test, never NULL + * @param cont function to call with result + * @param cont_cls closure for 'cont' + * @return handle to the blacklist check, NULL if the decision + * was made instantly and 'cont' was already called + */ +struct GST_BlacklistCheck * +GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer, + const char *transport_name, + GST_BlacklistTestContinuation cont, void *cont_cls); + + +/** + * Cancel a blacklist check. + * + * @param bc check to cancel + */ +void +GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc); + +#endif +/* end of file gnunet-service-transport_blacklist.h */ diff --git a/src/transport/gnunet-service-transport_clients.c b/src/transport/gnunet-service-transport_clients.c new file mode 100644 index 0000000..d6ff554 --- /dev/null +++ b/src/transport/gnunet-service-transport_clients.c @@ -0,0 +1,1057 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_clients.c + * @brief plugin management API + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-transport_blacklist.h" +#include "gnunet-service-transport_clients.h" +#include "gnunet-service-transport_hello.h" +#include "gnunet-service-transport_neighbours.h" +#include "gnunet-service-transport_plugins.h" +#include "gnunet-service-transport_validation.h" +#include "gnunet-service-transport.h" +#include "transport.h" + +/** + * How many messages can we have pending for a given client process + * before we start to drop incoming messages? We typically should + * have only one client and so this would be the primary buffer for + * messages, so the number should be chosen rather generously. + * + * The expectation here is that most of the time the queue is large + * enough so that a drop is virtually never required. Note that + * this value must be about as large as 'TOTAL_MSGS' in the + * 'test_transport_api_reliability.c', otherwise that testcase may + * fail. + */ +#define MAX_PENDING (128 * 1024) + + +/** + * Linked list of messages to be transmitted to the client. Each + * entry is followed by the actual message. + */ +struct ClientMessageQueueEntry +{ + /** + * This is a doubly-linked list. + */ + struct ClientMessageQueueEntry *next; + + /** + * This is a doubly-linked list. + */ + struct ClientMessageQueueEntry *prev; +}; + + +/** + * Client connected to the transport service. + */ +struct TransportClient +{ + + /** + * This is a doubly-linked list. + */ + struct TransportClient *next; + + /** + * This is a doubly-linked list. + */ + struct TransportClient *prev; + + /** + * Handle to the client. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Linked list of messages yet to be transmitted to + * the client. + */ + struct ClientMessageQueueEntry *message_queue_head; + + /** + * Tail of linked list of messages yet to be transmitted to the + * client. + */ + struct ClientMessageQueueEntry *message_queue_tail; + + /** + * Current transmit request handle. + */ + struct GNUNET_CONNECTION_TransmitHandle *th; + + /** + * Length of the list of messages pending for this client. + */ + unsigned int message_count; + + /** + * Is this client interested in payload messages? + */ + int send_payload; +}; + + +/** + * Client monitoring changes of active addresses of our neighbours. + */ +struct MonitoringClient +{ + /** + * This is a doubly-linked list. + */ + struct MonitoringClient *next; + + /** + * This is a doubly-linked list. + */ + struct MonitoringClient *prev; + + /** + * Handle to the client. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Peer identity to monitor the addresses of. + * Zero to monitor all neighrours. + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Head of linked list of all clients to this service. + */ +static struct TransportClient *clients_head; + +/** + * Tail of linked list of all clients to this service. + */ +static struct TransportClient *clients_tail; + +/** + * Head of linked list of monitoring clients. + */ +static struct MonitoringClient *monitoring_clients_head; + +/** + * Tail of linked list of monitoring clients. + */ +static struct MonitoringClient *monitoring_clients_tail; + +/** + * Notification context, to send updates on changes to active addresses + * of our neighbours. + */ +struct GNUNET_SERVER_NotificationContext *nc = NULL; + + +/** + * Find the internal handle associated with the given client handle + * + * @param client server's client handle to look up + * @return internal client handle + */ +static struct TransportClient * +lookup_client (struct GNUNET_SERVER_Client *client) +{ + struct TransportClient *tc; + + tc = clients_head; + while (tc != NULL) + { + if (tc->client == client) + return tc; + tc = tc->next; + } + return NULL; +} + + +/** + * Create the internal handle for the given server client handle + * + * @param client server's client handle to create our internal handle for + * @return fresh internal client handle + */ +static struct TransportClient * +setup_client (struct GNUNET_SERVER_Client *client) +{ + struct TransportClient *tc; + + GNUNET_assert (lookup_client (client) == NULL); + tc = GNUNET_malloc (sizeof (struct TransportClient)); + tc->client = client; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc); +#endif + return tc; +} + + +/** + * Find the handle to the monitoring client associated with the given + * client handle + * + * @param client server's client handle to look up + * @return handle to the monitoring client + */ +static struct MonitoringClient * +lookup_monitoring_client (struct GNUNET_SERVER_Client *client) +{ + struct MonitoringClient *mc; + + mc = monitoring_clients_head; + while (mc != NULL) + { + if (mc->client == client) + return mc; + mc = mc->next; + } + return NULL; +} + + +/** + * Setup a new monitoring client using the given server client handle and + * the peer identity. + * + * @param client server's client handle to create our internal handle for + * @param peer identity of the peer to monitor the addresses of, + * zero to monitor all neighrours. + * @return handle to the new monitoring client + */ +static struct MonitoringClient * +setup_monitoring_client (struct GNUNET_SERVER_Client *client, + struct GNUNET_PeerIdentity *peer) +{ + struct MonitoringClient *mc; + + GNUNET_assert (lookup_monitoring_client (client) == NULL); + mc = GNUNET_malloc (sizeof (struct MonitoringClient)); + mc->client = client; + mc->peer = *peer; + GNUNET_CONTAINER_DLL_insert (monitoring_clients_head, + monitoring_clients_tail, + mc); + GNUNET_SERVER_notification_context_add (nc, client); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client %p started monitoring of the peer `%s'\n", + mc, GNUNET_i2s (peer)); + return mc; +} + + +/** + * Function called to notify a client about the socket being ready to + * queue more data. "buf" will be NULL and "size" zero if the socket + * was closed for writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_to_client_callback (void *cls, size_t size, void *buf) +{ + struct TransportClient *tc = cls; + struct ClientMessageQueueEntry *q; + const struct GNUNET_MessageHeader *msg; + char *cbuf; + uint16_t msize; + size_t tsize; + + tc->th = NULL; + if (buf == NULL) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmission to client failed, closing connection.\n"); +#endif + return 0; + } + cbuf = buf; + tsize = 0; + while (NULL != (q = tc->message_queue_head)) + { + msg = (const struct GNUNET_MessageHeader *) &q[1]; + msize = ntohs (msg->size); + if (msize + tsize > size) + break; +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting message of type %u to client %p.\n", + ntohs (msg->type), tc); +#endif + GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, tc->message_queue_tail, + q); + tc->message_count--; + memcpy (&cbuf[tsize], msg, msize); + GNUNET_free (q); + tsize += msize; + } + if (NULL != q) + { + GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); + tc->th = + GNUNET_SERVER_notify_transmit_ready (tc->client, msize, + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_to_client_callback, tc); + GNUNET_assert (tc->th != NULL); + } + return tsize; +} + + +/** + * Queue the given message for transmission to the given client + * + * @param tc target of the message + * @param msg message to transmit + * @param may_drop GNUNET_YES if the message can be dropped + */ +static void +unicast (struct TransportClient *tc, const struct GNUNET_MessageHeader *msg, + int may_drop) +{ + struct ClientMessageQueueEntry *q; + uint16_t msize; + + if ((tc->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Dropping message of type %u and size %u, have %u/%u messages pending\n"), + ntohs (msg->type), ntohs (msg->size), tc->message_count, + MAX_PENDING); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# messages dropped due to slow client"), 1, + GNUNET_NO); + return; + } + msize = ntohs (msg->size); + GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); + q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize); + memcpy (&q[1], msg, msize); + GNUNET_CONTAINER_DLL_insert_tail (tc->message_queue_head, + tc->message_queue_tail, q); + tc->message_count++; + if (tc->th != NULL) + return; + tc->th = + GNUNET_SERVER_notify_transmit_ready (tc->client, msize, + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_to_client_callback, tc); + GNUNET_assert (tc->th != NULL); +} + + +/** + * Called whenever a client is disconnected. Frees our + * resources associated with that client. + * + * @param cls closure + * @param client identification of the client + */ +static void +client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct TransportClient *tc; + struct MonitoringClient *mc; + struct ClientMessageQueueEntry *mqe; + + if (client == NULL) + return; + mc = lookup_monitoring_client (client); + if (mc != NULL) + { + GNUNET_CONTAINER_DLL_remove (monitoring_clients_head, + monitoring_clients_tail, + mc); + GNUNET_free (mc); + } + tc = lookup_client (client); + if (tc == NULL) + return; +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Client %p disconnected, cleaning up.\n", tc); +#endif + while (NULL != (mqe = tc->message_queue_head)) + { + GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, tc->message_queue_tail, + mqe); + tc->message_count--; + GNUNET_free (mqe); + } + GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc); + if (tc->th != NULL) + { + GNUNET_CONNECTION_notify_transmit_ready_cancel (tc->th); + tc->th = NULL; + } + GNUNET_break (0 == tc->message_count); + GNUNET_free (tc); +} + + +/** + * Function called for each of our connected neighbours. Notify the + * client about the existing neighbour. + * + * @param cls the 'struct TransportClient' to notify + * @param peer identity of the neighbour + * @param ats performance data + * @param ats_count number of entries in ats (excluding 0-termination) + * @param address the address + */ +static void +notify_client_about_neighbour (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count, + const struct GNUNET_HELLO_Address *address) +{ + struct TransportClient *tc = cls; + struct ConnectInfoMessage *cim; + struct GNUNET_ATS_Information *ap; + size_t size = + sizeof (struct ConnectInfoMessage) + + ats_count * sizeof (struct GNUNET_ATS_Information); + char buf[size]; + + GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); + cim = (struct ConnectInfoMessage *) buf; + cim->header.size = htons (size); + cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT); + cim->ats_count = htonl (ats_count); + cim->id = *peer; + ap = (struct GNUNET_ATS_Information *) &cim[1]; + memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information)); + unicast (tc, &cim->header, GNUNET_NO); +} + + +/** + * Initialize a normal client. We got a start message from this + * client, add him to the list of clients for broadcasting of inbound + * messages. + * + * @param cls unused + * @param client the client + * @param message the start message that was sent + */ +static void +clients_handle_start (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct StartMessage *start; + struct TransportClient *tc; + uint32_t options; + + tc = lookup_client (client); + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Client %p sent START\n", tc); +#endif + if (tc != NULL) + { + /* got 'start' twice from the same client, not allowed */ +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "TransportClient %p ServerClient %p sent multiple START messages\n", + tc, tc->client); +#endif + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + start = (const struct StartMessage *) message; + options = ntohl (start->options); + if ((0 != (1 & options)) && + (0 != + memcmp (&start->self, &GST_my_identity, + sizeof (struct GNUNET_PeerIdentity)))) + { + /* client thinks this is a different peer, reject */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Rejecting control connection from peer `%s', which is not me!\n"), + GNUNET_i2s (&start->self)); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + tc = setup_client (client); + tc->send_payload = (0 != (2 & options)); + unicast (tc, GST_hello_get (), GNUNET_NO); + GST_neighbours_iterate (¬ify_client_about_neighbour, tc); + GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Client sent us a HELLO. Process the request. + * + * @param cls unused + * @param client the client + * @param message the HELLO message + */ +static void +clients_handle_hello (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + GST_validation_handle_hello (message); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Closure for 'handle_send_transmit_continuation' + */ +struct SendTransmitContinuationContext +{ + /** + * Client that made the request. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Peer that was the target. + */ + struct GNUNET_PeerIdentity target; +}; + + +/** + * Function called after the transmission is done. Notify the client that it is + * OK to send the next message. + * + * @param cls closure + * @param success GNUNET_OK on success, GNUNET_NO on failure, GNUNET_SYSERR if we're not connected + */ +static void +handle_send_transmit_continuation (void *cls, int success) +{ + struct SendTransmitContinuationContext *stcc = cls; + struct SendOkMessage send_ok_msg; + + send_ok_msg.header.size = htons (sizeof (send_ok_msg)); + send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK); + send_ok_msg.success = htonl (success); + send_ok_msg.latency = + GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL); + send_ok_msg.peer = stcc->target; + GST_clients_unicast (stcc->client, &send_ok_msg.header, GNUNET_NO); + GNUNET_SERVER_client_drop (stcc->client); + GNUNET_free (stcc); +} + + +/** + * Client asked for transmission to a peer. Process the request. + * + * @param cls unused + * @param client the client + * @param message the send message that was sent + */ +static void +clients_handle_send (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct OutboundMessage *obm; + const struct GNUNET_MessageHeader *obmm; + struct SendTransmitContinuationContext *stcc; + uint16_t size; + uint16_t msize; + struct TransportClient *tc; + + tc = lookup_client (client); + if (NULL == tc) + { + /* client asked for transmission before 'START' */ + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + size = ntohs (message->size); + if (size < + sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + obm = (const struct OutboundMessage *) message; + obmm = (const struct GNUNET_MessageHeader *) &obm[1]; + msize = size - sizeof (struct OutboundMessage); + if (msize < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# bytes payload received for other peers"), msize, + GNUNET_NO); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received `%s' request from client with target `%4s' and first message of type %u and total size %u\n", + "SEND", GNUNET_i2s (&obm->peer), ntohs (obmm->type), msize); +#endif + if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer)) + { + /* not connected, not allowed to send; can happen due to asynchronous operations */ +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Could not send message to peer `%s': not connected\n", + GNUNET_i2s (&obm->peer)); +#endif + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# bytes payload dropped (other peer was not connected)"), + msize, GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + GNUNET_SERVER_receive_done (client, GNUNET_OK); + stcc = GNUNET_malloc (sizeof (struct SendTransmitContinuationContext)); + stcc->target = obm->peer; + stcc->client = client; + GNUNET_SERVER_client_keep (client); + GST_neighbours_send (&obm->peer, obmm, msize, + GNUNET_TIME_relative_ntoh (obm->timeout), + &handle_send_transmit_continuation, stcc); +} + + +/** + * Try to initiate a connection to the given peer if the blacklist + * allowed it. + * + * @param cls closure (unused, NULL) + * @param peer identity of peer that was tested + * @param result GNUNET_OK if the connection is allowed, + * GNUNET_NO if not + */ +static void +try_connect_if_allowed (void *cls, const struct GNUNET_PeerIdentity *peer, + int result) +{ + if (GNUNET_OK != result) + return; /* not allowed */ + GST_neighbours_try_connect (peer); +} + + +/** + * Handle request connect message + * + * @param cls closure (always NULL) + * @param client identification of the client + * @param message the actual message + */ +static void +clients_handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct TransportRequestConnectMessage *trcm = + (const struct TransportRequestConnectMessage *) message; + + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# REQUEST CONNECT messages received"), 1, + GNUNET_NO); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received a request connect message for peer `%s'\n", + GNUNET_i2s (&trcm->peer)); +#endif + (void) GST_blacklist_test_allowed (&trcm->peer, NULL, &try_connect_if_allowed, + NULL); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Take the given address and append it to the set of results sent back to + * the client. + * + * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*') + * @param buf text to transmit + */ +static void +transmit_address_to_client (void *cls, const char *buf) +{ + struct GNUNET_SERVER_TransmitContext *tc = cls; + + if (NULL == buf) + { + GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); + return; + } + GNUNET_SERVER_transmit_context_append_data (tc, buf, strlen (buf) + 1, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); +} + + +/** + * Client asked to resolve an address. Process the request. + * + * @param cls unused + * @param client the client + * @param message the resolution request + */ +static void +clients_handle_address_to_string (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct AddressLookupMessage *alum; + struct GNUNET_TRANSPORT_PluginFunctions *papi; + const char *plugin_name; + const char *address; + uint32_t address_len; + uint16_t size; + struct GNUNET_SERVER_TransmitContext *tc; + struct GNUNET_TIME_Relative rtimeout; + int32_t numeric; + + size = ntohs (message->size); + if (size < sizeof (struct AddressLookupMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + alum = (const struct AddressLookupMessage *) message; + address_len = ntohs (alum->addrlen); + if (size <= sizeof (struct AddressLookupMessage) + address_len) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + address = (const char *) &alum[1]; + plugin_name = (const char *) &address[address_len]; + if (plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1] + != '\0') + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout); + numeric = ntohs (alum->numeric_only); + tc = GNUNET_SERVER_transmit_context_create (client); + papi = GST_plugins_find (plugin_name); + if (NULL == papi) + { + GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); + GNUNET_SERVER_transmit_context_run (tc, rtimeout); + return; + } + GNUNET_SERVER_disable_receive_done_warning (client); + papi->address_pretty_printer (papi->cls, plugin_name, address, address_len, + numeric, rtimeout, &transmit_address_to_client, + tc); +} + + +/** + * Compose AddressIterateResponseMessage using the given peer and address. + * + * @param peer identity of the peer + * @param address the address, NULL on disconnect + * @return composed message + */ +static struct AddressIterateResponseMessage * +compose_address_iterate_response_message (const struct GNUNET_PeerIdentity + *peer, + const struct GNUNET_HELLO_Address + *address) +{ + struct AddressIterateResponseMessage *msg; + size_t size; + size_t tlen; + size_t alen; + char *addr; + + GNUNET_assert (NULL != peer); + if (NULL != address) + { + tlen = strlen (address->transport_name) + 1; + alen = address->address_length; + } + else + tlen = alen = 0; + size = (sizeof (struct AddressIterateResponseMessage) + alen + tlen); + msg = GNUNET_malloc (size); + msg->header.size = htons (size); + msg->header.type = + htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); + msg->reserved = htonl (0); + msg->peer = *peer; + msg->addrlen = htonl (alen); + msg->pluginlen = htonl (tlen); + if (NULL != address) + { + addr = (char *) &msg[1]; + memcpy (addr, address->address, alen); + memcpy (&addr[alen], address->transport_name, tlen); + } + return msg; +} + + +/** + * Output the active address of connected neighbours to the given client. + * + * @param cls the 'struct GNUNET_SERVER_TransmitContext' for transmission to the client + * @param peer identity of the neighbour + * @param ats performance data + * @param ats_count number of entries in ats (excluding 0-termination) + * @param address the address + */ +static void +output_address (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count, + const struct GNUNET_HELLO_Address *address) +{ + struct GNUNET_SERVER_TransmitContext *tc = cls; + struct AddressIterateResponseMessage *msg; + + msg = compose_address_iterate_response_message (peer, address); + GNUNET_SERVER_transmit_context_append_message (tc, &msg->header); + GNUNET_free (msg); +} + + +/** + * Client asked to obtain information about all actively used addresses + * of connected peers + * Process the request. + * + * @param cls unused + * @param client the client + * @param message the peer address information request + */ +static void +clients_handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + static struct GNUNET_PeerIdentity all_zeros; + struct GNUNET_SERVER_TransmitContext *tc; + struct AddressIterateMessage *msg; + struct GNUNET_HELLO_Address *address; + + if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if (ntohs (message->size) != sizeof (struct AddressIterateMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msg = (struct AddressIterateMessage *) message; + if ( (GNUNET_YES != ntohl (msg->one_shot)) && + (NULL != lookup_monitoring_client (client)) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "ServerClient %p tried to start monitoring twice\n", + client); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_SERVER_disable_receive_done_warning (client); + tc = GNUNET_SERVER_transmit_context_create (client); + if (0 == memcmp (&msg->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity))) + { + /* iterate over all neighbours */ + GST_neighbours_iterate (&output_address, tc); + } + else + { + /* just return one neighbour */ + address = GST_neighbour_get_current_address (&msg->peer); + if (address != NULL) + output_address (tc, &msg->peer, NULL, 0, address); + } + if (GNUNET_YES != ntohl (msg->one_shot)) + setup_monitoring_client (client, &msg->peer); + else + GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Start handling requests from clients. + * + * @param server server used to accept clients from. + */ +void +GST_clients_start (struct GNUNET_SERVER_Handle *server) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&clients_handle_start, NULL, + GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)}, + {&clients_handle_hello, NULL, + GNUNET_MESSAGE_TYPE_HELLO, 0}, + {&clients_handle_send, NULL, + GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0}, + {&clients_handle_request_connect, NULL, + GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, + sizeof (struct TransportRequestConnectMessage)}, + {&clients_handle_address_to_string, NULL, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0}, + {&clients_handle_address_iterate, NULL, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE, + sizeof (struct AddressIterateMessage)}, + {&GST_blacklist_handle_init, NULL, + GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, + sizeof (struct GNUNET_MessageHeader)}, + {&GST_blacklist_handle_reply, NULL, + GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, + sizeof (struct BlacklistMessage)}, + {NULL, NULL, 0, 0} + }; + nc = GNUNET_SERVER_notification_context_create (server, 0); + GNUNET_SERVER_add_handlers (server, handlers); + GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification, + NULL); +} + + +/** + * Stop processing clients. + */ +void +GST_clients_stop () +{ + if (NULL != nc) + { + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; + } +} + + +/** + * Broadcast the given message to all of our clients. + * + * @param msg message to broadcast + * @param may_drop GNUNET_YES if the message can be dropped / is payload + */ +void +GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, int may_drop) +{ + struct TransportClient *tc; + + for (tc = clients_head; tc != NULL; tc = tc->next) + { + if ((GNUNET_YES == may_drop) && (GNUNET_YES != tc->send_payload)) + continue; /* skip, this client does not care about payload */ + unicast (tc, msg, may_drop); + } +} + + +/** + * Send the given message to a particular client + * + * @param client target of the message + * @param msg message to transmit + * @param may_drop GNUNET_YES if the message can be dropped + */ +void +GST_clients_unicast (struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg, int may_drop) +{ + struct TransportClient *tc; + + tc = lookup_client (client); + if (NULL == tc) + return; /* client got disconnected in the meantime, drop message */ + unicast (tc, msg, may_drop); +} + + +/** + * Broadcast the new active address to all clients monitoring the peer. + * + * @param peer peer this update is about (never NULL) + * @param address address, NULL on disconnect + */ +void +GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity + *peer, + const struct GNUNET_HELLO_Address + *address) +{ + struct AddressIterateResponseMessage *msg; + struct MonitoringClient *mc; + static struct GNUNET_PeerIdentity all_zeros; + + msg = compose_address_iterate_response_message (peer, address); + mc = monitoring_clients_head; + while (mc != NULL) + { + if ((0 == memcmp (&mc->peer, &all_zeros, + sizeof (struct GNUNET_PeerIdentity))) || + (0 == memcmp (&mc->peer, peer, + sizeof (struct GNUNET_PeerIdentity)))) + { + GNUNET_SERVER_notification_context_unicast (nc, mc->client, + &msg->header, GNUNET_NO); + } + + mc = mc->next; + } + GNUNET_free (msg); +} + + +/* end of file gnunet-service-transport_clients.c */ diff --git a/src/transport/gnunet-service-transport_clients.h b/src/transport/gnunet-service-transport_clients.h new file mode 100644 index 0000000..9556620 --- /dev/null +++ b/src/transport/gnunet-service-transport_clients.h @@ -0,0 +1,86 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_clients.h + * @brief plugin management API + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_TRANSPORT_CLIENTS_H +#define GNUNET_SERVICE_TRANSPORT_CLIENTS_H + +#include "gnunet_statistics_service.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" + + +/** + * Start handling requests from clients. + * + * @param server server used to accept clients from. + */ +void +GST_clients_start (struct GNUNET_SERVER_Handle *server); + + +/** + * Stop processing clients. + */ +void +GST_clients_stop (void); + + +/** + * Broadcast the given message to all of our clients. + * + * @param msg message to broadcast + * @param may_drop GNUNET_YES if the message can be dropped / is payload + */ +void +GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, int may_drop); + + +/** + * Send the given message to a particular client + * + * @param client target of the message + * @param msg message to transmit + * @param may_drop GNUNET_YES if the message can be dropped + */ +void +GST_clients_unicast (struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg, int may_drop); + + +/** + * Broadcast the new active address to all clients monitoring the peer. + * + * @param peer peer this update is about (never NULL) + * @param address address, NULL on disconnect + */ +void +GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity + *peer, + const struct GNUNET_HELLO_Address + *address); + + +#endif +/* end of file gnunet-service-transport_clients.h */ diff --git a/src/transport/gnunet-service-transport_hello.c b/src/transport/gnunet-service-transport_hello.c new file mode 100644 index 0000000..120f176 --- /dev/null +++ b/src/transport/gnunet-service-transport_hello.c @@ -0,0 +1,318 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_hello.c + * @brief hello management implementation + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_hello_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet-service-transport_hello.h" +#include "gnunet-service-transport.h" +#include "gnunet-service-transport_plugins.h" + + +/** + * How often do we refresh our HELLO (due to expiration concerns)? + */ +#define HELLO_REFRESH_PERIOD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) + + +/** + * Entry in linked list of network addresses for ourselves. Also + * includes a cached signature for 'struct TransportPongMessage's. + */ +struct OwnAddressList +{ + /** + * This is a doubly-linked list. + */ + struct OwnAddressList *next; + + /** + * This is a doubly-linked list. + */ + struct OwnAddressList *prev; + + /** + * The address. + */ + struct GNUNET_HELLO_Address *address; + + /** + * How long until the current signature expires? (ZERO if the + * signature was never created). + */ + struct GNUNET_TIME_Absolute pong_sig_expires; + + /** + * Signature for a 'struct TransportPongMessage' for this address. + */ + struct GNUNET_CRYPTO_RsaSignature pong_signature; + +}; + + +/** + * Our HELLO message. + */ +static struct GNUNET_HELLO_Message *our_hello; + +/** + * Function to call on HELLO changes. + */ +static GST_HelloCallback hello_cb; + +/** + * Closure for 'hello_cb'. + */ +static void *hello_cb_cls; + +/** + * Head of my addresses. + */ +struct OwnAddressList *oal_head; + +/** + * Tail of my addresses. + */ +struct OwnAddressList *oal_tail; + +/** + * Identifier of 'refresh_hello' task. + */ +static GNUNET_SCHEDULER_TaskIdentifier hello_task; + + +/** + * Closure for 'address_generator'. + */ +struct GeneratorContext +{ + /** + * Where are we in the DLL? + */ + struct OwnAddressList *addr_pos; + + /** + * When do addresses expire? + */ + struct GNUNET_TIME_Absolute expiration; +}; + + +/** + * Add an address from the 'OwnAddressList' to the buffer. + * + * @param cls the 'struct GeneratorContext' + * @param max maximum number of bytes left + * @param buf where to write the address + */ +static size_t +address_generator (void *cls, size_t max, void *buf) +{ + struct GeneratorContext *gc = cls; + size_t ret; + + if (NULL == gc->addr_pos) + return 0; + ret = + GNUNET_HELLO_add_address (gc->addr_pos->address, gc->expiration, buf, + max); + gc->addr_pos = gc->addr_pos->next; + return ret; +} + + +/** + * Construct our HELLO message from all of the addresses of + * all of the transports. + * + * @param cls unused + * @param tc scheduler context + */ +static void +refresh_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GeneratorContext gc; + + hello_task = GNUNET_SCHEDULER_NO_TASK; + gc.addr_pos = oal_head; + gc.expiration = + GNUNET_TIME_relative_to_absolute + (GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION); + GNUNET_free (our_hello); + our_hello = GNUNET_HELLO_create (&GST_my_public_key, &address_generator, &gc); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Refreshed my `%s', new size is %d\n", "HELLO", + GNUNET_HELLO_size (our_hello)); +#endif + GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# refreshed my HELLO"), 1, + GNUNET_NO); + if (NULL != hello_cb) + hello_cb (hello_cb_cls, GST_hello_get ()); + GNUNET_PEERINFO_add_peer (GST_peerinfo, our_hello); + hello_task = + GNUNET_SCHEDULER_add_delayed (HELLO_REFRESH_PERIOD, &refresh_hello_task, + NULL); + +} + + +/** + * Schedule task to refresh hello (unless such a + * task exists already). + */ +static void +refresh_hello () +{ + if (hello_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (hello_task); + hello_task = GNUNET_SCHEDULER_add_now (&refresh_hello_task, NULL); +} + + +/** + * Initialize the HELLO module. + * + * @param cb function to call whenever our HELLO changes + * @param cb_cls closure for cb + */ +void +GST_hello_start (GST_HelloCallback cb, void *cb_cls) +{ + hello_cb = cb; + hello_cb_cls = cb_cls; + our_hello = GNUNET_HELLO_create (&GST_my_public_key, NULL, NULL); + refresh_hello (); +} + + +/** + * Shutdown the HELLO module. + */ +void +GST_hello_stop () +{ + hello_cb = NULL; + hello_cb_cls = NULL; + if (GNUNET_SCHEDULER_NO_TASK != hello_task) + { + GNUNET_SCHEDULER_cancel (hello_task); + hello_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != our_hello) + { + GNUNET_free (our_hello); + our_hello = NULL; + } +} + + +/** + * Obtain this peers HELLO message. + * + * @return our HELLO message + */ +const struct GNUNET_MessageHeader * +GST_hello_get () +{ + return (struct GNUNET_MessageHeader *) our_hello; +} + + +/** + * Add or remove an address from this peer's HELLO message. + * + * @param addremove GNUNET_YES to add, GNUNET_NO to remove + * @param address address to add or remove + */ +void +GST_hello_modify_addresses (int addremove, + const struct GNUNET_HELLO_Address *address) +{ + struct OwnAddressList *al; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + (add_remove == + GNUNET_YES) ? "Adding `%s':%s to the set of our addresses\n" : + "Removing `%s':%s from the set of our addresses\n", + GST_plugins_a2s (address), p->short_name); +#endif + GNUNET_assert (address != NULL); + if (GNUNET_NO == addremove) + { + for (al = oal_head; al != NULL; al = al->next) + if (0 == GNUNET_HELLO_address_cmp (address, al->address)) + { + GNUNET_CONTAINER_DLL_remove (oal_head, oal_tail, al); + GNUNET_HELLO_address_free (al->address); + GNUNET_free (al); + refresh_hello (); + return; + } + /* address to be removed not found!? */ + GNUNET_break (0); + return; + } + al = GNUNET_malloc (sizeof (struct OwnAddressList)); + GNUNET_CONTAINER_DLL_insert (oal_head, oal_tail, al); + al->address = GNUNET_HELLO_address_copy (address); + refresh_hello (); +} + + +/** + * Test if a particular address is one of ours. + * + * @param address address to test + * @param sig location where to cache PONG signatures for this address [set] + * @param sig_expiration how long until the current 'sig' expires? + * (ZERO if sig was never created) [set] + * @return GNUNET_YES if this is one of our addresses, + * GNUNET_NO if not + */ +int +GST_hello_test_address (const struct GNUNET_HELLO_Address *address, + struct GNUNET_CRYPTO_RsaSignature **sig, + struct GNUNET_TIME_Absolute **sig_expiration) +{ + struct OwnAddressList *al; + + for (al = oal_head; al != NULL; al = al->next) + if (0 == GNUNET_HELLO_address_cmp (address, al->address)) + { + *sig = &al->pong_signature; + *sig_expiration = &al->pong_sig_expires; + return GNUNET_YES; + } + *sig = NULL; + *sig_expiration = NULL; + return GNUNET_NO; +} + + +/* end of file gnunet-service-transport_hello.c */ diff --git a/src/transport/gnunet-service-transport_hello.h b/src/transport/gnunet-service-transport_hello.h new file mode 100644 index 0000000..605d198 --- /dev/null +++ b/src/transport/gnunet-service-transport_hello.h @@ -0,0 +1,100 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_hello.h + * @brief hello API + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_TRANSPORT_HELLO_H +#define GNUNET_SERVICE_TRANSPORT_HELLO_H + +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" + + + +/** + * Signature of a function to call whenever our hello changes. + * + * @param cls closure + * @param hello updated HELLO + */ +typedef void (*GST_HelloCallback) (void *cls, + const struct GNUNET_MessageHeader * hello); + + +/** + * Initialize the HELLO module. + * + * @param cb function to call whenever our HELLO changes + * @param cb_cls closure for cb + */ +void +GST_hello_start (GST_HelloCallback cb, void *cb_cls); + + +/** + * Shutdown the HELLO module. + */ +void +GST_hello_stop (void); + + +/** + * Obtain this peers HELLO message. + * + * @return our HELLO message + */ +const struct GNUNET_MessageHeader * +GST_hello_get (void); + + +/** + * Add or remove an address from this peer's HELLO message. + * + * @param addremove GNUNET_YES to add, GNUNET_NO to remove + * @param address address to add or remove + */ +void +GST_hello_modify_addresses (int addremove, + const struct GNUNET_HELLO_Address *address); + + +/** + * Test if a particular address is one of ours. + * + * @param address the address to test + * @param sig location where to cache PONG signatures for this address [set] + * @param sig_expiration how long until the current 'sig' expires? + * (ZERO if sig was never created) [set] + * @return GNUNET_YES if this is one of our addresses, + * GNUNET_NO if not + */ +int +GST_hello_test_address (const struct GNUNET_HELLO_Address *address, + struct GNUNET_CRYPTO_RsaSignature **sig, + struct GNUNET_TIME_Absolute **sig_expiration); + + +#endif +/* end of file gnunet-service-transport_hello.h */ diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c new file mode 100644 index 0000000..3e8ef5a --- /dev/null +++ b/src/transport/gnunet-service-transport_neighbours.c @@ -0,0 +1,2721 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_neighbours.c + * @brief neighbour management + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_ats_service.h" +#include "gnunet-service-transport_neighbours.h" +#include "gnunet-service-transport_plugins.h" +#include "gnunet-service-transport_validation.h" +#include "gnunet-service-transport_clients.h" +#include "gnunet-service-transport.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet-service-transport_blacklist.h" +#include "gnunet_constants.h" +#include "transport.h" + + +/** + * Size of the neighbour hash map. + */ +#define NEIGHBOUR_TABLE_SIZE 256 + +/** + * How often must a peer violate bandwidth quotas before we start + * to simply drop its messages? + */ +#define QUOTA_VIOLATION_DROP_THRESHOLD 10 + +/** + * How often do we send KEEPALIVE messages to each of our neighbours and measure + * the latency with this neighbour? + * (idle timeout is 5 minutes or 300 seconds, so with 30s interval we + * send 10 keepalives in each interval, so 10 messages would need to be + * lost in a row for a disconnect). + */ +#define KEEPALIVE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + + +#define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +#define FAST_RECONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +#define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) + +#define TEST_NEW_CODE GNUNET_NO + +/** + * Entry in neighbours. + */ +struct NeighbourMapEntry; + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message a peer sends to another to indicate its + * preference for communicating via a particular + * session (and the desire to establish a real + * connection). + */ +struct SessionConnectMessage +{ + /** + * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT' + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Absolute time at the sender. Only the most recent connect + * message implies which session is preferred by the sender. + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + +}; + + +struct SessionDisconnectMessage +{ + /** + * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT' + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Purpose of the signature. Extends over the timestamp. + * Purpose should be GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT. + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * Absolute time at the sender. Only the most recent connect + * message implies which session is preferred by the sender. + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + + /** + * Public key of the sender. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + + /** + * Signature of the peer that sends us the disconnect. Only + * valid if the timestamp is AFTER the timestamp from the + * corresponding 'CONNECT' message. + */ + struct GNUNET_CRYPTO_RsaSignature signature; + +}; +GNUNET_NETWORK_STRUCT_END + +/** + * For each neighbour we keep a list of messages + * that we still want to transmit to the neighbour. + */ +struct MessageQueue +{ + + /** + * This is a doubly linked list. + */ + struct MessageQueue *next; + + /** + * This is a doubly linked list. + */ + struct MessageQueue *prev; + + /** + * Once this message is actively being transmitted, which + * neighbour is it associated with? + */ + struct NeighbourMapEntry *n; + + /** + * Function to call once we're done. + */ + GST_NeighbourSendContinuation cont; + + /** + * Closure for 'cont' + */ + void *cont_cls; + + /** + * The message(s) we want to transmit, GNUNET_MessageHeader(s) + * stuck together in memory. Allocated at the end of this struct. + */ + const char *message_buf; + + /** + * Size of the message buf + */ + size_t message_buf_size; + + /** + * At what time should we fail? + */ + struct GNUNET_TIME_Absolute timeout; + +}; + + +enum State +{ + /** + * fresh peer or completely disconnected + */ + S_NOT_CONNECTED, + + /** + * sent CONNECT message to other peer, waiting for CONNECT_ACK + */ + S_CONNECT_SENT, + + /** + * received CONNECT message to other peer, sending CONNECT_ACK + */ + S_CONNECT_RECV, + + /** + * received ACK or payload + */ + S_CONNECTED, + + /** + * connection ended, fast reconnect + */ + S_FAST_RECONNECT, + + /** + * Disconnect in progress + */ + S_DISCONNECT +}; + +enum Address_State +{ + USED, + UNUSED, + FRESH, +}; + + +/** + * Entry in neighbours. + */ +struct NeighbourMapEntry +{ + + /** + * Head of list of messages we would like to send to this peer; + * must contain at most one message per client. + */ + struct MessageQueue *messages_head; + + /** + * Tail of list of messages we would like to send to this peer; must + * contain at most one message per client. + */ + struct MessageQueue *messages_tail; + + /** + * Are we currently trying to send a message? If so, which one? + */ + struct MessageQueue *is_active; + + /** + * Active session for communicating with the peer. + */ + struct Session *session; + + /** + * Address we currently use. + */ + struct GNUNET_HELLO_Address *address; + + /** + * Identity of this neighbour. + */ + struct GNUNET_PeerIdentity id; + + /** + * ID of task scheduled to run when this peer is about to + * time out (will free resources associated with the peer). + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * ID of task scheduled to send keepalives. + */ + GNUNET_SCHEDULER_TaskIdentifier keepalive_task; + + /** + * ID of task scheduled to run when we should try transmitting + * the head of the message queue. + */ + GNUNET_SCHEDULER_TaskIdentifier transmission_task; + + /** + * Tracker for inbound bandwidth. + */ + struct GNUNET_BANDWIDTH_Tracker in_tracker; + + /** + * Inbound bandwidth from ATS, activated when connection is up + */ + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; + + /** + * Inbound bandwidth from ATS, activated when connection is up + */ + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; + + /** + * Timestamp of the 'SESSION_CONNECT' message we got from the other peer + */ + struct GNUNET_TIME_Absolute connect_ts; + + /** + * When did we sent the last keep-alive message? + */ + struct GNUNET_TIME_Absolute keep_alive_sent; + + /** + * Latest calculated latency value + */ + struct GNUNET_TIME_Relative latency; + + /** + * Timeout for ATS + * We asked ATS for a new address for this peer + */ + GNUNET_SCHEDULER_TaskIdentifier ats_suggest; + + /** + * Task the resets the peer state after due to an pending + * unsuccessful connection setup + */ + GNUNET_SCHEDULER_TaskIdentifier state_reset; + + + /** + * How often has the other peer (recently) violated the inbound + * traffic limit? Incremented by 10 per violation, decremented by 1 + * per non-violation (for each time interval). + */ + unsigned int quota_violation_count; + + + /** + * The current state of the peer + * Element of enum State + */ + int state; + + /** + * Did we sent an KEEP_ALIVE message and are we expecting a response? + */ + int expect_latency_response; + int address_state; +}; + + +/** + * All known neighbours and their HELLOs. + */ +static struct GNUNET_CONTAINER_MultiHashMap *neighbours; + +/** + * Closure for connect_notify_cb, disconnect_notify_cb and address_change_cb + */ +static void *callback_cls; + +/** + * Function to call when we connected to a neighbour. + */ +static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb; + +/** + * Function to call when we disconnected from a neighbour. + */ +static GNUNET_TRANSPORT_NotifyDisconnect disconnect_notify_cb; + +/** + * Function to call when we changed an active address of a neighbour. + */ +static GNUNET_TRANSPORT_PeerIterateCallback address_change_cb; + +/** + * counter for connected neighbours + */ +static int neighbours_connected; + +/** + * Lookup a neighbour entry in the neighbours hash map. + * + * @param pid identity of the peer to look up + * @return the entry, NULL if there is no existing record + */ +static struct NeighbourMapEntry * +lookup_neighbour (const struct GNUNET_PeerIdentity *pid) +{ + return GNUNET_CONTAINER_multihashmap_get (neighbours, &pid->hashPubKey); +} + +/** + * Disconnect from the given neighbour, clean up the record. + * + * @param n neighbour to disconnect from + */ +static void +disconnect_neighbour (struct NeighbourMapEntry *n); + +#define change_state(n, state, ...) change (n, state, __LINE__) + +static int +is_connecting (struct NeighbourMapEntry *n) +{ + if ((n->state > S_NOT_CONNECTED) && (n->state < S_CONNECTED)) + return GNUNET_YES; + return GNUNET_NO; +} + +static int +is_connected (struct NeighbourMapEntry *n) +{ + if (n->state == S_CONNECTED) + return GNUNET_YES; + return GNUNET_NO; +} + +static int +is_disconnecting (struct NeighbourMapEntry *n) +{ + if (n->state == S_DISCONNECT) + return GNUNET_YES; + return GNUNET_NO; +} + +static const char * +print_state (int state) +{ + switch (state) + { + case S_CONNECTED: + return "S_CONNECTED"; + break; + case S_CONNECT_RECV: + return "S_CONNECT_RECV"; + break; + case S_CONNECT_SENT: + return "S_CONNECT_SENT"; + break; + case S_DISCONNECT: + return "S_DISCONNECT"; + break; + case S_NOT_CONNECTED: + return "S_NOT_CONNECTED"; + break; + case S_FAST_RECONNECT: + return "S_FAST_RECONNECT"; + break; + default: + GNUNET_break (0); + break; + } + return NULL; +} + +static int +change (struct NeighbourMapEntry *n, int state, int line); + +static void +ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +static void +reset_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NeighbourMapEntry *n = cls; + + if (n == NULL) + return; + + n->state_reset = GNUNET_SCHEDULER_NO_TASK; + if (n->state == S_CONNECTED) + return; + +#if DEBUG_TRANSPORT + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# failed connection attempts due to timeout"), 1, + GNUNET_NO); +#endif + + /* resetting state */ + + if (n->state == S_FAST_RECONNECT) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Fast reconnect time out, disconnecting peer `%s'\n", + GNUNET_i2s (&n->id)); + disconnect_neighbour(n); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n", + GNUNET_i2s (&n->id), n, print_state(n->state), "S_NOT_CONNECTED", __LINE__); + + n->state = S_NOT_CONNECTED; + + /* destroying address */ + if (n->address != NULL) + { + GNUNET_assert (strlen (n->address->transport_name) > 0); + GNUNET_ATS_address_destroyed (GST_ats, n->address, n->session); + } + + /* request new address */ + if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->ats_suggest); + n->ats_suggest = + GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, + n); + GNUNET_ATS_suggest_address (GST_ats, &n->id); +} + +static int +change (struct NeighbourMapEntry *n, int state, int line) +{ + int previous_state; + /* allowed transitions */ + int allowed = GNUNET_NO; + + previous_state = n->state; + + switch (n->state) + { + case S_NOT_CONNECTED: + if ((state == S_CONNECT_RECV) || (state == S_CONNECT_SENT) || + (state == S_DISCONNECT)) + allowed = GNUNET_YES; + break; + case S_CONNECT_RECV: + allowed = GNUNET_YES; + break; + case S_CONNECT_SENT: + allowed = GNUNET_YES; + break; + case S_CONNECTED: + if ((state == S_DISCONNECT) || (state == S_FAST_RECONNECT)) + allowed = GNUNET_YES; + break; + case S_DISCONNECT: + break; + case S_FAST_RECONNECT: + if ((state == S_CONNECTED) || (state == S_DISCONNECT)) + allowed = GNUNET_YES; + break; + default: + GNUNET_break (0); + break; + } + if (allowed == GNUNET_NO) + { + char *old = GNUNET_strdup (print_state (n->state)); + char *new = GNUNET_strdup (print_state (state)); + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Illegal state transition from `%s' to `%s' in line %u \n", old, + new, line); + GNUNET_break (0); + GNUNET_free (old); + GNUNET_free (new); + return GNUNET_SYSERR; + } + { + char *old = GNUNET_strdup (print_state (n->state)); + char *new = GNUNET_strdup (print_state (state)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n", + GNUNET_i2s (&n->id), n, old, new, line); + GNUNET_free (old); + GNUNET_free (new); + } + n->state = state; + + switch (n->state) + { + case S_FAST_RECONNECT: + case S_CONNECT_RECV: + case S_CONNECT_SENT: + if (n->state_reset != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->state_reset); + n->state_reset = + GNUNET_SCHEDULER_add_delayed (SETUP_CONNECTION_TIMEOUT, &reset_task, n); + break; + case S_CONNECTED: + case S_NOT_CONNECTED: + case S_DISCONNECT: + if (GNUNET_SCHEDULER_NO_TASK != n->state_reset) + { +#if DEBUG_TRANSPORT + char *old = GNUNET_strdup (print_state (n->state)); + char *new = GNUNET_strdup (print_state (state)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Removed reset task for peer `%s' %s failed in state transition `%s' -> `%s' \n", + GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), old, new); + GNUNET_free (old); + GNUNET_free (new); +#endif + GNUNET_assert (n->state_reset != GNUNET_SCHEDULER_NO_TASK); + GNUNET_SCHEDULER_cancel (n->state_reset); + n->state_reset = GNUNET_SCHEDULER_NO_TASK; + } + break; + + default: + GNUNET_assert (0); + } + + if (NULL != address_change_cb) + { + if (n->state == S_CONNECTED) + address_change_cb (callback_cls, &n->id, n->address); + else if (previous_state == S_CONNECTED) + address_change_cb (callback_cls, &n->id, NULL); + } + + return GNUNET_OK; +} + +static ssize_t +send_with_session (struct NeighbourMapEntry *n, + const char *msgbuf, size_t msgbuf_size, + uint32_t priority, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *papi; + size_t ret = GNUNET_SYSERR; + + GNUNET_assert (n != NULL); + GNUNET_assert (n->session != NULL); + + papi = GST_plugins_find (n->address->transport_name); + if (papi == NULL) + { + if (cont != NULL) + cont (cont_cls, &n->id, GNUNET_SYSERR); + return GNUNET_SYSERR; + } + + ret = papi->send (papi->cls, + n->session, + msgbuf, msgbuf_size, + 0, + timeout, + cont, cont_cls); + + if ((ret == -1) && (cont != NULL)) + cont (cont_cls, &n->id, GNUNET_SYSERR); + return ret; +} + +/** + * Task invoked to start a transmission to another peer. + * + * @param cls the 'struct NeighbourMapEntry' + * @param tc scheduler context + */ +static void +transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * We're done with our transmission attempt, continue processing. + * + * @param cls the 'struct MessageQueue' of the message + * @param receiver intended receiver + * @param success whether it worked or not + */ +static void +transmit_send_continuation (void *cls, + const struct GNUNET_PeerIdentity *receiver, + int success) +{ + struct MessageQueue *mq = cls; + struct NeighbourMapEntry *n; + struct NeighbourMapEntry *tmp; + + tmp = lookup_neighbour (receiver); + n = mq->n; + if ((NULL != n) && (tmp != NULL) && (tmp == n)) + { + GNUNET_assert (n->is_active == mq); + n->is_active = NULL; + if (success == GNUNET_YES) + { + GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK); + n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n); + } + } +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message of type %u was %s\n", + ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type), + (success == GNUNET_OK) ? "successful" : "FAILED"); +#endif + if (NULL != mq->cont) + mq->cont (mq->cont_cls, success); + GNUNET_free (mq); +} + + +/** + * Check the ready list for the given neighbour and if a plugin is + * ready for transmission (and if we have a message), do so! + * + * @param n target peer for which to transmit + */ +static void +try_transmission_to_peer (struct NeighbourMapEntry *n) +{ + struct MessageQueue *mq; + struct GNUNET_TIME_Relative timeout; + ssize_t ret; + + if (n->is_active != NULL) + { + GNUNET_break (0); + return; /* transmission already pending */ + } + if (n->transmission_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_break (0); + return; /* currently waiting for bandwidth */ + } + while (NULL != (mq = n->messages_head)) + { + timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout); + if (timeout.rel_value > 0) + break; + GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); + n->is_active = mq; + mq->n = n; + transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); /* timeout */ + } + if (NULL == mq) + return; /* no more messages */ + + if (n->address == NULL) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No address for peer `%s'\n", + GNUNET_i2s (&n->id)); +#endif + GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); + transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); + GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK); + n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n); + return; + } + + if (GST_plugins_find (n->address->transport_name) == NULL) + { + GNUNET_break (0); + return; + } + GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); + n->is_active = mq; + mq->n = n; + + if ((n->address->address_length == 0) && (n->session == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No address for peer `%s'\n", + GNUNET_i2s (&n->id)); + transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); + GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK); + n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n); + return; + } + + ret = send_with_session(n, + mq->message_buf, mq->message_buf_size, + 0, timeout, + &transmit_send_continuation, mq); + + if (ret == -1) + { + /* failure, but 'send' would not call continuation in this case, + * so we need to do it here! */ + transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); + } + +} + + +/** + * Task invoked to start a transmission to another peer. + * + * @param cls the 'struct NeighbourMapEntry' + * @param tc scheduler context + */ +static void +transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NeighbourMapEntry *n = cls; + + GNUNET_assert (NULL != lookup_neighbour (&n->id)); + n->transmission_task = GNUNET_SCHEDULER_NO_TASK; + try_transmission_to_peer (n); +} + + +/** + * Initialize the neighbours subsystem. + * + * @param cls closure for callbacks + * @param connect_cb function to call if we connect to a peer + * @param disconnect_cb function to call if we disconnect from a peer + * @param peer_address_cb function to call if we change an active address + * of a neighbour + */ +void +GST_neighbours_start (void *cls, + GNUNET_TRANSPORT_NotifyConnect connect_cb, + GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb, + GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb) +{ + callback_cls = cls; + connect_notify_cb = connect_cb; + disconnect_notify_cb = disconnect_cb; + address_change_cb = peer_address_cb; + neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE); +} + + +static void +send_disconnect_cont (void *cls, const struct GNUNET_PeerIdentity *target, + int result) +{ +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending DISCONNECT message to peer `%4s': %i\n", + GNUNET_i2s (target), result); +#endif +} + + +static int +send_disconnect (struct NeighbourMapEntry * n) +{ + size_t ret; + struct SessionDisconnectMessage disconnect_msg; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending DISCONNECT message to peer `%4s'\n", + GNUNET_i2s (&n->id)); +#endif + + disconnect_msg.header.size = htons (sizeof (struct SessionDisconnectMessage)); + disconnect_msg.header.type = + htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT); + disconnect_msg.reserved = htonl (0); + disconnect_msg.purpose.size = + htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + sizeof (struct GNUNET_TIME_AbsoluteNBO)); + disconnect_msg.purpose.purpose = + htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT); + disconnect_msg.timestamp = + GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + disconnect_msg.public_key = GST_my_public_key; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (GST_my_private_key, + &disconnect_msg.purpose, + &disconnect_msg.signature)); + + ret = send_with_session (n, + (const char *) &disconnect_msg, sizeof (disconnect_msg), + UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, + &send_disconnect_cont, NULL); + + if (ret == GNUNET_SYSERR) + return GNUNET_SYSERR; + + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# peers disconnected due to external request"), 1, + GNUNET_NO); + return GNUNET_OK; +} + + +/** + * Disconnect from the given neighbour, clean up the record. + * + * @param n neighbour to disconnect from + */ +static void +disconnect_neighbour (struct NeighbourMapEntry *n) +{ + struct MessageQueue *mq; + int previous_state; + + previous_state = n->state; + + if (is_disconnecting (n)) + return; + + /* send DISCONNECT MESSAGE */ + if (previous_state == S_CONNECTED) + { + if (GNUNET_OK == send_disconnect (n)) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent DISCONNECT_MSG to `%s'\n", + GNUNET_i2s (&n->id)); + else + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Could not send DISCONNECT_MSG to `%s'\n", + GNUNET_i2s (&n->id)); + } + + change_state (n, S_DISCONNECT); + + if (previous_state == S_CONNECTED) + { + GNUNET_assert (NULL != n->address); + if (n->address_state == USED) + { + GST_validation_set_address_use (n->address, n->session, GNUNET_NO); + GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO); + n->address_state = UNUSED; + } + } + + if (n->address != NULL) + { + struct GNUNET_TRANSPORT_PluginFunctions *papi; + + papi = GST_plugins_find (n->address->transport_name); + if (papi != NULL) + papi->disconnect (papi->cls, &n->id); + } + while (NULL != (mq = n->messages_head)) + { + GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); + if (NULL != mq->cont) + mq->cont (mq->cont_cls, GNUNET_SYSERR); + GNUNET_free (mq); + } + if (NULL != n->is_active) + { + n->is_active->n = NULL; + n->is_active = NULL; + } + + switch (previous_state) + { + case S_CONNECTED: + GNUNET_assert (neighbours_connected > 0); + neighbours_connected--; + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->keepalive_task); + GNUNET_SCHEDULER_cancel (n->keepalive_task); + n->keepalive_task = GNUNET_SCHEDULER_NO_TASK; + n->expect_latency_response = GNUNET_NO; + GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1, + GNUNET_NO); + disconnect_notify_cb (callback_cls, &n->id); + break; + case S_FAST_RECONNECT: + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# fast reconnects failed"), 1, + GNUNET_NO); + disconnect_notify_cb (callback_cls, &n->id); + break; + default: + break; + } + + GNUNET_ATS_suggest_address_cancel (GST_ats, &n->id); + + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (neighbours, + &n->id.hashPubKey, n)); + if (GNUNET_SCHEDULER_NO_TASK != n->ats_suggest) + { + GNUNET_SCHEDULER_cancel (n->ats_suggest); + n->ats_suggest = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task) + { + GNUNET_SCHEDULER_cancel (n->timeout_task); + n->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != n->transmission_task) + { + GNUNET_SCHEDULER_cancel (n->transmission_task); + n->transmission_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != n->address) + { + GNUNET_HELLO_address_free (n->address); + n->address = NULL; + } + n->session = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting peer `%4s', %X\n", + GNUNET_i2s (&n->id), n); + GNUNET_free (n); +} + + +/** + * Peer has been idle for too long. Disconnect. + * + * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle + * @param tc scheduler context + */ +static void +neighbour_timeout_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NeighbourMapEntry *n = cls; + + n->timeout_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# peers disconnected due to timeout"), 1, + GNUNET_NO); + disconnect_neighbour (n); +} + + +/** + * Send another keepalive message. + * + * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle + * @param tc scheduler context + */ +static void +neighbour_keepalive_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NeighbourMapEntry *n = cls; + struct GNUNET_MessageHeader m; + int ret; + + GNUNET_assert (S_CONNECTED == n->state); + n->keepalive_task = + GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY, + &neighbour_keepalive_task, n); + + GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# keepalives sent"), 1, + GNUNET_NO); + m.size = htons (sizeof (struct GNUNET_MessageHeader)); + m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE); + + ret = send_with_session (n, + (const void *) &m, sizeof (m), + UINT32_MAX /* priority */ , + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, NULL); + + n->expect_latency_response = GNUNET_NO; + n->keep_alive_sent = GNUNET_TIME_absolute_get_zero (); + if (ret != GNUNET_SYSERR) + { + n->expect_latency_response = GNUNET_YES; + n->keep_alive_sent = GNUNET_TIME_absolute_get (); + } + +} + + +/** + * Disconnect from the given neighbour. + * + * @param cls unused + * @param key hash of neighbour's public key (not used) + * @param value the 'struct NeighbourMapEntry' of the neighbour + */ +static int +disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct NeighbourMapEntry *n = value; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n", + GNUNET_i2s (&n->id), "SHUTDOWN_TASK"); +#endif + if (S_CONNECTED == n->state) + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# peers disconnected due to global disconnect"), + 1, GNUNET_NO); + disconnect_neighbour (n); + return GNUNET_OK; +} + + +static void +ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NeighbourMapEntry *n = cls; + + n->ats_suggest = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "ATS did not suggested address to connect to peer `%s'\n", + GNUNET_i2s (&n->id)); + + disconnect_neighbour (n); +} + +/** + * Cleanup the neighbours subsystem. + */ +void +GST_neighbours_stop () +{ + // This can happen during shutdown + if (neighbours == NULL) + { + return; + } + + GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (neighbours); +// GNUNET_assert (neighbours_connected == 0); + neighbours = NULL; + callback_cls = NULL; + connect_notify_cb = NULL; + disconnect_notify_cb = NULL; + address_change_cb = NULL; +} + +struct ContinutionContext +{ + struct GNUNET_HELLO_Address *address; + + struct Session *session; +}; + +static void +send_outbound_quota (const struct GNUNET_PeerIdentity *target, + struct GNUNET_BANDWIDTH_Value32NBO quota) +{ + struct QuotaSetMessage q_msg; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending outbound quota of %u Bps for peer `%s' to all clients\n", + ntohl (quota.value__), GNUNET_i2s (target)); +#endif + q_msg.header.size = htons (sizeof (struct QuotaSetMessage)); + q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA); + q_msg.quota = quota; + q_msg.peer = (*target); + GST_clients_broadcast (&q_msg.header, GNUNET_NO); +} + +/** + * We tried to send a SESSION_CONNECT message to another peer. If this + * succeeded, we change the state. If it failed, we should tell + * ATS to not use this address anymore (until it is re-validated). + * + * @param cls the 'struct GNUNET_HELLO_Address' of the address that was tried + * @param target peer to send the message to + * @param success GNUNET_OK on success + */ +static void +send_connect_continuation (void *cls, const struct GNUNET_PeerIdentity *target, + int success) +{ + struct ContinutionContext *cc = cls; + struct NeighbourMapEntry *n = lookup_neighbour (&cc->address->peer); + + if (GNUNET_YES != success) + { + GNUNET_assert (strlen (cc->address->transport_name) > 0); + GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session); + } + if ((NULL == neighbours) || (NULL == n) || (n->state == S_DISCONNECT)) + { + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); + return; + } + + if ((GNUNET_YES == success) && + ((n->state == S_NOT_CONNECTED) || (n->state == S_CONNECT_SENT))) + { + change_state (n, S_CONNECT_SENT); + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); + return; + } + + if ((GNUNET_NO == success) && + ((n->state == S_NOT_CONNECTED) || (n->state == S_CONNECT_SENT))) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %p, asking ATS for new address \n", + GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session); +#endif + change_state (n, S_NOT_CONNECTED); + if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->ats_suggest); + n->ats_suggest = + GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, &ats_suggest_cancel, + n); + GNUNET_ATS_suggest_address (GST_ats, &n->id); + } + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); +} + + +/** + * We tried to switch addresses with an peer already connected. If it failed, + * we should tell ATS to not use this address anymore (until it is re-validated). + * + * @param cls the 'struct NeighbourMapEntry' + * @param target peer to send the message to + * @param success GNUNET_OK on success + */ +static void +send_switch_address_continuation (void *cls, + const struct GNUNET_PeerIdentity *target, + int success) +{ + struct ContinutionContext *cc = cls; + struct NeighbourMapEntry *n; + + if (neighbours == NULL) + { + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); + return; /* neighbour is going away */ + } + + n = lookup_neighbour (&cc->address->peer); + if ((n == NULL) || (is_disconnecting (n))) + { + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); + return; /* neighbour is going away */ + } + + GNUNET_assert ((n->state == S_CONNECTED) || (n->state == S_FAST_RECONNECT)); + if (GNUNET_YES != success) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to switch connected peer `%s' to address '%s' session %X, asking ATS for new address \n", + GNUNET_i2s (&n->id), GST_plugins_a2s (cc->address), cc->session); +#endif + GNUNET_assert (strlen (cc->address->transport_name) > 0); + GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session); + + if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->ats_suggest); + n->ats_suggest = + GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, + n); + GNUNET_ATS_suggest_address (GST_ats, &n->id); + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); + return; + } + /* Tell ATS that switching addresses was successful */ + switch (n->state) + { + case S_CONNECTED: + if (n->address_state == FRESH) + { + GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES); + GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0); + if (cc->session != n->session) + GNUNET_break (0); + GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES); + n->address_state = USED; + } + break; + case S_FAST_RECONNECT: +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successful fast reconnect to peer `%s'\n", + GNUNET_i2s (&n->id)); +#endif + change_state (n, S_CONNECTED); + neighbours_connected++; + GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1, + GNUNET_NO); + + if (n->address_state == FRESH) + { + GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES); + GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0); + GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES); + n->address_state = USED; + } + + if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK) + n->keepalive_task = + GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n); + + /* Updating quotas */ + GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in); + send_outbound_quota (target, n->bandwidth_out); + + default: + break; + } + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); +} + + +/** + * We tried to send a SESSION_CONNECT message to another peer. If this + * succeeded, we change the state. If it failed, we should tell + * ATS to not use this address anymore (until it is re-validated). + * + * @param cls the 'struct NeighbourMapEntry' + * @param target peer to send the message to + * @param success GNUNET_OK on success + */ +static void +send_connect_ack_continuation (void *cls, + const struct GNUNET_PeerIdentity *target, + int success) +{ + struct ContinutionContext *cc = cls; + struct NeighbourMapEntry *n; + + if (neighbours == NULL) + { + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); + return; /* neighbour is going away */ + } + + n = lookup_neighbour (&cc->address->peer); + if ((n == NULL) || (is_disconnecting (n))) + { + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); + return; /* neighbour is going away */ + } + + if (GNUNET_YES == success) + { + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); + return; /* sending successful */ + } + + /* sending failed, ask for next address */ +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %X, asking ATS for new address \n", + GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session); +#endif + change_state (n, S_NOT_CONNECTED); + GNUNET_assert (strlen (cc->address->transport_name) > 0); + GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session); + + if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->ats_suggest); + n->ats_suggest = + GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, + n); + GNUNET_ATS_suggest_address (GST_ats, &n->id); + GNUNET_HELLO_address_free (cc->address); + GNUNET_free (cc); +} + + +/** + * For an existing neighbour record, set the active connection to + * use the given address. + * + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats + * @param bandwidth_in inbound quota to be used when connection is up + * @param bandwidth_out outbound quota to be used when connection is up + * @return GNUNET_YES if we are currently connected, GNUNET_NO if the + * connection is not up (yet) + */ +int +GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address + *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_in, + struct GNUNET_BANDWIDTH_Value32NBO + bandwidth_out) +{ + struct NeighbourMapEntry *n; + struct SessionConnectMessage connect_msg; + struct ContinutionContext *cc; + size_t msg_len; + size_t ret; + + if (neighbours == NULL) + { + /* This can happen during shutdown */ + return GNUNET_NO; + } + n = lookup_neighbour (peer); + if (NULL == n) + return GNUNET_NO; + if (n->state == S_DISCONNECT) + { + /* We are disconnecting, nothing to do here */ + return GNUNET_NO; + } + GNUNET_assert (address->transport_name != NULL); + if ((session == NULL) && (0 == address->address_length)) + { + GNUNET_break_op (0); + /* FIXME: is this actually possible? When does this happen? */ + if (strlen (address->transport_name) > 0) + GNUNET_ATS_address_destroyed (GST_ats, address, session); + GNUNET_ATS_suggest_address (GST_ats, peer); + return GNUNET_NO; + } + + /* checks successful and neighbour != NULL */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "ATS tells us to switch to address '%s' session %p for peer `%s' in state `%s'\n", + (address->address_length != 0) ? GST_plugins_a2s (address): "", + session, + GNUNET_i2s (peer), + print_state (n->state)); + + if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (n->ats_suggest); + n->ats_suggest = GNUNET_SCHEDULER_NO_TASK; + } + /* do not switch addresses just update quotas */ +/* + if (n->state == S_FAST_RECONNECT) + { + if (0 == GNUNET_HELLO_address_cmp(address, n->address)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "FAST RECONNECT to peer `%s' and address '%s' with identical ADDRESS\n", + GNUNET_i2s (&n->id), GST_plugins_a2s (n->address)); + } + } +*/ + if ((n->state == S_CONNECTED) && (NULL != n->address) && + (0 == GNUNET_HELLO_address_cmp (address, n->address)) && + (n->session == session)) + { + n->bandwidth_in = bandwidth_in; + n->bandwidth_out = bandwidth_out; + GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in); + send_outbound_quota (peer, n->bandwidth_out); + return GNUNET_NO; + } + if (n->state == S_CONNECTED) + { + /* mark old address as no longer used */ + GNUNET_assert (NULL != n->address); + if (n->address_state == USED) + { + GST_validation_set_address_use (n->address, n->session, GNUNET_NO); + GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO); + n->address_state = UNUSED; + } + } + + /* set new address */ + if (NULL != n->address) + GNUNET_HELLO_address_free (n->address); + n->address = GNUNET_HELLO_address_copy (address); + n->address_state = FRESH; + n->bandwidth_in = bandwidth_in; + n->bandwidth_out = bandwidth_out; + GNUNET_SCHEDULER_cancel (n->timeout_task); + n->timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &neighbour_timeout_task, n); + + if (NULL != address_change_cb && n->state == S_CONNECTED) + address_change_cb (callback_cls, &n->id, n->address); + + /* Obtain an session for this address from plugin */ + struct GNUNET_TRANSPORT_PluginFunctions *papi; + papi = GST_plugins_find (address->transport_name); + + if (papi == NULL) + { + /* we don't have the plugin for this address */ + GNUNET_ATS_address_destroyed (GST_ats, n->address, NULL); + + if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->ats_suggest); + n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, + ats_suggest_cancel, + n); + GNUNET_ATS_suggest_address (GST_ats, &n->id); + GNUNET_HELLO_address_free (n->address); + n->address = NULL; + n->session = NULL; + return GNUNET_NO; + } + + if (session == NULL) + { + n->session = papi->get_session (papi->cls, address); + /* Session could not be initiated */ + if (n->session == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to obtain new session %p for peer `%s' and address '%s'\n", + n->session, GNUNET_i2s (&n->id), GST_plugins_a2s (n->address)); + + GNUNET_ATS_address_destroyed (GST_ats, n->address, NULL); + + if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->ats_suggest); + n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, + ats_suggest_cancel, + n); + GNUNET_ATS_suggest_address (GST_ats, &n->id); + GNUNET_HELLO_address_free (n->address); + n->address = NULL; + n->session = NULL; + return GNUNET_NO; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Obtained new session %p for peer `%s' and address '%s'\n", + n->session, GNUNET_i2s (&n->id), GST_plugins_a2s (n->address)); + /* Telling ATS about new session */ + GNUNET_ATS_address_update (GST_ats, n->address, n->session, NULL, 0); + } + else + { + n->session = session; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using existing session %p for peer `%s' and address '%s'\n", + n->session, + GNUNET_i2s (&n->id), + (address->address_length != 0) ? GST_plugins_a2s (address): ""); + } + + switch (n->state) + { + case S_NOT_CONNECTED: + case S_CONNECT_SENT: + msg_len = sizeof (struct SessionConnectMessage); + connect_msg.header.size = htons (msg_len); + connect_msg.header.type = + htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT); + connect_msg.reserved = htonl (0); + connect_msg.timestamp = + GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + + cc = GNUNET_malloc (sizeof (struct ContinutionContext)); + cc->session = n->session; + cc->address = GNUNET_HELLO_address_copy (address); + + ret = send_with_session (n, + (const char *) &connect_msg, msg_len, + UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, + &send_connect_continuation, cc); + + return GNUNET_NO; + case S_CONNECT_RECV: + /* We received a CONNECT message and asked ATS for an address */ + msg_len = sizeof (struct SessionConnectMessage); + connect_msg.header.size = htons (msg_len); + connect_msg.header.type = + htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK); + connect_msg.reserved = htonl (0); + connect_msg.timestamp = + GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + cc = GNUNET_malloc (sizeof (struct ContinutionContext)); + cc->session = n->session; + cc->address = GNUNET_HELLO_address_copy (address); + + ret = send_with_session(n, + (const void *) &connect_msg, msg_len, + UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, + &send_connect_ack_continuation, + cc); + return GNUNET_NO; + case S_CONNECTED: + case S_FAST_RECONNECT: + /* connected peer is switching addresses or tries fast reconnect */ + msg_len = sizeof (struct SessionConnectMessage); + connect_msg.header.size = htons (msg_len); + connect_msg.header.type = + htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT); + connect_msg.reserved = htonl (0); + connect_msg.timestamp = + GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + cc = GNUNET_malloc (sizeof (struct ContinutionContext)); + cc->session = n->session; + cc->address = GNUNET_HELLO_address_copy (address); + ret = send_with_session(n, + (const void *) &connect_msg, msg_len, + UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, + &send_switch_address_continuation, cc); + if (ret == GNUNET_SYSERR) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to send CONNECT_MESSAGE to `%4s' using address '%s' session %X\n", + GNUNET_i2s (peer), GST_plugins_a2s (address), session); + } + return GNUNET_NO; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid connection state to switch addresses %u \n", n->state); + GNUNET_break_op (0); + return GNUNET_NO; + } +} + + +/** + * Obtain current latency information for the given neighbour. + * + * @param peer + * @return observed latency of the address, FOREVER if the address was + * never successfully validated + */ +struct GNUNET_TIME_Relative +GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer) +{ + struct NeighbourMapEntry *n; + + n = lookup_neighbour (peer); + if ((NULL == n) || ((n->address == NULL) && (n->session == NULL))) + return GNUNET_TIME_UNIT_FOREVER_REL; + + return n->latency; +} + +/** + * Obtain current address information for the given neighbour. + * + * @param peer + * @return address currently used + */ +struct GNUNET_HELLO_Address * +GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer) +{ + struct NeighbourMapEntry *n; + + n = lookup_neighbour (peer); + if ((NULL == n) || ((n->address == NULL) && (n->session == NULL))) + return NULL; + + return n->address; +} + + + +/** + * Create an entry in the neighbour map for the given peer + * + * @param peer peer to create an entry for + * @return new neighbour map entry + */ +static struct NeighbourMapEntry * +setup_neighbour (const struct GNUNET_PeerIdentity *peer) +{ + struct NeighbourMapEntry *n; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Unknown peer `%s', creating new neighbour\n", GNUNET_i2s (peer)); +#endif + n = GNUNET_malloc (sizeof (struct NeighbourMapEntry)); + n->id = *peer; + n->state = S_NOT_CONNECTED; + n->latency = GNUNET_TIME_relative_get_forever (); + GNUNET_BANDWIDTH_tracker_init (&n->in_tracker, + GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT, + MAX_BANDWIDTH_CARRY_S); + n->timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &neighbour_timeout_task, n); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (neighbours, + &n->id.hashPubKey, n, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + return n; +} + + +/** + * Try to create a connection to the given target (eventually). + * + * @param target peer to try to connect to + */ +void +GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target) +{ + struct NeighbourMapEntry *n; + + // This can happen during shutdown + if (neighbours == NULL) + { + return; + } +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to peer `%s'\n", + GNUNET_i2s (target)); +#endif + if (0 == + memcmp (target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity))) + { + /* my own hello */ + return; + } + n = lookup_neighbour (target); + + if (NULL != n) + { + if ((S_CONNECTED == n->state) || (is_connecting (n))) + return; /* already connecting or connected */ + if (is_disconnecting (n)) + change_state (n, S_NOT_CONNECTED); + } + + + if (n == NULL) + n = setup_neighbour (target); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asking ATS for suggested address to connect to peer `%s'\n", + GNUNET_i2s (&n->id)); +#endif + + GNUNET_ATS_suggest_address (GST_ats, &n->id); +} + +/** + * Test if we're connected to the given peer. + * + * @param target peer to test + * @return GNUNET_YES if we are connected, GNUNET_NO if not + */ +int +GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target) +{ + struct NeighbourMapEntry *n; + + // This can happen during shutdown + if (neighbours == NULL) + { + return GNUNET_NO; + } + + n = lookup_neighbour (target); + + if ((NULL == n) || (S_CONNECTED != n->state)) + return GNUNET_NO; /* not connected */ + return GNUNET_YES; +} + +/** + * A session was terminated. Take note. + * + * @param peer identity of the peer where the session died + * @param session session that is gone + */ +void +GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, + struct Session *session) +{ + struct NeighbourMapEntry *n; + + if (neighbours == NULL) + { + /* This can happen during shutdown */ + return; + } + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %X to peer `%s' ended \n", + session, GNUNET_i2s (peer)); +#endif + + n = lookup_neighbour (peer); + if (NULL == n) + return; + if (session != n->session) + return; /* doesn't affect us */ + if (n->state == S_CONNECTED) + { + if (n->address_state == USED) + { + GST_validation_set_address_use (n->address, n->session, GNUNET_NO); + GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO); + n->address_state = UNUSED; + } + } + + if (NULL != n->address) + { + GNUNET_HELLO_address_free (n->address); + n->address = NULL; + } + n->session = NULL; + + /* not connected anymore anyway, shouldn't matter */ + if (S_CONNECTED != n->state) + return; + + if (n->keepalive_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (n->keepalive_task); + n->keepalive_task = GNUNET_SCHEDULER_NO_TASK; + n->expect_latency_response = GNUNET_NO; + } + + /* connected, try fast reconnect */ + /* statistics "transport" : "# peers connected" -= 1 + * neighbours_connected -= 1 + * BUT: no disconnect_cb to notify clients about disconnect + */ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying fast reconnect to peer `%s'\n", + GNUNET_i2s (peer)); + + GNUNET_assert (neighbours_connected > 0); + change_state (n, S_FAST_RECONNECT); + neighbours_connected--; + GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1, + GNUNET_NO); + + + /* We are connected, so ask ATS to switch addresses */ + GNUNET_SCHEDULER_cancel (n->timeout_task); + n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT, + &neighbour_timeout_task, n); + /* try QUICKLY to re-establish a connection, reduce timeout! */ + if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->ats_suggest); + n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, + &ats_suggest_cancel, + n); + GNUNET_ATS_suggest_address (GST_ats, peer); +} + + +/** + * Transmit a message to the given target using the active connection. + * + * @param target destination + * @param msg message to send + * @param msg_size number of bytes in msg + * @param timeout when to fail with timeout + * @param cont function to call when done + * @param cont_cls closure for 'cont' + */ +void +GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg, + size_t msg_size, struct GNUNET_TIME_Relative timeout, + GST_NeighbourSendContinuation cont, void *cont_cls) +{ + struct NeighbourMapEntry *n; + struct MessageQueue *mq; + + // This can happen during shutdown + if (neighbours == NULL) + { + return; + } + + n = lookup_neighbour (target); + if ((n == NULL) || (!is_connected (n))) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# messages not sent (no such peer or not connected)"), + 1, GNUNET_NO); +#if DEBUG_TRANSPORT + if (n == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Could not send message to peer `%s': unknown neighbour", + GNUNET_i2s (target)); + else if (!is_connected (n)) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Could not send message to peer `%s': not connected\n", + GNUNET_i2s (target)); +#endif + if (NULL != cont) + cont (cont_cls, GNUNET_SYSERR); + return; + } + + if ((n->session == NULL) && (n->address == NULL)) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# messages not sent (no such peer or not connected)"), + 1, GNUNET_NO); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Could not send message to peer `%s': no address available\n", + GNUNET_i2s (target)); +#endif + + if (NULL != cont) + cont (cont_cls, GNUNET_SYSERR); + return; + } + + GNUNET_assert (msg_size >= sizeof (struct GNUNET_MessageHeader)); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# bytes in message queue for other peers"), + msg_size, GNUNET_NO); + mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size); + mq->cont = cont; + mq->cont_cls = cont_cls; + /* FIXME: this memcpy can be up to 7% of our total runtime! */ + memcpy (&mq[1], msg, msg_size); + mq->message_buf = (const char *) &mq[1]; + mq->message_buf_size = msg_size; + mq->timeout = GNUNET_TIME_relative_to_absolute (timeout); + GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq); + + if ((GNUNET_SCHEDULER_NO_TASK == n->transmission_task) && + (NULL == n->is_active)) + n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n); +} + + +/** + * We have received a message from the given sender. How long should + * we delay before receiving more? (Also used to keep the peer marked + * as live). + * + * @param sender sender of the message + * @param size size of the message + * @param do_forward set to GNUNET_YES if the message should be forwarded to clients + * GNUNET_NO if the neighbour is not connected or violates the quota, + * GNUNET_SYSERR if the connection is not fully up yet + * @return how long to wait before reading more from this sender + */ +struct GNUNET_TIME_Relative +GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity + *sender, ssize_t size, int *do_forward) +{ + struct NeighbourMapEntry *n; + struct GNUNET_TIME_Relative ret; + + // This can happen during shutdown + if (neighbours == NULL) + { + return GNUNET_TIME_UNIT_FOREVER_REL; + } + + n = lookup_neighbour (sender); + if (n == NULL) + { + GST_neighbours_try_connect (sender); + n = lookup_neighbour (sender); + if (NULL == n) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# messages discarded due to lack of neighbour record"), + 1, GNUNET_NO); + *do_forward = GNUNET_NO; + return GNUNET_TIME_UNIT_ZERO; + } + } + if (!is_connected (n)) + { + *do_forward = GNUNET_SYSERR; + return GNUNET_TIME_UNIT_ZERO; + } + if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size)) + { + n->quota_violation_count++; +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Bandwidth quota (%u b/s) violation detected (total of %u).\n", + n->in_tracker.available_bytes_per_s__, + n->quota_violation_count); +#endif + /* Discount 32k per violation */ + GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024); + } + else + { + if (n->quota_violation_count > 0) + { + /* try to add 32k back */ + GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024); + n->quota_violation_count--; + } + } + if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# bandwidth quota violations by other peers"), + 1, GNUNET_NO); + *do_forward = GNUNET_NO; + return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT; + } + *do_forward = GNUNET_YES; + ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024); + if (ret.rel_value > 0) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n", + (unsigned long long) n->in_tracker. + consumption_since_last_update__, + (unsigned int) n->in_tracker.available_bytes_per_s__, + (unsigned long long) ret.rel_value); +#endif + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# ms throttling suggested"), + (int64_t) ret.rel_value, GNUNET_NO); + } + return ret; +} + + +/** + * Keep the connection to the given neighbour alive longer, + * we received a KEEPALIVE (or equivalent). + * + * @param neighbour neighbour to keep alive + */ +void +GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour) +{ + struct NeighbourMapEntry *n; + + // This can happen during shutdown + if (neighbours == NULL) + { + return; + } + + n = lookup_neighbour (neighbour); + if (NULL == n) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# KEEPALIVE messages discarded (not connected)"), + 1, GNUNET_NO); + return; + } + GNUNET_SCHEDULER_cancel (n->timeout_task); + n->timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &neighbour_timeout_task, n); + + /* send reply to measure latency */ + if (S_CONNECTED != n->state) + return; + + struct GNUNET_MessageHeader m; + + m.size = htons (sizeof (struct GNUNET_MessageHeader)); + m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE); + + send_with_session(n, + (const void *) &m, sizeof (m), + UINT32_MAX, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, NULL); +} + +/** + * We received a KEEP_ALIVE_RESPONSE message and use this to calculate latency + * to this peer + * + * @param neighbour neighbour to keep alive + * @param ats performance data + * @param ats_count number of entries in ats + */ +void +GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) +{ + struct NeighbourMapEntry *n; + struct GNUNET_ATS_Information *ats_new; + uint32_t latency; + + if (neighbours == NULL) + { + // This can happen during shutdown + return; + } + + n = lookup_neighbour (neighbour); + if ((NULL == n) || (n->state != S_CONNECTED)) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# KEEPALIVE_RESPONSE messages discarded (not connected)"), + 1, GNUNET_NO); + return; + } + if (n->expect_latency_response != GNUNET_YES) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# KEEPALIVE_RESPONSE messages discarded (not expected)"), + 1, GNUNET_NO); + return; + } + n->expect_latency_response = GNUNET_NO; + + GNUNET_assert (n->keep_alive_sent.abs_value != + GNUNET_TIME_absolute_get_zero ().abs_value); + n->latency = + GNUNET_TIME_absolute_get_difference (n->keep_alive_sent, + GNUNET_TIME_absolute_get ()); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Latency for peer `%s' is %llu ms\n", + GNUNET_i2s (&n->id), n->latency.rel_value); +#endif + + + if (n->latency.rel_value == GNUNET_TIME_relative_get_forever ().rel_value) + { + GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats, ats_count); + } + else + { + ats_new = + GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) * + (ats_count + 1)); + memcpy (ats_new, ats, sizeof (struct GNUNET_ATS_Information) * ats_count); + + /* add latency */ + ats_new[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); + if (n->latency.rel_value > UINT32_MAX) + latency = UINT32_MAX; + else + latency = n->latency.rel_value; + ats_new[ats_count].value = htonl (latency); + + GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats_new, + ats_count + 1); + GNUNET_free (ats_new); + } +} + + +/** + * Change the incoming quota for the given peer. + * + * @param neighbour identity of peer to change qutoa for + * @param quota new quota + */ +void +GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour, + struct GNUNET_BANDWIDTH_Value32NBO quota) +{ + struct NeighbourMapEntry *n; + + // This can happen during shutdown + if (neighbours == NULL) + { + return; + } + + n = lookup_neighbour (neighbour); + if (n == NULL) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# SET QUOTA messages ignored (no such peer)"), + 1, GNUNET_NO); + return; + } +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setting inbound quota of %u Bps for peer `%s' to all clients\n", + ntohl (quota.value__), GNUNET_i2s (&n->id)); +#endif + GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota); + if (0 != ntohl (quota.value__)) + return; +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s' due to `%s'\n", + GNUNET_i2s (&n->id), "SET_QUOTA"); +#endif + if (is_connected (n)) + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# disconnects due to quota of 0"), + 1, GNUNET_NO); + disconnect_neighbour (n); +} + + +/** + * Closure for the neighbours_iterate function. + */ +struct IteratorContext +{ + /** + * Function to call on each connected neighbour. + */ + GST_NeighbourIterator cb; + + /** + * Closure for 'cb'. + */ + void *cb_cls; +}; + + +/** + * Call the callback from the closure for each connected neighbour. + * + * @param cls the 'struct IteratorContext' + * @param key the hash of the public key of the neighbour + * @param value the 'struct NeighbourMapEntry' + * @return GNUNET_OK (continue to iterate) + */ +static int +neighbours_iterate (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct IteratorContext *ic = cls; + struct NeighbourMapEntry *n = value; + + if (!is_connected (n)) + return GNUNET_OK; + + ic->cb (ic->cb_cls, &n->id, NULL, 0, n->address); + return GNUNET_OK; +} + + +/** + * Iterate over all connected neighbours. + * + * @param cb function to call + * @param cb_cls closure for cb + */ +void +GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls) +{ + struct IteratorContext ic; + + // This can happen during shutdown + if (neighbours == NULL) + { + return; + } + + ic.cb = cb; + ic.cb_cls = cb_cls; + GNUNET_CONTAINER_multihashmap_iterate (neighbours, &neighbours_iterate, &ic); +} + +/** + * If we have an active connection to the given target, it must be shutdown. + * + * @param target peer to disconnect from + */ +void +GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target) +{ + struct NeighbourMapEntry *n; + + // This can happen during shutdown + if (neighbours == NULL) + { + return; + } + + n = lookup_neighbour (target); + if (NULL == n) + return; /* not active */ + disconnect_neighbour (n); +} + + +/** + * We received a disconnect message from the given peer, + * validate and process. + * + * @param peer sender of the message + * @param msg the disconnect message + */ +void +GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity + *peer, + const struct GNUNET_MessageHeader + *msg) +{ + struct NeighbourMapEntry *n; + const struct SessionDisconnectMessage *sdm; + GNUNET_HashCode hc; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received DISCONNECT message from peer `%s'\n", + GNUNET_i2s (peer)); +#endif + + if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage)) + { + // GNUNET_break_op (0); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# disconnect messages ignored (old format)"), 1, + GNUNET_NO); + return; + } + sdm = (const struct SessionDisconnectMessage *) msg; + n = lookup_neighbour (peer); + if (NULL == n) + return; /* gone already */ + if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <= + n->connect_ts.abs_value) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# disconnect messages ignored (timestamp)"), 1, + GNUNET_NO); + return; + } + GNUNET_CRYPTO_hash (&sdm->public_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &hc); + if (0 != memcmp (peer, &hc, sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break_op (0); + return; + } + if (ntohl (sdm->purpose.size) != + sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + sizeof (struct GNUNET_TIME_AbsoluteNBO)) + { + GNUNET_break_op (0); + return; + } + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify + (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT, &sdm->purpose, + &sdm->signature, &sdm->public_key)) + { + GNUNET_break_op (0); + return; + } + GST_neighbours_force_disconnect (peer); +} + + +/** + * We received a 'SESSION_CONNECT_ACK' message from the other peer. + * Consider switching to it. + * + * @param message possibly a 'struct SessionConnectMessage' (check format) + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats + */ +void +GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) +{ + const struct SessionConnectMessage *scm; + struct GNUNET_MessageHeader msg; + struct NeighbourMapEntry *n; + size_t msg_len; + size_t ret; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received CONNECT_ACK message from peer `%s'\n", + GNUNET_i2s (peer)); + + if (ntohs (message->size) != sizeof (struct SessionConnectMessage)) + { + GNUNET_break_op (0); + return; + } + scm = (const struct SessionConnectMessage *) message; + GNUNET_break_op (ntohl (scm->reserved) == 0); + n = lookup_neighbour (peer); + if (NULL == n) + { + /* we did not send 'CONNECT' -- at least not recently */ + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# unexpected CONNECT_ACK messages (no peer)"), + 1, GNUNET_NO); + return; + } + + /* Additional check + * + * ((n->state != S_CONNECT_RECV) && (n->address != NULL)): + * + * We also received an CONNECT message, switched from SENDT to RECV and + * ATS already suggested us an address after a successful blacklist check + */ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received CONNECT_ACK message from peer `%s' in state `%s'\n", + GNUNET_i2s (peer), + print_state(n->state)); + + if ((n->address != NULL) && (n->state == S_CONNECTED)) + { + /* After fast reconnect: send ACK (ACK) even when we are connected */ + msg_len = sizeof (msg); + msg.size = htons (msg_len); + msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK); + + ret = send_with_session(n, + (const char *) &msg, msg_len, + UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, + NULL, NULL); + + if (ret == GNUNET_SYSERR) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n", + GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session); + return; + } + + if ((n->state != S_CONNECT_SENT) && + ((n->state != S_CONNECT_RECV) && (n->address != NULL))) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# unexpected CONNECT_ACK messages"), 1, + GNUNET_NO); + return; + } + if (n->state != S_CONNECTED) + change_state (n, S_CONNECTED); + + if (NULL != session) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "transport-ats", + "Giving ATS session %p of plugin %s for peer %s\n", + session, address->transport_name, GNUNET_i2s (peer)); + } + GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count); + GNUNET_assert (NULL != n->address); + + if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address))) + { + GST_validation_set_address_use (n->address, n->session, GNUNET_YES); + GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES); + n->address_state = USED; + } + + GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in); + + /* send ACK (ACK) */ + msg_len = sizeof (msg); + msg.size = htons (msg_len); + msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK); + + ret = send_with_session(n, + (const char *) &msg, msg_len, + UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, + NULL, NULL); + + if (ret == GNUNET_SYSERR) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n", + GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session); + + + if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK) + n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n); + + neighbours_connected++; + GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1, + GNUNET_NO); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Notify about connect of `%4s' using address '%s' session %X LINE %u\n", + GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session, + __LINE__); +#endif + connect_notify_cb (callback_cls, &n->id, ats, ats_count); + send_outbound_quota (peer, n->bandwidth_out); + +} + + +void +GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) +{ + struct NeighbourMapEntry *n; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ACK message from peer `%s'\n", + GNUNET_i2s (peer)); +#endif + + if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return; + } + n = lookup_neighbour (peer); + if (NULL == n) + { + GNUNET_break (0); + return; + } + if (S_CONNECTED == n->state) + return; + if (!is_connecting (n)) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# unexpected ACK messages"), 1, + GNUNET_NO); + return; + } + change_state (n, S_CONNECTED); + if (NULL != session) + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "transport-ats", + "Giving ATS session %p of plugin %s for peer %s\n", + session, address->transport_name, GNUNET_i2s (peer)); + GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count); + GNUNET_assert (n->address != NULL); + + if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address))) + { + GST_validation_set_address_use (n->address, n->session, GNUNET_YES); + GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES); + n->address_state = USED; + } + + + neighbours_connected++; + GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1, + GNUNET_NO); + + GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in); + if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK) + n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Notify about connect of `%4s' using address '%s' session %X LINE %u\n", + GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session, + __LINE__); +#endif + connect_notify_cb (callback_cls, &n->id, ats, ats_count); + send_outbound_quota (peer, n->bandwidth_out); +} + +struct BlackListCheckContext +{ + struct GNUNET_ATS_Information *ats; + + uint32_t ats_count; + + struct Session *session; + + struct GNUNET_HELLO_Address *address; + + struct GNUNET_TIME_Absolute ts; +}; + + +static void +handle_connect_blacklist_cont (void *cls, + const struct GNUNET_PeerIdentity *peer, + int result) +{ + struct NeighbourMapEntry *n; + struct BlackListCheckContext *bcc = cls; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklist check due to CONNECT message: `%s'\n", + GNUNET_i2s (peer), + (result == GNUNET_OK) ? "ALLOWED" : "FORBIDDEN"); +#endif + + /* not allowed */ + if (GNUNET_OK != result) + { + GNUNET_HELLO_address_free (bcc->address); + GNUNET_free (bcc); + return; + } + + n = lookup_neighbour (peer); + if (NULL == n) + n = setup_neighbour (peer); + + if (bcc->ts.abs_value > n->connect_ts.abs_value) + { + if (NULL != bcc->session) + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "transport-ats", + "Giving ATS session %p of address `%s' for peer %s\n", + bcc->session, GST_plugins_a2s (bcc->address), + GNUNET_i2s (peer)); + /* Tell ATS about the session, so ATS can suggest it if it likes it. */ + + GNUNET_ATS_address_update (GST_ats, bcc->address, bcc->session, bcc->ats, + bcc->ats_count); + n->connect_ts = bcc->ts; + } + + GNUNET_HELLO_address_free (bcc->address); + GNUNET_free (bcc); + + if (n->state != S_CONNECT_RECV) + change_state (n, S_CONNECT_RECV); + + + /* Ask ATS for an address to connect via that address */ + if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->ats_suggest); + n->ats_suggest = + GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, + n); + GNUNET_ATS_suggest_address (GST_ats, peer); +} + +/** + * We received a 'SESSION_CONNECT' message from the other peer. + * Consider switching to it. + * + * @param message possibly a 'struct SessionConnectMessage' (check format) + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats (excluding 0-termination) + */ +void +GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count) +{ + const struct SessionConnectMessage *scm; + struct BlackListCheckContext *bcc = NULL; + struct NeighbourMapEntry *n; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received CONNECT message from peer `%s'\n", GNUNET_i2s (peer)); +#endif + + if (ntohs (message->size) != sizeof (struct SessionConnectMessage)) + { + GNUNET_break_op (0); + return; + } + + scm = (const struct SessionConnectMessage *) message; + GNUNET_break_op (ntohl (scm->reserved) == 0); + + GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count); + + n = lookup_neighbour (peer); + if ((n != NULL) && ((S_CONNECTED == n->state) || (S_FAST_RECONNECT == n->state))) + { + /* connected peer switches addresses or is trying to do a fast reconnect*/ + return; + } + + + /* we are not connected to this peer */ + /* do blacklist check */ + bcc = + GNUNET_malloc (sizeof (struct BlackListCheckContext) + + sizeof (struct GNUNET_ATS_Information) * (ats_count + 1)); + bcc->ts = GNUNET_TIME_absolute_ntoh (scm->timestamp); + bcc->ats_count = ats_count + 1; + bcc->address = GNUNET_HELLO_address_copy (address); + bcc->session = session; + bcc->ats = (struct GNUNET_ATS_Information *) &bcc[1]; + memcpy (bcc->ats, ats, sizeof (struct GNUNET_ATS_Information) * ats_count); + bcc->ats[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); + bcc->ats[ats_count].value = + htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value); + GST_blacklist_test_allowed (peer, address->transport_name, + &handle_connect_blacklist_cont, bcc); +} + + +/* end of file gnunet-service-transport_neighbours.c */ diff --git a/src/transport/gnunet-service-transport_neighbours.h b/src/transport/gnunet-service-transport_neighbours.h new file mode 100644 index 0000000..33fa1da --- /dev/null +++ b/src/transport/gnunet-service-transport_neighbours.h @@ -0,0 +1,314 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_neighbours.h + * @brief neighbour management API + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_TRANSPORT_NEIGHBOURS_H +#define GNUNET_SERVICE_TRANSPORT_NEIGHBOURS_H + +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" +#include "gnunet_util_lib.h" + +// TODO: +// - ATS and similar info is a bit lacking in the API right now... + + + +/** + * Initialize the neighbours subsystem. + * + * @param cls closure for callbacks + * @param connect_cb function to call if we connect to a peer + * @param disconnect_cb function to call if we disconnect from a peer + * @param peer_address_cb function to call if a neighbour's active address changes + */ +void +GST_neighbours_start (void *cls, + GNUNET_TRANSPORT_NotifyConnect connect_cb, + GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb, + GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb); + + +/** + * Cleanup the neighbours subsystem. + */ +void +GST_neighbours_stop (void); + + +/** + * Try to create a connection to the given target (eventually). + * + * @param target peer to try to connect to + */ +void +GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target); + + +/** + * Test if we're connected to the given peer. + * + * @param target peer to test + * @return GNUNET_YES if we are connected, GNUNET_NO if not + */ +int +GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target); + + +/** + * Function called after the transmission is done. + * + * @param cls closure + * @param success GNUNET_OK on success, GNUNET_NO on failure, GNUNET_SYSERR if we're not connected + */ +typedef void (*GST_NeighbourSendContinuation) (void *cls, int success); + + +/** + * Transmit a message to the given target using the active connection. + * + * @param target destination + * @param msg message to send + * @param msg_size number of bytes in msg + * @param timeout when to fail with timeout + * @param cont function to call when done + * @param cont_cls closure for 'cont' + */ +void +GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg, + size_t msg_size, struct GNUNET_TIME_Relative timeout, + GST_NeighbourSendContinuation cont, void *cont_cls); + + +/** + * We have received a message from the given sender. + * How long should we delay before receiving more? + * (Also used to keep the peer marked as live). + * + * @param sender sender of the message + * @param size size of the message + * @param do_forward set to GNUNET_YES if the message should be forwarded to clients + * GNUNET_NO if the neighbour is not connected or violates the quota + * @return how long to wait before reading more from this sender + */ +struct GNUNET_TIME_Relative +GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity + *sender, ssize_t size, int *do_forward); + + +/** + * Keep the connection to the given neighbour alive longer, + * we received a KEEPALIVE (or equivalent). + * + * @param neighbour neighbour to keep alive + */ +void +GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour); + +/** + * We received a KEEP_ALIVE_RESPONSE message and use this to calculate latency + * to this peer + * + * @param neighbour neighbour to keep alive + * @param ats performance data + * @param ats_count number of entries in ats + */ +void +GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count); + + +/** + * Change the incoming quota for the given peer. + * + * @param neighbour identity of peer to change qutoa for + * @param quota new quota + */ +void +GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour, + struct GNUNET_BANDWIDTH_Value32NBO quota); + + +/** + * If we have an active connection to the given target, it must be shutdown. + * + * @param target peer to disconnect from + */ +void +GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target); + + +/** + * Function called for each connected neighbour. + * + * @param cls closure + * @param neighbour identity of the neighbour + * @param ats performance data + * @param ats_count number of entries in ats (including 0-termination) + * @param address the address (or NULL) + */ +typedef void (*GST_NeighbourIterator) (void *cls, + const struct GNUNET_PeerIdentity * + neighbour, + const struct GNUNET_ATS_Information * + ats, uint32_t ats_count, + const struct GNUNET_HELLO_Address * + address); + + +/** + * Iterate over all connected neighbours. + * + * @param cb function to call + * @param cb_cls closure for cb + */ +void +GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls); + + +/** + * A session was terminated. Take note. + * + * @param peer identity of the peer where the session died + * @param session session that is gone + */ +void +GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, + struct Session *session); + + +/** + * For an existing neighbour record, set the active connection to + * use the given address. + * + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats + * @param bandwidth_in inbound quota to be used when connection is up + * @param bandwidth_out outbound quota to be used when connection is up + * @return GNUNET_YES if we are currently connected, GNUNET_NO if the + * connection is not up (yet) + */ +int +GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address + *address, struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out); + + +/** + * We received a 'SESSION_CONNECT' message from the other peer. + * Consider switching to it. + * + * @param message possibly a 'struct SessionConnectMessage' (check format) + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats (excluding 0-termination) + */ +void +GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count); + + +/** + * We received a 'SESSION_CONNECT_ACK' message from the other peer. + * Consider switching to it. + * + * @param message possibly a 'struct SessionConnectMessage' (check format) + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, NULL if other peer + * connected to us + * @param session session to use (or NULL) + * @param ats performance data + * @param ats_count number of entries in ats + */ +void +GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count); + +void +GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count); + + +/** + * Obtain current latency information for the given neighbour. + * + * @param peer + * @return observed latency of the address, FOREVER if the address was + * never successfully validated + */ +struct GNUNET_TIME_Relative +GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer); + + +/** + * Obtain current address information for the given neighbour. + * + * @param peer + * @return address currently used + */ +struct GNUNET_HELLO_Address * +GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer); + + +/** + * We received a disconnect message from the given peer, + * validate and process. + * + * @param peer sender of the message + * @param msg the disconnect message + */ +void +GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity + *peer, + const struct GNUNET_MessageHeader + *msg); + + +#endif +/* end of file gnunet-service-transport_neighbours.h */ diff --git a/src/transport/gnunet-service-transport_plugins.c b/src/transport/gnunet-service-transport_plugins.c new file mode 100644 index 0000000..fc14b6e --- /dev/null +++ b/src/transport/gnunet-service-transport_plugins.c @@ -0,0 +1,230 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_plugins.c + * @brief plugin management + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-transport.h" +#include "gnunet-service-transport_hello.h" +#include "gnunet-service-transport_plugins.h" + +/** + * Entry in doubly-linked list of all of our plugins. + */ +struct TransportPlugin +{ + /** + * This is a doubly-linked list. + */ + struct TransportPlugin *next; + + /** + * This is a doubly-linked list. + */ + struct TransportPlugin *prev; + + /** + * API of the transport as returned by the plugin's + * initialization function. + */ + struct GNUNET_TRANSPORT_PluginFunctions *api; + + /** + * Short name for the plugin (i.e. "tcp"). + */ + char *short_name; + + /** + * Name of the library (i.e. "gnunet_plugin_transport_tcp"). + */ + char *lib_name; + + /** + * Environment this transport service is using + * for this plugin. + */ + struct GNUNET_TRANSPORT_PluginEnvironment env; + +}; + +/** + * Head of DLL of all loaded plugins. + */ +static struct TransportPlugin *plugins_head; + +/** + * Head of DLL of all loaded plugins. + */ +static struct TransportPlugin *plugins_tail; + + + +/** + * Load and initialize all plugins. The respective functions will be + * invoked by the plugins when the respective events happen. The + * closure will be set to a 'const char*' containing the name of the + * plugin that caused the call. + * + * @param recv_cb function to call when data is received + * @param address_cb function to call when our public addresses changed + * @param session_end_cb function to call when a session was terminated + * @param address_type_cb function to call when a address type is requested + */ +void +GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb, + GNUNET_TRANSPORT_AddressNotification address_cb, + GNUNET_TRANSPORT_SessionEnd session_end_cb, + GNUNET_TRANSPORT_AddressToType address_type_cb) +{ + struct TransportPlugin *plug; + struct TransportPlugin *next; + unsigned long long tneigh; + char *libname; + char *plugs; + char *pos; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (GST_cfg, "TRANSPORT", + "NEIGHBOUR_LIMIT", &tneigh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Transport service is lacking NEIGHBOUR_LIMIT option.\n")); + return; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (GST_cfg, "TRANSPORT", "PLUGINS", + &plugs)) + return; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting transport plugins `%s'\n"), + plugs); + for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " ")) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' transport plugin\n"), + pos); + GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", pos); + plug = GNUNET_malloc (sizeof (struct TransportPlugin)); + plug->short_name = GNUNET_strdup (pos); + plug->lib_name = libname; + plug->env.cfg = GST_cfg; + plug->env.my_identity = &GST_my_identity; + plug->env.get_our_hello = &GST_hello_get; + plug->env.cls = plug->short_name; + plug->env.receive = recv_cb; + plug->env.notify_address = address_cb; + plug->env.session_end = session_end_cb; + plug->env.get_address_type = address_type_cb; + plug->env.max_connections = tneigh; + plug->env.stats = GST_stats; + GNUNET_CONTAINER_DLL_insert (plugins_head, plugins_tail, plug); + } + GNUNET_free (plugs); + next = plugins_head; + while (next != NULL) + { + plug = next; + next = plug->next; + plug->api = GNUNET_PLUGIN_load (plug->lib_name, &plug->env); + if (plug->api == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to load transport plugin for `%s'\n"), + plug->lib_name); + GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug); + GNUNET_free (plug->short_name); + GNUNET_free (plug->lib_name); + GNUNET_free (plug); + } + } +} + + +/** + * Unload all plugins + */ +void +GST_plugins_unload () +{ + struct TransportPlugin *plug; + + while (NULL != (plug = plugins_head)) + { + GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api)); + GNUNET_free (plug->lib_name); + GNUNET_free (plug->short_name); + GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug); + GNUNET_free (plug); + } +} + + +/** + * Obtain the plugin API based on a plugin name. + * + * @param name name of the plugin + * @return the plugin's API, NULL if the plugin is not loaded + */ +struct GNUNET_TRANSPORT_PluginFunctions * +GST_plugins_find (const char *name) +{ + struct TransportPlugin *head = plugins_head; + + while ((head != NULL) && (0 != strcmp (name, head->short_name))) + head = head->next; + if (NULL == head) + return NULL; + return head->api; +} + + +/** + * Convert a given address to a human-readable format. Note that the + * return value will be overwritten on the next call to this function. + * + * @param address the address to convert + * @return statically allocated (!) human-readable address + */ +const char * +GST_plugins_a2s (const struct GNUNET_HELLO_Address *address) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api; + static char unable_to_show[1024]; + + if (address == NULL) + return ""; + api = GST_plugins_find (address->transport_name); + if (NULL == api) + return ""; + if (0 == address->address_length) + { + GNUNET_snprintf (unable_to_show, sizeof (unable_to_show), + "", + (unsigned int) address->address_length, + address->transport_name); + return unable_to_show; + } + return api->address_to_string (NULL, address->address, + address->address_length); +} + + +/* end of file gnunet-service-transport_plugins.c */ diff --git a/src/transport/gnunet-service-transport_plugins.h b/src/transport/gnunet-service-transport_plugins.h new file mode 100644 index 0000000..04bb5ea --- /dev/null +++ b/src/transport/gnunet-service-transport_plugins.h @@ -0,0 +1,82 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_plugins.h + * @brief plugin management API + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_TRANSPORT_PLUGINS_H +#define GNUNET_SERVICE_TRANSPORT_PLUGINS_H + +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" + + +/** + * Load and initialize all plugins. The respective functions will be + * invoked by the plugins when the respective events happen. The + * closure will be set to a 'const char*' containing the name of the + * plugin that caused the call. + * + * @param recv_cb function to call when data is received + * @param address_cb function to call when our public addresses changed + * @param session_end_cb function to call when a session was terminated + * @param address_type_cb function to call when a address type is requested + */ +void +GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb, + GNUNET_TRANSPORT_AddressNotification address_cb, + GNUNET_TRANSPORT_SessionEnd session_end_cb, + GNUNET_TRANSPORT_AddressToType address_type_cb); + +/** + * Unload all plugins + */ +void +GST_plugins_unload (void); + + +/** + * Obtain the plugin API based on a plugin name. + * + * @param name name of the plugin + * @return the plugin's API, NULL if the plugin is not loaded + */ +struct GNUNET_TRANSPORT_PluginFunctions * +GST_plugins_find (const char *name); + + +/** + * Convert a given address to a human-readable format. Note that the + * return value will be overwritten on the next call to this function. + * + * @param address address to convert + * @return statically allocated (!) human-readable address + */ +const char * +GST_plugins_a2s (const struct GNUNET_HELLO_Address *address); + + +#endif +/* end of file gnunet-service-transport_plugins.h */ diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c new file mode 100644 index 0000000..a6d9424 --- /dev/null +++ b/src/transport/gnunet-service-transport_validation.c @@ -0,0 +1,1276 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_validation.c + * @brief address validation subsystem + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet-service-transport_validation.h" +#include "gnunet-service-transport_plugins.h" +#include "gnunet-service-transport_hello.h" +#include "gnunet-service-transport_blacklist.h" +#include "gnunet-service-transport.h" +#include "gnunet_hello_lib.h" +#include "gnunet_ats_service.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_signatures.h" + + +/** + * How long is a PONG signature valid? We'll recycle a signature until + * 1/4 of this time is remaining. PONGs should expire so that if our + * external addresses change an adversary cannot replay them indefinitely. + * OTOH, we don't want to spend too much time generating PONG signatures, + * so they must have some lifetime to reduce our CPU usage. + */ +#define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1) + +/** + * After how long do we expire an address in a HELLO that we just + * validated? This value is also used for our own addresses when we + * create a HELLO. + */ +#define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) + +/** + * How often do we allow PINGing an address that we have not yet + * validated? This also determines how long we track an address that + * we cannot validate (because after this time we can destroy the + * validation record). + */ +#define UNVALIDATED_PING_KEEPALIVE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) + +/** + * How often do we PING an address that we have successfully validated + * in the past but are not actively using? Should be (significantly) + * smaller than HELLO_ADDRESS_EXPIRATION. + */ +#define VALIDATED_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) + +/** + * How often do we PING an address that we are currently using? + */ +#define CONNECTED_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) + +/** + * How much delay is acceptable for sending the PING or PONG? + */ +#define ACCEPTABLE_PING_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * Size of the validation map hashmap. + */ +#define VALIDATION_MAP_SIZE 256 + +/** + * Priority to use for PINGs + */ +#define PING_PRIORITY 2 + +/** + * Priority to use for PONGs + */ +#define PONG_PRIORITY 4 + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message used to ask a peer to validate receipt (to check an address + * from a HELLO). Followed by the address we are trying to validate, + * or an empty address if we are just sending a PING to confirm that a + * connection which the receiver (of the PING) initiated is still valid. + */ +struct TransportPingMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING + */ + struct GNUNET_MessageHeader header; + + /** + * Challenge code (to ensure fresh reply). + */ + uint32_t challenge GNUNET_PACKED; + + /** + * Who is the intended recipient? + */ + struct GNUNET_PeerIdentity target; + +}; + + +/** + * Message used to validate a HELLO. The challenge is included in the + * confirmation to make matching of replies to requests possible. The + * signature signs our public key, an expiration time and our address.

+ * + * This message is followed by our transport address that the PING tried + * to confirm (if we liked it). The address can be empty (zero bytes) + * if the PING had not address either (and we received the request via + * a connection that we initiated). + */ +struct TransportPongMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG + */ + struct GNUNET_MessageHeader header; + + /** + * Challenge code from PING (showing freshness). Not part of what + * is signed so that we can re-use signatures. + */ + uint32_t challenge GNUNET_PACKED; + + /** + * Signature. + */ + struct GNUNET_CRYPTO_RsaSignature signature; + + /** + * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a + * plausible address for the signing peer. + */ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + /** + * When does this signature expire? + */ + struct GNUNET_TIME_AbsoluteNBO expiration; + + /** + * Size of address appended to this message (part of what is + * being signed, hence not redundant). + */ + uint32_t addrlen GNUNET_PACKED; + +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Information about an address under validation + */ +struct ValidationEntry +{ + + /** + * The address. + */ + struct GNUNET_HELLO_Address *address; + + /** + * Handle to the blacklist check (if we're currently in it). + */ + struct GST_BlacklistCheck *bc; + + /** + * Public key of the peer. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + + /** + * The identity of the peer. FIXME: duplicated (also in 'address') + */ + struct GNUNET_PeerIdentity pid; + + /** + * ID of task that will clean up this entry if nothing happens. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * ID of task that will trigger address revalidation. + */ + GNUNET_SCHEDULER_TaskIdentifier revalidation_task; + + /** + * At what time did we send the latest validation request (PING)? + */ + struct GNUNET_TIME_Absolute send_time; + + /** + * Until when is this address valid? + * ZERO if it is not currently considered valid. + */ + struct GNUNET_TIME_Absolute valid_until; + + /** + * How long until we can try to validate this address again? + * FOREVER if the address is for an unsupported plugin (from PEERINFO) + * ZERO if the address is considered valid (no validation needed) + * otherwise a time in the future if we're currently denying re-validation + */ + struct GNUNET_TIME_Absolute revalidation_block; + + /** + * Last observed latency for this address (round-trip), delay between + * last PING sent and PONG received; FOREVER if we never got a PONG. + */ + struct GNUNET_TIME_Relative latency; + + /** + * Challenge number we used. + */ + uint32_t challenge; + + /** + * When passing the address in 'add_valid_peer_address', did we + * copy the address to the HELLO yet? + */ + int copied; + + /** + * Are we currently using this address for a connection? + */ + int in_use; + + /** + * Are we expecting a PONG message for this validation entry? + */ + int expecting_pong; +}; + + +/** + * Context of currently active requests to peerinfo + * for validation of HELLOs. + */ +struct CheckHelloValidatedContext +{ + + /** + * This is a doubly-linked list. + */ + struct CheckHelloValidatedContext *next; + + /** + * This is a doubly-linked list. + */ + struct CheckHelloValidatedContext *prev; + + /** + * Hello that we are validating. + */ + const struct GNUNET_HELLO_Message *hello; + +}; + + +/** + * Head of linked list of HELLOs awaiting validation. + */ +static struct CheckHelloValidatedContext *chvc_head; + +/** + * Tail of linked list of HELLOs awaiting validation + */ +static struct CheckHelloValidatedContext *chvc_tail; + +/** + * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses + * of the given peer that we are currently validating, have validated + * or are blocked from re-validation for a while). + */ +static struct GNUNET_CONTAINER_MultiHashMap *validation_map; + +/** + * Context for peerinfo iteration. + */ +static struct GNUNET_PEERINFO_NotifyContext *pnc; + + +/** + * Context for the validation entry match function. + */ +struct ValidationEntryMatchContext +{ + /** + * Where to store the result? + */ + struct ValidationEntry *ve; + + /** + * Address we're interested in. + */ + const struct GNUNET_HELLO_Address *address; + +}; + + +/** + * Iterate over validation entries until a matching one is found. + * + * @param cls the 'struct ValidationEntryMatchContext' + * @param key peer identity (unused) + * @param value a 'struct ValidationEntry' to match + * @return GNUNET_YES if the entry does not match, + * GNUNET_NO if the entry does match + */ +static int +validation_entry_match (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ValidationEntryMatchContext *vemc = cls; + struct ValidationEntry *ve = value; + + if (0 == GNUNET_HELLO_address_cmp (ve->address, vemc->address)) + { + vemc->ve = ve; + return GNUNET_NO; + } + return GNUNET_YES; +} + + +/** + * Iterate over validation entries and free them. + * + * @param cls (unused) + * @param key peer identity (unused) + * @param value a 'struct ValidationEntry' to clean up + * @return GNUNET_YES (continue to iterate) + */ +static int +cleanup_validation_entry (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ValidationEntry *ve = value; + + if (NULL != ve->bc) + { + GST_blacklist_test_cancel (ve->bc); + ve->bc = NULL; + } + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (validation_map, + &ve->pid.hashPubKey, ve)); + GNUNET_HELLO_address_free (ve->address); + if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task) + { + GNUNET_SCHEDULER_cancel (ve->timeout_task); + ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != ve->revalidation_task) + { + GNUNET_SCHEDULER_cancel (ve->revalidation_task); + ve->revalidation_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (ve); + return GNUNET_OK; +} + + +/** + * Address validation cleanup task. Assesses if the record is no + * longer valid and then possibly triggers its removal. + * + * @param cls the 'struct ValidationEntry' + * @param tc scheduler context (unused) + */ +static void +timeout_hello_validation (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ValidationEntry *ve = cls; + struct GNUNET_TIME_Absolute max; + struct GNUNET_TIME_Relative left; + + ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; + max = GNUNET_TIME_absolute_max (ve->valid_until, ve->revalidation_block); + left = GNUNET_TIME_absolute_get_remaining (max); + if (left.rel_value > 0) + { + /* should wait a bit longer */ + ve->timeout_task = + GNUNET_SCHEDULER_add_delayed (left, &timeout_hello_validation, ve); + return; + } + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# address records discarded"), 1, + GNUNET_NO); + cleanup_validation_entry (NULL, &ve->pid.hashPubKey, ve); +} + + +/** + * Function called with the result from blacklisting. + * Send a PING to the other peer if a communication is allowed. + * + * @param cls our 'struct ValidationEntry' + * @param pid identity of the other peer + * @param result GNUNET_OK if the connection is allowed, GNUNET_NO if not + */ +static void +transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, + int result) +{ + struct ValidationEntry *ve = cls; + struct TransportPingMessage ping; + struct GNUNET_TRANSPORT_PluginFunctions *papi; + const struct GNUNET_MessageHeader *hello; + ssize_t ret; + size_t tsize; + size_t slen; + uint16_t hsize; + + ve->bc = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s' %s\n", + GNUNET_i2s (pid), GST_plugins_a2s (ve->address)); + + slen = strlen (ve->address->transport_name) + 1; + hello = GST_hello_get (); + hsize = ntohs (hello->size); + tsize = + sizeof (struct TransportPingMessage) + ve->address->address_length + + slen + hsize; + + ping.header.size = + htons (sizeof (struct TransportPingMessage) + + ve->address->address_length + slen); + ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING); + ping.challenge = htonl (ve->challenge); + ping.target = *pid; + + if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Not transmitting `%s' with `%s', message too big (%u bytes!). This should not happen.\n"), + "HELLO", "PING", (unsigned int) tsize); + /* message too big (!?), get rid of HELLO */ + hsize = 0; + tsize = + sizeof (struct TransportPingMessage) + ve->address->address_length + + slen + hsize; + } + { + char message_buf[tsize]; + + /* build message with structure: + * [HELLO][TransportPingMessage][Transport name][Address] */ + memcpy (message_buf, hello, hsize); + memcpy (&message_buf[hsize], &ping, sizeof (struct TransportPingMessage)); + memcpy (&message_buf[sizeof (struct TransportPingMessage) + hsize], + ve->address->transport_name, slen); + memcpy (&message_buf[sizeof (struct TransportPingMessage) + slen + hsize], + ve->address, ve->address->address_length); + papi = GST_plugins_find (ve->address->transport_name); + if (papi == NULL) + ret = -1; + else + { + GNUNET_assert (papi->send != NULL); + GNUNET_assert (papi->get_session != NULL); + struct Session * session = papi->get_session(papi->cls, ve->address); + + if (session != NULL) + { + ret = papi->send (papi->cls, session, + message_buf, tsize, + PING_PRIORITY, ACCEPTABLE_PING_DELAY, + NULL, NULL); + } + else + { + /* Could not get a valid session */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not get a valid session for `%s' %s\n", + GNUNET_i2s (pid), GST_plugins_a2s (ve->address)); + ret = -1; + } + } + } + if (-1 != ret) + { + ve->send_time = GNUNET_TIME_absolute_get (); + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# PING without HELLO messages sent"), 1, + GNUNET_NO); + ve->expecting_pong = GNUNET_YES; + } +} + + +/** + * Do address validation again to keep address valid. + * + * @param cls the 'struct ValidationEntry' + * @param tc scheduler context (unused) + */ +static void +revalidate_address (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ValidationEntry *ve = cls; + struct GNUNET_TIME_Relative canonical_delay; + struct GNUNET_TIME_Relative delay; + struct GST_BlacklistCheck *bc; + uint32_t rdelay; + + ve->revalidation_task = GNUNET_SCHEDULER_NO_TASK; + delay = GNUNET_TIME_absolute_get_remaining (ve->revalidation_block); + /* How long until we can possibly permit the next PING? */ + canonical_delay = + (ve->in_use == + GNUNET_YES) ? CONNECTED_PING_FREQUENCY + : ((GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value > + 0) ? VALIDATED_PING_FREQUENCY : UNVALIDATED_PING_KEEPALIVE); + if (delay.rel_value > canonical_delay.rel_value * 2) + { + /* situation changed, recalculate delay */ + delay = canonical_delay; + ve->revalidation_block = GNUNET_TIME_relative_to_absolute (delay); + } + if (delay.rel_value > 0) + { + /* should wait a bit longer */ + ve->revalidation_task = + GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); + return; + } + ve->revalidation_block = GNUNET_TIME_relative_to_absolute (canonical_delay); + + /* schedule next PINGing with some extra random delay to avoid synchronous re-validations */ + rdelay = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + canonical_delay.rel_value); + delay = + GNUNET_TIME_relative_add (canonical_delay, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, rdelay)); + ve->revalidation_task = + GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); + + /* start PINGing by checking blacklist */ + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# address revalidations started"), 1, + GNUNET_NO); + bc = GST_blacklist_test_allowed (&ve->pid, ve->address->transport_name, + &transmit_ping_if_allowed, ve); + if (NULL != bc) + ve->bc = bc; /* only set 'bc' if 'transmit_ping_if_allowed' was not already + * called... */ +} + + +/** + * Find a ValidationEntry entry for the given neighbour that matches + * the given address and transport. If none exists, create one (but + * without starting any validation). + * + * @param public_key public key of the peer, NULL for unknown + * @param address address to find + * @return validation entry matching the given specifications, NULL + * if we don't have an existing entry and no public key was given + */ +static struct ValidationEntry * +find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *public_key, const struct GNUNET_HELLO_Address *address) +{ + struct ValidationEntryMatchContext vemc; + struct ValidationEntry *ve; + + vemc.ve = NULL; + vemc.address = address; + GNUNET_CONTAINER_multihashmap_get_multiple (validation_map, + &address->peer.hashPubKey, + &validation_entry_match, &vemc); + if (NULL != (ve = vemc.ve)) + return ve; + if (public_key == NULL) + return NULL; + ve = GNUNET_malloc (sizeof (struct ValidationEntry)); + ve->address = GNUNET_HELLO_address_copy (address); + ve->public_key = *public_key; + ve->pid = address->peer; + ve->latency = GNUNET_TIME_UNIT_FOREVER_REL; + ve->challenge = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + ve->timeout_task = + GNUNET_SCHEDULER_add_delayed (UNVALIDATED_PING_KEEPALIVE, + &timeout_hello_validation, ve); + GNUNET_CONTAINER_multihashmap_put (validation_map, &address->peer.hashPubKey, + ve, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + ve->expecting_pong = GNUNET_NO; + return ve; +} + + +/** + * Iterator which adds the given address to the set of validated + * addresses. + * + * @param cls original HELLO message + * @param address the address + * @param expiration expiration time + * @return GNUNET_OK (keep the address) + */ +static int +add_valid_address (void *cls, const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + const struct GNUNET_HELLO_Message *hello = cls; + struct ValidationEntry *ve; + struct GNUNET_PeerIdentity pid; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + + if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) + return GNUNET_OK; /* expired */ + if ((GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) || + (GNUNET_OK != GNUNET_HELLO_get_key (hello, &public_key))) + { + GNUNET_break (0); + return GNUNET_OK; /* invalid HELLO !? */ + } + if (0 == memcmp (&GST_my_identity, &pid, sizeof (struct GNUNET_PeerIdentity))) + { + /* Peerinfo returned own identity, skip validation */ + return GNUNET_OK; + } + + ve = find_validation_entry (&public_key, address); + ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until, expiration); + + if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task) + ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); + GNUNET_ATS_address_update (GST_ats, address, NULL, NULL, 0); + return GNUNET_OK; +} + + +/** + * Function called for any HELLO known to PEERINFO. + * + * @param cls unused + * @param peer id of the peer, NULL for last call + * @param hello hello message for the peer (can be NULL) + * @param err_msg error message + */ +static void +process_peerinfo_hello (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, + const char *err_msg) +{ + GNUNET_assert (NULL != peer); + if (NULL == hello) + return; + GNUNET_assert (NULL == + GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, + &add_valid_address, + (void *) hello)); +} + + +/** + * Start the validation subsystem. + */ +void +GST_validation_start () +{ + validation_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE); + pnc = GNUNET_PEERINFO_notify (GST_cfg, &process_peerinfo_hello, NULL); +} + + +/** + * Stop the validation subsystem. + */ +void +GST_validation_stop () +{ + struct CheckHelloValidatedContext *chvc; + + GNUNET_CONTAINER_multihashmap_iterate (validation_map, + &cleanup_validation_entry, NULL); + GNUNET_CONTAINER_multihashmap_destroy (validation_map); + validation_map = NULL; + while (NULL != (chvc = chvc_head)) + { + GNUNET_CONTAINER_DLL_remove (chvc_head, chvc_tail, chvc); + GNUNET_free (chvc); + } + GNUNET_PEERINFO_notify_cancel (pnc); +} + + +/** + * Send the given PONG to the given address. + * + * @param cls the PONG message + * @param public_key public key for the peer, never NULL + * @param valid_until is ZERO if we never validated the address, + * otherwise a time up to when we consider it (or was) valid + * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO) + * is ZERO if the address is considered valid (no validation needed) + * otherwise a time in the future if we're currently denying re-validation + * @param address target address + */ +static void +multicast_pong (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *public_key, struct GNUNET_TIME_Absolute valid_until, + struct GNUNET_TIME_Absolute validation_block, + const struct GNUNET_HELLO_Address *address) +{ + struct TransportPongMessage *pong = cls; + struct GNUNET_TRANSPORT_PluginFunctions *papi; + + papi = GST_plugins_find (address->transport_name); + if (papi == NULL) + return; + + GNUNET_assert (papi->send != NULL); + GNUNET_assert (papi->get_session != NULL); + + struct Session * session = papi->get_session(papi->cls, address); + if (session == NULL) + { + GNUNET_break (0); + return; + } + + papi->send (papi->cls, session, + (const char *) pong, ntohs (pong->header.size), + PONG_PRIORITY, ACCEPTABLE_PING_DELAY, + NULL, NULL); +} + + +/** + * We've received a PING. If appropriate, generate a PONG. + * + * @param sender peer sending the PING + * @param hdr the PING + * @param sender_address the sender address as we got it + * @param session session we got the PING from + */ +void +GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *hdr, + const struct GNUNET_HELLO_Address *sender_address, + struct Session *session) +{ + const struct TransportPingMessage *ping; + struct TransportPongMessage *pong; + struct GNUNET_TRANSPORT_PluginFunctions *papi; + struct GNUNET_CRYPTO_RsaSignature *sig_cache; + struct GNUNET_TIME_Absolute *sig_cache_exp; + const char *addr; + const char *addrend; + size_t alen; + size_t slen; + ssize_t ret; + struct GNUNET_HELLO_Address address; + + if (ntohs (hdr->size) < sizeof (struct TransportPingMessage)) + { + GNUNET_break_op (0); + return; + } + ping = (const struct TransportPingMessage *) hdr; + if (0 != + memcmp (&ping->target, &GST_my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# PING message for different peer received"), 1, + GNUNET_NO); + return; + } + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# PING messages received"), 1, + GNUNET_NO); + addr = (const char *) &ping[1]; + alen = ntohs (hdr->size) - sizeof (struct TransportPingMessage); + /* peer wants to confirm that this is one of our addresses, this is what is + * used for address validation */ + + sig_cache = NULL; + sig_cache_exp = NULL; + + if (0 < alen) + { + addrend = memchr (addr, '\0', alen); + if (NULL == addrend) + { + GNUNET_break_op (0); + return; + } + addrend++; + slen = strlen (addr) + 1; + alen -= slen; + address.address = addrend; + address.address_length = alen; + address.transport_name = addr; + address.peer = *sender; + if (GNUNET_YES != + GST_hello_test_address (&address, &sig_cache, &sig_cache_exp)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Not confirming PING with address `%s' since I cannot confirm having this address.\n"), + GST_plugins_a2s (&address)); + return; + } + } + else + { + addrend = NULL; /* make gcc happy */ + slen = 0; + static struct GNUNET_CRYPTO_RsaSignature no_address_signature; + static struct GNUNET_TIME_Absolute no_address_signature_expiration; + + sig_cache = &no_address_signature; + sig_cache_exp = &no_address_signature_expiration; + } + + pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen); + pong->header.size = + htons (sizeof (struct TransportPongMessage) + alen + slen); + pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG); + pong->purpose.size = + htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + + alen + slen); + pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN); + pong->challenge = ping->challenge; + pong->addrlen = htonl (alen + slen); + memcpy (&pong[1], addr, slen); + memcpy (&((char *) &pong[1])[slen], addrend, alen); + if (GNUNET_TIME_absolute_get_remaining (*sig_cache_exp).rel_value < + PONG_SIGNATURE_LIFETIME.rel_value / 4) + { + /* create / update cached sig */ +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating PONG signature to indicate ownership.\n"); +#endif + *sig_cache_exp = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME); + pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (GST_my_private_key, &pong->purpose, + sig_cache)); + } + else + { + pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp); + } + pong->signature = *sig_cache; + + GNUNET_assert (sender_address != NULL); + + /* first see if the session we got this PING from can be used to transmit + * a response reliably */ + papi = GST_plugins_find (sender_address->transport_name); + if (papi == NULL) + ret = -1; + else + { + GNUNET_assert (papi->send != NULL); + GNUNET_assert (papi->get_session != NULL); + + if (session == NULL) + { + session = papi->get_session (papi->cls, sender_address); + } + if (session == NULL) + { + GNUNET_break (0); + ret = -1; + } + else + { + ret = papi->send (papi->cls, session, + (const char *) pong, ntohs (pong->header.size), + PONG_PRIORITY, ACCEPTABLE_PING_DELAY, + NULL, NULL); + } + } + if (ret != -1) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitted PONG to `%s' via reliable mechanism\n", + GNUNET_i2s (sender)); + /* done! */ + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# PONGs unicast via reliable transport"), 1, + GNUNET_NO); + GNUNET_free (pong); + return; + } + + /* no reliable method found, try transmission via all known addresses */ + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# PONGs multicast to all available addresses"), 1, + GNUNET_NO); + GST_validation_get_addresses (sender, &multicast_pong, pong); + GNUNET_free (pong); +} + + +/** + * Context for the 'validate_address' function + */ +struct ValidateAddressContext +{ + /** + * Hash of the public key of the peer whose address is being validated. + */ + struct GNUNET_PeerIdentity pid; + + /** + * Public key of the peer whose address is being validated. + */ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; +}; + + +/** + * Iterator callback to go over all addresses and try to validate them + * (unless blocked or already validated). + * + * @param cls pointer to a 'struct ValidateAddressContext' + * @param address the address + * @param expiration expiration time + * @return GNUNET_OK (keep the address) + */ +static int +validate_address_iterator (void *cls, + const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + const struct ValidateAddressContext *vac = cls; + struct ValidationEntry *ve; + + if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) + return GNUNET_OK; /* expired */ + ve = find_validation_entry (&vac->public_key, address); + if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task) + ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); + return GNUNET_OK; +} + + +/** + * Add the validated peer address to the HELLO. + * + * @param cls the 'struct ValidationEntry' with the validated address + * @param max space in buf + * @param buf where to add the address + * @return number of bytes written, 0 to signal the + * end of the iteration. + */ +static size_t +add_valid_peer_address (void *cls, size_t max, void *buf) +{ + struct ValidationEntry *ve = cls; + + if (GNUNET_YES == ve->copied) + return 0; /* terminate */ + ve->copied = GNUNET_YES; + return GNUNET_HELLO_add_address (ve->address, ve->valid_until, buf, max); +} + + +/** + * We've received a PONG. Check if it matches a pending PING and + * mark the respective address as confirmed. + * + * @param sender peer sending the PONG + * @param hdr the PONG + */ +void +GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *hdr) +{ + const struct TransportPongMessage *pong; + struct ValidationEntry *ve; + const char *tname; + const char *addr; + size_t addrlen; + size_t slen; + size_t size; + struct GNUNET_HELLO_Message *hello; + struct GNUNET_HELLO_Address address; + + if (ntohs (hdr->size) < sizeof (struct TransportPongMessage)) + { + GNUNET_break_op (0); + return; + } + GNUNET_STATISTICS_update (GST_stats, + gettext_noop ("# PONG messages received"), 1, + GNUNET_NO); + + pong = (const struct TransportPongMessage *) hdr; + tname = (const char *) &pong[1]; + size = ntohs (hdr->size) - sizeof (struct TransportPongMessage); + addr = memchr (tname, '\0', size); + if (NULL == addr) + { + GNUNET_break_op (0); + return; + } + addr++; + slen = strlen (tname) + 1; + addrlen = size - slen; + address.peer = *sender; + address.address = addr; + address.address_length = addrlen; + address.transport_name = tname; + ve = find_validation_entry (NULL, &address); + if ((NULL == ve) || (ve->expecting_pong == GNUNET_NO)) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# PONGs dropped, no matching pending validation"), + 1, GNUNET_NO); + return; + } + /* now check that PONG is well-formed */ + if (0 != memcmp (&ve->pid, sender, sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_break_op (0); + return; + } + + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN, + &pong->purpose, &pong->signature, + &ve->public_key)) + { + GNUNET_break_op (0); + return; + } + + if (GNUNET_TIME_absolute_get_remaining + (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0) + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# PONGs dropped, signature expired"), 1, + GNUNET_NO); + return; + } +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Address validated for peer `%s' with plugin `%s': `%s'\n", + GNUNET_i2s (sender), tname, GST_plugins_a2s (tname, addr, + addrlen)); +#endif + + /* validity achieved, remember it! */ + ve->expecting_pong = GNUNET_NO; + ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); + ve->latency = GNUNET_TIME_absolute_get_duration (ve->send_time); + { + struct GNUNET_ATS_Information ats; + + ats.type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); + ats.value = htonl ((uint32_t) ve->latency.rel_value); + GNUNET_ATS_address_update (GST_ats, ve->address, NULL, &ats, 1); + } + /* build HELLO to store in PEERINFO */ + ve->copied = GNUNET_NO; + hello = GNUNET_HELLO_create (&ve->public_key, &add_valid_peer_address, ve); + GNUNET_PEERINFO_add_peer (GST_peerinfo, hello); + GNUNET_free (hello); +} + + +/** + * We've received a HELLO, check which addresses are new and trigger + * validation. + * + * @param hello the HELLO we received + */ +void +GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) +{ + const struct GNUNET_HELLO_Message *hm = + (const struct GNUNET_HELLO_Message *) hello; + struct ValidateAddressContext vac; + struct GNUNET_HELLO_Message *h; + + if ((GNUNET_OK != GNUNET_HELLO_get_id (hm, &vac.pid)) || + (GNUNET_OK != GNUNET_HELLO_get_key (hm, &vac.public_key))) + { + /* malformed HELLO */ + GNUNET_break (0); + return; + } + if (0 == + memcmp (&GST_my_identity, &vac.pid, sizeof (struct GNUNET_PeerIdentity))) + return; + /* Add peer identity without addresses to peerinfo service */ + h = GNUNET_HELLO_create (&vac.public_key, NULL, NULL); + GNUNET_PEERINFO_add_peer (GST_peerinfo, h); +#if VERBOSE_VALIDATION + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Adding `%s' without addresses for peer `%s'\n"), "HELLO", + GNUNET_i2s (&vac.pid)); +#endif + GNUNET_free (h); + GNUNET_assert (NULL == + GNUNET_HELLO_iterate_addresses (hm, GNUNET_NO, + &validate_address_iterator, + &vac)); +} + + +/** + * Closure for 'iterate_addresses' + */ +struct IteratorContext +{ + /** + * Function to call on each address. + */ + GST_ValidationAddressCallback cb; + + /** + * Closure for 'cb'. + */ + void *cb_cls; + +}; + + +/** + * Call the callback in the closure for each validation entry. + * + * @param cls the 'struct GST_ValidationIteratorContext' + * @param key the peer's identity + * @param value the 'struct ValidationEntry' + * @return GNUNET_OK (continue to iterate) + */ +static int +iterate_addresses (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct IteratorContext *ic = cls; + struct ValidationEntry *ve = value; + + ic->cb (ic->cb_cls, &ve->public_key, ve->valid_until, ve->revalidation_block, + ve->address); + return GNUNET_OK; +} + + +/** + * Call the given function for each address for the given target. + * Can either give a snapshot (synchronous API) or be continuous. + * + * @param target peer information is requested for + * @param cb function to call; will not be called after this function returns + * @param cb_cls closure for 'cb' + */ +void +GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, + GST_ValidationAddressCallback cb, void *cb_cls) +{ + struct IteratorContext ic; + + ic.cb = cb; + ic.cb_cls = cb_cls; + GNUNET_CONTAINER_multihashmap_get_multiple (validation_map, + &target->hashPubKey, + &iterate_addresses, &ic); +} + + +/** + * Update if we are using an address for a connection actively right now. + * Based on this, the validation module will measure latency for the + * address more or less often. + * + * @param address the address + * @param session the session + * @param in_use GNUNET_YES if we are now using the address for a connection, + * GNUNET_NO if we are no longer using the address for a connection + */ +void +GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address, + struct Session *session, + int in_use) +{ + struct ValidationEntry *ve; + + if (NULL != address) + ve = find_validation_entry (NULL, address); + else + ve = NULL; /* FIXME: lookup based on session... */ + if (NULL == ve) + { + /* this can happen for inbound connections (sender_address_len == 0); */ + return; + } + if (ve->in_use == in_use) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "GST_validation_set_address_use: %s %s: ve->in_use %i <-> in_use %i\n", + GNUNET_i2s (&address->peer), GST_plugins_a2s (address), ve->in_use, + in_use); + GNUNET_break (ve->in_use != in_use); /* should be different... */ + ve->in_use = in_use; + if (in_use == GNUNET_YES) + { + /* from now on, higher frequeny, so reschedule now */ + GNUNET_SCHEDULER_cancel (ve->revalidation_task); + ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); + } +} + + +/** + * Query validation about the latest observed latency on a given + * address. + * + * @param sender peer + * @param address the address + * @param session session + * @return observed latency of the address, FOREVER if the address was + * never successfully validated + */ +struct GNUNET_TIME_Relative +GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_HELLO_Address *address, + struct Session *session) +{ + struct ValidationEntry *ve; + + if (NULL == address) + { + GNUNET_break (0); // FIXME: support having latency only with session... + return GNUNET_TIME_UNIT_FOREVER_REL; + } + ve = find_validation_entry (NULL, address); + if (NULL == ve) + return GNUNET_TIME_UNIT_FOREVER_REL; + return ve->latency; +} + + +/* end of file gnunet-service-transport_validation.c */ diff --git a/src/transport/gnunet-service-transport_validation.h b/src/transport/gnunet-service-transport_validation.h new file mode 100644 index 0000000..9b1063b --- /dev/null +++ b/src/transport/gnunet-service-transport_validation.h @@ -0,0 +1,155 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_validation.h + * @brief address validation API + * @author Christian Grothoff + */ +#ifndef GNUNET_SERVICE_TRANSPORT_VALIDATION_H +#define GNUNET_SERVICE_TRANSPORT_VALIDATION_H + +#include "gnunet_statistics_service.h" +#include "gnunet_transport_plugin.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" + + +/** + * Start the validation subsystem. + */ +void +GST_validation_start (void); + + +/** + * Stop the validation subsystem. + */ +void +GST_validation_stop (void); + + +/** + * Update if we are using an address for a connection actively right now. + * Based on this, the validation module will measure latency for the + * address more or less often. + * + * @param address the address + * @param session session + * @param in_use GNUNET_YES if we are now using the address for a connection, + * GNUNET_NO if we are no longer using the address for a connection + */ +void +GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address, + struct Session *session, int in_use); + + +/** + * Query validation about the latest observed latency on a given + * address. + * + * @param sender peer + * @param address the address + * @param session session + * @return observed latency of the address, FOREVER if the address was + * never successfully validated + */ +struct GNUNET_TIME_Relative +GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_HELLO_Address *address, + struct Session *session); + + +/** + * We've received a PING. If appropriate, generate a PONG. + * + * @param sender peer sending the PING + * @param hdr the PING + * @param sender_address address of the sender, NULL if we did not initiate + * @param session session we got the PING from + */ +void +GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *hdr, + const struct GNUNET_HELLO_Address *sender_address, + struct Session *session); + + +/** + * We've received a PONG. Check if it matches a pending PING and + * mark the respective address as confirmed. + * + * @param sender peer sending the PONG + * @param hdr the PONG + */ +void +GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *hdr); + + +/** + * We've received a HELLO, check which addresses are new and trigger + * validation. + * + * @param hello the HELLO we received + */ +void +GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello); + + +/** + * Function called for each address (or address status change) that + * the validation module is aware of (for the given target). + * + * @param cls closure + * @param public_key public key for the peer, never NULL + * @param valid_until is ZERO if we never validated the address, + * otherwise a time up to when we consider it (or was) valid + * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO) + * is ZERO if the address is considered valid (no validation needed) + * otherwise a time in the future if we're currently denying re-validation + * @param address the address + */ +typedef void (*GST_ValidationAddressCallback) (void *cls, + const struct + GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + * public_key, + struct GNUNET_TIME_Absolute + valid_until, + struct GNUNET_TIME_Absolute + validation_block, + const struct GNUNET_HELLO_Address + * address); + + +/** + * Call the given function for each address for the given target. + * + * @param target peer information is requested for + * @param cb function to call; will not be called after this function returns + * @param cb_cls closure for 'cb' + */ +void +GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, + GST_ValidationAddressCallback cb, void *cb_cls); + + +#endif +/* end of file gnunet-service-transport_validation.h */ diff --git a/src/transport/gnunet-transport-certificate-creation b/src/transport/gnunet-transport-certificate-creation new file mode 100755 index 0000000..a38a7b7 --- /dev/null +++ b/src/transport/gnunet-transport-certificate-creation @@ -0,0 +1,148 @@ +#! /bin/bash + +# gnunet-transport-certificate-creation - temporary wrapper script for .libs/gnunet-transport-certificate-creation +# Generated by ltmain.sh (GNU libtool) 2.2.6b Debian-2.2.6b-2 +# +# The gnunet-transport-certificate-creation program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='/bin/sed -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command="(cd /home/grothoff/svn/gnunet/src/transport; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; LD_LIBRARY_PATH=/usr/lib/debug:/home/grothoff/lib; export LD_LIBRARY_PATH; PATH=/opt/jdk1.6.0_22/bin:/usr/lib/jvm/java-6-sun//bin:.:/home/grothoff/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games; export PATH; gcc -fno-strict-aliasing -Wall -g -Wall -Werror -O0 -I/home/grothoff//include -o \$progdir/\$file gnunet-transport-certificate-creation.o -L/home/grothoff//lib ../../src/util/.libs/libgnunetutil.so -ldl -Wl,-rpath -Wl,/home/grothoff/svn/gnunet/src/util/.libs -Wl,-rpath -Wl,/home/grothoff/lib)" + +# This environment variable determines our operation mode. +if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then + # install mode needs the following variables: + generated_by_libtool_version='2.2.6b' + notinst_deplibs=' ../../src/util/libgnunetutil.la' +else + # When we are sourced in execute mode, $file and $ECHO are already set. + if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then + ECHO="echo" + file="$0" + # Make sure echo works. + if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then + # Yippee, $ECHO works! + : + else + # Restart under the correct shell, and then maybe $ECHO will work. + exec /bin/bash "$0" --no-reexec ${1+"$@"} + fi + fi + + # Find the directory that this script lives in. + thisdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "x$thisdir" = "x$file" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'` + while test -n "$file"; do + destdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'` + + # If there was a directory component, then change thisdir. + if test "x$destdir" != "x$file"; then + case "$destdir" in + [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;; + *) thisdir="$thisdir/$destdir" ;; + esac + fi + + file=`$ECHO "X$file" | $Xsed -e 's%^.*/%%'` + file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'` + done + + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no + if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then + # special case for '.' + if test "$thisdir" = "."; then + thisdir=`pwd` + fi + # remove .libs from thisdir + case "$thisdir" in + *[\\/].libs ) thisdir=`$ECHO "X$thisdir" | $Xsed -e 's%[\\/][^\\/]*$%%'` ;; + .libs ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=`cd "$thisdir" && pwd` + test -n "$absdir" && thisdir="$absdir" + + program=lt-'gnunet-transport-certificate-creation' + progdir="$thisdir/.libs" + + if test ! -f "$progdir/$program" || + { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \ + test "X$file" != "X$progdir/$program"; }; then + + file="$$-$program" + + if test ! -d "$progdir"; then + mkdir "$progdir" + else + rm -f "$progdir/$file" + fi + + # relink executable if necessary + if test -n "$relink_command"; then + if relink_command_output=`eval $relink_command 2>&1`; then : + else + echo "$relink_command_output" >&2 + rm -f "$progdir/$file" + exit 1 + fi + fi + + mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null || + { rm -f "$progdir/$program"; + mv -f "$progdir/$file" "$progdir/$program"; } + rm -f "$progdir/$file" + fi + + if test -f "$progdir/$program"; then + if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then + # Run the actual program with our arguments. + + exec "$progdir/$program" ${1+"$@"} + + $ECHO "$0: cannot exec $program $*" 1>&2 + exit 1 + fi + else + # The program doesn't exist. + $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2 + $ECHO "This script is just a wrapper for $program." 1>&2 + echo "See the libtool documentation for more information." 1>&2 + exit 1 + fi +fi diff --git a/src/transport/gnunet-transport-certificate-creation.c b/src/transport/gnunet-transport-certificate-creation.c new file mode 100644 index 0000000..2ec8d36 --- /dev/null +++ b/src/transport/gnunet-transport-certificate-creation.c @@ -0,0 +1,82 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-transport-certificate-creation.c + * @brief create certificate for HTTPS transport + * @author LRN + * + */ +#include "platform.h" +#include "gnunet_disk_lib.h" +#include "gnunet_os_lib.h" + + +static void +removecerts (const char *file1, const char *file2) +{ + if (GNUNET_DISK_file_test (file1) == GNUNET_YES) + { + CHMOD (file1, S_IWUSR | S_IRUSR); + REMOVE (file1); + } + if (GNUNET_DISK_file_test (file2) == GNUNET_YES) + { + CHMOD (file2, S_IWUSR | S_IRUSR); + REMOVE (file2); + } +} + + +int +main (int argc, char **argv) +{ + struct GNUNET_OS_Process *openssl; + + if (argc != 3) + return 1; + removecerts (argv[1], argv[2]); + close (2); /* eliminate stderr */ + /* Create RSA Private Key */ + /* openssl genrsa -out $1 1024 2> /dev/null */ + openssl = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "openssl", "openssl", "genrsa", + "-out", argv[1], "1024", NULL); + if (openssl == NULL) + return 2; + GNUNET_assert (GNUNET_OS_process_wait (openssl) == GNUNET_OK); + GNUNET_OS_process_close (openssl); + + /* Create a self-signed certificate in batch mode using rsa key */ + /* openssl req -batch -days 365 -out $2 -new -x509 -key $1 2> /dev/null */ + openssl = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "openssl", "openssl", "req", + "-batch", "-days", "365", "-out", argv[2], + "-new", "-x509", "-key", argv[1], NULL); + if (openssl == NULL) + return 3; + GNUNET_assert (GNUNET_OS_process_wait (openssl) == GNUNET_OK); + GNUNET_OS_process_close (openssl); + CHMOD (argv[1], S_IRUSR); + CHMOD (argv[2], S_IRUSR); + return 0; +} + +/* end of gnunet-transport-certificate-creation.c */ diff --git a/src/transport/gnunet-transport-wlan-sender.c b/src/transport/gnunet-transport-wlan-sender.c new file mode 100644 index 0000000..9f06b63 --- /dev/null +++ b/src/transport/gnunet-transport-wlan-sender.c @@ -0,0 +1,237 @@ +/* + This file is part of GNUnet + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file transport/gnunet-transport-wlan-sender.c + * @brief program to send via WLAN as much as possible (to test physical/theoretical throughput) + * @author David Brodski + */ +#include "platform.h" +#include "gnunet_protocols.h" +#include "plugin_transport_wlan.h" + +#define WLAN_MTU 1500 + +/** + * LLC fields for better compatibility + */ +#define WLAN_LLC_DSAP_FIELD 0x1f +#define WLAN_LLC_SSAP_FIELD 0x1f + +#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ + +#define IEEE80211_FC0_VERSION_MASK 0x03 +#define IEEE80211_FC0_VERSION_SHIFT 0 +#define IEEE80211_FC0_VERSION_0 0x00 +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_SHIFT 2 +#define IEEE80211_FC0_TYPE_MGT 0x00 +#define IEEE80211_FC0_TYPE_CTL 0x04 +#define IEEE80211_FC0_TYPE_DATA 0x08 + +GNUNET_NETWORK_STRUCT_BEGIN + +/* + * generic definitions for IEEE 802.11 frames + */ +struct ieee80211_frame +{ + u_int8_t i_fc[2]; + u_int8_t i_dur[2]; + u_int8_t i_addr1[IEEE80211_ADDR_LEN]; + u_int8_t i_addr2[IEEE80211_ADDR_LEN]; + u_int8_t i_addr3[IEEE80211_ADDR_LEN]; + u_int8_t i_seq[2]; + u_int8_t llc[4]; +} GNUNET_PACKED; +GNUNET_NETWORK_STRUCT_END + +/** + * function to fill the radiotap header + * @param header pointer to the radiotap header + * @return GNUNET_YES at success + */ +static int +getRadiotapHeader (struct Radiotap_Send *header) +{ + header->rate = 255; + header->tx_power = 0; + header->antenna = 0; + + return GNUNET_YES; +} + +/** + * function to generate the wlan hardware header for one packet + * @param Header address to write the header to + * @param to_mac_addr pointer to the address of the recipient + * @param mac pointer to the mac address to send from (normally overwritten over by helper) + * @param size size of the whole packet, needed to calculate the time to send the packet + * @return GNUNET_YES if there was no error + */ +static int +getWlanHeader (struct ieee80211_frame *Header, const char *to_mac_addr, + const char *mac, unsigned int size) +{ + uint16_t *tmp16; + const int rate = 11000000; + + Header->i_fc[0] = IEEE80211_FC0_TYPE_DATA; + Header->i_fc[1] = 0x00; + memcpy (&Header->i_addr3, &mac_bssid_gnunet, sizeof (mac_bssid_gnunet)); + memcpy (&Header->i_addr2, mac, sizeof (mac_bssid_gnunet)); + memcpy (&Header->i_addr1, to_mac_addr, sizeof (mac_bssid_gnunet)); + + tmp16 = (uint16_t *) Header->i_dur; + *tmp16 = (uint16_t) GNUNET_htole16 ((size * 1000000) / rate + 290); + Header->llc[0] = WLAN_LLC_DSAP_FIELD; + Header->llc[1] = WLAN_LLC_SSAP_FIELD; + + return GNUNET_YES; +} + + +int +main (int argc, char *argv[]) +{ + char msg_buf[WLAN_MTU]; + struct GNUNET_MessageHeader *msg; + struct ieee80211_frame *wlan_header; + struct Radiotap_Send *radiotap; + + unsigned int temp[6]; + char inmac[6]; + char outmac[6]; + int pos; + long long count; + double bytes_per_s; + time_t start; + time_t akt; + int i; + + if (4 != argc) + { + fprintf (stderr, + "This program must be started with the interface and the targets and source mac as argument.\n"); + fprintf (stderr, + "Usage: interface-name mac-target mac-source\n" + "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n"); + return 1; + } + if (6 != + sscanf (argv[3], "%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2], + &temp[3], &temp[4], &temp[5])) + { + fprintf (stderr, + "Usage: interface-name mac-target mac-source\n" + "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n"); + return 1; + } + if (6 != + sscanf (argv[2], "%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2], + &temp[3], &temp[4], &temp[5])) + { + fprintf (stderr, + "Usage: interface-name mac-target mac-source\n" + "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n"); + return 1; + } + for (i = 0; i < 6; i++) + inmac[i] = temp[i]; + for (i = 0; i < 6; i++) + outmac[i] = temp[i]; + + pid_t pid; + int commpipe[2]; /* This holds the fd for the input & output of the pipe */ + + /* Setup communication pipeline first */ + if (pipe (commpipe)) + { + fprintf (stderr, + "Failed to create pipe: %s\n", + STRERROR (errno)); + exit (1); + } + + /* Attempt to fork and check for errors */ + if ((pid = fork ()) == -1) + { + fprintf (stderr, "Failed to fork: %s\n", + STRERROR (errno)); + exit (1); + } + + if (pid) + { + /* A positive (non-negative) PID indicates the parent process */ + close (commpipe[0]); /* Close unused side of pipe (in side) */ + setvbuf (stdout, (char *) NULL, _IONBF, 0); /* Set non-buffered output on stdout */ + + + msg = (struct GNUNET_MessageHeader *) msg_buf; + msg->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); + msg->size = htons (WLAN_MTU); + radiotap = (struct Radiotap_Send *) &msg[1]; + wlan_header = (struct ieee80211_frame *) &radiotap[1]; + pos = 0; + + getRadiotapHeader (radiotap); + getWlanHeader (wlan_header, outmac, inmac, + WLAN_MTU - sizeof (struct GNUNET_MessageHeader)); + + start = time (NULL); + count = 0; + while (1) + { + pos += write (commpipe[1], msg, WLAN_MTU - pos); + if (pos % WLAN_MTU == 0) + { + pos = 0; + count++; + + if (count % 1000 == 0) + { + akt = time (NULL); + bytes_per_s = count * WLAN_MTU / (akt - start); + bytes_per_s /= 1024; + printf ("send %f kbytes/s\n", bytes_per_s); + } + } + + } + } + else + { + /* A zero PID indicates that this is the child process */ + (void) close (0); + if (-1 == dup2 (commpipe[0], 0)) /* Replace stdin with the in side of the pipe */ + fprintf (stderr, "dup2 failed: %s\n", strerror (errno)); + (void) close (commpipe[1]); /* Close unused side of pipe (out side) */ + /* Replace the child fork with a new process */ + if (execl + ("gnunet-helper-transport-wlan", "gnunet-helper-transport-wlan", + argv[1], NULL) == -1) + { + fprintf (stderr, "Could not start gnunet-helper-transport-wlan!"); + _exit (1); + } + } + return 0; +} diff --git a/src/transport/gnunet-transport.c b/src/transport/gnunet-transport.c new file mode 100644 index 0000000..ee977f5 --- /dev/null +++ b/src/transport/gnunet-transport.c @@ -0,0 +1,619 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/transport/gnunet-transport.c + * @brief Tool to help configure, measure and control the transport subsystem. + * @author Christian Grothoff + * @author Nathan Evans + * + * This utility can be used to test if a transport mechanism for + * GNUnet is properly configured. + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_resolver_service.h" +#include "gnunet_protocols.h" +#include "gnunet_transport_service.h" +#include "gnunet_nat_lib.h" + +/** + * How long do we wait for the NAT test to report success? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * Which peer should we connect to? + */ +static char *cpid; + +/** + * Handle to transport service. + */ +static struct GNUNET_TRANSPORT_Handle *handle; + +/** + * Option -s. + */ +static int benchmark_send; + +/** + * Option -b. + */ +static int benchmark_receive; + +/** + * Option -l. + */ +static int benchmark_receive; + +/** + * Option -i. + */ +static int iterate_connections; + +/** + * Option -t. + */ +static int test_configuration; + +/** + * Option -m. + */ +static int monitor_connections; + +/** + * Option -n. + */ +static int numeric; + +/** + * Global return value (0 success). + */ +static int ret; + +/** + * Number of bytes of traffic we received so far. + */ +static unsigned long long traffic_received; + +/** + * Number of bytes of traffic we sent so far. + */ +static unsigned long long traffic_sent; + +/** + * Starting time of transmitting/receiving data. + */ +static struct GNUNET_TIME_Absolute start_time; + +/** + * Handle for current transmission request. + */ +static struct GNUNET_TRANSPORT_TransmitHandle *th; + +/** + * Identity of the peer we transmit to / connect to. + * (equivalent to 'cpid' string). + */ +static struct GNUNET_PeerIdentity pid; + +/** + * Task scheduled for cleanup / termination of the process. + */ +static GNUNET_SCHEDULER_TaskIdentifier end; + +/** + * Selected level of verbosity. + */ +static int verbosity; + +/** + * Resolver process handle. + */ +struct GNUNET_OS_Process *resolver; + +/** + * Number of tasks running that still need the resolver. + */ +static unsigned int resolver_users; + + +/** + * Context for a plugin test. + */ +struct TestContext +{ + + /** + * Handle to the active NAT test. + */ + struct GNUNET_NAT_Test *tst; + + /** + * Task identifier for the timeout. + */ + GNUNET_SCHEDULER_TaskIdentifier tsk; + + /** + * Name of plugin under test. + */ + const char *name; + +}; + + +/** + * Display the result of the test. + * + * @param tc test context + * @param result GNUNET_YES on success + */ +static void +display_test_result (struct TestContext *tc, int result) +{ + if (GNUNET_YES != result) + { + FPRINTF (stderr, "Configuration for plugin `%s' did not work!\n", tc->name); + } + else + { + FPRINTF (stderr, "Configuration for plugin `%s' is working!\n", tc->name); + } + if (GNUNET_SCHEDULER_NO_TASK != tc->tsk) + { + GNUNET_SCHEDULER_cancel (tc->tsk); + tc->tsk = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != tc->tst) + { + GNUNET_NAT_test_stop (tc->tst); + tc->tst = NULL; + } + GNUNET_free (tc); + resolver_users--; + if ((0 == resolver_users) && (NULL != resolver)) + { + GNUNET_break (0 == GNUNET_OS_process_kill (resolver, SIGTERM)); + GNUNET_OS_process_close (resolver); + resolver = NULL; + } +} + + +/** + * Function called by NAT on success. + * Clean up and update GUI (with success). + * + * @param cls test context + * @param success currently always GNUNET_OK + */ +static void +result_callback (void *cls, int success) +{ + struct TestContext *tc = cls; + + display_test_result (tc, success); +} + + +/** + * Function called if NAT failed to confirm success. + * Clean up and update GUI (with failure). + * + * @param cls test context + * @param tc scheduler callback + */ +static void +fail_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestContext *tstc = cls; + + tstc->tsk = GNUNET_SCHEDULER_NO_TASK; + display_test_result (tstc, GNUNET_NO); +} + + +/** + * Test our plugin's configuration (NAT traversal, etc.). + * + * @param cfg configuration to test + */ +static void +do_test_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *plugins; + char *tok; + unsigned long long bnd_port; + unsigned long long adv_port; + struct TestContext *tc; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "transport", "plugins", + &plugins)) + { + FPRINTF (stderr, + "%s", + _ + ("No transport plugins configured, peer will never communicate\n")); + ret = 4; + return; + } + for (tok = strtok (plugins, " "); tok != NULL; tok = strtok (NULL, " ")) + { + char section[12 + strlen (tok)]; + + GNUNET_snprintf (section, sizeof (section), "transport-%s", tok); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, section, "PORT", &bnd_port)) + { + FPRINTF (stderr, + _("No port configured for plugin `%s', cannot test it\n"), tok); + continue; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, section, "ADVERTISED_PORT", + &adv_port)) + adv_port = bnd_port; + if (NULL == resolver) + resolver = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-resolver", + "gnunet-service-resolver", NULL); + resolver_users++; + GNUNET_RESOLVER_connect (cfg); + tc = GNUNET_malloc (sizeof (struct TestContext)); + tc->name = GNUNET_strdup (tok); + tc->tst = + GNUNET_NAT_test_start (cfg, + (0 == + strcasecmp (tok, + "udp")) ? GNUNET_NO : GNUNET_YES, + (uint16_t) bnd_port, (uint16_t) adv_port, + &result_callback, tc); + if (NULL == tc->tst) + { + display_test_result (tc, GNUNET_SYSERR); + continue; + } + tc->tsk = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &fail_timeout, tc); + } + GNUNET_free (plugins); +} + + +/** + * Shutdown, print statistics. + */ +static void +do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TIME_Relative duration; + + if (NULL != th) + { + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + } + GNUNET_TRANSPORT_disconnect (handle); + if (benchmark_receive) + { + duration = GNUNET_TIME_absolute_get_duration (start_time); + FPRINTF (stdout, _("Received %llu bytes/s (%llu bytes in %llu ms)\n"), + 1000 * traffic_received / (1 + duration.rel_value), + traffic_received, (unsigned long long) duration.rel_value); + } + if (benchmark_send) + { + duration = GNUNET_TIME_absolute_get_duration (start_time); + FPRINTF (stdout, _("Transmitted %llu bytes/s (%llu bytes in %llu ms)\n"), + 1000 * traffic_sent / (1 + duration.rel_value), traffic_sent, + (unsigned long long) duration.rel_value); + } +} + + +/** + * Function called to notify a client about the socket + * begin ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_data (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *m = buf; + + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); + m->size = ntohs (size); + m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY); + memset (&m[1], 52, size - sizeof (struct GNUNET_MessageHeader)); + traffic_sent += size; + th = GNUNET_TRANSPORT_notify_transmit_ready (handle, &pid, 32 * 1024, 0, + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_data, NULL); + if (verbosity > 0) + FPRINTF (stdout, _("Transmitting %u bytes to %s\n"), (unsigned int) size, + GNUNET_i2s (&pid)); + return size; +} + + +/** + * Function called to notify transport users that another + * peer connected to us. + * + * @param cls closure + * @param peer the peer that connected + * @param ats performance data + * @param ats_count number of entries in ats (excluding 0-termination) + */ +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + if (verbosity > 0) + FPRINTF (stdout, _("Connected to %s\n"), GNUNET_i2s (peer)); + if (0 != memcmp (&pid, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + ret = 0; + if (benchmark_send) + { + start_time = GNUNET_TIME_absolute_get (); + th = GNUNET_TRANSPORT_notify_transmit_ready (handle, peer, 32 * 1024, 0, + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_data, NULL); + } + else + { + /* all done, terminate instantly */ + GNUNET_SCHEDULER_cancel (end); + end = GNUNET_SCHEDULER_add_now (&do_disconnect, NULL); + } +} + + +/** + * Function called to notify transport users that another + * peer disconnected from us. + * + * @param cls closure + * @param peer the peer that disconnected + */ +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + if (verbosity > 0) + FPRINTF (stdout, _("Disconnected from %s\n"), GNUNET_i2s (peer)); + if ((0 == memcmp (&pid, peer, sizeof (struct GNUNET_PeerIdentity))) && + (NULL != th)) + { + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + GNUNET_SCHEDULER_cancel (end); + end = GNUNET_SCHEDULER_add_now (&do_disconnect, NULL); + } +} + + +/** + * Function called by the transport for each received message. + * + * @param cls closure + * @param peer (claimed) identity of the other peer + * @param message the message + * @param ats performance data + * @param ats_count number of entries in ats + */ +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + if (!benchmark_receive) + return; + if (verbosity > 0) + FPRINTF (stdout, _("Received %u bytes from %s\n"), + (unsigned int) ntohs (message->size), GNUNET_i2s (peer)); + if (traffic_received == 0) + start_time = GNUNET_TIME_absolute_get (); + traffic_received += ntohs (message->size); +} + +void +process_string (void *cls, const char *address) +{ + struct GNUNET_HELLO_Address *addrcp = cls; + + if ((address != NULL)) + { + FPRINTF (stdout, _("Peer `%s': %s %s\n"), GNUNET_i2s (&addrcp->peer), addrcp->transport_name, address); + } + else + { + /* done */ + GNUNET_free (addrcp); + } +} + +/** + * Function to call with a binary address + * + * @param cls closure + * @param peer identity of the peer + * @param address binary address (NULL on disconnect) + */ +static void +process_address (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address) +{ + const struct GNUNET_CONFIGURATION_Handle *cfg = cls; + + if (peer == NULL) + { + /* done */ + return; + } + + if (address == NULL) + { + FPRINTF (stdout, _("Peer `%s' disconnected\n"), GNUNET_i2s (peer)); + return; + } + + /* Resolve address to string */ + GNUNET_TRANSPORT_address_to_string (cfg, address, numeric, + GNUNET_TIME_UNIT_MINUTES, &process_string, + GNUNET_HELLO_address_copy(address)); +} + + +/** + * Task run in monitor mode when the user presses CTRL-C to abort. + * Stops monitoring activity. + * + * @param cls the 'struct GNUNET_TRANSPORT_PeerIterateContext *' + * @param tc scheduler context + */ +static void +shutdown_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TRANSPORT_PeerIterateContext *pic = cls; + + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pic); +} + + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + if (test_configuration) + { + do_test_configuration (cfg); + } + if (benchmark_send && (NULL == cpid)) + { + FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"), + "-s", "-C"); + return; + } + if (NULL != cpid) + { + ret = 1; + if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (cpid, &pid.hashPubKey)) + { + FPRINTF (stderr, _("Failed to parse peer identity `%s'\n"), cpid); + return; + } + handle = + GNUNET_TRANSPORT_connect (cfg, NULL, NULL, ¬ify_receive, + ¬ify_connect, ¬ify_disconnect); + GNUNET_TRANSPORT_try_connect (handle, &pid); + end = + GNUNET_SCHEDULER_add_delayed (benchmark_send ? + GNUNET_TIME_UNIT_FOREVER_REL : + GNUNET_TIME_UNIT_SECONDS, &do_disconnect, + NULL); + } + else if (benchmark_receive) + { + handle = + GNUNET_TRANSPORT_connect (cfg, NULL, NULL, ¬ify_receive, + ¬ify_connect, ¬ify_disconnect); + GNUNET_TRANSPORT_try_connect (handle, &pid); + end = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &do_disconnect, NULL); + } + if (iterate_connections) + { + GNUNET_TRANSPORT_peer_get_active_addresses (cfg, NULL, GNUNET_YES, + GNUNET_TIME_UNIT_MINUTES, + &process_address, (void *) cfg); + } + if (monitor_connections) + { + struct GNUNET_TRANSPORT_PeerIterateContext *pic; + + pic = GNUNET_TRANSPORT_peer_get_active_addresses (cfg, NULL, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + &process_address, (void *) cfg); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, + pic); + } +} + + +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'b', "benchmark", NULL, + gettext_noop ("measure how fast we are receiving data (until CTRL-C)"), + 0, &GNUNET_GETOPT_set_one, &benchmark_receive}, + {'C', "connect", "PEER", + gettext_noop ("try to connect to the given peer"), + 1, &GNUNET_GETOPT_set_string, &cpid}, + {'i', "information", NULL, + gettext_noop ("provide information about all current connections (once)"), + 0, &GNUNET_GETOPT_set_one, &iterate_connections}, + {'m', "monitor", NULL, + gettext_noop ("provide information about all current connections (continuously)"), + 0, &GNUNET_GETOPT_set_one, &monitor_connections}, + {'n', "numeric", NULL, + gettext_noop ("do not resolve hostnames"), + 0, &GNUNET_GETOPT_set_one, &numeric}, + {'s', "send", NULL, + gettext_noop + ("send data for benchmarking to the other peer (until CTRL-C)"), + 0, &GNUNET_GETOPT_set_one, &benchmark_send}, + {'t', "test", NULL, + gettext_noop ("test transport configuration (involves external server)"), + 0, &GNUNET_GETOPT_set_one, &test_configuration}, + GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-transport", + gettext_noop + ("Direct access to transport service."), options, + &run, NULL)) ? ret : 1; +} + + +/* end of gnunet-transport.c */ diff --git a/src/transport/plugin_transport_http.c b/src/transport/plugin_transport_http.c new file mode 100644 index 0000000..f88ff33 --- /dev/null +++ b/src/transport/plugin_transport_http.c @@ -0,0 +1,1529 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_http.c + * @brief http transport service plugin + * @author Matthias Wachs + */ + +#include "plugin_transport_http.h" + +/** + * After how long do we expire an address that we + * learned from another peer if it is not reconfirmed + * by anyone? + */ +#define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) + +/** + * Wrapper to manage IPv4 addresses + */ +struct IPv4HttpAddressWrapper +{ + /** + * Linked list next + */ + struct IPv4HttpAddressWrapper *next; + + /** + * Linked list previous + */ + struct IPv4HttpAddressWrapper *prev; + + struct IPv4HttpAddress addr; +}; + +/** + * Wrapper for IPv4 addresses. + */ +struct IPv6HttpAddressWrapper +{ + /** + * Linked list next + */ + struct IPv6HttpAddressWrapper *next; + + /** + * Linked list previous + */ + struct IPv6HttpAddressWrapper *prev; + + struct IPv6HttpAddress addr6; +}; + + +/** + * Context for address to string conversion. + */ +struct PrettyPrinterContext +{ + /** + * Function to call with the result. + */ + GNUNET_TRANSPORT_AddressStringCallback asc; + + /** + * Plugin + */ + struct Plugin *plugin; + + /** + * Clsoure for 'asc'. + */ + void *asc_cls; + + /** + * Port to add after the IP address. + */ + uint16_t port; + + uint32_t addrlen; + + int numeric; +}; + + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin; + + + +/** + * Append our port and forward the result. + * + * @param cls the 'struct PrettyPrinterContext*' + * @param hostname hostname part of the address + */ +static void +append_port (void *cls, const char *hostname) +{ + struct PrettyPrinterContext *ppc = cls; + static char rbuf[INET6_ADDRSTRLEN + 13]; + + if (hostname == NULL) + { + ppc->asc (ppc->asc_cls, NULL); + GNUNET_free (ppc); + return; + } + +#if !BUILD_HTTPS + const char *protocol = "http"; +#else + const char *protocol = "https"; +#endif + GNUNET_assert ((strlen (hostname) + 7) < (INET6_ADDRSTRLEN + 13)); + if (ppc->addrlen == sizeof (struct IPv6HttpAddress)) + { + if (ppc->numeric == GNUNET_YES) + GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, hostname, ppc->port); + else + { + if (strchr(hostname, ':') != NULL) + GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, hostname, ppc->port); + else + GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, hostname, ppc->port); + } + } + else if (ppc->addrlen == sizeof (struct IPv4HttpAddress)) + GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, hostname, ppc->port); + ppc->asc (ppc->asc_cls, rbuf); +} + + +/** + * Convert the transports address to a nice, human-readable + * format. + * + * @param cls closure + * @param type name of the transport that generated the address + * @param addr one of the addresses of the host, NULL for the last address + * the specific address format depends on the transport + * @param addrlen length of the address + * @param numeric should (IP) addresses be displayed in numeric form? + * @param timeout after how long should we give up? + * @param asc function to call on each string + * @param asc_cls closure for asc + */ +static void +http_plugin_address_pretty_printer (void *cls, const char *type, + const void *addr, size_t addrlen, + int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressStringCallback asc, + void *asc_cls) +{ + GNUNET_assert (cls != NULL); + struct PrettyPrinterContext *ppc; + const void *sb; + struct sockaddr_in s4; + struct sockaddr_in6 s6; + size_t sbs; + uint16_t port = 0; + + if ((addrlen == sizeof (struct IPv6HttpAddress)) && (addr != NULL)) + { + struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr; + s6.sin6_family = AF_INET6; + s6.sin6_addr = a6->ipv6_addr; + s6.sin6_port = a6->u6_port; +#if HAVE_SOCKADDR_IN_SIN_LEN + s6.sin6_len = sizeof (struct sockaddr_in6); +#endif + sb = &s6; + sbs = sizeof (struct sockaddr_in6); + port = ntohs (a6->u6_port); + + } + else if ((addrlen == sizeof (struct IPv4HttpAddress)) && (addr != NULL)) + { + struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr; + + s4.sin_family = AF_INET; + s4.sin_addr.s_addr = a4->ipv4_addr; + s4.sin_port = a4->u4_port; +#if HAVE_SOCKADDR_IN_SIN_LEN + s4.sin_len = sizeof (struct sockaddr_in); +#endif + sb = &s4; + sbs = sizeof (struct sockaddr_in); + port = ntohs (a4->u4_port); + } + else + { + /* invalid address */ + GNUNET_break_op (0); + asc (asc_cls, NULL); + return; + } + ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); + ppc->asc = asc; + ppc->asc_cls = asc_cls; + ppc->port = port; + ppc->plugin = cls; + ppc->addrlen = addrlen; + ppc->numeric = numeric; + GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); +} + + + +/** + * Another peer has suggested an address for this + * peer and transport plugin. Check that this could be a valid + * address. If so, consider adding it to the list + * of addresses. + * + * @param cls closure + * @param addr pointer to the address + * @param addrlen length of addr + * @return GNUNET_OK if this is a plausible address for this peer + * and transport + */ +static int +http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) +{ + + struct Plugin *plugin = cls; + struct IPv4HttpAddressWrapper *w_tv4 = plugin->ipv4_addr_head; + struct IPv6HttpAddressWrapper *w_tv6 = plugin->ipv6_addr_head; + + + + GNUNET_assert (cls != NULL); + if ((addrlen != sizeof (struct sockaddr_in)) || + (addrlen != sizeof (struct sockaddr_in6))) + return GNUNET_SYSERR; + + if (addrlen == sizeof (struct IPv4HttpAddress)) + { + struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr; + + while (w_tv4 != NULL) + { + if ((0 == + memcmp (&w_tv4->addr.ipv4_addr, &a4->ipv4_addr, + sizeof (struct in_addr))) && + (w_tv4->addr.u4_port == a4->u4_port)) + break; + w_tv4 = w_tv4->next; + } + if (w_tv4 != NULL) + return GNUNET_OK; + else + return GNUNET_SYSERR; + } + if (addrlen == sizeof (struct sockaddr_in6)) + { + struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr; + + while (w_tv6 != NULL) + { + if ((0 == + memcmp (&w_tv6->addr6.ipv6_addr, &a6->ipv6_addr, + sizeof (struct in6_addr))) && + (w_tv6->addr6.u6_port == a6->u6_port)) + break; + w_tv6 = w_tv6->next; + } + if (w_tv6 != NULL) + return GNUNET_OK; + else + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +struct GNUNET_TIME_Relative +http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + struct Session *session, const char *sender_address, + uint16_t sender_address_len) +{ + struct Session *s = cls; + struct Plugin *plugin = s->plugin; + struct GNUNET_TIME_Relative delay; + struct GNUNET_ATS_Information atsi[2]; + + atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); + atsi[0].value = htonl (1); + atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); + atsi[1].value = session->ats_address_network_type; + GNUNET_break (session->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED)); + + delay = + plugin->env->receive (plugin->env->cls, &s->target, message, + (const struct GNUNET_ATS_Information *) &atsi, + 2, s, s->addr, s->addrlen); + return delay; +} + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure + * @param addr binary address + * @param addrlen length of the address + * @return string representing the same address + */ +const char * +http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) +{ + + struct IPv4HttpAddress *a4; + struct IPv6HttpAddress *a6; + char *address; + static char rbuf[INET6_ADDRSTRLEN + 13]; + uint16_t port; + int res = 0; + + if (addrlen == sizeof (struct IPv6HttpAddress)) + { + a6 = (struct IPv6HttpAddress *) addr; + address = GNUNET_malloc (INET6_ADDRSTRLEN); + GNUNET_assert (NULL != + inet_ntop (AF_INET6, &a6->ipv6_addr, address, + INET6_ADDRSTRLEN)); + port = ntohs (a6->u6_port); + } + else if (addrlen == sizeof (struct IPv4HttpAddress)) + { + a4 = (struct IPv4HttpAddress *) addr; + address = GNUNET_malloc (INET_ADDRSTRLEN); + GNUNET_assert (NULL != + inet_ntop (AF_INET, &(a4->ipv4_addr), address, + INET_ADDRSTRLEN)); + port = ntohs (a4->u4_port); + } + else + { + /* invalid address */ + GNUNET_break (0); + return NULL; + } +#if !BUILD_HTTPS + char *protocol = "http"; +#else + char *protocol = "https"; +#endif + + GNUNET_assert (strlen (address) + 7 < (INET6_ADDRSTRLEN + 13)); + if (addrlen == sizeof (struct IPv6HttpAddress)) + res = + GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, + address, port); + else if (addrlen == sizeof (struct IPv4HttpAddress)) + res = + GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, address, + port); + + GNUNET_free (address); + GNUNET_assert (res != 0); + return rbuf; +} + +struct Session * +lookup_session_old (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, + struct Session *session, const void *addr, size_t addrlen, + int force_address) +{ + struct Session *t; + int e_peer; + int e_addr; + + for (t = plugin->head; NULL != t; t = t->next) + { +#if 0 + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + "Comparing peer `%s' address `%s' len %i session %X to \n", + GNUNET_i2s (target), GNUNET_a2s (addr, addrlen), addrlen, + session); + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + "peer `%s' address `%s' len %i session %X \n\n", + GNUNET_i2s (&t->target), GNUNET_a2s (t->addr, t->addrlen), + t->addrlen, t); + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "memcmp %i \n", + memcmp (addr, t->addr, addrlen)); +#endif + e_peer = GNUNET_NO; + e_addr = GNUNET_NO; + if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity))) + { + e_peer = GNUNET_YES; + if ( (addrlen == t->addrlen) && + (0 == memcmp (addr, t->addr, addrlen)) ) + e_addr = GNUNET_YES; + if ( (t == session) && + (t->addrlen == session->addrlen) && + (0 == memcmp (session->addr, t->addr, t->addrlen)) ) + e_addr = GNUNET_YES; + } + + if ( ((e_peer == GNUNET_YES) && (force_address == GNUNET_NO)) || + ((e_peer == GNUNET_YES) && (force_address == GNUNET_YES) && (e_addr == GNUNET_YES)) || + ((e_peer == GNUNET_YES) && (force_address == GNUNET_SYSERR)) ) + return t; + } + return NULL; +} + +struct Session * +lookup_session (struct Plugin *plugin, + const struct GNUNET_HELLO_Address *address) +{ + struct Session *pos; + + for (pos = plugin->head; NULL != pos; pos = pos->next) + if ( (0 == memcmp (&address->peer, &pos->target, sizeof (struct GNUNET_PeerIdentity))) && + (address->address_length == pos->addrlen) && + (0 == memcmp (address->address, pos->addr, pos->addrlen)) ) + return pos; + return NULL; +} + + +void +delete_session (struct Session *s) +{ + if (s->msg_tk != NULL) + { + GNUNET_SERVER_mst_destroy (s->msg_tk); + s->msg_tk = NULL; + } + GNUNET_free (s->addr); + GNUNET_free_non_null (s->server_recv); + GNUNET_free_non_null (s->server_send); + GNUNET_free (s); +} + +struct Session * +create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, + const void *addr, size_t addrlen, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct Session *s = NULL; + + GNUNET_assert ((addrlen == sizeof (struct IPv6HttpAddress)) || + (addrlen == sizeof (struct IPv4HttpAddress))); + s = GNUNET_malloc (sizeof (struct Session)); + memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity)); + s->plugin = plugin; + s->addr = GNUNET_malloc (addrlen); + memcpy (s->addr, addr, addrlen); + s->addrlen = addrlen; + s->next = NULL; + s->next_receive = GNUNET_TIME_absolute_get_zero (); + s->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED); + return s; +} + +void +notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, + struct Session *s) +{ + struct Plugin *plugin = cls; + + plugin->env->session_end (plugin->env->cls, peer, s); + GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); + delete_session (s); +} + +/** + * Creates a new outbound session the transport service will use to send data to the + * peer + * + * @param cls the plugin + * @param address the address + * @return the session or NULL of max connections exceeded + */ + +static struct Session * +http_get_session (void *cls, + const struct GNUNET_HELLO_Address *address) +{ + struct Plugin *plugin = cls; + struct Session * s = NULL; + struct GNUNET_ATS_Information ats; + size_t addrlen; + + GNUNET_assert (plugin != NULL); + GNUNET_assert (address != NULL); + GNUNET_assert (address->address != NULL); + + ats.type = htonl (GNUNET_ATS_ARRAY_TERMINATOR); + ats.value = htonl (GNUNET_ATS_ARRAY_TERMINATOR); + + /* find existing session */ + s = lookup_session (plugin, address); + if (s != NULL) + return s; + + if (plugin->max_connections <= plugin->cur_connections) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, + "Maximum number of connections reached, " + "cannot connect to peer `%s'\n", GNUNET_i2s (&address->peer)); + return NULL; + } + + /* create new session */ + addrlen = address->address_length; + + GNUNET_assert ((addrlen == sizeof (struct IPv6HttpAddress)) || + (addrlen == sizeof (struct IPv4HttpAddress))); + + s = GNUNET_malloc (sizeof (struct Session)); + memcpy (&s->target, &address->peer, sizeof (struct GNUNET_PeerIdentity)); + s->plugin = plugin; + s->addr = GNUNET_malloc (address->address_length); + memcpy (s->addr, address->address, address->address_length); + s->addrlen = addrlen; + s->next = NULL; + s->next_receive = GNUNET_TIME_absolute_get_zero (); + s->inbound = GNUNET_NO; + s->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED); + + /* Get ATS type */ + if (addrlen == sizeof (struct IPv4HttpAddress)) + { + struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) address->address; + struct sockaddr_in s4; + + s4.sin_family = AF_INET; + s4.sin_addr.s_addr = a4->ipv4_addr; + s4.sin_port = a4->u4_port; +#if HAVE_SOCKADDR_IN_SIN_LEN + s4.sin_len = sizeof (struct sockaddr_in); +#endif + ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s4, sizeof (struct sockaddr_in)); + } + if (addrlen == sizeof (struct IPv6HttpAddress)) + { + struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) address->address; + struct sockaddr_in6 s6; + + s6.sin6_family = AF_INET6; + s6.sin6_addr = a6->ipv6_addr; + s6.sin6_port = a6->u6_port; +#if HAVE_SOCKADDR_IN_SIN_LEN + s6.sin6_len = sizeof (struct sockaddr_in6); +#endif + ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6)); + } + s->ats_address_network_type = ats.value; + + /* add new session */ + GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); + /* initiate new connection */ + if (GNUNET_SYSERR == client_connect (s)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + "Cannot connect to peer `%s' address `%s''\n", + http_plugin_address_to_string(NULL, s->addr, s->addrlen), + GNUNET_i2s (&s->target)); + GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); + delete_session (s); + return NULL; + } + + return s; +} + +/** + * Function that can be used by the transport service to transmit + * a message using the plugin. Note that in the case of a + * peer disconnecting, the continuation MUST be called + * prior to the disconnect notification itself. This function + * will be called with this peer's HELLO message to initiate + * a fresh connection to another peer. + * + * @param cls closure + * @param session which session must be used + * @param msgbuf the message to transmit + * @param msgbuf_size number of bytes in 'msgbuf' + * @param priority how important is the message (most plugins will + * ignore message priority and just FIFO) + * @param to how long to wait at most for the transmission (does not + * require plugins to discard the message after the timeout, + * just advisory for the desired delay; most plugins will ignore + * this as well) + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...); can be NULL + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV) + */ +static ssize_t +http_plugin_send (void *cls, + struct Session *session, + const char *msgbuf, size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative to, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct Plugin *plugin = cls; + struct HTTP_Message *msg; + struct Session *tmp; + size_t res = -1; + + GNUNET_assert (plugin != NULL); + GNUNET_assert (session != NULL); + + /* lookup if session is really existing */ + tmp = plugin->head; + while (tmp != NULL) + { + if ((tmp == session) && + (0 == memcmp (&session->target, &tmp->target, sizeof (struct GNUNET_PeerIdentity))) && + (session->addrlen == tmp->addrlen) && + (0 == memcmp (session->addr, tmp->addr, tmp->addrlen))) + break; + tmp = tmp->next; + } + if (tmp == NULL) + { + GNUNET_break_op (0); + return res; + } + + /* create new message and schedule */ + + msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size); + msg->next = NULL; + msg->size = msgbuf_size; + msg->pos = 0; + msg->buf = (char *) &msg[1]; + msg->transmit_cont = cont; + msg->transmit_cont_cls = cont_cls; + memcpy (msg->buf, msgbuf, msgbuf_size); + + if (session->inbound == GNUNET_NO) + { +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Using outbound client session %p to send to `%session'\n", session, + GNUNET_i2s (&session->target)); +#endif + + client_send (session, msg); + res = msgbuf_size; + } + if (session->inbound == GNUNET_YES) + { +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Using inbound server %p session to send to `%session'\n", session, + GNUNET_i2s (&session->target)); +#endif + + server_send (session, msg); + res = msgbuf_size; + } + return res; + +} + + +/** + * Function that can be used to force the plugin to disconnect + * from the given peer and cancel all previous transmissions + * (and their continuationc). + * + * @param cls closure + * @param target peer from which to disconnect + */ +static void +http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +{ + struct Plugin *plugin = cls; + struct Session *next = NULL; + struct Session *s = plugin->head; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Transport tells me to disconnect `%s'\n", + GNUNET_i2s (target)); + while (s != NULL) + { + next = s->next; + if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity))) + { + if (s->inbound == GNUNET_NO) + GNUNET_assert (GNUNET_OK == client_disconnect (s)); + else + GNUNET_assert (GNUNET_OK == server_disconnect (s)); + GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); + + struct HTTP_Message *msg = s->msg_head; + struct HTTP_Message *tmp = NULL; + + while (msg != NULL) + { + tmp = msg->next; + + GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); + if (msg->transmit_cont != NULL) + { + msg->transmit_cont (msg->transmit_cont_cls, target, GNUNET_SYSERR); + } + GNUNET_free (msg); + msg = tmp; + } + + delete_session (s); + } + s = next; + } +} + +static void +nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + struct Plugin *plugin = cls; + struct IPv4HttpAddressWrapper *w_t4 = NULL; + struct IPv6HttpAddressWrapper *w_t6 = NULL; + int af; + + af = addr->sa_family; + switch (af) + { + case AF_INET: + w_t4 = plugin->ipv4_addr_head; + struct sockaddr_in *a4 = (struct sockaddr_in *) addr; + + while (w_t4 != NULL) + { + int res = memcmp (&w_t4->addr.ipv4_addr, + &a4->sin_addr, + sizeof (struct in_addr)); + + if (res == 0) + { + if (a4->sin_port != w_t4->addr.u4_port) + res = -1; + } + + if (0 == res) + break; + w_t4 = w_t4->next; + } + if (w_t4 == NULL) + { + w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper)); + memcpy (&w_t4->addr.ipv4_addr, &a4->sin_addr, sizeof (struct in_addr)); + w_t4->addr.u4_port = a4->sin_port; + + GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, + plugin->ipv4_addr_tail, w_t4); + } +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Notifying transport to add IPv4 address `%s'\n", + http_plugin_address_to_string (NULL, &w_t4->addr, + sizeof (struct + IPv4HttpAddress))); +#endif + plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, + sizeof (struct IPv4HttpAddress)); + + break; + case AF_INET6: + w_t6 = plugin->ipv6_addr_head; + struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr; + + while (w_t6) + { + int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, + sizeof (struct in6_addr)); + + if (res == 0) + { + if (a6->sin6_port != w_t6->addr6.u6_port) + res = -1; + } + if (0 == res) + break; + w_t6 = w_t6->next; + } + if (w_t6 == NULL) + { + w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper)); + + memcpy (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, sizeof (struct in6_addr)); + w_t6->addr6.u6_port = a6->sin6_port; + + GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head, + plugin->ipv6_addr_tail, w_t6); + } +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Notifying transport to add IPv6 address `%s'\n", + http_plugin_address_to_string (NULL, &w_t6->addr6, + sizeof (struct + IPv6HttpAddress))); +#endif + plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, + sizeof (struct IPv6HttpAddress)); + break; + default: + return; + } + +} + +static void +nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + struct Plugin *plugin = cls; + struct IPv4HttpAddressWrapper *w_t4 = NULL; + struct IPv6HttpAddressWrapper *w_t6 = NULL; + int af; + + af = addr->sa_family; + switch (af) + { + case AF_INET: + w_t4 = plugin->ipv4_addr_head; + struct sockaddr_in *a4 = (struct sockaddr_in *) addr; + + while (w_t4 != NULL) + { + int res = memcmp (&w_t4->addr.ipv4_addr, + &a4->sin_addr, + sizeof (struct in_addr)); + + if (res == 0) + { + if (a4->sin_port != w_t4->addr.u4_port) + res = -1; + } + + if (0 == res) + break; + w_t4 = w_t4->next; + } + if (w_t4 == NULL) + return; + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Notifying transport to remove IPv4 address `%s'\n", + http_plugin_address_to_string (NULL, &w_t4->addr, + sizeof (struct + IPv4HttpAddress))); +#endif + plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, + sizeof (struct IPv4HttpAddress)); + + GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, + w_t4); + GNUNET_free (w_t4); + break; + case AF_INET6: + w_t6 = plugin->ipv6_addr_head; + struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr; + + while (w_t6) + { + int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, + sizeof (struct in6_addr)); + + if (res == 0) + { + if (a6->sin6_port != w_t6->addr6.u6_port) + res = -1; + } + if (0 == res) + break; + w_t6 = w_t6->next; + } + if (w_t6 == NULL) + return; +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Notifying transport to remove IPv6 address `%s'\n", + http_plugin_address_to_string (NULL, &w_t6->addr6, + sizeof (struct + IPv6HttpAddress))); +#endif + plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, + sizeof (struct IPv6HttpAddress)); + + GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, + w_t6); + GNUNET_free (w_t6); + break; + default: + return; + } + +} + +/** + * Our external IP address/port mapping has changed. + * + * @param cls closure, the 'struct LocalAddrList' + * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean + * the previous (now invalid) one + * @param addr either the previous or the new public IP address + * @param addrlen actual lenght of the address + */ +static void +nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + GNUNET_assert (cls != NULL); +#if DEBUG_HTTP + struct Plugin *plugin = cls; +#endif +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "NPMC called %s to address `%s'\n", + (add_remove == GNUNET_NO) ? "remove" : "add", + GNUNET_a2s (addr, addrlen)); +#endif + switch (add_remove) + { + case GNUNET_YES: + nat_add_address (cls, add_remove, addr, addrlen); + break; + case GNUNET_NO: + nat_remove_address (cls, add_remove, addr, addrlen); + break; + } +} + +void +http_check_ipv6 (struct Plugin *plugin) +{ + struct GNUNET_NETWORK_Handle *desc = NULL; + + if (plugin->ipv6 == GNUNET_YES) + { + /* probe IPv6 support */ + desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); + if (NULL == desc) + { + if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || + (errno == EACCES)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); + } + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, + _ + ("Disabling IPv6 since it is not supported on this system!\n")); + plugin->ipv6 = GNUNET_NO; + } + else + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); + desc = NULL; + } + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Testing IPv6 on this system: %s\n", + (plugin->ipv6 == GNUNET_YES) ? "successful" : "failed"); + } +} + +int +http_get_addresses (struct Plugin *plugin, const char *serviceName, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct sockaddr ***addrs, socklen_t ** addr_lens) +{ + int disablev6; + unsigned long long port; + struct addrinfo hints; + struct addrinfo *res; + struct addrinfo *pos; + struct addrinfo *next; + unsigned int i; + int resi; + int ret; + struct sockaddr **saddrs; + socklen_t *saddrlens; + char *hostname; + + *addrs = NULL; + *addr_lens = NULL; + + disablev6 = !plugin->ipv6; + + port = 0; + if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT")) + { + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, serviceName, + "PORT", &port)); + if (port > 65535) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Require valid port number for service in configuration!\n")); + return GNUNET_SYSERR; + } + } + + if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO")) + { + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, serviceName, + "BINDTO", &hostname)); + } + else + hostname = NULL; + + if (hostname != NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Resolving `%s' since that is where `%s' will bind to.\n", + hostname, serviceName); + memset (&hints, 0, sizeof (struct addrinfo)); + if (disablev6) + hints.ai_family = AF_INET; + if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || + (res == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"), + hostname, gai_strerror (ret)); + GNUNET_free (hostname); + return GNUNET_SYSERR; + } + next = res; + i = 0; + while (NULL != (pos = next)) + { + next = pos->ai_next; + if ((disablev6) && (pos->ai_family == AF_INET6)) + continue; + i++; + } + if (0 == i) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to find %saddress for `%s'.\n"), + disablev6 ? "IPv4 " : "", hostname); + freeaddrinfo (res); + GNUNET_free (hostname); + return GNUNET_SYSERR; + } + resi = i; + saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); + saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); + i = 0; + next = res; + while (NULL != (pos = next)) + { + next = pos->ai_next; + if ((disablev6) && (pos->ai_family == AF_INET6)) + continue; + if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0)) + continue; /* not TCP */ + if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0)) + continue; /* huh? */ + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Service will bind to `%s'\n", GNUNET_a2s (pos->ai_addr, + pos->ai_addrlen)); + if (pos->ai_family == AF_INET) + { + GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in)); + saddrlens[i] = pos->ai_addrlen; + saddrs[i] = GNUNET_malloc (saddrlens[i]); + memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); + ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); + } + else + { + GNUNET_assert (pos->ai_family == AF_INET6); + GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6)); + saddrlens[i] = pos->ai_addrlen; + saddrs[i] = GNUNET_malloc (saddrlens[i]); + memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); + ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); + } + i++; + } + GNUNET_free (hostname); + freeaddrinfo (res); + resi = i; + } + else + { + /* will bind against everything, just set port */ + if (disablev6) + { + /* V4-only */ + resi = 1; + i = 0; + saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); + saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); + + saddrlens[i] = sizeof (struct sockaddr_in); + saddrs[i] = GNUNET_malloc (saddrlens[i]); +#if HAVE_SOCKADDR_IN_SIN_LEN + ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; +#endif + ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; + ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); + } + else + { + /* dual stack */ + resi = 2; + saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); + saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); + i = 0; + saddrlens[i] = sizeof (struct sockaddr_in6); + saddrs[i] = GNUNET_malloc (saddrlens[i]); +#if HAVE_SOCKADDR_IN_SIN_LEN + ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; +#endif + ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; + ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); + i++; + saddrlens[i] = sizeof (struct sockaddr_in); + saddrs[i] = GNUNET_malloc (saddrlens[i]); +#if HAVE_SOCKADDR_IN_SIN_LEN + ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; +#endif + ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; + ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); + } + } + *addrs = saddrs; + *addr_lens = saddrlens; + return resi; +} + +static void +start_report_addresses (struct Plugin *plugin) +{ + int res = GNUNET_OK; + struct sockaddr **addrs; + socklen_t *addrlens; + + res = + http_get_addresses (plugin, plugin->name, plugin->env->cfg, &addrs, + &addrlens); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + _("Found %u addresses to report to NAT service\n"), res); + + if (res != GNUNET_SYSERR) + { + plugin->nat = + GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port, + (unsigned int) res, + (const struct sockaddr **) addrs, addrlens, + &nat_port_map_callback, NULL, plugin); + while (res > 0) + { + res--; +#if 0 + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _("FREEING %s\n"), + GNUNET_a2s (addrs[res], addrlens[res])); +#endif + GNUNET_assert (addrs[res] != NULL); + GNUNET_free (addrs[res]); + } + GNUNET_free_non_null (addrs); + GNUNET_free_non_null (addrlens); + } + else + { + plugin->nat = + GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, 0, 0, NULL, NULL, + NULL, NULL, plugin); + } +} + +static void +stop_report_addresses (struct Plugin *plugin) +{ + /* Stop NAT handle */ + GNUNET_NAT_unregister (plugin->nat); + + /* Clean up addresses */ + struct IPv4HttpAddressWrapper *w_t4; + struct IPv6HttpAddressWrapper *w_t6; + + while (plugin->ipv4_addr_head != NULL) + { + w_t4 = plugin->ipv4_addr_head; + GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, + w_t4); + GNUNET_free (w_t4); + } + + while (plugin->ipv6_addr_head != NULL) + { + w_t6 = plugin->ipv6_addr_head; + GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, + w_t6); + GNUNET_free (w_t6); + } +} + +static int +configure_plugin (struct Plugin *plugin) +{ + int res = GNUNET_OK; + + /* Use IPv4? */ + if (GNUNET_CONFIGURATION_have_value + (plugin->env->cfg, plugin->name, "USE_IPv4")) + { + plugin->ipv4 = + GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, + "USE_IPv4"); + } + else + plugin->ipv4 = GNUNET_YES; + + /* Use IPv6? */ + if (GNUNET_CONFIGURATION_have_value + (plugin->env->cfg, plugin->name, "USE_IPv6")) + { + plugin->ipv6 = + GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, + "USE_IPv6"); + } + else + plugin->ipv6 = GNUNET_YES; + + if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _ + ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"), + plugin->name); + res = GNUNET_SYSERR; + } + + /* Reading port number from config file */ + unsigned long long port; + + if ((GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, + "PORT", &port)) || (port > 65535)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _("Port is required! Fix in configuration\n"), + plugin->name); + res = GNUNET_SYSERR; + goto fail; + } + plugin->port = port; + + plugin->client_only = GNUNET_NO; + if (plugin->port == 0) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + _("Port 0, client only mode\n")); + plugin->client_only = GNUNET_YES; + } + + char *bind4_address = NULL; + + if ((plugin->ipv4 == GNUNET_YES) && + (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, + "BINDTO", &bind4_address))) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Binding %s plugin to specific IPv4 address: `%s'\n", + plugin->protocol, bind4_address); + plugin->server_addr_v4 = GNUNET_malloc (sizeof (struct sockaddr_in)); + if (1 != + inet_pton (AF_INET, bind4_address, &plugin->server_addr_v4->sin_addr)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _ + ("Specific IPv4 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"), + bind4_address, plugin->protocol); + GNUNET_free (plugin->server_addr_v4); + plugin->server_addr_v4 = NULL; + } + else + { + plugin->server_addr_v4->sin_family = AF_INET; + plugin->server_addr_v4->sin_port = htons (plugin->port); + } + GNUNET_free (bind4_address); + } + + + char *bind6_address = NULL; + + if ((plugin->ipv6 == GNUNET_YES) && + (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, + "BINDTO6", &bind6_address))) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Binding %s plugin to specific IPv6 address: `%s'\n", + plugin->protocol, bind6_address); + plugin->server_addr_v6 = GNUNET_malloc (sizeof (struct sockaddr_in6)); + if (1 != + inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _ + ("Specific IPv6 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"), + bind6_address, plugin->protocol); + GNUNET_free (plugin->server_addr_v6); + plugin->server_addr_v6 = NULL; + } + else + { + plugin->server_addr_v6->sin6_family = AF_INET6; + plugin->server_addr_v6->sin6_port = htons (plugin->port); + } + GNUNET_free (bind6_address); + } + + + /* Optional parameters */ + unsigned long long maxneigh; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, + "MAX_CONNECTIONS", &maxneigh)) + maxneigh = 128; + plugin->max_connections = maxneigh; + +fail: + return res; +} + +/** + * Entry point for the plugin. + */ +void * +LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) +{ + struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; + struct GNUNET_TRANSPORT_PluginFunctions *api; + struct Plugin *plugin; + int res; + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = plugin; + api->disconnect = &http_plugin_disconnect; + api->address_pretty_printer = &http_plugin_address_pretty_printer; + api->check_address = &http_plugin_address_suggested; + api->address_to_string = &http_plugin_address_to_string; + api->get_session = &http_get_session; + api->send = &http_plugin_send; + +#if BUILD_HTTPS + plugin->name = "transport-https"; + plugin->protocol = "https"; +#else + plugin->name = "transport-http"; + plugin->protocol = "http"; +#endif + /* Configure plugin from configuration */ + res = configure_plugin (plugin); + if (res == GNUNET_SYSERR) + { + GNUNET_free_non_null (plugin->server_addr_v4); + GNUNET_free_non_null (plugin->server_addr_v6); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; + } + + /* checking IPv6 support */ + http_check_ipv6 (plugin); + + /* Start client */ + res = client_start (plugin); + if (res == GNUNET_SYSERR) + { + GNUNET_free_non_null (plugin->server_addr_v4); + GNUNET_free_non_null (plugin->server_addr_v6); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; + } + + /* Start server */ + if (plugin->client_only == GNUNET_NO) + { + res = server_start (plugin); + if (res == GNUNET_SYSERR) + { + server_stop (plugin); + client_stop (plugin); + + GNUNET_free_non_null (plugin->server_addr_v4); + GNUNET_free_non_null (plugin->server_addr_v6); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; + } + } + /* Report addresses to transport service */ + start_report_addresses (plugin); + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Plugin `%s' loaded\n", plugin->name); +#endif + + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + struct Session *s = NULL; + + /* Stop reporting addresses to transport service */ + stop_report_addresses (plugin); + + /* cleaning up sessions */ + s = plugin->head; + while (s != NULL) + { +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Disconnecting `%s' \n", GNUNET_i2s (&s->target)); +#endif + if (s->inbound == GNUNET_NO) + GNUNET_assert (GNUNET_OK == client_disconnect (s)); + else + GNUNET_assert (GNUNET_OK == server_disconnect (s)); + s = s->next; + } + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping server\n"); +#endif + /* Stop server */ + server_stop (plugin); + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping client\n"); +#endif + /* Stop client */ + client_stop (plugin); + + /* deleting up sessions */ + s = plugin->head; + while (s != NULL) + { + struct Session *t = s->next; + + GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); + + struct HTTP_Message *msg = s->msg_head; + struct HTTP_Message *tmp = NULL; + + while (msg != NULL) + { + tmp = msg->next; + + GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); + if (msg->transmit_cont != NULL) + { + msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); + } + GNUNET_free (msg); + msg = tmp; + } + + delete_session (s); + s = t; + } + + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Plugin `%s' unloaded\n", plugin->name); +#endif + + GNUNET_free_non_null (plugin->server_addr_v4); + GNUNET_free_non_null (plugin->server_addr_v6); + GNUNET_free (plugin); + GNUNET_free (api); + + return NULL; +} + +/* end of plugin_transport_http.c */ diff --git a/src/transport/plugin_transport_http.h b/src/transport/plugin_transport_http.h new file mode 100644 index 0000000..be8f93d --- /dev/null +++ b/src/transport/plugin_transport_http.h @@ -0,0 +1,504 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_http.h + * @brief http transport service plugin + * @author Matthias Wachs + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_constants.h" +#include "gnunet_protocols.h" +#include "gnunet_connection_lib.h" +#include "gnunet_service_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_resolver_service.h" +#include "gnunet_server_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_transport_plugin.h" +#include "gnunet_os_lib.h" +#include "gnunet_nat_lib.h" +#include "microhttpd.h" +#include + + +#define DEBUG_HTTP GNUNET_EXTRA_LOGGING +#define VERBOSE_SERVER GNUNET_EXTRA_LOGGING +#define VERBOSE_CLIENT GNUNET_EXTRA_LOGGING +#define VERBOSE_CURL GNUNET_EXTRA_LOGGING + +#if BUILD_HTTPS +#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_init +#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_done +#else +#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_init +#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_done +#endif + +#define INBOUND GNUNET_YES +#define OUTBOUND GNUNET_NO + + +#define HTTP_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin +{ + /** + * General handles + * --------------- + */ + + /** + * Our environment. + */ + struct GNUNET_TRANSPORT_PluginEnvironment *env; + + /** + * Linked list of open sessions. + */ + + struct Session *head; + + struct Session *tail; + + /** + * NAT handle & address management + */ + struct GNUNET_NAT_Handle *nat; + + /** + * List of own addresses + */ + + /** + * IPv4 addresses DLL head + */ + struct IPv4HttpAddressWrapper *ipv4_addr_head; + + /** + * IPv4 addresses DLL tail + */ + struct IPv4HttpAddressWrapper *ipv4_addr_tail; + + /** + * IPv6 addresses DLL head + */ + struct IPv6HttpAddressWrapper *ipv6_addr_head; + + /** + * IPv6 addresses DLL tail + */ + struct IPv6HttpAddressWrapper *ipv6_addr_tail; + + /** + * Plugin configuration + * -------------------- + */ + + /** + * Plugin name + * Equals configuration section: transport-http, transport-https + */ + char *name; + + /** + * Plugin protocol + * http, https + */ + char *protocol; + + /** + * Use IPv4? + * GNUNET_YES or GNUNET_NO + */ + int ipv4; + + /** + * Use IPv6? + * GNUNET_YES or GNUNET_NO + */ + int ipv6; + + /** + * Does plugin just use outbound connections and not accept inbound? + */ + + int client_only; + + /** + * Port used + */ + uint16_t port; + + /** + * Maximum number of sockets the plugin can use + * Each http inbound /outbound connections are two connections + */ + int max_connections; + + /** + * Plugin HTTPS SSL/TLS options + * ---------------------------- + */ + + /** + * libCurl TLS crypto init string, can be set to enhance performance + * + * Example: + * + * Use RC4-128 instead of AES: + * NONE:+VERS-TLS1.0:+ARCFOUR-128:+SHA1:+RSA:+COMP-NULL + * + */ + char *crypto_init; + + /** + * TLS key + */ + char *key; + + /** + * TLS certificate + */ + char *cert; + + /** + * Plugin values + * ------------- + */ + + /** + * Current number of establishes connections + */ + int cur_connections; + + /** + * Last used unique HTTP connection tag + */ + uint32_t last_tag; + + /** + * Server handles + * -------------- + */ + + /** + * MHD IPv4 daemon + */ + struct MHD_Daemon *server_v4; + + /** + * MHD IPv4 task + */ + GNUNET_SCHEDULER_TaskIdentifier server_v4_task; + + /** + * MHD IPv6 daemon + */ + struct MHD_Daemon *server_v6; + + /** + * MHD IPv4 task + */ + GNUNET_SCHEDULER_TaskIdentifier server_v6_task; + + /** + * IPv4 server socket to bind to + */ + struct sockaddr_in *server_addr_v4; + + /** + * IPv6 server socket to bind to + */ + struct sockaddr_in6 *server_addr_v6; + + /** + * Server semi connections + * A full session consists of 2 semi-connections: send and receive + * If not both directions are established the server keeps this sessions here + */ + struct Session *server_semi_head; + + struct Session *server_semi_tail; + + /* + * Client handles + */ + + /** + * cURL Multihandle + */ + CURLM *client_mh; + + /** + * curl perform task + */ + GNUNET_SCHEDULER_TaskIdentifier client_perform_task; + +}; + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * IPv4 addresses + */ +struct IPv4HttpAddress +{ + /** + * IPv4 address, in network byte order. + */ + uint32_t ipv4_addr GNUNET_PACKED; + + /** + * Port number, in network byte order. + */ + uint16_t u4_port GNUNET_PACKED; +}; + +/** + * IPv4 addresses + */ +struct IPv6HttpAddress +{ + /** + * IPv6 address. + */ + struct in6_addr ipv6_addr GNUNET_PACKED; + + /** + * Port number, in network byte order. + */ + uint16_t u6_port GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Session handle for connections. + */ +struct Session +{ + + /** + * Stored in a linked list. + */ + struct Session *next; + + /** + * Stored in a linked list. + */ + struct Session *prev; + + /** + * Pointer to the global plugin struct. + */ + struct Plugin *plugin; + + /** + * Address + */ + void *addr; + + /** + * Address length + */ + size_t addrlen; + + /** + * ATS network type in NBO + */ + uint32_t ats_address_network_type; + + /** + * To whom are we talking to + */ + struct GNUNET_PeerIdentity target; + + /** + * next pointer for double linked list + */ + struct HTTP_Message *msg_head; + + /** + * previous pointer for double linked list + */ + struct HTTP_Message *msg_tail; + + + /** + * Message stream tokenizer for incoming data + */ + struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; + + /** + * Absolute time when to receive data again + * Used for receive throttling + */ + struct GNUNET_TIME_Absolute next_receive; + + /** + * Inbound or outbound connection + * Outbound: GNUNET_NO (client is used to send and receive) + * Inbound : GNUNET_YES (server is used to send and receive) + */ + int inbound; + + /** + * Unique HTTP/S connection tag for this connection + */ + uint32_t tag; + + /** + * Client handles + */ + + /** + * Client send handle + */ + void *client_put; + + /** + * Client receive handle + */ + void *client_get; + + /** + * Task to wake up client receive handle when receiving is allowed again + */ + GNUNET_SCHEDULER_TaskIdentifier recv_wakeup_task; + + /** + * Is client send handle paused since there are no data to send? + * GNUNET_YES/NO + */ + int client_put_paused; + + /** + * Server handles + */ + + /** + * Client send handle + */ + void *server_recv; + + /** + * Client send handle + */ + void *server_send; +}; + +/** + * Message to send using http + */ +struct HTTP_Message +{ + /** + * next pointer for double linked list + */ + struct HTTP_Message *next; + + /** + * previous pointer for double linked list + */ + struct HTTP_Message *prev; + + /** + * buffer containing data to send + */ + char *buf; + + /** + * amount of data already sent + */ + size_t pos; + + /** + * buffer length + */ + size_t size; + + /** + * Continuation function to call once the transmission buffer + * has again space available. NULL if there is no + * continuation to call. + */ + GNUNET_TRANSPORT_TransmitContinuation transmit_cont; + + /** + * Closure for transmit_cont. + */ + void *transmit_cont_cls; +}; + +void +delete_session (struct Session *s); + +struct Session * +create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, + const void *addr, size_t addrlen, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls); + +struct GNUNET_TIME_Relative +http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + struct Session *session, const char *sender_address, + uint16_t sender_address_len); + +const char * +http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen); + +int +client_disconnect (struct Session *s); + +int +client_connect (struct Session *s); + +int +client_send (struct Session *s, struct HTTP_Message *msg); + +int +client_start (struct Plugin *plugin); + +void +client_stop (struct Plugin *plugin); + +int +server_disconnect (struct Session *s); + +int +server_send (struct Session *s, struct HTTP_Message *msg); + +int +server_start (struct Plugin *plugin); + +void +server_stop (struct Plugin *plugin); + +void +notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, + struct Session *s); + +/* end of plugin_transport_http.h */ diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c new file mode 100644 index 0000000..4679e45 --- /dev/null +++ b/src/transport/plugin_transport_http_client.c @@ -0,0 +1,643 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_http_client.c + * @brief http transport service plugin + * @author Matthias Wachs + */ + +#include "plugin_transport_http.h" + +#if VERBOSE_CURL +/** + * Function to log curl debug messages with GNUNET_log + * @param curl handle + * @param type curl_infotype + * @param data data + * @param size size + * @param cls closure + * @return 0 + */ +static int +client_log (CURL * curl, curl_infotype type, char *data, size_t size, void *cls) +{ + if (type == CURLINFO_TEXT) + { + char text[size + 2]; + + memcpy (text, data, size); + if (text[size - 1] == '\n') + text[size] = '\0'; + else + { + text[size] = '\n'; + text[size + 1] = '\0'; + } +#if BUILD_HTTPS + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-https", + "Client: %X - %s", cls, text); +#else + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-http", + "Client: %X - %s", cls, text); +#endif + } + return 0; +} +#endif + +/** + * Task performing curl operations + * @param cls plugin as closure + * @param tc gnunet scheduler task context + */ +static void +client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Function setting up file descriptors and scheduling task to run + * + * @param plugin plugin as closure + * @param now schedule task in 1ms, regardless of what curl may say + * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok + */ +static int +client_schedule (struct Plugin *plugin, int now) +{ + fd_set rs; + fd_set ws; + fd_set es; + int max; + struct GNUNET_NETWORK_FDSet *grs; + struct GNUNET_NETWORK_FDSet *gws; + long to; + CURLMcode mret; + struct GNUNET_TIME_Relative timeout; + + /* Cancel previous scheduled task */ + if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->client_perform_task); + plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; + } + + max = -1; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + mret = curl_multi_fdset (plugin->client_mh, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_fdset", __FILE__, __LINE__, + curl_multi_strerror (mret)); + return GNUNET_SYSERR; + } + mret = curl_multi_timeout (plugin->client_mh, &to); + if (to == -1) + timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1); + else + timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to); + if (now == GNUNET_YES) + timeout = GNUNET_TIME_UNIT_MILLISECONDS; + + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_timeout", __FILE__, __LINE__, + curl_multi_strerror (mret)); + return GNUNET_SYSERR; + } + + grs = GNUNET_NETWORK_fdset_create (); + gws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); + + plugin->client_perform_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, timeout, grs, gws, + &client_run, plugin); + GNUNET_NETWORK_fdset_destroy (gws); + GNUNET_NETWORK_fdset_destroy (grs); + return GNUNET_OK; +} + + +int +client_send (struct Session *s, struct HTTP_Message *msg) +{ + GNUNET_assert (s != NULL); + GNUNET_CONTAINER_DLL_insert (s->msg_head, s->msg_tail, msg); + + if (s->client_put_paused == GNUNET_YES) + { +#if VERBOSE_CLIENT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, + "Client: %X was suspended, unpausing\n", s->client_put); +#endif + s->client_put_paused = GNUNET_NO; + curl_easy_pause (s->client_put, CURLPAUSE_CONT); + } + + client_schedule (s->plugin, GNUNET_YES); + + return GNUNET_OK; +} + + + +/** + * Task performing curl operations + * @param cls plugin as closure + * @param tc gnunet scheduler task context + */ +static void +client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + int running; + CURLMcode mret; + + GNUNET_assert (cls != NULL); + + plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + do + { + running = 0; + mret = curl_multi_perform (plugin->client_mh, &running); + + CURLMsg *msg; + int msgs_left; + + while ((msg = curl_multi_info_read (plugin->client_mh, &msgs_left))) + { + CURL *easy_h = msg->easy_handle; + struct Session *s = NULL; + char *d = (char *) s; + + + //GNUNET_assert (easy_h != NULL); + if (easy_h == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Client: connection to ended with reason %i: `%s', %i handles running\n", + msg->data.result, + curl_easy_strerror (msg->data.result), running); + continue; + } + + GNUNET_assert (CURLE_OK == + curl_easy_getinfo (easy_h, CURLINFO_PRIVATE, &d)); + s = (struct Session *) d; + GNUNET_assert (s != NULL); + + if (msg->msg == CURLMSG_DONE) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Client: %X connection to '%s' %s ended with reason %i: `%s'\n", + msg->easy_handle, GNUNET_i2s (&s->target), + http_plugin_address_to_string (NULL, s->addr, + s->addrlen), + msg->data.result, + curl_easy_strerror (msg->data.result)); + + client_disconnect (s); + //GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,"Notifying about ended session to peer `%s' `%s'\n", GNUNET_i2s (&s->target), http_plugin_address_to_string (plugin, s->addr, s->addrlen)); + notify_session_end (plugin, &s->target, s); + } + } + } + while (mret == CURLM_CALL_MULTI_PERFORM); + client_schedule (plugin, GNUNET_NO); +} + +int +client_disconnect (struct Session *s) +{ + int res = GNUNET_OK; + CURLMcode mret; + struct Plugin *plugin = s->plugin; + struct HTTP_Message *msg; + struct HTTP_Message *t; + + + + if (s->client_put != NULL) + { +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Client: %X Deleting outbound PUT session to peer `%s'\n", + s->client_put, GNUNET_i2s (&s->target)); +#endif + + mret = curl_multi_remove_handle (plugin->client_mh, s->client_put); + if (mret != CURLM_OK) + { + curl_easy_cleanup (s->client_put); + res = GNUNET_SYSERR; + GNUNET_break (0); + } + curl_easy_cleanup (s->client_put); + s->client_put = NULL; + } + + + if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); + s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (s->client_get != NULL) + { +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Client: %X Deleting outbound GET session to peer `%s'\n", + s->client_get, GNUNET_i2s (&s->target)); +#endif + + mret = curl_multi_remove_handle (plugin->client_mh, s->client_get); + if (mret != CURLM_OK) + { + curl_easy_cleanup (s->client_get); + res = GNUNET_SYSERR; + GNUNET_break (0); + } + curl_easy_cleanup (s->client_get); + s->client_get = NULL; + } + + msg = s->msg_head; + while (msg != NULL) + { + t = msg->next; + if (NULL != msg->transmit_cont) + msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); + GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); + GNUNET_free (msg); + msg = t; + } + + plugin->cur_connections -= 2; + /* Re-schedule since handles have changed */ + if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->client_perform_task); + plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; + } + + client_schedule (plugin, GNUNET_YES); + + return res; +} + +static void +client_receive_mst_cb (void *cls, void *client, + const struct GNUNET_MessageHeader *message) +{ + struct Session *s = cls; + struct GNUNET_TIME_Relative delay; + + delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); + s->next_receive = + GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); + + if (GNUNET_TIME_absolute_get ().abs_value < s->next_receive.abs_value) + { +#if VERBOSE_CLIENT + struct Plugin *plugin = s->plugin; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Client: peer `%s' address `%s' next read delayed for %llu ms\n", + GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen), + delay); +#endif + } +} + +static void +client_wake_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Session *s = cls; + + s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, + "Client: %X Waking up receive handle\n", s->client_get); + + if (s->client_get != NULL) + curl_easy_pause (s->client_get, CURLPAUSE_CONT); + +} + +/** +* Callback method used with libcurl +* Method is called when libcurl needs to write data during sending +* @param stream pointer where to write data +* @param size size of an individual element +* @param nmemb count of elements that can be written to the buffer +* @param cls destination pointer, passed to the libcurl handle +* @return bytes read from stream +*/ +static size_t +client_receive (void *stream, size_t size, size_t nmemb, void *cls) +{ + struct Session *s = cls; + struct GNUNET_TIME_Absolute now; + size_t len = size * nmemb; + + +#if VERBOSE_CLIENT + struct Plugin *plugin = s->plugin; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Client: Received %Zu bytes from peer `%s'\n", len, + GNUNET_i2s (&s->target)); +#endif + + now = GNUNET_TIME_absolute_get (); + if (now.abs_value < s->next_receive.abs_value) + { + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct GNUNET_TIME_Relative delta = + GNUNET_TIME_absolute_get_difference (now, s->next_receive); +#if DEBUG_CLIENT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Client: %X No inbound bandwidth available! Next read was delayed for %llu ms\n", + s->client_get, delta.rel_value); +#endif + if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); + s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; + } + s->recv_wakeup_task = + GNUNET_SCHEDULER_add_delayed (delta, &client_wake_up, s); + return CURLPAUSE_ALL; + } + + + if (s->msg_tk == NULL) + s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb, s); + + GNUNET_SERVER_mst_receive (s->msg_tk, s, stream, len, GNUNET_NO, GNUNET_NO); + + return len; +} + +/** + * Callback method used with libcurl + * Method is called when libcurl needs to read data during sending + * @param stream pointer where to write data + * @param size size of an individual element + * @param nmemb count of elements that can be written to the buffer + * @param cls source pointer, passed to the libcurl handle + * @return bytes written to stream, returning 0 will terminate connection! + */ +static size_t +client_send_cb (void *stream, size_t size, size_t nmemb, void *cls) +{ + struct Session *s = cls; + +#if VERBOSE_CLIENT + struct Plugin *plugin = s->plugin; +#endif + size_t bytes_sent = 0; + size_t len; + + struct HTTP_Message *msg = s->msg_head; + + if (msg == NULL) + { +#if VERBOSE_CLIENT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Client: %X Nothing to send! Suspending PUT handle!\n", + s->client_put); +#endif + s->client_put_paused = GNUNET_YES; + return CURL_READFUNC_PAUSE; + } + + GNUNET_assert (msg != NULL); + /* data to send */ + if (msg->pos < msg->size) + { + /* data fit in buffer */ + if ((msg->size - msg->pos) <= (size * nmemb)) + { + len = (msg->size - msg->pos); + memcpy (stream, &msg->buf[msg->pos], len); + msg->pos += len; + bytes_sent = len; + } + else + { + len = size * nmemb; + memcpy (stream, &msg->buf[msg->pos], len); + msg->pos += len; + bytes_sent = len; + } + } + /* no data to send */ + else + { + GNUNET_assert (0); + bytes_sent = 0; + } + + if (msg->pos == msg->size) + { +#if VERBOSE_CLIENT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Client: %X Message with %u bytes sent, removing message from queue\n", + s->client_put, msg->size, msg->pos); +#endif + /* Calling transmit continuation */ + if (NULL != msg->transmit_cont) + msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); + GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); + GNUNET_free (msg); + } + return bytes_sent; +} + +int +client_connect (struct Session *s) +{ + struct Plugin *plugin = s->plugin; + int res = GNUNET_OK; + char *url; + CURLMcode mret; + +#if VERBOSE_CLIENT +#endif + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Initiating outbound session peer `%s'\n", + GNUNET_i2s (&s->target)); + + + s->inbound = GNUNET_NO; + + plugin->last_tag++; + /* create url */ + GNUNET_asprintf (&url, "%s%s;%u", + http_plugin_address_to_string (plugin, s->addr, s->addrlen), + GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey), + plugin->last_tag); +#if 0 + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "URL `%s'\n", url); +#endif + /* create get connection */ + s->client_get = curl_easy_init (); +#if VERBOSE_CURL + curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L); + curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log); + curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get); +#endif +#if BUILD_HTTPS + curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0); +#endif + curl_easy_setopt (s->client_get, CURLOPT_URL, url); + //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, &curl_get_header_cb); + //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps); + curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, client_send_cb); + curl_easy_setopt (s->client_get, CURLOPT_READDATA, s); + curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, client_receive); + curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, s); + curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT_MS, + (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, s); + curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT_MS, + (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); + curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE, + 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); +#if CURL_TCP_NODELAY + curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1); +#endif + + /* create put connection */ + s->client_put = curl_easy_init (); +#if VERBOSE_CURL + curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L); + curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log); + curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put); +#endif +#if BUILD_HTTPS + curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0); +#endif + curl_easy_setopt (s->client_put, CURLOPT_URL, url); + curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L); + //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, &curl_put_header_cb); + //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps); + curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, client_send_cb); + curl_easy_setopt (s->client_put, CURLOPT_READDATA, s); + curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, client_receive); + curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, s); + curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT_MS, + (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, s); + curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT_MS, + (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); + curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE, + 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); +#if CURL_TCP_NODELAY + curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1); +#endif + + GNUNET_free (url); + + mret = curl_multi_add_handle (plugin->client_mh, s->client_get); + if (mret != CURLM_OK) + { + curl_easy_cleanup (s->client_get); + res = GNUNET_SYSERR; + GNUNET_break (0); + } + + mret = curl_multi_add_handle (plugin->client_mh, s->client_put); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (plugin->client_mh, s->client_get); + curl_easy_cleanup (s->client_get); + curl_easy_cleanup (s->client_put); + res = GNUNET_SYSERR; + GNUNET_break (0); + } + + /* Perform connect */ + plugin->cur_connections += 2; + + /* Re-schedule since handles have changed */ + if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->client_perform_task); + plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; + } + plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin); + + return res; +} + +int +client_start (struct Plugin *plugin) +{ + int res = GNUNET_OK; + + curl_global_init (CURL_GLOBAL_ALL); + plugin->client_mh = curl_multi_init (); + + if (NULL == plugin->client_mh) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _ + ("Could not initialize curl multi handle, failed to start %s plugin!\n"), + plugin->name); + res = GNUNET_SYSERR; + } + return res; +} + +void +client_stop (struct Plugin *plugin) +{ + if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->client_perform_task); + plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; + } + + curl_multi_cleanup (plugin->client_mh); + curl_global_cleanup (); +} + + + +/* end of plugin_transport_http_client.c */ diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c new file mode 100644 index 0000000..8ec5a5e --- /dev/null +++ b/src/transport/plugin_transport_http_server.c @@ -0,0 +1,1223 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_http.c + * @brief http transport service plugin + * @author Matthias Wachs + */ + +#include "plugin_transport_http.h" + +#define HTTP_ERROR_RESPONSE "404 Not Found

Not Found

The requested URL was not found on this server.


" +#define _RECEIVE 0 +#define _SEND 1 + +struct ServerConnection +{ + /* _RECV or _SEND */ + int direction; + + /* should this connection get disconnected? GNUNET_YES/NO */ + int disconnect; + + struct Session *session; + struct MHD_Connection *mhd_conn; +}; + +/** + * Function that queries MHD's select sets and + * starts the task waiting for them. + * @param plugin plugin + * @param daemon_handle the MHD daemon handle + * @param now schedule now or with MHD delay + * @return gnunet task identifier + */ +static GNUNET_SCHEDULER_TaskIdentifier +server_schedule (struct Plugin *plugin, + struct MHD_Daemon *daemon_handle, + int now); + +static void +server_log (void *arg, const char *fmt, va_list ap) +{ + char text[1024]; + + vsnprintf (text, sizeof (text), fmt, ap); + va_end (ap); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server: %s\n", text); +} + +/** + * Check if incoming connection is accepted. + * NOTE: Here every connection is accepted + * @param cls plugin as closure + * @param addr address of incoming connection + * @param addr_len address length of incoming connection + * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected + * + */ +static int +server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len) +{ + struct Plugin *plugin = cls; + + if (plugin->cur_connections <= plugin->max_connections) + return MHD_YES; + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Server: Cannot accept new connections\n"); + return MHD_NO; + } +} + + +#if BUILD_HTTPS +static char * +server_load_file (const char *file) +{ + struct GNUNET_DISK_FileHandle *gn_file; + struct stat fstat; + char *text = NULL; + + if (0 != STAT (file, &fstat)) + return NULL; + text = GNUNET_malloc (fstat.st_size + 1); + gn_file = + GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_USER_READ); + if (gn_file == NULL) + { + GNUNET_free (text); + return NULL; + } + if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fstat.st_size)) + { + GNUNET_free (text); + GNUNET_DISK_file_close (gn_file); + return NULL; + } + text[fstat.st_size] = '\0'; + GNUNET_DISK_file_close (gn_file); + return text; +} +#endif + + +#if BUILD_HTTPS + +static int +server_load_certificate (struct Plugin *plugin) +{ + int res = GNUNET_OK; + + char *key_file; + char *cert_file; + + /* Get crypto init string from config + * If not present just use default values */ + + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, + plugin->name, + "CRYPTO_INIT", + &plugin->crypto_init)); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, + "KEY_FILE", &key_file)) + { + key_file = GNUNET_strdup ("https_key.key"); + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, + "CERT_FILE", &cert_file)) + { + GNUNET_asprintf (&cert_file, "%s", "https_cert.crt"); + } + + /* read key & certificates from file */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Loading TLS certificate from key-file `%s' cert-file`%s'\n", + key_file, cert_file); + + plugin->key = server_load_file (key_file); + plugin->cert = server_load_file (cert_file); + + if ((plugin->key == NULL) || (plugin->cert == NULL)) + { + struct GNUNET_OS_Process *cert_creation; + + GNUNET_free_non_null (plugin->key); + plugin->key = NULL; + GNUNET_free_non_null (plugin->cert); + plugin->cert = NULL; + +#if VERBOSE_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No usable TLS certificate found, creating certificate\n"); +#endif + errno = 0; + cert_creation = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, + "gnunet-transport-certificate-creation", + "gnunet-transport-certificate-creation", + key_file, cert_file, NULL); + if (cert_creation == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _ + ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n")); + GNUNET_free (key_file); + GNUNET_free (cert_file); + + GNUNET_free_non_null (plugin->key); + plugin->key = NULL; + GNUNET_free_non_null (plugin->cert); + plugin->cert = NULL; + GNUNET_free_non_null (plugin->crypto_init); + plugin->crypto_init = NULL; + + return GNUNET_SYSERR; + } + GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation)); + GNUNET_OS_process_close (cert_creation); + + plugin->key = server_load_file (key_file); + plugin->cert = server_load_file (cert_file); + } + + if ((plugin->key == NULL) || (plugin->cert == NULL)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _ + ("No usable TLS certificate found and creating one failed!\n"), + "transport-https"); + GNUNET_free (key_file); + GNUNET_free (cert_file); + + GNUNET_free_non_null (plugin->key); + plugin->key = NULL; + GNUNET_free_non_null (plugin->cert); + plugin->cert = NULL; + GNUNET_free_non_null (plugin->crypto_init); + plugin->crypto_init = NULL; + + return GNUNET_SYSERR; + } + GNUNET_free (key_file); + GNUNET_free (cert_file); +#if DEBUG_HTTP + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n"); +#endif + + return res; +} +#endif + + +/** + * Reschedule the execution of both IPv4 and IPv6 server + * @param plugin the plugin + * @param server which server to schedule v4 or v6? + * @param now GNUNET_YES to schedule execution immediately, GNUNET_NO to wait + * until timeout + */ + +static void +server_reschedule (struct Plugin *plugin, struct MHD_Daemon *server, int now) +{ + if ((server == plugin->server_v4) && (plugin->server_v4 != NULL)) + { + if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_v4_task); + plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; + } + plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now); + } + + if ((server == plugin->server_v6) && (plugin->server_v6 != NULL)) + { + if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_v6_task); + plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; + } + plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now); + } +} + +/** + * Callback called by MessageStreamTokenizer when a message has arrived + * @param cls current session as closure + * @param client clien + * @param message the message to be forwarded to transport service + */ +static void +server_receive_mst_cb (void *cls, void *client, + const struct GNUNET_MessageHeader *message) +{ + struct Session *s = cls; + struct Plugin *plugin = s->plugin; + struct GNUNET_TIME_Relative delay; + + delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); + + s->next_receive = + GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); + + if (delay.rel_value > 0) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: peer `%s' address `%s' next read delayed for %llu ms\n", + GNUNET_i2s (&s->target), + http_plugin_address_to_string (NULL, s->addr, s->addrlen), + delay); + } +} + +/** + * Callback called by MHD when it needs data to send + * @param cls current session + * @param pos position in buffer + * @param buf the buffer to write data to + * @param max max number of bytes available in buffer + * @return bytes written to buffer + */ +static ssize_t +server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) +{ + struct Session *s = cls; + + struct HTTP_Message *msg; + int bytes_read = 0; + + //static int c = 0; + msg = s->msg_head; + if (msg != NULL) + { + /* sending */ + if ((msg->size - msg->pos) <= max) + { + memcpy (buf, &msg->buf[msg->pos], (msg->size - msg->pos)); + bytes_read = msg->size - msg->pos; + msg->pos += (msg->size - msg->pos); + } + else + { + memcpy (buf, &msg->buf[msg->pos], max); + msg->pos += max; + bytes_read = max; + } + + /* removing message */ + if (msg->pos == msg->size) + { + if (NULL != msg->transmit_cont) + msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); + GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); + GNUNET_free (msg); + } + } + + struct Plugin *plugin = s->plugin; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: %X: sent %u bytes\n", s, bytes_read); + + return bytes_read; +} + +static struct ServerConnection * +server_lookup_session (struct Plugin *plugin, + struct MHD_Connection *mhd_connection, const char *url, + const char *method) +{ + struct Session *s = NULL; + struct Session *t; + struct ServerConnection *sc = NULL; + const union MHD_ConnectionInfo *conn_info; + struct GNUNET_ATS_Information ats; + struct IPv4HttpAddress a4; + struct IPv6HttpAddress a6; + struct sockaddr_in *s4; + struct sockaddr_in6 *s6; + void *a; + size_t a_len; + struct GNUNET_PeerIdentity target; + int check = GNUNET_NO; + uint32_t tag = 0; + int direction = GNUNET_SYSERR; + + conn_info = + MHD_get_connection_info (mhd_connection, + MHD_CONNECTION_INFO_CLIENT_ADDRESS); + if ((conn_info->client_addr->sa_family != AF_INET) && + (conn_info->client_addr->sa_family != AF_INET6)) + return MHD_NO; + + if ((strlen (&url[1]) >= 105) && (url[104] == ';')) + { + char hash[104]; + char *tagc = (char *) &url[105]; + + memcpy (&hash, &url[1], 103); + hash[103] = '\0'; + if (GNUNET_OK == + GNUNET_CRYPTO_hash_from_string ((const char *) &hash, + &(target.hashPubKey))) + { + tag = strtoul (tagc, NULL, 10); + if (tagc > 0) + check = GNUNET_YES; + } + } + + if (0 == strcmp (MHD_HTTP_METHOD_PUT, method)) + direction = _RECEIVE; + else if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) + direction = _SEND; + else + { + GNUNET_break_op (0); + goto error; + } + + + if (check == GNUNET_NO) + goto error; + + plugin->cur_connections++; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: New inbound connection from %s with tag %u\n", + GNUNET_i2s (&target), tag); + /* find duplicate session */ + + t = plugin->head; + + while (t != NULL) + { + if ((t->inbound) && + (0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) + && + /* FIXME add source address comparison */ + (t->tag == tag)) + break; + t = t->next; + } + if (t != NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Duplicate session, dismissing new connection from peer `%s'\n", + GNUNET_i2s (&target)); + goto error; + } + + /* find semi-session */ + t = plugin->server_semi_head; + + while (t != NULL) + { + /* FIXME add source address comparison */ + if ((0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) + && (t->tag == tag)) + { + break; + } + t = t->next; + } + + if (t == NULL) + goto create; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Found existing semi-session for `%s'\n", + GNUNET_i2s (&target)); + + if ((direction == _SEND) && (t->server_send != NULL)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Duplicate GET session, dismissing new connection from peer `%s'\n", + GNUNET_i2s (&target)); + goto error; + } + else + { + s = t; + GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, + plugin->server_semi_tail, s); + GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Found matching semi-session, merging session for peer `%s'\n", + GNUNET_i2s (&target)); + + goto found; + } + if ((direction == _RECEIVE) && (t->server_recv != NULL)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Duplicate PUT session, dismissing new connection from peer `%s'\n", + GNUNET_i2s (&target)); + goto error; + } + else + { + s = t; + GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, + plugin->server_semi_tail, s); + GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Found matching semi-session, merging session for peer `%s'\n", + GNUNET_i2s (&target)); + goto found; + } + +create: +/* create new session */ + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Creating new session for peer `%s' \n", + GNUNET_i2s (&target)); + switch (conn_info->client_addr->sa_family) + { + case (AF_INET): + s4 = ((struct sockaddr_in *) conn_info->client_addr); + a4.u4_port = s4->sin_port; + memcpy (&a4.ipv4_addr, &s4->sin_addr, sizeof (struct in_addr)); + a = &a4; + a_len = sizeof (struct IPv4HttpAddress); + ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s4, sizeof (struct sockaddr_in)); + break; + case (AF_INET6): + s6 = ((struct sockaddr_in6 *) conn_info->client_addr); + a6.u6_port = s6->sin6_port; + memcpy (&a6.ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); + a = &a6; + a_len = sizeof (struct IPv6HttpAddress); + ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s6, sizeof (struct sockaddr_in6)); + break; + default: + GNUNET_break (0); + goto error; + } + s = create_session (plugin, &target, a, a_len, NULL, NULL); + s->ats_address_network_type = ats.value; + + s->inbound = GNUNET_YES; + s->next_receive = GNUNET_TIME_absolute_get_zero (); + s->tag = tag; + if (0 == strcmp (MHD_HTTP_METHOD_PUT, method)) + s->server_recv = s; + if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) + s->server_send = s; + GNUNET_CONTAINER_DLL_insert (plugin->server_semi_head, + plugin->server_semi_tail, s); + goto found; + +error: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Invalid connection request\n"); + return NULL; + +found: + sc = GNUNET_malloc (sizeof (struct ServerConnection)); + sc->mhd_conn = mhd_connection; + sc->direction = direction; + sc->session = s; + if (direction == _SEND) + s->server_send = sc; + if (direction == _RECEIVE) + s->server_recv = sc; + +#if MHD_VERSION >= 0x00090E00 + int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Setting timeout for %X to %u sec.\n", sc, to); + MHD_set_connection_option (mhd_connection, MHD_CONNECTION_OPTION_TIMEOUT, to); + + struct MHD_Daemon *d = NULL; + + if (s->addrlen == sizeof (struct IPv6HttpAddress)) + d = plugin->server_v6; + if (s->addrlen == sizeof (struct IPv4HttpAddress)) + d = plugin->server_v4; + + server_reschedule (plugin, d, GNUNET_NO); +#endif + return sc; +} + +/** + * Process GET or PUT request received via MHD. For + * GET, queue response that will send back our pending + * messages. For PUT, process incoming data and send + * to GNUnet core. In either case, check if a session + * already exists and create a new one if not. + */ +static int +server_access_cb (void *cls, struct MHD_Connection *mhd_connection, + const char *url, const char *method, const char *version, + const char *upload_data, size_t * upload_data_size, + void **httpSessionCache) +{ + + struct Plugin *plugin = cls; + struct ServerConnection *sc = *httpSessionCache; + struct Session *s = NULL; + + int res = MHD_YES; + struct MHD_Response *response; + + GNUNET_assert (cls != NULL); + /* new connection */ + if (sc == NULL) + { + sc = server_lookup_session (plugin, mhd_connection, url, method); + if (sc != NULL) + (*httpSessionCache) = sc; + else + { + response = + MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE), + HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO); + res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response); + MHD_destroy_response (response); + return res; + } + } + + /* existing connection */ + sc = (*httpSessionCache); + s = sc->session; + + /* connection is to be disconnected */ + if (sc->disconnect == GNUNET_YES) + { + /* Sent HTTP/1.1: 200 OK as PUT Response\ */ + response = + MHD_create_response_from_data (strlen ("Thank you!"), "Thank you!", + MHD_NO, MHD_NO); + res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return MHD_YES; + } + + GNUNET_assert (s != NULL); + /* Check if both directions are connected */ + if ((sc->session->server_recv == NULL) || (sc->session->server_send == NULL)) + { + /* Delayed read from since not both semi-connections are connected */ + return MHD_YES; + } + + if (sc->direction == _SEND) + { + response = + MHD_create_response_from_callback (-1, 32 * 1024, &server_send_callback, + s, NULL); + MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return MHD_YES; + } + if (sc->direction == _RECEIVE) + { + if (*upload_data_size == 0) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Peer `%s' PUT on address `%s' connected\n", + GNUNET_i2s (&s->target), + http_plugin_address_to_string (NULL, s->addr, + s->addrlen)); + return MHD_YES; + } + + /* Receiving data */ + if ((*upload_data_size > 0)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: peer `%s' PUT on address `%s' received %u bytes\n", + GNUNET_i2s (&s->target), + http_plugin_address_to_string (NULL, s->addr, + s->addrlen), + *upload_data_size); + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + + if ((s->next_receive.abs_value <= now.abs_value)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: %X: PUT with %u bytes forwarded to MST\n", s, + *upload_data_size); + if (s->msg_tk == NULL) + { + s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s); + } + GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, + *upload_data_size, GNUNET_NO, GNUNET_NO); + +#if MHD_VERSION >= 0x00090E00 + int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); + struct ServerConnection *t = NULL; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Received %u bytes\n", *upload_data_size); + /* Setting timeouts for other connections */ + if (s->server_recv != NULL) + { + t = s->server_recv; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Setting timeout for %X to %u sec.\n", t, + to); + MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, + to); + } + if (s->server_send != NULL) + { + t = s->server_send; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: Setting timeout for %X to %u sec.\n", t, + to); + MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, + to); + } + struct MHD_Daemon *d = NULL; + + if (s->addrlen == sizeof (struct IPv6HttpAddress)) + d = plugin->server_v6; + if (s->addrlen == sizeof (struct IPv4HttpAddress)) + d = plugin->server_v4; + server_reschedule (plugin, d, GNUNET_NO); +#endif + (*upload_data_size) = 0; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Server: %X no inbound bandwidth available! Next read was delayed by %llu ms\n", + s, now.abs_value - s->next_receive.abs_value); + } + return MHD_YES; + } + else + return MHD_NO; + } + return res; +} + +static void +server_disconnect_cb (void *cls, struct MHD_Connection *connection, + void **httpSessionCache) +{ + struct ServerConnection *sc = *httpSessionCache; + struct ServerConnection *tc = NULL; + struct Session *s = NULL; + struct Session *t = NULL; + struct Plugin *plugin = NULL; + + if (sc == NULL) + return; + + s = sc->session; + plugin = s->plugin; + if (sc->direction == _SEND) + { + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: %X peer `%s' GET on address `%s' disconnected\n", + s->server_send, GNUNET_i2s (&s->target), + http_plugin_address_to_string (NULL, s->addr, s->addrlen)); + + s->server_send = NULL; + + if (s->server_recv != NULL) + { + tc = s->server_recv; + tc->disconnect = GNUNET_YES; +#if MHD_VERSION >= 0x00090E00 + MHD_set_connection_option (sc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, + 1); +#endif + } + } + if (sc->direction == _RECEIVE) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: %X peer `%s' PUT on address `%s' disconnected\n", + s->server_recv, GNUNET_i2s (&s->target), + http_plugin_address_to_string (NULL, s->addr, s->addrlen)); + s->server_recv = NULL; + if (s->server_send != NULL) + { + tc = s->server_send; + tc->disconnect = GNUNET_YES; +#if MHD_VERSION >= 0x00090E00 + MHD_set_connection_option (sc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, + 1); +#endif + } + if (s->msg_tk != NULL) + { + GNUNET_SERVER_mst_destroy (s->msg_tk); + s->msg_tk = NULL; + } + } + GNUNET_free (sc); + + t = plugin->server_semi_head; + while (t != NULL) + { + if (t == s) + { + GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, + plugin->server_semi_tail, s); + GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); + break; + } + t = t->next; + } + plugin->cur_connections--; + + struct MHD_Daemon *d = NULL; + + if (s->addrlen == sizeof (struct IPv6HttpAddress)) + d = plugin->server_v6; + if (s->addrlen == sizeof (struct IPv4HttpAddress)) + d = plugin->server_v4; + server_reschedule (plugin, d, GNUNET_NO); + + if ((s->server_send == NULL) && (s->server_recv == NULL)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Server: peer `%s' on address `%s' disconnected\n", + GNUNET_i2s (&s->target), + http_plugin_address_to_string (NULL, s->addr, s->addrlen)); + if (s->msg_tk != NULL) + { + GNUNET_SERVER_mst_destroy (s->msg_tk); + s->msg_tk = NULL; + } + + notify_session_end (s->plugin, &s->target, s); + } +} + +int +server_disconnect (struct Session *s) +{ + struct Plugin *plugin = s->plugin; + struct Session *t = plugin->head; + + while (t != NULL) + { + if (t->inbound == GNUNET_YES) + { + if (t->server_send != NULL) + { + ((struct ServerConnection *) t->server_send)->disconnect = GNUNET_YES; + } + if (t->server_send != NULL) + { + ((struct ServerConnection *) t->server_send)->disconnect = GNUNET_YES; + } + } + t = t->next; + } + return GNUNET_OK; +} + +int +server_send (struct Session *s, struct HTTP_Message *msg) +{ + GNUNET_CONTAINER_DLL_insert (s->msg_head, s->msg_tail, msg); + + if (s->addrlen == sizeof (struct IPv4HttpAddress)) + { + server_reschedule (s->plugin, s->plugin->server_v4, GNUNET_YES); + } + else if (s->addrlen == sizeof (struct IPv6HttpAddress)) + { + server_reschedule (s->plugin, s->plugin->server_v6, GNUNET_YES); + } + else + return GNUNET_SYSERR; + return GNUNET_OK; +} + + + +/** + * Call MHD IPv4 to process pending requests and then go back + * and schedule the next run. + * @param cls plugin as closure + * @param tc task context + */ +static void +server_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + + GNUNET_assert (cls != NULL); + + plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Running IPv4 server\n"); + + GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4)); + if (plugin->server_v4 != NULL) + plugin->server_v4_task = + server_schedule (plugin, plugin->server_v4, GNUNET_NO); +} + + +/** + * Call MHD IPv6 to process pending requests and then go back + * and schedule the next run. + * @param cls plugin as closure + * @param tc task context + */ +static void +server_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + + GNUNET_assert (cls != NULL); + + plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Running IPv6 server\n"); + + GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6)); + if (plugin->server_v6 != NULL) + plugin->server_v6_task = + server_schedule (plugin, plugin->server_v6, GNUNET_NO); +} + +/** + * Function that queries MHD's select sets and + * starts the task waiting for them. + * @param plugin plugin + * @param daemon_handle the MHD daemon handle + * @return gnunet task identifier + */ +static GNUNET_SCHEDULER_TaskIdentifier +server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle, + int now) +{ + GNUNET_SCHEDULER_TaskIdentifier ret; + fd_set rs; + fd_set ws; + fd_set es; + struct GNUNET_NETWORK_FDSet *wrs; + struct GNUNET_NETWORK_FDSet *wws; + struct GNUNET_NETWORK_FDSet *wes; + int max; + unsigned long long timeout; + static unsigned long long last_timeout = 0; + int haveto; + + struct GNUNET_TIME_Relative tv; + + ret = GNUNET_SCHEDULER_NO_TASK; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + wrs = GNUNET_NETWORK_fdset_create (); + wes = GNUNET_NETWORK_fdset_create (); + wws = GNUNET_NETWORK_fdset_create (); + max = -1; + GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); + haveto = MHD_get_timeout (daemon_handle, &timeout); + if (haveto == MHD_YES) + { + if (timeout != last_timeout) + { +#if VERBOSE_SERVER + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "SELECT Timeout changed from %llu to %llu\n", + last_timeout, timeout); +#endif + last_timeout = timeout; + } + tv.rel_value = (uint64_t) timeout; + } + else + tv = GNUNET_TIME_UNIT_SECONDS; + /* Force immediate run, since we have outbound data to send */ + if (now == GNUNET_YES) + tv = GNUNET_TIME_UNIT_MILLISECONDS; + GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); + GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); + + if (daemon_handle == plugin->server_v4) + { + if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_v4_task); + plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; + } +#if VERBOSE_SERVER + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Scheduling IPv4 server task in %llu ms\n", tv); +#endif + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws, + &server_v4_run, plugin); + } + if (daemon_handle == plugin->server_v6) + { + if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_v6_task); + plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; + } +#if VERBOSE_SERVER + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Scheduling IPv6 server task in %llu ms\n", tv); +#endif + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws, + &server_v6_run, plugin); + } + GNUNET_NETWORK_fdset_destroy (wrs); + GNUNET_NETWORK_fdset_destroy (wws); + GNUNET_NETWORK_fdset_destroy (wes); + return ret; +} + +int +server_start (struct Plugin *plugin) +{ + int res = GNUNET_OK; + unsigned int timeout; + +#if BUILD_HTTPS + res = server_load_certificate (plugin); + if (res == GNUNET_SYSERR) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + "Could not load or create server certificate! Loading plugin failed!\n"); + return res; + } +#endif + + +#if MHD_VERSION >= 0x00090E00 + timeout = HTTP_NOT_VALIDATED_TIMEOUT.rel_value / 1000; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "MHD can set timeout per connection! Default time out %u sec.\n", + timeout); +#else + timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000; + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, + "MHD cannot set timeout per connection! Default time out %u sec.\n", + timeout); +#endif + plugin->server_v4 = NULL; + if (plugin->ipv4 == GNUNET_YES) + { + plugin->server_v4 = MHD_start_daemon ( +#if VERBOSE_SERVER + MHD_USE_DEBUG | +#endif +#if BUILD_HTTPS + MHD_USE_SSL | +#endif + MHD_NO_FLAG, plugin->port, + &server_accept_cb, plugin, + &server_access_cb, plugin, + MHD_OPTION_SOCK_ADDR, + (struct sockaddr_in *) + plugin->server_addr_v4, + MHD_OPTION_CONNECTION_LIMIT, + (unsigned int) + plugin->max_connections, +#if BUILD_HTTPS + MHD_OPTION_HTTPS_PRIORITIES, + plugin->crypto_init, + MHD_OPTION_HTTPS_MEM_KEY, + plugin->key, + MHD_OPTION_HTTPS_MEM_CERT, + plugin->cert, +#endif + MHD_OPTION_CONNECTION_TIMEOUT, + timeout, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (2 * + GNUNET_SERVER_MAX_MESSAGE_SIZE), + MHD_OPTION_NOTIFY_COMPLETED, + &server_disconnect_cb, plugin, + MHD_OPTION_EXTERNAL_LOGGER, + server_log, NULL, MHD_OPTION_END); + } + plugin->server_v6 = NULL; + if (plugin->ipv6 == GNUNET_YES) + { + plugin->server_v6 = MHD_start_daemon ( +#if VERBOSE_SERVER + MHD_USE_DEBUG | +#endif +#if BUILD_HTTPS + MHD_USE_SSL | +#endif + MHD_USE_IPv6, plugin->port, + &server_accept_cb, plugin, + &server_access_cb, plugin, + MHD_OPTION_SOCK_ADDR, + (struct sockaddr_in6 *) + plugin->server_addr_v6, + MHD_OPTION_CONNECTION_LIMIT, + (unsigned int) + plugin->max_connections, +#if BUILD_HTTPS + MHD_OPTION_HTTPS_PRIORITIES, + plugin->crypto_init, + MHD_OPTION_HTTPS_MEM_KEY, + plugin->key, + MHD_OPTION_HTTPS_MEM_CERT, + plugin->cert, +#endif + MHD_OPTION_CONNECTION_TIMEOUT, + timeout, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (2 * + GNUNET_SERVER_MAX_MESSAGE_SIZE), + MHD_OPTION_NOTIFY_COMPLETED, + &server_disconnect_cb, plugin, + MHD_OPTION_EXTERNAL_LOGGER, + server_log, NULL, MHD_OPTION_END); + + } + + if ((plugin->ipv4 == GNUNET_YES) && (plugin->server_v4 == NULL)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + "Failed to start %s IPv4 server component on port %u\n", + plugin->name, plugin->port); + return GNUNET_SYSERR; + } + server_reschedule (plugin, plugin->server_v4, GNUNET_NO); + + if ((plugin->ipv6 == GNUNET_YES) && (plugin->server_v6 == NULL)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + "Failed to start %s IPv6 server component on port %u\n", + plugin->name, plugin->port); + return GNUNET_SYSERR; + } + server_reschedule (plugin, plugin->server_v6, GNUNET_NO); + + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "%s server component started on port %u\n", plugin->name, + plugin->port); +#endif + return res; +} + +void +server_stop (struct Plugin *plugin) +{ + struct Session *s = NULL; + struct Session *t = NULL; + + struct MHD_Daemon *server_v4_tmp = plugin->server_v4; + + plugin->server_v4 = NULL; + struct MHD_Daemon *server_v6_tmp = plugin->server_v6; + + plugin->server_v6 = NULL; + + if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_v4_task); + plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_v6_task); + plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (server_v6_tmp != NULL) + { + MHD_stop_daemon (server_v4_tmp); + } + if (server_v6_tmp != NULL) + { + MHD_stop_daemon (server_v6_tmp); + } + + /* cleaning up semi-sessions never propagated */ + s = plugin->server_semi_head; + while (s != NULL) + { +#if VERBOSE_SERVER + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Deleting semi-sessions %p\n", s); +#endif + t = s->next; + struct HTTP_Message *msg = s->msg_head; + struct HTTP_Message *tmp = NULL; + + while (msg != NULL) + { + tmp = msg->next; + + GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); + if (msg->transmit_cont != NULL) + { + msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); + } + GNUNET_free (msg); + msg = tmp; + } + + delete_session (s); + s = t; + } + +#if BUILD_HTTPS + GNUNET_free_non_null (plugin->crypto_init); + GNUNET_free_non_null (plugin->cert); + GNUNET_free_non_null (plugin->key); +#endif + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "%s server component stopped\n", plugin->name); +#endif +} + + + +/* end of plugin_transport_http.c */ diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c new file mode 100644 index 0000000..2b2d728 --- /dev/null +++ b/src/transport/plugin_transport_tcp.c @@ -0,0 +1,2115 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/plugin_transport_tcp.c + * @brief Implementation of the TCP transport service + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_hello_lib.h" +#include "gnunet_constants.h" +#include "gnunet_connection_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_nat_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_resolver_service.h" +#include "gnunet_server_lib.h" +#include "gnunet_service_lib.h" +#include "gnunet_signatures.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" +#include "transport.h" + +#define DEBUG_TCP GNUNET_EXTRA_LOGGING + +#define DEBUG_TCP_NAT GNUNET_EXTRA_LOGGING + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Initial handshake message for a session. + */ +struct WelcomeMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME. + */ + struct GNUNET_MessageHeader header; + + /** + * Identity of the node connecting (TCP client) + */ + struct GNUNET_PeerIdentity clientIdentity; + +}; + + +/** + * Basically a WELCOME message, but with the purpose + * of giving the waiting peer a client handle to use + */ +struct TCP_NAT_ProbeMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE. + */ + struct GNUNET_MessageHeader header; + + /** + * Identity of the sender of the message. + */ + struct GNUNET_PeerIdentity clientIdentity; + +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Context for sending a NAT probe via TCP. + */ +struct TCPProbeContext +{ + + /** + * Active probes are kept in a DLL. + */ + struct TCPProbeContext *next; + + /** + * Active probes are kept in a DLL. + */ + struct TCPProbeContext *prev; + + /** + * Probe connection. + */ + struct GNUNET_CONNECTION_Handle *sock; + + /** + * Message to be sent. + */ + struct TCP_NAT_ProbeMessage message; + + /** + * Handle to the transmission. + */ + struct GNUNET_CONNECTION_TransmitHandle *transmit_handle; + + /** + * Transport plugin handle. + */ + struct Plugin *plugin; +}; + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Network format for IPv4 addresses. + */ +struct IPv4TcpAddress +{ + /** + * IPv4 address, in network byte order. + */ + uint32_t ipv4_addr GNUNET_PACKED; + + /** + * Port number, in network byte order. + */ + uint16_t t4_port GNUNET_PACKED; + +}; + + +/** + * Network format for IPv6 addresses. + */ +struct IPv6TcpAddress +{ + /** + * IPv6 address. + */ + struct in6_addr ipv6_addr GNUNET_PACKED; + + /** + * Port number, in network byte order. + */ + uint16_t t6_port GNUNET_PACKED; + +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin; + + +/** + * Information kept for each message that is yet to + * be transmitted. + */ +struct PendingMessage +{ + + /** + * This is a doubly-linked list. + */ + struct PendingMessage *next; + + /** + * This is a doubly-linked list. + */ + struct PendingMessage *prev; + + /** + * The pending message + */ + const char *msg; + + /** + * Continuation function to call once the message + * has been sent. Can be NULL if there is no + * continuation to call. + */ + GNUNET_TRANSPORT_TransmitContinuation transmit_cont; + + /** + * Closure for transmit_cont. + */ + void *transmit_cont_cls; + + /** + * Timeout value for the pending message. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * So that the gnunet-service-transport can group messages together, + * these pending messages need to accept a message buffer and size + * instead of just a GNUNET_MessageHeader. + */ + size_t message_size; + +}; + + +/** + * Session handle for TCP connections. + */ +struct Session +{ + + /** + * API requirement. + */ + struct SessionHeader header; + + /** + * Stored in a linked list. + */ + struct Session *next; + + /** + * Pointer to the global plugin struct. + */ + struct Plugin *plugin; + + /** + * The client (used to identify this connection) + */ + struct GNUNET_SERVER_Client *client; + + /** + * Messages currently pending for transmission + * to this peer, if any. + */ + struct PendingMessage *pending_messages_head; + + /** + * Messages currently pending for transmission + * to this peer, if any. + */ + struct PendingMessage *pending_messages_tail; + + /** + * Handle for pending transmission request. + */ + struct GNUNET_CONNECTION_TransmitHandle *transmit_handle; + + /** + * To whom are we talking to (set to our identity + * if we are still waiting for the welcome message) + */ + struct GNUNET_PeerIdentity target; + + /** + * ID of task used to delay receiving more to throttle sender. + */ + GNUNET_SCHEDULER_TaskIdentifier receive_delay_task; + + /** + * Address of the other peer (either based on our 'connect' + * call or on our 'accept' call). + * + * struct IPv4TcpAddress or struct IPv6TcpAddress + * + */ + void *addr; + + /** + * Length of connect_addr. + */ + size_t addrlen; + + /** + * Last activity on this connection. Used to select preferred + * connection. + */ + struct GNUNET_TIME_Absolute last_activity; + + /** + * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO) + */ + int expecting_welcome; + + /** + * Was this a connection that was inbound (we accepted)? (GNUNET_YES/GNUNET_NO) + */ + int inbound; + + /** + * Was this session created using NAT traversal? + */ + int is_nat; + + /** + * ATS network type in NBO + */ + uint32_t ats_address_network_type; +}; + + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin +{ + /** + * Our environment. + */ + struct GNUNET_TRANSPORT_PluginEnvironment *env; + + /** + * The listen socket. + */ + struct GNUNET_CONNECTION_Handle *lsock; + + /** + * Our handle to the NAT module. + */ + struct GNUNET_NAT_Handle *nat; + + struct GNUNET_CONTAINER_MultiHashMap * sessionmap; + + /** + * Handle to the network service. + */ + struct GNUNET_SERVICE_Context *service; + + /** + * Handle to the server for this service. + */ + struct GNUNET_SERVER_Handle *server; + + /** + * Copy of the handler array where the closures are + * set to this struct's instance. + */ + struct GNUNET_SERVER_MessageHandler *handlers; + + /** + * Map of peers we have tried to contact behind a NAT + */ + struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns; + + /** + * List of active TCP probes. + */ + struct TCPProbeContext *probe_head; + + /** + * List of active TCP probes. + */ + struct TCPProbeContext *probe_tail; + + /** + * Handle for (DYN)DNS lookup of our external IP. + */ + struct GNUNET_RESOLVER_RequestHandle *ext_dns; + + /** + * How many more TCP sessions are we allowed to open right now? + */ + unsigned long long max_connections; + + /** + * ID of task used to update our addresses when one expires. + */ + GNUNET_SCHEDULER_TaskIdentifier address_update_task; + + /** + * Port that we are actually listening on. + */ + uint16_t open_port; + + /** + * Port that the user said we would have visible to the + * rest of the world. + */ + uint16_t adv_port; + +}; + + +/** + * Function to check if an inbound connection is acceptable. + * Mostly used to limit the total number of open connections + * we can have. + * + * @param cls the 'struct Plugin' + * @param ucred credentials, if available, otherwise NULL + * @param addr address + * @param addrlen length of address + * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR + * for unknown address family (will be denied). + */ +static int +plugin_tcp_access_check (void *cls, + const struct GNUNET_CONNECTION_Credentials *ucred, + const struct sockaddr *addr, socklen_t addrlen) +{ + struct Plugin *plugin = cls; + + if (0 == plugin->max_connections) + return GNUNET_NO; + plugin->max_connections--; + return GNUNET_YES; +} + + +/** + * Our external IP address/port mapping has changed. + * + * @param cls closure, the 'struct LocalAddrList' + * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean + * the previous (now invalid) one + * @param addr either the previous or the new public IP address + * @param addrlen actual lenght of the address + */ +static void +tcp_nat_port_map_callback (void *cls, int add_remove, + const struct sockaddr *addr, socklen_t addrlen) +{ + struct Plugin *plugin = cls; + struct IPv4TcpAddress t4; + struct IPv6TcpAddress t6; + void *arg; + size_t args; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "NPMC called with %d for address `%s'\n", add_remove, + GNUNET_a2s (addr, addrlen)); + /* convert 'addr' to our internal format */ + switch (addr->sa_family) + { + case AF_INET: + GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); + t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; + t4.t4_port = ((struct sockaddr_in *) addr)->sin_port; + arg = &t4; + args = sizeof (t4); + break; + case AF_INET6: + GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); + memcpy (&t6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr, + sizeof (struct in6_addr)); + t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port; + arg = &t6; + args = sizeof (t6); + break; + default: + GNUNET_break (0); + return; + } + /* modify our published address list */ + plugin->env->notify_address (plugin->env->cls, add_remove, arg, args); +} + + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure ('struct Plugin*') + * @param addr binary address + * @param addrlen length of the address + * @return string representing the same address + */ +static const char * +tcp_address_to_string (void *cls, const void *addr, size_t addrlen) +{ + static char rbuf[INET6_ADDRSTRLEN + 12]; + char buf[INET6_ADDRSTRLEN]; + const void *sb; + struct in_addr a4; + struct in6_addr a6; + const struct IPv4TcpAddress *t4; + const struct IPv6TcpAddress *t6; + int af; + uint16_t port; + + if (addrlen == sizeof (struct IPv6TcpAddress)) + { + t6 = addr; + af = AF_INET6; + port = ntohs (t6->t6_port); + memcpy (&a6, &t6->ipv6_addr, sizeof (a6)); + sb = &a6; + } + else if (addrlen == sizeof (struct IPv4TcpAddress)) + { + t4 = addr; + af = AF_INET; + port = ntohs (t4->t4_port); + memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); + sb = &a4; + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + _("Unexpected address length: %u bytes\n"), + (unsigned int) addrlen); + GNUNET_break (0); + return NULL; + } + if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); + return NULL; + } + GNUNET_snprintf (rbuf, sizeof (rbuf), (af == AF_INET6) ? "[%s]:%u" : "%s:%u", + buf, port); + return rbuf; +} + + +struct SessionClientCtx +{ + const struct GNUNET_SERVER_Client *client; + struct Session *ret; +}; + +int session_lookup_by_client_it (void *cls, + const GNUNET_HashCode * key, + void *value) +{ + struct SessionClientCtx *sc_ctx = cls; + struct Session *s = value; + + if (s->client == sc_ctx->client) + { + sc_ctx->ret = s; + return GNUNET_NO; + } + return GNUNET_YES; +} + +/** + * Find the session handle for the given client. + * + * @param plugin the plugin + * @param client which client to find the session handle for + * @return NULL if no matching session exists + */ +static struct Session * +lookup_session_by_client (struct Plugin *plugin, + const struct GNUNET_SERVER_Client *client) +{ + struct SessionClientCtx sc_ctx; + sc_ctx.client = client; + sc_ctx.ret = NULL; + + GNUNET_CONTAINER_multihashmap_iterate (plugin->sessionmap, &session_lookup_by_client_it, &sc_ctx); + + return sc_ctx.ret; +} + + +/** + * Create a new session. Also queues a welcome message. + * + * @param plugin the plugin + * @param target peer to connect to + * @param client client to use + * @param is_nat this a NAT session, we should wait for a client to + * connect to us from an address, then assign that to + * the session + * @return new session object + */ +static struct Session * +create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, + struct GNUNET_SERVER_Client *client, int is_nat) +{ + struct Session *ret; + struct PendingMessage *pm; + struct WelcomeMessage welcome; + + if (is_nat != GNUNET_YES) + GNUNET_assert (client != NULL); + else + GNUNET_assert (client == NULL); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Creating new session for peer `%4s'\n", + GNUNET_i2s (target)); + + ret = GNUNET_malloc (sizeof (struct Session)); + ret->last_activity = GNUNET_TIME_absolute_get (); + ret->plugin = plugin; + ret->is_nat = is_nat; + ret->client = client; + ret->target = *target; + ret->expecting_welcome = GNUNET_YES; + ret->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED); + pm = GNUNET_malloc (sizeof (struct PendingMessage) + + sizeof (struct WelcomeMessage)); + pm->msg = (const char *) &pm[1]; + pm->message_size = sizeof (struct WelcomeMessage); + welcome.header.size = htons (sizeof (struct WelcomeMessage)); + welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME); + welcome.clientIdentity = *plugin->env->my_identity; + memcpy (&pm[1], &welcome, sizeof (welcome)); + pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# bytes currently in TCP buffers"), + pm->message_size, GNUNET_NO); + GNUNET_CONTAINER_DLL_insert (ret->pending_messages_head, + ret->pending_messages_tail, pm); + if (is_nat != GNUNET_YES) + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# TCP sessions active"), 1, + GNUNET_NO); + return ret; +} + + +/** + * If we have pending messages, ask the server to + * transmit them (schedule the respective tasks, etc.) + * + * @param session for which session should we do this + */ +static void +process_pending_messages (struct Session *session); + + +/** + * Function called to notify a client about the socket + * being ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +do_transmit (void *cls, size_t size, void *buf) +{ + struct Session *session = cls; + struct GNUNET_PeerIdentity pid; + struct Plugin *plugin; + struct PendingMessage *pos; + struct PendingMessage *hd; + struct PendingMessage *tl; + struct GNUNET_TIME_Absolute now; + char *cbuf; + size_t ret; + + GNUNET_assert (session != NULL); + session->transmit_handle = NULL; + plugin = session->plugin; + if (buf == NULL) + { +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Timeout trying to transmit to peer `%4s', discarding message queue.\n", + GNUNET_i2s (&session->target)); +#endif + /* timeout; cancel all messages that have already expired */ + hd = NULL; + tl = NULL; + ret = 0; + now = GNUNET_TIME_absolute_get (); + while ((NULL != (pos = session->pending_messages_head)) && + (pos->timeout.abs_value <= now.abs_value)) + { + GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, + session->pending_messages_tail, pos); +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Failed to transmit %u byte message to `%4s'.\n", + pos->message_size, GNUNET_i2s (&session->target)); +#endif + ret += pos->message_size; + GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos); + } + /* do this call before callbacks (so that if callbacks destroy + * session, they have a chance to cancel actions done by this + * call) */ + process_pending_messages (session); + pid = session->target; + /* no do callbacks and do not use session again since + * the callbacks may abort the session */ + while (NULL != (pos = hd)) + { + GNUNET_CONTAINER_DLL_remove (hd, tl, pos); + if (pos->transmit_cont != NULL) + pos->transmit_cont (pos->transmit_cont_cls, &pid, GNUNET_SYSERR); + GNUNET_free (pos); + } + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# bytes currently in TCP buffers"), + -(int64_t) ret, GNUNET_NO); + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop + ("# bytes discarded by TCP (timeout)"), ret, + GNUNET_NO); + return 0; + } + /* copy all pending messages that would fit */ + ret = 0; + cbuf = buf; + hd = NULL; + tl = NULL; + while (NULL != (pos = session->pending_messages_head)) + { + if (ret + pos->message_size > size) + break; + GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, + session->pending_messages_tail, pos); + GNUNET_assert (size >= pos->message_size); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Transmitting message of type %u\n", + ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type)); + /* FIXME: this memcpy can be up to 7% of our total runtime */ + memcpy (cbuf, pos->msg, pos->message_size); + cbuf += pos->message_size; + ret += pos->message_size; + size -= pos->message_size; + GNUNET_CONTAINER_DLL_insert_tail (hd, tl, pos); + } + /* schedule 'continuation' before callbacks so that callbacks that + * cancel everything don't cause us to use a session that no longer + * exists... */ + process_pending_messages (session); + session->last_activity = GNUNET_TIME_absolute_get (); + pid = session->target; + /* we'll now call callbacks that may cancel the session; hence + * we should not use 'session' after this point */ + while (NULL != (pos = hd)) + { + GNUNET_CONTAINER_DLL_remove (hd, tl, pos); + if (pos->transmit_cont != NULL) + pos->transmit_cont (pos->transmit_cont_cls, &pid, GNUNET_OK); + GNUNET_free (pos); + } + GNUNET_assert (hd == NULL); + GNUNET_assert (tl == NULL); +#if DEBUG_TCP > 1 + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Transmitting %u bytes\n", + ret); +#endif + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# bytes currently in TCP buffers"), + -(int64_t) ret, GNUNET_NO); + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# bytes transmitted via TCP"), ret, + GNUNET_NO); + return ret; +} + + +/** + * If we have pending messages, ask the server to + * transmit them (schedule the respective tasks, etc.) + * + * @param session for which session should we do this + */ +static void +process_pending_messages (struct Session *session) +{ + struct PendingMessage *pm; + + GNUNET_assert (session->client != NULL); + if (session->transmit_handle != NULL) + return; + if (NULL == (pm = session->pending_messages_head)) + return; + + session->transmit_handle = + GNUNET_SERVER_notify_transmit_ready (session->client, pm->message_size, + GNUNET_TIME_absolute_get_remaining + (pm->timeout), &do_transmit, + session); +} + + +/** + * Functions with this signature are called whenever we need + * to close a session due to a disconnect or failure to + * establish a connection. + * + * @param session session to close down + */ +static void +disconnect_session (struct Session *session) +{ + struct PendingMessage *pm; + struct Plugin * plugin = session->plugin; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Disconnecting session %p for peer `%s' address `%s'\n", + session, + GNUNET_i2s (&session->target), + tcp_address_to_string(NULL, session->addr, session->addrlen)); + + GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(plugin->sessionmap, &session->target.hashPubKey, session)); + + /* clean up state */ + if (session->transmit_handle != NULL) + { + GNUNET_CONNECTION_notify_transmit_ready_cancel (session->transmit_handle); + session->transmit_handle = NULL; + } + session->plugin->env->session_end (session->plugin->env->cls, + &session->target, session); + while (NULL != (pm = session->pending_messages_head)) + { +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + pm->transmit_cont != + NULL ? "Could not deliver message to `%4s'.\n" : + "Could not deliver message to `%4s', notifying.\n", + GNUNET_i2s (&session->target)); +#endif + GNUNET_STATISTICS_update (session->plugin->env->stats, + gettext_noop ("# bytes currently in TCP buffers"), + -(int64_t) pm->message_size, GNUNET_NO); + GNUNET_STATISTICS_update (session->plugin->env->stats, + gettext_noop + ("# bytes discarded by TCP (disconnect)"), + pm->message_size, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, + session->pending_messages_tail, pm); + if (NULL != pm->transmit_cont) + pm->transmit_cont (pm->transmit_cont_cls, &session->target, + GNUNET_SYSERR); + GNUNET_free (pm); + } + GNUNET_break (session->client != NULL); + if (session->receive_delay_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (session->receive_delay_task); + if (session->client != NULL) + GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR); + } + if (session->client != NULL) + { + GNUNET_SERVER_client_drop (session->client); + session->client = NULL; + } + GNUNET_STATISTICS_update (session->plugin->env->stats, + gettext_noop ("# TCP sessions active"), -1, + GNUNET_NO); + GNUNET_free_non_null (session->addr); + GNUNET_assert (NULL == session->transmit_handle); + GNUNET_free (session); +} + + +/** + * Function that can be used by the transport service to transmit + * a message using the plugin. Note that in the case of a + * peer disconnecting, the continuation MUST be called + * prior to the disconnect notification itself. This function + * will be called with this peer's HELLO message to initiate + * a fresh connection to another peer. + * + * @param cls closure + * @param session which session must be used + * @param msgbuf the message to transmit + * @param msgbuf_size number of bytes in 'msgbuf' + * @param priority how important is the message (most plugins will + * ignore message priority and just FIFO) + * @param to how long to wait at most for the transmission (does not + * require plugins to discard the message after the timeout, + * just advisory for the desired delay; most plugins will ignore + * this as well) + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...); can be NULL + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV) + */ +static ssize_t +tcp_plugin_send (void *cls, + struct Session *session, + const char *msgbuf, size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative to, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct Plugin * plugin = cls; + struct PendingMessage *pm; + + GNUNET_assert (plugin != NULL); + GNUNET_assert (session != NULL); + GNUNET_assert (session->client != NULL); + + GNUNET_SERVER_client_set_timeout (session->client, + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# bytes currently in TCP buffers"), + msgbuf_size, GNUNET_NO); + /* create new message entry */ + pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); + pm->msg = (const char *) &pm[1]; + memcpy (&pm[1], msgbuf, msgbuf_size); + pm->message_size = msgbuf_size; + pm->timeout = GNUNET_TIME_relative_to_absolute (to); + pm->transmit_cont = cont; + pm->transmit_cont_cls = cont_cls; + + /* append pm to pending_messages list */ + GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, + session->pending_messages_tail, pm); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Asked to transmit %u bytes to `%s', added message to list.\n", + msgbuf_size, GNUNET_i2s (&session->target)); + + process_pending_messages (session); + return msgbuf_size; +} + +struct SessionItCtx +{ + void * addr; + size_t addrlen; + struct Session * result; +}; + +int session_lookup_it (void *cls, + const GNUNET_HashCode * key, + void *value) +{ + struct SessionItCtx * si_ctx = cls; + struct Session * session = value; +#if 0 + char * a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen)); + char * a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen)); + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + "Comparing: %s %u <-> %s %u\n", + a1, + session->addrlen, + a2, + si_ctx->addrlen); + GNUNET_free (a1); + GNUNET_free (a2); +#endif + if (session->addrlen != si_ctx->addrlen) + { + return GNUNET_YES; + } + if (0 != memcmp (session->addr, si_ctx->addr, si_ctx->addrlen)) + { + return GNUNET_YES; + } +#if 0 + a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen)); + a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen)); + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + "Comparing: %s %u <-> %s %u , OK!\n", + a1, + session->addrlen, + a2, + si_ctx->addrlen); + GNUNET_free (a1); + GNUNET_free (a2); +#endif + /* Found existing session */ + si_ctx->result = session; + return GNUNET_NO; +} + + +/** + * Create a new session to transmit data to the target + * This session will used to send data to this peer and the plugin will + * notify us by calling the env->session_end function + * + * @param cls closure + * @param address pointer to the GNUNET_HELLO_Address + * @return the session if the address is valid, NULL otherwise + */ +static struct Session * +tcp_plugin_get_session (void *cls, + const struct GNUNET_HELLO_Address *address) +{ + struct Plugin * plugin = cls; + struct Session * session = NULL; + + int af; + const void *sb; + size_t sbs; + struct GNUNET_CONNECTION_Handle *sa; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4TcpAddress *t4; + const struct IPv6TcpAddress *t6; + struct GNUNET_ATS_Information ats; + unsigned int is_natd = GNUNET_NO; + size_t addrlen = 0; + + GNUNET_assert (plugin != NULL); + GNUNET_assert (address != NULL); + + addrlen = address->address_length; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Trying to get session for `%s' address length %i\n", + tcp_address_to_string(NULL, address->address, address->address_length), + addrlen); + + /* look for existing session */ + if (GNUNET_CONTAINER_multihashmap_contains(plugin->sessionmap, &address->peer.hashPubKey)) + { + struct SessionItCtx si_ctx; + + si_ctx.addr = (void *) address->address; + si_ctx.addrlen = address->address_length; + + si_ctx.result = NULL; + + GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessionmap, &address->peer.hashPubKey, &session_lookup_it, &si_ctx); + if (si_ctx.result != NULL) + { + session = si_ctx.result; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Found exisiting session for `%s' address `%s' session %p\n", + GNUNET_i2s (&address->peer), + tcp_address_to_string(NULL, address->address, address->address_length), + session); + return session; + } + } + + if (addrlen == sizeof (struct IPv6TcpAddress)) + { + GNUNET_assert (NULL != address->address); /* make static analysis happy */ + t6 = address->address; + af = AF_INET6; + memset (&a6, 0, sizeof (a6)); +#if HAVE_SOCKADDR_IN_SIN_LEN + a6.sin6_len = sizeof (a6); +#endif + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->t6_port; + if (t6->t6_port == 0) + is_natd = GNUNET_YES; + memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr)); + sb = &a6; + sbs = sizeof (a6); + } + else if (addrlen == sizeof (struct IPv4TcpAddress)) + { + GNUNET_assert (NULL != address->address); /* make static analysis happy */ + t4 = address->address; + af = AF_INET; + memset (&a4, 0, sizeof (a4)); +#if HAVE_SOCKADDR_IN_SIN_LEN + a4.sin_len = sizeof (a4); +#endif + a4.sin_family = AF_INET; + a4.sin_port = t4->t4_port; + if (t4->t4_port == 0) + is_natd = GNUNET_YES; + a4.sin_addr.s_addr = t4->ipv4_addr; + sb = &a4; + sbs = sizeof (a4); + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + _("Address of unexpected length: %u\n"), addrlen); + GNUNET_break (0); + return NULL; + } + + ats = plugin->env->get_address_type (plugin->env->cls, sb ,sbs); + + if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress))) + { + /* NAT client only works with IPv4 addresses */ + return NULL; + } + + if (0 == plugin->max_connections) + { + /* saturated */ + return NULL; + } + + if ((is_natd == GNUNET_YES) && + (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, + &address->peer.hashPubKey))) + { + /* Only do one NAT punch attempt per peer identity */ + return NULL; + } + + if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) && + (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, + &address->peer.hashPubKey))) + { +#if DEBUG_TCP_NAT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + _("Found valid IPv4 NAT address (creating session)!\n")); +#endif + session = create_session (plugin, &address->peer, NULL, GNUNET_YES); + session->addrlen = 0; + session->addr = NULL; + session->ats_address_network_type = ats.value; + GNUNET_assert (session != NULL); + + GNUNET_assert (GNUNET_CONTAINER_multihashmap_put + (plugin->nat_wait_conns, &address->peer.hashPubKey, session, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == GNUNET_OK); +#if DEBUG_TCP_NAT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Created NAT WAIT connection to `%4s' at `%s'\n", + GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs)); +#endif + GNUNET_NAT_run_client (plugin->nat, &a4); + return session; + } + + /* create new outbound session */ + GNUNET_assert (0 != plugin->max_connections); + sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs); + if (sa == NULL) + { +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Failed to create connection to `%4s' at `%s'\n", + GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs)); +#endif + return NULL; + } + plugin->max_connections--; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Asked to transmit to `%4s', creating fresh session using address `%s'.\n", + GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs)); + + session = create_session (plugin, + &address->peer, + GNUNET_SERVER_connect_socket (plugin->server, sa), + GNUNET_NO); + session->addr = GNUNET_malloc (addrlen); + memcpy (session->addr, address->address, addrlen); + session->addrlen = addrlen; + session->ats_address_network_type = ats.value; + + GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &address->peer.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Creating new session for `%s' address `%s' session %p\n", + GNUNET_i2s (&address->peer), + tcp_address_to_string(NULL, address->address, address->address_length), + session); + + /* Send TCP Welcome */ + process_pending_messages (session); + + return session; +} + + +int session_disconnect_it (void *cls, + const GNUNET_HashCode * key, + void *value) +{ + struct Session *session = value; + + GNUNET_STATISTICS_update (session->plugin->env->stats, + gettext_noop + ("# transport-service disconnect requests for TCP"), + 1, GNUNET_NO); + disconnect_session (session); + return GNUNET_YES; +} + +int session_nat_disconnect_it (void *cls, + const GNUNET_HashCode * key, + void *value) +{ + struct Session *session = value; + + if (session != NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Cleaning up pending NAT session for peer `%4s'\n", GNUNET_i2s (&session->target)); + GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (session->plugin->nat_wait_conns, &session->target.hashPubKey, session)); + GNUNET_SERVER_client_drop (session->client); + GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR); + GNUNET_free (session); + } + + return GNUNET_YES; +} + + +/** + * Function that can be called to force a disconnect from the + * specified neighbour. This should also cancel all previously + * scheduled transmissions. Obviously the transmission may have been + * partially completed already, which is OK. The plugin is supposed + * to close the connection (if applicable) and no longer call the + * transmit continuation(s). + * + * Finally, plugin MUST NOT call the services's receive function to + * notify the service that the connection to the specified target was + * closed after a getting this call. + * + * @param cls closure + * @param target peer for which the last transmission is + * to be cancelled + */ +static void +tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +{ + struct Plugin *plugin = cls; + struct Session *nat_session = NULL; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Disconnecting peer `%4s'\n", GNUNET_i2s (target)); + + GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessionmap, &target->hashPubKey, session_disconnect_it, plugin); + + nat_session = GNUNET_CONTAINER_multihashmap_get(plugin->nat_wait_conns, &target->hashPubKey); + if (nat_session != NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Cleaning up pending NAT session for peer `%4s'\n", GNUNET_i2s (target)); + GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (plugin->nat_wait_conns, &target->hashPubKey, nat_session)); + GNUNET_SERVER_client_drop (nat_session->client); + GNUNET_SERVER_receive_done (nat_session->client, GNUNET_SYSERR); + GNUNET_free (nat_session); + } +} + + +/** + * Context for address to string conversion. + */ +struct PrettyPrinterContext +{ + /** + * Function to call with the result. + */ + GNUNET_TRANSPORT_AddressStringCallback asc; + + /** + * Clsoure for 'asc'. + */ + void *asc_cls; + + /** + * Port to add after the IP address. + */ + uint16_t port; +}; + + +/** + * Append our port and forward the result. + * + * @param cls the 'struct PrettyPrinterContext*' + * @param hostname hostname part of the address + */ +static void +append_port (void *cls, const char *hostname) +{ + struct PrettyPrinterContext *ppc = cls; + char *ret; + + if (hostname == NULL) + { + ppc->asc (ppc->asc_cls, NULL); + GNUNET_free (ppc); + return; + } + GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port); + ppc->asc (ppc->asc_cls, ret); + GNUNET_free (ret); +} + + +/** + * Convert the transports address to a nice, human-readable + * format. + * + * @param cls closure + * @param type name of the transport that generated the address + * @param addr one of the addresses of the host, NULL for the last address + * the specific address format depends on the transport + * @param addrlen length of the address + * @param numeric should (IP) addresses be displayed in numeric form? + * @param timeout after how long should we give up? + * @param asc function to call on each string + * @param asc_cls closure for asc + */ +static void +tcp_plugin_address_pretty_printer (void *cls, const char *type, + const void *addr, size_t addrlen, + int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressStringCallback asc, + void *asc_cls) +{ + struct PrettyPrinterContext *ppc; + const void *sb; + size_t sbs; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4TcpAddress *t4; + const struct IPv6TcpAddress *t6; + uint16_t port; + + if (addrlen == sizeof (struct IPv6TcpAddress)) + { + t6 = addr; + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->t6_port; + memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr)); + port = ntohs (t6->t6_port); + sb = &a6; + sbs = sizeof (a6); + } + else if (addrlen == sizeof (struct IPv4TcpAddress)) + { + t4 = addr; + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; + a4.sin_port = t4->t4_port; + a4.sin_addr.s_addr = t4->ipv4_addr; + port = ntohs (t4->t4_port); + sb = &a4; + sbs = sizeof (a4); + } + else + { + /* invalid address */ + GNUNET_break_op (0); + asc (asc_cls, NULL); + return; + } + ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); + ppc->asc = asc; + ppc->asc_cls = asc_cls; + ppc->port = port; + GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); +} + + +/** + * Check if the given port is plausible (must be either our listen + * port or our advertised port), or any port if we are behind NAT + * and do not have a port open. If it is neither, we return + * GNUNET_SYSERR. + * + * @param plugin global variables + * @param in_port port number to check + * @return GNUNET_OK if port is either open_port or adv_port + */ +static int +check_port (struct Plugin *plugin, uint16_t in_port) +{ + if ((in_port == plugin->adv_port) || (in_port == plugin->open_port)) + return GNUNET_OK; + return GNUNET_SYSERR; +} + + +/** + * Function that will be called to check if a binary address for this + * plugin is well-formed and corresponds to an address for THIS peer + * (as per our configuration). Naturally, if absolutely necessary, + * plugins can be a bit conservative in their answer, but in general + * plugins should make sure that the address does not redirect + * traffic to a 3rd party that might try to man-in-the-middle our + * traffic. + * + * @param cls closure, our 'struct Plugin*' + * @param addr pointer to the address + * @param addrlen length of addr + * @return GNUNET_OK if this is a plausible address for this peer + * and transport, GNUNET_SYSERR if not + */ +static int +tcp_plugin_check_address (void *cls, const void *addr, size_t addrlen) +{ + struct Plugin *plugin = cls; + struct IPv4TcpAddress *v4; + struct IPv6TcpAddress *v6; + + if ((addrlen != sizeof (struct IPv4TcpAddress)) && + (addrlen != sizeof (struct IPv6TcpAddress))) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (addrlen == sizeof (struct IPv4TcpAddress)) + { + v4 = (struct IPv4TcpAddress *) addr; + if (GNUNET_OK != check_port (plugin, ntohs (v4->t4_port))) + return GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_NAT_test_address (plugin->nat, &v4->ipv4_addr, + sizeof (struct in_addr))) + return GNUNET_SYSERR; + } + else + { + v6 = (struct IPv6TcpAddress *) addr; + if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != check_port (plugin, ntohs (v6->t6_port))) + return GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_NAT_test_address (plugin->nat, &v6->ipv6_addr, + sizeof (struct in6_addr))) + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * We've received a nat probe from this peer via TCP. Finish + * creating the client session and resume sending of queued + * messages. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_tcp_nat_probe (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct Plugin *plugin = cls; + struct Session *session; + const struct TCP_NAT_ProbeMessage *tcp_nat_probe; + size_t alen; + void *vaddr; + struct IPv4TcpAddress *t4; + struct IPv6TcpAddress *t6; + const struct sockaddr_in *s4; + const struct sockaddr_in6 *s6; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "received NAT probe\n"); + + /* We have received a TCP NAT probe, meaning we (hopefully) initiated + * a connection to this peer by running gnunet-nat-client. This peer + * received the punch message and now wants us to use the new connection + * as the default for that peer. Do so and then send a WELCOME message + * so we can really be connected! + */ + if (ntohs (message->size) != sizeof (struct TCP_NAT_ProbeMessage)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message; + if (0 == + memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { + /* refuse connections from ourselves */ + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + session = + GNUNET_CONTAINER_multihashmap_get (plugin->nat_wait_conns, + &tcp_nat_probe-> + clientIdentity.hashPubKey); + if (session == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Did NOT find session for NAT probe!\n"); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Found session for NAT probe!\n"); + + GNUNET_assert (GNUNET_CONTAINER_multihashmap_remove + (plugin->nat_wait_conns, + &tcp_nat_probe->clientIdentity.hashPubKey, + session) == GNUNET_YES); + if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) + { + GNUNET_break (0); + GNUNET_free (session); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + GNUNET_SERVER_client_keep (client); + session->client = client; + session->last_activity = GNUNET_TIME_absolute_get (); + session->inbound = GNUNET_NO; + +#if DEBUG_TCP_NAT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Found address `%s' for incoming connection\n", + GNUNET_a2s (vaddr, alen)); +#endif + switch (((const struct sockaddr *) vaddr)->sa_family) + { + case AF_INET: + s4 = vaddr; + t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); + t4->t4_port = s4->sin_port; + t4->ipv4_addr = s4->sin_addr.s_addr; + session->addr = t4; + session->addrlen = sizeof (struct IPv4TcpAddress); + break; + case AF_INET6: + s6 = vaddr; + t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); + t6->t6_port = s6->sin6_port; + memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); + session->addr = t6; + session->addrlen = sizeof (struct IPv6TcpAddress); + break; + default: + GNUNET_break_op (0); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Bad address for incoming connection!\n"); + GNUNET_free (vaddr); + + GNUNET_SERVER_client_drop (client); + GNUNET_free (session); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_free (vaddr); + + GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &session->target.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# TCP sessions active"), 1, + GNUNET_NO); + process_pending_messages (session); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * We've received a welcome from this peer via TCP. Possibly create a + * fresh client record and send back our welcome. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct Plugin *plugin = cls; + const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message; + struct Session *session; + size_t alen; + void *vaddr; + struct IPv4TcpAddress *t4; + struct IPv6TcpAddress *t6; + const struct sockaddr_in *s4; + const struct sockaddr_in6 *s6; + + if (0 == + memcmp (&wm->clientIdentity, plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { + /* refuse connections from ourselves */ + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Received %s message from `%4s'\n", "WELCOME", + GNUNET_i2s (&wm->clientIdentity)); + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# TCP WELCOME messages received"), 1, + GNUNET_NO); + + session = lookup_session_by_client (plugin, client); + if (session != NULL) + { + if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Found existing session %p for peer `%s'\n", + session, + GNUNET_a2s (vaddr, alen)); + GNUNET_free (vaddr); + } + } + else + { + GNUNET_SERVER_client_keep (client); + session = create_session (plugin, &wm->clientIdentity, client, GNUNET_NO); + session->inbound = GNUNET_YES; + + if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) + { + if (alen == sizeof (struct sockaddr_in)) + { + s4 = vaddr; + t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); + t4->t4_port = s4->sin_port; + t4->ipv4_addr = s4->sin_addr.s_addr; + session->addr = t4; + session->addrlen = sizeof (struct IPv4TcpAddress); + } + else if (alen == sizeof (struct sockaddr_in6)) + { + s6 = vaddr; + t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); + t6->t6_port = s6->sin6_port; + memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); + session->addr = t6; + session->addrlen = sizeof (struct IPv6TcpAddress); + } + + struct GNUNET_ATS_Information ats; + ats = plugin->env->get_address_type (plugin->env->cls, vaddr ,alen); + session->ats_address_network_type = ats.value; + + GNUNET_free (vaddr); + } + else + { +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Did not obtain TCP socket address for incoming connection\n"); +#endif + } + GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &wm->clientIdentity.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + } + + if (session->expecting_welcome != GNUNET_YES) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + session->last_activity = GNUNET_TIME_absolute_get (); + session->expecting_welcome = GNUNET_NO; + + + process_pending_messages (session); + + GNUNET_SERVER_client_set_timeout (client, + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Task to signal the server that we can continue + * receiving from the TCP client now. + * + * @param cls the 'struct Session*' + * @param tc task context (unused) + */ +static void +delayed_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Session *session = cls; + struct GNUNET_TIME_Relative delay; + struct GNUNET_ATS_Information ats; + + session->receive_delay_task = GNUNET_SCHEDULER_NO_TASK; + delay = + session->plugin->env->receive (session->plugin->env->cls, + &session->target, NULL, &ats, 0, session, + NULL, 0); + if (delay.rel_value == 0) + GNUNET_SERVER_receive_done (session->client, GNUNET_OK); + else + session->receive_delay_task = + GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session); +} + + +/** + * We've received data for this peer via TCP. Unbox, + * compute latency and forward. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_tcp_data (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct Plugin *plugin = cls; + struct Session *session; + struct GNUNET_TIME_Relative delay; + uint16_t type; + + type = ntohs (message->type); + if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) || + (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type)) + { + /* We don't want to propagate WELCOME and NAT Probe messages up! */ + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + session = lookup_session_by_client (plugin, client); + if (NULL == session) + { + /* No inbound session found */ + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + else if (GNUNET_YES == session->expecting_welcome) + { + /* Session is expecting WELCOME message */ + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + session->last_activity = GNUNET_TIME_absolute_get (); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Passing %u bytes of type %u from `%4s' to transport service.\n", + (unsigned int) ntohs (message->size), + (unsigned int) ntohs (message->type), + GNUNET_i2s (&session->target)); + + GNUNET_STATISTICS_update (plugin->env->stats, + gettext_noop ("# bytes received via TCP"), + ntohs (message->size), GNUNET_NO); + struct GNUNET_ATS_Information distance[2]; + + distance[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); + distance[0].value = htonl (1); + distance[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); + distance[1].value = session->ats_address_network_type; + GNUNET_break (ntohl(session->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED); + + delay = plugin->env->receive (plugin->env->cls, + &session->target, + message, + (const struct GNUNET_ATS_Information *) &distance, + 1, session, + (GNUNET_YES == session->inbound) ? NULL : session->addr, + (GNUNET_YES == session->inbound) ? 0 : session->addrlen); + if (delay.rel_value == 0) + { + GNUNET_SERVER_receive_done (client, GNUNET_OK); + } + else + { +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Throttling receiving from `%s' for %llu ms\n", + GNUNET_i2s (&session->target), + (unsigned long long) delay.rel_value); +#endif + GNUNET_SERVER_disable_receive_done_warning (client); + session->receive_delay_task = + GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session); + } +} + + +/** + * Functions with this signature are called whenever a peer + * is disconnected on the network level. + * + * @param cls closure + * @param client identification of the client + */ +static void +disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct Plugin *plugin = cls; + struct Session *session; + + if (client == NULL) + return; + plugin->max_connections++; + session = lookup_session_by_client (plugin, client); + if (session == NULL) + return; /* unknown, nothing to do */ +#if DEBUG_TCP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + "Destroying session of `%4s' with %s due to network-level disconnect.\n", + GNUNET_i2s (&session->target), + (session->addr != + NULL) ? tcp_address_to_string (session->plugin, + session->addr, + session->addrlen) : + "*"); +#endif + GNUNET_STATISTICS_update (session->plugin->env->stats, + gettext_noop + ("# network-level TCP disconnect events"), 1, + GNUNET_NO); + disconnect_session (session); +} + + +/** + * We can now send a probe message, copy into buffer to really send. + * + * @param cls closure, a struct TCPProbeContext + * @param size max size to copy + * @param buf buffer to copy message to + * @return number of bytes copied into buf + */ +static size_t +notify_send_probe (void *cls, size_t size, void *buf) +{ + struct TCPProbeContext *tcp_probe_ctx = cls; + struct Plugin *plugin = tcp_probe_ctx->plugin; + size_t ret; + + tcp_probe_ctx->transmit_handle = NULL; + GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail, + tcp_probe_ctx); + if (buf == NULL) + { + GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock, GNUNET_NO); + GNUNET_free (tcp_probe_ctx); + return 0; + } + GNUNET_assert (size >= sizeof (tcp_probe_ctx->message)); + memcpy (buf, &tcp_probe_ctx->message, sizeof (tcp_probe_ctx->message)); + GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server, + tcp_probe_ctx->sock); + ret = sizeof (tcp_probe_ctx->message); + GNUNET_free (tcp_probe_ctx); + return ret; +} + + +/** + * Function called by the NAT subsystem suggesting another peer wants + * to connect to us via connection reversal. Try to connect back to the + * given IP. + * + * @param cls closure + * @param addr address to try + * @param addrlen number of bytes in addr + */ +static void +try_connection_reversal (void *cls, const struct sockaddr *addr, + socklen_t addrlen) +{ + struct Plugin *plugin = cls; + struct GNUNET_CONNECTION_Handle *sock; + struct TCPProbeContext *tcp_probe_ctx; + + /** + * We have received an ICMP response, ostensibly from a peer + * that wants to connect to us! Send a message to establish a connection. + */ + sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen); + if (sock == NULL) + { + /* failed for some odd reason (out of sockets?); ignore attempt */ + return; + } + + /* FIXME: do we need to track these probe context objects so that + * we can clean them up on plugin unload? */ + tcp_probe_ctx = GNUNET_malloc (sizeof (struct TCPProbeContext)); + tcp_probe_ctx->message.header.size = + htons (sizeof (struct TCP_NAT_ProbeMessage)); + tcp_probe_ctx->message.header.type = + htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE); + memcpy (&tcp_probe_ctx->message.clientIdentity, plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity)); + tcp_probe_ctx->plugin = plugin; + tcp_probe_ctx->sock = sock; + GNUNET_CONTAINER_DLL_insert (plugin->probe_head, plugin->probe_tail, + tcp_probe_ctx); + tcp_probe_ctx->transmit_handle = + GNUNET_CONNECTION_notify_transmit_ready (sock, + ntohs (tcp_probe_ctx-> + message.header.size), + GNUNET_TIME_UNIT_FOREVER_REL, + ¬ify_send_probe, + tcp_probe_ctx); + +} + + +/** + * Entry point for the plugin. + * + * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*' + * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error + */ +void * +libgnunet_plugin_transport_tcp_init (void *cls) +{ + static const struct GNUNET_SERVER_MessageHandler my_handlers[] = { + {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME, + sizeof (struct WelcomeMessage)}, + {&handle_tcp_nat_probe, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE, + sizeof (struct TCP_NAT_ProbeMessage)}, + {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0}, + {NULL, NULL, 0, 0} + }; + struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; + struct GNUNET_TRANSPORT_PluginFunctions *api; + struct Plugin *plugin; + struct GNUNET_SERVICE_Context *service; + unsigned long long aport; + unsigned long long bport; + unsigned long long max_connections; + unsigned int i; + struct GNUNET_TIME_Relative idle_timeout; + int ret; + struct sockaddr **addrs; + socklen_t *addrlens; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", + "MAX_CONNECTIONS", + &max_connections)) + max_connections = 128; + + aport = 0; + if ((GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", "PORT", + &bport)) || (bport > 65535) || + ((GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", + "ADVERTISED-PORT", &aport)) && + (aport > 65535))) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + _ + ("Require valid port number for service `%s' in configuration!\n"), + "transport-tcp"); + return NULL; + } + if (aport == 0) + aport = bport; + if (bport == 0) + aport = 0; + if (bport != 0) + { + service = GNUNET_SERVICE_start ("transport-tcp", env->cfg); + if (service == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "tcp", + _("Failed to start service.\n")); + return NULL; + } + } + else + service = NULL; + + + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->sessionmap = GNUNET_CONTAINER_multihashmap_create(max_connections); + plugin->max_connections = max_connections; + plugin->open_port = bport; + plugin->adv_port = aport; + plugin->env = env; + plugin->lsock = NULL; + if ((service != NULL) && + (GNUNET_SYSERR != + (ret = + GNUNET_SERVICE_get_server_addresses ("transport-tcp", env->cfg, &addrs, + &addrlens)))) + { + plugin->nat = + GNUNET_NAT_register (env->cfg, GNUNET_YES, aport, (unsigned int) ret, + (const struct sockaddr **) addrs, addrlens, + &tcp_nat_port_map_callback, + &try_connection_reversal, plugin); + while (ret > 0) + { + ret--; + GNUNET_assert (addrs[ret] != NULL); + GNUNET_free (addrs[ret]); + } + GNUNET_free_non_null (addrs); + GNUNET_free_non_null (addrlens); + } + else + { + plugin->nat = + GNUNET_NAT_register (env->cfg, GNUNET_YES, 0, 0, NULL, NULL, NULL, + &try_connection_reversal, plugin); + } + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = plugin; + api->send = &tcp_plugin_send; + api->get_session = &tcp_plugin_get_session; + + api->disconnect = &tcp_plugin_disconnect; + api->address_pretty_printer = &tcp_plugin_address_pretty_printer; + api->check_address = &tcp_plugin_check_address; + api->address_to_string = &tcp_address_to_string; + plugin->service = service; + if (service != NULL) + { + plugin->server = GNUNET_SERVICE_get_server (service); + } + else + { + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (env->cfg, "transport-tcp", + "TIMEOUT", &idle_timeout)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp", + _("Failed to find option %s in section %s!\n"), + "TIMEOUT", "transport-tcp"); + if (plugin->nat != NULL) + GNUNET_NAT_unregister (plugin->nat); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; + } + plugin->server = + GNUNET_SERVER_create_with_sockets (&plugin_tcp_access_check, plugin, + NULL, idle_timeout, GNUNET_YES); + } + plugin->handlers = GNUNET_malloc (sizeof (my_handlers)); + memcpy (plugin->handlers, my_handlers, sizeof (my_handlers)); + for (i = 0; + i < sizeof (my_handlers) / sizeof (struct GNUNET_SERVER_MessageHandler); + i++) + plugin->handlers[i].callback_cls = plugin; + GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers); + GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin); + plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create (16); + if (bport != 0) + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp", + _("TCP transport listening on port %llu\n"), bport); + else + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp", + _ + ("TCP transport not listening on any port (client only)\n")); + if (aport != bport) + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp", + _ + ("TCP transport advertises itself as being on port %llu\n"), + aport); + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +libgnunet_plugin_transport_tcp_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + struct TCPProbeContext *tcp_probe; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Shutting down TCP plugin\n"); + + + /* Removing leftover sessions */ + GNUNET_CONTAINER_multihashmap_iterate(plugin->sessionmap, &session_disconnect_it, NULL); + /* Removing leftover NAT sessions */ + GNUNET_CONTAINER_multihashmap_iterate(plugin->nat_wait_conns, &session_nat_disconnect_it, NULL); + + if (plugin->service != NULL) + GNUNET_SERVICE_stop (plugin->service); + else + GNUNET_SERVER_destroy (plugin->server); + GNUNET_free (plugin->handlers); + if (plugin->nat != NULL) + GNUNET_NAT_unregister (plugin->nat); + while (NULL != (tcp_probe = plugin->probe_head)) + { + GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail, + tcp_probe); + GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO); + GNUNET_free (tcp_probe); + } + GNUNET_CONTAINER_multihashmap_destroy (plugin->nat_wait_conns); + GNUNET_CONTAINER_multihashmap_destroy (plugin->sessionmap); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + +/* end of plugin_transport_tcp.c */ diff --git a/src/transport/plugin_transport_template.c b/src/transport/plugin_transport_template.c new file mode 100644 index 0000000..d307262 --- /dev/null +++ b/src/transport/plugin_transport_template.c @@ -0,0 +1,299 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_template.c + * @brief template for a new transport service + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_protocols.h" +#include "gnunet_connection_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_service_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" + +#define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING + +/** + * After how long do we expire an address that we + * learned from another peer if it is not reconfirmed + * by anyone? + */ +#define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) + + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin; + + +/** + * Session handle for connections. + */ +struct Session +{ + + /** + * Stored in a linked list. + */ + struct Session *next; + + /** + * Pointer to the global plugin struct. + */ + struct Plugin *plugin; + + /** + * The client (used to identify this connection) + */ + /* void *client; */ + + /** + * Continuation function to call once the transmission buffer + * has again space available. NULL if there is no + * continuation to call. + */ + GNUNET_TRANSPORT_TransmitContinuation transmit_cont; + + /** + * Closure for transmit_cont. + */ + void *transmit_cont_cls; + + /** + * To whom are we talking to (set to our identity + * if we are still waiting for the welcome message) + */ + struct GNUNET_PeerIdentity sender; + + /** + * At what time did we reset last_received last? + */ + struct GNUNET_TIME_Absolute last_quota_update; + + /** + * How many bytes have we received since the "last_quota_update" + * timestamp? + */ + uint64_t last_received; + + /** + * Number of bytes per ms that this peer is allowed + * to send to us. + */ + uint32_t quota; + +}; + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin +{ + /** + * Our environment. + */ + struct GNUNET_TRANSPORT_PluginEnvironment *env; + + /** + * List of open sessions. + */ + struct Session *sessions; + +}; + + +/** + * Function that can be used by the transport service to transmit + * a message using the plugin. Note that in the case of a + * peer disconnecting, the continuation MUST be called + * prior to the disconnect notification itself. This function + * will be called with this peer's HELLO message to initiate + * a fresh connection to another peer. + * + * @param cls closure + * @param session which session must be used + * @param msgbuf the message to transmit + * @param msgbuf_size number of bytes in 'msgbuf' + * @param priority how important is the message (most plugins will + * ignore message priority and just FIFO) + * @param to how long to wait at most for the transmission (does not + * require plugins to discard the message after the timeout, + * just advisory for the desired delay; most plugins will ignore + * this as well) + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...); can be NULL + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV) + */ +static ssize_t +template_plugin_send (void *cls, + struct Session *session, + const char *msgbuf, size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative to, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct Plugin *plugin = cls; + int bytes_sent = 0; + + GNUNET_assert (plugin != NULL); + GNUNET_assert (session != NULL); + + /* struct Plugin *plugin = cls; */ + return bytes_sent; +} + + + +/** + * Function that can be used to force the plugin to disconnect + * from the given peer and cancel all previous transmissions + * (and their continuationc). + * + * @param cls closure + * @param target peer from which to disconnect + */ +static void +template_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +{ + // struct Plugin *plugin = cls; + // FIXME +} + + +/** + * Convert the transports address to a nice, human-readable + * format. + * + * @param cls closure + * @param type name of the transport that generated the address + * @param addr one of the addresses of the host, NULL for the last address + * the specific address format depends on the transport + * @param addrlen length of the address + * @param numeric should (IP) addresses be displayed in numeric form? + * @param timeout after how long should we give up? + * @param asc function to call on each string + * @param asc_cls closure for asc + */ +static void +template_plugin_address_pretty_printer (void *cls, const char *type, + const void *addr, size_t addrlen, + int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressStringCallback + asc, void *asc_cls) +{ + asc (asc_cls, NULL); +} + + + +/** + * Another peer has suggested an address for this + * peer and transport plugin. Check that this could be a valid + * address. If so, consider adding it to the list + * of addresses. + * + * @param cls closure + * @param addr pointer to the address + * @param addrlen length of addr + * @return GNUNET_OK if this is a plausible address for this peer + * and transport + */ +static int +template_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) +{ + /* struct Plugin *plugin = cls; */ + + /* check if the address is plausible; if so, + * add it to our list! */ + return GNUNET_OK; +} + + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure + * @param addr binary address + * @param addrlen length of the address + * @return string representing the same address + */ +static const char * +template_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) +{ + GNUNET_break (0); + return NULL; +} + + + + +/** + * Entry point for the plugin. + */ +void * +gnunet_plugin_transport_template_init (void *cls) +{ + struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; + struct GNUNET_TRANSPORT_PluginFunctions *api; + struct Plugin *plugin; + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = plugin; + api->send = &template_plugin_send; + api->disconnect = &template_plugin_disconnect; + api->address_pretty_printer = &template_plugin_address_pretty_printer; + api->check_address = &template_plugin_address_suggested; + api->address_to_string = &template_plugin_address_to_string; + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +gnunet_plugin_transport_template_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + +/* end of plugin_transport_template.c */ diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c new file mode 100644 index 0000000..7141563 --- /dev/null +++ b/src/transport/plugin_transport_udp.c @@ -0,0 +1,2297 @@ +/* + This file is part of GNUnet + (C) 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_udp.c + * @brief Implementation of the UDP transport protocol + * @author Christian Grothoff + * @author Nathan Evans + * @author Matthias Wachs + */ +#include "platform.h" +#include "plugin_transport_udp.h" +#include "gnunet_hello_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_fragmentation_lib.h" +#include "gnunet_nat_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_resolver_service.h" +#include "gnunet_signatures.h" +#include "gnunet_constants.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" +#include "transport.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__) + + +/** + * Number of messages we can defragment in parallel. We only really + * defragment 1 message at a time, but if messages get re-ordered, we + * may want to keep knowledge about the previous message to avoid + * discarding the current message in favor of a single fragment of a + * previous message. 3 should be good since we don't expect massive + * message reorderings with UDP. + */ +#define UDP_MAX_MESSAGES_IN_DEFRAG 3 + +/** + * We keep a defragmentation queue per sender address. How many + * sender addresses do we support at the same time? Memory consumption + * is roughly a factor of 32k * UDP_MAX_MESSAGES_IN_DEFRAG times this + * value. (So 128 corresponds to 12 MB and should suffice for + * connecting to roughly 128 peers via UDP). + */ +#define UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG 128 + + + +/** + * Closure for 'append_port'. + */ +struct PrettyPrinterContext +{ + /** + * Function to call with the result. + */ + GNUNET_TRANSPORT_AddressStringCallback asc; + + /** + * Clsoure for 'asc'. + */ + void *asc_cls; + + /** + * Port to add after the IP address. + */ + uint16_t port; +}; + +struct Session +{ + /** + * Which peer is this session for? + */ + struct GNUNET_PeerIdentity target; + + /** + * Address of the other peer + */ + const struct sockaddr *sock_addr; + + size_t addrlen; + + /** + * Desired delay for next sending we send to other peer + */ + struct GNUNET_TIME_Relative flow_delay_for_other_peer; + + /** + * Desired delay for next sending we received from other peer + */ + struct GNUNET_TIME_Absolute flow_delay_from_other_peer; + + /** + * expected delay for ACKs + */ + struct GNUNET_TIME_Relative last_expected_delay; + + + struct GNUNET_ATS_Information ats; + + struct FragmentationContext * frag_ctx; +}; + + +struct SessionCompareContext +{ + struct Session *res; + const struct GNUNET_HELLO_Address *addr; +}; + + +/** + * Closure for 'process_inbound_tokenized_messages' + */ +struct SourceInformation +{ + /** + * Sender identity. + */ + struct GNUNET_PeerIdentity sender; + + /** + * Source address. + */ + const void *arg; + + /** + * Number of bytes in source address. + */ + size_t args; + + struct Session *session; +}; + + +/** + * Closure for 'find_receive_context'. + */ +struct FindReceiveContext +{ + /** + * Where to store the result. + */ + struct DefragContext *rc; + + /** + * Address to find. + */ + const struct sockaddr *addr; + + /** + * Number of bytes in 'addr'. + */ + socklen_t addr_len; + + struct Session *session; +}; + + + +/** + * Data structure to track defragmentation contexts based + * on the source of the UDP traffic. + */ +struct DefragContext +{ + + /** + * Defragmentation context. + */ + struct GNUNET_DEFRAGMENT_Context *defrag; + + /** + * Source address this receive context is for (allocated at the + * end of the struct). + */ + const struct sockaddr *src_addr; + + /** + * Reference to master plugin struct. + */ + struct Plugin *plugin; + + /** + * Node in the defrag heap. + */ + struct GNUNET_CONTAINER_HeapNode *hnode; + + /** + * Length of 'src_addr' + */ + size_t addr_len; +}; + + + +/** + * Closure for 'process_inbound_tokenized_messages' + */ +struct FragmentationContext +{ + struct FragmentationContext * next; + struct FragmentationContext * prev; + + struct Plugin * plugin; + struct GNUNET_FRAGMENT_Context * frag; + struct Session * session; + + struct GNUNET_TIME_Absolute timeout; + + + /** + * Function to call upon completion of the transmission. + */ + GNUNET_TRANSPORT_TransmitContinuation cont; + + /** + * Closure for 'cont'. + */ + void *cont_cls; + + size_t bytes_to_send; +}; + + +struct UDPMessageWrapper +{ + struct Session *session; + struct UDPMessageWrapper *prev; + struct UDPMessageWrapper *next; + char *udp; + size_t msg_size; + + struct GNUNET_TIME_Absolute timeout; + + /** + * Function to call upon completion of the transmission. + */ + GNUNET_TRANSPORT_TransmitContinuation cont; + + /** + * Closure for 'cont'. + */ + void *cont_cls; + + struct FragmentationContext *frag_ctx; + +}; + + +/** + * UDP ACK Message-Packet header (after defragmentation). + */ +struct UDP_ACK_Message +{ + /** + * Message header. + */ + struct GNUNET_MessageHeader header; + + /** + * Desired delay for flow control + */ + uint32_t delay; + + /** + * What is the identity of the sender + */ + struct GNUNET_PeerIdentity sender; + +}; + +/** + * We have been notified that our readset has something to read. We don't + * know which socket needs to be read, so we have to check each one + * Then reschedule this function to be called again once more is available. + * + * @param cls the plugin handle + * @param tc the scheduling context (for rescheduling this function again) + */ +static void +udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * We have been notified that our readset has something to read. We don't + * know which socket needs to be read, so we have to check each one + * Then reschedule this function to be called again once more is available. + * + * @param cls the plugin handle + * @param tc the scheduling context (for rescheduling this function again) + */ +static void +udp_plugin_select_v6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure + * @param addr binary address + * @param addrlen length of the address + * @return string representing the same address + */ +const char * +udp_address_to_string (void *cls, const void *addr, size_t addrlen) +{ + static char rbuf[INET6_ADDRSTRLEN + 10]; + char buf[INET6_ADDRSTRLEN]; + const void *sb; + struct in_addr a4; + struct in6_addr a6; + const struct IPv4UdpAddress *t4; + const struct IPv6UdpAddress *t6; + int af; + uint16_t port; + + if (addrlen == sizeof (struct IPv6UdpAddress)) + { + t6 = addr; + af = AF_INET6; + port = ntohs (t6->u6_port); + memcpy (&a6, &t6->ipv6_addr, sizeof (a6)); + sb = &a6; + } + else if (addrlen == sizeof (struct IPv4UdpAddress)) + { + t4 = addr; + af = AF_INET; + port = ntohs (t4->u4_port); + memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); + sb = &a4; + } + else + { + GNUNET_break_op (0); + return NULL; + } + inet_ntop (af, sb, buf, INET6_ADDRSTRLEN); + GNUNET_snprintf (rbuf, sizeof (rbuf), (af == AF_INET6) ? "[%s]:%u" : "%s:%u", + buf, port); + return rbuf; +} + + +/** + * Append our port and forward the result. + * + * @param cls a 'struct PrettyPrinterContext' + * @param hostname result from DNS resolver + */ +static void +append_port (void *cls, const char *hostname) +{ + struct PrettyPrinterContext *ppc = cls; + char *ret; + + if (hostname == NULL) + { + ppc->asc (ppc->asc_cls, NULL); + GNUNET_free (ppc); + return; + } + GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port); + ppc->asc (ppc->asc_cls, ret); + GNUNET_free (ret); +} + + +/** + * Convert the transports address to a nice, human-readable + * format. + * + * @param cls closure + * @param type name of the transport that generated the address + * @param addr one of the addresses of the host, NULL for the last address + * the specific address format depends on the transport + * @param addrlen length of the address + * @param numeric should (IP) addresses be displayed in numeric form? + * @param timeout after how long should we give up? + * @param asc function to call on each string + * @param asc_cls closure for asc + */ +static void +udp_plugin_address_pretty_printer (void *cls, const char *type, + const void *addr, size_t addrlen, + int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressStringCallback asc, + void *asc_cls) +{ + struct PrettyPrinterContext *ppc; + const void *sb; + size_t sbs; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4UdpAddress *u4; + const struct IPv6UdpAddress *u6; + uint16_t port; + + if (addrlen == sizeof (struct IPv6UdpAddress)) + { + u6 = addr; + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + a6.sin6_len = sizeof (a6); +#endif + a6.sin6_port = u6->u6_port; + memcpy (&a6.sin6_addr, &u6->ipv6_addr, sizeof (struct in6_addr)); + port = ntohs (u6->u6_port); + sb = &a6; + sbs = sizeof (a6); + } + else if (addrlen == sizeof (struct IPv4UdpAddress)) + { + u4 = addr; + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + a4.sin_len = sizeof (a4); +#endif + a4.sin_port = u4->u4_port; + a4.sin_addr.s_addr = u4->ipv4_addr; + port = ntohs (u4->u4_port); + sb = &a4; + sbs = sizeof (a4); + } + else + { + /* invalid address */ + GNUNET_break_op (0); + asc (asc_cls, NULL); + return; + } + ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); + ppc->asc = asc; + ppc->asc_cls = asc_cls; + ppc->port = port; + GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); +} + + +/** + * Check if the given port is plausible (must be either our listen + * port or our advertised port). If it is neither, we return + * GNUNET_SYSERR. + * + * @param plugin global variables + * @param in_port port number to check + * @return GNUNET_OK if port is either open_port or adv_port + */ +static int +check_port (struct Plugin *plugin, uint16_t in_port) +{ + if ((in_port == plugin->port) || (in_port == plugin->aport)) + return GNUNET_OK; + return GNUNET_SYSERR; +} + + + +/** + * Function that will be called to check if a binary address for this + * plugin is well-formed and corresponds to an address for THIS peer + * (as per our configuration). Naturally, if absolutely necessary, + * plugins can be a bit conservative in their answer, but in general + * plugins should make sure that the address does not redirect + * traffic to a 3rd party that might try to man-in-the-middle our + * traffic. + * + * @param cls closure, should be our handle to the Plugin + * @param addr pointer to the address + * @param addrlen length of addr + * @return GNUNET_OK if this is a plausible address for this peer + * and transport, GNUNET_SYSERR if not + * + */ +static int +udp_plugin_check_address (void *cls, const void *addr, size_t addrlen) +{ + struct Plugin *plugin = cls; + struct IPv4UdpAddress *v4; + struct IPv6UdpAddress *v6; + + if ((addrlen != sizeof (struct IPv4UdpAddress)) && + (addrlen != sizeof (struct IPv6UdpAddress))) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (addrlen == sizeof (struct IPv4UdpAddress)) + { + v4 = (struct IPv4UdpAddress *) addr; + if (GNUNET_OK != check_port (plugin, ntohs (v4->u4_port))) + return GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_NAT_test_address (plugin->nat, &v4->ipv4_addr, + sizeof (struct in_addr))) + return GNUNET_SYSERR; + } + else + { + v6 = (struct IPv6UdpAddress *) addr; + if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != check_port (plugin, ntohs (v6->u6_port))) + return GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_NAT_test_address (plugin->nat, &v6->ipv6_addr, + sizeof (struct in6_addr))) + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Destroy a session, plugin is being unloaded. + * + * @param cls unused + * @param key hash of public key of target peer + * @param value a 'struct PeerSession*' to clean up + * @return GNUNET_OK (continue to iterate) + */ +static int +disconnect_and_free_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct Plugin *plugin = cls; + struct Session *s = value; + struct UDPMessageWrapper *udpw; + struct UDPMessageWrapper *next; + +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Session %p to peer `%s' address ended \n", + s, + GNUNET_i2s (&s->target), + GNUNET_a2s (s->sock_addr, s->addrlen)); +#endif + + if (s->frag_ctx != NULL) + { + GNUNET_FRAGMENT_context_destroy(s->frag_ctx->frag); + GNUNET_free (s->frag_ctx); + s->frag_ctx = NULL; + } + + udpw = plugin->ipv4_queue_head; + while (udpw != NULL) + { + next = udpw->next; + if (udpw->session == s) + { + GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); + + if (udpw->cont != NULL) + udpw->cont (udpw->cont_cls, &s->target, GNUNET_SYSERR); + GNUNET_free (udpw); + } + udpw = next; + } + + udpw = plugin->ipv6_queue_head; + while (udpw != NULL) + { + next = udpw->next; + if (udpw->session == s) + { + GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); + + if (udpw->cont != NULL) + udpw->cont (udpw->cont_cls, &s->target, GNUNET_SYSERR); + GNUNET_free (udpw); + } + udpw = next; + } + + plugin->env->session_end (plugin->env->cls, &s->target, s); + + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (plugin->sessions, + &s->target.hashPubKey, + s)); + + + GNUNET_free (s); + return GNUNET_OK; +} + + +/** + * Disconnect from a remote node. Clean up session if we have one for this peer + * + * @param cls closure for this call (should be handle to Plugin) + * @param target the peeridentity of the peer to disconnect + * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed + */ +static void +udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +{ + struct Plugin *plugin = cls; + GNUNET_assert (plugin != NULL); + + GNUNET_assert (target != NULL); +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Disconnecting from peer `%s'\n", GNUNET_i2s (target)); +#endif + /* Clean up sessions */ + GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessions, &target->hashPubKey, &disconnect_and_free_it, plugin); +} + +static struct Session * +create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, + const void *addr, size_t addrlen, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct Session *s; + const struct IPv4UdpAddress *t4; + const struct IPv6UdpAddress *t6; + struct sockaddr_in *v4; + struct sockaddr_in6 *v6; + size_t len; + + switch (addrlen) + { + case sizeof (struct IPv4UdpAddress): + if (NULL == plugin->sockv4) + { + return NULL; + } + t4 = addr; + s = GNUNET_malloc (sizeof (struct Session) + sizeof (struct sockaddr_in)); + len = sizeof (struct sockaddr_in); + v4 = (struct sockaddr_in *) &s[1]; + v4->sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + v4->sin_len = sizeof (struct sockaddr_in); +#endif + v4->sin_port = t4->u4_port; + v4->sin_addr.s_addr = t4->ipv4_addr; + s->ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) v4, sizeof (struct sockaddr_in)); + break; + case sizeof (struct IPv6UdpAddress): + if (NULL == plugin->sockv6) + { + return NULL; + } + t6 = addr; + s = + GNUNET_malloc (sizeof (struct Session) + sizeof (struct sockaddr_in6)); + len = sizeof (struct sockaddr_in6); + v6 = (struct sockaddr_in6 *) &s[1]; + v6->sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + v6->sin6_len = sizeof (struct sockaddr_in6); +#endif + v6->sin6_port = t6->u6_port; + v6->sin6_addr = t6->ipv6_addr; + s->ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) v6, sizeof (struct sockaddr_in6)); + break; + default: + /* Must have a valid address to send to */ + GNUNET_break_op (0); + return NULL; + } + + s->addrlen = len; + s->target = *target; + s->sock_addr = (const struct sockaddr *) &s[1]; + s->flow_delay_for_other_peer = GNUNET_TIME_relative_get_zero(); + s->flow_delay_from_other_peer = GNUNET_TIME_absolute_get_zero(); + s->last_expected_delay = GNUNET_TIME_UNIT_SECONDS; + + return s; +} + +static int session_cmp_it (void *cls, + const GNUNET_HashCode * key, + void *value) +{ + struct SessionCompareContext * cctx = cls; + const struct GNUNET_HELLO_Address *address = cctx->addr; + struct Session *s = value; + + socklen_t s_addrlen = s->addrlen; + +#if VERBOSE_UDP + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing address %s <-> %s\n", + udp_address_to_string (NULL, (void *) address->address, address->address_length), + GNUNET_a2s (s->sock_addr, s->addrlen)); +#endif + + if ((address->address_length == sizeof (struct IPv4UdpAddress)) && + (s_addrlen == sizeof (struct sockaddr_in))) + { + struct IPv4UdpAddress * u4 = NULL; + u4 = (struct IPv4UdpAddress *) address->address; + const struct sockaddr_in *s4 = (const struct sockaddr_in *) s->sock_addr; + if ((0 == memcmp ((const void *) &u4->ipv4_addr,(const void *) &s4->sin_addr, sizeof (struct in_addr))) && + (u4->u4_port == s4->sin_port)) + { + cctx->res = s; + return GNUNET_NO; + } + + } + if ((address->address_length == sizeof (struct IPv6UdpAddress)) && + (s_addrlen == sizeof (struct sockaddr_in6))) + { + struct IPv6UdpAddress * u6 = NULL; + u6 = (struct IPv6UdpAddress *) address->address; + const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) s->sock_addr; + if ((0 == memcmp (&u6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr))) && + (u6->u6_port == s6->sin6_port)) + { + cctx->res = s; + return GNUNET_NO; + } + } + + + return GNUNET_YES; +} + + +/** + * Creates a new outbound session the transport service will use to send data to the + * peer + * + * @param cls the plugin + * @param address the address + * @return the session or NULL of max connections exceeded + */ +static struct Session * +udp_plugin_get_session (void *cls, + const struct GNUNET_HELLO_Address *address) +{ + struct Session * s = NULL; + struct Plugin * plugin = cls; + struct IPv6UdpAddress * udp_a6; + struct IPv4UdpAddress * udp_a4; + + GNUNET_assert (plugin != NULL); + GNUNET_assert (address != NULL); + + + if ((address->address == NULL) || + ((address->address_length != sizeof (struct IPv4UdpAddress)) && + (address->address_length != sizeof (struct IPv6UdpAddress)))) + { + GNUNET_break (0); + return NULL; + } + + if (address->address_length == sizeof (struct IPv4UdpAddress)) + { + if (plugin->sockv4 == NULL) + return NULL; + udp_a4 = (struct IPv4UdpAddress *) address->address; + if (udp_a4->u4_port == 0) + return NULL; + } + + if (address->address_length == sizeof (struct IPv6UdpAddress)) + { + if (plugin->sockv6 == NULL) + return NULL; + udp_a6 = (struct IPv6UdpAddress *) address->address; + if (udp_a6->u6_port == 0) + return NULL; + } + + /* check if session already exists */ + struct SessionCompareContext cctx; + cctx.addr = address; + cctx.res = NULL; +#if VERBOSE_UDP + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for existing session for peer `%s' `%s' \n", GNUNET_i2s (&address->peer), udp_address_to_string(NULL, address->address, address->address_length)); +#endif + GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessions, &address->peer.hashPubKey, session_cmp_it, &cctx); + if (cctx.res != NULL) + { +#if VERBOSE_UDP + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found existing session %p\n", cctx.res); +#endif + return cctx.res; + } + + /* otherwise create new */ + s = create_session (plugin, + &address->peer, + address->address, + address->address_length, + NULL, NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating new session %p for peer `%s' address `%s'\n", + s, + GNUNET_i2s(&address->peer), + udp_address_to_string(NULL,address->address,address->address_length)); +#endif + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (plugin->sessions, + &s->target.hashPubKey, + s, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + + return s; +} + +static void enqueue (struct Plugin *plugin, struct UDPMessageWrapper * udpw) +{ + + if (udpw->session->addrlen == sizeof (struct sockaddr_in)) + GNUNET_CONTAINER_DLL_insert(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); + if (udpw->session->addrlen == sizeof (struct sockaddr_in6)) + GNUNET_CONTAINER_DLL_insert(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); +} + +/** + * Function that is called with messages created by the fragmentation + * module. In the case of the 'proc' callback of the + * GNUNET_FRAGMENT_context_create function, this function must + * eventually call 'GNUNET_FRAGMENT_context_transmission_done'. + * + * @param cls closure, the 'struct FragmentationContext' + * @param msg the message that was created + */ +static void +enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct FragmentationContext *frag_ctx = cls; + struct Plugin *plugin = frag_ctx->plugin; + struct UDPMessageWrapper * udpw; + struct Session *s; + + size_t msg_len = ntohs (msg->size); + +#if VERBOSE_UDP + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Enqueuing fragment with %u bytes %u\n", msg_len , sizeof (struct UDPMessageWrapper)); +#endif + + udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + msg_len); + udpw->session = frag_ctx->session; + s = udpw->session; + udpw->udp = (char *) &udpw[1]; + + udpw->msg_size = msg_len; + udpw->cont = frag_ctx->cont; + udpw->cont_cls = frag_ctx->cont_cls; + udpw->timeout = frag_ctx->timeout; + udpw->frag_ctx = frag_ctx; + memcpy (udpw->udp, msg, msg_len); + + enqueue (plugin, udpw); + + + if (s->addrlen == sizeof (struct sockaddr_in)) + { + if (plugin->with_v4_ws == GNUNET_NO) + { + if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel(plugin->select_task); + + plugin->select_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs_v4, + plugin->ws_v4, + &udp_plugin_select, plugin); + plugin->with_v4_ws = GNUNET_YES; + } + } + + else if (s->addrlen == sizeof (struct sockaddr_in6)) + { + if (plugin->with_v6_ws == GNUNET_NO) + { + if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel(plugin->select_task_v6); + + plugin->select_task_v6 = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs_v6, + plugin->ws_v6, + &udp_plugin_select_v6, plugin); + plugin->with_v6_ws = GNUNET_YES; + } + } + +} + + + + +/** + * Function that can be used by the transport service to transmit + * a message using the plugin. Note that in the case of a + * peer disconnecting, the continuation MUST be called + * prior to the disconnect notification itself. This function + * will be called with this peer's HELLO message to initiate + * a fresh connection to another peer. + * + * @param cls closure + * @param s which session must be used + * @param msgbuf the message to transmit + * @param msgbuf_size number of bytes in 'msgbuf' + * @param priority how important is the message (most plugins will + * ignore message priority and just FIFO) + * @param to how long to wait at most for the transmission (does not + * require plugins to discard the message after the timeout, + * just advisory for the desired delay; most plugins will ignore + * this as well) + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...); can be NULL + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV) + */ +static ssize_t +udp_plugin_send (void *cls, + struct Session *s, + const char *msgbuf, size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative to, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct Plugin *plugin = cls; + size_t mlen = msgbuf_size + sizeof (struct UDPMessage); + + struct UDPMessageWrapper * udpw; + struct UDPMessage *udp; + char mbuf[mlen]; + GNUNET_assert (plugin != NULL); + GNUNET_assert (s != NULL); + + if ((s->addrlen == sizeof (struct sockaddr_in6)) && (plugin->sockv6 == NULL)) + return GNUNET_SYSERR; + + if ((s->addrlen == sizeof (struct sockaddr_in)) && (plugin->sockv4 == NULL)) + return GNUNET_SYSERR; + + + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains_value(plugin->sessions, &s->target.hashPubKey, s)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "UDP transmits %u-byte message to `%s' using address `%s'\n", + msgbuf_size, + GNUNET_i2s (&s->target), + GNUNET_a2s(s->sock_addr, s->addrlen)); + + /* Message */ + udp = (struct UDPMessage *) mbuf; + udp->header.size = htons (mlen); + udp->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE); + udp->reserved = htonl (0); + udp->sender = *plugin->env->my_identity; + + if (mlen <= UDP_MTU) + { + udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + mlen); + udpw->session = s; + udpw->udp = (char *) &udpw[1]; + udpw->msg_size = mlen; + udpw->timeout = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), to); + udpw->cont = cont; + udpw->cont_cls = cont_cls; + udpw->frag_ctx = NULL; + + memcpy (udpw->udp, udp, sizeof (struct UDPMessage)); + memcpy (&udpw->udp[sizeof (struct UDPMessage)], msgbuf, msgbuf_size); + + enqueue (plugin, udpw); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "UDP has to fragment message \n"); + if (s->frag_ctx != NULL) + return GNUNET_SYSERR; + memcpy (&udp[1], msgbuf, msgbuf_size); + struct FragmentationContext * frag_ctx = GNUNET_malloc(sizeof (struct FragmentationContext)); + + frag_ctx->plugin = plugin; + frag_ctx->session = s; + frag_ctx->cont = cont; + frag_ctx->cont_cls = cont_cls; + frag_ctx->timeout = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), to); + frag_ctx->bytes_to_send = mlen; + frag_ctx->frag = GNUNET_FRAGMENT_context_create (plugin->env->stats, + UDP_MTU, + &plugin->tracker, + s->last_expected_delay, + &udp->header, + &enqueue_fragment, + frag_ctx); + + s->frag_ctx = frag_ctx; + + } + + if (s->addrlen == sizeof (struct sockaddr_in)) + { + if (plugin->with_v4_ws == GNUNET_NO) + { + if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel(plugin->select_task); + + plugin->select_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs_v4, + plugin->ws_v4, + &udp_plugin_select, plugin); + plugin->with_v4_ws = GNUNET_YES; + } + } + + else if (s->addrlen == sizeof (struct sockaddr_in6)) + { + if (plugin->with_v6_ws == GNUNET_NO) + { + if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel(plugin->select_task_v6); + + plugin->select_task_v6 = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs_v6, + plugin->ws_v6, + &udp_plugin_select_v6, plugin); + plugin->with_v6_ws = GNUNET_YES; + } + } + + return mlen; +} + + +/** + * Our external IP address/port mapping has changed. + * + * @param cls closure, the 'struct LocalAddrList' + * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean + * the previous (now invalid) one + * @param addr either the previous or the new public IP address + * @param addrlen actual lenght of the address + */ +static void +udp_nat_port_map_callback (void *cls, int add_remove, + const struct sockaddr *addr, socklen_t addrlen) +{ + struct Plugin *plugin = cls; + struct IPv4UdpAddress u4; + struct IPv6UdpAddress u6; + void *arg; + size_t args; + + /* convert 'addr' to our internal format */ + switch (addr->sa_family) + { + case AF_INET: + GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); + u4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; + u4.u4_port = ((struct sockaddr_in *) addr)->sin_port; + arg = &u4; + args = sizeof (u4); + break; + case AF_INET6: + GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); + memcpy (&u6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr, + sizeof (struct in6_addr)); + u6.u6_port = ((struct sockaddr_in6 *) addr)->sin6_port; + arg = &u6; + args = sizeof (u6); + break; + default: + GNUNET_break (0); + return; + } + /* modify our published address list */ + plugin->env->notify_address (plugin->env->cls, add_remove, arg, args); +} + + + +/** + * Message tokenizer has broken up an incomming message. Pass it on + * to the service. + * + * @param cls the 'struct Plugin' + * @param client the 'struct SourceInformation' + * @param hdr the actual message + */ +static void +process_inbound_tokenized_messages (void *cls, void *client, + const struct GNUNET_MessageHeader *hdr) +{ + struct Plugin *plugin = cls; + struct SourceInformation *si = client; + struct GNUNET_ATS_Information ats[2]; + struct GNUNET_TIME_Relative delay; + + GNUNET_assert (si->session != NULL); + /* setup ATS */ + ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); + ats[0].value = htonl (1); + ats[1] = si->session->ats; + GNUNET_break (ntohl(ats[1].value) != GNUNET_ATS_NET_UNSPECIFIED); + + delay = plugin->env->receive (plugin->env->cls, + &si->sender, + hdr, + (const struct GNUNET_ATS_Information *) &ats, 2, + NULL, + si->arg, + si->args); + si->session->flow_delay_for_other_peer = delay; +} + + +/** + * We've received a UDP Message. Process it (pass contents to main service). + * + * @param plugin plugin context + * @param msg the message + * @param sender_addr sender address + * @param sender_addr_len number of bytes in sender_addr + */ +static void +process_udp_message (struct Plugin *plugin, const struct UDPMessage *msg, + const struct sockaddr *sender_addr, + socklen_t sender_addr_len) +{ + struct SourceInformation si; + struct Session * s = NULL; + struct IPv4UdpAddress u4; + struct IPv6UdpAddress u6; + const void *arg; + size_t args; + + if (0 != ntohl (msg->reserved)) + { + GNUNET_break_op (0); + return; + } + if (ntohs (msg->header.size) < + sizeof (struct GNUNET_MessageHeader) + sizeof (struct UDPMessage)) + { + GNUNET_break_op (0); + return; + } + + /* convert address */ + switch (sender_addr->sa_family) + { + case AF_INET: + GNUNET_assert (sender_addr_len == sizeof (struct sockaddr_in)); + u4.ipv4_addr = ((struct sockaddr_in *) sender_addr)->sin_addr.s_addr; + u4.u4_port = ((struct sockaddr_in *) sender_addr)->sin_port; + arg = &u4; + args = sizeof (u4); + break; + case AF_INET6: + GNUNET_assert (sender_addr_len == sizeof (struct sockaddr_in6)); + u6.ipv6_addr = ((struct sockaddr_in6 *) sender_addr)->sin6_addr; + u6.u6_port = ((struct sockaddr_in6 *) sender_addr)->sin6_port; + arg = &u6; + args = sizeof (u6); + break; + default: + GNUNET_break (0); + return; + } +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received message with %u bytes from peer `%s' at `%s'\n", + (unsigned int) ntohs (msg->header.size), GNUNET_i2s (&msg->sender), + GNUNET_a2s (sender_addr, sender_addr_len)); +#endif + + struct GNUNET_HELLO_Address * address = GNUNET_HELLO_address_allocate(&msg->sender, "udp", arg, args); + s = udp_plugin_get_session(plugin, address); + GNUNET_free (address); + + /* iterate over all embedded messages */ + si.session = s; + si.sender = msg->sender; + si.arg = arg; + si.args = args; + + GNUNET_SERVER_mst_receive (plugin->mst, &si, (const char *) &msg[1], + ntohs (msg->header.size) - + sizeof (struct UDPMessage), GNUNET_YES, GNUNET_NO); +} + + +/** + * Scan the heap for a receive context with the given address. + * + * @param cls the 'struct FindReceiveContext' + * @param node internal node of the heap + * @param element value stored at the node (a 'struct ReceiveContext') + * @param cost cost associated with the node + * @return GNUNET_YES if we should continue to iterate, + * GNUNET_NO if not. + */ +static int +find_receive_context (void *cls, struct GNUNET_CONTAINER_HeapNode *node, + void *element, GNUNET_CONTAINER_HeapCostType cost) +{ + struct FindReceiveContext *frc = cls; + struct DefragContext *e = element; + + if ((frc->addr_len == e->addr_len) && + (0 == memcmp (frc->addr, e->src_addr, frc->addr_len))) + { + frc->rc = e; + return GNUNET_NO; + } + return GNUNET_YES; +} + + +/** + * Process a defragmented message. + * + * @param cls the 'struct ReceiveContext' + * @param msg the message + */ +static void +fragment_msg_proc (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct DefragContext *rc = cls; + + if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE) + { + GNUNET_break (0); + return; + } + if (ntohs (msg->size) < sizeof (struct UDPMessage)) + { + GNUNET_break (0); + return; + } + process_udp_message (rc->plugin, (const struct UDPMessage *) msg, + rc->src_addr, rc->addr_len); +} + +struct LookupContext +{ + const struct sockaddr * addr; + size_t addrlen; + + struct Session *res; +}; + +static int +lookup_session_by_addr_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct LookupContext *l_ctx = cls; + struct Session * s = value; + + if ((s->addrlen == l_ctx->addrlen) && + (0 == memcmp (s->sock_addr, l_ctx->addr, s->addrlen))) + { + l_ctx->res = s; + return GNUNET_NO; + } + return GNUNET_YES; +} + +/** + * Transmit an acknowledgement. + * + * @param cls the 'struct ReceiveContext' + * @param id message ID (unused) + * @param msg ack to transmit + */ +static void +ack_proc (void *cls, uint32_t id, const struct GNUNET_MessageHeader *msg) +{ + struct DefragContext *rc = cls; + + size_t msize = sizeof (struct UDP_ACK_Message) + ntohs (msg->size); + struct UDP_ACK_Message *udp_ack; + uint32_t delay = 0; + struct UDPMessageWrapper *udpw; + struct Session *s; + + struct LookupContext l_ctx; + l_ctx.addr = rc->src_addr; + l_ctx.addrlen = rc->addr_len; + l_ctx.res = NULL; + GNUNET_CONTAINER_multihashmap_iterate (rc->plugin->sessions, + &lookup_session_by_addr_it, + &l_ctx); + s = l_ctx.res; + + GNUNET_assert (s != NULL); + + if (s->flow_delay_for_other_peer.rel_value <= UINT32_MAX) + delay = s->flow_delay_for_other_peer.rel_value; + +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending ACK to `%s' including delay of %u ms\n", + GNUNET_a2s (rc->src_addr, + (rc->src_addr->sa_family == + AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct + sockaddr_in6)), + delay); +#endif + udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + msize); + udpw->cont = NULL; + udpw->cont_cls = NULL; + udpw->frag_ctx = NULL; + udpw->msg_size = msize; + udpw->session = s; + udpw->timeout = GNUNET_TIME_absolute_get_forever(); + udpw->udp = (char *)&udpw[1]; + + udp_ack = (struct UDP_ACK_Message *) udpw->udp; + udp_ack->header.size = htons ((uint16_t) msize); + udp_ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK); + udp_ack->delay = htonl (delay); + udp_ack->sender = *rc->plugin->env->my_identity; + memcpy (&udp_ack[1], msg, ntohs (msg->size)); + + enqueue (rc->plugin, udpw); +} + + +static void read_process_msg (struct Plugin *plugin, + const struct GNUNET_MessageHeader *msg, + char *addr, + socklen_t fromlen) +{ + if (ntohs (msg->size) < sizeof (struct UDPMessage)) + { + GNUNET_break_op (0); + return; + } + process_udp_message (plugin, (const struct UDPMessage *) msg, + (const struct sockaddr *) addr, fromlen); + return; +} + +static void read_process_ack (struct Plugin *plugin, + const struct GNUNET_MessageHeader *msg, + char *addr, + socklen_t fromlen) +{ + const struct GNUNET_MessageHeader *ack; + const struct UDP_ACK_Message *udp_ack; + struct LookupContext l_ctx; + struct Session *s = NULL; + struct GNUNET_TIME_Relative flow_delay; + + if (ntohs (msg->size) < + sizeof (struct UDP_ACK_Message) + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return; + } + + udp_ack = (const struct UDP_ACK_Message *) msg; + + l_ctx.addr = (const struct sockaddr *) addr; + l_ctx.addrlen = fromlen; + l_ctx.res = NULL; + GNUNET_CONTAINER_multihashmap_iterate (plugin->sessions, + &lookup_session_by_addr_it, + &l_ctx); + s = l_ctx.res; + + if ((s == NULL) || (s->frag_ctx == NULL)) + return; + + flow_delay.rel_value = (uint64_t) ntohl (udp_ack->delay); + LOG (GNUNET_ERROR_TYPE_DEBUG, "We received a sending delay of %llu\n", + flow_delay.rel_value); + s->flow_delay_from_other_peer = + GNUNET_TIME_relative_to_absolute (flow_delay); + + ack = (const struct GNUNET_MessageHeader *) &udp_ack[1]; + if (ntohs (ack->size) != + ntohs (msg->size) - sizeof (struct UDP_ACK_Message)) + { + GNUNET_break_op (0); + return; + } + + if (GNUNET_OK != GNUNET_FRAGMENT_process_ack (s->frag_ctx->frag, ack)) + { +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, + "UDP processes %u-byte acknowledgement from `%s' at `%s'\n", + (unsigned int) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender), + GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); +#endif + return; + } + +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, + "FULL MESSAGE ACKed\n", + (unsigned int) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender), + GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); +#endif + s->last_expected_delay = GNUNET_FRAGMENT_context_destroy (s->frag_ctx->frag); + + struct UDPMessageWrapper * udpw = NULL; + if (s->addrlen == sizeof (struct sockaddr_in6)) + { + udpw = plugin->ipv6_queue_head; + while (udpw!= NULL) + { + if ((udpw->frag_ctx != NULL) && (udpw->frag_ctx == s->frag_ctx)) + { + GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); + GNUNET_free (udpw); + } + udpw = udpw->next; + } + } + if (s->addrlen == sizeof (struct sockaddr_in)) + { + udpw = plugin->ipv4_queue_head; + while (udpw!= NULL) + { + if ((udpw->frag_ctx != NULL) && (udpw->frag_ctx == s->frag_ctx)) + { + GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); + GNUNET_free (udpw); + } + udpw = udpw->next; + } + } + + if (s->frag_ctx->cont != NULL) + s->frag_ctx->cont + (s->frag_ctx->cont_cls, &udp_ack->sender, GNUNET_OK); + GNUNET_free (s->frag_ctx); + s->frag_ctx = NULL; + return; +} + +static void read_process_fragment (struct Plugin *plugin, + const struct GNUNET_MessageHeader *msg, + char *addr, + socklen_t fromlen) +{ + struct DefragContext *d_ctx; + struct GNUNET_TIME_Absolute now; + struct FindReceiveContext frc; + + + frc.rc = NULL; + frc.addr = (const struct sockaddr *) addr; + frc.addr_len = fromlen; + +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, "UDP processes %u-byte fragment from `%s'\n", + (unsigned int) ntohs (msg->size), + GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); +#endif + + /* Lookup existing receive context for this address */ + GNUNET_CONTAINER_heap_iterate (plugin->defrag_ctxs, + &find_receive_context, + &frc); + now = GNUNET_TIME_absolute_get (); + d_ctx = frc.rc; + + if (d_ctx == NULL) + { + /* Create a new defragmentation context */ + d_ctx = GNUNET_malloc (sizeof (struct DefragContext) + fromlen); + memcpy (&d_ctx[1], addr, fromlen); + d_ctx->src_addr = (const struct sockaddr *) &d_ctx[1]; + d_ctx->addr_len = fromlen; + d_ctx->plugin = plugin; + d_ctx->defrag = + GNUNET_DEFRAGMENT_context_create (plugin->env->stats, UDP_MTU, + UDP_MAX_MESSAGES_IN_DEFRAG, d_ctx, + &fragment_msg_proc, &ack_proc); + d_ctx->hnode = + GNUNET_CONTAINER_heap_insert (plugin->defrag_ctxs, d_ctx, + (GNUNET_CONTAINER_HeapCostType) + now.abs_value); +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, "Created new defragmentation context for %u-byte fragment from `%s'\n", + (unsigned int) ntohs (msg->size), + GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); +#endif + } + else + { +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing defragmentation context for %u-byte fragment from `%s'\n", + (unsigned int) ntohs (msg->size), + GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); +#endif + } + + if (GNUNET_OK == GNUNET_DEFRAGMENT_process_fragment (d_ctx->defrag, msg)) + { + /* keep this 'rc' from expiring */ + GNUNET_CONTAINER_heap_update_cost (plugin->defrag_ctxs, d_ctx->hnode, + (GNUNET_CONTAINER_HeapCostType) + now.abs_value); + } + if (GNUNET_CONTAINER_heap_get_size (plugin->defrag_ctxs) > + UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG) + { + /* remove 'rc' that was inactive the longest */ + d_ctx = GNUNET_CONTAINER_heap_remove_root (plugin->defrag_ctxs); + GNUNET_assert (NULL != d_ctx); + GNUNET_DEFRAGMENT_context_destroy (d_ctx->defrag); + GNUNET_free (d_ctx); + } +} + +/** + * Read and process a message from the given socket. + * + * @param plugin the overall plugin + * @param rsock socket to read from + */ +static void +udp_select_read (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *rsock) +{ + socklen_t fromlen; + char addr[32]; + char buf[65536]; + ssize_t size; + const struct GNUNET_MessageHeader *msg; + + fromlen = sizeof (addr); + memset (&addr, 0, sizeof (addr)); + size = GNUNET_NETWORK_socket_recvfrom (rsock, buf, sizeof (buf), + (struct sockaddr *) &addr, &fromlen); + + if (size < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return; + } + msg = (const struct GNUNET_MessageHeader *) buf; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "UDP received %u-byte message from `%s' type %i\n", (unsigned int) size, + GNUNET_a2s ((const struct sockaddr *) addr, fromlen), ntohs (msg->type)); + + if (size != ntohs (msg->size)) + { + GNUNET_break_op (0); + return; + } + + switch (ntohs (msg->type)) + { + case GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON: + udp_broadcast_receive (plugin, &buf, size, addr, fromlen); + return; + + case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE: + read_process_msg (plugin, msg, addr, fromlen); + return; + + case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK: + read_process_ack (plugin, msg, addr, fromlen);; + return; + + case GNUNET_MESSAGE_TYPE_FRAGMENT: + read_process_fragment (plugin, msg, addr, fromlen); + return; + + default: + GNUNET_break_op (0); + return; + } +} + +size_t +udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock) +{ + ssize_t sent; + size_t slen; + struct GNUNET_TIME_Absolute max; + struct GNUNET_TIME_Absolute ; + + struct UDPMessageWrapper *udpw = NULL; + + if (sock == plugin->sockv4) + { + udpw = plugin->ipv4_queue_head; + } + else if (sock == plugin->sockv6) + { + udpw = plugin->ipv6_queue_head; + } + else + { + GNUNET_break (0); + return 0; + } + + const struct sockaddr * sa = udpw->session->sock_addr; + slen = udpw->session->addrlen; + + max = GNUNET_TIME_absolute_max(udpw->timeout, GNUNET_TIME_absolute_get()); + + while (udpw != NULL) + { + if (max.abs_value != udpw->timeout.abs_value) + { + /* Message timed out */ + + if (udpw->cont != NULL) + udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR); + if (udpw->frag_ctx != NULL) + { +#if DEBUG_UDP + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fragmented message for peer `%s' with size %u timed out\n", + GNUNET_i2s(&udpw->session->target), udpw->frag_ctx->bytes_to_send); +#endif + udpw->session->last_expected_delay = GNUNET_FRAGMENT_context_destroy(udpw->frag_ctx->frag); + GNUNET_free (udpw->frag_ctx); + udpw->session->frag_ctx = NULL; + } + else + { +#if DEBUG_UDP + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' with size %u timed out\n", + GNUNET_i2s(&udpw->session->target), udpw->msg_size); +#endif + } + + if (sock == plugin->sockv4) + { + GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); + GNUNET_free (udpw); + udpw = plugin->ipv4_queue_head; + } + else if (sock == plugin->sockv6) + { + GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); + GNUNET_free (udpw); + udpw = plugin->ipv6_queue_head; + } + } + else + { + struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_remaining (udpw->session->flow_delay_from_other_peer); + if (delta.rel_value == 0) + { + /* this message is not delayed */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' (%u bytes) is not delayed \n", + GNUNET_i2s(&udpw->session->target), udpw->msg_size); + break; + } + else + { + /* this message is delayed, try next */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' (%u bytes) is delayed for %llu \n", + GNUNET_i2s(&udpw->session->target), udpw->msg_size, + delta); + udpw = udpw->next; + } + } + + } + + if (udpw == NULL) + { + /* No message left */ + return 0; + } + + sent = GNUNET_NETWORK_socket_sendto (sock, udpw->udp, udpw->msg_size, sa, slen); + + if (GNUNET_SYSERR == sent) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto"); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "UDP transmitted %u-byte message to %s (%d: %s)\n", + (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), (int) sent, + (sent < 0) ? STRERROR (errno) : "ok"); + if (udpw->cont != NULL) + udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "UDP transmitted %u-byte message to %s (%d: %s)\n", + (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), (int) sent, + (sent < 0) ? STRERROR (errno) : "ok"); + + /* This was just a message fragment */ + if (udpw->frag_ctx != NULL) + { + GNUNET_FRAGMENT_context_transmission_done (udpw->frag_ctx->frag); + } + /* This was a complete message*/ + else + { + if (udpw->cont != NULL) + udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_OK); + } + + if (sock == plugin->sockv4) + GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); + else if (sock == plugin->sockv6) + GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); + GNUNET_free (udpw); + udpw = NULL; + + return sent; +} + +/** + * We have been notified that our readset has something to read. We don't + * know which socket needs to be read, so we have to check each one + * Then reschedule this function to be called again once more is available. + * + * @param cls the plugin handle + * @param tc the scheduling context (for rescheduling this function again) + */ +static void +udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + + plugin->select_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + plugin->with_v4_ws = GNUNET_NO; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) + { + if ((NULL != plugin->sockv4) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv4))) + udp_select_read (plugin, plugin->sockv4); + + } + + if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) + { + if ((NULL != plugin->sockv4) && (plugin->ipv4_queue_head != NULL) && + (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->sockv4))) + { + udp_select_send (plugin, plugin->sockv4); + } + } + + if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (plugin->select_task); + plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs_v4, + (plugin->ipv4_queue_head != NULL) ? plugin->ws_v4 : NULL, + &udp_plugin_select, plugin); + if (plugin->ipv4_queue_head != NULL) + plugin->with_v4_ws = GNUNET_YES; + else + plugin->with_v4_ws = GNUNET_NO; +} + + +/** + * We have been notified that our readset has something to read. We don't + * know which socket needs to be read, so we have to check each one + * Then reschedule this function to be called again once more is available. + * + * @param cls the plugin handle + * @param tc the scheduling context (for rescheduling this function again) + */ +static void +udp_plugin_select_v6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + + plugin->select_task_v6 = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + plugin->with_v6_ws = GNUNET_NO; + if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) + { + if ((NULL != plugin->sockv6) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv6))) + udp_select_read (plugin, plugin->sockv6); + } + + if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) + { + if ((NULL != plugin->sockv6) && (plugin->ipv6_queue_head != NULL) && + (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->sockv6))) + { + udp_select_send (plugin, plugin->sockv6); + } + } + if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (plugin->select_task_v6); + plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs_v6, + (plugin->ipv6_queue_head != NULL) ? plugin->ws_v6 : NULL, + &udp_plugin_select_v6, plugin); + if (plugin->ipv6_queue_head != NULL) + plugin->with_v6_ws = GNUNET_YES; + else + plugin->with_v6_ws = GNUNET_NO; +} + + +static int +setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct sockaddr_in *serverAddrv4) +{ + int tries; + int sockets_created = 0; + struct sockaddr *serverAddr; + struct sockaddr *addrs[2]; + socklen_t addrlens[2]; + socklen_t addrlen; + + /* Create IPv6 socket */ + if (plugin->enable_ipv6 == GNUNET_YES) + { + plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 0); + if (NULL == plugin->sockv6) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Disabling IPv6 since it is not supported on this system!\n"); + plugin->enable_ipv6 = GNUNET_NO; + } + else + { +#if HAVE_SOCKADDR_IN_SIN_LEN + serverAddrv6->sin6_len = sizeof (serverAddrv6); +#endif + serverAddrv6->sin6_family = AF_INET6; + serverAddrv6->sin6_addr = in6addr_any; + serverAddrv6->sin6_port = htons (plugin->port); + addrlen = sizeof (struct sockaddr_in6); + serverAddr = (struct sockaddr *) serverAddrv6; +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv6 port %d\n", + ntohs (serverAddrv6->sin6_port)); +#endif + tries = 0; + while (GNUNET_NETWORK_socket_bind (plugin->sockv6, serverAddr, addrlen) != + GNUNET_OK) + { + serverAddrv6->sin6_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, + "IPv6 Binding failed, trying new port %d\n", + ntohs (serverAddrv6->sin6_port)); +#endif + tries++; + if (tries > 10) + { + GNUNET_NETWORK_socket_close (plugin->sockv6); + plugin->sockv6 = NULL; + break; + } + } + if (plugin->sockv6 != NULL) + { +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, + "IPv6 socket created on port %d\n", + ntohs (serverAddrv6->sin6_port)); +#endif + addrs[sockets_created] = (struct sockaddr *) serverAddrv6; + addrlens[sockets_created] = sizeof (struct sockaddr_in6); + sockets_created++; + } + } + } + + /* Create IPv4 socket */ + plugin->sockv4 = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 0); + if (NULL == plugin->sockv4) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket"); + } + else + { +#if HAVE_SOCKADDR_IN_SIN_LEN + serverAddrv4->sin_len = sizeof (serverAddrv4); +#endif + serverAddrv4->sin_family = AF_INET; + serverAddrv4->sin_addr.s_addr = INADDR_ANY; + serverAddrv4->sin_port = htons (plugin->port); + addrlen = sizeof (struct sockaddr_in); + serverAddr = (struct sockaddr *) serverAddrv4; + +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv4 port %d\n", + ntohs (serverAddrv4->sin_port)); +#endif + tries = 0; + while (GNUNET_NETWORK_socket_bind (plugin->sockv4, serverAddr, addrlen) != + GNUNET_OK) + { + serverAddrv4->sin_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv4 Binding failed, trying new port %d\n", + ntohs (serverAddrv4->sin_port)); +#endif + tries++; + if (tries > 10) + { + GNUNET_NETWORK_socket_close (plugin->sockv4); + plugin->sockv4 = NULL; + break; + } + } + if (plugin->sockv4 != NULL) + { + addrs[sockets_created] = (struct sockaddr *) serverAddrv4; + addrlens[sockets_created] = sizeof (struct sockaddr_in); + sockets_created++; + } + } + + /* Create file descriptors */ + plugin->rs_v4 = GNUNET_NETWORK_fdset_create (); + plugin->ws_v4 = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_zero (plugin->rs_v4); + GNUNET_NETWORK_fdset_zero (plugin->ws_v4); + if (NULL != plugin->sockv4) + { + GNUNET_NETWORK_fdset_set (plugin->rs_v4, plugin->sockv4); + GNUNET_NETWORK_fdset_set (plugin->ws_v4, plugin->sockv4); + } + + if (sockets_created == 0) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UDP sockets\n")); + + plugin->select_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs_v4, + NULL, + &udp_plugin_select, plugin); + plugin->with_v4_ws = GNUNET_NO; + + if (plugin->enable_ipv6 == GNUNET_YES) + { + plugin->rs_v6 = GNUNET_NETWORK_fdset_create (); + plugin->ws_v6 = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_zero (plugin->rs_v6); + GNUNET_NETWORK_fdset_zero (plugin->ws_v6); + if (NULL != plugin->sockv6) + { + GNUNET_NETWORK_fdset_set (plugin->rs_v6, plugin->sockv6); + GNUNET_NETWORK_fdset_set (plugin->ws_v6, plugin->sockv6); + } + + plugin->select_task_v6 = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs_v6, + NULL, + &udp_plugin_select_v6, plugin); + plugin->with_v6_ws = GNUNET_NO; + } + + plugin->nat = GNUNET_NAT_register (plugin->env->cfg, + GNUNET_NO, plugin->port, + sockets_created, + (const struct sockaddr **) addrs, addrlens, + &udp_nat_port_map_callback, NULL, plugin); + + return sockets_created; +} + + +/** + * The exported method. Makes the core api available via a global and + * returns the udp transport API. + * + * @param cls our 'struct GNUNET_TRANSPORT_PluginEnvironment' + * @return our 'struct GNUNET_TRANSPORT_PluginFunctions' + */ +void * +libgnunet_plugin_transport_udp_init (void *cls) +{ + struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; + struct GNUNET_TRANSPORT_PluginFunctions *api; + struct Plugin *plugin; + + unsigned long long port; + unsigned long long aport; + unsigned long long broadcast; + unsigned long long udp_max_bps; + unsigned long long enable_v6; + char * bind4_address; + char * bind6_address; + struct GNUNET_TIME_Relative interval; + + struct sockaddr_in serverAddrv4; + struct sockaddr_in6 serverAddrv6; + + int res; + + /* Get port number */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp", "PORT", + &port)) + port = 2086; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp", + "ADVERTISED_PORT", &aport)) + aport = port; + if (port > 65535) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Given `%s' option is out of range: %llu > %u\n"), "PORT", port, + 65535); + return NULL; + } + + /* Protocols */ + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "nat", + "DISABLEV6"))) + { + enable_v6 = GNUNET_NO; + } + else + enable_v6 = GNUNET_YES; + + + /* Addresses */ + memset (&serverAddrv6, 0, sizeof (serverAddrv6)); + memset (&serverAddrv4, 0, sizeof (serverAddrv4)); + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (env->cfg, "transport-udp", + "BINDTO", &bind4_address)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Binding udp plugin to specific address: `%s'\n", + bind4_address); + if (1 != inet_pton (AF_INET, bind4_address, &serverAddrv4.sin_addr)) + { + GNUNET_free (bind4_address); + return NULL; + } + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (env->cfg, "transport-udp", + "BINDTO6", &bind6_address)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Binding udp plugin to specific address: `%s'\n", + bind6_address); + if (1 != + inet_pton (AF_INET6, bind6_address, &serverAddrv6.sin6_addr)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid IPv6 address: `%s'\n"), + bind6_address); + GNUNET_free_non_null (bind4_address); + GNUNET_free (bind6_address); + return NULL; + } + } + + + /* Enable neighbour discovery */ + broadcast = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "transport-udp", + "BROADCAST"); + if (broadcast == GNUNET_SYSERR) + broadcast = GNUNET_NO; + + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (env->cfg, "transport-udp", + "BROADCAST_INTERVAL", &interval)) + { + interval = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10); + } + + /* Maximum datarate */ + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp", + "MAX_BPS", &udp_max_bps)) + { + udp_max_bps = 1024 * 1024 * 50; /* 50 MB/s == infinity for practical purposes */ + } + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + + GNUNET_BANDWIDTH_tracker_init (&plugin->tracker, + GNUNET_BANDWIDTH_value_init ((uint32_t)udp_max_bps), 30); + + + plugin->sessions = GNUNET_CONTAINER_multihashmap_create (10); + plugin->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + plugin->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages, plugin); + plugin->port = port; + plugin->aport = aport; + plugin->broadcast_interval = interval; + plugin->enable_ipv6 = enable_v6; + plugin->env = env; + + api->cls = plugin; + api->send = NULL; + api->disconnect = &udp_disconnect; + api->address_pretty_printer = &udp_plugin_address_pretty_printer; + api->address_to_string = &udp_address_to_string; + api->check_address = &udp_plugin_check_address; + api->get_session = &udp_plugin_get_session; + api->send = &udp_plugin_send; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Setting up sockets\n"); + res = setup_sockets (plugin, &serverAddrv6, &serverAddrv4); + if ((res == 0) || ((plugin->sockv4 == NULL) && (plugin->sockv6 == NULL))) + { + LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to create network sockets, plugin failed\n"); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting broadcasting\n"); + if (broadcast == GNUNET_YES) + setup_broadcast (plugin, &serverAddrv6, &serverAddrv4); + + + GNUNET_free_non_null (bind4_address); + GNUNET_free_non_null (bind6_address); + return api; +} + +int heap_cleanup_iterator (void *cls, + struct GNUNET_CONTAINER_HeapNode * + node, void *element, + GNUNET_CONTAINER_HeapCostType + cost) +{ + struct DefragContext * d_ctx = element; + + GNUNET_CONTAINER_heap_remove_node (node); + GNUNET_DEFRAGMENT_context_destroy(d_ctx->defrag); + GNUNET_free (d_ctx); + + return GNUNET_YES; +} + + +/** + * The exported method. Makes the core api available via a global and + * returns the udp transport API. + * + * @param cls our 'struct GNUNET_TRANSPORT_PluginEnvironment' + * @return our 'struct GNUNET_TRANSPORT_PluginFunctions' + */ +void * +libgnunet_plugin_transport_udp_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + stop_broadcast (plugin); + + if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->select_task); + plugin->select_task = GNUNET_SCHEDULER_NO_TASK; + } + if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->select_task_v6); + plugin->select_task_v6 = GNUNET_SCHEDULER_NO_TASK; + } + + /* Closing sockets */ + if (plugin->sockv4 != NULL) + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv4)); + plugin->sockv4 = NULL; + } + GNUNET_NETWORK_fdset_destroy (plugin->rs_v4); + GNUNET_NETWORK_fdset_destroy (plugin->ws_v4); + + if (plugin->sockv6 != NULL) + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv6)); + plugin->sockv6 = NULL; + + GNUNET_NETWORK_fdset_destroy (plugin->rs_v6); + GNUNET_NETWORK_fdset_destroy (plugin->ws_v6); + } + + GNUNET_NAT_unregister (plugin->nat); + + if (plugin->defrag_ctxs != NULL) + { + GNUNET_CONTAINER_heap_iterate(plugin->defrag_ctxs, + heap_cleanup_iterator, NULL); + GNUNET_CONTAINER_heap_destroy(plugin->defrag_ctxs); + plugin->defrag_ctxs = NULL; + } + if (plugin->mst != NULL) + { + GNUNET_SERVER_mst_destroy(plugin->mst); + plugin->mst = NULL; + } + + /* Clean up leftover messages */ + struct UDPMessageWrapper * udpw; + udpw = plugin->ipv4_queue_head; + while (udpw != NULL) + { + struct UDPMessageWrapper *tmp = udpw->next; + GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); + if (udpw->cont != NULL) + udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR); + GNUNET_free (udpw); + udpw = tmp; + } + udpw = plugin->ipv6_queue_head; + while (udpw != NULL) + { + struct UDPMessageWrapper *tmp = udpw->next; + GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); + if (udpw->cont != NULL) + udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR); + GNUNET_free (udpw); + udpw = tmp; + } + + /* Clean up sessions */ +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up sessions\n"); +#endif + GNUNET_CONTAINER_multihashmap_iterate (plugin->sessions, &disconnect_and_free_it, plugin); + GNUNET_CONTAINER_multihashmap_destroy (plugin->sessions); + + plugin->nat = NULL; + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + + +/* end of plugin_transport_udp.c */ diff --git a/src/transport/plugin_transport_udp.h b/src/transport/plugin_transport_udp.h new file mode 100644 index 0000000..5637524 --- /dev/null +++ b/src/transport/plugin_transport_udp.h @@ -0,0 +1,291 @@ +/* + This file is part of GNUnet + (C) 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_udp.h + * @brief Implementation of the UDP transport protocol + * @author Christian Grothoff + * @author Nathan Evans + * @author Matthias Wachs + */ +#include "platform.h" +#include "gnunet_hello_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_fragmentation_lib.h" +#include "gnunet_nat_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_resolver_service.h" +#include "gnunet_signatures.h" +#include "gnunet_constants.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" +#include "transport.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__) + +#define DEBUG_UDP GNUNET_NO +#define DEBUG_UDP_BROADCASTING GNUNET_NO + +/** + * MTU for fragmentation subsystem. Should be conservative since + * all communicating peers MUST work with this MTU. + */ +#define UDP_MTU 1400 + + +GNUNET_NETWORK_STRUCT_BEGIN +/** + * Network format for IPv4 addresses. + */ +struct IPv4UdpAddress +{ + /** + * IPv4 address, in network byte order. + */ + uint32_t ipv4_addr GNUNET_PACKED; + + /** + * Port number, in network byte order. + */ + uint16_t u4_port GNUNET_PACKED; +}; + + +/** + * Network format for IPv6 addresses. + */ +struct IPv6UdpAddress +{ + + /** + * IPv6 address. + */ + struct in6_addr ipv6_addr GNUNET_PACKED; + + /** + * Port number, in network byte order. + */ + uint16_t u6_port GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * UDP Message-Packet header (after defragmentation). + */ +struct UDPMessage +{ + /** + * Message header. + */ + struct GNUNET_MessageHeader header; + + /** + * Always zero for now. + */ + uint32_t reserved; + + /** + * What is the identity of the sender + */ + struct GNUNET_PeerIdentity sender; + +}; + + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin +{ + + /** + * Our environment. + */ + struct GNUNET_TRANSPORT_PluginEnvironment *env; + + /** + * Session of peers with whom we are currently connected, + * map of peer identity to 'struct PeerSession'. + */ + struct GNUNET_CONTAINER_MultiHashMap *sessions; + + /** + * Heap with all of our defragmentation activities. + */ + struct GNUNET_CONTAINER_Heap *defrag_ctxs; + + /** + * ID of select task + */ + GNUNET_SCHEDULER_TaskIdentifier select_task; + GNUNET_SCHEDULER_TaskIdentifier select_task_v6; + + /** + * Tokenizer for inbound messages. + */ + struct GNUNET_SERVER_MessageStreamTokenizer *mst; + + /** + * Bandwidth tracker to limit global UDP traffic. + */ + struct GNUNET_BANDWIDTH_Tracker tracker; + + /** + * Address we were told to bind to exclusively (IPv4). + */ + char *bind4_address; + + /** + * Address we were told to bind to exclusively (IPv6). + */ + char *bind6_address; + + /** + * Handle to NAT traversal support. + */ + struct GNUNET_NAT_Handle *nat; + + /** + * FD Read set + */ + struct GNUNET_NETWORK_FDSet *rs_v4; + + /** + * FD Write set + */ + struct GNUNET_NETWORK_FDSet *ws_v4; + + + int with_v4_ws; + + /** + * The read socket for IPv4 + */ + struct GNUNET_NETWORK_Handle *sockv4; + + + /** + * FD Read set + */ + struct GNUNET_NETWORK_FDSet *rs_v6; + + /** + * FD Write set + */ + struct GNUNET_NETWORK_FDSet *ws_v6; + + int with_v6_ws; + + /** + * The read socket for IPv6 + */ + struct GNUNET_NETWORK_Handle *sockv6; + + /** + * Beacon broadcasting + * ------------------- + */ + + /** + * Broadcast interval + */ + struct GNUNET_TIME_Relative broadcast_interval; + + /** + * Broadcast with IPv4 + */ + int broadcast_ipv4; + + /** + * Broadcast with IPv6 + */ + int broadcast_ipv6; + + + /** + * Tokenizer for inbound messages. + */ + struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_ipv6_mst; + struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_ipv4_mst; + + /** + * ID of select broadcast task + */ + GNUNET_SCHEDULER_TaskIdentifier send_ipv4_broadcast_task; + + /** + * ID of select broadcast task + */ + GNUNET_SCHEDULER_TaskIdentifier send_ipv6_broadcast_task; + + /** + * IPv6 multicast address + */ + struct sockaddr_in6 ipv6_multicast_address; + + /** + * DLL of IPv4 broadcast addresses + */ + struct BroadcastAddress *ipv4_broadcast_tail; + struct BroadcastAddress *ipv4_broadcast_head; + + /** + * Enable IPv6 + */ + int enable_ipv6; + + /** + * Port we broadcasting on. + */ + uint16_t broadcast_port; + + /** + * Port we listen on. + */ + uint16_t port; + + /** + * Port we advertise on. + */ + uint16_t aport; + + struct UDPMessageWrapper *ipv4_queue_head; + struct UDPMessageWrapper *ipv4_queue_tail; + + struct UDPMessageWrapper *ipv6_queue_head; + struct UDPMessageWrapper *ipv6_queue_tail; +}; + + +const char * +udp_address_to_string (void *cls, const void *addr, size_t addrlen); + +void +udp_broadcast_receive (); + +void +setup_broadcast (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct sockaddr_in *serverAddrv4); + +void +stop_broadcast (struct Plugin *plugin); + +/* end of plugin_transport_udp.h */ diff --git a/src/transport/plugin_transport_udp_broadcasting.c b/src/transport/plugin_transport_udp_broadcasting.c new file mode 100644 index 0000000..e33af26 --- /dev/null +++ b/src/transport/plugin_transport_udp_broadcasting.c @@ -0,0 +1,522 @@ +/* + This file is part of GNUnet + (C) 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_udp_broadcasting.c + * @brief Neighbour discovery with UDP + * @author Christian Grothoff + * @author Matthias Wachs + */ +#include "platform.h" +#include "plugin_transport_udp.h" +#include "gnunet_hello_lib.h" +#include "gnunet_util_lib.h" +#include "gnunet_fragmentation_lib.h" +#include "gnunet_nat_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_resolver_service.h" +#include "gnunet_signatures.h" +#include "gnunet_constants.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" +#include "transport.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__) + + +struct UDP_Beacon_Message +{ + /** + * Message header. + */ + struct GNUNET_MessageHeader header; + + /** + * What is the identity of the sender + */ + struct GNUNET_PeerIdentity sender; +}; + + +struct BroadcastAddress +{ + struct BroadcastAddress *next; + struct BroadcastAddress *prev; + + void *addr; + socklen_t addrlen; +}; + + +struct Mstv4Context +{ + struct Plugin *plugin; + + struct IPv4UdpAddress addr; + /** + * ATS network type in NBO + */ + uint32_t ats_address_network_type; +}; + +struct Mstv6Context +{ + struct Plugin *plugin; + + struct IPv6UdpAddress addr; + /** + * ATS network type in NBO + */ + uint32_t ats_address_network_type; +}; + + + +void +broadcast_ipv6_mst_cb (void *cls, void *client, + const struct GNUNET_MessageHeader *message) +{ + + struct Plugin *plugin = cls; + struct Mstv6Context *mc = client; + const struct GNUNET_MessageHeader *hello; + struct UDP_Beacon_Message *msg; + + msg = (struct UDP_Beacon_Message *) message; + + if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON != + ntohs (msg->header.type)) + return; +#if DEBUG_UDP_BROADCASTING + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received beacon with %u bytes from peer `%s' via address `%s'\n", + ntohs (msg->header.size), GNUNET_i2s (&msg->sender), + udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr))); +#endif + struct GNUNET_ATS_Information atsi[2]; + + /* setup ATS */ + atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); + atsi[0].value = htonl (1); + atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); + atsi[1].value = mc->ats_address_network_type; + GNUNET_break (ntohl(mc->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED); + + hello = (struct GNUNET_MessageHeader *) &msg[1]; + plugin->env->receive (plugin->env->cls, &msg->sender, hello, + (const struct GNUNET_ATS_Information *) &atsi, 2, NULL, + (const char *) &mc->addr, sizeof (mc->addr)); + + GNUNET_STATISTICS_update (plugin->env->stats, + _ + ("# IPv6 multicast HELLO beacons received via udp"), + 1, GNUNET_NO); + GNUNET_free (mc); +} + +void +broadcast_ipv4_mst_cb (void *cls, void *client, + const struct GNUNET_MessageHeader *message) +{ + struct Plugin *plugin = cls; + struct Mstv4Context *mc = client; + const struct GNUNET_MessageHeader *hello; + struct UDP_Beacon_Message *msg; + + msg = (struct UDP_Beacon_Message *) message; + + if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON != + ntohs (msg->header.type)) + return; +#if DEBUG_UDP_BROADCASTING + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received beacon with %u bytes from peer `%s' via address `%s'\n", + ntohs (msg->header.size), GNUNET_i2s (&msg->sender), + udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr))); +#endif + + struct GNUNET_ATS_Information atsi[2]; + + /* setup ATS */ + atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); + atsi[0].value = htonl (1); + atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); + atsi[1].value = mc->ats_address_network_type; + GNUNET_break (ntohl(mc->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED); + + hello = (struct GNUNET_MessageHeader *) &msg[1]; + plugin->env->receive (plugin->env->cls, &msg->sender, hello, + (const struct GNUNET_ATS_Information *) &atsi, 2, NULL, + (const char *) &mc->addr, sizeof (mc->addr)); + + GNUNET_STATISTICS_update (plugin->env->stats, + _ + ("# IPv4 broadcast HELLO beacons received via udp"), + 1, GNUNET_NO); + GNUNET_free (mc); +} + +void +udp_broadcast_receive (struct Plugin *plugin, const char * buf, ssize_t size, struct sockaddr *addr, size_t addrlen) +{ + struct GNUNET_ATS_Information ats; + + if (addrlen == sizeof (struct sockaddr_in)) + { +#if DEBUG_UDP_BROADCASTING + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received IPv4 HELLO beacon broadcast with %i bytes from address %s\n", + size, GNUNET_a2s ((const struct sockaddr *) addr, addrlen)); +#endif + struct Mstv4Context *mc; + + mc = GNUNET_malloc (sizeof (struct Mstv4Context)); + struct sockaddr_in *av4 = (struct sockaddr_in *) addr; + + mc->addr.ipv4_addr = av4->sin_addr.s_addr; + mc->addr.u4_port = av4->sin_port; + ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen); + mc->ats_address_network_type = ats.value; + if (GNUNET_OK != + GNUNET_SERVER_mst_receive (plugin->broadcast_ipv4_mst, mc, buf, size, + GNUNET_NO, GNUNET_NO)) + GNUNET_free (mc); + } + else if (addrlen == sizeof (struct sockaddr_in6)) + { +#if DEBUG_UDP_BROADCASTING + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received IPv6 HELLO beacon broadcast with %i bytes from address %s\n", + size, GNUNET_a2s ((const struct sockaddr *) &addr, addrlen)); +#endif + struct Mstv6Context *mc; + + mc = GNUNET_malloc (sizeof (struct Mstv6Context)); + struct sockaddr_in6 *av6 = (struct sockaddr_in6 *) addr; + + mc->addr.ipv6_addr = av6->sin6_addr; + mc->addr.u6_port = av6->sin6_port; + ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen); + mc->ats_address_network_type = ats.value; + + if (GNUNET_OK != + GNUNET_SERVER_mst_receive (plugin->broadcast_ipv6_mst, mc, buf, size, + GNUNET_NO, GNUNET_NO)) + GNUNET_free (mc); + } +} + +static void +udp_ipv4_broadcast_send (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + int sent; + uint16_t msg_size; + uint16_t hello_size; + char buf[65536]; + + const struct GNUNET_MessageHeader *hello; + struct UDP_Beacon_Message *msg; + struct BroadcastAddress *baddr; + + plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK; + + hello = plugin->env->get_our_hello (); + hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello); + msg_size = hello_size + sizeof (struct UDP_Beacon_Message); + + if (hello_size < (sizeof (struct GNUNET_MessageHeader)) || + (msg_size > (UDP_MTU))) + return; + + msg = (struct UDP_Beacon_Message *) buf; + msg->sender = *(plugin->env->my_identity); + msg->header.size = ntohs (msg_size); + msg->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON); + memcpy (&msg[1], hello, hello_size); + sent = 0; + + baddr = plugin->ipv4_broadcast_head; + /* just IPv4 */ + while ((baddr != NULL) && (baddr->addrlen == sizeof (struct sockaddr_in))) + { + struct sockaddr_in *addr = (struct sockaddr_in *) baddr->addr; + + addr->sin_port = htons (plugin->port); + + sent = + GNUNET_NETWORK_socket_sendto (plugin->sockv4, msg, msg_size, + (const struct sockaddr *) addr, + baddr->addrlen); + if (sent == GNUNET_SYSERR) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto"); + else + { +#if DEBUG_UDP_BROADCASTING + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sent HELLO beacon broadcast with %i bytes to address %s\n", sent, + GNUNET_a2s (baddr->addr, baddr->addrlen)); +#endif + } + baddr = baddr->next; + } + + plugin->send_ipv4_broadcast_task = + GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, + &udp_ipv4_broadcast_send, plugin); +} + +static void +udp_ipv6_broadcast_send (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + int sent; + uint16_t msg_size; + uint16_t hello_size; + char buf[65536]; + + const struct GNUNET_MessageHeader *hello; + struct UDP_Beacon_Message *msg; + + plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_NO_TASK; + + hello = plugin->env->get_our_hello (); + hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello); + msg_size = hello_size + sizeof (struct UDP_Beacon_Message); + + if (hello_size < (sizeof (struct GNUNET_MessageHeader)) || + (msg_size > (UDP_MTU))) + return; + + msg = (struct UDP_Beacon_Message *) buf; + msg->sender = *(plugin->env->my_identity); + msg->header.size = ntohs (msg_size); + msg->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON); + memcpy (&msg[1], hello, hello_size); + sent = 0; + + sent = + GNUNET_NETWORK_socket_sendto (plugin->sockv6, msg, msg_size, + (const struct sockaddr *) + &plugin->ipv6_multicast_address, + sizeof (struct sockaddr_in6)); + if (sent == GNUNET_SYSERR) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto"); + else + { +#if DEBUG_UDP_BROADCASTING + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending IPv6 HELLO beacon broadcast with %i bytes to address %s\n", + sent, + GNUNET_a2s ((const struct sockaddr *) &plugin->ipv6_multicast_address, + sizeof (struct sockaddr_in6))); +#endif + } + + + plugin->send_ipv6_broadcast_task = + GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, + &udp_ipv6_broadcast_send, plugin); +} + + +static int +iface_proc (void *cls, const char *name, int isDefault, + const struct sockaddr *addr, const struct sockaddr *broadcast_addr, + const struct sockaddr *netmask, socklen_t addrlen) +{ + struct Plugin *plugin = cls; + + if (addr != NULL) + { +#if DEBUG_UDP_BROADCASTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "address %s for interface %s %p\n ", + GNUNET_a2s (addr, addrlen), name, addr); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "broadcast address %s for interface %s %p\n ", + GNUNET_a2s (broadcast_addr, addrlen), name, broadcast_addr); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "netmask %s for interface %s %p\n ", + GNUNET_a2s (netmask, addrlen), name, netmask); +#endif + + /* Collecting broadcast addresses */ + if (broadcast_addr != NULL) + { + struct BroadcastAddress *ba = + GNUNET_malloc (sizeof (struct BroadcastAddress)); + ba->addr = GNUNET_malloc (addrlen); + memcpy (ba->addr, broadcast_addr, addrlen); + ba->addrlen = addrlen; + GNUNET_CONTAINER_DLL_insert (plugin->ipv4_broadcast_head, + plugin->ipv4_broadcast_tail, ba); + } + } + return GNUNET_OK; +} + + +void +setup_broadcast (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct sockaddr_in *serverAddrv4) +{ + /* create IPv4 broadcast socket */ + plugin->broadcast_ipv4 = GNUNET_NO; + if (plugin->sockv4 != NULL) + { + int yes = 1; + + if (GNUNET_NETWORK_socket_setsockopt + (plugin->sockv4, SOL_SOCKET, SO_BROADCAST, &yes, + sizeof (int)) != GNUNET_OK) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _ + ("Failed to set IPv4 broadcast option for broadcast socket on port %d\n"), + ntohs (serverAddrv4->sin_port)); + } + else + { + GNUNET_OS_network_interfaces_list (iface_proc, plugin); + plugin->send_ipv4_broadcast_task = + GNUNET_SCHEDULER_add_now (&udp_ipv4_broadcast_send, plugin); + + plugin->broadcast_ipv4_mst = + GNUNET_SERVER_mst_create (broadcast_ipv4_mst_cb, plugin); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv4 Broadcasting running\n"); + plugin->broadcast_ipv4 = GNUNET_YES; + } + } + + plugin->broadcast_ipv6 = GNUNET_NO; + if (plugin->sockv6 != NULL) + { + memset (&plugin->ipv6_multicast_address, 0, sizeof (struct sockaddr_in6)); + GNUNET_assert (1 == + inet_pton (AF_INET6, "FF05::13B", + &plugin->ipv6_multicast_address.sin6_addr)); + + plugin->ipv6_multicast_address.sin6_family = AF_INET6; + plugin->ipv6_multicast_address.sin6_port = htons (plugin->port); + + plugin->broadcast_ipv6_mst = + GNUNET_SERVER_mst_create (broadcast_ipv6_mst_cb, plugin); + + /* Create IPv6 multicast request */ + struct ipv6_mreq multicastRequest; + + multicastRequest.ipv6mr_multiaddr = + plugin->ipv6_multicast_address.sin6_addr; + /* TODO: 0 selects the "best" interface, tweak to use all interfaces + * + * http://tools.ietf.org/html/rfc2553#section-5.2: + * + * IPV6_JOIN_GROUP + * + * Join a multicast group on a specified local interface. If the + * interface index is specified as 0, the kernel chooses the local + * interface. For example, some kernels look up the multicast + * group in the normal IPv6 routing table and using the resulting + * interface. + * */ + multicastRequest.ipv6mr_interface = 0; + + /* Join the multicast group */ + if (GNUNET_NETWORK_socket_setsockopt + (plugin->sockv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char *) &multicastRequest, sizeof (multicastRequest)) != GNUNET_OK) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Failed to join IPv6 multicast group: IPv6 broadcasting not running\n"); + } + else + { +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 broadcasting running\n"); +#endif + plugin->send_ipv6_broadcast_task = + GNUNET_SCHEDULER_add_now (&udp_ipv6_broadcast_send, plugin); + plugin->broadcast_ipv6 = GNUNET_YES; + } + } +} + +void +stop_broadcast (struct Plugin *plugin) +{ + if (plugin->broadcast_ipv4) + { + if (plugin->send_ipv4_broadcast_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->send_ipv4_broadcast_task); + plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (plugin->broadcast_ipv4_mst != NULL) + GNUNET_SERVER_mst_destroy (plugin->broadcast_ipv4_mst); + + while (plugin->ipv4_broadcast_head != NULL) + { + struct BroadcastAddress *p = plugin->ipv4_broadcast_head; + + GNUNET_CONTAINER_DLL_remove (plugin->ipv4_broadcast_head, + plugin->ipv4_broadcast_tail, p); + GNUNET_free (p->addr); + GNUNET_free (p); + } + } + + if (plugin->broadcast_ipv6) + { + /* Create IPv6 multicast request */ + struct ipv6_mreq multicastRequest; + + multicastRequest.ipv6mr_multiaddr = + plugin->ipv6_multicast_address.sin6_addr; + multicastRequest.ipv6mr_interface = 0; + + /* Join the multicast address */ + if (GNUNET_NETWORK_socket_setsockopt + (plugin->sockv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + (char *) &multicastRequest, sizeof (multicastRequest)) != GNUNET_OK) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, setsockopt); + } + else + { +#if DEBUG_UDP + LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 Broadcasting stopped\n"); +#endif + } + + if (plugin->send_ipv6_broadcast_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->send_ipv6_broadcast_task); + plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_NO_TASK; + } + if (plugin->broadcast_ipv6_mst != NULL) + GNUNET_SERVER_mst_destroy (plugin->broadcast_ipv6_mst); + } + +} + +/* end of plugin_transport_udp_broadcasting.c */ diff --git a/src/transport/plugin_transport_unix.c b/src/transport/plugin_transport_unix.c new file mode 100644 index 0000000..499cc23 --- /dev/null +++ b/src/transport/plugin_transport_unix.c @@ -0,0 +1,1078 @@ +/* + This file is part of GNUnet + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_unix.c + * @brief Transport plugin using unix domain sockets (!) + * Clearly, can only be used locally on Unix/Linux hosts... + * ONLY INTENDED FOR TESTING!!! + * @author Christian Grothoff + * @author Nathan Evans + */ + +#include "platform.h" +#include "gnunet_hello_lib.h" +#include "gnunet_connection_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet_protocols.h" +#include "gnunet_resolver_service.h" +#include "gnunet_server_lib.h" +#include "gnunet_signatures.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" +#include "transport.h" + +#define DEBUG_UNIX GNUNET_EXTRALOGGING +#define DETAILS GNUNET_NO + +#define MAX_PROBES 20 + +/* + * Transport cost to peer, always 1 for UNIX (direct connection) + */ +#define UNIX_DIRECT_DISTANCE 1 + +#define DEFAULT_NAT_PORT 0 + +/** + * How long until we give up on transmitting the welcome message? + */ +#define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +/** + * Starting port for listening and sending, eventually a config value + */ +#define UNIX_NAT_DEFAULT_PORT 22086 + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * UNIX Message-Packet header. + */ +struct UNIXMessage +{ + /** + * Message header. + */ + struct GNUNET_MessageHeader header; + + /** + * What is the identity of the sender (GNUNET_hash of public key) + */ + struct GNUNET_PeerIdentity sender; + +}; + +struct Session +{ + void *addr; + size_t addrlen; + struct GNUNET_PeerIdentity target; +}; + +struct UNIXMessageWrapper +{ + struct UNIXMessageWrapper *next; + struct UNIXMessageWrapper *prev; + + struct UNIXMessage * msg; + size_t msgsize; + + struct GNUNET_TIME_Relative timeout; + unsigned int priority; + + struct Session *session; + GNUNET_TRANSPORT_TransmitContinuation cont; + void *cont_cls; +}; + +/* Forward definition */ +struct Plugin; + + +/** + * UNIX NAT "Session" + */ +struct PeerSession +{ + + /** + * Stored in a linked list. + */ + struct PeerSession *next; + + /** + * Pointer to the global plugin struct. + */ + struct Plugin *plugin; + + /** + * To whom are we talking to (set to our identity + * if we are still waiting for the welcome message) + */ + struct GNUNET_PeerIdentity target; + + /** + * Address of the other peer (either based on our 'connect' + * call or on our 'accept' call). + */ + void *connect_addr; + + /** + * Length of connect_addr. + */ + size_t connect_alen; + + /** + * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO) + */ + int expecting_welcome; + + /** + * From which socket do we need to send to this peer? + */ + struct GNUNET_NETWORK_Handle *sock; + + /* + * Queue of messages for this peer, in the case that + * we have to await a connection... + */ + struct MessageQueue *messages; + +}; + +/** + * Information we keep for each of our listen sockets. + */ +struct UNIX_Sock_Info +{ + /** + * The network handle + */ + struct GNUNET_NETWORK_Handle *desc; + + /** + * The port we bound to + */ + uint16_t port; +}; + + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin +{ + /** + * Our environment. + */ + struct GNUNET_TRANSPORT_PluginEnvironment *env; + + /* + * Session of peers with whom we are currently connected + */ + struct PeerSession *sessions; + + /* + * Sessions + */ + struct GNUNET_CONTAINER_MultiHashMap *session_map; + + /** + * ID of task used to update our addresses when one expires. + */ + GNUNET_SCHEDULER_TaskIdentifier address_update_task; + + /** + * ID of select task + */ + GNUNET_SCHEDULER_TaskIdentifier select_task; + + /** + * Integer to append to unix domain socket. + */ + uint16_t port; + + /** + * FD Read set + */ + struct GNUNET_NETWORK_FDSet *rs; + + /** + * FD Write set + */ + struct GNUNET_NETWORK_FDSet *ws; + + int with_ws; + + /** + * socket that we transmit all data with + */ + struct UNIX_Sock_Info unix_sock; + + /** + * Path of our unix domain socket (/tmp/unix-plugin-PORT) + */ + char *unix_socket_path; + + struct UNIXMessageWrapper *msg_head; + struct UNIXMessageWrapper *msg_tail; + + /** + * ATS network + */ + struct GNUNET_ATS_Information ats_network; +}; + + +static int +get_session_delete_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct Session *s = value; + struct Plugin *plugin = cls; + GNUNET_assert (plugin != NULL); + +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting session for peer `%s' `%s' \n", GNUNET_i2s (&s->target), s->addr); +#endif + + plugin->env->session_end (plugin->env->cls, &s->target, s); + + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove(plugin->session_map, &s->target.hashPubKey, s)); + + GNUNET_free (s); + + return GNUNET_YES; +} + +/** + * Disconnect from a remote node. Clean up session if we have one for this peer + * + * @param cls closure for this call (should be handle to Plugin) + * @param target the peeridentity of the peer to disconnect + * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed + */ +void +unix_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +{ + struct Plugin *plugin = cls; + GNUNET_assert (plugin != NULL); + + GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &target->hashPubKey, &get_session_delete_it, plugin); + return; +} + +/** + * Shutdown the server process (stop receiving inbound traffic). Maybe + * restarted later! + * + * @param cls Handle to the plugin for this transport + * + * @return returns the number of sockets successfully closed, + * should equal the number of sockets successfully opened + */ +static int +unix_transport_server_stop (void *cls) +{ + struct Plugin *plugin = cls; + + struct UNIXMessageWrapper * msgw = plugin->msg_head; + + while (NULL != (msgw = plugin->msg_head)) + { + GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw); + if (msgw->cont != NULL) + msgw->cont (msgw->cont_cls, &msgw->session->target, GNUNET_SYSERR); + GNUNET_free (msgw->msg); + GNUNET_free (msgw); + } + + if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->select_task); + plugin->select_task = GNUNET_SCHEDULER_NO_TASK; + } + + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (plugin->unix_sock.desc)); + plugin->unix_sock.desc = NULL; + plugin->with_ws = GNUNET_NO; + return GNUNET_OK; +} + + +struct PeerSession * +find_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerSession *pos; + + pos = plugin->sessions; + while (pos != NULL) + { + if (memcmp (&pos->target, peer, sizeof (struct GNUNET_PeerIdentity)) == 0) + return pos; + pos = pos->next; + } + + return pos; +} + + +/** + * Actually send out the message, assume we've got the address and + * send_handle squared away! + * + * @param cls closure + * @param send_handle which handle to send message on + * @param target who should receive this message (ignored by UNIX) + * @param msgbuf one or more GNUNET_MessageHeader(s) strung together + * @param msgbuf_size the size of the msgbuf to send + * @param priority how important is the message (ignored by UNIX) + * @param timeout when should we time out (give up) if we can not transmit? + * @param addr the addr to send the message to, needs to be a sockaddr for us + * @param addrlen the len of addr + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...) + * @param cont_cls closure for cont + * + * @return the number of bytes written, -1 on errors + */ +static ssize_t +unix_real_send (void *cls, + struct GNUNET_NETWORK_Handle *send_handle, + const struct GNUNET_PeerIdentity *target, const char *msgbuf, + size_t msgbuf_size, unsigned int priority, + struct GNUNET_TIME_Relative timeout, const void *addr, + size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont, + void *cont_cls) +{ + + ssize_t sent; + const void *sb; + size_t sbs; + struct sockaddr_un un; + size_t slen; + int retry; + + if (send_handle == NULL) + { +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "unix_real_send with send_handle NULL!\n"); +#endif + /* failed to open send socket for AF */ + if (cont != NULL) + cont (cont_cls, target, GNUNET_SYSERR); + return 0; + } + if ((addr == NULL) || (addrlen == 0)) + { +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "unix_real_send called without address, returning!\n"); +#endif + if (cont != NULL) + cont (cont_cls, target, GNUNET_SYSERR); + return 0; /* Can never send if we don't have an address!! */ + } + + memset (&un, 0, sizeof (un)); + un.sun_family = AF_UNIX; + slen = strlen (addr) + 1; + if (slen >= sizeof (un.sun_path)) + slen = sizeof (un.sun_path) - 1; + sent = 0; + GNUNET_assert (slen < sizeof (un.sun_path)); + memcpy (un.sun_path, addr, slen); + un.sun_path[slen] = '\0'; + slen = sizeof (struct sockaddr_un); +#if LINUX + un.sun_path[0] = '\0'; +#endif +#if HAVE_SOCKADDR_IN_SIN_LEN + un.sun_len = (u_char) slen; +#endif + sb = (struct sockaddr *) &un; + sbs = slen; + retry = GNUNET_NO; + sent = GNUNET_NETWORK_socket_sendto (send_handle, msgbuf, msgbuf_size, sb, sbs); + + if ((GNUNET_SYSERR == sent) && ((errno == EAGAIN) || (errno == ENOBUFS))) + retry = GNUNET_YES; + + if ((GNUNET_SYSERR == sent) && (errno == EMSGSIZE)) + { + socklen_t size = 0; + socklen_t len = sizeof (size); + + GNUNET_NETWORK_socket_getsockopt ((struct GNUNET_NETWORK_Handle *) + send_handle, SOL_SOCKET, SO_SNDBUF, &size, + &len); + + if (size < msgbuf_size) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying to increase socket buffer size from %i to %i for message size %i\n", + size, ((msgbuf_size / 1000) + 2) * 1000, msgbuf_size); + size = ((msgbuf_size / 1000) + 2) * 1000; + if (GNUNET_NETWORK_socket_setsockopt + ((struct GNUNET_NETWORK_Handle *) send_handle, SOL_SOCKET, SO_SNDBUF, + &size, sizeof (size)) == GNUNET_OK) + retry = GNUNET_YES; + else + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt"); + } + } + +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "UNIX transmit %u-byte message to %s (%d: %s)\n", + (unsigned int) msgbuf_size, GNUNET_a2s (sb, sbs), (int) sent, + (sent < 0) ? STRERROR (errno) : "ok"); +#endif + /* Calling continuation */ + if (cont != NULL) + { + if ((sent == GNUNET_SYSERR) && (retry == GNUNET_NO)) + cont (cont_cls, target, GNUNET_SYSERR); + if (sent > 0) + cont (cont_cls, target, GNUNET_OK); + } + + /* return number of bytes successfully sent */ + if (sent > 0) + return sent; + /* failed and retry: return 0 */ + if ((GNUNET_SYSERR == sent) && (retry == GNUNET_YES)) + return 0; + /* failed and no retry: return -1 */ + if ((GNUNET_SYSERR == sent) && (retry == GNUNET_NO)) + return -1; + + return sent; +} + +struct gsi_ctx +{ + char *address; + size_t addrlen; + struct Session *res; +}; + +static int +get_session_it (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct gsi_ctx *gsi = cls; + struct Session *s = value; + +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing session %s %s\n", gsi->address, s->addr); +#endif + if ((gsi->addrlen == s->addrlen) && + (0 == memcmp (gsi->address, s->addr, s->addrlen))) + { + gsi->res = s; + return GNUNET_NO; + } + return GNUNET_YES; +} + +/** + * Creates a new outbound session the transport service will use to send data to the + * peer + * + * @param cls the plugin + * @param address the address + * @return the session or NULL of max connections exceeded + */ +static struct Session * +unix_plugin_get_session (void *cls, + const struct GNUNET_HELLO_Address *address) +{ + struct Session * s = NULL; + struct Plugin *plugin = cls; + struct gsi_ctx gsi; + + /* Checks */ + GNUNET_assert (plugin != NULL); + GNUNET_assert (address != NULL); + + /* Check if already existing */ + gsi.address = (char *) address->address; + gsi.addrlen = address->address_length; + gsi.res = NULL; + GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &address->peer.hashPubKey, &get_session_it, &gsi); + if (gsi.res != NULL) + { +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found existing session\n"); +#endif + return gsi.res; + } + + /* Create a new session */ + + s = GNUNET_malloc (sizeof (struct Session) + address->address_length); + s->addr = &s[1]; + s->addrlen = address->address_length; + memcpy(s->addr, address->address, s->addrlen); + memcpy(&s->target, &address->peer, sizeof (struct GNUNET_PeerIdentity)); + + GNUNET_CONTAINER_multihashmap_put (plugin->session_map, + &address->peer.hashPubKey, s, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating new session\n"); +#endif + + return s; +} + +/* + * @param cls the plugin handle + * @param tc the scheduling context (for rescheduling this function again) + * + * We have been notified that our writeset has something to read. We don't + * know which socket needs to be read, so we have to check each one + * Then reschedule this function to be called again once more is available. + * + */ +static void +unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Function that can be used by the transport service to transmit + * a message using the plugin. Note that in the case of a + * peer disconnecting, the continuation MUST be called + * prior to the disconnect notification itself. This function + * will be called with this peer's HELLO message to initiate + * a fresh connection to another peer. + * + * @param cls closure + * @param session which session must be used + * @param msgbuf the message to transmit + * @param msgbuf_size number of bytes in 'msgbuf' + * @param priority how important is the message (most plugins will + * ignore message priority and just FIFO) + * @param to how long to wait at most for the transmission (does not + * require plugins to discard the message after the timeout, + * just advisory for the desired delay; most plugins will ignore + * this as well) + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...); can be NULL + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV) + */ +static ssize_t +unix_plugin_send (void *cls, + struct Session *session, + const char *msgbuf, size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative to, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct Plugin *plugin = cls; + struct UNIXMessageWrapper *wrapper; + struct UNIXMessage *message; + int ssize; + + GNUNET_assert (plugin != NULL); + GNUNET_assert (session != NULL); + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_contains_value(plugin->session_map, + &session->target.hashPubKey, session)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + ssize = sizeof (struct UNIXMessage) + msgbuf_size; + message = GNUNET_malloc (sizeof (struct UNIXMessage) + msgbuf_size); + message->header.size = htons (ssize); + message->header.type = htons (0); + memcpy (&message->sender, plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity)); + memcpy (&message[1], msgbuf, msgbuf_size); + + wrapper = GNUNET_malloc (sizeof (struct UNIXMessageWrapper)); + wrapper->msg = message; + wrapper->msgsize = ssize; + wrapper->priority = priority; + wrapper->timeout = to; + wrapper->cont = cont; + wrapper->cont_cls = cont_cls; + wrapper->session = session; + + GNUNET_CONTAINER_DLL_insert(plugin->msg_head, plugin->msg_tail, wrapper); + +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes to `%s'\n", ssize, + (char *) session->addr); +#endif + + if (plugin->with_ws == GNUNET_NO) + { + if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel(plugin->select_task); + + plugin->select_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs, + plugin->ws, + &unix_plugin_select, plugin); + plugin->with_ws = GNUNET_YES; + } + return ssize; +} + + +/** + * Demultiplexer for UNIX messages + * + * @param plugin the main plugin for this transport + * @param sender from which peer the message was received + * @param currhdr pointer to the header of the message + * @param un the address from which the message was received + * @param fromlen the length of the address + */ +static void +unix_demultiplexer (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *currhdr, + const struct sockaddr_un *un, size_t fromlen) +{ + struct GNUNET_ATS_Information ats[2]; + + ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); + ats[0].value = htonl (UNIX_DIRECT_DISTANCE); + ats[1] = plugin->ats_network; + GNUNET_break (ntohl(plugin->ats_network.value) != GNUNET_ATS_NET_UNSPECIFIED); + + GNUNET_assert (fromlen >= sizeof (struct sockaddr_un)); + +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message from %s\n", + un->sun_path); +#endif + plugin->env->receive (plugin->env->cls, sender, currhdr, + (const struct GNUNET_ATS_Information *) &ats, 2, + NULL, un->sun_path, strlen (un->sun_path) + 1); +} + + +static void +unix_plugin_select_read (struct Plugin * plugin) +{ + char buf[65536]; + struct UNIXMessage *msg; + struct GNUNET_PeerIdentity sender; + struct sockaddr_un un; + socklen_t addrlen; + ssize_t ret; + int offset; + int tsize; + char *msgbuf; + const struct GNUNET_MessageHeader *currhdr; + uint16_t csize; + + addrlen = sizeof (un); + memset (&un, 0, sizeof (un)); + + ret = + GNUNET_NETWORK_socket_recvfrom (plugin->unix_sock.desc, buf, sizeof (buf), + (struct sockaddr *) &un, &addrlen); + + if ((GNUNET_SYSERR == ret) && ((errno == EAGAIN) || (errno == ENOBUFS))) + return; + + if (ret == GNUNET_SYSERR) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom"); + return; + } + else + { +#if LINUX + un.sun_path[0] = '/'; +#endif +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes from socket %s\n", ret, + &un.sun_path[0]); +#endif + } + + GNUNET_assert (AF_UNIX == (un.sun_family)); + + msg = (struct UNIXMessage *) buf; + csize = ntohs (msg->header.size); + if ((csize < sizeof (struct UNIXMessage)) || (csize > ret)) + { + GNUNET_break_op (0); + return; + } + msgbuf = (char *) &msg[1]; + memcpy (&sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity)); + offset = 0; + tsize = csize - sizeof (struct UNIXMessage); + while (offset + sizeof (struct GNUNET_MessageHeader) <= tsize) + { + currhdr = (struct GNUNET_MessageHeader *) &msgbuf[offset]; + csize = ntohs (currhdr->size); + if ((csize < sizeof (struct GNUNET_MessageHeader)) || + (csize > tsize - offset)) + { + GNUNET_break_op (0); + break; + } + unix_demultiplexer (plugin, &sender, currhdr, &un, sizeof (un)); + offset += csize; + } +} + +static void +unix_plugin_select_write (struct Plugin * plugin) +{ + int sent = 0; + struct UNIXMessageWrapper * msgw = plugin->msg_head; + + sent = unix_real_send (plugin, + plugin->unix_sock.desc, + &msgw->session->target, + (const char *) msgw->msg, + msgw->msgsize, + msgw->priority, + msgw->timeout, + msgw->session->addr, + msgw->session->addrlen, + msgw->cont, msgw->cont_cls); + + /* successfully sent bytes */ + if (sent > 0) + { + GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw); + GNUNET_free (msgw->msg); + GNUNET_free (msgw); + return; + } + + /* failed and no retry */ + if (sent == -1) + { + GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw); + GNUNET_free (msgw->msg); + GNUNET_free (msgw); + return; + } + + /* failed and retry */ + if (sent == 0) + return; +} + +/* + * @param cls the plugin handle + * @param tc the scheduling context (for rescheduling this function again) + * + * We have been notified that our writeset has something to read. We don't + * know which socket needs to be read, so we have to check each one + * Then reschedule this function to be called again once more is available. + * + */ +static void +unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + + plugin->select_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + plugin->with_ws = GNUNET_NO; + if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) + { + GNUNET_assert (GNUNET_NETWORK_fdset_isset + (tc->write_ready, plugin->unix_sock.desc)); + if (plugin->msg_head != NULL) + unix_plugin_select_write (plugin); + } + + if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) + { + GNUNET_assert (GNUNET_NETWORK_fdset_isset + (tc->read_ready, plugin->unix_sock.desc)); + unix_plugin_select_read (plugin); + } + + if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (plugin->select_task); + plugin->select_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs, + (plugin->msg_head != NULL) ? plugin->ws : NULL, + &unix_plugin_select, plugin); + if (plugin->msg_head != NULL) + plugin->with_ws = GNUNET_YES; +} + +/** + * Create a slew of UNIX sockets. If possible, use IPv6 and IPv4. + * + * @param cls closure for server start, should be a struct Plugin * + * @return number of sockets created or GNUNET_SYSERR on error +*/ +static int +unix_transport_server_start (void *cls) +{ + struct Plugin *plugin = cls; + struct sockaddr *serverAddr; + socklen_t addrlen; + struct sockaddr_un un; + size_t slen; + + memset (&un, 0, sizeof (un)); + un.sun_family = AF_UNIX; + slen = strlen (plugin->unix_socket_path) + 1; + if (slen >= sizeof (un.sun_path)) + slen = sizeof (un.sun_path) - 1; + + memcpy (un.sun_path, plugin->unix_socket_path, slen); + un.sun_path[slen] = '\0'; + slen = sizeof (struct sockaddr_un); +#if HAVE_SOCKADDR_IN_SIN_LEN + un.sun_len = (u_char) slen; +#endif + + serverAddr = (struct sockaddr *) &un; + addrlen = slen; +#if LINUX + un.sun_path[0] = '\0'; +#endif + plugin->ats_network = plugin->env->get_address_type (plugin->env->cls, serverAddr, addrlen); + plugin->unix_sock.desc = + GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0); + if (NULL == plugin->unix_sock.desc) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); + return GNUNET_SYSERR; + } + if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen) + != GNUNET_OK) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind"); + GNUNET_NETWORK_socket_close (plugin->unix_sock.desc); + plugin->unix_sock.desc = NULL; + return GNUNET_SYSERR; + } +#if DEBUG_UNIX + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "unix", "Bound to `%s'\n", + &un.sun_path[0]); +#endif + plugin->rs = GNUNET_NETWORK_fdset_create (); + plugin->ws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_zero (plugin->rs); + GNUNET_NETWORK_fdset_zero (plugin->ws); + GNUNET_NETWORK_fdset_set (plugin->rs, plugin->unix_sock.desc); + GNUNET_NETWORK_fdset_set (plugin->ws, plugin->unix_sock.desc); + + plugin->select_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, + plugin->rs, + NULL, + &unix_plugin_select, plugin); + plugin->with_ws = GNUNET_NO; + + return 1; +} + + +/** + * Function that will be called to check if a binary address for this + * plugin is well-formed and corresponds to an address for THIS peer + * (as per our configuration). Naturally, if absolutely necessary, + * plugins can be a bit conservative in their answer, but in general + * plugins should make sure that the address does not redirect + * traffic to a 3rd party that might try to man-in-the-middle our + * traffic. + * + * @param cls closure, should be our handle to the Plugin + * @param addr pointer to the address + * @param addrlen length of addr + * @return GNUNET_OK if this is a plausible address for this peer + * and transport, GNUNET_SYSERR if not + * + */ +static int +unix_check_address (void *cls, const void *addr, size_t addrlen) +{ + +#if DEBUG_UNIX + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Informing transport service about my address `%s'\n", + (char *) addr); +#endif + return GNUNET_OK; +} + + +/** + * Convert the transports address to a nice, human-readable + * format. + * + * @param cls closure + * @param type name of the transport that generated the address + * @param addr one of the addresses of the host, NULL for the last address + * the specific address format depends on the transport + * @param addrlen length of the address + * @param numeric should (IP) addresses be displayed in numeric form? + * @param timeout after how long should we give up? + * @param asc function to call on each string + * @param asc_cls closure for asc + */ +static void +unix_plugin_address_pretty_printer (void *cls, const char *type, + const void *addr, size_t addrlen, + int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressStringCallback asc, + void *asc_cls) +{ + if ((addr != NULL) && (addrlen > 0)) + asc (asc_cls, (const char *) addr); + else + { + GNUNET_break (0); + asc (asc_cls, "Invalid UNIX address"); + } + +} + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure + * @param addr binary address + * @param addrlen length of the address + * @return string representing the same address + */ +static const char * +unix_address_to_string (void *cls, const void *addr, size_t addrlen) +{ + if ((addr != NULL) && (addrlen > 0)) + return (const char *) addr; + else + return NULL; +} + +/** + * Notify transport service about address + * + * @param cls the plugin + * @param tc unused + */ +static void +address_notification (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + + plugin->env->notify_address (plugin->env->cls, GNUNET_YES, + plugin->unix_socket_path, + strlen (plugin->unix_socket_path) + 1); +} + +/** + * The exported method. Makes the core api available via a global and + * returns the unix transport API. + */ +void * +libgnunet_plugin_transport_unix_init (void *cls) +{ + struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; + unsigned long long port; + struct GNUNET_TRANSPORT_PluginFunctions *api; + struct Plugin *plugin; + int sockets_created; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-unix", "PORT", + &port)) + port = UNIX_NAT_DEFAULT_PORT; + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->port = port; + plugin->env = env; + GNUNET_asprintf (&plugin->unix_socket_path, "/tmp/unix-plugin-sock.%d", + plugin->port); + + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = plugin; + + api->get_session = &unix_plugin_get_session; + api->send = &unix_plugin_send; + api->disconnect = &unix_disconnect; + api->address_pretty_printer = &unix_plugin_address_pretty_printer; + api->address_to_string = &unix_address_to_string; + api->check_address = &unix_check_address; + sockets_created = unix_transport_server_start (plugin); + if (sockets_created == 0) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UNIX sockets\n")); + + plugin->session_map = GNUNET_CONTAINER_multihashmap_create(10); + + GNUNET_SCHEDULER_add_now (address_notification, plugin); + return api; +} + +void * +libgnunet_plugin_transport_unix_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + unix_transport_server_stop (plugin); + + GNUNET_CONTAINER_multihashmap_iterate (plugin->session_map, &get_session_delete_it, plugin); + GNUNET_CONTAINER_multihashmap_destroy (plugin->session_map); + + GNUNET_NETWORK_fdset_destroy (plugin->rs); + GNUNET_NETWORK_fdset_destroy (plugin->ws); + GNUNET_free (plugin->unix_socket_path); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + +/* end of plugin_transport_unix.c */ diff --git a/src/transport/plugin_transport_wlan.c b/src/transport/plugin_transport_wlan.c new file mode 100644 index 0000000..08f9c58 --- /dev/null +++ b/src/transport/plugin_transport_wlan.c @@ -0,0 +1,3201 @@ +/* + This file is part of GNUnet + (C) 2010 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file transport/plugin_transport_wlan.c + * @brief transport plugin for wlan + * @author David Brodski + */ + +//TODO split rx and tx structures for better handling + +#include "platform.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_transport_plugin.h" +#include "plugin_transport_wlan.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_fragmentation_lib.h" +#include "gnunet_constants.h" + +/** + * DEBUG switch + */ +#define DEBUG_WLAN GNUNET_EXTRA_LOGGING + + +#define PROTOCOL_PREFIX "wlan" + +#define PLUGIN_LOG_NAME "wlan-plugin" + +/** + * Max size of packet + */ +#define WLAN_MTU 1430 + +/** + * time out of a session + */ +#define SESSION_TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT + +/** + * time out of a mac endpoint + */ +#define MACENDPOINT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2) + +/** + * scaling factor for hello beacon + */ +#define HELLO_BEACON_SCALING_FACTOR 30 + +/** + * scaling factor for restarting the helper + */ +#define HELPER_RESTART_SCALING_FACTOR 2 + +/** + * max size of fragment queue + */ +#define FRAGMENT_QUEUE_SIZE 10 +/** + * max messages in fragment queue per session/client + */ +#define FRAGMENT_QUEUE_MESSAGES_OUT_PER_SESSION 1 + +/** + * max messages in fragment queue per MAC + */ +#define FRAGMENT_QUEUE_MESSAGES_OUT_PER_MACENDPOINT 1 + +/** + * max messages in in queue + */ +#define MESSAGES_IN_QUEUE_SIZE 10 +/** + * max messages in in queue per session/client + */ +#define MESSAGES_IN_DEFRAG_QUEUE_PER_MAC 1 + +/** + * LLC fields for better compatibility + */ +#define WLAN_LLC_DSAP_FIELD 0x1f +#define WLAN_LLC_SSAP_FIELD 0x1f + + +#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ + +#define IEEE80211_FC0_VERSION_MASK 0x03 +#define IEEE80211_FC0_VERSION_SHIFT 0 +#define IEEE80211_FC0_VERSION_0 0x00 +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_SHIFT 2 +#define IEEE80211_FC0_TYPE_MGT 0x00 +#define IEEE80211_FC0_TYPE_CTL 0x04 +#define IEEE80211_FC0_TYPE_DATA 0x08 + +GNUNET_NETWORK_STRUCT_BEGIN + +/* + * generic definitions for IEEE 802.11 frames + */ +struct ieee80211_frame +{ + u_int8_t i_fc[2]; + u_int8_t i_dur[2]; + u_int8_t i_addr1[IEEE80211_ADDR_LEN]; + u_int8_t i_addr2[IEEE80211_ADDR_LEN]; + u_int8_t i_addr3[IEEE80211_ADDR_LEN]; + u_int8_t i_seq[2]; + u_int8_t llc[4]; +} GNUNET_PACKED; +GNUNET_NETWORK_STRUCT_END + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin +{ + /** + * Our environment. + */ + struct GNUNET_TRANSPORT_PluginEnvironment *env; + + /** + * List of open connections. head + */ + struct MacEndpoint *mac_head; + + /** + * List of open connections. tail + */ + struct MacEndpoint *mac_tail; + + /** + * Number of connections + */ + unsigned int mac_count; + + /** + * encapsulation of data from the local wlan helper program + */ + struct GNUNET_SERVER_MessageStreamTokenizer *suid_tokenizer; + + /** + * encapsulation of packets received from the wlan helper + */ + struct GNUNET_SERVER_MessageStreamTokenizer *data_tokenizer; + + /** + * stdout pipe handle for the gnunet-helper-transport-wlan process + */ + struct GNUNET_DISK_PipeHandle *server_stdout; + + /** + * stdout file handle for the gnunet-helper-transport-wlan process + */ + const struct GNUNET_DISK_FileHandle *server_stdout_handle; + + /** + * stdin pipe handle for the gnunet-helper-transport-wlan process + */ + struct GNUNET_DISK_PipeHandle *server_stdin; + + /** + * stdin file handle for the gnunet-helper-transport-wlan process + */ + const struct GNUNET_DISK_FileHandle *server_stdin_handle; + + /** + * ID of the gnunet-wlan-server std read task + */ + GNUNET_SCHEDULER_TaskIdentifier server_read_task; + + /** + * ID of the gnunet-wlan-server std read task + */ + GNUNET_SCHEDULER_TaskIdentifier server_write_task; + + /** + * ID of the delay task for writing + */ + GNUNET_SCHEDULER_TaskIdentifier server_write_delay_task; + + /** + * The process id of the wlan process + */ + struct GNUNET_OS_Process *server_proc; + + /** + * The interface of the wlan card given to us by the user. + */ + char *interface; + + /** + * Mode of operation for the helper, 0 = normal, 1 = first loopback, 2 = second loopback + */ + long long unsigned int testmode; + + /** + * The mac_address of the wlan card given to us by the helper. + */ + struct GNUNET_TRANSPORT_WLAN_MacAddress mac_address; + + /** + * Sessions currently pending for transmission + * to a peer, if any. + */ + struct Sessionqueue *pending_Sessions_head; + + /** + * Sessions currently pending for transmission + * to a peer (tail), if any. + */ + struct Sessionqueue *pending_Sessions_tail; + + /** + * number of pending sessions + */ + unsigned int pendingsessions; + + /** + * Messages in the sending queues + */ + int pending_Fragment_Messages; + + /** + * messages ready for send, head + */ + struct FragmentMessage_queue *sending_messages_head; + /** + * messages ready for send, tail + */ + struct FragmentMessage_queue *sending_messages_tail; + /** + * time of the next "hello-beacon" + */ + struct GNUNET_TIME_Absolute beacon_time; + + /** + * queue to send acks for received fragments (head) + */ + struct AckSendQueue *ack_send_queue_head; + + /** + * queue to send acks for received fragments (tail) + */ + struct AckSendQueue *ack_send_queue_tail; + + /** + * Tracker for bandwidth limit + */ + struct GNUNET_BANDWIDTH_Tracker tracker; + + /** + * saves the current state of the helper process + */ + int helper_is_running; +}; + +/** + * Struct to store data if file write did not accept the whole packet + */ +struct Finish_send +{ + /** + * pointer to the global plugin struct + */ + struct Plugin *plugin; + + /** + * head of the next part to send to the helper + */ + char *head_of_next_write; + + /** + * Start of the message to send, needed for free + */ + struct GNUNET_MessageHeader *msgstart; + + /** + * rest size to send + */ + ssize_t size; +}; + +/** + * Queue of sessions, for the general session queue and the pending session queue + */ +//TODO DOXIGEN +struct Sessionqueue +{ + struct Sessionqueue *next; + struct Sessionqueue *prev; + struct Session *content; +#if !HAVE_UNALIGNED_64_ACCESS + void *dummy; /* for alignment, see #1909 */ +#endif +}; + +/** + * Queue of fragmented messages, for the sending queue of the plugin + */ +//TODO DOXIGEN +struct FragmentMessage_queue +{ + struct FragmentMessage_queue *next; + struct FragmentMessage_queue *prev; + struct FragmentMessage *content; +}; + +/** + * Queue for the fragments received + */ +//TODO DOXIGEN +struct Receive_Fragment_Queue +{ + struct Receive_Fragment_Queue *next; + struct Receive_Fragment_Queue *prev; + uint16_t num; + const char *msg; + uint16_t size; + struct Radiotap_rx rxinfo; +}; + +//TODO DOXIGEN +struct MacEndpoint_id_fragment_triple +{ + struct MacEndpoint *endpoint; + uint32_t message_id; + struct FragmentMessage *fm; +}; + +//TODO DOXIGEN +struct Plugin_Session_pair +{ + struct Plugin *plugin; + struct Session *session; +}; + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Header for messages which need fragmentation + */ +struct WlanHeader +{ + + struct GNUNET_MessageHeader header; + + /** + * checksum/error correction + */ + uint32_t crc GNUNET_PACKED; + + /** + * To whom are we talking to (set to our identity + * if we are still waiting for the welcome message) + */ + struct GNUNET_PeerIdentity target; + + /** + * Where the packet came from + */ + struct GNUNET_PeerIdentity source; + +// followed by payload + +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Information kept for each message that is yet to + * be transmitted. + */ +struct PendingMessage +{ + /** + * dll next + */ + struct PendingMessage *next; + /** + * dll prev + */ + struct PendingMessage *prev; + + /** + * The pending message + */ + struct WlanHeader *msg; + + /** + * Size of the message + */ + size_t message_size; + + /** + * Continuation function to call once the message + * has been sent. Can be NULL if there is no + * continuation to call. + */ + GNUNET_TRANSPORT_TransmitContinuation transmit_cont; + + /** + * Cls for transmit_cont + */ + void *transmit_cont_cls; + + /** + * Timeout value for the pending message. + */ + struct GNUNET_TIME_Absolute timeout; + +}; + +/** + * Queue for acks to send for fragments recived + */ +struct AckSendQueue +{ + + /** + * next ack in the ack send queue + */ + struct AckSendQueue *next; + /** + * previous ack in the ack send queue + */ + struct AckSendQueue *prev; + /** + * pointer to the session this ack belongs to + */ + struct MacEndpoint *endpoint; + /** + * ID of message, to distinguish between the messages, picked randomly. + */ + uint32_t message_id; + + /** + * msg to send + */ + struct GNUNET_MessageHeader *hdr; + /** + * pointer to the ieee wlan header + */ + struct ieee80211_frame *ieeewlanheader; + /** + * pointer to the radiotap header + */ + struct Radiotap_Send *radioHeader; +}; + +/** + * Session infos gathered from a messages + */ +struct Session_light +{ + /** + * the session this message belongs to + */ + struct Session *session; + /** + * peer mac address + */ + struct GNUNET_TRANSPORT_WLAN_MacAddress addr; + + /** + * mac endpoint + */ + struct MacEndpoint *macendpoint; +}; + +/** + * Session handle for connections. + */ +struct Session +{ + + /** + * API requirement. + */ + struct SessionHeader header; + + /** + * Message currently pending for transmission + * to this peer, if any. head + */ + struct PendingMessage *pending_message_head; + + /** + * Message currently pending for transmission + * to this peer, if any. tail + */ + struct PendingMessage *pending_message_tail; + + /** + * To whom are we talking to (set to our identity + * if we are still waiting for the welcome message) + */ + struct GNUNET_PeerIdentity target; + + /** + * Address of the other peer (either based on our 'connect' + * call or on our 'accept' call). + */ + void *connect_addr; + + /** + * Last activity on this connection. Used to select preferred + * connection and timeout + */ + struct GNUNET_TIME_Absolute last_activity; + + /** + * Timeout task. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * peer connection + */ + struct MacEndpoint *mac; + + /** + * count of messages in the fragment out queue for this session + */ + + int fragment_messages_out_count; + +}; + +/** + * Struct to represent one network card connection + */ +struct MacEndpoint +{ + /** + * Pointer to the global plugin struct. + */ + struct Plugin *plugin; + /** + * Struct to hold the session reachable over this mac; head + */ + struct Sessionqueue *sessions_head; + /** + * Struct to hold the session reachable over this mac; tail + */ + struct Sessionqueue *sessions_tail; + /** + * Messages currently sending + * to a peer, if any. + */ + struct FragmentMessage *sending_messages_head; + + /** + * Messages currently sending + * to a peer (tail), if any. + */ + struct FragmentMessage *sending_messages_tail; + /** + * dll next + */ + struct MacEndpoint *next; + /** + * dll prev + */ + struct MacEndpoint *prev; + + /** + * peer mac address + */ + struct GNUNET_TRANSPORT_WLAN_MacAddress addr; + + /** + * Defrag context for this mac endpoint + */ + struct GNUNET_DEFRAGMENT_Context *defrag; + + /** + * count of messages in the fragment out queue for this mac endpoint + */ + + int fragment_messages_out_count; + + //TODO DOXIGEN + uint8_t rate; + uint16_t tx_power; + uint8_t antenna; + + /** + * Duplicates received + */ + int dups; + + /** + * Fragments received + */ + int fragc; + + /** + * Acks received + */ + int acks; + + /** + * Last activity on this endpoint. Used to select preferred + * connection. + */ + struct GNUNET_TIME_Absolute last_activity; + + /** + * Timeout task. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; +}; + +/** + * Struct for Messages in the fragment queue + */ +struct FragmentMessage +{ + + /** + * Session this message belongs to + */ + struct Session *session; + + /** + * This is a doubly-linked list. + */ + struct FragmentMessage *next; + + /** + * This is a doubly-linked list. + */ + struct FragmentMessage *prev; + + /** + * Fragmentation context + */ + struct GNUNET_FRAGMENT_Context *fragcontext; + + /** + * Timeout value for the message. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Timeout task. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * Fragment to send + */ + char *frag; + + /** + * size of message + */ + size_t size; + + /** + * pointer to the ieee wlan header + */ + struct ieee80211_frame *ieeewlanheader; + /** + * pointer to the radiotap header + */ + struct Radiotap_Send *radioHeader; +}; + +static void +do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +static void +free_session (struct Plugin *plugin, struct Sessionqueue *queue, + int do_free_macendpoint); + +static struct MacEndpoint * +create_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr); + +static void +finish_sending (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Generates a nice hexdump of a memory area. + * + * \param mem pointer to memory to dump + * \param length how many bytes to dump + */ +static void +hexdump (const void *mem, unsigned length) +{ + char line[80]; + char *src = (char *) mem; + + printf ("dumping %u bytes from %p\r\n" + " 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF\r\n", + length, src); + unsigned i; + int j; + + for (i = 0; i < length; i += 16, src += 16) + { + char *t = line; + + t += sprintf (t, "%04x: ", i); + for (j = 0; j < 16; j++) + { + if (i + j < length) + t += sprintf (t, "%02X", src[j] & 0xff); + else + t += sprintf (t, " "); + + t += sprintf (t, (j % 2) ? " " : "-"); + } + + t += sprintf (t, " "); + for (j = 0; j < 16; j++) + { + if (i + j < length) + { + if (isprint ((unsigned char) src[j])) + t += sprintf (t, "%c", src[j]); + else + t += sprintf (t, "."); + } + else + { + t += sprintf (t, " "); + } + } + + t += sprintf (t, "\r\n"); + printf ("%s", line); + } +} + +/** + * Function to find a MacEndpoint with a specific mac addr + * @param plugin pointer to the plugin struct + * @param addr pointer to the mac address + * @param create_new GNUNET_YES if a new end point should be created + * @return + */ +static struct MacEndpoint * +get_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr, + int create_new) +{ + struct MacEndpoint *queue = plugin->mac_head; + + while (queue != NULL) + { + //GNUNET_assert (queue->sessions_head != NULL); + if (memcmp (addr, &queue->addr, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0) + return queue; /* session found */ + queue = queue->next; + } + + if (create_new == GNUNET_YES) + { + return create_macendpoint (plugin, addr); + } + else + { + return NULL; + } + +} + +/** + * search for a session with the macendpoint and peer id + * + * @param plugin pointer to the plugin struct + * @param endpoint pointer to the mac endpoint of the peer + * @param peer pointer to the peerid + * @return returns the session + */ +static struct Session * +search_session (struct Plugin *plugin, const struct MacEndpoint *endpoint, + const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_assert (endpoint != NULL); + struct Sessionqueue *queue = endpoint->sessions_head; + + while (queue != NULL) + { + GNUNET_assert (queue->content != NULL); + if (memcmp + (peer, &queue->content->target, + sizeof (struct GNUNET_PeerIdentity)) == 0) + return queue->content; /* session found */ + queue = queue->next; + } + return NULL; +} + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure + * @param addr binary address + * @param addrlen length of the address + * @return string representing the same address + */ +static const char * +wlan_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) +{ + static char ret[40]; + const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac; + + if (addrlen != sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) + { + GNUNET_break (0); + return NULL; + } + mac = addr; + GNUNET_snprintf (ret, sizeof (ret), "%s Mac-Address %X:%X:%X:%X:%X:%X", + PROTOCOL_PREFIX, mac->mac[0], mac->mac[1], mac->mac[2], + mac->mac[3], mac->mac[4], mac->mac[5]); + + return ret; +} + +/** + * Function for the scheduler if a session times out + * @param cls pointer to the Sessionqueue + * @param tc pointer to the GNUNET_SCHEDULER_TaskContext + */ +static void +session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Sessionqueue *queue = cls; + + GNUNET_assert (queue != NULL); + GNUNET_assert (queue->content != NULL); + queue->content->timeout_task = GNUNET_SCHEDULER_NO_TASK; + if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + { + return; + } + if (GNUNET_TIME_absolute_get_remaining + (GNUNET_TIME_absolute_add + (queue->content->last_activity, SESSION_TIMEOUT)).rel_value == 0) + { + + GNUNET_assert (queue->content->mac != NULL); + GNUNET_assert (queue->content->mac->plugin != NULL); + GNUNET_STATISTICS_update (queue->content->mac->plugin->env->stats, + _("# wlan session timeouts"), 1, GNUNET_NO); + free_session (queue->content->mac->plugin, queue, GNUNET_YES); + } + else + { + queue->content->timeout_task = + GNUNET_SCHEDULER_add_delayed (SESSION_TIMEOUT, &session_timeout, queue); + } +} + +/** + * create a new session + * + * @param plugin pointer to the plugin struct + * @param endpoint pointer to the mac endpoint of the peer + * @param peer peer identity to use for this session + * @return returns the session + */ +static struct Session * +create_session (struct Plugin *plugin, struct MacEndpoint *endpoint, + const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_assert (endpoint != NULL); + GNUNET_assert (plugin != NULL); + GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan session created"), 1, + GNUNET_NO); + struct Sessionqueue *queue = + GNUNET_malloc (sizeof (struct Sessionqueue) + sizeof (struct Session)); + + GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head, + endpoint->sessions_tail, queue); + + queue->content = (struct Session *) &queue[1]; + queue->content->mac = endpoint; + queue->content->target = *peer; + queue->content->last_activity = GNUNET_TIME_absolute_get (); + queue->content->timeout_task = + GNUNET_SCHEDULER_add_delayed (SESSION_TIMEOUT, &session_timeout, queue); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "New session %p with endpoint %p: %s\n", queue->content, + endpoint, wlan_plugin_address_to_string (NULL, + endpoint->addr.mac, + 6)); + return queue->content; +} + +/** + * Get session from address, create if no session exists + * + * @param plugin pointer to the plugin struct + * @param addr pointer to the mac address of the peer + * @param peer pointer to the peerid + * @return returns the session + */ +static struct Session * +get_session (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr, + const struct GNUNET_PeerIdentity *peer) +{ + struct MacEndpoint *mac; + + mac = get_macendpoint (plugin, addr, GNUNET_YES); + struct Session *session = search_session (plugin, mac, peer); + + if (session != NULL) + return session; + return create_session (plugin, mac, peer); +} + +/** + * Queue the session to send data + * checks if there is a message pending + * checks if this session is not allready in the queue + * @param plugin pointer to the plugin + * @param session pointer to the session to add + */ +static void +queue_session (struct Plugin *plugin, struct Session *session) +{ + struct Sessionqueue *queue = plugin->pending_Sessions_head; + + if (session->pending_message_head != NULL) + { + while (queue != NULL) + { + // content is never NULL + GNUNET_assert (queue->content != NULL); + // is session already in queue? + if (session == queue->content) + { + return; + } + // try next + queue = queue->next; + } + + // Session is not in the queue + + queue = GNUNET_malloc (sizeof (struct Sessionqueue)); + queue->content = session; + + //insert at the tail + GNUNET_CONTAINER_DLL_insert_tail (plugin->pending_Sessions_head, + plugin->pending_Sessions_tail, queue); + plugin->pendingsessions++; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), + plugin->pendingsessions, GNUNET_NO); + } + +} + +/** + * Function to schedule the write task, executed after a delay + * @param cls pointer to the plugin struct + * @param tc GNUNET_SCHEDULER_TaskContext pointer + */ +static void +delay_fragment_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + + plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + // GNUNET_TIME_UNIT_FOREVER_REL is needed to clean up old msg + if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK) + { + plugin->server_write_task = + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + plugin->server_stdin_handle, + &do_transmit, plugin); + } +} + +/** + * Function to calculate the time of the next periodic "hello-beacon" + * @param plugin pointer to the plugin struct + */ +static void +set_next_beacon_time (struct Plugin *const plugin) +{ + //under 10 known peers: once a second + if (plugin->mac_count < 10) + { + plugin->beacon_time = + GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + HELLO_BEACON_SCALING_FACTOR)); + } + //under 30 known peers: every 10 seconds + else if (plugin->mac_count < 30) + { + plugin->beacon_time = + GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + 10 * HELLO_BEACON_SCALING_FACTOR)); + } + //over 30 known peers: once a minute + else + { + plugin->beacon_time = + GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, + HELLO_BEACON_SCALING_FACTOR)); + } +} + +/** + * Function to set the timer for the next timeout of the fragment queue + * @param plugin the handle to the plugin struct + */ +static void +set_next_send (struct Plugin *const plugin) +{ + struct GNUNET_TIME_Relative next_send; + + //abort if helper is not running + if (plugin->helper_is_running == GNUNET_NO) + { + return; + } + + //cancel old task + if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_write_delay_task); + plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK; + } + + //check if some acks are in the queue + if (plugin->ack_send_queue_head != NULL) + { + next_send = GNUNET_TIME_UNIT_ZERO; + } + + //check if there are some fragments in the queue + else if (plugin->sending_messages_head != NULL) + { + next_send = GNUNET_TIME_UNIT_ZERO; + } + else + { + next_send = GNUNET_TIME_absolute_get_remaining (plugin->beacon_time); + } + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Next packet is send in: %u\n", next_send.rel_value); + if (next_send.rel_value == GNUNET_TIME_UNIT_ZERO.rel_value) + { + if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK) + { + plugin->server_write_task = + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + plugin->server_stdin_handle, + &do_transmit, plugin); + } + } + else + { + if (plugin->server_write_delay_task == GNUNET_SCHEDULER_NO_TASK) + { + plugin->server_write_delay_task = + GNUNET_SCHEDULER_add_delayed (next_send, &delay_fragment_task, + plugin); + } + } +} + +/** + * Function to get the next queued Session, removes the session from the queue + * @param plugin pointer to the plugin struct + * @return pointer to the session found, returns NULL if there is now session in the queue + */ +static struct Session * +get_next_queue_session (struct Plugin *plugin) +{ + struct Session *session; + struct Sessionqueue *sessionqueue; + struct Sessionqueue *sessionqueue_alt; + struct PendingMessage *pm; + + sessionqueue = plugin->pending_Sessions_head; + + while (sessionqueue != NULL) + { + session = sessionqueue->content; + + GNUNET_assert (session != NULL); + pm = session->pending_message_head; + + if (pm == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, + "pending message is empty, should not happen. session %p\n", + session); + sessionqueue_alt = sessionqueue; + sessionqueue = sessionqueue->next; + plugin->pendingsessions--; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), + plugin->pendingsessions, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head, + plugin->pending_Sessions_tail, + sessionqueue_alt); + + GNUNET_free (sessionqueue_alt); + continue; + + } + + //check for message timeout + if (GNUNET_TIME_absolute_get_remaining (pm->timeout).rel_value > 0) + { + //check if session has no message in the fragment queue + if ((session->mac->fragment_messages_out_count < + FRAGMENT_QUEUE_MESSAGES_OUT_PER_MACENDPOINT) && + (session->fragment_messages_out_count < + FRAGMENT_QUEUE_MESSAGES_OUT_PER_SESSION)) + { + plugin->pendingsessions--; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), + plugin->pendingsessions, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head, + plugin->pending_Sessions_tail, + sessionqueue); + GNUNET_free (sessionqueue); + + return session; + } + else + { + sessionqueue = sessionqueue->next; + } + } + else + { + GNUNET_CONTAINER_DLL_remove (session->pending_message_head, + session->pending_message_tail, pm); + + //call the cont func that it did not work + if (pm->transmit_cont != NULL) + pm->transmit_cont (pm->transmit_cont_cls, &(session->target), + GNUNET_SYSERR); + GNUNET_free (pm->msg); + GNUNET_free (pm); + + if (session->pending_message_head == NULL) + { + sessionqueue_alt = sessionqueue; + sessionqueue = sessionqueue->next; + plugin->pendingsessions--; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), + plugin->pendingsessions, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head, + plugin->pending_Sessions_tail, + sessionqueue_alt); + + GNUNET_free (sessionqueue_alt); + } + } + + } + return NULL; +} + +/** + * frees the space of a message in the fragment queue (send queue) + * @param plugin the plugin struct + * @param fm message to free + */ +static void +free_fragment_message (struct Plugin *plugin, struct FragmentMessage *fm) +{ + struct Session *session = fm->session; + struct MacEndpoint *endpoint = session->mac; + struct FragmentMessage_queue *fmq; + struct FragmentMessage_queue *fmq_next; + + fmq = plugin->sending_messages_head; + while (fmq != NULL) + { + fmq_next = fmq->next; + if (fmq->content == fm) + { + GNUNET_CONTAINER_DLL_remove (plugin->sending_messages_head, + plugin->sending_messages_tail, fmq); + GNUNET_free (fmq); + } + fmq = fmq_next; + } + + (session->mac->fragment_messages_out_count)--; + session->fragment_messages_out_count--; + plugin->pending_Fragment_Messages--; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending fragments"), + plugin->pending_Fragment_Messages, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head, + endpoint->sending_messages_tail, fm); + GNUNET_FRAGMENT_context_destroy (fm->fragcontext); + if (fm->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (fm->timeout_task); + fm->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + + GNUNET_free (fm); + + queue_session (plugin, session); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Free pending fragment messages %p, session %p\n", fm, + session); +} + +/** + * function to fill the radiotap header + * @param plugin pointer to the plugin struct + * @param endpoint pointer to the endpoint + * @param header pointer to the radiotap header + * @return GNUNET_YES at success + */ +static int +getRadiotapHeader (struct Plugin *plugin, struct MacEndpoint *endpoint, + struct Radiotap_Send *header) +{ + + if (endpoint != NULL) + { + header->rate = endpoint->rate; + header->tx_power = endpoint->tx_power; + header->antenna = endpoint->antenna; + } + else + { + header->rate = 255; + header->tx_power = 0; + header->antenna = 0; + } + + return GNUNET_YES; +} + +/** + * function to generate the wlan hardware header for one packet + * @param Header address to write the header to + * @param to_mac_addr address of the recipient + * @param plugin pointer to the plugin struct + * @param size size of the whole packet, needed to calculate the time to send the packet + * @return GNUNET_YES if there was no error + */ +static int +getWlanHeader (struct ieee80211_frame *Header, + const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr, struct Plugin *plugin, + unsigned int size) +{ + uint16_t *tmp16; + const int rate = 11000000; + + Header->i_fc[0] = IEEE80211_FC0_TYPE_DATA; + Header->i_fc[1] = 0x00; + memcpy (&Header->i_addr3, &mac_bssid_gnunet, sizeof (mac_bssid_gnunet)); + memcpy (&Header->i_addr2, plugin->mac_address.mac, + sizeof (plugin->mac_address)); + memcpy (&Header->i_addr1, to_mac_addr, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); + + tmp16 = (uint16_t *) Header->i_dur; + *tmp16 = (uint16_t) GNUNET_htole16 ((size * 1000000) / rate + 290); + Header->llc[0] = WLAN_LLC_DSAP_FIELD; + Header->llc[1] = WLAN_LLC_SSAP_FIELD; + + return GNUNET_YES; +} + + +/** + * function to add a fragment of a message to send + * @param cls FragmentMessage this message belongs to + * @param hdr pointer to the start of the message + */ +static void +add_message_for_send (void *cls, const struct GNUNET_MessageHeader *hdr) +{ + + struct FragmentMessage *fm = cls; + struct FragmentMessage_queue *fmqueue; + + GNUNET_assert (cls != NULL); + GNUNET_assert (fm->frag == NULL); + struct MacEndpoint *endpoint = fm->session->mac; + struct Plugin *plugin = endpoint->plugin; + struct GNUNET_MessageHeader *msgheader; + struct GNUNET_MessageHeader *msgheader2; + uint16_t size; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Adding fragment of message %p to send, session %p, endpoint %p, type %u\n", + fm, fm->session, endpoint, hdr->type); + size = + sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) + + sizeof (struct ieee80211_frame) + ntohs (hdr->size); + fm->frag = GNUNET_malloc (size); + fm->size = size; + + msgheader = (struct GNUNET_MessageHeader *) fm->frag; + msgheader->size = htons (size); + msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); + + fm->radioHeader = (struct Radiotap_Send *) &msgheader[1]; + fm->ieeewlanheader = (struct ieee80211_frame *) &fm->radioHeader[1]; + msgheader2 = (struct GNUNET_MessageHeader *) &fm->ieeewlanheader[1]; + memcpy (msgheader2, hdr, ntohs (hdr->size)); + + fmqueue = GNUNET_malloc (sizeof (struct FragmentMessage_queue)); + fmqueue->content = fm; + + GNUNET_CONTAINER_DLL_insert_tail (plugin->sending_messages_head, + plugin->sending_messages_tail, fmqueue); + set_next_send (plugin); +} + + +/** + * We have been notified that gnunet-helper-transport-wlan has written something to stdout. + * Handle the output, then reschedule this function to be called again once + * more is available. + * + * @param cls the plugin handle + * @param tc the scheduling context + */ +static void +wlan_plugin_helper_read (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + + plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + char mybuf[WLAN_MTU + sizeof (struct GNUNET_MessageHeader)]; + ssize_t bytes; + + bytes = + GNUNET_DISK_file_read (plugin->server_stdout_handle, mybuf, + sizeof (mybuf)); + if (bytes <= 0) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + _ + ("Finished reading from gnunet-helper-transport-wlan stdout with code: %d\n"), + bytes); + return; + } + GNUNET_SERVER_mst_receive (plugin->suid_tokenizer, NULL, mybuf, bytes, + GNUNET_NO, GNUNET_NO); + + GNUNET_assert (plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK); + plugin->server_read_task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + plugin->server_stdout_handle, + &wlan_plugin_helper_read, plugin); +} + +/** + * Start the gnunet-helper-transport-wlan process. + * + * @param plugin the transport plugin + * @return GNUNET_YES if process was started, GNUNET_SYSERR on error + */ +static int +wlan_transport_start_wlan_helper (struct Plugin *plugin) +{ + const char *filenamehw = "gnunet-helper-transport-wlan"; + const char *filenameloopback = "gnunet-helper-transport-wlan-dummy"; + char *absolute_filename = NULL; + + if (plugin->helper_is_running == GNUNET_YES) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "wlan_transport_start_wlan_helper not needed, helper already running!"); + return GNUNET_YES; + } + + plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); + if (plugin->server_stdout == NULL) + return GNUNET_SYSERR; + + plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); + if (plugin->server_stdin == NULL) + return GNUNET_SYSERR; + + if ((plugin->testmode == 1) || (plugin->testmode == 2)) + { + if (GNUNET_OS_check_helper_binary (filenameloopback) == GNUNET_YES) + { + absolute_filename = GNUNET_strdup (filenameloopback); + } + else + { + char cwd[FILENAME_MAX]; + + GNUNET_assert (getcwd (cwd, sizeof (cwd)) != NULL); + + GNUNET_asprintf (&absolute_filename, "%s%s%s", cwd, DIR_SEPARATOR_STR, + filenameloopback); + + if (GNUNET_DISK_file_test (filenameloopback) != GNUNET_YES) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, + "Helper `%s' not found! %i\n", absolute_filename); + GNUNET_break (0); + } + } + } + + /* Start the server process */ + + if (plugin->testmode == 0) + { + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Starting gnunet-helper-transport-wlan process cmd: %s %s %i\n", + filenamehw, plugin->interface, plugin->testmode); + if (GNUNET_OS_check_helper_binary (filenamehw) == GNUNET_YES) + { + plugin->server_proc = + GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout, + filenamehw, filenamehw, plugin->interface, + NULL); + } + else if (GNUNET_OS_check_helper_binary (filenamehw) == GNUNET_NO) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, + "gnunet-helper-transport-wlan is not suid, please change it or look at the doku\n"); + GNUNET_break (0); + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, + "gnunet-helper-transport-wlan not found, please look if it exists and is the $PATH variable!\n"); + GNUNET_break (0); + } + + } + else if (plugin->testmode == 1) + { + + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME, + "Starting gnunet-helper-transport-wlan-dummy loopback 1 process cmd: %s %s %i\n", + absolute_filename, plugin->interface, plugin->testmode); + plugin->server_proc = + GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout, + absolute_filename, absolute_filename, "1", + NULL); + if (plugin->server_proc == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, + "`%s' not found, please look if it exists and is in the $PATH variable!\n", + absolute_filename); + GNUNET_break (0); + } + } + else if (plugin->testmode == 2) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME, + "Starting gnunet-helper-transport-wlan-dummy loopback 2 process cmd: %s %s %i\n", + absolute_filename, plugin->interface, plugin->testmode); + plugin->server_proc = + GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout, + absolute_filename, absolute_filename, "2", + NULL); + if (plugin->server_proc == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, + "`%s' not found, please look if it exists and is in the $PATH variable!\n", + absolute_filename); + GNUNET_break (0); + } + } + if (absolute_filename != NULL) + GNUNET_free (absolute_filename); + if (plugin->server_proc == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Failed to start gnunet-helper-transport-wlan process\n"); + return GNUNET_SYSERR; + } + + + + /* Close the write end of the read pipe */ + GNUNET_DISK_pipe_close_end (plugin->server_stdout, + GNUNET_DISK_PIPE_END_WRITE); + + /* Close the read end of the write pipe */ + GNUNET_DISK_pipe_close_end (plugin->server_stdin, GNUNET_DISK_PIPE_END_READ); + + plugin->server_stdout_handle = + GNUNET_DISK_pipe_handle (plugin->server_stdout, + GNUNET_DISK_PIPE_END_READ); + plugin->server_stdin_handle = + GNUNET_DISK_pipe_handle (plugin->server_stdin, + GNUNET_DISK_PIPE_END_WRITE); + + GNUNET_assert (plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Adding server_read_task for the gnunet-helper-transport-wlan\n"); + plugin->server_read_task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + plugin->server_stdout_handle, + &wlan_plugin_helper_read, plugin); + + plugin->helper_is_running = GNUNET_YES; + return GNUNET_YES; +} + +/** + * Stops the gnunet-helper-transport-wlan process. + * + * @param plugin the transport plugin + * @return GNUNET_YES if process was started, GNUNET_SYSERR on error + */ +static int +wlan_transport_stop_wlan_helper (struct Plugin *plugin) +{ + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Stoping WLAN helper process\n"); + + if (plugin->helper_is_running == GNUNET_NO) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "wlan_transport_stop_wlan_helper not needed, helper already stopped!"); + return GNUNET_YES; + } + + if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_write_delay_task); + plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (plugin->server_write_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_write_task); + plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (plugin->server_read_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_read_task); + plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK; + } + + GNUNET_DISK_pipe_close (plugin->server_stdout); + GNUNET_DISK_pipe_close (plugin->server_stdin); + GNUNET_OS_process_kill (plugin->server_proc, SIGKILL); + GNUNET_OS_process_wait (plugin->server_proc); + GNUNET_OS_process_close (plugin->server_proc); + + plugin->helper_is_running = GNUNET_NO; + + return GNUNET_YES; +} + +/** + * function for delayed restart of the helper process + * @param cls Finish_send struct if message should be finished + * @param tc TaskContext + */ +static void +delay_restart_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Finish_send *finish = cls; + struct Plugin *plugin; + + plugin = finish->plugin; + + plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + { + GNUNET_free_non_null (finish->msgstart); + GNUNET_free (finish); + return; + } + + wlan_transport_start_wlan_helper (plugin); + + if (finish->size != 0) + { + plugin->server_write_task = + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + plugin->server_stdin_handle, + &finish_sending, finish); + } + else + { + set_next_send (plugin); + GNUNET_free_non_null (finish->msgstart); + GNUNET_free (finish); + } + +} + +/** + * Function to restart the helper + * @param plugin pointer to the global plugin struct + * @param finish pointer to the Finish_send struct to finish + */ +static void +restart_helper (struct Plugin *plugin, struct Finish_send *finish) +{ + static struct GNUNET_TIME_Relative next_try = { 1000 }; + GNUNET_assert (finish != NULL); + + wlan_transport_stop_wlan_helper (plugin); + plugin->server_write_task = + GNUNET_SCHEDULER_add_delayed (next_try, &delay_restart_helper, finish); + GNUNET_TIME_relative_multiply (next_try, HELPER_RESTART_SCALING_FACTOR); + +} + +/** + * function to finish a sending if not all could have been writen befor + * @param cls pointer to the Finish_send struct + * @param tc TaskContext + */ +static void +finish_sending (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Finish_send *finish = cls; + struct Plugin *plugin; + ssize_t bytes; + + plugin = finish->plugin; + plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + { + GNUNET_free (finish->msgstart); + GNUNET_free (finish); + return; + } + bytes = + GNUNET_DISK_file_write (plugin->server_stdin_handle, + finish->head_of_next_write, finish->size); + + if (bytes != finish->size) + { + if (bytes != GNUNET_SYSERR) + { + finish->head_of_next_write += bytes; + finish->size -= bytes; + plugin->server_write_task = + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + plugin->server_stdin_handle, + &finish_sending, finish); + } + else + { + restart_helper (plugin, finish); + } + } + else + { + GNUNET_free (finish->msgstart); + GNUNET_free (finish); + set_next_send (plugin); + } +} + +/** + * function to send a hello beacon + * @param plugin pointer to the plugin struct + */ +static void +send_hello_beacon (struct Plugin *plugin) +{ + uint16_t size; + ssize_t bytes; + uint16_t hello_size; + struct GNUNET_MessageHeader *msgheader; + struct ieee80211_frame *ieeewlanheader; + struct Radiotap_Send *radioHeader; + struct GNUNET_MessageHeader *msgheader2; + const struct GNUNET_MessageHeader *hello; + struct Finish_send *finish; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Sending hello beacon\n"); + + GNUNET_assert (plugin != NULL); + + GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan hello beacons send"), + 1, GNUNET_NO); + + hello = plugin->env->get_our_hello (); + hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello); + GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU); + size = + sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) + + sizeof (struct ieee80211_frame) + hello_size; + + msgheader = GNUNET_malloc (size); + msgheader->size = htons (size); + msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); + + radioHeader = (struct Radiotap_Send *) &msgheader[1]; + getRadiotapHeader (plugin, NULL, radioHeader); + ieeewlanheader = (struct ieee80211_frame *) &radioHeader[1]; + getWlanHeader (ieeewlanheader, &bc_all_mac, plugin, size); + + msgheader2 = (struct GNUNET_MessageHeader *) &ieeewlanheader[1]; + /*msgheader2->size = + * htons (GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello) + + * sizeof (struct GNUNET_MessageHeader)); + * + * msgheader2->type = htons (GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT); */ + memcpy (msgheader2, hello, hello_size); + + bytes = GNUNET_DISK_file_write (plugin->server_stdin_handle, msgheader, size); + + if (bytes == GNUNET_SYSERR) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, + _ + ("Error writing to wlan helper. errno == %d, ERROR: %s\n"), + errno, strerror (errno)); + finish = GNUNET_malloc (sizeof (struct Finish_send)); + finish->plugin = plugin; + finish->head_of_next_write = NULL; + finish->size = 0; + finish->msgstart = NULL; + restart_helper (plugin, finish); + + set_next_beacon_time (plugin); + + } + else + { + GNUNET_assert (bytes == size); + set_next_beacon_time (plugin); + set_next_send (plugin); + } + GNUNET_free (msgheader); + + +} + +/** + * function to add an ack to send it for a received fragment + * @param cls MacEndpoint this ack belongs to + * @param msg_id id of the message + * @param hdr pointer to the hdr where the ack is stored + * + */ +static void +add_ack_for_send (void *cls, uint32_t msg_id, + const struct GNUNET_MessageHeader *hdr) +{ + + struct AckSendQueue *ack; + + GNUNET_assert (cls != NULL); + struct MacEndpoint *endpoint = cls; + struct Plugin *plugin = endpoint->plugin; + struct GNUNET_MessageHeader *msgheader; + struct GNUNET_MessageHeader *msgheader2; + uint16_t size; + + size = + sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) + + sizeof (struct ieee80211_frame) + ntohs (hdr->size) + + sizeof (struct AckSendQueue); + + ack = GNUNET_malloc (size); + ack->message_id = msg_id; + ack->endpoint = endpoint; + + size = + sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) + + sizeof (struct ieee80211_frame) + ntohs (hdr->size); + + msgheader = (struct GNUNET_MessageHeader *) &ack[1]; + ack->hdr = (struct GNUNET_MessageHeader *) &ack[1]; + msgheader->size = htons (size); + msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA); + + ack->radioHeader = (struct Radiotap_Send *) &msgheader[1]; + ack->ieeewlanheader = (struct ieee80211_frame *) &(ack->radioHeader)[1]; + msgheader2 = (struct GNUNET_MessageHeader *) &(ack->ieeewlanheader)[1]; + memcpy (msgheader2, hdr, ntohs (hdr->size)); + + GNUNET_CONTAINER_DLL_insert_tail (plugin->ack_send_queue_head, + plugin->ack_send_queue_tail, ack); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Adding ack with message id %u to send, AckSendQueue %p, endpoint %p\n", + msg_id, ack, endpoint); + set_next_send (plugin); +} + +/** + * Function for the scheduler if a FragmentMessage times out + * @param cls pointer to the FragmentMessage + * @param tc pointer to the GNUNET_SCHEDULER_TaskContext + */ +static void +fragmentmessage_timeout (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct FragmentMessage *fm = cls; + + GNUNET_assert (fm != NULL); + fm->timeout_task = GNUNET_SCHEDULER_NO_TASK; + if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + { + return; + } + free_fragment_message (fm->session->mac->plugin, fm); +} + +/** + * Function to check if there is some space in the fragment queue + * inserts a message if space is available + * @param plugin the plugin struct + */ + +static void +check_fragment_queue (struct Plugin *plugin) +{ + struct Session *session; + struct FragmentMessage *fm; + struct GNUNET_PeerIdentity pid; + + struct PendingMessage *pm; + + if (plugin->pending_Fragment_Messages < FRAGMENT_QUEUE_SIZE) + { + session = get_next_queue_session (plugin); + if (session != NULL) + { + pm = session->pending_message_head; + GNUNET_assert (pm != NULL); + GNUNET_CONTAINER_DLL_remove (session->pending_message_head, + session->pending_message_tail, pm); + session->mac->fragment_messages_out_count++; + session->fragment_messages_out_count++; + plugin->pending_Fragment_Messages++; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending fragments"), + plugin->pending_Fragment_Messages, GNUNET_NO); + + fm = GNUNET_malloc (sizeof (struct FragmentMessage)); + fm->session = session; + fm->timeout.abs_value = pm->timeout.abs_value; + fm->frag = NULL; + fm->fragcontext = + GNUNET_FRAGMENT_context_create (plugin->env->stats, WLAN_MTU, + &plugin->tracker, + GNUNET_TIME_UNIT_SECONDS, + &(pm->msg->header), + &add_message_for_send, fm); + fm->timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (fm->timeout), fragmentmessage_timeout, + fm); + GNUNET_CONTAINER_DLL_insert_tail (session->mac->sending_messages_head, + session->mac->sending_messages_tail, + fm); + + if (pm->transmit_cont != NULL) + { + pid = session->target; + pm->transmit_cont (pm->transmit_cont_cls, &pid, GNUNET_OK); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "called pm->transmit_cont for %p\n", session); + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "no pm->transmit_cont for %p\n", session); + } + GNUNET_free (pm); + + if (session->pending_message_head != NULL) + { + //requeue session + queue_session (plugin, session); + } + + } + } + + //check if timeout changed + set_next_send (plugin); +} + +/** + * Function to send an ack, does not free the ack + * @param plugin pointer to the plugin + */ +static void +send_ack (struct Plugin *plugin) +{ + + ssize_t bytes; + struct AckSendQueue *ack; + struct Finish_send *finish; + + ack = plugin->ack_send_queue_head; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Sending ack for message_id %u for mac endpoint %p, size %u\n", + ack->message_id, ack->endpoint, + ntohs (ack->hdr->size) - sizeof (struct Radiotap_Send)); + GNUNET_assert (plugin != NULL); + GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan acks send"), 1, + GNUNET_NO); + + getRadiotapHeader (plugin, ack->endpoint, ack->radioHeader); + getWlanHeader (ack->ieeewlanheader, &ack->endpoint->addr, plugin, + ntohs (ack->hdr->size)); + + bytes = + GNUNET_DISK_file_write (plugin->server_stdin_handle, ack->hdr, + ntohs (ack->hdr->size)); + if (bytes == GNUNET_SYSERR) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, + _ + ("Error writing to wlan helper. errno == %d, ERROR: %s\n"), + errno, strerror (errno)); + finish = GNUNET_malloc (sizeof (struct Finish_send)); + finish->plugin = plugin; + finish->head_of_next_write = NULL; + finish->size = 0; + finish->msgstart = NULL; + restart_helper (plugin, finish); + } + else + { + GNUNET_assert (bytes == ntohs (ack->hdr->size)); + GNUNET_CONTAINER_DLL_remove (plugin->ack_send_queue_head, + plugin->ack_send_queue_tail, ack); + GNUNET_free (ack); + set_next_send (plugin); + } +} + +/** + * Function called when wlan helper is ready to get some data + * + * @param cls closure + * @param tc GNUNET_SCHEDULER_TaskContext + */ +static void +do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Plugin *plugin = cls; + + GNUNET_assert (plugin != NULL); + + plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + struct Session *session; + struct FragmentMessage *fm; + struct Finish_send *finish; + struct FragmentMessage_queue *fmq; + ssize_t bytes; + + if (plugin->ack_send_queue_head != NULL) + { + send_ack (plugin); + return; + } + + //test if a "hello-beacon" has to be send + if (GNUNET_TIME_absolute_get_remaining (plugin->beacon_time).rel_value == 0) + { + send_hello_beacon (plugin); + return; + } + + if (plugin->sending_messages_head != NULL) + { + GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan fragments send"), 1, + GNUNET_NO); + + fmq = plugin->sending_messages_head; + fm = fmq->content; + GNUNET_CONTAINER_DLL_remove (plugin->sending_messages_head, + plugin->sending_messages_tail, fmq); + GNUNET_free (fmq); + + session = fm->session; + GNUNET_assert (session != NULL); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Sending GNUNET_MESSAGE_TYPE_WLAN_FRAGMENT for fragment message %p, size: %u\n", + fm, fm->size); + getRadiotapHeader (plugin, session->mac, fm->radioHeader); + getWlanHeader (fm->ieeewlanheader, &(fm->session->mac->addr), plugin, + fm->size); + + bytes = + GNUNET_DISK_file_write (plugin->server_stdin_handle, fm->frag, + fm->size); + + + if (bytes != fm->size) + { + finish = GNUNET_malloc (sizeof (struct Finish_send)); + finish->plugin = plugin; + finish->msgstart = (struct GNUNET_MessageHeader *) fm->frag; + GNUNET_assert (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK); + + if (bytes == GNUNET_SYSERR) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, + _ + ("Error writing to wlan helper. errno == %d, ERROR: %s\n"), + errno, strerror (errno)); + + finish->head_of_next_write = fm->frag; + finish->size = fm->size; + restart_helper (plugin, finish); + } + else + { + finish->head_of_next_write = fm->frag + bytes; + finish->size = fm->size - bytes; + plugin->server_write_task = + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + plugin->server_stdin_handle, + &finish_sending, finish); + } + + fm->frag = NULL; + } + else + { + GNUNET_free (fm->frag); + fm->frag = NULL; + set_next_send (plugin); + } + GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext); + return; + } + +#if 1 + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "do_transmit did nothing, should not happen!\n"); +#endif + set_next_send (plugin); +} + +/** + * Another peer has suggested an address for this + * peer and transport plugin. Check that this could be a valid + * address. If so, consider adding it to the list + * of addresses. + * + * @param cls closure + * @param addr pointer to the address + * @param addrlen length of addr + * @return GNUNET_OK if this is a plausible address for this peer + * and transport + */ +static int +wlan_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) +{ + //struct Plugin *plugin = cls; + + /* check if the address is plausible; if so, + * add it to our list! */ + + GNUNET_assert (cls != NULL); + //FIXME mitm is not checked + //Mac Address has 6 bytes + if (addrlen == 6) + { + /* TODO check for bad addresses like multicast, broadcast, etc */ + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "wlan_plugin_address_suggested got good address, size %u!\n", + addrlen); + return GNUNET_OK; + } + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "wlan_plugin_address_suggested got bad address, size %u!\n", + addrlen); + return GNUNET_SYSERR; +} + + +/** + * Creates a new outbound session the transport service will use to send data to the + * peer + * + * @param cls the plugin + * @param address the address + * @return the session or NULL of max connections exceeded + */ + +static struct Session * +wlan_plugin_get_session (void *cls, + const struct GNUNET_HELLO_Address *address) +{ + struct Plugin *plugin = cls; + struct Session * s = NULL; + + GNUNET_assert (plugin != NULL); + GNUNET_assert (address != NULL); + + if (GNUNET_OK == wlan_plugin_address_suggested (plugin, + address->address, + address->address_length)) + { + s = get_session (plugin, address->address, &address->peer); + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME, + _("Wlan Address len %d is wrong\n"), address->address_length); + return s; + } + + return s; +} + +/** + * Function that can be used by the transport service to transmit + * a message using the plugin. Note that in the case of a + * peer disconnecting, the continuation MUST be called + * prior to the disconnect notification itself. This function + * will be called with this peer's HELLO message to initiate + * a fresh connection to another peer. + * + * @param cls closure + * @param session which session must be used + * @param msgbuf the message to transmit + * @param msgbuf_size number of bytes in 'msgbuf' + * @param priority how important is the message (most plugins will + * ignore message priority and just FIFO) + * @param to how long to wait at most for the transmission (does not + * require plugins to discard the message after the timeout, + * just advisory for the desired delay; most plugins will ignore + * this as well) + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...); can be NULL + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV) + */ +static ssize_t +wlan_plugin_send (void *cls, + struct Session *session, + const char *msgbuf, size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative to, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct Plugin *plugin = cls; + struct PendingMessage *newmsg; + struct WlanHeader *wlanheader; + + GNUNET_assert (plugin != NULL); + GNUNET_assert (session != NULL); + GNUNET_assert (msgbuf_size > 0); + + //queue message: + + //queue message in session + //test if there is no other message in the "queue" + //FIXME: to many send requests + if (session->pending_message_head != NULL) + { + newmsg = session->pending_message_head; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "wlan_plugin_send: a pending message is already in the queue for this client\n remaining time to send this message is %u, queued fragment messages for this mac connection %u\n", + GNUNET_TIME_absolute_get_remaining (newmsg-> + timeout).rel_value, + session->mac->fragment_messages_out_count); + } + + newmsg = GNUNET_malloc (sizeof (struct PendingMessage)); + newmsg->msg = GNUNET_malloc (msgbuf_size + sizeof (struct WlanHeader)); + wlanheader = newmsg->msg; + //copy msg to buffer, not fragmented / segmented yet, but with message header + wlanheader->header.size = htons (msgbuf_size + sizeof (struct WlanHeader)); + wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA); + memcpy (&(wlanheader->target), &session->target, sizeof (struct GNUNET_PeerIdentity)); + memcpy (&(wlanheader->source), plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity)); + wlanheader->crc = 0; + memcpy (&wlanheader[1], msgbuf, msgbuf_size); + wlanheader->crc = + htonl (GNUNET_CRYPTO_crc32_n + ((char *) wlanheader, msgbuf_size + sizeof (struct WlanHeader))); + + newmsg->transmit_cont = cont; + newmsg->transmit_cont_cls = cont_cls; + newmsg->timeout = GNUNET_TIME_relative_to_absolute (to); + + newmsg->timeout.abs_value = newmsg->timeout.abs_value - 500; + + newmsg->message_size = msgbuf_size + sizeof (struct WlanHeader); + + GNUNET_CONTAINER_DLL_insert_tail (session->pending_message_head, + session->pending_message_tail, newmsg); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "New message for %p with size (incl wlan header) %u added\n", + session, newmsg->message_size); +#if DEBUG_WLAN > 1 + hexdump (msgbuf, GNUNET_MIN (msgbuf_size, 256)); +#endif + //queue session + queue_session (plugin, session); + + check_fragment_queue (plugin); + //FIXME not the correct size + return msgbuf_size; +} + + +/** + * function to free a mac endpoint + * @param plugin pointer to the plugin struct + * @param endpoint pointer to the MacEndpoint to free + */ +static void +free_macendpoint (struct Plugin *plugin, struct MacEndpoint *endpoint) +{ + struct Sessionqueue *sessions; + struct Sessionqueue *sessions_next; + + GNUNET_assert (endpoint != NULL); + + sessions = endpoint->sessions_head; + while (sessions != NULL) + { + sessions_next = sessions->next; + free_session (plugin, sessions, GNUNET_NO); + sessions = sessions_next; + } + + GNUNET_CONTAINER_DLL_remove (plugin->mac_head, plugin->mac_tail, endpoint); + if (endpoint->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (endpoint->timeout_task); + endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + plugin->mac_count--; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"), + plugin->mac_count, GNUNET_NO); + GNUNET_free (endpoint); + +} + +/** + * function to free a session + * @param plugin pointer to the plugin + * @param queue pointer to the sessionqueue element to free + * @param do_free_macendpoint if GNUNET_YES and mac endpoint would be empty, free mac endpoint + */ +static void +free_session (struct Plugin *plugin, struct Sessionqueue *queue, + int do_free_macendpoint) +{ + struct Sessionqueue *pendingsession; + struct Sessionqueue *pendingsession_tmp; + struct PendingMessage *pm; + struct MacEndpoint *endpoint; + struct FragmentMessage *fm; + struct FragmentMessage *fmnext; + int check = 0; + + GNUNET_assert (plugin != NULL); + GNUNET_assert (queue != NULL); + GNUNET_assert (queue->content != NULL); + + //session found + //is this session pending for send + pendingsession = plugin->pending_Sessions_head; + while (pendingsession != NULL) + { + pendingsession_tmp = pendingsession; + pendingsession = pendingsession->next; + GNUNET_assert (pendingsession_tmp->content != NULL); + if (pendingsession_tmp->content == queue->content) + { + plugin->pendingsessions--; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), + plugin->pendingsessions, GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head, + plugin->pending_Sessions_tail, + pendingsession_tmp); + GNUNET_free (pendingsession_tmp); + + GNUNET_assert (check == 0); + check = 1; + } + } + + endpoint = queue->content->mac; + fm = endpoint->sending_messages_head; + while (fm != NULL) + { + fmnext = fm->next; + if (fm->session == queue->content) + { + free_fragment_message (plugin, fm); + } + fm = fmnext; + } + + // remove PendingMessage + pm = queue->content->pending_message_head; + while (pm != NULL) + { + GNUNET_CONTAINER_DLL_remove (queue->content->pending_message_head, + queue->content->pending_message_tail, pm); + GNUNET_free (pm->msg); + GNUNET_free (pm); + pm = queue->content->pending_message_head; + } + + GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head, endpoint->sessions_tail, + queue); + //Check that no ohter session on this endpoint for this session exits + GNUNET_assert (search_session (plugin, endpoint, &queue->content->target) == + NULL); + if (endpoint->sessions_head == NULL && do_free_macendpoint == GNUNET_YES) + { + free_macendpoint (plugin, endpoint); + //check if no endpoint with the same address exists + GNUNET_assert (get_macendpoint (plugin, &endpoint->addr, GNUNET_NO) == + NULL); + } + + if (queue->content->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (queue->content->timeout_task); + queue->content->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (queue); + + check_fragment_queue (plugin); +} + +/** + * Function that can be used to force the plugin to disconnect + * from the given peer and cancel all previous transmissions + * (and their continuation). + * + * @param cls closure + * @param target peer from which to disconnect + */ +static void +wlan_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +{ + struct Plugin *plugin = cls; + struct Sessionqueue *queue; + struct Sessionqueue *queue_next; + struct MacEndpoint *endpoint = plugin->mac_head; + struct MacEndpoint *endpoint_next; + + // just look at all the session for the needed one + while (endpoint != NULL) + { + queue = endpoint->sessions_head; + endpoint_next = endpoint->next; + while (queue != NULL) + { + // content is never NULL + GNUNET_assert (queue->content != NULL); + queue_next = queue->next; + if (memcmp + (target, &(queue->content->target), + sizeof (struct GNUNET_PeerIdentity)) == 0) + { + free_session (plugin, queue, GNUNET_YES); + } + // try next + queue = queue_next; + } + endpoint = endpoint_next; + } +} + +/** + * Convert the transports address to a nice, human-readable + * format. + * + * @param cls closure + * @param type name of the transport that generated the address + * @param addr one of the addresses of the host, NULL for the last address + * the specific address format depends on the transport + * @param addrlen length of the address + * @param numeric should (IP) addresses be displayed in numeric form? + * @param timeout after how long should we give up? + * @param asc function to call on each string + * @param asc_cls closure for asc + */ +static void +wlan_plugin_address_pretty_printer (void *cls, const char *type, + const void *addr, size_t addrlen, + int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressStringCallback asc, + void *asc_cls) +{ + char *ret; + const unsigned char *input; + + //GNUNET_assert(cls !=NULL); + if (addrlen != sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) + { + /* invalid address (MAC addresses have 6 bytes) */ + //GNUNET_break (0); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Func wlan_plugin_address_pretty_printer got size: %u, worng size!\n", + addrlen); + asc (asc_cls, NULL); + return; + } + input = (const unsigned char *) addr; + GNUNET_asprintf (&ret, + "Transport %s: %s Mac-Address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X", + type, PROTOCOL_PREFIX, input[0], input[1], input[2], + input[3], input[4], input[5]); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Func wlan_plugin_address_pretty_printer got size: %u, nummeric %u, type %s; made string: %s\n", + addrlen, numeric, type, ret); + asc (asc_cls, ret); + //only one mac address per plugin + asc (asc_cls, NULL); +} + + + +/** + * handels the data after all fragments are put together + * @param cls macendpoint this messages belongs to + * @param hdr pointer to the data + */ +static void +wlan_data_message_handler (void *cls, const struct GNUNET_MessageHeader *hdr) +{ + struct MacEndpoint *endpoint = (struct MacEndpoint *) cls; + struct Plugin *plugin = endpoint->plugin; + struct WlanHeader *wlanheader; + struct Session *session; + + const struct GNUNET_MessageHeader *temp_hdr; + struct GNUNET_PeerIdentity tmpsource; + int crc; + + GNUNET_assert (plugin != NULL); + + if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_WLAN_DATA) + { + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Func wlan_data_message_handler got GNUNET_MESSAGE_TYPE_WLAN_DATA size: %u\n", + ntohs (hdr->size)); + + if (ntohs (hdr->size) < + sizeof (struct WlanHeader) + sizeof (struct GNUNET_MessageHeader)) + { + //packet not big enought + return; + } + + GNUNET_STATISTICS_update (plugin->env->stats, + _("# wlan whole messages received"), 1, + GNUNET_NO); + wlanheader = (struct WlanHeader *) hdr; + + session = search_session (plugin, endpoint, &wlanheader->source); + + temp_hdr = (const struct GNUNET_MessageHeader *) &wlanheader[1]; + crc = ntohl (wlanheader->crc); + wlanheader->crc = 0; + if (GNUNET_CRYPTO_crc32_n + ((char *) wlanheader, ntohs (wlanheader->header.size)) != crc) + { + //wrong crc, dispose message + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME, + "Wlan message header crc was wrong: %u != %u\n", + GNUNET_CRYPTO_crc32_n ((char *) wlanheader, + ntohs (wlanheader->header.size)), + crc); + hexdump ((void *) hdr, ntohs (hdr->size)); + return; + } + + //if not in session list + if (session == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "WLAN client not in session list: packet size = %u, inner size = %u, header size = %u\n", + ntohs (wlanheader->header.size), ntohs (temp_hdr->size), + sizeof (struct WlanHeader)); + //try if it is a hello message + if (ntohs (wlanheader->header.size) >= + ntohs (temp_hdr->size) + sizeof (struct WlanHeader)) + { + if (ntohs (temp_hdr->type) == GNUNET_MESSAGE_TYPE_HELLO) + { + if (GNUNET_HELLO_get_id + ((const struct GNUNET_HELLO_Message *) temp_hdr, + &tmpsource) == GNUNET_OK) + { + session = create_session (plugin, endpoint, &tmpsource); + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME, + "WLAN client not in session list and hello message is not okay\n"); + return; + } + + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME, + "WLAN client not in session list and not a hello message\n"); + return; + } + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME, + "WLAN client not in session list and message size in does not fit\npacket size = %u, inner size = %u, header size = %u\n", + ntohs (wlanheader->header.size), + ntohs (temp_hdr->size), sizeof (struct WlanHeader)); + return; + } + } + + //"receive" the message + + if (memcmp + (&wlanheader->source, &session->target, + sizeof (struct GNUNET_PeerIdentity)) != 0) + { + //wrong peer id + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "WLAN peer source id doesn't match packet peer source id: session %p\n", + session); + return; + } + + if (memcmp + (&wlanheader->target, plugin->env->my_identity, + sizeof (struct GNUNET_PeerIdentity)) != 0) + { + //wrong peer id + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "WLAN peer target id doesn't match our peer id: session %p\n", + session); + return; + } + + GNUNET_SERVER_mst_receive (plugin->data_tokenizer, session, + (const char *) temp_hdr, + ntohs (hdr->size) - sizeof (struct WlanHeader), + GNUNET_YES, GNUNET_NO); + + return; + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME, + "wlan_data_message_handler got wrong message type: %u\n", + ntohs (hdr->size)); + return; + } +} + +/** + * function to process the a message, give it to the higher layer + * @param cls pointer to the plugin + * @param client pointer to the session this message belongs to + * @param hdr start of the message + */ +//TODO ATS informations +static void +process_data (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) +{ + + GNUNET_assert (client != NULL); + GNUNET_assert (cls != NULL); + struct Session *session = (struct Session *) client; + struct Plugin *plugin = (struct Plugin *) cls; + struct GNUNET_ATS_Information ats[2]; + + ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); + ats[0].value = htonl (1); + ats[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); + ats[1].value = htonl (GNUNET_ATS_NET_WLAN); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Calling plugin->env->receive for session %p; %s; size: %u\n", + session, wlan_plugin_address_to_string (NULL, + session->mac-> + addr.mac, 6), + htons (hdr->size)); + plugin->env->receive (plugin->env->cls, &(session->target), hdr, + (const struct GNUNET_ATS_Information *) &ats, 2, + session, (const char *) &session->mac->addr, + sizeof (session->mac->addr)); +} + +/** + * Function used for to process the data received from the wlan interface + * + * @param cls the plugin handle + * @param session_light pointer to the struct holding known informations + * @param hdr hdr of the GNUNET_MessageHeader + * @param rxinfo pointer to the radiotap informations got with this packet FIXME: give ATS for info + */ +static void +wlan_data_helper (void *cls, struct Session_light *session_light, + const struct GNUNET_MessageHeader *hdr, + const struct Radiotap_rx *rxinfo) +{ + struct Plugin *plugin = cls; + struct FragmentMessage *fm; + struct FragmentMessage *fm2; + struct GNUNET_PeerIdentity tmpsource; + + GNUNET_assert (plugin != NULL); + + //ADVERTISEMENT + if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_HELLO) + { + + //TODO better DOS protection, error handling + //TODO test first than create session + GNUNET_assert (session_light != NULL); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_HELLO size: %u; %s\n", + ntohs (hdr->size), wlan_plugin_address_to_string (NULL, + session_light->addr. + mac, 6)); + if (session_light->macendpoint == NULL) + { + session_light->macendpoint = + get_macendpoint (plugin, &session_light->addr, GNUNET_YES); + } + + + if (GNUNET_HELLO_get_id + ((const struct GNUNET_HELLO_Message *) hdr, &tmpsource) == GNUNET_OK) + { + session_light->session = + search_session (plugin, session_light->macendpoint, &tmpsource); + if (session_light->session == NULL) + { + session_light->session = + create_session (plugin, session_light->macendpoint, &tmpsource); + } + GNUNET_STATISTICS_update (plugin->env->stats, + _("# wlan hello messages received"), 1, + GNUNET_NO); + plugin->env->receive (plugin->env->cls, &session_light->session->target, + hdr, NULL, 0, session_light->session, + (const char *) &session_light->session->mac->addr, + sizeof (session_light->session->mac->addr)); + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME, + "WLAN client not in session list and hello message is not okay\n"); + return; + } + } + + //FRAGMENT + + else if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_FRAGMENT) + { + + GNUNET_assert (session_light != NULL); + if (session_light->macendpoint == NULL) + { + session_light->macendpoint = + get_macendpoint (plugin, &session_light->addr, GNUNET_YES); + } + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_FRAGMENT with size: %u; mac endpoint %p: %s\n", + ntohs (hdr->size), session_light->macendpoint, + wlan_plugin_address_to_string (NULL, + session_light->addr.mac, + 6)); + GNUNET_STATISTICS_update (plugin->env->stats, + _("# wlan fragments received"), 1, GNUNET_NO); + int ret = + GNUNET_DEFRAGMENT_process_fragment (session_light->macendpoint->defrag, + hdr); + + if (ret == GNUNET_NO) + { + session_light->macendpoint->dups++; + } + else if (ret == GNUNET_OK) + { + session_light->macendpoint->fragc++; + } + set_next_send (plugin); + + } + + //ACK + + else if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_FRAGMENT_ACK) + { + GNUNET_assert (session_light != NULL); + if (session_light->macendpoint == NULL) + { + session_light->macendpoint = + get_macendpoint (plugin, &session_light->addr, GNUNET_NO); + } + + if (session_light->macendpoint == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Macendpoint does not exist for this GNUNET_MESSAGE_TYPE_FRAGMENT_ACK size: %u; %s\n", + ntohs (hdr->size), wlan_plugin_address_to_string (NULL, + session_light->addr.mac, + 6)); + return; + } + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_FRAGMENT_ACK size: %u; mac endpoint: %p; %s\n", + ntohs (hdr->size), session_light->macendpoint, + wlan_plugin_address_to_string (NULL, + session_light->addr.mac, + 6)); + fm = session_light->macendpoint->sending_messages_head; + while (fm != NULL) + { + fm2 = fm->next; + GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan acks received"), + 1, GNUNET_NO); + int ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr); + + if (ret == GNUNET_OK) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Got last ack, finished fragment message %p\n", fm); + session_light->macendpoint->acks++; + fm->session->last_activity = GNUNET_TIME_absolute_get (); + session_light->macendpoint->last_activity = fm->session->last_activity; + free_fragment_message (plugin, fm); + check_fragment_queue (plugin); + return; + } + if (ret == GNUNET_NO) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Got ack for: %p\n", fm); + session_light->macendpoint->acks++; + return; + } + if (ret == GNUNET_SYSERR) + { + + } + + fm = fm2; + } + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "WLAN fragment not in fragment list\n"); + return; + + } + else + { + // TODO Wrong data? + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME, + "WLAN packet inside the WLAN helper packet has not the right type: %u size: %u\n", + ntohs (hdr->type), ntohs (hdr->size)); + GNUNET_break (0); + return; + } + +#if 0 + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Helper finished\n"); +#endif + +} + +/** + * Function to print mac addresses nice * + * @param pointer to 6 byte with the mac address + * @return pointer to the chars which hold the print out + */ +static const char * +macprinter (const u_int8_t * mac) +{ + static char macstr[20]; + + GNUNET_snprintf (macstr, sizeof (macstr), "%X:%X:%X:%X:%X:%X", mac[0], mac[1], + mac[2], mac[3], mac[4], mac[5]); + return macstr; +} + +/** + * Function for the scheduler if a mac endpoint times out + * @param cls pointer to the MacEndpoint + * @param tc pointer to the GNUNET_SCHEDULER_TaskContext + */ +static void +macendpoint_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct MacEndpoint *endpoint = cls; + + GNUNET_assert (endpoint != NULL); + endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK; + if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + { + return; + } + if (GNUNET_TIME_absolute_get_remaining + (GNUNET_TIME_absolute_add + (endpoint->last_activity, MACENDPOINT_TIMEOUT)).rel_value == 0) + { + GNUNET_assert (endpoint->plugin != NULL); + GNUNET_STATISTICS_update (endpoint->plugin->env->stats, + _("# wlan mac endpoints timeouts"), 1, GNUNET_NO); + free_macendpoint (endpoint->plugin, endpoint); + } + else + { + endpoint->timeout_task = + GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout, + endpoint); + } +} + +/** + * function to create an macendpoint + * @param plugin pointer to the plugin struct + * @param addr pointer to the macaddress + * @return returns a macendpoint + */ +static struct MacEndpoint * +create_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr) +{ + struct MacEndpoint *newend = GNUNET_malloc (sizeof (struct MacEndpoint)); + + GNUNET_assert (plugin != NULL); + GNUNET_STATISTICS_update (plugin->env->stats, + _("# wlan mac endpoints created"), 1, GNUNET_NO); + newend->addr = *addr; + newend->plugin = plugin; + newend->addr = *addr; + newend->fragment_messages_out_count = 0; + newend->defrag = + GNUNET_DEFRAGMENT_context_create (plugin->env->stats, WLAN_MTU, + MESSAGES_IN_DEFRAG_QUEUE_PER_MAC, + newend, &wlan_data_message_handler, + &add_ack_for_send); + newend->last_activity = GNUNET_TIME_absolute_get (); + newend->timeout_task = + GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout, + newend); + + plugin->mac_count++; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"), + plugin->mac_count, GNUNET_NO); + GNUNET_CONTAINER_DLL_insert_tail (plugin->mac_head, plugin->mac_tail, newend); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "New Mac Endpoint %p: %s\n", newend, + wlan_plugin_address_to_string (NULL, newend->addr.mac, 6)); + return newend; +} + +/** + * Function used for to process the data from the suid process + * + * @param cls the plugin handle + * @param client client that send the data (not used) + * @param hdr header of the GNUNET_MessageHeader + */ +static void +wlan_process_helper (void *cls, void *client, + const struct GNUNET_MessageHeader *hdr) +{ + struct Plugin *plugin = cls; + struct ieee80211_frame *wlanIeeeHeader = NULL; + struct Session_light *session_light = NULL; + struct Radiotap_rx *rxinfo; + const struct GNUNET_MessageHeader *temp_hdr = NULL; + + int datasize = 0; + int pos; + + GNUNET_assert (plugin != NULL); + switch (ntohs (hdr->type)) + { + case GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Func wlan_process_helper got GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA size: %u\n", + ntohs (hdr->size)); + GNUNET_STATISTICS_update (plugin->env->stats, + _("# wlan WLAN_HELPER_DATA received"), 1, + GNUNET_NO); + //call wlan_process_helper with the message inside, later with wlan: analyze signal + if (ntohs (hdr->size) < + sizeof (struct ieee80211_frame) + + 2 * sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_rx)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Size of packet is too small; size: %u min size: %u\n", + ntohs (hdr->size), + sizeof (struct ieee80211_frame) + + sizeof (struct GNUNET_MessageHeader)); + //GNUNET_break (0); + /* FIXME: restart SUID process */ + return; + } + + rxinfo = (struct Radiotap_rx *) &hdr[1]; + wlanIeeeHeader = (struct ieee80211_frame *) &rxinfo[1]; + + //process only if it is an broadcast or for this computer both with the gnunet bssid + + //check for bssid + if (memcmp + (&(wlanIeeeHeader->i_addr3), &mac_bssid_gnunet, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0) + { + //check for broadcast or mac + if ((memcmp + (&(wlanIeeeHeader->i_addr1), &bc_all_mac, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0) || + (memcmp + (&(wlanIeeeHeader->i_addr1), &(plugin->mac_address), + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)) + { + //if packet is from us return + if ((memcmp + (&(wlanIeeeHeader->i_addr2), &(plugin->mac_address), + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)) + { + return; + } + // process the inner data + + + datasize = + ntohs (hdr->size) - sizeof (struct ieee80211_frame) - + sizeof (struct GNUNET_MessageHeader) - sizeof (struct Radiotap_rx); + + session_light = GNUNET_malloc (sizeof (struct Session_light)); + memcpy (&session_light->addr, &(wlanIeeeHeader->i_addr2), + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); + //session_light->session = search_session(plugin,session_light->addr); + GNUNET_STATISTICS_update (plugin->env->stats, + _("# wlan messages for this client received"), + 1, GNUNET_NO); + + pos = 0; + while (pos < datasize) + { + temp_hdr = (struct GNUNET_MessageHeader *) &wlanIeeeHeader[1] + pos; + if (ntohs (temp_hdr->size) <= datasize + pos) + { + GNUNET_STATISTICS_update (plugin->env->stats, + _ + ("# wlan messages inside WLAN_HELPER_DATA received"), + 1, GNUNET_NO); + wlan_data_helper (plugin, session_light, temp_hdr, rxinfo); + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Size of packet is too small; size: %u > size of packet: %u\n", + ntohs (temp_hdr->size), datasize + pos); + } + pos += ntohs (temp_hdr->size); + + } + + //clean up + GNUNET_free (session_light); + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Func wlan_process_helper got wrong MAC: %s\n", + macprinter (wlanIeeeHeader->i_addr1)); + } + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Func wlan_process_helper got wrong BSSID: %s\n", + macprinter (wlanIeeeHeader->i_addr2)); + } + break; + case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL: + //TODO more control messages + if (ntohs (hdr->size) != sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)) + { + GNUNET_break (0); + /* FIXME: restart SUID process */ + return; + } + memcpy (&plugin->mac_address, &hdr[1], sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Received WLAN_HELPER_CONTROL message with transport of address %s\n", + wlan_plugin_address_to_string (cls, &plugin->mac_address, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))); + plugin->env->notify_address (plugin->env->cls, GNUNET_YES, + &plugin->mac_address, + sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); + break; + default: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "Func wlan_process_helper got unknown message with number %u, size %u\n", + ntohs (hdr->type), ntohs (hdr->size)); + +#if DEBUG_WLAN > 1 + hexdump (hdr, GNUNET_MIN (ntohs (hdr->size), 256)); +#endif + GNUNET_break (0); + return; + } +} + +/** + * Exit point from the plugin. + * @param cls pointer to the api struct + */ + +//FIXME cleanup +void * +libgnunet_plugin_transport_wlan_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + struct MacEndpoint *endpoint = plugin->mac_head; + struct MacEndpoint *endpoint_next; + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "libgnunet_plugin_transport_wlan_done started\n"); + wlan_transport_stop_wlan_helper (plugin); + + GNUNET_assert (cls != NULL); + //free sessions + while (endpoint != NULL) + { + endpoint_next = endpoint->next; + free_macendpoint (plugin, endpoint); + endpoint = endpoint_next; + + } + + + if (plugin->suid_tokenizer != NULL) + GNUNET_SERVER_mst_destroy (plugin->suid_tokenizer); + + if (plugin->data_tokenizer != NULL) + GNUNET_SERVER_mst_destroy (plugin->data_tokenizer); + + GNUNET_free_non_null (plugin->interface); + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + +/** + * Entry point for the plugin. + * + * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*' + * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error + */ +void * +libgnunet_plugin_transport_wlan_init (void *cls) +{ + //struct GNUNET_SERVICE_Context *service; + struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; + struct GNUNET_TRANSPORT_PluginFunctions *api; + struct Plugin *plugin; + + GNUNET_assert (cls != NULL); + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + plugin->pendingsessions = 0; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"), + plugin->pendingsessions, GNUNET_NO); + plugin->mac_count = 0; + GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"), + plugin->mac_count, GNUNET_NO); + plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK; + plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK; + plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_BANDWIDTH_tracker_init (&plugin->tracker, + GNUNET_BANDWIDTH_value_init (100 * 1024 * + 1024 / 8), 100); + + plugin->suid_tokenizer = + GNUNET_SERVER_mst_create (&wlan_process_helper, plugin); + + plugin->data_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); + + //plugin->sessions = GNUNET_malloc (sizeof (struct Sessionqueue)); + //plugin->pending_Sessions_head = GNUNET_malloc (sizeof (struct Sessionqueue)); + + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = plugin; + api->send = &wlan_plugin_send; + api->get_session = &wlan_plugin_get_session; + api->disconnect = &wlan_plugin_disconnect; + api->address_pretty_printer = &wlan_plugin_address_pretty_printer; + api->check_address = &wlan_plugin_address_suggested; + api->address_to_string = &wlan_plugin_address_to_string; + + //read config + + if (GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "TESTMODE")) + { + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-wlan", + "TESTMODE", &(plugin->testmode))) + plugin->testmode = 0; //default value + } + + if (GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "INTERFACE")) + { + if (GNUNET_CONFIGURATION_get_value_string + (env->cfg, "transport-wlan", "INTERFACE", + &(plugin->interface)) != GNUNET_YES) + { + libgnunet_plugin_transport_wlan_done (api); + return NULL; + } + } + + //start the plugin + wlan_transport_start_wlan_helper (plugin); + set_next_beacon_time (plugin); + set_next_send (plugin); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME, + "wlan init finished\n"); + return api; +} + +/* end of plugin_transport_wlan.c */ diff --git a/src/transport/plugin_transport_wlan.h b/src/transport/plugin_transport_wlan.h new file mode 100644 index 0000000..9e1bc4f --- /dev/null +++ b/src/transport/plugin_transport_wlan.h @@ -0,0 +1,152 @@ +/* + This file is part of GNUnet + (C) 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file transport/plugin_transport_wlan.h + * @brief header for transport plugin and the helper for wlan + * @author David Brodski + */ +#ifndef PLUGIN_TRANSPORT_WLAN +#define PLUGIN_TRANSPORT_WLAN + +#include +#include "gnunet_common.h" + +/** + * Number fo bytes in a mac address. + */ +#define MAC_ADDR_SIZE 6 + +GNUNET_NETWORK_STRUCT_BEGIN +/** + * A MAC Address. + */ +struct GNUNET_TRANSPORT_WLAN_MacAddress +{ + uint8_t mac[MAC_ADDR_SIZE]; +}; + +/** + * Format of a WLAN Control Message. + */ +struct GNUNET_TRANSPORT_WLAN_HelperControlMessage +{ + /** + * Message header. Type is + * GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL + */ + struct GNUNET_MessageHeader hdr; + + /** + * MAC Address of the local WLAN interface. + */ + struct GNUNET_TRANSPORT_WLAN_MacAddress mac; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * GNUnet bssid + */ +static const struct GNUNET_TRANSPORT_WLAN_MacAddress mac_bssid_gnunet = { + {0x13, 0x22, 0x33, 0x44, 0x55, 0x66} +}; + + +/** + * Broadcast MAC + */ +static const struct GNUNET_TRANSPORT_WLAN_MacAddress bc_all_mac = { + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} +}; + + +struct Radiotap_Send +{ + /** + * wlan send rate + */ + uint8_t rate; + + /** + * Antenna; the first antenna is 0. + */ + uint8_t antenna; + + /** + * Transmit power expressed as unitless distance from max power set at factory calibration. + * 0 is max power. Monotonically nondecreasing with lower power levels. + */ + uint16_t tx_power; +}; + + +/** + * struct to represent infos gathered form the radiotap fields, see RadiotapHeader for more Infos + */ +struct Radiotap_rx +{ + /** + * FIXME: not initialized properly so far. (supposed to contain + * information about which of the fields below are actually valid). + */ + uint32_t ri_present; + + /** + * IEEE80211_RADIOTAP_TSFT + */ + uint64_t ri_mactime; + + /** + * from radiotap + * either IEEE80211_RADIOTAP_DBM_ANTSIGNAL + * or IEEE80211_RADIOTAP_DB_ANTSIGNAL + */ + int32_t ri_power; + + /** + * either IEEE80211_RADIOTAP_DBM_ANTNOISE + * or IEEE80211_RADIOTAP_DB_ANTNOISE + */ + int32_t ri_noise; + + /** + * IEEE80211_RADIOTAP_CHANNEL + */ + uint32_t ri_channel; + + /** + * Frequency we use. FIXME: not properly initialized so far! + */ + uint32_t ri_freq; + + /** + * IEEE80211_RADIOTAP_RATE * 50000 + */ + uint32_t ri_rate; + + /** + * IEEE80211_RADIOTAP_ANTENNA + */ + uint32_t ri_antenna; +}; + + + +#endif diff --git a/src/transport/template_cfg_peer1.conf b/src/transport/template_cfg_peer1.conf new file mode 100644 index 0000000..ba05e93 --- /dev/null +++ b/src/transport/template_cfg_peer1.conf @@ -0,0 +1,50 @@ +@INLINE@ test_transport_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p1/ +DEFAULTCONFIG = template_cfg_peer1.conf + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[nat] +RETURN_LOCAL_ADDRESSES = YES +DISABLEV6 = NO + +[transport-tcp] +PORT = 12000 +TIMEOUT = 5 s + +[transport-udp] +BROADCAST = NO + +[arm] +PORT = 12005 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12004 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12003 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12002 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +#PREFIX = valgrind --leak-check=full +PORT = 12001 +#DEBUG = YES +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + +[ats] +#DEBUG = YES +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB +PORT = 12006 +UNIXPATH = /tmp/gnunet-p1-service-ats.sock + + diff --git a/src/transport/template_cfg_peer2.conf b/src/transport/template_cfg_peer2.conf new file mode 100644 index 0000000..0a0e74a --- /dev/null +++ b/src/transport/template_cfg_peer2.conf @@ -0,0 +1,50 @@ +@INLINE@ test_transport_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p2/ +DEFAULTCONFIG = template_cfg_peer2.conf + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[nat] +RETURN_LOCAL_ADDRESSES = YES +DISABLEV6 = NO + +[transport-tcp] +PORT = 12100 +TIMEOUT = 5 s + +[transport-udp] +BROADCAST = NO + +[arm] +PORT = 12014 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12013 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12012 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12011 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock +TRUST = $SERVICEHOME/data/credit/ + +[transport] +#PREFIX = valgrind --leak-check=full +PORT = 12010 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + +[ats] +#DEBUG = YES +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB +PORT = 12016 +UNIXPATH = /tmp/gnunet-p2-service-ats.sock + + diff --git a/src/transport/test_plugin_transport_data.conf b/src/transport/test_plugin_transport_data.conf new file mode 100644 index 0000000..adc7a59 --- /dev/null +++ b/src/transport/test_plugin_transport_data.conf @@ -0,0 +1,25 @@ +@INLINE@ test_transport_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunetd-plugin-transport/ +DEFAULTCONFIG = test_plugin_transport_data.conf + +[transport-tcp] +PORT = 2368 +TIMEOUT = 5 s + +[arm] +PORT = 2366 + +[statistics] +PORT = 2367 + +[resolver] +PORT = 2364 + +[peerinfo] +PORT = 2369 + +[transport] +PORT = 2365 + + diff --git a/src/transport/test_plugin_transport_data_udp.conf b/src/transport/test_plugin_transport_data_udp.conf new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/transport/test_plugin_transport_data_udp.conf @@ -0,0 +1 @@ + diff --git a/src/transport/test_quota_compliance.c b/src/transport/test_quota_compliance.c new file mode 100644 index 0000000..8f4db53 --- /dev/null +++ b/src/transport/test_quota_compliance.c @@ -0,0 +1,632 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_quota_compliance.c + * @brief base test case for transport implementations + * + * This test case tests quota compliance both on transport level + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_transport_service.h" +#include "gauger.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO + +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * Testcase timeout + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20) + +#define DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +static char *test_source; + +static char *test_plugin; + +static char *test_name; + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static GNUNET_SCHEDULER_TaskIdentifier measure_task; + +struct PeerContext *p1; + +struct PeerContext *p2; + +struct PeerContext *sender; + +struct PeerContext *receiver; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +char *cfg_file_p1; +char *gen_cfg_p2; +unsigned long long quota_in_p1; +unsigned long long quota_out_p1; + +char *cfg_file_p2; +char *gen_cfg_p1; +unsigned long long quota_in_p2; +unsigned long long quota_out_p2; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + + +/* + * Testcase specific declarations + */ + +/** + * Note that this value must not significantly exceed + * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise + * messages may be dropped even for a reliable transport. + */ +#define TOTAL_MSGS (1024 * 2) + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct TestMessage +{ + struct GNUNET_MessageHeader header; + uint32_t num; +}; +GNUNET_NETWORK_STRUCT_END + +static int msg_scheduled; +static int msg_sent; +static int msg_recv_expected; +static int msg_recv; + +static int test_failed; +static int test_connected; + +static unsigned long long total_bytes_sent; + +static struct GNUNET_TIME_Absolute start_time; + +/* + * END Testcase specific declarations + */ + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +end () +{ + unsigned long long delta; + unsigned long long datarate; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; + datarate = (total_bytes_sent * 1000) / delta; + + FPRINTF (stderr, "Throughput was %llu b/s\n", datarate); + + test_failed = GNUNET_NO; + if (datarate > quota_in_p2) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Datarate of %llu b/s higher than allowed inbound quota of %llu b/s\n", + datarate, quota_in_p2); + test_failed = GNUNET_YES; + } + if (datarate > quota_out_p1) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Datarate of %llu b/s higher than allowed outbound quota of %llu b/s\n", + datarate, quota_out_p1); + test_failed = GNUNET_YES; + } + if (test_failed == GNUNET_NO) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Datarate of %llu b/s complied to allowed outbound quota of %llu b/s and inbound quota of %llu b/s\n", + datarate, quota_out_p1, quota_in_p2); + } + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (cc != NULL) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + +} + +static void +end_badly () +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + if (measure_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (measure_task); + + if (test_connected == GNUNET_YES) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n"); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n"); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (cc != NULL) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + ok = GNUNET_SYSERR; +} + + +static unsigned int +get_size (unsigned int iter) +{ + unsigned int ret; + + ret = (iter * iter * iter); + return sizeof (struct TestMessage) + (ret % 60000); +} + + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + static int n; + unsigned int s; + char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + const struct TestMessage *hdr; + + hdr = (const struct TestMessage *) message; + s = get_size (n); + if (MTYPE != ntohs (message->type)) + return; + msg_recv_expected = n; + msg_recv = ntohl (hdr->num); + if (ntohs (message->size) != (s)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u of size %u, got %u bytes of message %u\n", + n, s, ntohs (message->size), ntohl (hdr->num)); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + test_failed = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } + if (ntohl (hdr->num) != n) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u of size %u, got %u bytes of message %u\n", + n, s, ntohs (message->size), ntohl (hdr->num)); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + test_failed = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } + memset (cbuf, n, s - sizeof (struct TestMessage)); + if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u with bits %u, but body did not match\n", n, + (unsigned char) n); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + test_failed = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +#if VERBOSE + if (ntohl (hdr->num) % 5000 == 0) + { + struct PeerContext *p = cls; + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", + p->no, ps, ntohl (hdr->num), ntohs (message->size), + GNUNET_i2s (peer)); + GNUNET_free (ps); + } +#endif + n++; +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + static int n; + char *cbuf = buf; + struct TestMessage hdr; + unsigned int s; + unsigned int ret; + + th = NULL; + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout occurred while waiting for transmit_ready for message %u of %u\n", + msg_scheduled, TOTAL_MSGS); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + ok = 42; + return 0; + } + + ret = 0; + s = get_size (n); + GNUNET_assert (size >= s); + GNUNET_assert (buf != NULL); + cbuf = buf; + do + { + hdr.header.size = htons (s); + hdr.header.type = htons (MTYPE); + hdr.num = htonl (n); + msg_sent = n; + memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); + ret += sizeof (struct TestMessage); + memset (&cbuf[ret], n, s - sizeof (struct TestMessage)); + ret += s - sizeof (struct TestMessage); +#if VERBOSE + if (n % 5000 == 0) + { + + char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message of size %u from peer %u (`%4s') -> peer %u (`%s') !\n", + n, sender->no, GNUNET_i2s (&sender->id), receiver->no, + receiver_s); + GNUNET_free (receiver_s); + } +#endif + n++; + s = get_size (n); + if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) + break; /* sometimes pack buffer full, sometimes not */ + } + while (size - ret >= s); + if (n < TOTAL_MSGS) + { + if (th == NULL) + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0, + TIMEOUT_TRANSMIT, + ¬ify_ready, NULL); + msg_scheduled = n; + } + if (n % 5000 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Returning total message block of size %u\n", ret); + } + total_bytes_sent += ret; + if (n == TOTAL_MSGS) + { + FPRINTF (stderr, "%s", "\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All messages sent\n"); + } + return ret; +} + + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') connected to us!\n", + p->no, GNUNET_i2s (peer)); +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') disconnected!\n", p->no, + GNUNET_i2s (peer)); + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + +} + +static void +sendtask () +{ + start_time = GNUNET_TIME_absolute_get (); + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0, + TIMEOUT_TRANSMIT, ¬ify_ready, + NULL); +} + + +static void +measure (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static int counter; + + measure_task = GNUNET_SCHEDULER_NO_TASK; + + counter++; + if ((DURATION.rel_value / 1000) < counter) + { + FPRINTF (stderr, "%s", ".\n"); + GNUNET_SCHEDULER_add_now (&end, NULL); + } + else + { + FPRINTF (stderr, "%s", "."); + measure_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &measure, NULL); + } +} + + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", + p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + cc = NULL; + test_connected = GNUNET_YES; + + measure_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &measure, NULL); + GNUNET_SCHEDULER_add_now (&sendtask, NULL); + +} + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + test_connected = GNUNET_NO; + + sender = p2; + receiver = p1; + + char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test tries to send from %u (%s) -> peer %u (%s)\n", sender->no, + sender_c, receiver->no, GNUNET_i2s (&receiver->id)); + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + +static char * +generate_config (char *cfg_file, unsigned long long quota_in, + unsigned long long quota_out) +{ + char *fname = NULL; + struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create (); + + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (cfg, cfg_file)); + GNUNET_asprintf (&fname, "q_in_%llu_q_out_%llu_%s", quota_in, quota_out, + cfg_file); + GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG", fname); + GNUNET_CONFIGURATION_set_value_number (cfg, "ats", "WAN_QUOTA_IN", quota_in); + GNUNET_CONFIGURATION_set_value_number (cfg, "ats", "WAN_QUOTA_OUT", + quota_out); + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_write (cfg, fname)); + GNUNET_CONFIGURATION_destroy (cfg); + return fname; +} + +static void +run_measurement (unsigned long long p1_quota_in, + unsigned long long p1_quota_out, + unsigned long long p2_quota_in, + unsigned long long p2_quota_out) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + + /* setting ATS quota */ + quota_out_p1 = p1_quota_out; + gen_cfg_p1 = generate_config (cfg_file_p1, p1_quota_in, p1_quota_out); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Generated config file `%s'\n", + gen_cfg_p1); + + quota_in_p2 = p2_quota_in; + gen_cfg_p2 = generate_config (cfg_file_p2, p2_quota_in, p2_quota_out); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Generated config file `%s'\n", + gen_cfg_p2); + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, gen_cfg_p1, 1, ¬ify_receive, + ¬ify_connect, ¬ify_disconnect, + &start_cb, NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, gen_cfg_p2, 2, ¬ify_receive, + ¬ify_connect, ¬ify_disconnect, + &start_cb, NULL); + + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + unsigned long long p1_quota_in = 10000; + unsigned long long p1_quota_out = 10000; + unsigned long long p2_quota_in = 10000; + unsigned long long p2_quota_out = 10000; + + if (NULL != strstr (test_name, "asymmetric")) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Running asymmetric test with sending peer unlimited, receiving peer (in/out): %llu/%llu b/s \n", + p2_quota_in, p2_quota_out); + p1_quota_out = 1024 * 1024 * 1024; + p1_quota_in = 1024 * 1024 * 1024; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Running symmetric test with (in/out) %llu/%llu b/s \n", + p2_quota_in, p2_quota_out); + } + run_measurement (p1_quota_in, p1_quota_out, p2_quota_in, p2_quota_out); +} + +static int +check () +{ + static char *argv[] = { "test_transport-quota-compliance", + "-c", + "test_quota_compliance_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); + GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, + &test_plugin); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); + + check (); + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + if (GNUNET_YES == GNUNET_DISK_file_test (gen_cfg_p1)) + { + GNUNET_DISK_directory_remove (gen_cfg_p1); + GNUNET_free (gen_cfg_p1); + } + + if (GNUNET_YES == GNUNET_DISK_file_test (gen_cfg_p2)) + { + GNUNET_DISK_directory_remove (gen_cfg_p2); + GNUNET_free (gen_cfg_p2); + } + + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + + GNUNET_TRANSPORT_TESTING_done (tth); + + return test_failed; +} + + +/* end of test_quota_compliance.c */ diff --git a/src/transport/test_quota_compliance_data.conf b/src/transport/test_quota_compliance_data.conf new file mode 100644 index 0000000..93f75dd --- /dev/null +++ b/src/transport/test_quota_compliance_data.conf @@ -0,0 +1,25 @@ +@INLINE@ test_transport_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunetd-plugin-transport/ +DEFAULTCONFIG = test_quota_compliance_data.conf + +[transport-tcp] +PORT = 2368 +TIMEOUT = 5 s + +[arm] +PORT = 2366 + +[statistics] +PORT = 2367 + +[resolver] +PORT = 2364 + +[peerinfo] +PORT = 2369 + +[transport] +PORT = 2365 + + diff --git a/src/transport/test_quota_compliance_http_asymmetric_peer1.conf b/src/transport/test_quota_compliance_http_asymmetric_peer1.conf new file mode 100644 index 0000000..f56b157 --- /dev/null +++ b/src/transport/test_quota_compliance_http_asymmetric_peer1.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer1 +DEFAULTCONFIG = test_quota_compliance_http_peer1.conf + +[transport-http] +PORT = 4010 + +[arm] +PORT = 4015 +UNIXPATH = /tmp/test_quota_compliance_http_arm_peer1.sock + +[statistics] +PORT = 4014 +UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer1.sock + +[resolver] +PORT = 4013 +UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer1.sock + +[peerinfo] +PORT = 4012 +UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer1.sock + +[transport] +PORT = 4011 +PLUGINS = http +UNIXPATH = /tmp/test_quota_compliance_http_transport_peer1.sock + + diff --git a/src/transport/test_quota_compliance_http_asymmetric_peer2.conf b/src/transport/test_quota_compliance_http_asymmetric_peer2.conf new file mode 100644 index 0000000..20ef582 --- /dev/null +++ b/src/transport/test_quota_compliance_http_asymmetric_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer2 +DEFAULTCONFIG = test_quota_compliance_http_peer2.conf + +[transport-http] +PORT = 3010 + +[arm] +PORT = 3015 +UNIXPATH = /tmp/test_quota_compliance_http_arm_peer2.sock + +[statistics] +PORT = 3014 +UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer2.sock + +[resolver] +PORT = 3013 +UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer2.sock + +[peerinfo] +PORT = 3012 +UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer2.sock + +[transport] +PORT = 3011 +PLUGINS = http +UNIXPATH = /tmp/test_quota_compliance_http_transport_peer2.sock + + diff --git a/src/transport/test_quota_compliance_http_peer1.conf b/src/transport/test_quota_compliance_http_peer1.conf new file mode 100644 index 0000000..f56b157 --- /dev/null +++ b/src/transport/test_quota_compliance_http_peer1.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer1 +DEFAULTCONFIG = test_quota_compliance_http_peer1.conf + +[transport-http] +PORT = 4010 + +[arm] +PORT = 4015 +UNIXPATH = /tmp/test_quota_compliance_http_arm_peer1.sock + +[statistics] +PORT = 4014 +UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer1.sock + +[resolver] +PORT = 4013 +UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer1.sock + +[peerinfo] +PORT = 4012 +UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer1.sock + +[transport] +PORT = 4011 +PLUGINS = http +UNIXPATH = /tmp/test_quota_compliance_http_transport_peer1.sock + + diff --git a/src/transport/test_quota_compliance_http_peer2.conf b/src/transport/test_quota_compliance_http_peer2.conf new file mode 100644 index 0000000..20ef582 --- /dev/null +++ b/src/transport/test_quota_compliance_http_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer2 +DEFAULTCONFIG = test_quota_compliance_http_peer2.conf + +[transport-http] +PORT = 3010 + +[arm] +PORT = 3015 +UNIXPATH = /tmp/test_quota_compliance_http_arm_peer2.sock + +[statistics] +PORT = 3014 +UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer2.sock + +[resolver] +PORT = 3013 +UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer2.sock + +[peerinfo] +PORT = 3012 +UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer2.sock + +[transport] +PORT = 3011 +PLUGINS = http +UNIXPATH = /tmp/test_quota_compliance_http_transport_peer2.sock + + diff --git a/src/transport/test_quota_compliance_https_asymmetric_peer1.conf b/src/transport/test_quota_compliance_https_asymmetric_peer1.conf new file mode 100644 index 0000000..ad4aab0 --- /dev/null +++ b/src/transport/test_quota_compliance_https_asymmetric_peer1.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer1/ +DEFAULTCONFIG = test_quota_compliance_https_peer1.conf + +[transport-https] +PORT = 4001 +KEY_FILE = https_key_quota_p1.key +CERT_FILE = https_cert_quota_p1.crt + +[arm] +PORT = 4006 +UNIXPATH = /tmp/test_quota_compliance_https_arm_peer1.sock + +[statistics] +PORT = 4005 +UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer1.sock + +[resolver] +PORT = 4004 +UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer1.sock + +[peerinfo] +PORT = 4003 +UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer1.sock + +[transport] +PORT = 4002 +PLUGINS = https +UNIXPATH = /tmp/test_quota_compliance_https_transport_peer1.sock + + diff --git a/src/transport/test_quota_compliance_https_asymmetric_peer2.conf b/src/transport/test_quota_compliance_https_asymmetric_peer2.conf new file mode 100644 index 0000000..94d7412 --- /dev/null +++ b/src/transport/test_quota_compliance_https_asymmetric_peer2.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer2 +DEFAULTCONFIG = test_quota_compliance_https_peer2.conf + +[transport-https] +PORT = 3001 +KEY_FILE = https_key_quota_p2.key +CERT_FILE = https_cert_qutoa_p2.crt + +[arm] +PORT = 3006 +UNIXPATH = /tmp/test_quota_compliance_https_arm_peer2.sock + +[statistics] +PORT = 3005 +UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer2.sock + +[resolver] +PORT = 3004 +UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer2.sock + +[peerinfo] +PORT = 3003 +UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer2.sock + +[transport] +PORT = 3002 +PLUGINS = https +UNIXPATH = /tmp/https_transport_peer2.sock + + diff --git a/src/transport/test_quota_compliance_https_peer1.conf b/src/transport/test_quota_compliance_https_peer1.conf new file mode 100644 index 0000000..ad4aab0 --- /dev/null +++ b/src/transport/test_quota_compliance_https_peer1.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer1/ +DEFAULTCONFIG = test_quota_compliance_https_peer1.conf + +[transport-https] +PORT = 4001 +KEY_FILE = https_key_quota_p1.key +CERT_FILE = https_cert_quota_p1.crt + +[arm] +PORT = 4006 +UNIXPATH = /tmp/test_quota_compliance_https_arm_peer1.sock + +[statistics] +PORT = 4005 +UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer1.sock + +[resolver] +PORT = 4004 +UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer1.sock + +[peerinfo] +PORT = 4003 +UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer1.sock + +[transport] +PORT = 4002 +PLUGINS = https +UNIXPATH = /tmp/test_quota_compliance_https_transport_peer1.sock + + diff --git a/src/transport/test_quota_compliance_https_peer2.conf b/src/transport/test_quota_compliance_https_peer2.conf new file mode 100644 index 0000000..94d7412 --- /dev/null +++ b/src/transport/test_quota_compliance_https_peer2.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer2 +DEFAULTCONFIG = test_quota_compliance_https_peer2.conf + +[transport-https] +PORT = 3001 +KEY_FILE = https_key_quota_p2.key +CERT_FILE = https_cert_qutoa_p2.crt + +[arm] +PORT = 3006 +UNIXPATH = /tmp/test_quota_compliance_https_arm_peer2.sock + +[statistics] +PORT = 3005 +UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer2.sock + +[resolver] +PORT = 3004 +UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer2.sock + +[peerinfo] +PORT = 3003 +UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer2.sock + +[transport] +PORT = 3002 +PLUGINS = https +UNIXPATH = /tmp/https_transport_peer2.sock + + diff --git a/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf b/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf new file mode 100644 index 0000000..a7bac62 --- /dev/null +++ b/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/quota-tcp-p1/ +DEFAULTCONFIG = test_quota_compliance_tcp_asymmetric_peer1.conf + +[transport-tcp] +PORT = 4094 + +[transport-udp] +PORT = 4094 + +[arm] +PORT = 4087 +UNIXPATH = /tmp/test_quota_compliance_tcp_arm_peer1.sock + +[statistics] +PORT = 4088 +UNIXPATH = /tmp/test_quota_compliance_tcp_statistics_peer1.sock + +[resolver] +PORT = 4089 +UNIXPATH = /tmp/test_quota_compliance_tcp_resolver_peer1.sock + +[peerinfo] +PORT = 4090 +UNIXPATH = /tmp/test_quota_compliance_tcp_peerinfo_peer1.sock + +[transport] +PORT = 4091 +UNIXPATH = /tmp/test_quota_compliance_tcp_transport_peer1.sock + + diff --git a/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf b/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf new file mode 100644 index 0000000..75a4fe9 --- /dev/null +++ b/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/quota-tcp-p2/ +DEFAULTCONFIG = test_quota_compliance_tcp_asymmetric_peer2.conf + +[transport-tcp] +PORT = 12015 +TIMEOUT = 5 s + +[arm] +PORT = 12014 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12013 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12012 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12011 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12010 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + diff --git a/src/transport/test_quota_compliance_tcp_peer1.conf b/src/transport/test_quota_compliance_tcp_peer1.conf new file mode 100644 index 0000000..ff63514 --- /dev/null +++ b/src/transport/test_quota_compliance_tcp_peer1.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/quota-tcp-p1/ +DEFAULTCONFIG = test_quota_compliance_tcp_peer1.conf + +[transport-tcp] +PORT = 4094 + +[transport-udp] +PORT = 4094 + +[arm] +PORT = 4087 +UNIXPATH = /tmp/test_quota_compliance_tcp_arm_peer1.sock + +[statistics] +PORT = 4088 +UNIXPATH = /tmp/test_quota_compliance_tcp_statistics_peer1.sock + +[resolver] +PORT = 4089 +UNIXPATH = /tmp/test_quota_compliance_tcp_resolver_peer1.sock + +[peerinfo] +PORT = 4090 +UNIXPATH = /tmp/test_quota_compliance_tcp_peerinfo_peer1.sock + +[transport] +PORT = 4091 +UNIXPATH = /tmp/test_quota_compliance_tcp_transport_peer1.sock + + diff --git a/src/transport/test_quota_compliance_tcp_peer2.conf b/src/transport/test_quota_compliance_tcp_peer2.conf new file mode 100644 index 0000000..18b199c --- /dev/null +++ b/src/transport/test_quota_compliance_tcp_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p2/ +DEFAULTCONFIG = test_quota_compliance_tcp_peer2.conf + +[transport-tcp] +PORT = 12015 +TIMEOUT = 5 s + +[arm] +PORT = 12014 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12013 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12012 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12011 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12010 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + diff --git a/src/transport/test_quota_compliance_udp_peer1.conf b/src/transport/test_quota_compliance_udp_peer1.conf new file mode 100644 index 0000000..fceee7b --- /dev/null +++ b/src/transport/test_quota_compliance_udp_peer1.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer1/ +DEFAULTCONFIG = test_quota_compliance_udp_peer1.conf + +[transport-udp] +PORT = 4368 +MAX_BPS = 50000000 + +[arm] +PORT = 4087 +UNIXPATH = /tmp/test_quota_compliance_udp_arm_peer1.sock + +[statistics] +PORT = 4088 +UNIXPATH = /tmp/test_quota_compliance_udp_statistics_peer1.sock + +[resolver] +PORT = 4089 +UNIXPATH = /tmp/test_quota_compliance_udp_resolver_peer1.sock + +[peerinfo] +PORT = 4090 +UNIXPATH = /tmp/test_quota_compliance_udp_peerinfo_peer1.sock + +[transport] +PORT = 4091 +PLUGINS = udp +UNIXPATH = /tmp/test_quota_compliance_udp_transport_peer1.sock + diff --git a/src/transport/test_quota_compliance_udp_peer2.conf b/src/transport/test_quota_compliance_udp_peer2.conf new file mode 100644 index 0000000..4b58c93 --- /dev/null +++ b/src/transport/test_quota_compliance_udp_peer2.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer2 +DEFAULTCONFIG = test_quota_compliance_udp_peer2.conf + +[transport-udp] +PORT = 3368 +MAX_BPS = 50000000 + +[arm] +PORT = 3087 +UNIXPATH = /tmp/test_quota_compliance_udp_arm_peer2.sock + +[statistics] +PORT = 3088 +UNIXPATH = /tmp/test_quota_compliance_udp_statistics_peer2.sock + +[resolver] +PORT = 3089 +UNIXPATH = /tmp/test_quota_compliance_udp_resolver_peer2.sock + +[peerinfo] +PORT = 3090 +UNIXPATH = /tmp/test_quota_compliance_udp_peerinfo_peer2.sock + +[transport] +PORT = 3091 +PLUGINS = udp +UNIXPATH = /tmp/test_quota_compliance_udp_transport_peer2.sock + + diff --git a/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf b/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf new file mode 100644 index 0000000..649cf1c --- /dev/null +++ b/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf @@ -0,0 +1,29 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer1/ +DEFAULTCONFIG = test_quota_compliance_unix_asymmetric_peer1.conf + +[arm] +PORT = 4087 +UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer1.sock + +[statistics] +PORT = 4088 +UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer1.sock + +[resolver] +PORT = 4089 +UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer1.sock + +[peerinfo] +PORT = 4090 +UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer1.sock + +[transport] +PORT = 4091 +PLUGINS = unix +UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer1.sock + +[transport-unix] +PORT = 4092 + diff --git a/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf b/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf new file mode 100644 index 0000000..a2d1bdd --- /dev/null +++ b/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf @@ -0,0 +1,29 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer2 +DEFAULTCONFIG = test_quota_compliance_unix_asymmetric_peer2.conf + +[arm] +PORT = 3087 +UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer2.sock + +[statistics] +PORT = 3088 +UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer2.sock + +[resolver] +PORT = 3089 +UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer2.sock + +[peerinfo] +PORT = 3090 +UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer2.sock + +[transport] +PORT = 3091 +PLUGINS = unix +UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer2.sock + +[transport-unix] +PORT = 3368 + diff --git a/src/transport/test_quota_compliance_unix_peer1.conf b/src/transport/test_quota_compliance_unix_peer1.conf new file mode 100644 index 0000000..60e656b --- /dev/null +++ b/src/transport/test_quota_compliance_unix_peer1.conf @@ -0,0 +1,28 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer1/ +DEFAULTCONFIG = test_quota_compliance_unix_peer1.conf + +[transport-unix] +PORT = 12120 + +[arm] +PORT = 4087 +UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer1.sock + +[statistics] +PORT = 4088 +UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer1.sock + +[resolver] +PORT = 4089 +UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer1.sock + +[peerinfo] +PORT = 4090 +UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer1.sock + +[transport] +PORT = 4091 +PLUGINS = unix +UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer1.sock diff --git a/src/transport/test_quota_compliance_unix_peer2.conf b/src/transport/test_quota_compliance_unix_peer2.conf new file mode 100644 index 0000000..b4f0b64 --- /dev/null +++ b/src/transport/test_quota_compliance_unix_peer2.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test_quota_compliance_peer2 +DEFAULTCONFIG = test_quota_compliance_unix_peer2.conf + +[transport-unix] +PORT = 12136 + +[arm] +PORT = 3087 +UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer2.sock + +[statistics] +PORT = 3088 +UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer2.sock + +[resolver] +PORT = 3089 +UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer2.sock + +[peerinfo] +PORT = 3090 +UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer2.sock + +[transport] +PORT = 3091 +PLUGINS = unix +UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer2.sock + +[transport-unix] +PORT = 3368 + diff --git a/src/transport/test_transport_api.c b/src/transport/test_transport_api.c new file mode 100644 index 0000000..5fb81e1 --- /dev/null +++ b/src/transport/test_transport_api.c @@ -0,0 +1,442 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api.c + * @brief base test case for transport implementations + * + * This test case serves as a base for tcp, udp, and udp-nat + * transport test cases. Based on the executable being run + * the correct test case will be performed. Conservation of + * C code apparently. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + +#define MSIZE 2600 + +#define MTYPE 12345 + +static char *test_source; + +static char *test_plugin; + +static char *test_name; + +static int ok; + +static int s_started; +static int s_connected; +static int s_sending; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static GNUNET_SCHEDULER_TaskIdentifier send_task; + +struct PeerContext *p1; + +struct PeerContext *p2; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +char *cfg_file_p1; + +char *cfg_file_p2; + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + +static void +end () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + + if (cc != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + cc = NULL; + } + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not ready to send data\n")); + + if (s_started == GNUNET_NO) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were not started n")); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were started n")); + + if (s_connected == GNUNET_NO) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not connected\n")); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were connected\n")); + + if (s_sending == GNUNET_NO) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not ready to send data\n")); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were ready to send data\n")); + + th = NULL; + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer 1 was not started\n")); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer 2 was not started\n")); + + ok = GNUNET_SYSERR; +} + + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", + p->no, ps, ntohs (message->type), ntohs (message->size), t->no, + GNUNET_i2s (&t->id)); + GNUNET_free (ps); + + if ((MTYPE == ntohs (message->type)) && + (MSIZE == ntohs (message->size))) + { + ok = 0; + end (); + } + else + { + GNUNET_break (0); + ok = 1; + end (); + } +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + struct PeerContext *p = cls; + struct GNUNET_MessageHeader *hdr; + + th = NULL; + + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout occurred while waiting for transmit_ready\n"); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + ok = 42; + return 0; + } + + GNUNET_assert (size >= MSIZE); + + if (buf != NULL) + { + hdr = buf; + hdr->size = htons (MSIZE); + hdr->type = htons (MTYPE); + } + + char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", + p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, + GNUNET_i2s (&p->id)); + GNUNET_free (ps); + + return MSIZE; +} + + +static void +sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + send_task = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", + p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); + GNUNET_free (receiver_s); + s_sending = GNUNET_YES; + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, MSIZE, 0, + TIMEOUT_TRANSMIT, ¬ify_ready, + p1); +} + + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + static int c; + + c++; + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, + t->no, GNUNET_i2s (peer)); + GNUNET_free (ps); +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *p = cls; + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, + GNUNET_i2s (peer)); + + GNUNET_free (ps); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + cc = NULL; + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", + p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + s_connected = GNUNET_YES; + send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); +} + + + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + else + s_started = GNUNET_YES; + char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", + p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (sender_c); + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + + s_started = GNUNET_NO; + s_connected = GNUNET_NO; + s_sending = GNUNET_NO; + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +} + + +static int +check () +{ + static char *const argv[] = { "test-transport-api", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + send_task = GNUNET_SCHEDULER_NO_TASK; + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); + GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, + &test_plugin); + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); + + ret = check (); + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + + GNUNET_TRANSPORT_TESTING_done (tth); + + return ret; +} + +/* end of test_transport_api.c */ diff --git a/src/transport/test_transport_api_bidirectional_connect.c b/src/transport/test_transport_api_bidirectional_connect.c new file mode 100644 index 0000000..604554c --- /dev/null +++ b/src/transport/test_transport_api_bidirectional_connect.c @@ -0,0 +1,415 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api_bidirectional_connect.c + * @brief base test case for transport implementations + * + * Perform a 3-way handshake connection set up in both directions at + * (almost) the same time + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +#define MTYPE 12345 + +static char *test_source; + +static char *test_plugin; + +static char *test_name; + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static GNUNET_SCHEDULER_TaskIdentifier send_task; + +struct PeerContext *p1; + +struct PeerContext *p2; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc1; +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc2; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +char *cfg_file_p1; + +char *cfg_file_p2; + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +end () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + + if (cc2 != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc2); + cc2 = NULL; + } + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + ok = GNUNET_SYSERR; +} + + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", + p->no, ps, ntohs (message->type), ntohs (message->size), t->no, + GNUNET_i2s (&t->id)); + + if ((MTYPE == ntohs (message->type)) && + (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size))) + { + ok = 0; + end (); + } + else + { + GNUNET_break (0); + ok = 1; + end (); + } +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + struct PeerContext *p = cls; + struct GNUNET_MessageHeader *hdr; + + th = NULL; + + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout occurred while waiting for transmit_ready\n"); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + ok = 42; + return 0; + } + + GNUNET_assert (size >= 256); + + if (buf != NULL) + { + hdr = buf; + hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); + hdr->type = htons (MTYPE); + } + char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", + p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, + GNUNET_i2s (&p->id)); + GNUNET_free (ps); + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + send_task = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", + p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); + GNUNET_free (receiver_s); + + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0, + TIMEOUT_TRANSMIT, ¬ify_ready, + p1); +} + + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + static int c; + + c++; + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, + t->no, GNUNET_i2s (peer)); + GNUNET_free (ps); +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *p = cls; + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, + GNUNET_i2s (peer)); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + if (cls == cc1) + { + cc1 = NULL; + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc2); + } + if (cls == cc2) + { + cc2 = NULL; + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc1); + } + + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", + p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); +} + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test tries to connect peer %u (`%s') <-> peer %u (`%s')\n", + p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); + + cc1 = + GNUNET_TRANSPORT_TESTING_connect_peers (tth, p2, p1, &testing_connect_cb, + NULL); + cc2 = + GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +} + + +static int +check () +{ + static char *const argv[] = { "test-transport-api", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + send_task = GNUNET_SCHEDULER_NO_TASK; + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); + GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, + &test_plugin); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); + + ret = check (); + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + + GNUNET_TRANSPORT_TESTING_done (tth); + + return ret; +} + +/* end of test_transport_api_bidirectional_connect.c */ diff --git a/src/transport/test_transport_api_bidirectional_connect_peer1.conf b/src/transport/test_transport_api_bidirectional_connect_peer1.conf new file mode 100644 index 0000000..21591b5 --- /dev/null +++ b/src/transport/test_transport_api_bidirectional_connect_peer1.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p1/ +DEFAULTCONFIG = test_transport_api_bidirectional_connect_peer1.conf + +[transport-tcp] +PORT = 12000 +TIMEOUT = 5 s + +[arm] +PORT = 12005 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12004 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12003 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12002 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12001 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +#DEBUG = YES + diff --git a/src/transport/test_transport_api_bidirectional_connect_peer2.conf b/src/transport/test_transport_api_bidirectional_connect_peer2.conf new file mode 100644 index 0000000..db3ba8c --- /dev/null +++ b/src/transport/test_transport_api_bidirectional_connect_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p2/ +DEFAULTCONFIG = test_transport_api_bidirectional_connect_peer2.conf + +[transport-tcp] +PORT = 12015 +TIMEOUT = 5 s + +[arm] +PORT = 12014 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12013 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12012 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12011 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12010 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + diff --git a/src/transport/test_transport_api_blacklisting.c b/src/transport/test_transport_api_blacklisting.c new file mode 100644 index 0000000..f8f6040 --- /dev/null +++ b/src/transport/test_transport_api_blacklisting.c @@ -0,0 +1,480 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/transport_api_blacklisting.c + * @brief test for the blacklisting API + * @author Matthias Wachs + * + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + + +struct PeerContext *p1; + +struct PeerContext *p2; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +#define MSIZE 2600 + +#define MTYPE 12345 + + +static int ok; +static int connected; +static int blacklist_request_p1; +static int blacklist_request_p2; + +struct GNUNET_TRANSPORT_Blacklist * blacklist_p1; + +struct GNUNET_TRANSPORT_Blacklist * blacklist_p2; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static GNUNET_SCHEDULER_TaskIdentifier send_task; + +static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping\n"); + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (cc != NULL) + { + GNUNET_TRANSPORT_TESTING_connect_peers_cancel(tth, cc); + cc = NULL; + } + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (blacklist_p1 != NULL) + { + GNUNET_TRANSPORT_blacklist_cancel (blacklist_p1); + blacklist_p1 = NULL; + } + + if (blacklist_p2 != NULL) + { + GNUNET_TRANSPORT_blacklist_cancel (blacklist_p2); + blacklist_p2 = NULL; + } + + if (p1 != NULL) + { + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + p1 = NULL; + } + if (p2 != NULL) + { + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + p2 = NULL; + } + + if ((blacklist_request_p1 == GNUNET_YES) && + (blacklist_request_p2 == GNUNET_YES) && + (connected == GNUNET_NO)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Peers were not connected, success\n")); + ok = 0; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Peers were not connected, fail\n")); + ok = 1; + } +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (send_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (send_task); + send_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (shutdown_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (shutdown_task); + shutdown_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (cc != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + cc = NULL; + } + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (blacklist_p1 != NULL) + GNUNET_TRANSPORT_blacklist_cancel (blacklist_p1); + + if (blacklist_p2 != NULL) + GNUNET_TRANSPORT_blacklist_cancel (blacklist_p2); + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + ok = GNUNET_SYSERR; +} + + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", + p->no, ps, ntohs (message->type), ntohs (message->size), t->no, + GNUNET_i2s (&t->id)); + GNUNET_free (ps); + + if ((MTYPE == ntohs (message->type)) && + (MSIZE == ntohs (message->size))) + { + ok = 0; + shutdown_task = GNUNET_SCHEDULER_add_now(&end, NULL); + } + else + { + GNUNET_break (0); + ok = 1; + shutdown_task = GNUNET_SCHEDULER_add_now(&end, NULL); + } +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + struct PeerContext *p = cls; + struct GNUNET_MessageHeader *hdr; + + th = NULL; + + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout occurred while waiting for transmit_ready\n"); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + } + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + ok = 42; + return 0; + } + + GNUNET_assert (size >= MSIZE); + + if (buf != NULL) + { + hdr = buf; + hdr->size = htons (MSIZE); + hdr->type = htons (MTYPE); + } + + char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", + p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, + GNUNET_i2s (&p->id)); + GNUNET_free (ps); + + return MSIZE; +} + +static void +sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + send_task = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", + p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); + GNUNET_free (receiver_s); + + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, MSIZE, 0, + TIMEOUT_TRANSMIT, ¬ify_ready, + p1); +} + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + static int c; + + c++; + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, + t->no, GNUNET_i2s (peer)); + GNUNET_free (ps); +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *p = cls; + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, + GNUNET_i2s (peer)); + + GNUNET_free (ps); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + cc = NULL; + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", + p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + + + send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); +} + + +int blacklist_cb (void *cls, + const struct + GNUNET_PeerIdentity * pid) +{ + struct PeerContext * p = cls; + int res = GNUNET_SYSERR; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u : Blacklist request for peer `%s'\n", p->no, GNUNET_i2s (pid)); + + if (p == p1) + { + blacklist_request_p1 = GNUNET_YES; + res = GNUNET_OK; + } + else if (p == p2) + { + blacklist_request_p2 = GNUNET_YES; + res = GNUNET_SYSERR; + } + + if (((blacklist_request_p2 == GNUNET_YES) && (blacklist_request_p1 == GNUNET_YES)) && (shutdown_task == GNUNET_SCHEDULER_NO_TASK)) + { + shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3), &end, NULL); + } + + return res; +} + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", + p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (sender_c); + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + connected = GNUNET_NO; + blacklist_request_p1 = GNUNET_NO; + blacklist_request_p2 = GNUNET_NO; + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, "test_transport_api_tcp_peer1.conf", 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, "test_transport_api_tcp_peer2.conf", 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + blacklist_p1 = GNUNET_TRANSPORT_blacklist (p1->cfg, + &blacklist_cb, + p1); + + blacklist_p2 = GNUNET_TRANSPORT_blacklist (p2->cfg, + &blacklist_cb, + p2); + + GNUNET_assert (blacklist_p1 != NULL); + GNUNET_assert (blacklist_p2 != NULL); +} + + +static int +check () +{ + static char *const argv[] = { "test-transport-api-blacklisting", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-transport-api-blacklisting", + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-transport-api-blacklisting", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + ret = check (); + + GNUNET_TRANSPORT_TESTING_done (tth); + + return ret; +} + +/* end of transport_api_blacklisting.c */ diff --git a/src/transport/test_transport_api_data.conf b/src/transport/test_transport_api_data.conf new file mode 100644 index 0000000..3955246 --- /dev/null +++ b/src/transport/test_transport_api_data.conf @@ -0,0 +1,12 @@ +@INLINE@ test_transport_defaults.conf +[PATHS] +DEFAULTCONFIG = test_transport_api_data.conf + +[transport-tcp] +PORT = 2094 + +[transport-udp] +PORT = 2094 + + + diff --git a/src/transport/test_transport_api_disconnect.c b/src/transport/test_transport_api_disconnect.c new file mode 100644 index 0000000..973c4cf --- /dev/null +++ b/src/transport/test_transport_api_disconnect.c @@ -0,0 +1,436 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api_disconnect.c + * @brief base test case for transport implementations + * + * This test case tests disconnect notifications in peer shutdown + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +#define MTYPE 12345 + +static char *test_source; + +static char *test_plugin; + +static char *test_name; + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static GNUNET_SCHEDULER_TaskIdentifier send_task; + +struct PeerContext *p1; + +struct PeerContext *p2; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +int shutdown_; + +char *cfg_file_p1; + +char *cfg_file_p2; + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +end () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (send_task); + send_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + p1 = NULL; + + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + p2 = NULL; + + /* success */ + ok = 0; +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + if (cc != NULL) + { + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + cc = NULL; + } + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (send_task); + send_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + ok = GNUNET_SYSERR; +} + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *p = cls; + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, + GNUNET_i2s (peer)); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (shutdown_ == GNUNET_YES) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Complete, shutting down...\n"); + GNUNET_SCHEDULER_add_now (&end, NULL); + } +} + + +static void +stop_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down peer %u (`%s')\n", p->no, + GNUNET_i2s (&p->id)); + shutdown_ = GNUNET_YES; + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + p2 = NULL; + GNUNET_assert (p2 == NULL); +} + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", + p->no, ps, ntohs (message->type), ntohs (message->size), t->no, + GNUNET_i2s (&t->id)); + + if ((MTYPE == ntohs (message->type)) && + (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size))) + { + ok = 1; + GNUNET_SCHEDULER_add_now (stop_peer, p2); + return; + } +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + struct PeerContext *p = cls; + struct GNUNET_MessageHeader *hdr; + + th = NULL; + + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout occurred while waiting for transmit_ready\n"); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + ok = 42; + return 0; + } + + GNUNET_assert (size >= 256); + + if (buf != NULL) + { + hdr = buf; + hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); + hdr->type = htons (MTYPE); + } + char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", + p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, + GNUNET_i2s (&p->id)); + GNUNET_free (ps); + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + send_task = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", + p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); + GNUNET_free (receiver_s); + + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0, + TIMEOUT_TRANSMIT, ¬ify_ready, + p1); +} + + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + static int c; + + c++; + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, + t->no, GNUNET_i2s (peer)); + GNUNET_free (ps); +} + + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + cc = NULL; + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", + p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); +} + + + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", + p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +} + + +static int +check () +{ + static char *const argv[] = { "test-transport-api", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + send_task = GNUNET_SCHEDULER_NO_TASK; + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); + GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, + &test_plugin); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); + + ret = check (); + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + + GNUNET_TRANSPORT_TESTING_done (tth); + + return ret; +} + +/* end of test_transport_api.c */ diff --git a/src/transport/test_transport_api_disconnect_tcp_peer1.conf b/src/transport/test_transport_api_disconnect_tcp_peer1.conf new file mode 100644 index 0000000..8bfa374 --- /dev/null +++ b/src/transport/test_transport_api_disconnect_tcp_peer1.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p1/ +DEFAULTCONFIG = test_transport_api_tcp_peer1.conf + +[transport-tcp] +PORT = 12000 +TIMEOUT = 5 s + +[arm] +PORT = 12005 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12004 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12003 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12002 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12001 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +#DEBUG = YES + diff --git a/src/transport/test_transport_api_disconnect_tcp_peer2.conf b/src/transport/test_transport_api_disconnect_tcp_peer2.conf new file mode 100644 index 0000000..6bb7fad --- /dev/null +++ b/src/transport/test_transport_api_disconnect_tcp_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p2/ +DEFAULTCONFIG = test_transport_api_tcp_peer2.conf + +[transport-tcp] +PORT = 12015 +TIMEOUT = 5 s + +[arm] +PORT = 12014 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12013 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12012 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12011 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12010 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + diff --git a/src/transport/test_transport_api_http_nat_peer1.conf b/src/transport/test_transport_api_http_nat_peer1.conf new file mode 100644 index 0000000..447508c --- /dev/null +++ b/src/transport/test_transport_api_http_nat_peer1.conf @@ -0,0 +1,38 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-http-p1/ +DEFAULTCONFIG = test_transport_api_http_nat_peer1.conf + +[nat] +BEHIND_NAT = YES +ENABLE_NAT_SERVER = YES + +[transport-http] +PORT = 0 + +[arm] +PORT = 12085 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12084 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12083 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12082 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +#DEBUG = YES +PORT = 12081 +PLUGINS = http +#BINARY = .libs/gnunet-service-transport +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +#PREFIX = valgrind --leak-check=full +#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args + diff --git a/src/transport/test_transport_api_http_nat_peer2.conf b/src/transport/test_transport_api_http_nat_peer2.conf new file mode 100644 index 0000000..2f56eab --- /dev/null +++ b/src/transport/test_transport_api_http_nat_peer2.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-http-p2/ +DEFAULTCONFIG = test_transport_api_http_nat_peer2.conf + +[transport-http] +PORT = 12090 + +[arm] +PORT = 12095 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12094 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12093 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12092 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +#DEBUG = YES +PORT = 12091 +PLUGINS = http +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +#PREFIX = valgrind --leak-check=full diff --git a/src/transport/test_transport_api_http_peer1.conf b/src/transport/test_transport_api_http_peer1.conf new file mode 100644 index 0000000..26c2969 --- /dev/null +++ b/src/transport/test_transport_api_http_peer1.conf @@ -0,0 +1,34 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-http-p1/ +DEFAULTCONFIG = test_transport_api_http_peer1.conf + +[transport-http] +PORT = 12080 + +[arm] +PORT = 12085 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12084 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12083 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12082 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +#DEBUG = YES +PORT = 12081 +PLUGINS = http +#BINARY = .libs/gnunet-service-transport +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +#PREFIX = valgrind --leak-check=full +#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args + diff --git a/src/transport/test_transport_api_http_peer2.conf b/src/transport/test_transport_api_http_peer2.conf new file mode 100644 index 0000000..fa7aa3b --- /dev/null +++ b/src/transport/test_transport_api_http_peer2.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-http-p2/ +DEFAULTCONFIG = test_transport_api_http_peer2.conf + +[transport-http] +PORT = 12090 + +[arm] +PORT = 12095 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12094 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12093 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12092 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +#DEBUG = YES +PORT = 12091 +PLUGINS = http +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +#PREFIX = valgrind --leak-check=full diff --git a/src/transport/test_transport_api_https_nat_peer1.conf b/src/transport/test_transport_api_https_nat_peer1.conf new file mode 100644 index 0000000..e97b473 --- /dev/null +++ b/src/transport/test_transport_api_https_nat_peer1.conf @@ -0,0 +1,36 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-https-p1/ +DEFAULTCONFIG = test_transport_api_https_nat_peer1.conf + +[nat] +BEHIND_NAT = YES +ENABLE_NAT_SERVER = YES + +[transport-https] +PORT = 0 +KEY_FILE = $SERVICEHOME/https_key_p1.key +CERT_FILE = $SERVICEHOME/https_cert_p1.crt + +[arm] +PORT = 12105 + +[statistics] +PORT = 12104 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12103 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12102 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12101 +PLUGINS = https +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +DEBUG = NO + + diff --git a/src/transport/test_transport_api_https_nat_peer2.conf b/src/transport/test_transport_api_https_nat_peer2.conf new file mode 100644 index 0000000..a23f3a5 --- /dev/null +++ b/src/transport/test_transport_api_https_nat_peer2.conf @@ -0,0 +1,33 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-https-p2/ +DEFAULTCONFIG = test_transport_api_https_nat_peer2.conf + +[transport-https] +PORT = 12110 +KEY_FILE = $SERVICEHOME/https_key_p2.key +CERT_FILE = $SERVICEHOME/https_cert_p2.crt + +[arm] +PORT = 12115 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12114 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12113 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12112 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12111 +PLUGINS = https +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +DEBUG = NO + + diff --git a/src/transport/test_transport_api_https_peer1.conf b/src/transport/test_transport_api_https_peer1.conf new file mode 100644 index 0000000..8a93ca1 --- /dev/null +++ b/src/transport/test_transport_api_https_peer1.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-https-p1/ +DEFAULTCONFIG = test_transport_api_https_peer1.conf + +[transport-https] +PORT = 12100 +KEY_FILE = $SERVICEHOME/https_key_p1.key +CERT_FILE = $SERVICEHOME/https_cert_p1.crt + +[arm] +PORT = 12105 + +[statistics] +PORT = 12104 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12103 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12102 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12101 +PLUGINS = https +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +DEBUG = NO + + diff --git a/src/transport/test_transport_api_https_peer2.conf b/src/transport/test_transport_api_https_peer2.conf new file mode 100644 index 0000000..0710f41 --- /dev/null +++ b/src/transport/test_transport_api_https_peer2.conf @@ -0,0 +1,33 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-https-p2/ +DEFAULTCONFIG = test_transport_api_https_peer2.conf + +[transport-https] +PORT = 12110 +KEY_FILE = $SERVICEHOME/https_key_p2.key +CERT_FILE = $SERVICEHOME/https_cert_p2.crt + +[arm] +PORT = 12115 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12114 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12113 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12112 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12111 +PLUGINS = https +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +DEBUG = NO + + diff --git a/src/transport/test_transport_api_limited_sockets.c b/src/transport/test_transport_api_limited_sockets.c new file mode 100644 index 0000000..8b8cdc0 --- /dev/null +++ b/src/transport/test_transport_api_limited_sockets.c @@ -0,0 +1,383 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api.c + * @brief base test case for transport implementations + * + * This test case serves as a base for tcp, udp, and udp-nat + * transport test cases. Based on the executable being run + * the correct test case will be performed. Conservation of + * C code apparently. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO + +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +#define MTYPE 12345 + +#define MAX_FILES 50 + +static char *test_source; + +static char *test_plugin; + +static char *test_name; + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static GNUNET_SCHEDULER_TaskIdentifier send_task; + +struct PeerContext *p1; + +struct PeerContext *p2; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +char *cfg_file_p1; + +char *cfg_file_p2; + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +end () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + + if (cc != NULL) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + ok = GNUNET_SYSERR; +} + + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received message of type %d from peer %s!\n", + ntohs (message->type), GNUNET_i2s (peer)); + + if ((MTYPE == ntohs (message->type)) && + (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size))) + { + ok = 0; + end (); + } + else + { + GNUNET_break (0); + ok = 1; + end (); + } +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + struct PeerContext *p = cls; + struct GNUNET_MessageHeader *hdr; + + th = NULL; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting message with %u bytes to peer %s\n", + sizeof (struct GNUNET_MessageHeader), GNUNET_i2s (&p->id)); + GNUNET_assert (size >= 256); + + if (buf != NULL) + { + hdr = buf; + hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); + hdr->type = htons (MTYPE); + } + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n", + GNUNET_i2s (peer), cls); +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n", + GNUNET_i2s (peer), cls); + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; +} + +static void +sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + send_task = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + th = GNUNET_TRANSPORT_notify_transmit_ready (p1->th, &p2->id, 256, 0, TIMEOUT, + ¬ify_ready, &p1); +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + cc = NULL; + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c, + GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + // FIXME: THIS IS REQUIRED! SEEMS TO BE A BUG! + send_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &sendtask, NULL); +} + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +} + + +static int +check () +{ + static char *const argv[] = { "test-transport-api", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + send_task = GNUNET_SCHEDULER_NO_TASK; + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + test_plugin = NULL; + + GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); + GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, + &test_plugin); + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + +#if !HAVE_SETRLIMIT + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot run test on this system\n"); + + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + + return 0; +#else + struct rlimit r_file_old; + struct rlimit r_file_new; + int res; + + res = getrlimit (RLIMIT_NOFILE, &r_file_old); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Maximum number of open files was: %u/%u\n", r_file_old.rlim_cur, + r_file_old.rlim_max); + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Setting maximum number of open files to: %u\n", MAX_FILES); + r_file_new.rlim_cur = MAX_FILES; + r_file_new.rlim_max = r_file_old.rlim_max; + res = setrlimit (RLIMIT_NOFILE, &r_file_new); + + if (res != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Setting limit failed!\n"); + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + return 0; + } + + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); + ret = check (); +#endif + + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + +#if HAVE_SETRLIMIT + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Restoring previous value maximum number of open files\n"); + res = setrlimit (RLIMIT_NOFILE, &r_file_old); + if (res != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Restoring limit failed!\n"); + return 0; + } +#endif + + return ret; +} + +/* end of test_transport_api.c */ diff --git a/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf b/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf new file mode 100644 index 0000000..dee44f6 --- /dev/null +++ b/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p1/ +DEFAULTCONFIG = test_transport_api_tcp_peer1.conf + +[transport-tcp] +PORT = 12000 +TIMEOUT = 5 s + +[arm] +PORT = 12005 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12004 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12003 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12002 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12001 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + + diff --git a/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf b/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf new file mode 100644 index 0000000..04324f4 --- /dev/null +++ b/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p2/ +DEFAULTCONFIG = test_transport_api_tcp_peer2.conf + +[transport-tcp] +PORT = 0 +TIMEOUT = 5 s + +[arm] +PORT = 12014 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12013 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12012 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12011 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12010 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + diff --git a/src/transport/test_transport_api_multi_peer1.conf b/src/transport/test_transport_api_multi_peer1.conf new file mode 100644 index 0000000..a7c57fc --- /dev/null +++ b/src/transport/test_transport_api_multi_peer1.conf @@ -0,0 +1,43 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-multi-p1/ +DEFAULTCONFIG = test_transport_api_multi_peer1.conf + +[transport-tcp] +PORT = 12140 +TIMEOUT = 5 s + +[transport-udp] +PORT = 12141 + +[transport-http] +PORT = 12142 + +[transport-https] +PORT = 12143 + +[arm] +PORT = 12149 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12148 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12147 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12146 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12145 +PLUGINS = tcp udp unix +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + +[transport-unix] +PORT = 12144 + diff --git a/src/transport/test_transport_api_multi_peer2.conf b/src/transport/test_transport_api_multi_peer2.conf new file mode 100644 index 0000000..8008e7f --- /dev/null +++ b/src/transport/test_transport_api_multi_peer2.conf @@ -0,0 +1,46 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-multi-p2/ +DEFAULTCONFIG = test_transport_api_multi_peer2.conf + +[nat] +ALLOW_NAT = NO + +[transport-tcp] +PORT = 12150 +TIMEOUT = 5 s + +[transport-udp] +PORT = 12151 + +[transport-http] +PORT = 12152 + +[transport-https] +PORT = 12153 + +[arm] +PORT = 12159 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12158 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12157 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12156 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12155 +PLUGINS = tcp udp unix +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + +[transport-unix] +PORT = 12154 + diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c new file mode 100644 index 0000000..f719a42 --- /dev/null +++ b/src/transport/test_transport_api_reliability.c @@ -0,0 +1,538 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api_reliability.c + * @brief base test case for transport implementations + * + * This test case serves as a base for tcp and http + * transport test cases to check that the transports + * achieve reliable message delivery. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_transport_service.h" +#include "gauger.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO + +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * Testcase timeout + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) + + +static char *test_source; + +static char *test_plugin; + +static char *test_name; + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +struct PeerContext *p1; + +struct PeerContext *p2; + +struct PeerContext *sender; + +struct PeerContext *receiver; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +char *cfg_file_p1; + +char *cfg_file_p2; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + + +/* + * Testcase specific declarations + */ + +/** + * Note that this value must not significantly exceed + * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise + * messages may be dropped even for a reliable transport. + */ +#define TOTAL_MSGS (1024 * 2) + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct TestMessage +{ + struct GNUNET_MessageHeader header; + uint32_t num; +}; +GNUNET_NETWORK_STRUCT_END + +static int msg_scheduled; +static int msg_sent; +static int msg_recv_expected; +static int msg_recv; + +static int test_failed; +static int test_connected; + +static unsigned long long total_bytes; + +static struct GNUNET_TIME_Absolute start_time; + +/* + * END Testcase specific declarations + */ + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +end () +{ + unsigned long long delta; + + char *value_name; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; + FPRINTF (stderr, "\nThroughput was %llu kb/s\n", + total_bytes * 1000 / 1024 / delta); + GNUNET_asprintf (&value_name, "reliable_%s", test_plugin); + GAUGER ("TRANSPORT", value_name, (int) (total_bytes * 1000 / 1024 / delta), + "kb/s"); + GNUNET_free (value_name); + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (cc != NULL) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + GNUNET_TRANSPORT_TESTING_done (tth); +} + +static void +end_badly () +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + if (test_connected == GNUNET_YES) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n"); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n"); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (cc != NULL) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + GNUNET_TRANSPORT_TESTING_done (tth); + + ok = GNUNET_SYSERR; +} + + +static unsigned int +get_size (unsigned int iter) +{ + unsigned int ret; + + ret = (iter * iter * iter); + return sizeof (struct TestMessage) + (ret % 60000); +} + + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + static int n; + unsigned int s; + char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + const struct TestMessage *hdr; + + hdr = (const struct TestMessage *) message; + s = get_size (n); + if (MTYPE != ntohs (message->type)) + return; + msg_recv_expected = n; + msg_recv = ntohl (hdr->num); + if (ntohs (message->size) != (s)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u of size %u, got %u bytes of message %u\n", + n, s, ntohs (message->size), ntohl (hdr->num)); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + test_failed = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } + if (ntohl (hdr->num) != n) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u of size %u, got %u bytes of message %u\n", + n, s, ntohs (message->size), ntohl (hdr->num)); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + test_failed = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } + memset (cbuf, n, s - sizeof (struct TestMessage)); + if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u with bits %u, but body did not match\n", n, + (unsigned char) n); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + test_failed = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +#if VERBOSE + if (ntohl (hdr->num) % 5000 == 0) + { + struct PeerContext *p = cls; + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", + p->no, ps, ntohl (hdr->num), ntohs (message->size), + GNUNET_i2s (peer)); + GNUNET_free (ps); + } +#endif + n++; + if (0 == (n % (TOTAL_MSGS / 100))) + { + FPRINTF (stderr, "%s", "."); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + } + if (n == TOTAL_MSGS) + { + ok = 0; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\nAll messages received\n"); + end (); + } +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + static int n; + char *cbuf = buf; + struct TestMessage hdr; + unsigned int s; + unsigned int ret; + + th = NULL; + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout occurred while waiting for transmit_ready for message %u of %u\n", + msg_scheduled, TOTAL_MSGS); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + ok = 42; + return 0; + } + + ret = 0; + s = get_size (n); + GNUNET_assert (size >= s); + GNUNET_assert (buf != NULL); + cbuf = buf; + do + { + hdr.header.size = htons (s); + hdr.header.type = htons (MTYPE); + hdr.num = htonl (n); + msg_sent = n; + memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); + ret += sizeof (struct TestMessage); + memset (&cbuf[ret], n, s - sizeof (struct TestMessage)); + ret += s - sizeof (struct TestMessage); +#if VERBOSE + if (n % 5000 == 0) + { + + char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message of size %u from peer %u (`%4s') -> peer %u (`%s') !\n", + n, sender->no, GNUNET_i2s (&sender->id), receiver->no, + receiver_s); + GNUNET_free (receiver_s); + } +#endif + n++; + s = get_size (n); + if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) + break; /* sometimes pack buffer full, sometimes not */ + } + while (size - ret >= s); + if (n < TOTAL_MSGS) + { + if (th == NULL) + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0, + TIMEOUT_TRANSMIT, + ¬ify_ready, NULL); + msg_scheduled = n; + } + if (n % 5000 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Returning total message block of size %u\n", ret); + } + total_bytes += ret; + if (n == TOTAL_MSGS) + { + FPRINTF (stderr, "%s", "\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All messages sent\n"); + } + return ret; +} + + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') connected to us!\n", + p->no, GNUNET_i2s (peer)); +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *p = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') disconnected!\n", p->no, + GNUNET_i2s (peer)); + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + +} + +static void +sendtask () +{ + start_time = GNUNET_TIME_absolute_get (); + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0, + TIMEOUT_TRANSMIT, ¬ify_ready, + NULL); +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", + p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + test_connected = GNUNET_YES; + cc = NULL; + + GNUNET_SCHEDULER_add_now (&sendtask, NULL); + +} + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + test_connected = GNUNET_NO; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u: `%s' using configuration file `%s'\n", p1->no, + GNUNET_i2s (&p1->id), cfg_file_p1); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u: `%s' using configuration file `%s'\n", p2->no, + GNUNET_i2s (&p2->id), cfg_file_p2); + + sender = p2; + receiver = p1; + + char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test triest to send from %u (%s) -> peer %u (%s)\n", sender->no, + sender_c, receiver->no, GNUNET_i2s (&receiver->id)); + GNUNET_free (sender_c); + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +} + +static int +check () +{ + static char *argv[] = { "test_transport", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); + GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, + &test_plugin); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); + + ret = check (); + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + + return ret; +} + + +/* end of test_transport_api_reliability.c */ diff --git a/src/transport/test_transport_api_reliability_http_nat_peer1.conf b/src/transport/test_transport_api_reliability_http_nat_peer1.conf new file mode 100644 index 0000000..cd841a3 --- /dev/null +++ b/src/transport/test_transport_api_reliability_http_nat_peer1.conf @@ -0,0 +1,38 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-http-p1/ +DEFAULTCONFIG = test_transport_api_reliability_http_nat_peer1.conf + +[nat] +BEHIND_NAT = YES +ENABLE_NAT_SERVER = YES + +[transport-http] +PORT = 0 + +[arm] +PORT = 12085 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12084 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12083 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12082 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +#DEBUG = YES +PORT = 12081 +PLUGINS = http +#BINARY = .libs/gnunet-service-transport +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +#PREFIX = valgrind --leak-check=full +#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args + diff --git a/src/transport/test_transport_api_reliability_http_nat_peer2.conf b/src/transport/test_transport_api_reliability_http_nat_peer2.conf new file mode 100644 index 0000000..c87a256 --- /dev/null +++ b/src/transport/test_transport_api_reliability_http_nat_peer2.conf @@ -0,0 +1,35 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-http-p2/ +DEFAULTCONFIG = test_transport_api_reliability_http_nat_peer2.conf + +[ats] +WAN_QUOTA_OUT = 1073741824 +WAN_QUOTA_IN = 1073741824 + +[transport-http] +PORT = 12090 + +[arm] +PORT = 12095 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12094 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12093 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12092 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +#DEBUG = YES +PORT = 12091 +PLUGINS = http +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +#PREFIX = valgrind --leak-check=full diff --git a/src/transport/test_transport_api_reliability_http_peer1.conf b/src/transport/test_transport_api_reliability_http_peer1.conf new file mode 100644 index 0000000..ebb6e43 --- /dev/null +++ b/src/transport/test_transport_api_reliability_http_peer1.conf @@ -0,0 +1,33 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-http-p1/ +DEFAULTCONFIG = test_transport_api_reliability_http_peer1.conf + +[transport-tcp] +TIMEOUT = 5 s + +[transport-http] +PORT = 12180 + +[arm] +PORT = 12185 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12184 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12183 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12182 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12181 +PLUGINS = http +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +#DEBUG = YES + diff --git a/src/transport/test_transport_api_reliability_http_peer2.conf b/src/transport/test_transport_api_reliability_http_peer2.conf new file mode 100644 index 0000000..c21fa1d --- /dev/null +++ b/src/transport/test_transport_api_reliability_http_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-http-p2/ +DEFAULTCONFIG = test_transport_api_reliability_http_peer2.conf + +[transport-http] +PORT = 12190 + +[arm] +PORT = 12195 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12194 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12193 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12192 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12191 +PLUGINS = http +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +#DEBUG = YES + diff --git a/src/transport/test_transport_api_reliability_https_nat_peer1.conf b/src/transport/test_transport_api_reliability_https_nat_peer1.conf new file mode 100644 index 0000000..ca14c72 --- /dev/null +++ b/src/transport/test_transport_api_reliability_https_nat_peer1.conf @@ -0,0 +1,36 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-https-p1/ +DEFAULTCONFIG = test_transport_api_reliability_https_nat_peer1.conf + +[nat] +BEHIND_NAT = YES +ENABLE_NAT_SERVER = YES + +[transport-https] +PORT = 0 +KEY_FILE = $SERVICEHOME/https_key_p1.key +CERT_FILE = $SERVICEHOME/https_cert_p1.crt + +[arm] +PORT = 12105 + +[statistics] +PORT = 12104 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12103 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12102 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12101 +PLUGINS = https +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +DEBUG = NO + + diff --git a/src/transport/test_transport_api_reliability_https_nat_peer2.conf b/src/transport/test_transport_api_reliability_https_nat_peer2.conf new file mode 100644 index 0000000..b7c2e97 --- /dev/null +++ b/src/transport/test_transport_api_reliability_https_nat_peer2.conf @@ -0,0 +1,33 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-https-p2/ +DEFAULTCONFIG = test_transport_api_reliability_https_nat_peer2.conf + +[transport-https] +PORT = 12110 +KEY_FILE = $SERVICEHOME/https_key_p2.key +CERT_FILE = $SERVICEHOME/https_cert_p2.crt + +[arm] +PORT = 12115 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12114 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12113 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12112 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12111 +PLUGINS = https +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +DEBUG = NO + + diff --git a/src/transport/test_transport_api_reliability_https_peer1.conf b/src/transport/test_transport_api_reliability_https_peer1.conf new file mode 100644 index 0000000..0699f69 --- /dev/null +++ b/src/transport/test_transport_api_reliability_https_peer1.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-https-p1/ +DEFAULTCONFIG = test_transport_api_reliability_https_peer1.conf + +[transport-https] +PORT = 12300 +KEY_FILE = $SERVICEHOME/https_key_p1.key +CERT_FILE = $SERVICEHOME/https_cert_p1.crt + +[arm] +PORT = 12305 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12304 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12303 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12302 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12301 +PLUGINS = https +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + diff --git a/src/transport/test_transport_api_reliability_https_peer2.conf b/src/transport/test_transport_api_reliability_https_peer2.conf new file mode 100644 index 0000000..bd344ab --- /dev/null +++ b/src/transport/test_transport_api_reliability_https_peer2.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-https-p2/ +DEFAULTCONFIG = test_transport_api_reliability_https_peer2.conf + +[transport-https] +PORT = 12310 +KEY_FILE = $SERVICEHOME/https_key_p2.key +CERT_FILE = $SERVICEHOME/https_cert_p2.crt + +[arm] +PORT = 12315 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12314 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12313 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12312 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12311 +PLUGINS = https +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + + diff --git a/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf b/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf new file mode 100644 index 0000000..2f0b3ba --- /dev/null +++ b/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf @@ -0,0 +1,36 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-reliability-tcp-nat-p1/ +DEFAULTCONFIG = test_transport_api_reliability_tcp_nat_peer1.conf + +[nat] +BEHIND_NAT = YES +ENABLE_NAT_SERVER = YES +DISABLEV6 = YES + +[transport-tcp] +PORT = 0 +TIMEOUT = 5 s + +[arm] +PORT = 1204 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12023 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12022 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12021 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 29542 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + + diff --git a/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf b/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf new file mode 100644 index 0000000..20ca7a0 --- /dev/null +++ b/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf @@ -0,0 +1,35 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-reliability-tcp-nat-p2/ +DEFAULTCONFIG = test_transport_api_reliability_tcp_nat_peer2.conf + +[nat] +DISABLEV6 = YES +ENABLE_NAT_CLIENT = YES + +[transport-tcp] +PORT = 12030 +TIMEOUT = 5 s + +[arm] +PORT = 12034 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12033 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12032 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12031 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 45923 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + + diff --git a/src/transport/test_transport_api_reliability_tcp_peer1.conf b/src/transport/test_transport_api_reliability_tcp_peer1.conf new file mode 100644 index 0000000..a05165a --- /dev/null +++ b/src/transport/test_transport_api_reliability_tcp_peer1.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p1/ +DEFAULTCONFIG = test_transport_api_reliability_tcp_peer1.conf + +[transport-tcp] +PORT = 12000 +TIMEOUT = 5 s + +[arm] +PORT = 12005 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12004 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12003 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12002 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12001 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + diff --git a/src/transport/test_transport_api_reliability_tcp_peer2.conf b/src/transport/test_transport_api_reliability_tcp_peer2.conf new file mode 100644 index 0000000..2ceff2c --- /dev/null +++ b/src/transport/test_transport_api_reliability_tcp_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p2/ +DEFAULTCONFIG = test_transport_api_reliability_tcp_peer2.conf + +[transport-tcp] +PORT = 12015 +TIMEOUT = 5 s + +[arm] +PORT = 12014 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12013 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12012 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12011 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12010 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +#DEBUG = YES diff --git a/src/transport/test_transport_api_reliability_wlan_peer1.conf b/src/transport/test_transport_api_reliability_wlan_peer1.conf new file mode 100644 index 0000000..9dd9d1b --- /dev/null +++ b/src/transport/test_transport_api_reliability_wlan_peer1.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-wlan-p1/ +DEFAULTCONFIG = test_transport_api_wlan_peer1.conf + +[transport-wlan] +TESTMODE = 1 + +[arm] +PORT = 12164 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12163 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12162 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12161 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12160 +PLUGINS = wlan +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + + diff --git a/src/transport/test_transport_api_reliability_wlan_peer2.conf b/src/transport/test_transport_api_reliability_wlan_peer2.conf new file mode 100644 index 0000000..bc868d7 --- /dev/null +++ b/src/transport/test_transport_api_reliability_wlan_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-wlan-p2/ +DEFAULTCONFIG = test_transport_api_wlan_peer2.conf + +[transport-wlan] +INTERFACE = mon1 +TESTMODE = 2 + +[arm] +PORT = 12174 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12173 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12172 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12171 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12170 +PLUGINS = wlan +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + diff --git a/src/transport/test_transport_api_restart_1peer.c b/src/transport/test_transport_api_restart_1peer.c new file mode 100644 index 0000000..b414805 --- /dev/null +++ b/src/transport/test_transport_api_restart_1peer.c @@ -0,0 +1,491 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api_restart_1peer.c + * @brief base test case for transport implementations + * + * This test case starts 2 peers, connects and exchanges a message + * 1 peer is restarted and tested if peers reconnect + * C code apparently. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +#define MTYPE 12345 + +static char *test_name; + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static GNUNET_SCHEDULER_TaskIdentifier send_task; + +static GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + +struct PeerContext *p1; + +int p1_connected; + +struct PeerContext *p2; + +int p2_connected; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +char *cfg_file_p1; + +char *cfg_file_p2; + +static int restarted; + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +end () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + send_task = GNUNET_SCHEDULER_NO_TASK; + + if (reconnect_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (reconnect_task); + reconnect_task = GNUNET_SCHEDULER_NO_TASK; + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + if (restarted == GNUNET_YES) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was restarted\n"); + + if (restarted == GNUNET_NO) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was NOT restarted\n"); + + if (reconnect_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (reconnect_task); + reconnect_task = GNUNET_SCHEDULER_NO_TASK; + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + send_task = GNUNET_SCHEDULER_NO_TASK; + + if (cc != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + cc = NULL; + } + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + ok = GNUNET_SYSERR; +} + +static void +reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerContext *p = cls; + + reconnect_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_TRANSPORT_try_connect (p->th, &p2->id); + reconnect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, p); +} + +static void +restart_cb (struct PeerContext *p, void *cls) +{ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Restarted peer %u (`%4s'), issuing reconnect\n", p->no, + GNUNET_i2s (&p->id)); + + reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, p); +} + +static void +restart (struct PeerContext *p, char *cfg_file) +{ + GNUNET_assert (p != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting peer %u (`%4s')\n", p->no, + GNUNET_i2s (&p->id)); + GNUNET_TRANSPORT_TESTING_restart_peer (tth, p, cfg_file, &restart_cb, p); + return; +} + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", + p->no, ps, ntohs (message->type), ntohs (message->size), t->no, + GNUNET_i2s (&t->id)); + GNUNET_free (ps); + + if ((MTYPE == ntohs (message->type)) && + (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size))) + { + if (restarted == GNUNET_NO) + { + restarted = GNUNET_YES; + restart (p1, cfg_file_p1); + return; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Restarted peers connected and message was sent, stopping test...\n"); + ok = 0; + end (); + } + } + else + { + GNUNET_break (0); + ok = 1; + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + } +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + struct PeerContext *p = cls; + struct GNUNET_MessageHeader *hdr; + + th = NULL; + + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout occurred while waiting for transmit_ready\n"); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + ok = 42; + return 0; + } + + GNUNET_assert (size >= 256); + + if (buf != NULL) + { + hdr = buf; + hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); + hdr->type = htons (MTYPE); + } + char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", + p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, + GNUNET_i2s (&p->id)); + GNUNET_free (ps); + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + send_task = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", + p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); + GNUNET_free (receiver_s); + + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0, + TIMEOUT_TRANSMIT, ¬ify_ready, + p1); +} + + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + static int c; + + c++; + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + { + p1_connected = GNUNET_YES; + t = p1; + } + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + { + p2_connected = GNUNET_YES; + t = p2; + } + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, + t->no, GNUNET_i2s (peer)); + GNUNET_free (ps); + + if ((restarted == GNUNET_YES) && ((p1_connected == GNUNET_YES) && (p2_connected == GNUNET_YES))) + { + /* Peer was restarted and we received 3 connect messages (2 from first connect, 1 from reconnect) */ + send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); + } +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *p = cls; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + { + p1_connected = GNUNET_NO; + } + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + { + p2_connected = GNUNET_NO; + } + + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, + GNUNET_i2s (peer)); + GNUNET_free (ps); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + cc = NULL; + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", + p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); +} + + + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", + p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (sender_c); + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + p1_connected = GNUNET_NO; + p2_connected = GNUNET_NO; + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +} + + +static int +check () +{ + static char *const argv[] = { "test-transport-api", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + send_task = GNUNET_SCHEDULER_NO_TASK; + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + GNUNET_asprintf (&cfg_file_p1, "test_transport_api_tcp_peer1.conf"); + GNUNET_asprintf (&cfg_file_p2, "test_transport_api_tcp_peer2.conf"); + + ret = check (); + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + GNUNET_free (test_name); + + GNUNET_TRANSPORT_TESTING_done (tth); + + return ret; +} + +/* end of test_transport_api_restart_1peer.c */ diff --git a/src/transport/test_transport_api_restart_2peers.c b/src/transport/test_transport_api_restart_2peers.c new file mode 100644 index 0000000..86758df --- /dev/null +++ b/src/transport/test_transport_api_restart_2peers.c @@ -0,0 +1,477 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api_restart_2peers.c + * @brief base test case for transport implementations + * + * This test case starts 2 peers, connects and exchanges a message + * boths peer are restarted and tested if peers reconnect + * C code apparently. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +#define MTYPE 12345 + +static char *test_name; + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static GNUNET_SCHEDULER_TaskIdentifier send_task; + +static GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + +struct PeerContext *p1; + +struct PeerContext *p2; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +char *cfg_file_p1; + +char *cfg_file_p2; + +static int restarted; + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +end () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + send_task = GNUNET_SCHEDULER_NO_TASK; + + if (reconnect_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (reconnect_task); + reconnect_task = GNUNET_SCHEDULER_NO_TASK; + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + if (restarted == GNUNET_YES) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was restarted\n"); + + if (restarted == GNUNET_NO) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was NOT restarted\n"); + + if (reconnect_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (reconnect_task); + reconnect_task = GNUNET_SCHEDULER_NO_TASK; + + if (send_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (send_task); + send_task = GNUNET_SCHEDULER_NO_TASK; + + if (cc != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + cc = NULL; + } + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + ok = GNUNET_SYSERR; +} + +static void +reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerContext *p = cls; + + reconnect_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_TRANSPORT_try_connect (p1->th, &p2->id); + reconnect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, p); +} + +static void +restart_cb (struct PeerContext *p, void *cls) +{ + static int c; + + c++; + + if (c != 2) + return; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Restarted peer %u (`%4s'), issuing reconnect\n", p->no, + GNUNET_i2s (&p->id)); + + reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, p); +} + +static void +restart (struct PeerContext *p, char *cfg_file) +{ + GNUNET_assert (p != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting peer %u (`%4s')\n", p->no, + GNUNET_i2s (&p->id)); + GNUNET_TRANSPORT_TESTING_restart_peer (tth, p, cfg_file, &restart_cb, p); + return; +} + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", + p->no, ps, ntohs (message->type), ntohs (message->size), t->no, + GNUNET_i2s (&t->id)); + GNUNET_free (ps); + + if ((MTYPE == ntohs (message->type)) && + (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size))) + { + if (restarted == GNUNET_NO) + { + restarted = GNUNET_YES; + restart (p1, cfg_file_p1); + restart (p2, cfg_file_p2); + return; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Restarted peers connected, stopping test...\n"); + ok = 0; + end (); + } + } + else + { + GNUNET_break (0); + ok = 1; + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + } +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + struct PeerContext *p = cls; + struct GNUNET_MessageHeader *hdr; + + th = NULL; + + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout occurred while waiting for transmit_ready\n"); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + ok = 42; + return 0; + } + + GNUNET_assert (size >= 256); + + if (buf != NULL) + { + hdr = buf; + hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); + hdr->type = htons (MTYPE); + } + char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", + p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, + GNUNET_i2s (&p->id)); + GNUNET_free (ps); + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + send_task = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", + p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); + GNUNET_free (receiver_s); + + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0, + TIMEOUT_TRANSMIT, ¬ify_ready, + p1); +} + + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + static int c; + + c++; + struct PeerContext *p = cls; + struct PeerContext *t = NULL; + + if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) + t = p1; + if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) + t = p2; + GNUNET_assert (t != NULL); + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, + t->no, GNUNET_i2s (peer)); + GNUNET_free (ps); + + if ((restarted == GNUNET_YES) && (c == 4)) + { + send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); + } +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *p = cls; + + + char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, + GNUNET_i2s (peer)); + GNUNET_free (ps); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + cc = NULL; + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", + p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); +} + + + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", + p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (sender_c); + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +} + + +static int +check () +{ + static char *const argv[] = { "test-transport-api", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + send_task = GNUNET_SCHEDULER_NO_TASK; + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + GNUNET_asprintf (&cfg_file_p1, "test_transport_api_tcp_peer1.conf"); + GNUNET_asprintf (&cfg_file_p2, "test_transport_api_tcp_peer2.conf"); + + ret = check (); + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + GNUNET_free (test_name); + + GNUNET_TRANSPORT_TESTING_done (tth); + + return ret; +} + +/* end of test_transport_api_restart_2peers.c */ diff --git a/src/transport/test_transport_api_tcp_nat_peer1.conf b/src/transport/test_transport_api_tcp_nat_peer1.conf new file mode 100644 index 0000000..78afb3d --- /dev/null +++ b/src/transport/test_transport_api_tcp_nat_peer1.conf @@ -0,0 +1,36 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-nat-p1/ +DEFAULTCONFIG = test_transport_api_tcp_nat_peer1.conf + +[nat] +BEHIND_NAT = YES +ENABLE_NAT_SERVER = YES +DISABLEV6 = YES + +[transport-tcp] +PORT = 0 +TIMEOUT = 5 s + +[arm] +PORT = 1204 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12023 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12022 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12021 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 29542 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +#DEBUG = YES + diff --git a/src/transport/test_transport_api_tcp_nat_peer2.conf b/src/transport/test_transport_api_tcp_nat_peer2.conf new file mode 100644 index 0000000..d94ebb1 --- /dev/null +++ b/src/transport/test_transport_api_tcp_nat_peer2.conf @@ -0,0 +1,34 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-nat-p2/ +DEFAULTCONFIG = test_transport_api_tcp_nat_peer2.conf + +[nat] +DISABLEV6 = YES +ENABLE_NAT_CLIENT = YES + +[transport-tcp] +PORT = 12030 +TIMEOUT = 5 s + +[arm] +PORT = 12034 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12033 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12032 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12031 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 45923 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +#DEBUG = YES diff --git a/src/transport/test_transport_api_tcp_peer1.conf b/src/transport/test_transport_api_tcp_peer1.conf new file mode 100644 index 0000000..8bfa374 --- /dev/null +++ b/src/transport/test_transport_api_tcp_peer1.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p1/ +DEFAULTCONFIG = test_transport_api_tcp_peer1.conf + +[transport-tcp] +PORT = 12000 +TIMEOUT = 5 s + +[arm] +PORT = 12005 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12004 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12003 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12002 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12001 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +#DEBUG = YES + diff --git a/src/transport/test_transport_api_tcp_peer2.conf b/src/transport/test_transport_api_tcp_peer2.conf new file mode 100644 index 0000000..6bb7fad --- /dev/null +++ b/src/transport/test_transport_api_tcp_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p2/ +DEFAULTCONFIG = test_transport_api_tcp_peer2.conf + +[transport-tcp] +PORT = 12015 +TIMEOUT = 5 s + +[arm] +PORT = 12014 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12013 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12012 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12011 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12010 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + diff --git a/src/transport/test_transport_api_timeout.c b/src/transport/test_transport_api_timeout.c new file mode 100644 index 0000000..9ce701a --- /dev/null +++ b/src/transport/test_transport_api_timeout.c @@ -0,0 +1,361 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api_timeout.c + * @brief test case for transport plugin implementations complying timeout + * settings + * + * + * This test case serves ensures that no peer disconnect events occurs + * while plugins are idle + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO + +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on transmitting the message? + */ +#define WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90) + +#define MTYPE 12345 + +static char *test_source; + +static char *test_plugin; + +static char *test_name; + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static GNUNET_SCHEDULER_TaskIdentifier timer_task; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +struct PeerContext *p1; + +struct PeerContext *p2; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +char *cfg_file_p1; + +char *cfg_file_p2; + +static struct GNUNET_TIME_Relative time_running; + +static int shutdown_flag; + +static int disconnects; + + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + + +static void +end () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + if (timer_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (timer_task); + timer_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + if (disconnects == 0) + ok = 0; + else + { + ok = disconnects; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Fail! Had %u disconnects while waiting %llu seconds \n", + disconnects, WAIT.rel_value); + } + + GNUNET_TRANSPORT_TESTING_done (tth); +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + if (timer_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (timer_task); + timer_task = GNUNET_SCHEDULER_NO_TASK; + } + if (cc != NULL) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + ok = GNUNET_SYSERR; + + GNUNET_TRANSPORT_TESTING_done (tth); +} + + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received message of type %d from peer %s!\n", + ntohs (message->type), GNUNET_i2s (peer)); +} + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n", + GNUNET_i2s (peer), cls); +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + if (shutdown_flag != GNUNET_YES) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "FAIL! Peer `%4s' disconnected during waiting period!\n", + GNUNET_i2s (peer)); + disconnects++; + } + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; +} + +static void +timer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static int percentage; + + timer_task = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + percentage += 10; + time_running = + GNUNET_TIME_relative_add (time_running, + GNUNET_TIME_relative_divide (WAIT, 10)); + + if (time_running.rel_value == + GNUNET_TIME_relative_max (time_running, WAIT).rel_value) + { + FPRINTF (stderr, "%s", "100%%\n"); + shutdown_flag = GNUNET_YES; + GNUNET_SCHEDULER_add_now (&end, NULL); + } + else + { + FPRINTF (stderr, "%u%%..", percentage); + timer_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (WAIT, 10), + &timer, NULL); + } +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + cc = NULL; + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c, + GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + shutdown_flag = GNUNET_NO; + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Waiting for %llu seconds\n", (WAIT.rel_value) / 1000); + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_delayed (WAIT, &end_badly, NULL); + + timer_task = GNUNET_SCHEDULER_add_now (&timer, NULL); +} + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", + p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +} + +static int +check () +{ + static char *const argv[] = { "test-transport-api-timeout", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + timer_task = GNUNET_SCHEDULER_NO_TASK; + + ok = 1; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-transport-api-timeout", "nohelp", options, &run, + &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); + GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, + &test_plugin); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); + + ret = check (); + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + + + return ret; +} + +/* end of test_transport_api_timeout.c*/ diff --git a/src/transport/test_transport_api_timeout_http_peer1.conf b/src/transport/test_transport_api_timeout_http_peer1.conf new file mode 100644 index 0000000..a28750a --- /dev/null +++ b/src/transport/test_transport_api_timeout_http_peer1.conf @@ -0,0 +1,36 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-http-p1/ +DEFAULTCONFIG = test_transport_api_http_peer1.conf + +[nat] + +[transport-http] +PORT = 12080 + +[arm] +PORT = 12085 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12084 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12083 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12082 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +#DEBUG = YES +PORT = 12081 +PLUGINS = http +#BINARY = .libs/gnunet-service-transport +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +#PREFIX = valgrind --leak-check=full +#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args + diff --git a/src/transport/test_transport_api_timeout_http_peer2.conf b/src/transport/test_transport_api_timeout_http_peer2.conf new file mode 100644 index 0000000..1269358 --- /dev/null +++ b/src/transport/test_transport_api_timeout_http_peer2.conf @@ -0,0 +1,33 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-http-p2/ +DEFAULTCONFIG = test_transport_api_http_peer2.conf + +[nat] + +[transport-http] +PORT = 12090 + +[arm] +PORT = 12095 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12094 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12093 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12092 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +#DEBUG = YES +PORT = 12091 +PLUGINS = http +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +#PREFIX = valgrind --leak-check=full diff --git a/src/transport/test_transport_api_timeout_https_peer1.conf b/src/transport/test_transport_api_timeout_https_peer1.conf new file mode 100644 index 0000000..8a93ca1 --- /dev/null +++ b/src/transport/test_transport_api_timeout_https_peer1.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-https-p1/ +DEFAULTCONFIG = test_transport_api_https_peer1.conf + +[transport-https] +PORT = 12100 +KEY_FILE = $SERVICEHOME/https_key_p1.key +CERT_FILE = $SERVICEHOME/https_cert_p1.crt + +[arm] +PORT = 12105 + +[statistics] +PORT = 12104 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12103 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12102 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12101 +PLUGINS = https +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +DEBUG = NO + + diff --git a/src/transport/test_transport_api_timeout_https_peer2.conf b/src/transport/test_transport_api_timeout_https_peer2.conf new file mode 100644 index 0000000..0710f41 --- /dev/null +++ b/src/transport/test_transport_api_timeout_https_peer2.conf @@ -0,0 +1,33 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-https-p2/ +DEFAULTCONFIG = test_transport_api_https_peer2.conf + +[transport-https] +PORT = 12110 +KEY_FILE = $SERVICEHOME/https_key_p2.key +CERT_FILE = $SERVICEHOME/https_cert_p2.crt + +[arm] +PORT = 12115 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12114 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12113 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12112 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12111 +PLUGINS = https +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +DEBUG = NO + + diff --git a/src/transport/test_transport_api_timeout_tcp_peer1.conf b/src/transport/test_transport_api_timeout_tcp_peer1.conf new file mode 100644 index 0000000..89beecb --- /dev/null +++ b/src/transport/test_transport_api_timeout_tcp_peer1.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p1/ +DEFAULTCONFIG = test_transport_api_timeout_tcp_peer1.conf + +[transport-tcp] +PORT = 12000 +TIMEOUT = 5 s + +[arm] +PORT = 12005 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12004 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12003 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12002 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12001 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + + diff --git a/src/transport/test_transport_api_timeout_tcp_peer2.conf b/src/transport/test_transport_api_timeout_tcp_peer2.conf new file mode 100644 index 0000000..a21c4f5 --- /dev/null +++ b/src/transport/test_transport_api_timeout_tcp_peer2.conf @@ -0,0 +1,33 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-tcp-p2/ +DEFAULTCONFIG = test_transport_api_timeout_tcp_peer2.conf + +[nat] +ALLOW_NAT = NO + +[transport-tcp] +PORT = 12100 + +[arm] +PORT = 12014 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12013 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12012 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12011 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12010 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + + diff --git a/src/transport/test_transport_api_timeout_udp_peer1.conf b/src/transport/test_transport_api_timeout_udp_peer1.conf new file mode 100644 index 0000000..a1216e4 --- /dev/null +++ b/src/transport/test_transport_api_timeout_udp_peer1.conf @@ -0,0 +1,34 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-udp-p1/ +DEFAULTCONFIG = test_transport_api_udp_peer1.conf + +[transport-udp] +PORT = 12040 +BROADCAST = NO +BROADCAST_INTERVAL = 30000 +MAX_BPS = 50000000 + +[arm] +PORT = 12045 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12044 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12043 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12042 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +#PREFIX = valgrind --leak-check=full +PORT = 12041 +PLUGINS = udp +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + + diff --git a/src/transport/test_transport_api_timeout_udp_peer2.conf b/src/transport/test_transport_api_timeout_udp_peer2.conf new file mode 100644 index 0000000..3e487a6 --- /dev/null +++ b/src/transport/test_transport_api_timeout_udp_peer2.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-udp-p2/ +DEFAULTCONFIG = test_transport_api_udp_peer2.conf + +[transport-udp] +PORT = 12050 +BROADCAST = NO +MAX_BPS = 50000000 + +[arm] +PORT = 12055 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12054 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12053 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12052 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12051 +PLUGINS = udp +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + + diff --git a/src/transport/test_transport_api_timeout_unix_peer1.conf b/src/transport/test_transport_api_timeout_unix_peer1.conf new file mode 100644 index 0000000..b1ace7d --- /dev/null +++ b/src/transport/test_transport_api_timeout_unix_peer1.conf @@ -0,0 +1,29 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-unix-p1/ +DEFAULTCONFIG = test_transport_api_unix_peer1.conf + +[arm] +PORT = 12125 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12124 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12123 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12122 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12121 +PLUGINS = unix +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + +[transport-unix] +PORT = 12120 + diff --git a/src/transport/test_transport_api_timeout_unix_peer2.conf b/src/transport/test_transport_api_timeout_unix_peer2.conf new file mode 100644 index 0000000..a153588 --- /dev/null +++ b/src/transport/test_transport_api_timeout_unix_peer2.conf @@ -0,0 +1,29 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-unix-p2/ +DEFAULTCONFIG = test_transport_api_unix_peer2.conf + +[arm] +PORT = 12135 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12134 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12133 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12132 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12131 +PLUGINS = unix +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + +[transport-unix] +PORT = 12136 + diff --git a/src/transport/test_transport_api_udp_nat_peer1.conf b/src/transport/test_transport_api_udp_nat_peer1.conf new file mode 100644 index 0000000..16a4e62 --- /dev/null +++ b/src/transport/test_transport_api_udp_nat_peer1.conf @@ -0,0 +1,37 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-udp-nat-p1/ +DEFAULTCONFIG = test_transport_api_udp_nat_peer1.conf + +[nat] +BEHIND_NAT = YES +ALLOW_NAT = NO +ONLY_NAT_ADDRESSES = YES + +[transport-udp] +PORT = 0 + +[arm] +PORT = 12065 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12064 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12063 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12062 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12061 +PLUGINS = udp +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +DEBUG = NO + + diff --git a/src/transport/test_transport_api_udp_nat_peer2.conf b/src/transport/test_transport_api_udp_nat_peer2.conf new file mode 100644 index 0000000..0852b25 --- /dev/null +++ b/src/transport/test_transport_api_udp_nat_peer2.conf @@ -0,0 +1,35 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-udp-nat-p2/ +DEFAULTCONFIG = test_transport_api_udp_nat_peer2.conf + +[nat] +ALLOW_NAT = YES + +[transport-udp] +PORT = 12070 + +[arm] +PORT = 12075 +DEFAULTSERVICES = transport +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12074 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12073 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12072 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12071 +PLUGINS = udp +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +DEBUG = NO + + diff --git a/src/transport/test_transport_api_udp_peer1.conf b/src/transport/test_transport_api_udp_peer1.conf new file mode 100644 index 0000000..a1216e4 --- /dev/null +++ b/src/transport/test_transport_api_udp_peer1.conf @@ -0,0 +1,34 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-udp-p1/ +DEFAULTCONFIG = test_transport_api_udp_peer1.conf + +[transport-udp] +PORT = 12040 +BROADCAST = NO +BROADCAST_INTERVAL = 30000 +MAX_BPS = 50000000 + +[arm] +PORT = 12045 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12044 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12043 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12042 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +#PREFIX = valgrind --leak-check=full +PORT = 12041 +PLUGINS = udp +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + + diff --git a/src/transport/test_transport_api_udp_peer2.conf b/src/transport/test_transport_api_udp_peer2.conf new file mode 100644 index 0000000..3e487a6 --- /dev/null +++ b/src/transport/test_transport_api_udp_peer2.conf @@ -0,0 +1,32 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-udp-p2/ +DEFAULTCONFIG = test_transport_api_udp_peer2.conf + +[transport-udp] +PORT = 12050 +BROADCAST = NO +MAX_BPS = 50000000 + +[arm] +PORT = 12055 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12054 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12053 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12052 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12051 +PLUGINS = udp +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + + diff --git a/src/transport/test_transport_api_unix_peer1.conf b/src/transport/test_transport_api_unix_peer1.conf new file mode 100644 index 0000000..b1ace7d --- /dev/null +++ b/src/transport/test_transport_api_unix_peer1.conf @@ -0,0 +1,29 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-unix-p1/ +DEFAULTCONFIG = test_transport_api_unix_peer1.conf + +[arm] +PORT = 12125 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12124 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12123 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12122 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12121 +PLUGINS = unix +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + +[transport-unix] +PORT = 12120 + diff --git a/src/transport/test_transport_api_unix_peer2.conf b/src/transport/test_transport_api_unix_peer2.conf new file mode 100644 index 0000000..a153588 --- /dev/null +++ b/src/transport/test_transport_api_unix_peer2.conf @@ -0,0 +1,29 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-unix-p2/ +DEFAULTCONFIG = test_transport_api_unix_peer2.conf + +[arm] +PORT = 12135 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12134 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12133 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12132 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12131 +PLUGINS = unix +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + +[transport-unix] +PORT = 12136 + diff --git a/src/transport/test_transport_api_unreliability.c b/src/transport/test_transport_api_unreliability.c new file mode 100644 index 0000000..53de91a --- /dev/null +++ b/src/transport/test_transport_api_unreliability.c @@ -0,0 +1,585 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api_unreliability.c + * @brief test case for transports; ensures messages get + * through, regardless of order + * + * This test case serves as a base for unreliable + * transport test cases to check that the transports + * achieve reliable message delivery. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_transport_service.h" +#include "gauger.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO + +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * Testcase timeout + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 900) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +static char *test_source; + +static char *test_plugin; + +static char *test_name; + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +struct PeerContext *p1; + +struct PeerContext *p2; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +char *cfg_file_p1; + +char *cfg_file_p2; + +uint32_t max_bps_p1; +uint32_t max_bps_p2; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +/* + * Testcase specific declarations + */ + +/** + * Note that this value must not significantly exceed + * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise + * messages may be dropped even for a reliable transport. + */ +#define TOTAL_MSGS (1024 * 3) + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct TestMessage +{ + struct GNUNET_MessageHeader header; + uint32_t num; +}; +GNUNET_NETWORK_STRUCT_END + +static char *test_name; + +static int msg_scheduled; +static int msg_sent; +static int msg_recv_expected; +static int msg_recv; + +static int test_connected; +static int test_sending; +static int test_send_timeout; + +static unsigned long long total_bytes; + +static struct GNUNET_TIME_Absolute start_time; + +static char bitmap[TOTAL_MSGS / 8]; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + +/* + * END Testcase specific declarations + */ + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + +static int +get_bit (const char *map, unsigned int bit); + +static void +end () +{ + unsigned long long delta; + + char *value_name; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; + FPRINTF (stderr, "\nThroughput was %llu kb/s\n", + total_bytes * 1000 / 1024 / delta); + GNUNET_asprintf (&value_name, "unreliable_%s", test_plugin); + GAUGER ("TRANSPORT", value_name, (int) (total_bytes * 1000 / 1024 / delta), + "kb/s"); + GNUNET_free (value_name); + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (cc != NULL) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + cc = NULL; + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + GNUNET_TRANSPORT_TESTING_done (tth); + + ok = 0; + + int i; + + for (i = 0; i < TOTAL_MSGS; i++) + { + if (get_bit (bitmap, i) == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Did not receive message %d\n", i); + ok = -1; + } + } +} + +static void +end_badly () +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + if (test_connected == GNUNET_YES) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n"); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n"); + + if (test_sending == GNUNET_NO) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Testcase did not send any messages before timeout\n"); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Reliability failed: Last message sent %u, Next message scheduled %u, Last message received %u, Message expected %u\n", + msg_sent, msg_scheduled, msg_recv, msg_recv_expected); + if (test_send_timeout == GNUNET_YES) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Test had timeout while waiting to send data\n"); + + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (cc != NULL) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + cc = NULL; + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + GNUNET_TRANSPORT_TESTING_done (tth); + + ok = GNUNET_SYSERR; +} + + +static unsigned int +get_size (unsigned int iter) +{ + unsigned int ret; + + ret = (iter * iter * iter); + +#ifndef LINUX + /* FreeBSD/OSX etc. Unix DGRAMs do not work + * with large messages */ + if (0 == strcmp ("unix", test_plugin)) + return sizeof (struct TestMessage) + (ret % 1024); +#endif + return sizeof (struct TestMessage) + (ret % 60000); +} + + +/** + * Sets a bit active in the bitmap. + * + * @param bitIdx which bit to set + */ +static void +set_bit (unsigned int bitIdx) +{ + size_t arraySlot; + unsigned int targetBit; + + if (bitIdx >= sizeof (bitmap) * 8) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "tried to set bit %d of %d(!?!?)\n", + bitIdx, sizeof (bitmap) * 8); + return; + } + arraySlot = bitIdx / 8; + targetBit = (1L << (bitIdx % 8)); + bitmap[arraySlot] |= targetBit; +} + +/** + * Obtain a bit from bitmap. + * @param map the bitmap + * @param bit index from bitmap + * + * @return Bit \a bit from hashcode \a code + */ +static int +get_bit (const char *map, unsigned int bit) +{ + if (bit >= TOTAL_MSGS) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "get bit %d of %d(!?!?)\n", bit, + sizeof (bitmap) * 8); + return 0; + } + return ((map)[bit >> 3] & (1 << (bit & 7))) > 0; +} + + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + static int n; + + unsigned int s; + char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + const struct TestMessage *hdr; + + hdr = (const struct TestMessage *) message; + + if (MTYPE != ntohs (message->type)) + return; + msg_recv_expected = n; + msg_recv = ntohl (hdr->num); + s = get_size (ntohl (hdr->num)); + + if (ntohs (message->size) != s) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u of size %u, got %u bytes of message %u\n", + ntohl (hdr->num), s, ntohs (message->size), ntohl (hdr->num)); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + test_sending = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } + + memset (cbuf, ntohl (hdr->num), s - sizeof (struct TestMessage)); + if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u with bits %u, but body did not match\n", + ntohl (hdr->num), (unsigned char) n); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + test_sending = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +#if VERBOSE + if (ntohl (hdr->num) % 5 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message %u of size %u\n", + ntohl (hdr->num), ntohs (message->size)); + } +#endif + n++; + set_bit (ntohl (hdr->num)); + test_sending = GNUNET_YES; + if (0 == (n % (TOTAL_MSGS / 100))) + { + FPRINTF (stderr, "%s", "."); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + } + if (n == TOTAL_MSGS) + { + end (); + } +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + static int n; + char *cbuf = buf; + struct TestMessage hdr; + unsigned int s; + unsigned int ret; + + th = NULL; + + if (buf == NULL) + { + test_send_timeout = GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout occurred while waiting for transmit_ready for msg %u of %u\n", + msg_scheduled, TOTAL_MSGS); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + ok = 42; + return 0; + } + ret = 0; + s = get_size (n); + GNUNET_assert (size >= s); + GNUNET_assert (buf != NULL); + cbuf = buf; + do + { + hdr.header.size = htons (s); + hdr.header.type = htons (MTYPE); + hdr.num = htonl (n); + msg_sent = n; + memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); + ret += sizeof (struct TestMessage); + memset (&cbuf[ret], n, s - sizeof (struct TestMessage)); + ret += s - sizeof (struct TestMessage); +#if VERBOSE + if (n % 5000 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message %u of size %u\n", n, + s); + } + +#endif + n++; + s = get_size (n); + if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) + break; /* sometimes pack buffer full, sometimes not */ + } + while (size - ret >= s); + if (n < TOTAL_MSGS) + { + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0, + TIMEOUT_TRANSMIT, + ¬ify_ready, NULL); + msg_scheduled = n; + } + else + { + FPRINTF (stderr, "%s", "\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All messages scheduled to be sent\n"); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + } + if (n % 5000 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Returning total message block of size %u\n", ret); + } + total_bytes += ret; + return ret; +} + + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n", + GNUNET_i2s (peer), cls); +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n", + GNUNET_i2s (peer), cls); + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; +} + +static void +sendtask () +{ + start_time = GNUNET_TIME_absolute_get (); + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0, + TIMEOUT_TRANSMIT, ¬ify_ready, + NULL); +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c, + GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + test_connected = GNUNET_YES; + cc = NULL; + + GNUNET_SCHEDULER_add_now (&sendtask, NULL); +} + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + test_connected = GNUNET_NO; + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + test_send_timeout = GNUNET_NO; + + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } + + +} + +static int +check () +{ + static char *const argv[] = { "test-transport-api-unreliability", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + ok = GNUNET_SYSERR; + + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); + GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, + &test_plugin); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); + + ret = check (); + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + + + return ret; +} + +/* end of test_transport_api_unreliability.c */ diff --git a/src/transport/test_transport_api_unreliability_constant.c b/src/transport/test_transport_api_unreliability_constant.c new file mode 100644 index 0000000..fb72b0f --- /dev/null +++ b/src/transport/test_transport_api_unreliability_constant.c @@ -0,0 +1,523 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api_unreliability_constant.c + * @brief test case for transports; ensures messages get + * through, regardless of order, constant packet size + * + * This test case serves as a base for unreliable + * transport test cases to check that the transports + * achieve reliable message delivery. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_transport_service.h" +#include "gauger.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO + +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * Testcase timeout + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 900) + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +static char *test_source; + +static char *test_plugin; + +static char *test_name; + +static int ok; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +struct PeerContext *p1; + +struct PeerContext *p2; + +struct GNUNET_TRANSPORT_TransmitHandle *th; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +char *cfg_file_p1; + +char *cfg_file_p2; + +uint32_t max_bps_p1; +uint32_t max_bps_p2; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + +/* + * Testcase specific declarations + */ + +/** + * Note that this value must not significantly exceed + * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise + * messages may be dropped even for a reliable transport. + */ +#define TOTAL_MSGS (1024 * 3) + +#define MTYPE 12345 + +#define MSG_SIZE 10000 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct TestMessage +{ + struct GNUNET_MessageHeader header; + uint32_t num; +}; +GNUNET_NETWORK_STRUCT_END + +static char *test_name; + +static int msg_scheduled; +static int msg_sent; +static int msg_recv_expected; +static int msg_recv; + +static int test_failed; + +static unsigned long long total_bytes; + +static struct GNUNET_TIME_Absolute start_time; + +/* + * END Testcase specific declarations + */ + +#if VERBOSE +#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) +#else +#define OKPP do { ok++; } while (0) +#endif + +int +get_bit (const char *map, unsigned int bit); + +static void +end () +{ + unsigned long long delta; + + char *value_name; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; + FPRINTF (stderr, "\nThroughput was %llu kb/s\n", + total_bytes * 1000 / 1024 / delta); + GNUNET_asprintf (&value_name, "unreliable_%s", test_plugin); + GAUGER ("TRANSPORT", value_name, (int) (total_bytes * 1000 / 1024 / delta), + "kb/s"); + GNUNET_free (value_name); + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (cc != NULL) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + cc = NULL; + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + GNUNET_TRANSPORT_TESTING_done (tth); + + ok = 0; + if (test_failed == GNUNET_NO) + ok = GNUNET_SYSERR; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GOT %u of %u messages\n", msg_recv, + TOTAL_MSGS); +} + +static void +end_badly () +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + if (test_failed == GNUNET_NO) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testcase timeout\n"); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Reliability failed: Last message sent %u, Next message scheduled %u, Last message received %u, Message expected %u\n", + msg_sent, msg_scheduled, msg_recv, msg_recv_expected); + + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + + if (cc != NULL) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + cc = NULL; + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + GNUNET_TRANSPORT_TESTING_done (tth); + + ok = GNUNET_SYSERR; +} + + +static unsigned int +get_size (unsigned int iter) +{ +/* + unsigned int ret; + ret = (iter * iter * iter); + return sizeof (struct TestMessage) + (ret % 60000); + */ + return MSG_SIZE; +} + + + + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + static int n; + + unsigned int s; + char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + const struct TestMessage *hdr; + + hdr = (const struct TestMessage *) message; + + if (MTYPE != ntohs (message->type)) + return; + msg_recv_expected = n; + msg_recv = ntohl (hdr->num); + if (msg_recv_expected != msg_recv) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message no %u, got %u\n", + msg_recv_expected, msg_recv); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + test_failed = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } + + s = get_size (ntohl (hdr->num)); + if (ntohs (message->size) != s) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u of size %u, got %u bytes of message %u\n", + ntohl (hdr->num), s, ntohs (message->size), ntohl (hdr->num)); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + test_failed = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } + + memset (cbuf, ntohl (hdr->num), s - sizeof (struct TestMessage)); + if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected message %u with bits %u, but body did not match\n", + ntohl (hdr->num), (unsigned char) n); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + test_failed = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +#if VERBOSE + if (ntohl (hdr->num) % 5 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message %u of size %u\n", + ntohl (hdr->num), ntohs (message->size)); + } +#endif + n++; + if (0 == (n % (TOTAL_MSGS / 100))) + { + FPRINTF (stderr, "%s", "."); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + test_failed = GNUNET_YES; + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + } + if (n == TOTAL_MSGS) + { + /* because of starting with 0 */ + msg_recv++; + FPRINTF (stderr, "%s", "\n"); + end (); + } +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + static int n; + char *cbuf = buf; + struct TestMessage hdr; + unsigned int s; + unsigned int ret; + + th = NULL; + + if (buf == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Timeout occurred while waiting for transmit_ready\n"); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + ok = 42; + return 0; + } + ret = 0; + s = get_size (n); + GNUNET_assert (size >= s); + GNUNET_assert (buf != NULL); + cbuf = buf; + do + { + hdr.header.size = htons (s); + hdr.header.type = htons (MTYPE); + hdr.num = htonl (n); + msg_sent = n; + memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); + ret += sizeof (struct TestMessage); + memset (&cbuf[ret], n, s - sizeof (struct TestMessage)); + ret += s - sizeof (struct TestMessage); +#if VERBOSE + if (n % 1 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message %u of size %u\n", n, + s); + } + +#endif + n++; + s = get_size (n); + if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) + break; /* sometimes pack buffer full, sometimes not */ + } + while (size - ret >= s); + if (n < TOTAL_MSGS) + { + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0, + TIMEOUT_TRANSMIT, + ¬ify_ready, NULL); + msg_scheduled = n; + } + else + { + FPRINTF (stderr, "%s", "\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All messages scheduled to be sent!!\n"); + if (GNUNET_SCHEDULER_NO_TASK != die_task) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + } + if (n % 5000 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Returning total message block of size %u\n", ret); + } + total_bytes += ret; + return ret; +} + + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n", + GNUNET_i2s (peer), cls); +} + + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n", + GNUNET_i2s (peer), cls); + if (th != NULL) + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; +} + +static void +sendtask () +{ + start_time = GNUNET_TIME_absolute_get (); + th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0, + TIMEOUT_TRANSMIT, ¬ify_ready, + NULL); +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c, + GNUNET_i2s (&p2->id)); + GNUNET_free (p1_c); + + cc = NULL; + + GNUNET_SCHEDULER_add_now (&sendtask, NULL); +} + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + if ((p1 == NULL) || (p2 == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + return; + } +} + +static int +check () +{ + static char *const argv[] = { "test-transport-api-unreliability-constant", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + static struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + +#if WRITECONFIG + setTransportOptions ("test_transport_api_data.conf"); +#endif + ok = GNUNET_SYSERR; + + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, + "nohelp", options, &run, &ok); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); + + GNUNET_log_setup (test_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); + GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, + &test_plugin); + + tth = GNUNET_TRANSPORT_TESTING_init (); + + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); + GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); + + ret = check (); + + GNUNET_free (cfg_file_p1); + GNUNET_free (cfg_file_p2); + + GNUNET_free (test_source); + GNUNET_free (test_plugin); + GNUNET_free (test_name); + + return ret; +} + +/* end of test_transport_api_unreliability_constant.c */ diff --git a/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf b/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf new file mode 100644 index 0000000..d872f02 --- /dev/null +++ b/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-udp-p1/ +DEFAULTCONFIG = test_transport_api_unreliability_constant_udp_peer1.conf + +[transport-udp] +PORT = 12040 +MAX_BPS = 1073741824 + +[arm] +PORT = 12045 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12044 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12043 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12042 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12041 +PLUGINS = udp +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + + diff --git a/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf b/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf new file mode 100644 index 0000000..50ee65a --- /dev/null +++ b/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-udp-p2/ +DEFAULTCONFIG = test_transport_api_unreliability_constant_udp_peer2.conf + +[transport-udp] +PORT = 12050 +MAX_BPS = 1073741824 + +[arm] +PORT = 12055 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12054 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12053 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12052 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12051 +PLUGINS = udp +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + + diff --git a/src/transport/test_transport_api_unreliability_udp_peer1.conf b/src/transport/test_transport_api_unreliability_udp_peer1.conf new file mode 100644 index 0000000..8a5a405 --- /dev/null +++ b/src/transport/test_transport_api_unreliability_udp_peer1.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-udp-p1/ +DEFAULTCONFIG = test_transport_api_unreliability_udp_peer1.conf + +[transport-udp] +PORT = 12040 +MAX_BPS = 5000000 + +[arm] +PORT = 12045 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12044 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12043 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12042 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12041 +PLUGINS = udp +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + + diff --git a/src/transport/test_transport_api_unreliability_udp_peer2.conf b/src/transport/test_transport_api_unreliability_udp_peer2.conf new file mode 100644 index 0000000..d240c42 --- /dev/null +++ b/src/transport/test_transport_api_unreliability_udp_peer2.conf @@ -0,0 +1,31 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-udp-p2/ +DEFAULTCONFIG = test_transport_api_unreliability_udp_peer2.conf + +[transport-udp] +PORT = 12050 +MAX_BPS = 5000000 + +[arm] +PORT = 12055 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12054 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12053 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12052 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12051 +PLUGINS = udp +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + + diff --git a/src/transport/test_transport_api_unreliability_unix_peer1.conf b/src/transport/test_transport_api_unreliability_unix_peer1.conf new file mode 100644 index 0000000..8689e41 --- /dev/null +++ b/src/transport/test_transport_api_unreliability_unix_peer1.conf @@ -0,0 +1,29 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-unix-p1/ +DEFAULTCONFIG = test_transport_api_unreliability_unix_peer1.conf + +[arm] +PORT = 12125 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12124 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12123 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12122 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12121 +PLUGINS = unix +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + +[transport-unix] +PORT = 12120 + diff --git a/src/transport/test_transport_api_unreliability_unix_peer2.conf b/src/transport/test_transport_api_unreliability_unix_peer2.conf new file mode 100644 index 0000000..7c3cc19 --- /dev/null +++ b/src/transport/test_transport_api_unreliability_unix_peer2.conf @@ -0,0 +1,29 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-unix-p2/ +DEFAULTCONFIG = test_transport_api_unreliability_unix_peer2.conf + +[arm] +PORT = 12135 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12134 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12133 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12132 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12131 +PLUGINS = unix +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + +[transport-unix] +PORT = 12131 + diff --git a/src/transport/test_transport_api_unreliability_wlan_peer1.conf b/src/transport/test_transport_api_unreliability_wlan_peer1.conf new file mode 100644 index 0000000..9dd9d1b --- /dev/null +++ b/src/transport/test_transport_api_unreliability_wlan_peer1.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-wlan-p1/ +DEFAULTCONFIG = test_transport_api_wlan_peer1.conf + +[transport-wlan] +TESTMODE = 1 + +[arm] +PORT = 12164 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12163 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12162 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12161 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12160 +PLUGINS = wlan +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + + diff --git a/src/transport/test_transport_api_unreliability_wlan_peer2.conf b/src/transport/test_transport_api_unreliability_wlan_peer2.conf new file mode 100644 index 0000000..bc868d7 --- /dev/null +++ b/src/transport/test_transport_api_unreliability_wlan_peer2.conf @@ -0,0 +1,30 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-wlan-p2/ +DEFAULTCONFIG = test_transport_api_wlan_peer2.conf + +[transport-wlan] +INTERFACE = mon1 +TESTMODE = 2 + +[arm] +PORT = 12174 +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12173 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12172 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12171 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12170 +PLUGINS = wlan +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + diff --git a/src/transport/test_transport_api_wlan_peer1.conf b/src/transport/test_transport_api_wlan_peer1.conf new file mode 100644 index 0000000..e379cf0 --- /dev/null +++ b/src/transport/test_transport_api_wlan_peer1.conf @@ -0,0 +1,38 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-wlan-p1/ +DEFAULTCONFIG = test_transport_api_wlan_peer1.conf + +[transport-wlan] +INTERFACE = mon0 +TESTMODE = 1 + +[arm] +DEBUG = YES +PORT = 12164 +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12163 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12162 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12161 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12160 +PLUGINS = wlan +#DEBUG = YES +UNIXPATH = /tmp/gnunet-p1-service-transport.sock +#PREFIX = xterm -T transport2 -e gdb --command=cmd --args +#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600 +#PREFIX = valgrind --leak-check=full --show-reachable=yes +#PREFIX = valgrind --leak-check=full +#PREFIX = valgrind --tool=massif +#PREFIX = gdbserver :2345 + diff --git a/src/transport/test_transport_api_wlan_peer2.conf b/src/transport/test_transport_api_wlan_peer2.conf new file mode 100644 index 0000000..3e0ce27 --- /dev/null +++ b/src/transport/test_transport_api_wlan_peer2.conf @@ -0,0 +1,37 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +SERVICEHOME = /tmp/test-transport/api-wlan-p2/ +DEFAULTCONFIG = test_transport_api_wlan_peer2.conf + +[transport-wlan] +INTERFACE = mon1 +TESTMODE = 2 + +[arm] +PORT = 12174 +DEBUG = YES +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 12173 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 12172 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 12171 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 12170 +PLUGINS = wlan +#DEBUG = YES +UNIXPATH = /tmp/gnunet-p2-service-transport.sock +#PREFIX = xterm -T transport2 -e gdb --command=cmd --args +#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600 +#PREFIX = valgrind --leak-check=full --show-reachable=yes +#PREFIX = valgrind --leak-check=full +#PREFIX = valgrind --tool=massif +#PREFIX = gdbserver :2345 diff --git a/src/transport/test_transport_defaults.conf b/src/transport/test_transport_defaults.conf new file mode 100644 index 0000000..f553377 --- /dev/null +++ b/src/transport/test_transport_defaults.conf @@ -0,0 +1,54 @@ +[PATHS] +SERVICEHOME = /tmp/test-transport-api/ +DEFAULTCONFIG = test_transport_defaults.conf + +[transport-tcp] +TIMEOUT = 300 s + +[arm] +DEFAULTSERVICES = + +[transport] +PREFIX = + +[core] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[fs] +AUTOSTART = NO + +[dht] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[dns] +AUTOSTART = NO + +[dv] +AUTOSTART = NO + +[gns] +AUTOSTART = NO + +[chat] +AUTOSTART = NO + +[vpn] +AUTOSTART = NO + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[TESTING] +WEAKRANDOM = YES diff --git a/src/transport/test_transport_startonly.c b/src/transport/test_transport_startonly.c new file mode 100644 index 0000000..79578ab --- /dev/null +++ b/src/transport/test_transport_startonly.c @@ -0,0 +1,189 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api.c + * @brief base test case for transport implementations + * + * This test case serves as a base for tcp, udp, and udp-nat + * transport test cases. Based on the executable being run + * the correct test case will be performed. Conservation of + * C code apparently. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO + +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90) + +#define ITERATIONS 10 + +GNUNET_SCHEDULER_TaskIdentifier timeout_task; + +static struct PeerContext *p1; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +static int connected = GNUNET_NO; + +static int ret = 0; + +static int i; + +static void +end () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + if (timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (timeout_task); + timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Exiting\n"); +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + timeout_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + + ret = GNUNET_SYSERR; +} + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected \n", + GNUNET_i2s (peer)); + connected++; +} + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected \n", + GNUNET_i2s (peer)); +} + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving\n"); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + tth = GNUNET_TRANSPORT_TESTING_init (); + + timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); + + i = 1; + FPRINTF (stderr, "%i", i); + while (i <= ITERATIONS) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting peer\n"); + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, + "test_transport_startonly.conf", + 1, ¬ify_receive, + ¬ify_connect, + ¬ify_disconnect, NULL, p1); + + + if (p1 != NULL) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer was successfully started\n"); + else + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer1 was not started successfully\n"); + GNUNET_assert (p1 != NULL); + GNUNET_assert (p1->th != NULL); + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + + i++; + if (i <= ITERATIONS) + FPRINTF (stderr, "..%i", i); + } + + tth = GNUNET_TRANSPORT_TESTING_init (); + + FPRINTF (stderr, "%s", "\n"); + end (); +} + +int +main (int argc, char *argv[]) +{ + GNUNET_log_setup ("test_transport_testing", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + char *const argv_1[] = { "test_transport_testing", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_PROGRAM_run ((sizeof (argv_1) / sizeof (char *)) - 1, argv_1, + "test_transport_testing", "nohelp", options, &run, &ret); + + return ret; +} + +/* end of test_transport_api.c */ diff --git a/src/transport/test_transport_startonly.conf b/src/transport/test_transport_startonly.conf new file mode 100644 index 0000000..255df4c --- /dev/null +++ b/src/transport/test_transport_startonly.conf @@ -0,0 +1,15 @@ +@INLINE@ test_transport_defaults.conf +[PATHS] +DEFAULTCONFIG = test_transport_api_data.conf + +[arm] +DEFAULTSERVICES = transport + +[transport-tcp] +PORT = 2094 + +[transport-udp] +PORT = 2094 + + + diff --git a/src/transport/test_transport_testing.c b/src/transport/test_transport_testing.c new file mode 100644 index 0000000..842d686 --- /dev/null +++ b/src/transport/test_transport_testing.c @@ -0,0 +1,227 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file transport/test_transport_api.c + * @brief base test case for transport implementations + * + * This test case serves as a base for tcp, udp, and udp-nat + * transport test cases. Based on the executable being run + * the correct test case will be performed. Conservation of + * C code apparently. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_hello_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" +#include "transport-testing.h" + +#define VERBOSE GNUNET_NO + +#define VERBOSE_ARM GNUNET_NO + +#define START_ARM GNUNET_YES + +/** + * How long until we give up on transmitting the message? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + +GNUNET_SCHEDULER_TaskIdentifier timeout_task; + +static struct PeerContext *p1; +static struct PeerContext *p2; + +static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; + +struct GNUNET_TRANSPORT_TESTING_handle *tth; + +static int connected = GNUNET_NO; + +static int ret = 0; + +static void +end () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); + + if (timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (timeout_task); + + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + GNUNET_TRANSPORT_TESTING_done (tth); +} + +static void +end_badly () +{ + timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); + + if (p1 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (p2 != NULL) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + + GNUNET_TRANSPORT_TESTING_done (tth); + + ret = GNUNET_SYSERR; +} + +static void +testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) +{ + char *ps = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%4s') connected to peer %u (`%s')!\n", p1->no, ps, + p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (ps); + GNUNET_SCHEDULER_add_now (&end, NULL); +} + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected \n", + GNUNET_i2s (peer)); + connected++; +} + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected \n", + GNUNET_i2s (peer)); +} + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving\n"); +} + +void +start_cb (struct PeerContext *p, void *cls) +{ + static int started; + + started++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, + GNUNET_i2s (&p->id)); + + if (started != 2) + return; + + char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", + p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); + GNUNET_free (sender_c); + + cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, + NULL); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + tth = GNUNET_TRANSPORT_TESTING_init (); + + timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &end_badly, NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting peer\n"); + p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, + "test_transport_api_tcp_peer1.conf", + 1, ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, p1); + + GNUNET_assert (p1->hostkeyfile != NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, + "test_transport_api_tcp_peer2.conf", + 2, ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, p2); + + GNUNET_assert (p2->hostkeyfile != NULL); + + if (p1 == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer1 was not started successfully\n"); + if (timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (timeout_task); + timeout_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + } + if (p2 == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer2 was not started successfully\n"); + if (timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (timeout_task); + timeout_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + } +} + +int +main (int argc, char *argv[]) +{ + GNUNET_log_setup ("test_transport_testing", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + + char *const argv_1[] = { "test_transport_testing", + "-c", + "test_transport_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_PROGRAM_run ((sizeof (argv_1) / sizeof (char *)) - 1, argv_1, + "test_transport_testing", "nohelp", options, &run, &ret); + + return ret; +} + +/* end of test_transport_api.c */ diff --git a/src/transport/transport-testing.c b/src/transport/transport-testing.c new file mode 100644 index 0000000..752106b --- /dev/null +++ b/src/transport/transport-testing.c @@ -0,0 +1,872 @@ +/* + This file is part of GNUnet. + (C) 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport-testing.c + * @brief testing lib for transport service + * + * @author Matthias Wachs + */ + +#include "transport-testing.h" + +#define HOSTKEYFILESIZE 914 + +static const char * +get_host_key (struct GNUNET_TRANSPORT_TESTING_handle *tth) +{ + if (tth->hostkey_data == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "No precomputed hostkeys available\n"); + return NULL; + } + if (tth->hostkeys_total > tth->hostkeys_last) + { + tth->hostkeys_last++; + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Used hostkey %u of %u available hostkeys\n", + tth->hostkeys_last, tth->hostkeys_total); + return &tth->hostkey_data[(tth->hostkeys_last - 1) * HOSTKEYFILESIZE]; + } + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "No hostkey available (%u of %u already used)\n", + tth->hostkeys_last, tth->hostkeys_total); + return NULL; +} + +static struct PeerContext * +find_peer_context (struct GNUNET_TRANSPORT_TESTING_handle *tth, + const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_assert (tth != NULL); + struct PeerContext *t = tth->p_head; + + while (t != NULL) + { + if (0 == memcmp (&t->id, peer, sizeof (struct GNUNET_PeerIdentity))) + break; + t = t->next; + } + + return t; +} + +struct ConnectingContext * +find_connecting_context (struct GNUNET_TRANSPORT_TESTING_handle *tth, + struct PeerContext *p1, struct PeerContext *p2) +{ + GNUNET_assert (tth != NULL); + struct ConnectingContext *cc = tth->cc_head; + + while (cc != NULL) + { + if ((cc->p1 == p1) && (cc->p2 == p2)) + break; + if ((cc->p1 == p2) && (cc->p2 == p1)) + break; + cc = cc->next; + } + + return cc; +} + +static void +notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + struct PeerContext *p = cls; + + /* Find PeerContext */ + GNUNET_assert (p != 0); + GNUNET_assert (p->tth != NULL); + struct PeerContext *p2 = find_peer_context (p->tth, peer); + + if (p == NULL) + return; + if (p->nc != NULL) + p->nc (p->cb_cls, peer, ats, ats_count); + + char *p2_s; + + if (p2 != NULL) + GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id)); + else + GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Peers %s connected to peer %u (`%s')\n", p2_s, p->no, + GNUNET_i2s (&p->id)); + GNUNET_free (p2_s); + + /* Find ConnectingContext */ + struct ConnectingContext *cc = find_connecting_context (p->tth, p, p2); + + if (cc == NULL) + return; + + if (p == cc->p1) + cc->p1_c = GNUNET_YES; + + if (p == cc->p2) + cc->p2_c = GNUNET_YES; + + if ((cc->p1_c == GNUNET_YES) && (cc->p2_c == GNUNET_YES)) + { + cc->cb (cc->p1, cc->p2, cc->cb_cls); + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (p->tth, cc); + } +} + +static void +notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct PeerContext *p = cls; + + /* Find PeerContext */ + int no = 0; + struct PeerContext *p2 = NULL; + + if (p != NULL) + { + GNUNET_assert (p->tth != NULL); + p2 = find_peer_context (p->tth, peer); + no = p->no; + } + + char *p2_s; + + if (p2 != NULL) + GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id)); + else + GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Peers %s disconnected from peer %u (`%s')\n", p2_s, no, + GNUNET_i2s (&p->id)); + GNUNET_free (p2_s); + + if (p == NULL) + return; + if (p->nd != NULL) + p->nd (p->cb_cls, peer); +} + +static void +notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, uint32_t ats_count) +{ + struct PeerContext *p = cls; + + if (p == NULL) + return; + if (p->rec != NULL) + p->rec (p->cb_cls, peer, message, ats, ats_count); +} + +static void +get_hello (void *cb_cls, const struct GNUNET_MessageHeader *message) +{ + struct PeerContext *p = cb_cls; + + GNUNET_assert (message != NULL); + GNUNET_assert (GNUNET_OK == + GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) + message, &p->id)); + GNUNET_free_non_null (p->hello); + p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message); + + if (p->start_cb != NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Peer %u (`%s') successfully started\n", p->no, + GNUNET_i2s (&p->id)); + + p->start_cb (p, p->cb_cls); + p->start_cb = NULL; + } +} + + +static void +try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ConnectingContext *cc = cls; + struct PeerContext *p1 = cc->p1; + struct PeerContext *p2 = cc->p2; + + cc->tct = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + GNUNET_assert (cc != NULL); + GNUNET_assert (cc->p1 != NULL); + GNUNET_assert (cc->p2 != NULL); + + char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id)); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n", + p1->no, GNUNET_i2s (&p1->id), p2->no, p2_s, + GNUNET_HELLO_size (cc->p2->hello)); + GNUNET_free (p2_s); + + GNUNET_TRANSPORT_offer_hello (cc->th_p1, + (const struct GNUNET_MessageHeader *) cc-> + p2->hello, NULL, NULL); + GNUNET_TRANSPORT_try_connect (cc->th_p1, &p2->id); + + cc->tct = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, cc); +} + + +/** + * Start a peer with the given configuration + * @param tth the testing handle + * @param cfgname configuration file + * @param peer_id the peer_id + * @param rec receive callback + * @param nc connect callback + * @param nd disconnect callback + * @param start_cb start callback + * @param cb_cls closure for callback + * @return the peer context + */ +struct PeerContext * +GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle + *tth, const char *cfgname, int peer_id, + GNUNET_TRANSPORT_ReceiveCallback rec, + GNUNET_TRANSPORT_NotifyConnect nc, + GNUNET_TRANSPORT_NotifyDisconnect nd, + GNUNET_TRANSPORT_TESTING_start_cb start_cb, + void *cb_cls) +{ + const char *hostkey = NULL; + struct GNUNET_DISK_FileHandle *fn; + + GNUNET_assert (tth != NULL); + if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing", + "File not found: `%s' \n", cfgname); + return NULL; + } + + struct PeerContext *p = GNUNET_malloc (sizeof (struct PeerContext)); + + p->cfg = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + + if (GNUNET_CONFIGURATION_have_value (p->cfg, "PATHS", "SERVICEHOME")) + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (p->cfg, "PATHS", + "SERVICEHOME", + &p->servicehome)); + + if (NULL != p->servicehome) + GNUNET_DISK_directory_remove (p->servicehome); + + hostkey = get_host_key (tth); + if (hostkey != NULL) + { + + GNUNET_asprintf (&p->hostkeyfile, "%s/.hostkey", p->servicehome); + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_directory_create_for_file (p->hostkeyfile)); + fn = GNUNET_DISK_file_open (p->hostkeyfile, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + GNUNET_assert (fn != NULL); + GNUNET_assert (HOSTKEYFILESIZE == + GNUNET_DISK_file_write (fn, hostkey, HOSTKEYFILESIZE)); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fn)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Wrote hostkey to file: `%s' \n", p->hostkeyfile); + } + + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, + NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", "-c", cfgname, +#if VERBOSE_PEERS + "-L", "DEBUG", +#else + "-L", "ERROR", +#endif + NULL); + + p->no = peer_id; + p->tth = tth; + p->nc = nc; + p->nd = nd; + p->rec = rec; + p->start_cb = start_cb; + if (cb_cls != NULL) + p->cb_cls = cb_cls; + else + p->cb_cls = p; + + p->th = + GNUNET_TRANSPORT_connect (p->cfg, NULL, p, ¬ify_receive, + ¬ify_connect, ¬ify_disconnect); + GNUNET_assert (p->th != NULL); + + p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p); + GNUNET_assert (p->ghh != NULL); + + GNUNET_CONTAINER_DLL_insert (tth->p_head, tth->p_tail, p); + return p; +} + +/** +* Restart the given peer +* @param tth testing handle +* @param p the peer +* @param cfgname the cfg file used to restart +* @param restart_cb callback to call when restarted +* @param cb_cls callback closure +* @return GNUNET_OK in success otherwise GNUNET_SYSERR +*/ +int +GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle + *tth, struct PeerContext *p, + const char *cfgname, + GNUNET_TRANSPORT_TESTING_start_cb + restart_cb, void *cb_cls) +{ + struct GNUNET_DISK_FileHandle *fn; + + GNUNET_assert (tth != NULL); + GNUNET_assert (p != NULL); + GNUNET_assert (p->hostkeyfile != NULL); + GNUNET_assert (p->servicehome != NULL); + + /* shutdown */ +#if VERBOSE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Stopping peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id)); +#endif + if (p->ghh != NULL) + GNUNET_TRANSPORT_get_hello_cancel (p->ghh); + p->ghh = NULL; + + if (p->th != NULL) + GNUNET_TRANSPORT_disconnect (p->th); + + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + GNUNET_OS_process_wait (p->arm_proc); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } + if (p->hello != NULL) + GNUNET_free (p->hello); + p->hello = NULL; + + if (p->cfg != NULL) + GNUNET_CONFIGURATION_destroy (p->cfg); + p->cfg = NULL; + + + /* start */ +#if VERBOSE + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Restarting peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id)); +#endif + + sleep (5); // YUCK! + + if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing", + "File not found: `%s' \n", cfgname); + goto fail; + } + + p->cfg = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + + if (!GNUNET_CONFIGURATION_have_value (p->cfg, "PATHS", "SERVICEHOME")) + goto fail; + + fn = GNUNET_DISK_file_open (p->hostkeyfile, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (fn == NULL) + goto fail; + if (GNUNET_OK != GNUNET_DISK_file_close (fn)) + goto fail; + + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, + NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", "-c", cfgname, +#if VERBOSE_PEERS + "-L", "DEBUG", +#else + "-L", "ERROR", +#endif + NULL); + + p->th = + GNUNET_TRANSPORT_connect (p->cfg, NULL, p, ¬ify_receive, + ¬ify_connect, ¬ify_disconnect); + GNUNET_assert (p->th != NULL); + + p->start_cb = restart_cb; + p->cb_cls = cb_cls; + + p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p); + GNUNET_assert (p->ghh != NULL); + return GNUNET_OK; + +fail: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Restarting peer %u (`%s') failed, removing peer\n", p->no, + GNUNET_i2s (&p->id)); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p); + return GNUNET_SYSERR; +} + +/** + * shutdown the given peer + * @param tth testing handle + * @param p the peer + */ +void +GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth, + struct PeerContext *p) +{ + GNUNET_assert (p != NULL); + + if (p->ghh != NULL) + GNUNET_TRANSPORT_get_hello_cancel (p->ghh); + p->ghh = NULL; + + if (p->th != NULL) + GNUNET_TRANSPORT_disconnect (p->th); + + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + GNUNET_OS_process_wait (p->arm_proc); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } + + if (p->hostkeyfile != NULL) + { + GNUNET_DISK_directory_remove (p->hostkeyfile); + GNUNET_free (p->hostkeyfile); + } + + if (p->servicehome != NULL) + { + GNUNET_DISK_directory_remove (p->servicehome); + GNUNET_free (p->servicehome); + } + + if (p->hello != NULL) + GNUNET_free (p->hello); + p->hello = NULL; + + if (p->cfg != NULL) + GNUNET_CONFIGURATION_destroy (p->cfg); + p->cfg = NULL; + + GNUNET_CONTAINER_DLL_remove (tth->p_head, tth->p_tail, p); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Peer %u (`%s') stopped \n", p->no, + GNUNET_i2s (&p->id)); + + GNUNET_free (p); + p = NULL; +} + +/** + * Connect the given peers and call the callback when both peers report the + * inbound connection. Remarks: start_peer's notify_connect callback can be called + * before. + * + * @param tth transport testing handle + * @param p1 peer 1 + * @param p2 peer 2 + * @param cb the callback to call when both peers notified that they are connected + * @param cls callback cls + * @return a connect request handle + */ +GNUNET_TRANSPORT_TESTING_ConnectRequest +GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth, + struct PeerContext *p1, + struct PeerContext *p2, + GNUNET_TRANSPORT_TESTING_connect_cb cb, + void *cls) +{ + GNUNET_assert (tth != NULL); + + struct ConnectingContext *cc = + GNUNET_malloc (sizeof (struct ConnectingContext)); + + GNUNET_assert (p1 != NULL); + GNUNET_assert (p2 != NULL); + + cc->p1 = p1; + cc->p2 = p2; + + cc->cb = cb; + if (cls != NULL) + cc->cb_cls = cls; + else + cc->cb_cls = cc; + + cc->th_p1 = p1->th; + cc->th_p2 = p2->th; + + GNUNET_assert (cc->th_p1 != NULL); + GNUNET_assert (cc->th_p2 != NULL); + + GNUNET_CONTAINER_DLL_insert (tth->cc_head, tth->cc_tail, cc); + + cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "New connect request %X\n", cc); + + return cc; +} + +/** + * Cancel the request to connect two peers + * Tou MUST cancel the request if you stop the peers before the peers connected succesfully + * + * @param tth transport testing handle + * @param ccr a connect request handle + */ +void +GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct + GNUNET_TRANSPORT_TESTING_handle + *tth, + GNUNET_TRANSPORT_TESTING_ConnectRequest + ccr) +{ + struct ConnectingContext *cc = ccr; + + GNUNET_assert (tth != NULL); + + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Canceling connect request %X!\n", cc); + + if (cc->tct != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (cc->tct); + cc->tct = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_CONTAINER_DLL_remove (tth->cc_head, tth->cc_tail, cc); + GNUNET_free (cc); +} + + +/** + * Clean up the transport testing + * @param tth transport testing handle + */ +void +GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth) +{ + struct ConnectingContext *cc = tth->cc_head; + struct ConnectingContext *ct = NULL; + struct PeerContext *p = tth->p_head; + struct PeerContext *t = NULL; + + GNUNET_assert (tth != NULL); + + while (cc != tth->cc_tail) + { + ct = cc->next; + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing", + "Developer forgot to cancel connect request %X!\n", cc); + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); + cc = ct; + } + + while (p != NULL) + { + t = p->next; + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing", + "Developer forgot to stop peer!\n"); + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p); + p = t; + } + + GNUNET_free_non_null (tth->hostkey_data); + + GNUNET_free (tth); + tth = NULL; +} + +/** + * Initialize the transport testing + * @return transport testing handle + */ +struct GNUNET_TRANSPORT_TESTING_handle * +GNUNET_TRANSPORT_TESTING_init () +{ + struct GNUNET_TRANSPORT_TESTING_handle *tth; + struct GNUNET_DISK_FileHandle *fd; + uint64_t fs; + uint64_t total_hostkeys; + + + /* prepare hostkeys */ + tth = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TESTING_handle)); + tth->hostkey_data = NULL; + const char *hostkeys_file = "../../contrib/testing_hostkeys.dat"; + + if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read hostkeys file!\n")); + } + else + { + /* Check hostkey file size, read entire thing into memory */ + fd = GNUNET_DISK_file_open (hostkeys_file, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fd) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkeys_file); + GNUNET_free (tth); + return NULL; + } + + if (GNUNET_YES != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES)) + fs = 0; + + if (0 != (fs % HOSTKEYFILESIZE)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing", + "File size %llu seems incorrect for hostkeys...\n", fs); + } + else + { + total_hostkeys = fs / HOSTKEYFILESIZE; + tth->hostkey_data = GNUNET_malloc_large (fs); + GNUNET_assert (fs == GNUNET_DISK_file_read (fd, tth->hostkey_data, fs)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Read %llu hostkeys from file\n", total_hostkeys); + tth->hostkeys_total = total_hostkeys; + } + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); + } + + return tth; +} + + +/* + * Some utility functions + */ + +/** + * Removes all directory separators from absolute filename + * @param file the absolute file name, e.g. as found in argv[0] + * @return extracted file name, has to be freed by caller + */ +static char * +extract_filename (const char *file) +{ + char *pch = GNUNET_strdup (file); + char *backup = pch; + char *filename = NULL; + char *res; + + if (NULL != strstr (pch, "/")) + { + pch = strtok (pch, "/"); + while (pch != NULL) + { + pch = strtok (NULL, "/"); + if (pch != NULL) + { + filename = pch; + } + } + } + else + filename = pch; + + res = GNUNET_strdup (filename); + GNUNET_free (backup); + return res; +} + +/** + * Extracts the test filename from an absolute file name and removes the extension + * @param file absolute file name + * @param dest where to store result + */ +void +GNUNET_TRANSPORT_TESTING_get_test_name (const char *file, char **dest) +{ + char *filename = extract_filename (file); + char *backup = filename; + char *dotexe; + + if (filename == NULL) + goto fail; + + /* remove "lt-" */ + filename = strstr (filename, "tes"); + if (filename == NULL) + goto fail; + + /* remove ".exe" */ + if (NULL != (dotexe = strstr (filename, ".exe"))) + dotexe[0] = '\0'; + + goto suc; + +fail: + (*dest) = NULL; + return; + +suc: + /* create filename */ + GNUNET_asprintf (dest, "%s", filename); + GNUNET_free (backup); +} + + +/** + * Extracts the filename from an absolute file name and removes the extension + * @param file absolute file name + * @param dest where to store result + */ +void +GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file, char **dest) +{ + char *src = extract_filename (file); + char *split; + + split = strstr (src, "."); + if (split != NULL) + { + split[0] = '\0'; + } + GNUNET_asprintf (dest, "%s", src); + GNUNET_free (src); +} + + +/** + * Extracts the plugin anme from an absolute file name and the test name + * @param file absolute file name + * @param test test name + * @param dest where to store result + */ +void +GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file, + const char *test, char **dest) +{ + char *e = extract_filename (file); + char *t = extract_filename (test); + + char *filename = NULL; + char *dotexe; + + if (e == NULL) + goto fail; + + /* remove "lt-" */ + filename = strstr (e, "tes"); + if (filename == NULL) + goto fail; + + /* remove ".exe" */ + if (NULL != (dotexe = strstr (filename, ".exe"))) + dotexe[0] = '\0'; + + /* find last _ */ + filename = strstr (filename, t); + if (filename == NULL) + goto fail; + + /* copy plugin */ + filename += strlen (t); + filename++; + GNUNET_asprintf (dest, "%s", filename); + goto suc; + +fail: + (*dest) = NULL; +suc: + GNUNET_free (t); + GNUNET_free (e); + +} + +/** + * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and + * if existing ".exe"-prefix and adds the peer-number + * + * @param file filename of the test, e.g. argv[0] + * @param dest where to write the filename + * @param count peer number + */ +void +GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest, + int count) +{ + char *filename = extract_filename (file); + char *backup = filename; + char *dotexe; + + if (filename == NULL) + goto fail; + + /* remove "lt-" */ + filename = strstr (filename, "tes"); + if (filename == NULL) + goto fail; + + /* remove ".exe" */ + if (NULL != (dotexe = strstr (filename, ".exe"))) + dotexe[0] = '\0'; + + goto suc; + +fail: + (*dest) = NULL; + return; + +suc: + /* create cfg filename */ + GNUNET_asprintf (dest, "%s_peer%u.conf", filename, count); + GNUNET_free (backup); +} + + + +/* end of transport_testing.h */ diff --git a/src/transport/transport-testing.h b/src/transport/transport-testing.h new file mode 100644 index 0000000..20e802d --- /dev/null +++ b/src/transport/transport-testing.h @@ -0,0 +1,275 @@ +/* + This file is part of GNUnet. + (C) 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport-testing.h + * @brief testing lib for transport service + * + * @author Matthias Wachs + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_hello_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_transport_service.h" + + +#define GNUNET_TRANSPORT_TESTING_ConnectRequest void * + + +/** + * Context for a single peer + */ +struct PeerContext; + +/** + * Callback when two peers are connected and both have called the connect callback + * to notify clients about a new peer + */ +typedef void (*GNUNET_TRANSPORT_TESTING_start_cb) (struct PeerContext * p, + void *cls); + +/** + * Callback when two peers are connected and both have called the connect callback + * to notify clients about a new peer + */ +typedef void (*GNUNET_TRANSPORT_TESTING_connect_cb) (struct PeerContext * p1, + struct PeerContext * p2, + void *cls); + + + +struct GNUNET_TRANSPORT_TESTING_handle; + +/** + * Context for a single peer + */ +struct PeerContext +{ + struct PeerContext *next; + struct PeerContext *prev; + + struct GNUNET_TRANSPORT_TESTING_handle *tth; + + struct GNUNET_CONFIGURATION_Handle *cfg; + + struct GNUNET_TRANSPORT_Handle *th; + + struct GNUNET_TRANSPORT_GetHelloHandle *ghh; + + struct GNUNET_PeerIdentity id; + + struct GNUNET_OS_Process *arm_proc; + + GNUNET_TRANSPORT_ReceiveCallback rec; + + GNUNET_TRANSPORT_NotifyConnect nc; + + GNUNET_TRANSPORT_NotifyDisconnect nd; + + GNUNET_TRANSPORT_TESTING_start_cb start_cb; + + struct GNUNET_HELLO_Message *hello; + + void *cb_cls; + + char *servicehome; + + char *hostkeyfile; + + unsigned int no; +}; + + +struct ConnectingContext +{ + struct ConnectingContext *next; + struct ConnectingContext *prev; + struct PeerContext *p1; + struct PeerContext *p2; + GNUNET_SCHEDULER_TaskIdentifier tct; + GNUNET_TRANSPORT_TESTING_connect_cb cb; + void *cb_cls; + struct GNUNET_TRANSPORT_Handle *th_p1; + struct GNUNET_TRANSPORT_Handle *th_p2; + int p1_c; + int p2_c; +}; + +struct GNUNET_TRANSPORT_TESTING_handle +{ + struct ConnectingContext *cc_head; + struct ConnectingContext *cc_tail; + + char *hostkey_data; + int hostkeys_total; + int hostkeys_last; + + struct PeerContext *p_head; + struct PeerContext *p_tail; +}; + + +/** +* Start a peer with the given configuration +* @param tth the testing handle +* @param cfgname configuration file +* @param peer_id the peer_id +* @param rec receive callback +* @param nc connect callback +* @param nd disconnect callback +* @param start_cb start callback +* @param cb_cls closure for callback +* @return the peer context +*/ +struct PeerContext * +GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle + *tth, const char *cfgname, int peer_id, + GNUNET_TRANSPORT_ReceiveCallback rec, + GNUNET_TRANSPORT_NotifyConnect nc, + GNUNET_TRANSPORT_NotifyDisconnect nd, + GNUNET_TRANSPORT_TESTING_start_cb start_cb, + void *cb_cls); + + +/** + * shutdown the given peer + * @param tth the testing handle + * @param p the peer + */ + +void +GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth, + struct PeerContext *pc); + + +/** +* Restart the given peer +* @param tth testing handle +* @param p the peer +* @param cfgname the cfg file used to restart +* @param restart_cb restart callback +* @param cb_cls callback closure +* @return GNUNET_OK in success otherwise GNUNET_SYSERR +*/ +int +GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle + *tth, struct PeerContext *p, + const char *cfgname, + GNUNET_TRANSPORT_TESTING_start_cb + restart_cb, void *cb_cls); + +/** + * Connect the given peers and call the callback when both peers report the + * inbound connection. Remarks: start_peer's notify_connect callback can be called + * before. + * + * @param tth transport testing handle + * @param p1 peer 1 + * @param p2 peer 2 + * @param cb the callback to call when both peers notified that they are connected + * @param cls callback cls + * @return a connect request handle + */ +GNUNET_TRANSPORT_TESTING_ConnectRequest +GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth, + struct PeerContext *p1, + struct PeerContext *p2, + GNUNET_TRANSPORT_TESTING_connect_cb cb, + void *cls); + +/** + * Cancel the request to connect two peers + * Tou MUST cancel the request if you stop the peers before the peers connected succesfully + * @param tth testing + * @param ccr a connect request handle + */ +void +GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct + GNUNET_TRANSPORT_TESTING_handle + *tth, + GNUNET_TRANSPORT_TESTING_ConnectRequest + ccr); + +/** + * Clean up the transport testing + * @param tth transport testing handle + */ +void +GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth); + +/** + * Initialize the transport testing + * @return transport testing handle + */ +struct GNUNET_TRANSPORT_TESTING_handle * +GNUNET_TRANSPORT_TESTING_init (); + +/* + * Some utility functions + */ + +/** + * Extracts the test filename from an absolute file name and removes the extension + * @param file absolute file name + * @param dest where to store result + */ +void +GNUNET_TRANSPORT_TESTING_get_test_name (const char *file, char **dest); + +/** + * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and + * if existing ".exe"-prefix and adds the peer-number + * + * @param file filename of the test, e.g. argv[0] + * @param dest where to write the filename + * @param count peer number + */ +void +GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest, + int count); + + +/** + * Extracts the plugin anme from an absolute file name and the test name + * @param file absolute file name + * @param test test name + * @param dest where to store result + */ +void +GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *executable, + const char *testname, + char **pluginname); + + +/** + * Extracts the filename from an absolute file name and removes the extenstion + * @param file absolute file name + * @param dest where to store result + */ +void +GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file, + char **testname); + +/* end of transport_testing.h */ diff --git a/src/transport/transport.conf.in b/src/transport/transport.conf.in new file mode 100644 index 0000000..ff81ff0 --- /dev/null +++ b/src/transport/transport.conf.in @@ -0,0 +1,67 @@ +[transport] +AUTOSTART = YES +@UNIXONLY@ PORT = 2091 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-transport +#PREFIX = valgrind +NEIGHBOUR_LIMIT = 50 +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +PLUGINS = tcp +UNIXPATH = /tmp/gnunet-service-transport.sock +BLACKLIST_FILE = $SERVICEHOME/blacklist +# This could possibly be relaxed +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +# DISABLE_SOCKET_FORWARDING = NO +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = valgrind --leak-check=full + + +[transport-tcp] +# Use 0 to ONLY advertise as a peer behind NAT (no port binding) +PORT = 2086 +ADVERTISED_PORT = 2086 + +# Maximum number of open TCP connections allowed +MAX_CONNECTIONS = 128 + +TIMEOUT = 5 s +# ACCEPT_FROM = +# ACCEPT_FROM6 = +# REJECT_FROM = +# REJECT_FROM6 = +# BINDTO = +MAX_CONNECTIONS = 128 + +[transport-udp] +PORT = 2086 +BROADCAST = YES +BROADCAST_INTERVAL = 30000 +MAX_BPS = 1000000 + +[transport-http] +PORT = 1080 +MAX_CONNECTIONS = 128 + +[transport-https] +PORT = 4433 +CRYPTO_INIT = NORMAL +KEY_FILE = https.key +CERT_FILE = https.cert +MAX_CONNECTIONS = 128 + +[transport-wlan] +# Name of the interface in monitor mode (typically monX) +INTERFACE = mon0 +# Real hardware, no testing +TESTMODE = 0 + diff --git a/src/transport/transport.h b/src/transport/transport.h new file mode 100644 index 0000000..ff68188 --- /dev/null +++ b/src/transport/transport.h @@ -0,0 +1,438 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/transport.h + * @brief common internal definitions for transport service + * @author Christian Grothoff + */ +#ifndef TRANSPORT_H +#define TRANSPORT_H + +#include "gnunet_crypto_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_constants.h" + +#define DEBUG_TRANSPORT GNUNET_EXTRA_LOGGING + +#define DEBUG_TRANSPORT_TIMEOUT GNUNET_EXTRA_LOGGING + +#define DEBUG_TRANSPORT_DISCONNECT GNUNET_EXTRA_LOGGING + +#define DEBUG_TRANSPORT_API GNUNET_EXTRA_LOGGING + +/** + * For how long do we allow unused bandwidth + * from the past to carry over into the future? (in seconds) + */ +#define MAX_BANDWIDTH_CARRY_S GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S + +/** + * How often do we (at most) do a full quota + * recalculation? (in ms) + */ +#define MIN_QUOTA_REFRESH_TIME 2000 + +/** + * Maximum frequency for re-evaluating latencies for all transport addresses. + */ +#define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1) + +/** + * Maximum frequency for re-evaluating latencies for connected addresses. + */ +#define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1) + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message from the transport service to the library + * asking to check if both processes agree about this + * peers identity. + */ +struct StartMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_START + */ + struct GNUNET_MessageHeader header; + + /** + * 0: no options + * 1: The 'self' field should be checked + * 2: this client is interested in payload traffic + */ + uint32_t options; + + /** + * Identity we think we have. If it does not match, the + * receiver should print out an error message and disconnect. + */ + struct GNUNET_PeerIdentity self; + +}; + + +/** + * Message from the transport service to the library + * informing about neighbors. + */ +struct ConnectInfoMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT + */ + struct GNUNET_MessageHeader header; + + /** + * Number of ATS key-value pairs that follow this struct + * (excluding the 0-terminator). + */ + uint32_t ats_count GNUNET_PACKED; + + /** + * Identity of the new neighbour. + */ + struct GNUNET_PeerIdentity id; +}; + + +/** + * Message from the transport service to the library + * informing about disconnects. + */ +struct DisconnectInfoMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT + */ + struct GNUNET_MessageHeader header; + + /** + * Reserved, always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Who got disconnected? + */ + struct GNUNET_PeerIdentity peer; + +}; + +/** + * Message type for sending a request connect message + * to the transport service. Must be done before transport + * api will allow messages to be queued/sent to transport + * service for transmission to a peer. + */ +struct TransportRequestConnectMessage +{ + /** + * Message header + */ + struct GNUNET_MessageHeader header; + + /** + * For alignment. + */ + uint32_t reserved; + + /** + * Identity of the peer we would like to connect to. + */ + struct GNUNET_PeerIdentity peer; +}; + +/** + * Message used to set a particular bandwidth quota. Sent TO the + * service to set an incoming quota, sent FROM the service to update + * an outgoing quota. + */ +struct QuotaSetMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA + */ + struct GNUNET_MessageHeader header; + + /** + * Quota. + */ + struct GNUNET_BANDWIDTH_Value32NBO quota; + + /** + * About which peer are we talking here? + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Message used to notify the transport API about a message + * received from the network. The actual message follows. + */ +struct InboundMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_RECV + */ + struct GNUNET_MessageHeader header; + + /** + * Number of ATS key-value pairs that follow this struct + * (excluding the 0-terminator). + */ + uint32_t ats_count GNUNET_PACKED; + + /** + * Which peer sent the message? + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Message used to notify the transport API that it can + * send another message to the transport service. + */ +struct SendOkMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK + */ + struct GNUNET_MessageHeader header; + + /** + * GNUNET_OK if the transmission succeeded, + * GNUNET_SYSERR if it failed (i.e. network disconnect); + * in either case, it is now OK for this client to + * send us another message for the given peer. + */ + uint32_t success GNUNET_PACKED; + + /** + * Latency estimate. + */ + struct GNUNET_TIME_RelativeNBO latency; + + /** + * Which peer can send more now? + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Message used to notify the transport service about a message + * to be transmitted to another peer. The actual message follows. + */ +struct OutboundMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SEND + */ + struct GNUNET_MessageHeader header; + + /** + * Message priority. + */ + uint32_t priority GNUNET_PACKED; + + /** + * Allowed delay. + */ + struct GNUNET_TIME_RelativeNBO timeout; + + /** + * Which peer should receive the message? + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Message from the library to the transport service + * asking for converting a transport address to a + * human-readable UTF-8 string. + */ +struct AddressLookupMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP + */ + struct GNUNET_MessageHeader header; + + /** + * Should the conversion use numeric IP addresses (otherwise + * a reverse DNS lookup is OK -- if applicable). + */ + int16_t numeric_only GNUNET_PACKED; + + /** + * Length of the (binary) address in bytes, in big-endian. + */ + uint16_t addrlen GNUNET_PACKED; + + /** + * timeout to give up. + */ + struct GNUNET_TIME_RelativeNBO timeout; + + /* followed by 'addrlen' bytes of the actual address, then + * followed by the 0-terminated name of the transport */ +}; + + +/** + * Message from the library to the transport service + * asking for human readable addresses known for a peer. + */ +struct PeerAddressLookupMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP + */ + struct GNUNET_MessageHeader header; + + /** + * For alignment. + */ + uint32_t reserved; + + /** + * timeout to give up. FIXME: remove in the future. + */ + struct GNUNET_TIME_RelativeNBO timeout; + + /** + * The identity of the peer to look up. + */ + struct GNUNET_PeerIdentity peer; +}; + + +/** + * Message from the library to the transport service + * asking for binary addresses known for a peer. + */ +struct AddressIterateMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE + */ + struct GNUNET_MessageHeader header; + + /** + * One shot call or continous replies? + */ + uint32_t one_shot; + + /** + * timeout to give up. FIXME: remove in the future + */ + struct GNUNET_TIME_AbsoluteNBO timeout; + + /** + * The identity of the peer to look up. + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Message from the transport service to the library + * containing binary addresses known for a peer. + * Memory layout: + * [AddressIterateResponseMessage][address[addrlen]][transportname[pluginlen]] + */ +struct AddressIterateResponseMessage +{ + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE + */ + struct GNUNET_MessageHeader header; + + /** + * For alignment. + */ + uint32_t reserved; + + /** + * Peer identity + */ + struct GNUNET_PeerIdentity peer; + + /** + * address length + */ + uint32_t addrlen GNUNET_PACKED; + + /** + * length of the plugin name + */ + uint32_t pluginlen GNUNET_PACKED; + +}; + + +/** + * Change in blacklisting (either request or notification, + * depending on which direction it is going). + */ +struct BlacklistMessage +{ + + /** + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY or + * GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY. + */ + struct GNUNET_MessageHeader header; + + /** + * 0 for the query, GNUNET_OK (allowed) or GNUNET_SYSERR (disallowed) + * for the response. + */ + uint32_t is_allowed GNUNET_PACKED; + + /** + * Which peer is being blacklisted or queried? + */ + struct GNUNET_PeerIdentity peer; + +}; +GNUNET_NETWORK_STRUCT_END + +/* end of transport.h */ +#endif diff --git a/src/transport/transport_api.c b/src/transport/transport_api.c new file mode 100644 index 0000000..9ff5cec --- /dev/null +++ b/src/transport/transport_api.c @@ -0,0 +1,1337 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/transport_api.c + * @brief library to access the low-level P2P IO service + * @author Christian Grothoff + * + * TODO: + * - adjust testcases to use new 'try connect' style (should be easy, breaks API compatibility!) + * - adjust core service to use new 'try connect' style (should be MUCH nicer there as well!) + * - test test test + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_bandwidth_lib.h" +#include "gnunet_client_lib.h" +#include "gnunet_constants.h" +#include "gnunet_container_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "transport-api",__VA_ARGS__) + +/** + * How large to start with for the hashmap of neighbours. + */ +#define STARTING_NEIGHBOURS_SIZE 16 + +/** + * Handle for a message that should be transmitted to the service. + * Used for both control messages and normal messages. + */ +struct GNUNET_TRANSPORT_TransmitHandle +{ + + /** + * We keep all requests in a DLL. + */ + struct GNUNET_TRANSPORT_TransmitHandle *next; + + /** + * We keep all requests in a DLL. + */ + struct GNUNET_TRANSPORT_TransmitHandle *prev; + + /** + * Neighbour for this handle, NULL for control messages. + */ + struct Neighbour *neighbour; + + /** + * Function to call when notify_size bytes are available + * for transmission. + */ + GNUNET_CONNECTION_TransmitReadyNotify notify; + + /** + * Closure for notify. + */ + void *notify_cls; + + /** + * Timeout for this request, 0 for control messages. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Task to trigger request timeout if the request is stalled due to + * congestion. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * How many bytes is our notify callback waiting for? + */ + size_t notify_size; + + /** + * How important is this message? Not used for control messages. + */ + uint32_t priority; + +}; + + +/** + * Entry in hash table of all of our current neighbours. + */ +struct Neighbour +{ + /** + * Overall transport handle. + */ + struct GNUNET_TRANSPORT_Handle *h; + + /** + * Active transmit handle or NULL. + */ + struct GNUNET_TRANSPORT_TransmitHandle *th; + + /** + * Identity of this neighbour. + */ + struct GNUNET_PeerIdentity id; + + /** + * Outbound bandwidh tracker. + */ + struct GNUNET_BANDWIDTH_Tracker out_tracker; + + /** + * Entry in our readyness heap (which is sorted by 'next_ready' + * value). NULL if there is no pending transmission request for + * this neighbour or if we're waiting for 'is_ready' to become + * true AFTER the 'out_tracker' suggested that this peer's quota + * has been satisfied (so once 'is_ready' goes to GNUNET_YES, + * we should immediately go back into the heap). + */ + struct GNUNET_CONTAINER_HeapNode *hn; + + /** + * Is this peer currently ready to receive a message? + */ + int is_ready; + +}; + + +/** + * Linked list of functions to call whenever our HELLO is updated. + */ +struct GNUNET_TRANSPORT_GetHelloHandle +{ + + /** + * This is a doubly linked list. + */ + struct GNUNET_TRANSPORT_GetHelloHandle *next; + + /** + * This is a doubly linked list. + */ + struct GNUNET_TRANSPORT_GetHelloHandle *prev; + + /** + * Transport handle. + */ + struct GNUNET_TRANSPORT_Handle *handle; + + /** + * Callback to call once we got our HELLO. + */ + GNUNET_TRANSPORT_HelloUpdateCallback rec; + + /** + * Closure for rec. + */ + void *rec_cls; + +}; + + +/** + * Handle for the transport service (includes all of the + * state for the transport service). + */ +struct GNUNET_TRANSPORT_Handle +{ + + /** + * Closure for the callbacks. + */ + void *cls; + + /** + * Function to call for received data. + */ + GNUNET_TRANSPORT_ReceiveCallback rec; + + /** + * function to call on connect events + */ + GNUNET_TRANSPORT_NotifyConnect nc_cb; + + /** + * function to call on disconnect events + */ + GNUNET_TRANSPORT_NotifyDisconnect nd_cb; + + /** + * Head of DLL of control messages. + */ + struct GNUNET_TRANSPORT_TransmitHandle *control_head; + + /** + * Tail of DLL of control messages. + */ + struct GNUNET_TRANSPORT_TransmitHandle *control_tail; + + /** + * The current HELLO message for this peer. Updated + * whenever transports change their addresses. + */ + struct GNUNET_HELLO_Message *my_hello; + + /** + * My client connection to the transport service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Handle to our registration with the client for notification. + */ + struct GNUNET_CLIENT_TransmitHandle *cth; + + /** + * Linked list of pending requests for our HELLO. + */ + struct GNUNET_TRANSPORT_GetHelloHandle *hwl_head; + + /** + * Linked list of pending requests for our HELLO. + */ + struct GNUNET_TRANSPORT_GetHelloHandle *hwl_tail; + + /** + * My configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Hash map of the current connected neighbours of this peer. + * Maps peer identities to 'struct Neighbour' entries. + */ + struct GNUNET_CONTAINER_MultiHashMap *neighbours; + + /** + * Heap sorting peers with pending messages by the timestamps that + * specify when we could next send a message to the respective peer. + * Excludes control messages (which can always go out immediately). + * Maps time stamps to 'struct Neighbour' entries. + */ + struct GNUNET_CONTAINER_Heap *ready_heap; + + /** + * Peer identity as assumed by this process, or all zeros. + */ + struct GNUNET_PeerIdentity self; + + /** + * ID of the task trying to reconnect to the service. + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * ID of the task trying to trigger transmission for a peer while + * maintaining bandwidth quotas. In use if there are no control + * messages and the smallest entry in the 'ready_heap' has a time + * stamp in the future. + */ + GNUNET_SCHEDULER_TaskIdentifier quota_task; + + /** + * Delay until we try to reconnect. + */ + struct GNUNET_TIME_Relative reconnect_delay; + + /** + * Should we check that 'self' matches what the service thinks? + * (if GNUNET_NO, then 'self' is all zeros!). + */ + int check_self; +}; + + +/** + * Schedule the task to send one message, either from the control + * list or the peer message queues to the service. + * + * @param h transport service to schedule a transmission for + */ +static void +schedule_transmission (struct GNUNET_TRANSPORT_Handle *h); + + +/** + * Function that will schedule the job that will try + * to connect us again to the client. + * + * @param h transport service to reconnect + */ +static void +disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_Handle *h); + + +/** + * Get the neighbour list entry for the given peer + * + * @param h our context + * @param peer peer to look up + * @return NULL if no such peer entry exists + */ +static struct Neighbour * +neighbour_find (struct GNUNET_TRANSPORT_Handle *h, + const struct GNUNET_PeerIdentity *peer) +{ + return GNUNET_CONTAINER_multihashmap_get (h->neighbours, &peer->hashPubKey); +} + + +/** + * Add neighbour to our list + * + * @return NULL if this API is currently disconnecting from the service + */ +static struct Neighbour * +neighbour_add (struct GNUNET_TRANSPORT_Handle *h, + const struct GNUNET_PeerIdentity *pid) +{ + struct Neighbour *n; + +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating entry for neighbour `%4s'.\n", + GNUNET_i2s (pid)); +#endif + n = GNUNET_malloc (sizeof (struct Neighbour)); + n->id = *pid; + n->h = h; + n->is_ready = GNUNET_YES; + GNUNET_BANDWIDTH_tracker_init (&n->out_tracker, + GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT, + MAX_BANDWIDTH_CARRY_S); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (h->neighbours, + &pid->hashPubKey, n, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + return n; +} + + +/** + * Iterator over hash map entries, for deleting state of a neighbour. + * + * @param cls the 'struct GNUNET_TRANSPORT_Handle*' + * @param key peer identity + * @param value value in the hash map, the neighbour entry to delete + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +neighbour_delete (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct GNUNET_TRANSPORT_Handle *handle = cls; + struct Neighbour *n = value; + + if (NULL != handle->nd_cb) + handle->nd_cb (handle->cls, &n->id); + GNUNET_assert (NULL == n->th); + GNUNET_assert (NULL == n->hn); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (handle->neighbours, key, + n)); + GNUNET_free (n); + return GNUNET_YES; +} + + +/** + * Function we use for handling incoming messages. + * + * @param cls closure (struct GNUNET_TRANSPORT_Handle *) + * @param msg message received, NULL on timeout or fatal error + */ +static void +demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_TRANSPORT_Handle *h = cls; + const struct DisconnectInfoMessage *dim; + const struct ConnectInfoMessage *cim; + const struct InboundMessage *im; + const struct GNUNET_MessageHeader *imm; + const struct SendOkMessage *okm; + const struct QuotaSetMessage *qm; + const struct GNUNET_ATS_Information *ats; + struct GNUNET_TRANSPORT_GetHelloHandle *hwl; + struct GNUNET_TRANSPORT_GetHelloHandle *next_hwl; + struct Neighbour *n; + struct GNUNET_PeerIdentity me; + uint16_t size; + uint32_t ats_count; + + GNUNET_assert (h->client != NULL); + if (msg == NULL) + { +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_INFO, + "Error receiving from transport service, disconnecting temporarily.\n"); +#endif + disconnect_and_schedule_reconnect (h); + return; + } + GNUNET_CLIENT_receive (h->client, &demultiplexer, h, + GNUNET_TIME_UNIT_FOREVER_REL); + size = ntohs (msg->size); + switch (ntohs (msg->type)) + { + case GNUNET_MESSAGE_TYPE_HELLO: + if (GNUNET_OK != + GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) msg, &me)) + { + GNUNET_break (0); + break; + } +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Receiving (my own) `%s' message, I am `%4s'.\n", "HELLO", + GNUNET_i2s (&me)); +#endif + GNUNET_free_non_null (h->my_hello); + h->my_hello = NULL; + if (size < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + break; + } + h->my_hello = GNUNET_malloc (size); + memcpy (h->my_hello, msg, size); + hwl = h->hwl_head; + while (NULL != hwl) + { + next_hwl = hwl->next; + hwl->rec (hwl->rec_cls, + (const struct GNUNET_MessageHeader *) h->my_hello); + hwl = next_hwl; + } + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT: + if (size < sizeof (struct ConnectInfoMessage)) + { + GNUNET_break (0); + break; + } + cim = (const struct ConnectInfoMessage *) msg; + ats_count = ntohl (cim->ats_count); + if (size != + sizeof (struct ConnectInfoMessage) + + ats_count * sizeof (struct GNUNET_ATS_Information)) + { + GNUNET_break (0); + break; + } + ats = (const struct GNUNET_ATS_Information *) &cim[1]; +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message for `%4s'.\n", + "CONNECT", GNUNET_i2s (&cim->id)); +#endif + n = neighbour_find (h, &cim->id); + if (n != NULL) + { + GNUNET_break (0); + break; + } + n = neighbour_add (h, &cim->id); + if (h->nc_cb != NULL) + h->nc_cb (h->cls, &n->id, ats, ats_count); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT: + if (size != sizeof (struct DisconnectInfoMessage)) + { + GNUNET_break (0); + break; + } + dim = (const struct DisconnectInfoMessage *) msg; + GNUNET_break (ntohl (dim->reserved) == 0); +#if DEBUG_TRANSPORT_API_DISCONNECT + LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message for `%4s'.\n", + "DISCONNECT", GNUNET_i2s (&dim->peer)); +#endif + n = neighbour_find (h, &dim->peer); + if (n == NULL) + { + GNUNET_break (0); + break; + } + neighbour_delete (h, &dim->peer.hashPubKey, n); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK: + if (size != sizeof (struct SendOkMessage)) + { + GNUNET_break (0); + break; + } + okm = (const struct SendOkMessage *) msg; +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message, transmission %s.\n", + "SEND_OK", ntohl (okm->success) == GNUNET_OK ? "succeeded" : "failed"); +#endif + n = neighbour_find (h, &okm->peer); + if (n == NULL) + break; + GNUNET_break (GNUNET_NO == n->is_ready); + n->is_ready = GNUNET_YES; + if ((n->th != NULL) && (n->hn == NULL)) + { + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->th->timeout_task); + GNUNET_SCHEDULER_cancel (n->th->timeout_task); + n->th->timeout_task = GNUNET_SCHEDULER_NO_TASK; + /* we've been waiting for this (congestion, not quota, + * caused delayed transmission) */ + n->hn = GNUNET_CONTAINER_heap_insert (h->ready_heap, n, 0); + schedule_transmission (h); + } + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_RECV: +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message.\n", "RECV"); +#endif + if (size < + sizeof (struct InboundMessage) + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + break; + } + im = (const struct InboundMessage *) msg; + ats_count = ntohl (im->ats_count); + ats = (const struct GNUNET_ATS_Information *) &im[1]; + imm = (const struct GNUNET_MessageHeader *) &ats[ats_count]; + if (ntohs (imm->size) + sizeof (struct InboundMessage) + + ats_count * sizeof (struct GNUNET_ATS_Information) != size) + { + GNUNET_break (0); + break; + } +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u from `%4s'.\n", + ntohs (imm->type), GNUNET_i2s (&im->peer)); +#endif + n = neighbour_find (h, &im->peer); + if (n == NULL) + { + GNUNET_break (0); + break; + } + if (h->rec != NULL) + h->rec (h->cls, &im->peer, imm, ats, ats_count); + break; + case GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA: +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message.\n", "SET_QUOTA"); +#endif + if (size != sizeof (struct QuotaSetMessage)) + { + GNUNET_break (0); + break; + } + qm = (const struct QuotaSetMessage *) msg; + n = neighbour_find (h, &qm->peer); + if (n == NULL) + break; + GNUNET_BANDWIDTH_tracker_update_quota (&n->out_tracker, qm->quota); + break; + default: + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Received unexpected message of type %u in %s:%u\n"), + ntohs (msg->type), __FILE__, __LINE__); + GNUNET_break (0); + break; + } +} + + +/** + * A transmission request could not be satisfied because of + * network congestion. Notify the initiator and clean up. + * + * @param cls the 'struct GNUNET_TRANSPORT_TransmitHandle' + * @param tc scheduler context + */ +static void +timeout_request_due_to_congestion (void *cls, + const struct GNUNET_SCHEDULER_TaskContext + *tc) +{ + struct GNUNET_TRANSPORT_TransmitHandle *th = cls; + struct Neighbour *n = th->neighbour; + + n->th->timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (th == n->th); + GNUNET_assert (NULL == n->hn); + n->th = NULL; + th->notify (th->notify_cls, 0, NULL); + GNUNET_free (th); +} + + +/** + * Transmit message(s) to service. + * + * @param cls handle to transport + * @param size number of bytes available in buf + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +transport_notify_ready (void *cls, size_t size, void *buf) +{ + struct GNUNET_TRANSPORT_Handle *h = cls; + struct GNUNET_TRANSPORT_TransmitHandle *th; + struct Neighbour *n; + char *cbuf; + struct OutboundMessage obm; + size_t ret; + size_t nret; + size_t mret; + + GNUNET_assert (NULL != h->client); + h->cth = NULL; + if (NULL == buf) + { + /* transmission failed */ + disconnect_and_schedule_reconnect (h); + return 0; + } + + cbuf = buf; + ret = 0; + /* first send control messages */ + while ((NULL != (th = h->control_head)) && (th->notify_size <= size)) + { + GNUNET_CONTAINER_DLL_remove (h->control_head, h->control_tail, th); + nret = th->notify (th->notify_cls, size, &cbuf[ret]); +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Added %u bytes of control message at %u\n", + nret, ret); +#endif + GNUNET_free (th); + ret += nret; + size -= nret; + } + + /* then, if possible and no control messages pending, send data messages */ + while ((NULL == h->control_head) && + (NULL != (n = GNUNET_CONTAINER_heap_peek (h->ready_heap)))) + { + if (GNUNET_YES != n->is_ready) + { + /* peer not ready, wait for notification! */ + GNUNET_assert (n == GNUNET_CONTAINER_heap_remove_root (h->ready_heap)); + n->hn = NULL; + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->th->timeout_task); + n->th->timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (n->th->timeout), + &timeout_request_due_to_congestion, + n->th); + continue; + } + th = n->th; + if (th->notify_size + sizeof (struct OutboundMessage) > size) + break; /* does not fit */ + if (GNUNET_BANDWIDTH_tracker_get_delay + (&n->out_tracker, th->notify_size).rel_value > 0) + break; /* too early */ + GNUNET_assert (n == GNUNET_CONTAINER_heap_remove_root (h->ready_heap)); + n->hn = NULL; + n->th = NULL; + n->is_ready = GNUNET_NO; + GNUNET_assert (size >= sizeof (struct OutboundMessage)); + mret = + th->notify (th->notify_cls, size - sizeof (struct OutboundMessage), + &cbuf[ret + sizeof (struct OutboundMessage)]); + GNUNET_assert (mret <= size - sizeof (struct OutboundMessage)); + if (mret != 0) + { + GNUNET_assert (mret + sizeof (struct OutboundMessage) < + GNUNET_SERVER_MAX_MESSAGE_SIZE); + obm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND); + obm.header.size = htons (mret + sizeof (struct OutboundMessage)); + obm.priority = htonl (th->priority); + obm.timeout = + GNUNET_TIME_relative_hton (GNUNET_TIME_absolute_get_remaining + (th->timeout)); + obm.peer = n->id; + memcpy (&cbuf[ret], &obm, sizeof (struct OutboundMessage)); + ret += (mret + sizeof (struct OutboundMessage)); + size -= (mret + sizeof (struct OutboundMessage)); + GNUNET_BANDWIDTH_tracker_consume (&n->out_tracker, mret); + } + GNUNET_free (th); + } + /* if there are more pending messages, try to schedule those */ + schedule_transmission (h); +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes to transport service\n", + ret); +#endif + return ret; +} + + +/** + * Schedule the task to send one message, either from the control + * list or the peer message queues to the service. + * + * @param cls transport service to schedule a transmission for + * @param tc scheduler context + */ +static void +schedule_transmission_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TRANSPORT_Handle *h = cls; + size_t size; + struct GNUNET_TRANSPORT_TransmitHandle *th; + struct Neighbour *n; + + h->quota_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (NULL != h->client); + /* destroy all requests that have timed out */ + while ((NULL != (n = GNUNET_CONTAINER_heap_peek (h->ready_heap))) && + (GNUNET_TIME_absolute_get_remaining (n->th->timeout).rel_value == 0)) + { + /* notify client that the request could not be satisfied within + * the given time constraints */ + th = n->th; + n->th = NULL; + GNUNET_assert (n == GNUNET_CONTAINER_heap_remove_root (h->ready_heap)); + n->hn = NULL; +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Signalling timeout for transmission to peer %s due to congestion\n", + GNUNET_i2s (&n->id)); +#endif + GNUNET_assert (0 == th->notify (th->notify_cls, 0, NULL)); + GNUNET_free (th); + } + if (NULL != h->cth) + return; + if (NULL != h->control_head) + { + size = h->control_head->notify_size; + } + else + { + n = GNUNET_CONTAINER_heap_peek (h->ready_heap); + if (NULL == n) + return; /* no pending messages */ + size = n->th->notify_size + sizeof (struct OutboundMessage); + } +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Calling notify_transmit_ready\n"); +#endif + h->cth = + GNUNET_CLIENT_notify_transmit_ready (h->client, size, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, &transport_notify_ready, + h); + GNUNET_assert (NULL != h->cth); +} + + +/** + * Schedule the task to send one message, either from the control + * list or the peer message queues to the service. + * + * @param h transport service to schedule a transmission for + */ +static void +schedule_transmission (struct GNUNET_TRANSPORT_Handle *h) +{ + struct GNUNET_TIME_Relative delay; + struct Neighbour *n; + + GNUNET_assert (NULL != h->client); + if (h->quota_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (h->quota_task); + h->quota_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != h->control_head) + delay = GNUNET_TIME_UNIT_ZERO; + else if (NULL != (n = GNUNET_CONTAINER_heap_peek (h->ready_heap))) + delay = + GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, + n->th->notify_size); + else + return; /* no work to be done */ +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling next transmission to service in %llu ms\n", + (unsigned long long) delay.rel_value); +#endif + h->quota_task = + GNUNET_SCHEDULER_add_delayed (delay, &schedule_transmission_task, h); +} + + +/** + * Queue control request for transmission to the transport + * service. + * + * @param h handle to the transport service + * @param size number of bytes to be transmitted + * @param notify function to call to get the content + * @param notify_cls closure for notify + */ +static void +schedule_control_transmit (struct GNUNET_TRANSPORT_Handle *h, size_t size, + GNUNET_CONNECTION_TransmitReadyNotify notify, + void *notify_cls) +{ + struct GNUNET_TRANSPORT_TransmitHandle *th; + +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Control transmit of %u bytes requested\n", + size); +#endif + th = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TransmitHandle)); + th->notify = notify; + th->notify_cls = notify_cls; + th->notify_size = size; + GNUNET_CONTAINER_DLL_insert_tail (h->control_head, h->control_tail, th); + schedule_transmission (h); +} + + +/** + * Transmit START message to service. + * + * @param cls unused + * @param size number of bytes available in buf + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +send_start (void *cls, size_t size, void *buf) +{ + struct GNUNET_TRANSPORT_Handle *h = cls; + struct StartMessage s; + uint32_t options; + + if (buf == NULL) + { + /* Can only be shutdown, just give up */ +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Shutdown while trying to transmit `%s' request.\n", "START"); +#endif + return 0; + } +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "START"); +#endif + GNUNET_assert (size >= sizeof (struct StartMessage)); + s.header.size = htons (sizeof (struct StartMessage)); + s.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_START); + options = 0; + if (h->check_self) + options |= 1; + if (h->rec != NULL) + options |= 2; + s.options = htonl (options); + s.self = h->self; + memcpy (buf, &s, sizeof (struct StartMessage)); + GNUNET_CLIENT_receive (h->client, &demultiplexer, h, + GNUNET_TIME_UNIT_FOREVER_REL); + return sizeof (struct StartMessage); +} + + +/** + * Try again to connect to transport service. + * + * @param cls the handle to the transport service + * @param tc scheduler context + */ +static void +reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TRANSPORT_Handle *h = cls; + + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + /* shutdown, just give up */ + return; + } +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n"); +#endif + GNUNET_assert (h->client == NULL); + GNUNET_assert (h->control_head == NULL); + GNUNET_assert (h->control_tail == NULL); + h->client = GNUNET_CLIENT_connect ("transport", h->cfg); + GNUNET_assert (h->client != NULL); + schedule_control_transmit (h, sizeof (struct StartMessage), &send_start, h); +} + + +/** + * Function that will schedule the job that will try + * to connect us again to the client. + * + * @param h transport service to reconnect + */ +static void +disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_Handle *h) +{ + struct GNUNET_TRANSPORT_TransmitHandle *th; + + GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); + if (NULL != h->cth) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth); + h->cth = NULL; + } + if (NULL != h->client) + { + GNUNET_CLIENT_disconnect (h->client, GNUNET_YES); + h->client = NULL; + } + /* Forget about all neighbours that we used to be connected to */ + GNUNET_CONTAINER_multihashmap_iterate (h->neighbours, &neighbour_delete, h); + if (h->quota_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (h->quota_task); + h->quota_task = GNUNET_SCHEDULER_NO_TASK; + } + while ((NULL != (th = h->control_head))) + { + GNUNET_CONTAINER_DLL_remove (h->control_head, h->control_tail, th); + th->notify (th->notify_cls, 0, NULL); + GNUNET_free (th); + } +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling task to reconnect to transport service in %llu ms.\n", + h->reconnect_delay.rel_value); +#endif + h->reconnect_task = + GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h); + if (h->reconnect_delay.rel_value == 0) + { + h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; + } + else + { + h->reconnect_delay = GNUNET_TIME_relative_multiply (h->reconnect_delay, 2); + h->reconnect_delay = + GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, h->reconnect_delay); + } +} + + +/** + * Send REQUEST_CONNECT message to the service. + * + * @param cls the 'struct GNUNET_PeerIdentity' + * @param size number of bytes available in buf + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +send_try_connect (void *cls, size_t size, void *buf) +{ + struct GNUNET_PeerIdentity *pid = cls; + struct TransportRequestConnectMessage msg; + + if (buf == NULL) + { + GNUNET_free (pid); + return 0; + } +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting `%s' request with respect to `%4s'.\n", "REQUEST_CONNECT", + GNUNET_i2s (pid)); +#endif + GNUNET_assert (size >= sizeof (struct TransportRequestConnectMessage)); + msg.header.size = htons (sizeof (struct TransportRequestConnectMessage)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT); + msg.reserved = htonl (0); + msg.peer = *pid; + memcpy (buf, &msg, sizeof (msg)); + GNUNET_free (pid); + return sizeof (struct TransportRequestConnectMessage); +} + + +/** + * Ask the transport service to establish a connection to + * the given peer. + * + * @param handle connection to transport service + * @param target who we should try to connect to + */ +void +GNUNET_TRANSPORT_try_connect (struct GNUNET_TRANSPORT_Handle *handle, + const struct GNUNET_PeerIdentity *target) +{ + struct GNUNET_PeerIdentity *pid; + + if (NULL == handle->client) + return; + pid = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); + *pid = *target; + schedule_control_transmit (handle, + sizeof (struct TransportRequestConnectMessage), + &send_try_connect, pid); +} + + +/** + * Send HELLO message to the service. + * + * @param cls the HELLO message to send + * @param size number of bytes available in buf + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +send_hello (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg = cls; + uint16_t ssize; + + if (buf == NULL) + { +#if DEBUG_TRANSPORT_TIMEOUT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Timeout while trying to transmit `%s' request.\n", "HELLO"); +#endif + GNUNET_free (msg); + return 0; + } +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "HELLO"); +#endif + ssize = ntohs (msg->size); + GNUNET_assert (size >= ssize); + memcpy (buf, msg, ssize); + GNUNET_free (msg); + return ssize; +} + + +/** + * Offer the transport service the HELLO of another peer. Note that + * the transport service may just ignore this message if the HELLO is + * malformed or useless due to our local configuration. + * + * @param handle connection to transport service + * @param hello the hello message + * @param cont continuation to call when HELLO has been sent + * @param cls closure for continuation + * + */ +void +GNUNET_TRANSPORT_offer_hello (struct GNUNET_TRANSPORT_Handle *handle, + const struct GNUNET_MessageHeader *hello, + GNUNET_SCHEDULER_Task cont, void *cls) +{ + uint16_t size; + struct GNUNET_PeerIdentity peer; + struct GNUNET_MessageHeader *msg; + + if (NULL == handle->client) + return; + GNUNET_break (ntohs (hello->type) == GNUNET_MESSAGE_TYPE_HELLO); + size = ntohs (hello->size); + GNUNET_break (size >= sizeof (struct GNUNET_MessageHeader)); + if (GNUNET_OK != + GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hello, &peer)) + { + GNUNET_break (0); + return; + } + msg = GNUNET_malloc (size); + memcpy (msg, hello, size); +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Offering `%s' message of `%4s' to transport for validation.\n", "HELLO", + GNUNET_i2s (&peer)); +#endif + schedule_control_transmit (handle, size, &send_hello, msg); +} + + +/** + * Obtain the HELLO message for this peer. + * + * @param handle connection to transport service + * @param rec function to call with the HELLO, sender will be our peer + * identity; message and sender will be NULL on timeout + * (handshake with transport service pending/failed). + * cost estimate will be 0. + * @param rec_cls closure for rec + * @return handle to cancel the operation + */ +struct GNUNET_TRANSPORT_GetHelloHandle * +GNUNET_TRANSPORT_get_hello (struct GNUNET_TRANSPORT_Handle *handle, + GNUNET_TRANSPORT_HelloUpdateCallback rec, + void *rec_cls) +{ + struct GNUNET_TRANSPORT_GetHelloHandle *hwl; + + hwl = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_GetHelloHandle)); + hwl->rec = rec; + hwl->rec_cls = rec_cls; + hwl->handle = handle; + GNUNET_CONTAINER_DLL_insert (handle->hwl_head, handle->hwl_tail, hwl); + if (handle->my_hello != NULL) + rec (rec_cls, (const struct GNUNET_MessageHeader *) handle->my_hello); + return hwl; +} + + +/** + * Stop receiving updates about changes to our HELLO message. + * + * @param ghh handle to cancel + */ +void +GNUNET_TRANSPORT_get_hello_cancel (struct GNUNET_TRANSPORT_GetHelloHandle *ghh) +{ + struct GNUNET_TRANSPORT_Handle *handle = ghh->handle; + + GNUNET_CONTAINER_DLL_remove (handle->hwl_head, handle->hwl_tail, ghh); + GNUNET_free (ghh); +} + + +/** + * Connect to the transport service. Note that the connection may + * complete (or fail) asynchronously. + * + * @param cfg configuration to use + * @param self our own identity (API should check that it matches + * the identity found by transport), or NULL (no check) + * @param cls closure for the callbacks + * @param rec receive function to call + * @param nc function to call on connect events + * @param nd function to call on disconnect events + */ +struct GNUNET_TRANSPORT_Handle * +GNUNET_TRANSPORT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PeerIdentity *self, void *cls, + GNUNET_TRANSPORT_ReceiveCallback rec, + GNUNET_TRANSPORT_NotifyConnect nc, + GNUNET_TRANSPORT_NotifyDisconnect nd) +{ + struct GNUNET_TRANSPORT_Handle *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_Handle)); + if (self != NULL) + { + ret->self = *self; + ret->check_self = GNUNET_YES; + } + ret->cfg = cfg; + ret->cls = cls; + ret->rec = rec; + ret->nc_cb = nc; + ret->nd_cb = nd; + ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO; + ret->neighbours = + GNUNET_CONTAINER_multihashmap_create (STARTING_NEIGHBOURS_SIZE); + ret->ready_heap = + GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + ret->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, ret); + return ret; +} + + +/** + * Disconnect from the transport service. + * + * @param handle handle to the service as returned from GNUNET_TRANSPORT_connect + */ +void +GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle) +{ +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n"); +#endif + /* this disconnects all neighbours... */ + if (handle->reconnect_task == GNUNET_SCHEDULER_NO_TASK) + disconnect_and_schedule_reconnect (handle); + /* and now we stop trying to connect again... */ + if (handle->reconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (handle->reconnect_task); + handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_CONTAINER_multihashmap_destroy (handle->neighbours); + handle->neighbours = NULL; + if (handle->quota_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (handle->quota_task); + handle->quota_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free_non_null (handle->my_hello); + handle->my_hello = NULL; + GNUNET_assert (handle->hwl_head == NULL); + GNUNET_assert (handle->hwl_tail == NULL); + GNUNET_CONTAINER_heap_destroy (handle->ready_heap); + handle->ready_heap = NULL; + GNUNET_free (handle); +} + + +/** + * Check if we could queue a message of the given size for + * transmission. The transport service will take both its + * internal buffers and bandwidth limits imposed by the + * other peer into consideration when answering this query. + * + * @param handle connection to transport service + * @param target who should receive the message + * @param size how big is the message we want to transmit? + * @param priority how important is the message? + * @param timeout after how long should we give up (and call + * notify with buf NULL and size 0)? + * @param notify function to call when we are ready to + * send such a message + * @param notify_cls closure for notify + * @return NULL if someone else is already waiting to be notified + * non-NULL if the notify callback was queued (can be used to cancel + * using GNUNET_TRANSPORT_notify_transmit_ready_cancel) + */ +struct GNUNET_TRANSPORT_TransmitHandle * +GNUNET_TRANSPORT_notify_transmit_ready (struct GNUNET_TRANSPORT_Handle *handle, + const struct GNUNET_PeerIdentity + *target, size_t size, uint32_t priority, + struct GNUNET_TIME_Relative timeout, + GNUNET_CONNECTION_TransmitReadyNotify + notify, void *notify_cls) +{ + struct Neighbour *n; + struct GNUNET_TRANSPORT_TransmitHandle *th; + struct GNUNET_TIME_Relative delay; + + n = neighbour_find (handle, target); + if (NULL == n) + { + /* use GNUNET_TRANSPORT_try_connect first, only use this function + * once a connection has been established */ + GNUNET_assert (0); + return NULL; + } + if (NULL != n->th) + { + /* attempt to send two messages at the same time to the same peer */ + GNUNET_assert (0); + return NULL; + } + GNUNET_assert (NULL == n->hn); + th = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TransmitHandle)); + th->neighbour = n; + th->notify = notify; + th->notify_cls = notify_cls; + th->timeout = GNUNET_TIME_relative_to_absolute (timeout); + th->notify_size = size; + th->priority = priority; + n->th = th; + /* calculate when our transmission should be ready */ + delay = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, size); + if (delay.rel_value > timeout.rel_value) + delay.rel_value = 0; /* notify immediately (with failure) */ +#if DEBUG_TRANSPORT_API + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Bandwidth tracker allows next transmission to peer %s in %llu ms\n", + GNUNET_i2s (target), (unsigned long long) delay.rel_value); +#endif + n->hn = GNUNET_CONTAINER_heap_insert (handle->ready_heap, n, delay.rel_value); + schedule_transmission (handle); + return th; +} + + +/** + * Cancel the specified transmission-ready notification. + * + * @param th handle returned from GNUNET_TRANSPORT_notify_transmit_ready + */ +void +GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct + GNUNET_TRANSPORT_TransmitHandle + *th) +{ + struct Neighbour *n; + + GNUNET_assert (NULL == th->next); + GNUNET_assert (NULL == th->prev); + n = th->neighbour; + GNUNET_assert (th == n->th); + n->th = NULL; + if (n->hn != NULL) + { + GNUNET_CONTAINER_heap_remove_node (n->hn); + n->hn = NULL; + } + else + { + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != th->timeout_task); + GNUNET_SCHEDULER_cancel (th->timeout_task); + th->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (th); +} + + +/* end of transport_api.c */ diff --git a/src/transport/transport_api_address_lookup.c b/src/transport/transport_api_address_lookup.c new file mode 100644 index 0000000..6e03945 --- /dev/null +++ b/src/transport/transport_api_address_lookup.c @@ -0,0 +1,369 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/transport_api_address_lookup.c + * @brief given a peer id, get all known addresses from transport service + * + * This api provides the ability to query the transport service about + * the status of connections to a specific peer. Calls back with a + * pretty printed string of the address, as formatted by the appropriate + * transport plugin, and whether or not the address given is currently + * in the 'connected' state (according to the transport service). + */ + +#include "platform.h" +#include "gnunet_client_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" + +/** + * Context for the address lookup. + */ +struct GNUNET_TRANSPORT_PeerIterateContext +{ + /** + * Function to call with the binary address. + */ + GNUNET_TRANSPORT_PeerIterateCallback cb; + + /** + * Closure for cb. + */ + void *cb_cls; + + /** + * Connection to the service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Configuration we use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * When should this operation time out? + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Backoff for reconnect. + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Task ID for reconnect. + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * Identity of the peer to monitor. + */ + struct GNUNET_PeerIdentity peer; + + /** + * Was this a one-shot request? + */ + int one_shot; +}; + + +/** + * Function called with responses from the service. + * + * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*' + * @param msg NULL on timeout or error, otherwise presumably a + * message with the human-readable address + */ +static void +peer_address_response_processor (void *cls, + const struct GNUNET_MessageHeader *msg); + + +/** + * Send our subscription request to the service. + * + * @param pal_ctx our context + */ +static void +send_request (struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx) +{ + struct AddressIterateMessage msg; + + msg.header.size = htons (sizeof (struct AddressIterateMessage)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE); + msg.one_shot = htonl (pal_ctx->one_shot); + msg.timeout = GNUNET_TIME_absolute_hton (pal_ctx->timeout); + msg.peer = pal_ctx->peer; + GNUNET_assert (GNUNET_OK == + GNUNET_CLIENT_transmit_and_get_response (pal_ctx->client, + &msg.header, + GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout), + GNUNET_YES, + &peer_address_response_processor, + pal_ctx)); +} + +/** + * Task run to re-establish the connection. + * + * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*' + * @param tc scheduler context, unused + */ +static void +do_connect (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx = cls; + + pal_ctx->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + pal_ctx->client = GNUNET_CLIENT_connect ("transport", pal_ctx->cfg); + GNUNET_assert (NULL != pal_ctx->client); + send_request (pal_ctx); +} + + +/** + * Cut the existing connection and reconnect. + * + * @param pal_ctx our context + */ +static void +reconnect (struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx) +{ + GNUNET_assert (GNUNET_NO == pal_ctx->one_shot); + GNUNET_CLIENT_disconnect (pal_ctx->client, GNUNET_NO); + pal_ctx->client = NULL; + pal_ctx->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, + GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (pal_ctx->backoff, 2), + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30))); + pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff, + &do_connect, + pal_ctx); +} + + +/** + * Function called with responses from the service. + * + * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*' + * @param msg NULL on timeout or error, otherwise presumably a + * message with the human-readable address + */ +static void +peer_address_response_processor (void *cls, + const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx = cls; + struct AddressIterateResponseMessage *air_msg; + struct GNUNET_HELLO_Address *address; + const char *addr; + const char *transport_name; + uint16_t size; + size_t alen; + size_t tlen; + + if (msg == NULL) + { + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + size = ntohs (msg->size); + GNUNET_break (ntohs (msg->type) == + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); + if (size == sizeof (struct GNUNET_MessageHeader)) + { + /* done! */ + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + + if ((size < sizeof (struct AddressIterateResponseMessage)) || + (ntohs (msg->type) != + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE)) + { + GNUNET_break (0); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + + air_msg = (struct AddressIterateResponseMessage *) msg; + tlen = ntohl (air_msg->pluginlen); + alen = ntohl (air_msg->addrlen); + + if (size != sizeof (struct AddressIterateResponseMessage) + tlen + alen) + { + GNUNET_break (0); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + + if (alen == 0 && tlen == 0) + { + pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, NULL); + } + else + { + addr = (const char *) &air_msg[1]; + transport_name = &addr[alen]; + + if (transport_name[tlen - 1] != '\0') + { + GNUNET_break (0); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + + /* notify client */ + address = + GNUNET_HELLO_address_allocate (&air_msg->peer, transport_name, addr, + alen); + pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, address); + GNUNET_HELLO_address_free (address); + } + + /* expect more replies */ + GNUNET_CLIENT_receive (pal_ctx->client, &peer_address_response_processor, + pal_ctx, + GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout)); +} + + +/** + * Return all the known addresses for a specific peer or all peers. + * Returns continously all address if one_shot is set to GNUNET_NO + * + * CHANGE: Returns the address(es) that we are currently using for this + * peer. Upon completion, the 'AddressLookUpCallback' is called one more + * time with 'NULL' for the address and the peer. After this, the operation must no + * longer be explicitly cancelled. + * + * @param cfg configuration to use + * @param peer peer identity to look up the addresses of, CHANGE: allow NULL for all (connected) peers + * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL), + * GNUNET_NO to monitor the set of addresses used (continuously, must be explicitly cancelled) + * @param timeout how long is the lookup allowed to take at most (irrelevant if one_shot is set to GNUNET_NO) + * @param peer_address_callback function to call with the results + * @param peer_address_callback_cls closure for peer_address_callback + */ +struct GNUNET_TRANSPORT_PeerIterateContext * +GNUNET_TRANSPORT_peer_get_active_addresses (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PeerIdentity + *peer, int one_shot, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_PeerIterateCallback + peer_address_callback, + void *peer_address_callback_cls) +{ + struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx; + struct GNUNET_CLIENT_Connection *client; + + client = GNUNET_CLIENT_connect ("transport", cfg); + if (client == NULL) + return NULL; + if (GNUNET_YES != one_shot) + timeout = GNUNET_TIME_UNIT_FOREVER_REL; + pal_ctx = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PeerIterateContext)); + pal_ctx->cb = peer_address_callback; + pal_ctx->cb_cls = peer_address_callback_cls; + pal_ctx->cfg = cfg; + pal_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); + if (NULL != peer) + pal_ctx->peer = *peer; + pal_ctx->one_shot = one_shot; + pal_ctx->client = client; + send_request (pal_ctx); + + return pal_ctx; +} + + +/** + * Cancel request for address conversion. + * + * @param alc handle for the request to cancel + */ +void +GNUNET_TRANSPORT_peer_get_active_addresses_cancel (struct + GNUNET_TRANSPORT_PeerIterateContext + *alc) +{ + if (NULL != alc->client) + { + GNUNET_CLIENT_disconnect (alc->client, GNUNET_NO); + alc->client = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != alc->reconnect_task) + { + GNUNET_SCHEDULER_cancel (alc->reconnect_task); + alc->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (alc); +} + + +/* end of transport_api_peer_address_lookup.c */ diff --git a/src/transport/transport_api_address_to_string.c b/src/transport/transport_api_address_to_string.c new file mode 100644 index 0000000..4d80953 --- /dev/null +++ b/src/transport/transport_api_address_to_string.c @@ -0,0 +1,192 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#include "platform.h" +#include "gnunet_client_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" + +/** + * Context for the address lookup. + */ +struct GNUNET_TRANSPORT_AddressToStringContext +{ + /** + * Function to call with the human-readable address. + */ + GNUNET_TRANSPORT_AddressToStringCallback cb; + + /** + * Closure for cb. + */ + void *cb_cls; + + /** + * Connection to the service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * When should this operation time out? + */ + struct GNUNET_TIME_Absolute timeout; +}; + + +/** + * Function called with responses from the service. + * + * @param cls our 'struct GNUNET_TRANSPORT_AddressLookupContext*' + * @param msg NULL on timeout or error, otherwise presumably a + * message with the human-readable address + */ +static void +address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls; + const char *address; + uint16_t size; + + if (msg == NULL) + { + alucb->cb (alucb->cb_cls, NULL); + GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); + GNUNET_free (alucb); + return; + } + GNUNET_break (ntohs (msg->type) == + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); + size = ntohs (msg->size); + if (size == sizeof (struct GNUNET_MessageHeader)) + { + /* done! */ + alucb->cb (alucb->cb_cls, NULL); + GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); + GNUNET_free (alucb); + return; + } + address = (const char *) &msg[1]; + if (address[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0') + { + /* invalid reply */ + GNUNET_break (0); + alucb->cb (alucb->cb_cls, NULL); + GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO); + GNUNET_free (alucb); + return; + } + /* expect more replies */ + GNUNET_CLIENT_receive (alucb->client, &address_response_processor, alucb, + GNUNET_TIME_absolute_get_remaining (alucb->timeout)); + alucb->cb (alucb->cb_cls, address); +} + + +/** + * Convert a binary address into a human readable address. + * + * @param cfg configuration to use + * @param address address to convert (binary format) + * @param numeric should (IP) addresses be displayed in numeric form + * (otherwise do reverse DNS lookup) + * @param timeout how long is the lookup allowed to take at most + * @param aluc function to call with the results + * @param aluc_cls closure for aluc + * @return handle to cancel the operation, NULL on error + */ +struct GNUNET_TRANSPORT_AddressToStringContext * +GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle + *cfg, + const struct GNUNET_HELLO_Address *address, + int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressToStringCallback + aluc, void *aluc_cls) +{ + size_t len; + size_t alen; + size_t slen; + struct AddressLookupMessage *msg; + struct GNUNET_TRANSPORT_AddressToStringContext *alc; + struct GNUNET_CLIENT_Connection *client; + char *addrbuf; + + GNUNET_assert (address != NULL); + alen = address->address_length; + slen = strlen (address->transport_name) + 1; + len = sizeof (struct AddressLookupMessage) + alen + slen; + if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return NULL; + } + + client = GNUNET_CLIENT_connect ("transport", cfg); + if (client == NULL) + return NULL; +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_TRANSPORT_address_to_string\n"); +#endif + msg = GNUNET_malloc (len); + msg->header.size = htons (len); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING); + msg->numeric_only = htons ((int16_t) numeric); + msg->addrlen = htons ((uint16_t) alen); + msg->timeout = GNUNET_TIME_relative_hton (timeout); + addrbuf = (char *) &msg[1]; + memcpy (addrbuf, address->address, alen); + memcpy (&addrbuf[alen], address->transport_name, slen); + + alc = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_AddressToStringContext)); + alc->cb = aluc; + alc->cb_cls = aluc_cls; + alc->timeout = GNUNET_TIME_relative_to_absolute (timeout); + alc->client = client; + GNUNET_assert (GNUNET_OK == + GNUNET_CLIENT_transmit_and_get_response (client, &msg->header, + timeout, GNUNET_YES, + &address_response_processor, + alc)); + GNUNET_free (msg); + return alc; +} + + +/** + * Cancel request for address conversion. + * + * @param alc handle for the request to cancel + */ +void +GNUNET_TRANSPORT_address_to_string_cancel (struct + GNUNET_TRANSPORT_AddressToStringContext + *alc) +{ + GNUNET_CLIENT_disconnect (alc->client, GNUNET_NO); + GNUNET_free (alc); +} + + + +/* end of transport_api_address_to_string.c */ diff --git a/src/transport/transport_api_blacklist.c b/src/transport/transport_api_blacklist.c new file mode 100644 index 0000000..be52623 --- /dev/null +++ b/src/transport/transport_api_blacklist.c @@ -0,0 +1,296 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/transport_api_blacklist.c + * @brief library to access the blacklisting functions of the transport service + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_client_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_transport_service.h" +#include "transport.h" + +/** + * Handle for blacklisting requests. + */ +struct GNUNET_TRANSPORT_Blacklist +{ + + /** + * Connection to transport service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Pending handle for the current request. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Function to call for determining if a peer is allowed + * to communicate with us. + */ + GNUNET_TRANSPORT_BlacklistCallback cb; + + /** + * Closure for 'cb'. + */ + void *cb_cls; + + /** + * Peer currently under consideration. + */ + struct GNUNET_PeerIdentity peer; + +}; + + +/** + * Establish blacklist connection to transport service. + * + * @param br overall handle + */ +static void +reconnect (struct GNUNET_TRANSPORT_Blacklist *br); + + +/** + * Send our reply to a blacklisting request. + * + * @param br our overall context + */ +static void +reply (struct GNUNET_TRANSPORT_Blacklist *br); + + +/** + * Handle blacklist queries. + * + * @param cls our overall handle + * @param msg query + */ +static void +query_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_TRANSPORT_Blacklist *br = cls; + const struct BlacklistMessage *bm; + + GNUNET_assert (br != NULL); + if ((NULL == msg) || + (ntohs (msg->size) != sizeof (struct BlacklistMessage)) || + (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY)) + { + reconnect (br); + return; + } + bm = (const struct BlacklistMessage *) msg; + GNUNET_break (0 == ntohl (bm->is_allowed)); + br->peer = bm->peer; + reply (br); +} + + +/** + * Receive blacklist queries from transport service. + * + * @param br overall handle + */ +static void +receive (struct GNUNET_TRANSPORT_Blacklist *br) +{ + GNUNET_CLIENT_receive (br->client, &query_handler, br, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Transmit the blacklist initialization request to the service. + * + * @param cls closure (struct GNUNET_TRANSPORT_Blacklist*) + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_blacklist_init (void *cls, size_t size, void *buf) +{ + struct GNUNET_TRANSPORT_Blacklist *br = cls; + struct GNUNET_MessageHeader req; + + br->th = NULL; + if (buf == NULL) + { + reconnect (br); + return 0; + } + req.size = htons (sizeof (struct GNUNET_MessageHeader)); + req.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT); + memcpy (buf, &req, sizeof (req)); + receive (br); + return sizeof (req); +} + + +/** + * Establish blacklist connection to transport service. + * + * @param br overall handle + */ +static void +reconnect (struct GNUNET_TRANSPORT_Blacklist *br) +{ + if (br->client != NULL) + GNUNET_CLIENT_disconnect (br->client, GNUNET_NO); + br->client = GNUNET_CLIENT_connect ("transport", br->cfg); + GNUNET_assert (br->client != NULL); + br->th = + GNUNET_CLIENT_notify_transmit_ready (br->client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &transmit_blacklist_init, + br); +} + + +/** + * Transmit the blacklist response to the service. + * + * @param cls closure (struct GNUNET_TRANSPORT_Blacklist*) + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_blacklist_reply (void *cls, size_t size, void *buf) +{ + struct GNUNET_TRANSPORT_Blacklist *br = cls; + struct BlacklistMessage req; + + br->th = NULL; + if (buf == NULL) + { + reconnect (br); + return 0; + } + req.header.size = htons (sizeof (req)); + req.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY); + req.is_allowed = htonl (br->cb (br->cb_cls, &br->peer)); + req.peer = br->peer; + memcpy (buf, &req, sizeof (req)); + br->th = NULL; + receive (br); + return sizeof (req); +} + + +/** + * Send our reply to a blacklisting request. + * + * @param br our overall context + */ +static void +reply (struct GNUNET_TRANSPORT_Blacklist *br) +{ + GNUNET_assert (br->th == NULL); + br->th = + GNUNET_CLIENT_notify_transmit_ready (br->client, + sizeof (struct BlacklistMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, &transmit_blacklist_reply, + br); + if (br->th == NULL) + { + reconnect (br); + return; + } +} + + +/** + * Install a blacklist callback. The service will be queried for all + * existing connections as well as any fresh connections to check if + * they are permitted. If the blacklisting callback is unregistered, + * all hosts that were denied in the past will automatically be + * whitelisted again. Cancelling the blacklist handle is also the + * only way to re-enable connections from peers that were previously + * blacklisted. + * + * @param cfg configuration to use + * @param cb callback to invoke to check if connections are allowed + * @param cb_cls closure for cb + * @return NULL on error, otherwise handle for cancellation + */ +struct GNUNET_TRANSPORT_Blacklist * +GNUNET_TRANSPORT_blacklist (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_TRANSPORT_BlacklistCallback cb, void *cb_cls) +{ + struct GNUNET_CLIENT_Connection *client; + struct GNUNET_TRANSPORT_Blacklist *ret; + + client = GNUNET_CLIENT_connect ("transport", cfg); + if (NULL == client) + return NULL; + ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_Blacklist)); + ret->client = client; + ret->cfg = cfg; + ret->cb = cb; + ret->cb_cls = cb_cls; + GNUNET_assert (ret->th == NULL); + ret->th = + GNUNET_CLIENT_notify_transmit_ready (client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &transmit_blacklist_init, + ret); + return ret; +} + + +/** + * Abort the blacklist. Note that this function is the only way for + * removing a peer from the blacklist. + * + * @param br handle of the request that is to be cancelled + */ +void +GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_Blacklist *br) +{ + if (br->th != NULL) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (br->th); + br->th = NULL; + } + GNUNET_CLIENT_disconnect (br->client, GNUNET_NO); + GNUNET_free (br); +} + + +/* end of transport_api_blacklist.c */ diff --git a/src/tun/Makefile.am b/src/tun/Makefile.am new file mode 100644 index 0000000..390ce9e --- /dev/null +++ b/src/tun/Makefile.am @@ -0,0 +1,35 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +lib_LTLIBRARIES = libgnunettun.la + +libgnunettun_la_SOURCES = \ + tun.c +libgnunettun_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +libgnunettun_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + + +check_PROGRAMS = \ + test_tun + + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_tun_SOURCES = \ + test_tun.c +test_tun_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/tun/libgnunettun.la diff --git a/src/tun/Makefile.in b/src/tun/Makefile.in new file mode 100644 index 0000000..3d0f165 --- /dev/null +++ b/src/tun/Makefile.in @@ -0,0 +1,778 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +check_PROGRAMS = test_tun$(EXEEXT) +subdir = src/tun +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgnunettun_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_libgnunettun_la_OBJECTS = tun.lo +libgnunettun_la_OBJECTS = $(am_libgnunettun_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunettun_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunettun_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +am_test_tun_OBJECTS = test_tun.$(OBJEXT) +test_tun_OBJECTS = $(am_test_tun_OBJECTS) +test_tun_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/tun/libgnunettun.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunettun_la_SOURCES) $(test_tun_SOURCES) +DIST_SOURCES = $(libgnunettun_la_SOURCES) $(test_tun_SOURCES) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +lib_LTLIBRARIES = libgnunettun.la +libgnunettun_la_SOURCES = \ + tun.c + +libgnunettun_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) + +libgnunettun_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:0:0 + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_tun_SOURCES = \ + test_tun.c + +test_tun_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/tun/libgnunettun.la + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tun/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/tun/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunettun.la: $(libgnunettun_la_OBJECTS) $(libgnunettun_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunettun_la_LINK) -rpath $(libdir) $(libgnunettun_la_OBJECTS) $(libgnunettun_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +test_tun$(EXEEXT): $(test_tun_OBJECTS) $(test_tun_DEPENDENCIES) + @rm -f test_tun$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_tun_OBJECTS) $(test_tun_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_tun.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tun.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-libLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/tun/test_tun.c b/src/tun/test_tun.c new file mode 100644 index 0000000..3539fd1 --- /dev/null +++ b/src/tun/test_tun.c @@ -0,0 +1,74 @@ +/* + This file is part of GNUnet. + (C) 2010, 2011, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file tun/test_tun.c + * @brief test for tun.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_tun_lib.h" + +static int ret; + +static void +test_udp (size_t pll, + int pl_fill, + uint16_t crc) +{ + struct GNUNET_TUN_IPv4Header ip; + struct GNUNET_TUN_UdpHeader udp; + char payload[pll]; + struct in_addr src; + struct in_addr dst; + + GNUNET_assert (1 == inet_pton (AF_INET, "1.2.3.4", &src)); + GNUNET_assert (1 == inet_pton (AF_INET, "122.2.3.5", &dst)); + memset (payload, pl_fill, sizeof (payload)); + GNUNET_TUN_initialize_ipv4_header (&ip, + IPPROTO_UDP, + pll + sizeof (udp), + &src, + &dst); + udp.source_port = htons (4242); + udp.destination_port = htons (4242); + udp.len = htons (pll); + GNUNET_TUN_calculate_udp4_checksum (&ip, + &udp, + payload, + pll); + if (crc != ntohs (udp.crc)) + { + fprintf (stderr, "Got CRC: %u, wanted: %u\n", + ntohs (udp.crc), + crc); + ret = 1; + } +} + +int main (int argc, + char **argv) +{ + test_udp (4, 3, 22439); + test_udp (4, 1, 23467); + test_udp (7, 17, 6516); + test_udp (12451, 251, 42771); + return ret; +} diff --git a/src/tun/tun.c b/src/tun/tun.c new file mode 100644 index 0000000..3b0e9b9 --- /dev/null +++ b/src/tun/tun.c @@ -0,0 +1,271 @@ +/* + This file is part of GNUnet. + (C) 2010, 2011, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file tun/tun.c + * @brief standard IP calculations for TUN interaction + * @author Philipp Toelke + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_tun_lib.h" + +/** + * IP TTL we use for packets that we assemble (8 bit unsigned integer) + */ +#define FRESH_TTL 64 + + +/** + * Initialize an IPv4 header. + * + * @param ip header to initialize + * @param protocol protocol to use (i.e. IPPROTO_UDP) + * @param payload_length number of bytes of payload that follow (excluding IPv4 header) + * @param src source IP address to use + * @param dst destination IP address to use + */ +void +GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip, + uint8_t protocol, + uint16_t payload_length, + const struct in_addr *src, + const struct in_addr *dst) +{ + GNUNET_assert (20 == sizeof (struct GNUNET_TUN_IPv4Header)); + GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv4Header)); + memset (ip, 0, sizeof (struct GNUNET_TUN_IPv4Header)); + ip->header_length = sizeof (struct GNUNET_TUN_IPv4Header) / 4; + ip->version = 4; + ip->total_length = htons (sizeof (struct GNUNET_TUN_IPv4Header) + payload_length); + ip->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + 65536); + ip->ttl = FRESH_TTL; + ip->protocol = protocol; + ip->source_address = *src; + ip->destination_address = *dst; + ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header)); +} + + +/** + * Initialize an IPv6 header. + * + * @param ip header to initialize + * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6 + * @param payload_length number of bytes of payload that follow (excluding IPv4 header) + * @param src source IP address to use + * @param dst destination IP address to use + */ +void +GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip, + uint8_t protocol, + uint16_t payload_length, + const struct in6_addr *src, + const struct in6_addr *dst) +{ + GNUNET_assert (40 == sizeof (struct GNUNET_TUN_IPv6Header)); + GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv6Header)); + memset (ip, 0, sizeof (struct GNUNET_TUN_IPv6Header)); + ip->version = 6; + ip->next_header = protocol; + ip->payload_length = htons ((uint16_t) payload_length); + ip->hop_limit = FRESH_TTL; + ip->destination_address = *dst; + ip->source_address = *src; +} + + +/** + * Calculate IPv4 TCP checksum. + * + * @param ip ipv4 header fully initialized + * @param tcp TCP header (initialized except for CRC) + * @param payload the TCP payload + * @param payload_length number of bytes of TCP payload + */ +void +GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, + struct GNUNET_TUN_TcpHeader *tcp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint16_t tmp; + + GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader)); + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) == + ntohs (ip->total_length)); + GNUNET_assert (IPPROTO_TCP == ip->protocol); + + tcp->crc = 0; + sum = GNUNET_CRYPTO_crc16_step (0, + &ip->source_address, + sizeof (struct in_addr) * 2); + tmp = htons (IPPROTO_TCP); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t)); + tmp = htons (payload_length + sizeof (struct GNUNET_TUN_TcpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); + tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/** + * Calculate IPv6 TCP checksum. + * + * @param ip ipv6 header fully initialized + * @param tcp header (initialized except for CRC) + * @param payload the TCP payload + * @param payload_length number of bytes of TCP payload + */ +void +GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, + struct GNUNET_TUN_TcpHeader *tcp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint32_t tmp; + + GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader)); + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) == + ntohs (ip->payload_length)); + GNUNET_assert (IPPROTO_TCP == ip->next_header); + tcp->crc = 0; + sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr)); + tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + tmp = htonl (IPPROTO_TCP); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, tcp, + sizeof (struct GNUNET_TUN_TcpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); + tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/** + * Calculate IPv4 UDP checksum. + * + * @param ip ipv4 header fully initialized + * @param udp UDP header (initialized except for CRC) + * @param payload the UDP payload + * @param payload_length number of bytes of UDP payload + */ +void +GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, + struct GNUNET_TUN_UdpHeader *udp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint16_t tmp; + + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) == + ntohs (ip->total_length)); + GNUNET_assert (IPPROTO_UDP == ip->protocol); + + udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */ + sum = GNUNET_CRYPTO_crc16_step (0, + &ip->source_address, + sizeof (struct in_addr) * 2); + tmp = htons (IPPROTO_UDP); + sum = GNUNET_CRYPTO_crc16_step (sum, + &tmp, + sizeof (uint16_t)); + tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); + sum = GNUNET_CRYPTO_crc16_step (sum, + &tmp, + sizeof (uint16_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, + udp, + sizeof (struct GNUNET_TUN_UdpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, + payload, + payload_length); + udp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/** + * Calculate IPv6 UDP checksum. + * + * @param ip ipv6 header fully initialized + * @param udp UDP header (initialized except for CRC) + * @param payload the UDP payload + * @param payload_length number of bytes of UDP payload + */ +void +GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, + struct GNUNET_TUN_UdpHeader *udp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint32_t tmp; + + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) == + ntohs (ip->payload_length)); + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) == + ntohs (udp->len)); + GNUNET_assert (IPPROTO_UDP == ip->next_header); + + udp->crc = 0; + sum = GNUNET_CRYPTO_crc16_step (0, + &ip->source_address, + sizeof (struct in6_addr) * 2); + tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); /* aka udp->len */ + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + tmp = htons (ip->next_header); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); + udp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/** + * Calculate ICMP checksum. + * + * @param icmp IMCP header (initialized except for CRC) + * @param payload the ICMP payload + * @param payload_length number of bytes of ICMP payload + */ +void +GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_IcmpHeader)); + icmp->crc = 0; + sum = GNUNET_CRYPTO_crc16_step (0, + icmp, + sizeof (struct GNUNET_TUN_IcmpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); + icmp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/* end of tun.c */ diff --git a/src/util/Makefile.am b/src/util/Makefile.am new file mode 100644 index 0000000..cded34d --- /dev/null +++ b/src/util/Makefile.am @@ -0,0 +1,440 @@ +INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include + +plugindir = $(libdir)/gnunet + +pkgcfgdir= $(pkgdatadir)/config.d/ + +dist_pkgcfg_DATA = \ + util.conf + +pkgcfg_DATA = \ + resolver.conf + +if MINGW +noinst_LTLIBRARIES = \ + libgnunetutilwin.la +libgnunetutilwin_la_SOURCES = \ + win.cc \ + winproc.c +libgnunetutilwin_la_LDFLAGS = \ + -no-undefined -Wl,--export-all-symbols +libgnunetutilwin_la_LIBADD = \ + -lshell32 -liconv -lstdc++ \ + -lcomdlg32 -lgdi32 -liphlpapi +WINLIB = libgnunetutilwin.la +endif + +if !MINGW + SERVER_CLIENT_UNIX = test_server_with_client_unix +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +noinst_PROGRAMS = \ + gnunet-config-diff \ + test_common_logging_dummy + +gnunet_config_diff_SOURCES = \ + gnunet-config-diff.c +gnunet_config_diff_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la +gnunet_config_diff_DEPENDENCIES = \ + libgnunetutil.la + +test_common_logging_dummy_SOURCES = \ + test_common_logging_dummy.c +test_common_logging_dummy_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la +test_common_logging_dummy_DEPENDENCIES = \ + libgnunetutil.la + +lib_LTLIBRARIES = libgnunetutil.la + +libgnunetutil_la_SOURCES = \ + bandwidth.c \ + bio.c \ + client.c \ + common_allocation.c \ + common_endian.c \ + common_logging.c \ + configuration.c \ + connection.c \ + container_bloomfilter.c \ + container_heap.c \ + container_meta_data.c \ + container_multihashmap.c \ + container_slist.c \ + crypto_aes.c \ + crypto_crc.c \ + crypto_hash.c \ + crypto_hkdf.c \ + crypto_kdf.c \ + crypto_ksk.c \ + crypto_random.c \ + crypto_rsa.c \ + disk.c \ + disk.h \ + getopt.c \ + getopt_helpers.c \ + helper.c \ + load.c \ + network.c \ + os_installation.c \ + os_network.c \ + os_priority.c \ + peer.c \ + plugin.c \ + program.c \ + pseudonym.c \ + resolver_api.c resolver.h \ + scheduler.c \ + server.c \ + server_mst.c \ + server_nc.c \ + server_tc.c \ + service.c \ + signal.c \ + strings.c \ + time.c + + +libgnunetutil_la_LIBADD = \ + $(GCLIBADD) $(WINLIB) \ + $(LIBGCRYPT_LIBS) \ + $(LTLIBICONV) \ + -lltdl -lz $(XLIB) + +libgnunetutil_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 7:0:0 + + +bin_PROGRAMS = \ + gnunet-service-resolver \ + gnunet-resolver + +gnunet_service_resolver_SOURCES = \ + gnunet-service-resolver.c +gnunet_service_resolver_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_service_resolver_DEPENDENCIES = \ + libgnunetutil.la + + +gnunet_resolver_SOURCES = \ + gnunet-resolver.c +gnunet_resolver_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_resolver_DEPENDENCIES = \ + libgnunetutil.la + +plugin_LTLIBRARIES = \ + libgnunet_plugin_test.la + +libgnunet_plugin_test_la_SOURCES = \ + test_plugin_plug.c +libgnunet_plugin_test_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +if HAVE_BENCHMARKS + BENCHMARKS = \ + perf_crypto_hash +endif + +check_PROGRAMS = \ + test_bio \ + test_client \ + test_common_allocation \ + test_common_endian \ + test_common_logging \ + test_configuration \ + test_container_bloomfilter \ + test_container_meta_data \ + test_container_multihashmap \ + test_container_heap \ + test_container_slist \ + test_crypto_aes \ + test_crypto_aes_weak \ + test_crypto_crc \ + test_crypto_hash \ + test_crypto_hkdf \ + test_crypto_ksk \ + test_crypto_random \ + test_crypto_rsa \ + test_disk \ + test_getopt \ + test_connection \ + test_connection_addressing \ + test_connection_receive_cancel \ + test_connection_timeout \ + test_connection_timeout_no_connect \ + test_connection_transmit_cancel \ + test_os_network \ + test_os_priority \ + test_peer \ + test_plugin \ + test_program \ + test_pseudonym \ + test_resolver_api \ + test_scheduler \ + test_scheduler_delay \ + test_server \ + test_server_disconnect \ + test_server_with_client \ + $(SERVER_CLIENT_UNIX) \ + test_service \ + test_strings \ + test_time \ + $(BENCHMARKS) \ + test_os_start_process \ + test_common_logging_runtime_loglevels + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +test_bio_SOURCES = \ + test_bio.c +test_bio_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + + +test_os_start_process_SOURCES = \ + test_os_start_process.c +test_os_start_process_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_client_SOURCES = \ + test_client.c +test_client_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_common_allocation_SOURCES = \ + test_common_allocation.c +test_common_allocation_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_common_endian_SOURCES = \ + test_common_endian.c +test_common_endian_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_common_logging_SOURCES = \ + test_common_logging.c +test_common_logging_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_common_logging_runtime_loglevels_SOURCES = \ + test_common_logging_runtime_loglevels.c +test_common_logging_runtime_loglevels_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_configuration_SOURCES = \ + test_configuration.c +test_configuration_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_container_bloomfilter_SOURCES = \ + test_container_bloomfilter.c +test_container_bloomfilter_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_container_meta_data_SOURCES = \ + test_container_meta_data.c +test_container_meta_data_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la -lextractor + +test_container_multihashmap_SOURCES = \ + test_container_multihashmap.c +test_container_multihashmap_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_container_heap_SOURCES = \ + test_container_heap.c +test_container_heap_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_container_slist_SOURCES = \ + test_container_slist.c +test_container_slist_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_aes_SOURCES = \ + test_crypto_aes.c +test_crypto_aes_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_aes_weak_SOURCES = \ + test_crypto_aes_weak.c +test_crypto_aes_weak_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(LIBGCRYPT_LIBS) + +test_crypto_crc_SOURCES = \ + test_crypto_crc.c +test_crypto_crc_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_hash_SOURCES = \ + test_crypto_hash.c +test_crypto_hash_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_hkdf_SOURCES = \ + test_crypto_hkdf.c +test_crypto_hkdf_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_ksk_SOURCES = \ + test_crypto_ksk.c +test_crypto_ksk_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_random_SOURCES = \ + test_crypto_random.c +test_crypto_random_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_rsa_SOURCES = \ + test_crypto_rsa.c +test_crypto_rsa_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_disk_SOURCES = \ + test_disk.c +test_disk_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_getopt_SOURCES = \ + test_getopt.c +test_getopt_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_SOURCES = \ + test_connection.c +test_connection_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_addressing_SOURCES = \ + test_connection_addressing.c +test_connection_addressing_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_receive_cancel_SOURCES = \ + test_connection_receive_cancel.c +test_connection_receive_cancel_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_timeout_SOURCES = \ + test_connection_timeout.c +test_connection_timeout_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_timeout_no_connect_SOURCES = \ + test_connection_timeout_no_connect.c +test_connection_timeout_no_connect_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_transmit_cancel_SOURCES = \ + test_connection_transmit_cancel.c +test_connection_transmit_cancel_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_os_network_SOURCES = \ + test_os_network.c +test_os_network_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_os_priority_SOURCES = \ + test_os_priority.c +test_os_priority_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_peer_SOURCES = \ + test_peer.c +test_peer_LDADD = \ +$(top_builddir)/src/util/libgnunetutil.la + +test_plugin_SOURCES = \ + test_plugin.c +test_plugin_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_program_SOURCES = \ + test_program.c +test_program_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_pseudonym_SOURCES = \ + test_pseudonym.c +test_pseudonym_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_resolver_api_SOURCES = \ + test_resolver_api.c +test_resolver_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_scheduler_SOURCES = \ + test_scheduler.c +test_scheduler_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_scheduler_delay_SOURCES = \ + test_scheduler_delay.c +test_scheduler_delay_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_server_SOURCES = \ + test_server.c +test_server_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_server_disconnect_SOURCES = \ + test_server_disconnect.c +test_server_disconnect_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_server_with_client_SOURCES = \ + test_server_with_client.c +test_server_with_client_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_server_with_client_unix_SOURCES = \ + test_server_with_client_unix.c +test_server_with_client_unix_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + + +test_service_SOURCES = \ + test_service.c +test_service_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_strings_SOURCES = \ + test_strings.c +test_strings_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_time_SOURCES = \ + test_time.c +test_time_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_crypto_hash_SOURCES = \ + perf_crypto_hash.c +perf_crypto_hash_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + + +EXTRA_DIST = \ + test_configuration_data.conf \ + test_program_data.conf \ + test_pseudonym_data.conf \ + test_resolver_api_data.conf \ + test_service_data.conf diff --git a/src/util/Makefile.in b/src/util/Makefile.in new file mode 100644 index 0000000..3c82fbf --- /dev/null +++ b/src/util/Makefile.in @@ -0,0 +1,1945 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +noinst_PROGRAMS = gnunet-config-diff$(EXEEXT) \ + test_common_logging_dummy$(EXEEXT) +bin_PROGRAMS = gnunet-service-resolver$(EXEEXT) \ + gnunet-resolver$(EXEEXT) +check_PROGRAMS = test_bio$(EXEEXT) test_client$(EXEEXT) \ + test_common_allocation$(EXEEXT) test_common_endian$(EXEEXT) \ + test_common_logging$(EXEEXT) test_configuration$(EXEEXT) \ + test_container_bloomfilter$(EXEEXT) \ + test_container_meta_data$(EXEEXT) \ + test_container_multihashmap$(EXEEXT) \ + test_container_heap$(EXEEXT) test_container_slist$(EXEEXT) \ + test_crypto_aes$(EXEEXT) test_crypto_aes_weak$(EXEEXT) \ + test_crypto_crc$(EXEEXT) test_crypto_hash$(EXEEXT) \ + test_crypto_hkdf$(EXEEXT) test_crypto_ksk$(EXEEXT) \ + test_crypto_random$(EXEEXT) test_crypto_rsa$(EXEEXT) \ + test_disk$(EXEEXT) test_getopt$(EXEEXT) \ + test_connection$(EXEEXT) test_connection_addressing$(EXEEXT) \ + test_connection_receive_cancel$(EXEEXT) \ + test_connection_timeout$(EXEEXT) \ + test_connection_timeout_no_connect$(EXEEXT) \ + test_connection_transmit_cancel$(EXEEXT) \ + test_os_network$(EXEEXT) test_os_priority$(EXEEXT) \ + test_peer$(EXEEXT) test_plugin$(EXEEXT) test_program$(EXEEXT) \ + test_pseudonym$(EXEEXT) test_resolver_api$(EXEEXT) \ + test_scheduler$(EXEEXT) test_scheduler_delay$(EXEEXT) \ + test_server$(EXEEXT) test_server_disconnect$(EXEEXT) \ + test_server_with_client$(EXEEXT) $(am__EXEEXT_1) \ + test_service$(EXEEXT) test_strings$(EXEEXT) test_time$(EXEEXT) \ + $(am__EXEEXT_2) test_os_start_process$(EXEEXT) \ + test_common_logging_runtime_loglevels$(EXEEXT) +subdir = src/util +DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/resolver.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = resolver.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) \ + $(plugin_LTLIBRARIES) +libgnunet_plugin_test_la_LIBADD = +am_libgnunet_plugin_test_la_OBJECTS = test_plugin_plug.lo +libgnunet_plugin_test_la_OBJECTS = \ + $(am_libgnunet_plugin_test_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunet_plugin_test_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunet_plugin_test_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__DEPENDENCIES_1 = +libgnunetutil_la_DEPENDENCIES = $(WINLIB) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgnunetutil_la_OBJECTS = bandwidth.lo bio.lo client.lo \ + common_allocation.lo common_endian.lo common_logging.lo \ + configuration.lo connection.lo container_bloomfilter.lo \ + container_heap.lo container_meta_data.lo \ + container_multihashmap.lo container_slist.lo crypto_aes.lo \ + crypto_crc.lo crypto_hash.lo crypto_hkdf.lo crypto_kdf.lo \ + crypto_ksk.lo crypto_random.lo crypto_rsa.lo disk.lo getopt.lo \ + getopt_helpers.lo helper.lo load.lo network.lo \ + os_installation.lo os_network.lo os_priority.lo peer.lo \ + plugin.lo program.lo pseudonym.lo resolver_api.lo scheduler.lo \ + server.lo server_mst.lo server_nc.lo server_tc.lo service.lo \ + signal.lo strings.lo time.lo +libgnunetutil_la_OBJECTS = $(am_libgnunetutil_la_OBJECTS) +libgnunetutil_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetutil_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +libgnunetutilwin_la_DEPENDENCIES = +am__libgnunetutilwin_la_SOURCES_DIST = win.cc winproc.c +@MINGW_TRUE@am_libgnunetutilwin_la_OBJECTS = win.lo winproc.lo +libgnunetutilwin_la_OBJECTS = $(am_libgnunetutilwin_la_OBJECTS) +libgnunetutilwin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(libgnunetutilwin_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MINGW_TRUE@am_libgnunetutilwin_la_rpath = +@MINGW_FALSE@am__EXEEXT_1 = test_server_with_client_unix$(EXEEXT) +@HAVE_BENCHMARKS_TRUE@am__EXEEXT_2 = perf_crypto_hash$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am_gnunet_config_diff_OBJECTS = gnunet-config-diff.$(OBJEXT) +gnunet_config_diff_OBJECTS = $(am_gnunet_config_diff_OBJECTS) +am_gnunet_resolver_OBJECTS = gnunet-resolver.$(OBJEXT) +gnunet_resolver_OBJECTS = $(am_gnunet_resolver_OBJECTS) +am_gnunet_service_resolver_OBJECTS = \ + gnunet-service-resolver.$(OBJEXT) +gnunet_service_resolver_OBJECTS = \ + $(am_gnunet_service_resolver_OBJECTS) +am_perf_crypto_hash_OBJECTS = perf_crypto_hash.$(OBJEXT) +perf_crypto_hash_OBJECTS = $(am_perf_crypto_hash_OBJECTS) +perf_crypto_hash_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_bio_OBJECTS = test_bio.$(OBJEXT) +test_bio_OBJECTS = $(am_test_bio_OBJECTS) +test_bio_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_client_OBJECTS = test_client.$(OBJEXT) +test_client_OBJECTS = $(am_test_client_OBJECTS) +test_client_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_common_allocation_OBJECTS = test_common_allocation.$(OBJEXT) +test_common_allocation_OBJECTS = $(am_test_common_allocation_OBJECTS) +test_common_allocation_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_common_endian_OBJECTS = test_common_endian.$(OBJEXT) +test_common_endian_OBJECTS = $(am_test_common_endian_OBJECTS) +test_common_endian_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_common_logging_OBJECTS = test_common_logging.$(OBJEXT) +test_common_logging_OBJECTS = $(am_test_common_logging_OBJECTS) +test_common_logging_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_common_logging_dummy_OBJECTS = \ + test_common_logging_dummy.$(OBJEXT) +test_common_logging_dummy_OBJECTS = \ + $(am_test_common_logging_dummy_OBJECTS) +am_test_common_logging_runtime_loglevels_OBJECTS = \ + test_common_logging_runtime_loglevels.$(OBJEXT) +test_common_logging_runtime_loglevels_OBJECTS = \ + $(am_test_common_logging_runtime_loglevels_OBJECTS) +test_common_logging_runtime_loglevels_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_configuration_OBJECTS = test_configuration.$(OBJEXT) +test_configuration_OBJECTS = $(am_test_configuration_OBJECTS) +test_configuration_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_connection_OBJECTS = test_connection.$(OBJEXT) +test_connection_OBJECTS = $(am_test_connection_OBJECTS) +test_connection_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_connection_addressing_OBJECTS = \ + test_connection_addressing.$(OBJEXT) +test_connection_addressing_OBJECTS = \ + $(am_test_connection_addressing_OBJECTS) +test_connection_addressing_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_connection_receive_cancel_OBJECTS = \ + test_connection_receive_cancel.$(OBJEXT) +test_connection_receive_cancel_OBJECTS = \ + $(am_test_connection_receive_cancel_OBJECTS) +test_connection_receive_cancel_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_connection_timeout_OBJECTS = \ + test_connection_timeout.$(OBJEXT) +test_connection_timeout_OBJECTS = \ + $(am_test_connection_timeout_OBJECTS) +test_connection_timeout_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_connection_timeout_no_connect_OBJECTS = \ + test_connection_timeout_no_connect.$(OBJEXT) +test_connection_timeout_no_connect_OBJECTS = \ + $(am_test_connection_timeout_no_connect_OBJECTS) +test_connection_timeout_no_connect_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_connection_transmit_cancel_OBJECTS = \ + test_connection_transmit_cancel.$(OBJEXT) +test_connection_transmit_cancel_OBJECTS = \ + $(am_test_connection_transmit_cancel_OBJECTS) +test_connection_transmit_cancel_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_container_bloomfilter_OBJECTS = \ + test_container_bloomfilter.$(OBJEXT) +test_container_bloomfilter_OBJECTS = \ + $(am_test_container_bloomfilter_OBJECTS) +test_container_bloomfilter_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_container_heap_OBJECTS = test_container_heap.$(OBJEXT) +test_container_heap_OBJECTS = $(am_test_container_heap_OBJECTS) +test_container_heap_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_container_meta_data_OBJECTS = \ + test_container_meta_data.$(OBJEXT) +test_container_meta_data_OBJECTS = \ + $(am_test_container_meta_data_OBJECTS) +test_container_meta_data_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_container_multihashmap_OBJECTS = \ + test_container_multihashmap.$(OBJEXT) +test_container_multihashmap_OBJECTS = \ + $(am_test_container_multihashmap_OBJECTS) +test_container_multihashmap_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_container_slist_OBJECTS = test_container_slist.$(OBJEXT) +test_container_slist_OBJECTS = $(am_test_container_slist_OBJECTS) +test_container_slist_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_crypto_aes_OBJECTS = test_crypto_aes.$(OBJEXT) +test_crypto_aes_OBJECTS = $(am_test_crypto_aes_OBJECTS) +test_crypto_aes_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_crypto_aes_weak_OBJECTS = test_crypto_aes_weak.$(OBJEXT) +test_crypto_aes_weak_OBJECTS = $(am_test_crypto_aes_weak_OBJECTS) +test_crypto_aes_weak_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(am__DEPENDENCIES_1) +am_test_crypto_crc_OBJECTS = test_crypto_crc.$(OBJEXT) +test_crypto_crc_OBJECTS = $(am_test_crypto_crc_OBJECTS) +test_crypto_crc_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_crypto_hash_OBJECTS = test_crypto_hash.$(OBJEXT) +test_crypto_hash_OBJECTS = $(am_test_crypto_hash_OBJECTS) +test_crypto_hash_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_crypto_hkdf_OBJECTS = test_crypto_hkdf.$(OBJEXT) +test_crypto_hkdf_OBJECTS = $(am_test_crypto_hkdf_OBJECTS) +test_crypto_hkdf_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_crypto_ksk_OBJECTS = test_crypto_ksk.$(OBJEXT) +test_crypto_ksk_OBJECTS = $(am_test_crypto_ksk_OBJECTS) +test_crypto_ksk_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_crypto_random_OBJECTS = test_crypto_random.$(OBJEXT) +test_crypto_random_OBJECTS = $(am_test_crypto_random_OBJECTS) +test_crypto_random_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_crypto_rsa_OBJECTS = test_crypto_rsa.$(OBJEXT) +test_crypto_rsa_OBJECTS = $(am_test_crypto_rsa_OBJECTS) +test_crypto_rsa_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_disk_OBJECTS = test_disk.$(OBJEXT) +test_disk_OBJECTS = $(am_test_disk_OBJECTS) +test_disk_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_getopt_OBJECTS = test_getopt.$(OBJEXT) +test_getopt_OBJECTS = $(am_test_getopt_OBJECTS) +test_getopt_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_os_network_OBJECTS = test_os_network.$(OBJEXT) +test_os_network_OBJECTS = $(am_test_os_network_OBJECTS) +test_os_network_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_os_priority_OBJECTS = test_os_priority.$(OBJEXT) +test_os_priority_OBJECTS = $(am_test_os_priority_OBJECTS) +test_os_priority_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_os_start_process_OBJECTS = test_os_start_process.$(OBJEXT) +test_os_start_process_OBJECTS = $(am_test_os_start_process_OBJECTS) +test_os_start_process_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_peer_OBJECTS = test_peer.$(OBJEXT) +test_peer_OBJECTS = $(am_test_peer_OBJECTS) +test_peer_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_plugin_OBJECTS = test_plugin.$(OBJEXT) +test_plugin_OBJECTS = $(am_test_plugin_OBJECTS) +test_plugin_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_program_OBJECTS = test_program.$(OBJEXT) +test_program_OBJECTS = $(am_test_program_OBJECTS) +test_program_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_pseudonym_OBJECTS = test_pseudonym.$(OBJEXT) +test_pseudonym_OBJECTS = $(am_test_pseudonym_OBJECTS) +test_pseudonym_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_resolver_api_OBJECTS = test_resolver_api.$(OBJEXT) +test_resolver_api_OBJECTS = $(am_test_resolver_api_OBJECTS) +test_resolver_api_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_scheduler_OBJECTS = test_scheduler.$(OBJEXT) +test_scheduler_OBJECTS = $(am_test_scheduler_OBJECTS) +test_scheduler_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_scheduler_delay_OBJECTS = test_scheduler_delay.$(OBJEXT) +test_scheduler_delay_OBJECTS = $(am_test_scheduler_delay_OBJECTS) +test_scheduler_delay_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_server_OBJECTS = test_server.$(OBJEXT) +test_server_OBJECTS = $(am_test_server_OBJECTS) +test_server_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_server_disconnect_OBJECTS = test_server_disconnect.$(OBJEXT) +test_server_disconnect_OBJECTS = $(am_test_server_disconnect_OBJECTS) +test_server_disconnect_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_server_with_client_OBJECTS = \ + test_server_with_client.$(OBJEXT) +test_server_with_client_OBJECTS = \ + $(am_test_server_with_client_OBJECTS) +test_server_with_client_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_server_with_client_unix_OBJECTS = \ + test_server_with_client_unix.$(OBJEXT) +test_server_with_client_unix_OBJECTS = \ + $(am_test_server_with_client_unix_OBJECTS) +test_server_with_client_unix_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_service_OBJECTS = test_service.$(OBJEXT) +test_service_OBJECTS = $(am_test_service_OBJECTS) +test_service_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_strings_OBJECTS = test_strings.$(OBJEXT) +test_strings_OBJECTS = $(am_test_strings_OBJECTS) +test_strings_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +am_test_time_OBJECTS = test_time.$(OBJEXT) +test_time_OBJECTS = $(am_test_time_OBJECTS) +test_time_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_$(V)) +am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY)) +am__v_CXX_0 = @echo " CXX " $@; +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_$(V)) +am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CXXLD_0 = @echo " CXXLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunet_plugin_test_la_SOURCES) \ + $(libgnunetutil_la_SOURCES) $(libgnunetutilwin_la_SOURCES) \ + $(gnunet_config_diff_SOURCES) $(gnunet_resolver_SOURCES) \ + $(gnunet_service_resolver_SOURCES) $(perf_crypto_hash_SOURCES) \ + $(test_bio_SOURCES) $(test_client_SOURCES) \ + $(test_common_allocation_SOURCES) \ + $(test_common_endian_SOURCES) $(test_common_logging_SOURCES) \ + $(test_common_logging_dummy_SOURCES) \ + $(test_common_logging_runtime_loglevels_SOURCES) \ + $(test_configuration_SOURCES) $(test_connection_SOURCES) \ + $(test_connection_addressing_SOURCES) \ + $(test_connection_receive_cancel_SOURCES) \ + $(test_connection_timeout_SOURCES) \ + $(test_connection_timeout_no_connect_SOURCES) \ + $(test_connection_transmit_cancel_SOURCES) \ + $(test_container_bloomfilter_SOURCES) \ + $(test_container_heap_SOURCES) \ + $(test_container_meta_data_SOURCES) \ + $(test_container_multihashmap_SOURCES) \ + $(test_container_slist_SOURCES) $(test_crypto_aes_SOURCES) \ + $(test_crypto_aes_weak_SOURCES) $(test_crypto_crc_SOURCES) \ + $(test_crypto_hash_SOURCES) $(test_crypto_hkdf_SOURCES) \ + $(test_crypto_ksk_SOURCES) $(test_crypto_random_SOURCES) \ + $(test_crypto_rsa_SOURCES) $(test_disk_SOURCES) \ + $(test_getopt_SOURCES) $(test_os_network_SOURCES) \ + $(test_os_priority_SOURCES) $(test_os_start_process_SOURCES) \ + $(test_peer_SOURCES) $(test_plugin_SOURCES) \ + $(test_program_SOURCES) $(test_pseudonym_SOURCES) \ + $(test_resolver_api_SOURCES) $(test_scheduler_SOURCES) \ + $(test_scheduler_delay_SOURCES) $(test_server_SOURCES) \ + $(test_server_disconnect_SOURCES) \ + $(test_server_with_client_SOURCES) \ + $(test_server_with_client_unix_SOURCES) \ + $(test_service_SOURCES) $(test_strings_SOURCES) \ + $(test_time_SOURCES) +DIST_SOURCES = $(libgnunet_plugin_test_la_SOURCES) \ + $(libgnunetutil_la_SOURCES) \ + $(am__libgnunetutilwin_la_SOURCES_DIST) \ + $(gnunet_config_diff_SOURCES) $(gnunet_resolver_SOURCES) \ + $(gnunet_service_resolver_SOURCES) $(perf_crypto_hash_SOURCES) \ + $(test_bio_SOURCES) $(test_client_SOURCES) \ + $(test_common_allocation_SOURCES) \ + $(test_common_endian_SOURCES) $(test_common_logging_SOURCES) \ + $(test_common_logging_dummy_SOURCES) \ + $(test_common_logging_runtime_loglevels_SOURCES) \ + $(test_configuration_SOURCES) $(test_connection_SOURCES) \ + $(test_connection_addressing_SOURCES) \ + $(test_connection_receive_cancel_SOURCES) \ + $(test_connection_timeout_SOURCES) \ + $(test_connection_timeout_no_connect_SOURCES) \ + $(test_connection_transmit_cancel_SOURCES) \ + $(test_container_bloomfilter_SOURCES) \ + $(test_container_heap_SOURCES) \ + $(test_container_meta_data_SOURCES) \ + $(test_container_multihashmap_SOURCES) \ + $(test_container_slist_SOURCES) $(test_crypto_aes_SOURCES) \ + $(test_crypto_aes_weak_SOURCES) $(test_crypto_crc_SOURCES) \ + $(test_crypto_hash_SOURCES) $(test_crypto_hkdf_SOURCES) \ + $(test_crypto_ksk_SOURCES) $(test_crypto_random_SOURCES) \ + $(test_crypto_rsa_SOURCES) $(test_disk_SOURCES) \ + $(test_getopt_SOURCES) $(test_os_network_SOURCES) \ + $(test_os_priority_SOURCES) $(test_os_start_process_SOURCES) \ + $(test_peer_SOURCES) $(test_plugin_SOURCES) \ + $(test_program_SOURCES) $(test_pseudonym_SOURCES) \ + $(test_resolver_api_SOURCES) $(test_scheduler_SOURCES) \ + $(test_scheduler_delay_SOURCES) $(test_server_SOURCES) \ + $(test_server_disconnect_SOURCES) \ + $(test_server_with_client_SOURCES) \ + $(test_server_with_client_unix_SOURCES) \ + $(test_service_SOURCES) $(test_strings_SOURCES) \ + $(test_time_SOURCES) +DATA = $(dist_pkgcfg_DATA) $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include +plugindir = $(libdir)/gnunet +pkgcfgdir = $(pkgdatadir)/config.d/ +dist_pkgcfg_DATA = \ + util.conf + +pkgcfg_DATA = \ + resolver.conf + +@MINGW_TRUE@noinst_LTLIBRARIES = \ +@MINGW_TRUE@ libgnunetutilwin.la + +@MINGW_TRUE@libgnunetutilwin_la_SOURCES = \ +@MINGW_TRUE@ win.cc \ +@MINGW_TRUE@ winproc.c + +@MINGW_TRUE@libgnunetutilwin_la_LDFLAGS = \ +@MINGW_TRUE@ -no-undefined -Wl,--export-all-symbols + +@MINGW_TRUE@libgnunetutilwin_la_LIBADD = \ +@MINGW_TRUE@ -lshell32 -liconv -lstdc++ \ +@MINGW_TRUE@ -lcomdlg32 -lgdi32 -liphlpapi + +@MINGW_TRUE@WINLIB = libgnunetutilwin.la +@MINGW_FALSE@SERVER_CLIENT_UNIX = test_server_with_client_unix +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +@USE_COVERAGE_TRUE@XLIB = -lgcov +gnunet_config_diff_SOURCES = \ + gnunet-config-diff.c + +gnunet_config_diff_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_config_diff_DEPENDENCIES = \ + libgnunetutil.la + +test_common_logging_dummy_SOURCES = \ + test_common_logging_dummy.c + +test_common_logging_dummy_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_common_logging_dummy_DEPENDENCIES = \ + libgnunetutil.la + +lib_LTLIBRARIES = libgnunetutil.la +libgnunetutil_la_SOURCES = \ + bandwidth.c \ + bio.c \ + client.c \ + common_allocation.c \ + common_endian.c \ + common_logging.c \ + configuration.c \ + connection.c \ + container_bloomfilter.c \ + container_heap.c \ + container_meta_data.c \ + container_multihashmap.c \ + container_slist.c \ + crypto_aes.c \ + crypto_crc.c \ + crypto_hash.c \ + crypto_hkdf.c \ + crypto_kdf.c \ + crypto_ksk.c \ + crypto_random.c \ + crypto_rsa.c \ + disk.c \ + disk.h \ + getopt.c \ + getopt_helpers.c \ + helper.c \ + load.c \ + network.c \ + os_installation.c \ + os_network.c \ + os_priority.c \ + peer.c \ + plugin.c \ + program.c \ + pseudonym.c \ + resolver_api.c resolver.h \ + scheduler.c \ + server.c \ + server_mst.c \ + server_nc.c \ + server_tc.c \ + service.c \ + signal.c \ + strings.c \ + time.c + +libgnunetutil_la_LIBADD = \ + $(GCLIBADD) $(WINLIB) \ + $(LIBGCRYPT_LIBS) \ + $(LTLIBICONV) \ + -lltdl -lz $(XLIB) + +libgnunetutil_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 7:0:0 + +gnunet_service_resolver_SOURCES = \ + gnunet-service-resolver.c + +gnunet_service_resolver_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_service_resolver_DEPENDENCIES = \ + libgnunetutil.la + +gnunet_resolver_SOURCES = \ + gnunet-resolver.c + +gnunet_resolver_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_resolver_DEPENDENCIES = \ + libgnunetutil.la + +plugin_LTLIBRARIES = \ + libgnunet_plugin_test.la + +libgnunet_plugin_test_la_SOURCES = \ + test_plugin_plug.c + +libgnunet_plugin_test_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +@HAVE_BENCHMARKS_TRUE@BENCHMARKS = \ +@HAVE_BENCHMARKS_TRUE@ perf_crypto_hash + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +test_bio_SOURCES = \ + test_bio.c + +test_bio_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_os_start_process_SOURCES = \ + test_os_start_process.c + +test_os_start_process_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_client_SOURCES = \ + test_client.c + +test_client_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_common_allocation_SOURCES = \ + test_common_allocation.c + +test_common_allocation_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_common_endian_SOURCES = \ + test_common_endian.c + +test_common_endian_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_common_logging_SOURCES = \ + test_common_logging.c + +test_common_logging_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_common_logging_runtime_loglevels_SOURCES = \ + test_common_logging_runtime_loglevels.c + +test_common_logging_runtime_loglevels_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_configuration_SOURCES = \ + test_configuration.c + +test_configuration_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_container_bloomfilter_SOURCES = \ + test_container_bloomfilter.c + +test_container_bloomfilter_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_container_meta_data_SOURCES = \ + test_container_meta_data.c + +test_container_meta_data_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la -lextractor + +test_container_multihashmap_SOURCES = \ + test_container_multihashmap.c + +test_container_multihashmap_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_container_heap_SOURCES = \ + test_container_heap.c + +test_container_heap_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_container_slist_SOURCES = \ + test_container_slist.c + +test_container_slist_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_aes_SOURCES = \ + test_crypto_aes.c + +test_crypto_aes_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_aes_weak_SOURCES = \ + test_crypto_aes_weak.c + +test_crypto_aes_weak_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(LIBGCRYPT_LIBS) + +test_crypto_crc_SOURCES = \ + test_crypto_crc.c + +test_crypto_crc_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_hash_SOURCES = \ + test_crypto_hash.c + +test_crypto_hash_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_hkdf_SOURCES = \ + test_crypto_hkdf.c + +test_crypto_hkdf_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_ksk_SOURCES = \ + test_crypto_ksk.c + +test_crypto_ksk_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_random_SOURCES = \ + test_crypto_random.c + +test_crypto_random_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_crypto_rsa_SOURCES = \ + test_crypto_rsa.c + +test_crypto_rsa_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_disk_SOURCES = \ + test_disk.c + +test_disk_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_getopt_SOURCES = \ + test_getopt.c + +test_getopt_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_SOURCES = \ + test_connection.c + +test_connection_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_addressing_SOURCES = \ + test_connection_addressing.c + +test_connection_addressing_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_receive_cancel_SOURCES = \ + test_connection_receive_cancel.c + +test_connection_receive_cancel_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_timeout_SOURCES = \ + test_connection_timeout.c + +test_connection_timeout_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_timeout_no_connect_SOURCES = \ + test_connection_timeout_no_connect.c + +test_connection_timeout_no_connect_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_connection_transmit_cancel_SOURCES = \ + test_connection_transmit_cancel.c + +test_connection_transmit_cancel_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_os_network_SOURCES = \ + test_os_network.c + +test_os_network_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_os_priority_SOURCES = \ + test_os_priority.c + +test_os_priority_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_peer_SOURCES = \ + test_peer.c + +test_peer_LDADD = \ +$(top_builddir)/src/util/libgnunetutil.la + +test_plugin_SOURCES = \ + test_plugin.c + +test_plugin_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_program_SOURCES = \ + test_program.c + +test_program_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_pseudonym_SOURCES = \ + test_pseudonym.c + +test_pseudonym_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_resolver_api_SOURCES = \ + test_resolver_api.c + +test_resolver_api_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_scheduler_SOURCES = \ + test_scheduler.c + +test_scheduler_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_scheduler_delay_SOURCES = \ + test_scheduler_delay.c + +test_scheduler_delay_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_server_SOURCES = \ + test_server.c + +test_server_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_server_disconnect_SOURCES = \ + test_server_disconnect.c + +test_server_disconnect_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_server_with_client_SOURCES = \ + test_server_with_client.c + +test_server_with_client_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_server_with_client_unix_SOURCES = \ + test_server_with_client_unix.c + +test_server_with_client_unix_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_service_SOURCES = \ + test_service.c + +test_service_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_strings_SOURCES = \ + test_strings.c + +test_strings_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +test_time_SOURCES = \ + test_time.c + +test_time_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +perf_crypto_hash_SOURCES = \ + perf_crypto_hash.c + +perf_crypto_hash_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +EXTRA_DIST = \ + test_configuration_data.conf \ + test_program_data.conf \ + test_pseudonym_data.conf \ + test_resolver_api_data.conf \ + test_service_data.conf + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/util/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/util/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +resolver.conf: $(top_builddir)/config.status $(srcdir)/resolver.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunet_plugin_test.la: $(libgnunet_plugin_test_la_OBJECTS) $(libgnunet_plugin_test_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunet_plugin_test_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_test_la_OBJECTS) $(libgnunet_plugin_test_la_LIBADD) $(LIBS) +libgnunetutil.la: $(libgnunetutil_la_OBJECTS) $(libgnunetutil_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetutil_la_LINK) -rpath $(libdir) $(libgnunetutil_la_OBJECTS) $(libgnunetutil_la_LIBADD) $(LIBS) +libgnunetutilwin.la: $(libgnunetutilwin_la_OBJECTS) $(libgnunetutilwin_la_DEPENDENCIES) + $(AM_V_CXXLD)$(libgnunetutilwin_la_LINK) $(am_libgnunetutilwin_la_rpath) $(libgnunetutilwin_la_OBJECTS) $(libgnunetutilwin_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-config-diff$(EXEEXT): $(gnunet_config_diff_OBJECTS) $(gnunet_config_diff_DEPENDENCIES) + @rm -f gnunet-config-diff$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_config_diff_OBJECTS) $(gnunet_config_diff_LDADD) $(LIBS) +gnunet-resolver$(EXEEXT): $(gnunet_resolver_OBJECTS) $(gnunet_resolver_DEPENDENCIES) + @rm -f gnunet-resolver$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_resolver_OBJECTS) $(gnunet_resolver_LDADD) $(LIBS) +gnunet-service-resolver$(EXEEXT): $(gnunet_service_resolver_OBJECTS) $(gnunet_service_resolver_DEPENDENCIES) + @rm -f gnunet-service-resolver$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_service_resolver_OBJECTS) $(gnunet_service_resolver_LDADD) $(LIBS) +perf_crypto_hash$(EXEEXT): $(perf_crypto_hash_OBJECTS) $(perf_crypto_hash_DEPENDENCIES) + @rm -f perf_crypto_hash$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(perf_crypto_hash_OBJECTS) $(perf_crypto_hash_LDADD) $(LIBS) +test_bio$(EXEEXT): $(test_bio_OBJECTS) $(test_bio_DEPENDENCIES) + @rm -f test_bio$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_bio_OBJECTS) $(test_bio_LDADD) $(LIBS) +test_client$(EXEEXT): $(test_client_OBJECTS) $(test_client_DEPENDENCIES) + @rm -f test_client$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_client_OBJECTS) $(test_client_LDADD) $(LIBS) +test_common_allocation$(EXEEXT): $(test_common_allocation_OBJECTS) $(test_common_allocation_DEPENDENCIES) + @rm -f test_common_allocation$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_common_allocation_OBJECTS) $(test_common_allocation_LDADD) $(LIBS) +test_common_endian$(EXEEXT): $(test_common_endian_OBJECTS) $(test_common_endian_DEPENDENCIES) + @rm -f test_common_endian$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_common_endian_OBJECTS) $(test_common_endian_LDADD) $(LIBS) +test_common_logging$(EXEEXT): $(test_common_logging_OBJECTS) $(test_common_logging_DEPENDENCIES) + @rm -f test_common_logging$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_common_logging_OBJECTS) $(test_common_logging_LDADD) $(LIBS) +test_common_logging_dummy$(EXEEXT): $(test_common_logging_dummy_OBJECTS) $(test_common_logging_dummy_DEPENDENCIES) + @rm -f test_common_logging_dummy$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_common_logging_dummy_OBJECTS) $(test_common_logging_dummy_LDADD) $(LIBS) +test_common_logging_runtime_loglevels$(EXEEXT): $(test_common_logging_runtime_loglevels_OBJECTS) $(test_common_logging_runtime_loglevels_DEPENDENCIES) + @rm -f test_common_logging_runtime_loglevels$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_common_logging_runtime_loglevels_OBJECTS) $(test_common_logging_runtime_loglevels_LDADD) $(LIBS) +test_configuration$(EXEEXT): $(test_configuration_OBJECTS) $(test_configuration_DEPENDENCIES) + @rm -f test_configuration$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_configuration_OBJECTS) $(test_configuration_LDADD) $(LIBS) +test_connection$(EXEEXT): $(test_connection_OBJECTS) $(test_connection_DEPENDENCIES) + @rm -f test_connection$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_connection_OBJECTS) $(test_connection_LDADD) $(LIBS) +test_connection_addressing$(EXEEXT): $(test_connection_addressing_OBJECTS) $(test_connection_addressing_DEPENDENCIES) + @rm -f test_connection_addressing$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_connection_addressing_OBJECTS) $(test_connection_addressing_LDADD) $(LIBS) +test_connection_receive_cancel$(EXEEXT): $(test_connection_receive_cancel_OBJECTS) $(test_connection_receive_cancel_DEPENDENCIES) + @rm -f test_connection_receive_cancel$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_connection_receive_cancel_OBJECTS) $(test_connection_receive_cancel_LDADD) $(LIBS) +test_connection_timeout$(EXEEXT): $(test_connection_timeout_OBJECTS) $(test_connection_timeout_DEPENDENCIES) + @rm -f test_connection_timeout$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_connection_timeout_OBJECTS) $(test_connection_timeout_LDADD) $(LIBS) +test_connection_timeout_no_connect$(EXEEXT): $(test_connection_timeout_no_connect_OBJECTS) $(test_connection_timeout_no_connect_DEPENDENCIES) + @rm -f test_connection_timeout_no_connect$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_connection_timeout_no_connect_OBJECTS) $(test_connection_timeout_no_connect_LDADD) $(LIBS) +test_connection_transmit_cancel$(EXEEXT): $(test_connection_transmit_cancel_OBJECTS) $(test_connection_transmit_cancel_DEPENDENCIES) + @rm -f test_connection_transmit_cancel$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_connection_transmit_cancel_OBJECTS) $(test_connection_transmit_cancel_LDADD) $(LIBS) +test_container_bloomfilter$(EXEEXT): $(test_container_bloomfilter_OBJECTS) $(test_container_bloomfilter_DEPENDENCIES) + @rm -f test_container_bloomfilter$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_container_bloomfilter_OBJECTS) $(test_container_bloomfilter_LDADD) $(LIBS) +test_container_heap$(EXEEXT): $(test_container_heap_OBJECTS) $(test_container_heap_DEPENDENCIES) + @rm -f test_container_heap$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_container_heap_OBJECTS) $(test_container_heap_LDADD) $(LIBS) +test_container_meta_data$(EXEEXT): $(test_container_meta_data_OBJECTS) $(test_container_meta_data_DEPENDENCIES) + @rm -f test_container_meta_data$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_container_meta_data_OBJECTS) $(test_container_meta_data_LDADD) $(LIBS) +test_container_multihashmap$(EXEEXT): $(test_container_multihashmap_OBJECTS) $(test_container_multihashmap_DEPENDENCIES) + @rm -f test_container_multihashmap$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_container_multihashmap_OBJECTS) $(test_container_multihashmap_LDADD) $(LIBS) +test_container_slist$(EXEEXT): $(test_container_slist_OBJECTS) $(test_container_slist_DEPENDENCIES) + @rm -f test_container_slist$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_container_slist_OBJECTS) $(test_container_slist_LDADD) $(LIBS) +test_crypto_aes$(EXEEXT): $(test_crypto_aes_OBJECTS) $(test_crypto_aes_DEPENDENCIES) + @rm -f test_crypto_aes$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_crypto_aes_OBJECTS) $(test_crypto_aes_LDADD) $(LIBS) +test_crypto_aes_weak$(EXEEXT): $(test_crypto_aes_weak_OBJECTS) $(test_crypto_aes_weak_DEPENDENCIES) + @rm -f test_crypto_aes_weak$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_crypto_aes_weak_OBJECTS) $(test_crypto_aes_weak_LDADD) $(LIBS) +test_crypto_crc$(EXEEXT): $(test_crypto_crc_OBJECTS) $(test_crypto_crc_DEPENDENCIES) + @rm -f test_crypto_crc$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_crypto_crc_OBJECTS) $(test_crypto_crc_LDADD) $(LIBS) +test_crypto_hash$(EXEEXT): $(test_crypto_hash_OBJECTS) $(test_crypto_hash_DEPENDENCIES) + @rm -f test_crypto_hash$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_crypto_hash_OBJECTS) $(test_crypto_hash_LDADD) $(LIBS) +test_crypto_hkdf$(EXEEXT): $(test_crypto_hkdf_OBJECTS) $(test_crypto_hkdf_DEPENDENCIES) + @rm -f test_crypto_hkdf$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_crypto_hkdf_OBJECTS) $(test_crypto_hkdf_LDADD) $(LIBS) +test_crypto_ksk$(EXEEXT): $(test_crypto_ksk_OBJECTS) $(test_crypto_ksk_DEPENDENCIES) + @rm -f test_crypto_ksk$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_crypto_ksk_OBJECTS) $(test_crypto_ksk_LDADD) $(LIBS) +test_crypto_random$(EXEEXT): $(test_crypto_random_OBJECTS) $(test_crypto_random_DEPENDENCIES) + @rm -f test_crypto_random$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_crypto_random_OBJECTS) $(test_crypto_random_LDADD) $(LIBS) +test_crypto_rsa$(EXEEXT): $(test_crypto_rsa_OBJECTS) $(test_crypto_rsa_DEPENDENCIES) + @rm -f test_crypto_rsa$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_crypto_rsa_OBJECTS) $(test_crypto_rsa_LDADD) $(LIBS) +test_disk$(EXEEXT): $(test_disk_OBJECTS) $(test_disk_DEPENDENCIES) + @rm -f test_disk$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_disk_OBJECTS) $(test_disk_LDADD) $(LIBS) +test_getopt$(EXEEXT): $(test_getopt_OBJECTS) $(test_getopt_DEPENDENCIES) + @rm -f test_getopt$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_getopt_OBJECTS) $(test_getopt_LDADD) $(LIBS) +test_os_network$(EXEEXT): $(test_os_network_OBJECTS) $(test_os_network_DEPENDENCIES) + @rm -f test_os_network$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_os_network_OBJECTS) $(test_os_network_LDADD) $(LIBS) +test_os_priority$(EXEEXT): $(test_os_priority_OBJECTS) $(test_os_priority_DEPENDENCIES) + @rm -f test_os_priority$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_os_priority_OBJECTS) $(test_os_priority_LDADD) $(LIBS) +test_os_start_process$(EXEEXT): $(test_os_start_process_OBJECTS) $(test_os_start_process_DEPENDENCIES) + @rm -f test_os_start_process$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_os_start_process_OBJECTS) $(test_os_start_process_LDADD) $(LIBS) +test_peer$(EXEEXT): $(test_peer_OBJECTS) $(test_peer_DEPENDENCIES) + @rm -f test_peer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_peer_OBJECTS) $(test_peer_LDADD) $(LIBS) +test_plugin$(EXEEXT): $(test_plugin_OBJECTS) $(test_plugin_DEPENDENCIES) + @rm -f test_plugin$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_plugin_OBJECTS) $(test_plugin_LDADD) $(LIBS) +test_program$(EXEEXT): $(test_program_OBJECTS) $(test_program_DEPENDENCIES) + @rm -f test_program$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_program_OBJECTS) $(test_program_LDADD) $(LIBS) +test_pseudonym$(EXEEXT): $(test_pseudonym_OBJECTS) $(test_pseudonym_DEPENDENCIES) + @rm -f test_pseudonym$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_pseudonym_OBJECTS) $(test_pseudonym_LDADD) $(LIBS) +test_resolver_api$(EXEEXT): $(test_resolver_api_OBJECTS) $(test_resolver_api_DEPENDENCIES) + @rm -f test_resolver_api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_resolver_api_OBJECTS) $(test_resolver_api_LDADD) $(LIBS) +test_scheduler$(EXEEXT): $(test_scheduler_OBJECTS) $(test_scheduler_DEPENDENCIES) + @rm -f test_scheduler$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_scheduler_OBJECTS) $(test_scheduler_LDADD) $(LIBS) +test_scheduler_delay$(EXEEXT): $(test_scheduler_delay_OBJECTS) $(test_scheduler_delay_DEPENDENCIES) + @rm -f test_scheduler_delay$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_scheduler_delay_OBJECTS) $(test_scheduler_delay_LDADD) $(LIBS) +test_server$(EXEEXT): $(test_server_OBJECTS) $(test_server_DEPENDENCIES) + @rm -f test_server$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_server_OBJECTS) $(test_server_LDADD) $(LIBS) +test_server_disconnect$(EXEEXT): $(test_server_disconnect_OBJECTS) $(test_server_disconnect_DEPENDENCIES) + @rm -f test_server_disconnect$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_server_disconnect_OBJECTS) $(test_server_disconnect_LDADD) $(LIBS) +test_server_with_client$(EXEEXT): $(test_server_with_client_OBJECTS) $(test_server_with_client_DEPENDENCIES) + @rm -f test_server_with_client$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_server_with_client_OBJECTS) $(test_server_with_client_LDADD) $(LIBS) +test_server_with_client_unix$(EXEEXT): $(test_server_with_client_unix_OBJECTS) $(test_server_with_client_unix_DEPENDENCIES) + @rm -f test_server_with_client_unix$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_server_with_client_unix_OBJECTS) $(test_server_with_client_unix_LDADD) $(LIBS) +test_service$(EXEEXT): $(test_service_OBJECTS) $(test_service_DEPENDENCIES) + @rm -f test_service$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_service_OBJECTS) $(test_service_LDADD) $(LIBS) +test_strings$(EXEEXT): $(test_strings_OBJECTS) $(test_strings_DEPENDENCIES) + @rm -f test_strings$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_strings_OBJECTS) $(test_strings_LDADD) $(LIBS) +test_time$(EXEEXT): $(test_time_OBJECTS) $(test_time_DEPENDENCIES) + @rm -f test_time$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_time_OBJECTS) $(test_time_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bandwidth.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_allocation.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_endian.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_logging.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/configuration.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/container_bloomfilter.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/container_heap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/container_meta_data.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/container_multihashmap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/container_slist.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_aes.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_crc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_hash.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_hkdf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_kdf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_ksk.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_random.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_rsa.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/disk.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt_helpers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-config-diff.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-resolver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-resolver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helper.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/network.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_installation.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_network.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_priority.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_crypto_hash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/program.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pseudonym.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolver_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scheduler.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_mst.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_nc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_tc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/service.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strings.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_bio.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_common_allocation.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_common_endian.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_common_logging.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_common_logging_dummy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_common_logging_runtime_loglevels.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_configuration.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_addressing.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_receive_cancel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_timeout.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_timeout_no_connect.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_transmit_cancel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_container_bloomfilter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_container_heap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_container_meta_data.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_container_multihashmap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_container_slist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_aes.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_aes_weak.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_crc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_hash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_hkdf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_ksk.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_random.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_rsa.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_disk.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_getopt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_os_network.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_os_priority.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_os_start_process.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_peer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_plugin.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_plugin_plug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_program.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_pseudonym.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_resolver_api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_scheduler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_scheduler_delay.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_disconnect.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_with_client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_with_client_unix.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_service.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_strings.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_time.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/winproc.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-dist_pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ + clean-noinstPROGRAMS clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_pkgcfgDATA install-pkgcfgDATA \ + install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA \ + uninstall-libLTLIBRARIES uninstall-pkgcfgDATA \ + uninstall-pluginLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ + clean-noinstPROGRAMS clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dist_pkgcfgDATA install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-pkgcfgDATA install-pluginLTLIBRARIES install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA \ + uninstall-libLTLIBRARIES uninstall-pkgcfgDATA \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/util/bandwidth.c b/src/util/bandwidth.c new file mode 100644 index 0000000..9d67949 --- /dev/null +++ b/src/util/bandwidth.c @@ -0,0 +1,328 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/bandwidth.c + * @brief functions related to bandwidth (unit) + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_bandwidth_lib.h" +#include "gnunet_server_lib.h" + + +#define LOG(kind,...) GNUNET_log_from (kind, "util-bandwidth", __VA_ARGS__) + +/** + * Create a new bandwidth value. + * + * @param bytes_per_second value to create + * @return the new bandwidth value + */ +struct GNUNET_BANDWIDTH_Value32NBO +GNUNET_BANDWIDTH_value_init (uint32_t bytes_per_second) +{ + struct GNUNET_BANDWIDTH_Value32NBO ret; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Initializing bandwidth of %u Bps\n", + (unsigned int) bytes_per_second); + ret.value__ = htonl (bytes_per_second); + return ret; +} + + +/** + * Compute the MIN of two bandwidth values. + * + * @param b1 first value + * @param b2 second value + * @return the min of b1 and b2 + */ +struct GNUNET_BANDWIDTH_Value32NBO +GNUNET_BANDWIDTH_value_min (struct GNUNET_BANDWIDTH_Value32NBO b1, + struct GNUNET_BANDWIDTH_Value32NBO b2) +{ + return + GNUNET_BANDWIDTH_value_init (GNUNET_MIN + (ntohl (b1.value__), ntohl (b2.value__))); +} + + +/** + * At the given bandwidth, calculate how much traffic will be + * available until the given deadline. + * + * @param bps bandwidth + * @param deadline when is the deadline + * @return number of bytes available at bps until deadline + */ +uint64_t +GNUNET_BANDWIDTH_value_get_available_until (struct GNUNET_BANDWIDTH_Value32NBO + bps, + struct GNUNET_TIME_Relative + deadline) +{ + uint64_t b; + + b = ntohl (bps.value__); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Bandwidth has %llu bytes available until deadline in %llums\n", + (unsigned long long) ((b * deadline.rel_value + 500LL) / 1000LL), + deadline.rel_value); + return (b * deadline.rel_value + 500LL) / 1000LL; +} + + +/** + * At the given bandwidth, calculate how long it would take for + * 'size' bytes to be transmitted. + * + * @param bps bandwidth + * @param size number of bytes we want to have available + * @return how long it would take + */ +struct GNUNET_TIME_Relative +GNUNET_BANDWIDTH_value_get_delay_for (struct GNUNET_BANDWIDTH_Value32NBO bps, + uint64_t size) +{ + uint64_t b; + struct GNUNET_TIME_Relative ret; + + b = ntohl (bps.value__); + if (b == 0) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Bandwidth suggests delay of infinity (zero bandwidth)\n"); + return GNUNET_TIME_UNIT_FOREVER_REL; + } + ret.rel_value = size * 1000LL / b; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Bandwidth suggests delay of %llu ms for %llu bytes of traffic\n", + (unsigned long long) ret.rel_value, (unsigned long long) size); + return ret; +} + + +/** + * Initialize bandwidth tracker. Note that in addition to the + * 'max_carry_s' limit, we also always allow at least + * GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the + * bytes-per-second limit is so small that within 'max_carry_s' not + * even GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is + * ignored and replaced by GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in + * bytes). + * + * @param av tracker to initialize + * @param bytes_per_second_limit initial limit to assume + * @param max_carry_s maximum number of seconds unused bandwidth + * may accumulate before it expires + */ +void +GNUNET_BANDWIDTH_tracker_init (struct GNUNET_BANDWIDTH_Tracker *av, + struct GNUNET_BANDWIDTH_Value32NBO + bytes_per_second_limit, uint32_t max_carry_s) +{ + av->consumption_since_last_update__ = 0; + av->last_update__ = GNUNET_TIME_absolute_get (); + av->available_bytes_per_s__ = ntohl (bytes_per_second_limit.value__); + av->max_carry_s__ = max_carry_s; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tracker %p initialized with %u Bps and max carry %u\n", av, + (unsigned int) av->available_bytes_per_s__, (unsigned int) max_carry_s); +} + + +/** + * Update the tracker, looking at the current time and + * bandwidth consumption data. + * + * @param av tracker to update + */ +static void +update_tracker (struct GNUNET_BANDWIDTH_Tracker *av) +{ + struct GNUNET_TIME_Absolute now; + uint64_t delta_time; + uint64_t delta_avail; + uint64_t left_bytes; + uint64_t max_carry; + + now = GNUNET_TIME_absolute_get (); + delta_time = now.abs_value - av->last_update__.abs_value; + delta_avail = + (delta_time * ((unsigned long long) av->available_bytes_per_s__) + + 500LL) / 1000LL; + av->consumption_since_last_update__ -= delta_avail; + av->last_update__ = now; + if (av->consumption_since_last_update__ < 0) + { + left_bytes = -av->consumption_since_last_update__; + max_carry = av->available_bytes_per_s__ * av->max_carry_s__; + if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE) + max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE; + if (max_carry > left_bytes) + av->consumption_since_last_update__ = -left_bytes; + else + av->consumption_since_last_update__ = -max_carry; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tracker %p updated, have %u Bps, last update was %llu ms ago\n", av, + (unsigned int) av->available_bytes_per_s__, + (unsigned long long) delta_time); +} + + +/** + * Notify the tracker that a certain number of bytes of bandwidth have + * been consumed. Note that it is legal to consume bytes even if not + * enough bandwidth is available (in that case, + * GNUNET_BANDWIDTH_tracker_get_delay may return non-zero delay values + * even for a size of zero for a while). + * + * @param av tracker to update + * @param size number of bytes consumed + * @return GNUNET_YES if this consumption is above the limit + */ +int +GNUNET_BANDWIDTH_tracker_consume (struct GNUNET_BANDWIDTH_Tracker *av, + ssize_t size) +{ + int64_t nc; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p consumes %d bytes\n", av, + (int) size); + if (size > 0) + { + nc = av->consumption_since_last_update__ + size; + if (nc < av->consumption_since_last_update__) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + av->consumption_since_last_update__ = nc; + update_tracker (av); + if (av->consumption_since_last_update__ > 0) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tracker %p consumption %llu bytes above limit\n", av, + (unsigned long long) av->consumption_since_last_update__); + return GNUNET_YES; + } + } + else + { + av->consumption_since_last_update__ += size; + } + return GNUNET_NO; +} + + +/** + * Compute how long we should wait until consuming 'size' + * bytes of bandwidth in order to stay within the given + * quota. + * + * @param av tracker to query + * @param size number of bytes we would like to consume + * @return time in ms to wait for consumption to be OK + */ +struct GNUNET_TIME_Relative +GNUNET_BANDWIDTH_tracker_get_delay (struct GNUNET_BANDWIDTH_Tracker *av, + size_t size) +{ + struct GNUNET_TIME_Relative ret; + int64_t bytes_needed; + + if (av->available_bytes_per_s__ == 0) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p delay is infinity\n", av); + return GNUNET_TIME_UNIT_FOREVER_REL; + } + update_tracker (av); + bytes_needed = size + av->consumption_since_last_update__; + if (bytes_needed <= 0) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p delay for %u bytes is zero\n", av, + (unsigned int) size); + return GNUNET_TIME_UNIT_ZERO; + } + ret.rel_value = + (1000LL * bytes_needed) / + (unsigned long long) av->available_bytes_per_s__; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p delay for %u bytes is %llu ms\n", + av, (unsigned int) size, (unsigned long long) ret.rel_value); + return ret; +} + + +/** + * Compute how many bytes are available for consumption right now. + * quota. + * + * @param av tracker to query + * @return number of bytes available for consumption right now + */ +int64_t +GNUNET_BANDWIDTH_tracker_get_available (struct GNUNET_BANDWIDTH_Tracker * av) +{ + struct GNUNET_BANDWIDTH_Value32NBO bps; + uint64_t avail; + int64_t used; + + update_tracker (av); + bps = GNUNET_BANDWIDTH_value_init (av->available_bytes_per_s__); + avail = + GNUNET_BANDWIDTH_value_get_available_until (bps, + GNUNET_TIME_absolute_get_duration + (av->last_update__)); + used = av->consumption_since_last_update__; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tracker %p available bandwidth is %lld bytes\n", av, + (long long) (int64_t) (avail - used)); + return (int64_t) (avail - used); +} + + +/** + * Update quota of bandwidth tracker. + * + * @param av tracker to initialize + * @param bytes_per_second_limit new limit to assume + */ +void +GNUNET_BANDWIDTH_tracker_update_quota (struct GNUNET_BANDWIDTH_Tracker *av, + struct GNUNET_BANDWIDTH_Value32NBO + bytes_per_second_limit) +{ + uint32_t old_limit; + uint32_t new_limit; + + new_limit = ntohl (bytes_per_second_limit.value__); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p bandwidth changed to %u Bps\n", av, + (unsigned int) new_limit); + update_tracker (av); + old_limit = av->available_bytes_per_s__; + av->available_bytes_per_s__ = new_limit; + if (old_limit > new_limit) + update_tracker (av); /* maximum excess might be less now */ +} + + +/* end of bandwidth.c */ diff --git a/src/util/bio.c b/src/util/bio.c new file mode 100644 index 0000000..053b8e1 --- /dev/null +++ b/src/util/bio.c @@ -0,0 +1,525 @@ +/* + This file is part of GNUnet. + (C) 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/bio.c + * @brief functions for buffering IO + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_bio_lib.h" +#include "gnunet_disk_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) + +#define BIO_BUFFER_SIZE 65536 + +#define MAX_META_DATA (1024 * 1024) + +/** + * Handle for buffered reading. + */ +struct GNUNET_BIO_ReadHandle +{ + struct GNUNET_DISK_FileHandle *fd; + char *emsg; + char *buffer; + size_t have; + size_t size; + off_t pos; +}; + + +/** + * Open a file for reading. + * + * @param fn file name to be opened + * @return IO handle on success, NULL on error + */ +struct GNUNET_BIO_ReadHandle * +GNUNET_BIO_read_open (const char *fn) +{ + struct GNUNET_DISK_FileHandle *fd; + struct GNUNET_BIO_ReadHandle *h; + + fd = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); + if (NULL == fd) + return NULL; + h = GNUNET_malloc (sizeof (struct GNUNET_BIO_ReadHandle) + BIO_BUFFER_SIZE); + h->buffer = (char *) &h[1]; + h->size = BIO_BUFFER_SIZE; + h->fd = fd; + return h; +} + + +/** + * Close an open file. Reports if any errors reading + * from the file were encountered. + * + * @param h file handle + * @param emsg set to the error message + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h, char **emsg) +{ + int err; + + err = (NULL == h->emsg) ? GNUNET_OK : GNUNET_SYSERR; + if (emsg != NULL) + *emsg = h->emsg; + else + GNUNET_free_non_null (h->emsg); + GNUNET_DISK_file_close (h->fd); + GNUNET_free (h); + return err; +} + + +/** + * Read the contents of a binary file into a buffer. + * + * @param h handle to an open file + * @param what describes what is being read (for error message creation) + * @param result the buffer to write the result to + * @param len the number of bytes to read + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h, const char *what, + void *result, size_t len) +{ + char *dst = result; + size_t min; + size_t pos; + ssize_t ret; + + if (h->emsg != NULL) + return GNUNET_SYSERR; + pos = 0; + do + { + /* first, use buffer */ + min = h->have - h->pos; + if (min > 0) + { + if (min > len - pos) + min = len - pos; + memcpy (&dst[pos], &h->buffer[h->pos], min); + h->pos += min; + pos += min; + } + if (pos == len) + return GNUNET_OK; /* done! */ + GNUNET_assert (h->have == h->pos); + /* fill buffer */ + ret = GNUNET_DISK_file_read (h->fd, h->buffer, h->size); + if (ret == -1) + { + GNUNET_asprintf (&h->emsg, _("Error reading `%s': %s"), what, + STRERROR (errno)); + return GNUNET_SYSERR; + } + if (ret == 0) + { + GNUNET_asprintf (&h->emsg, _("Error reading `%s': %s"), what, + _("End of file")); + return GNUNET_SYSERR; + } + h->pos = 0; + h->have = ret; + } + while (pos < len); /* should always be true */ + return GNUNET_OK; +} + + +/** + * Read the contents of a binary file into a buffer. + * + * @param h handle to an open file + * @param file name of the source file + * @param line line number in the source file + * @param result the buffer to write the result to + * @param len the number of bytes to read + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_BIO_read_fn (struct GNUNET_BIO_ReadHandle *h, const char *file, int line, + void *result, size_t len) +{ + char what[1024]; + + GNUNET_snprintf (what, sizeof (what), "%s:%d", file, line); + return GNUNET_BIO_read (h, what, result, len); +} + + +/** + * Read 0-terminated string from a file. + * + * @param h handle to an open file + * @param what describes what is being read (for error message creation) + * @param result the buffer to store a pointer to the (allocated) string to + * (note that *result could be set to NULL as well) + * @param maxLen maximum allowed length for the string + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h, const char *what, + char **result, size_t maxLen) +{ + char *buf; + uint32_t big; + + if (GNUNET_OK != GNUNET_BIO_read_int32 (h, &big)) + { + GNUNET_free_non_null (h->emsg); + GNUNET_asprintf (&h->emsg, _("Error reading length of string `%s'"), what); + return GNUNET_SYSERR; + } + if (big == 0) + { + *result = NULL; + return GNUNET_OK; + } + if (big > maxLen) + { + GNUNET_asprintf (&h->emsg, _("String `%s' longer than allowed (%u > %u)"), + what, big, maxLen); + return GNUNET_SYSERR; + } + buf = GNUNET_malloc (big); + *result = buf; + buf[--big] = '\0'; + if (big == 0) + return GNUNET_OK; + if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, big)) + { + GNUNET_free (buf); + *result = NULL; + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Read metadata container from a file. + * + * @param h handle to an open file + * @param what describes what is being read (for error message creation) + * @param result the buffer to store a pointer to the (allocated) metadata + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h, const char *what, + struct GNUNET_CONTAINER_MetaData **result) +{ + uint32_t size; + char *buf; + struct GNUNET_CONTAINER_MetaData *meta; + + if (GNUNET_BIO_read_int32 (h, (int32_t *) & size) != GNUNET_OK) + return GNUNET_SYSERR; + if (size == 0) + { + *result = NULL; + return GNUNET_OK; + } + if (size > MAX_META_DATA) + { + GNUNET_asprintf (&h->emsg, + _("Serialized metadata `%s' larger than allowed (%u>%u)"), + what, size, MAX_META_DATA); + return GNUNET_SYSERR; + } + buf = GNUNET_malloc (size); + if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, size)) + { + GNUNET_free (buf); + return GNUNET_SYSERR; + } + meta = GNUNET_CONTAINER_meta_data_deserialize (buf, size); + if (meta == NULL) + { + GNUNET_free (buf); + GNUNET_asprintf (&h->emsg, _("Metadata `%s' failed to deserialize"), what); + return GNUNET_SYSERR; + } + GNUNET_free (buf); + *result = meta; + return GNUNET_OK; +} + + +/** + * Read an (u)int32_t. + * + * @param h hande to open file + * @param file name of the source file + * @param line line number in the source file + * @param i address of 32-bit integer to read + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h, const char *file, + int line, int32_t * i) +{ + int32_t big; + + if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof (int32_t))) + return GNUNET_SYSERR; + *i = ntohl (big); + return GNUNET_OK; +} + + +/** + * Read an (u)int64_t. + * + * @param h hande to open file + * @param file name of the source file + * @param line line number in the source file + * @param i address of 64-bit integer to read + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h, const char *file, + int line, int64_t * i) +{ + int64_t big; + + if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof (int64_t))) + return GNUNET_SYSERR; + *i = GNUNET_ntohll (big); + return GNUNET_OK; +} + + +/** + * Handle for buffered writing. + */ +struct GNUNET_BIO_WriteHandle +{ + struct GNUNET_DISK_FileHandle *fd; + char *buffer; + size_t have; + size_t size; +}; + + +/** + * Open a file for writing. + * + * @param fn file name to be opened + * @return IO handle on success, NULL on error + */ +struct GNUNET_BIO_WriteHandle * +GNUNET_BIO_write_open (const char *fn) +{ + struct GNUNET_DISK_FileHandle *fd; + struct GNUNET_BIO_WriteHandle *h; + + fd = GNUNET_DISK_file_open (fn, + GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE + | GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (NULL == fd) + return NULL; + h = GNUNET_malloc (sizeof (struct GNUNET_BIO_WriteHandle) + BIO_BUFFER_SIZE); + h->buffer = (char *) &h[1]; + h->size = BIO_BUFFER_SIZE; + h->fd = fd; + + return h; +} + + +/** + * Close an open file for writing. + * + * @param h file handle + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h) +{ + ssize_t wrt; + int ret; + + if (NULL == h->fd) + { + ret = GNUNET_SYSERR; + } + else + { + wrt = GNUNET_DISK_file_write (h->fd, h->buffer, h->have); + if (wrt == h->have) + ret = GNUNET_OK; + else + ret = GNUNET_SYSERR; + GNUNET_DISK_file_close (h->fd); + } + GNUNET_free (h); + return ret; +} + + +/** + * Write a buffer to a file. + * + * @param h handle to open file + * @param buffer the data to write + * @param n number of bytes to write + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h, const void *buffer, + size_t n) +{ + const char *src = buffer; + size_t min; + size_t pos; + ssize_t ret; + + if (NULL == h->fd) + return GNUNET_SYSERR; + pos = 0; + do + { + /* first, just use buffer */ + min = h->size - h->have; + if (min > n - pos) + min = n - pos; + memcpy (&h->buffer[h->have], &src[pos], min); + pos += min; + h->have += min; + if (pos == n) + return GNUNET_OK; /* done */ + GNUNET_assert (h->have == h->size); + ret = GNUNET_DISK_file_write (h->fd, h->buffer, h->size); + if (ret != h->size) + { + GNUNET_DISK_file_close (h->fd); + h->fd = NULL; + return GNUNET_SYSERR; /* error */ + } + h->have = 0; + } + while (pos < n); /* should always be true */ + GNUNET_break (0); + return GNUNET_OK; +} + + +/** + * Write a string to a file. + * + * @param h handle to open file + * @param s string to write (can be NULL) + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, const char *s) +{ + uint32_t slen; + + slen = (uint32_t) ((s == NULL) ? 0 : strlen (s) + 1); + if (GNUNET_OK != GNUNET_BIO_write_int32 (h, slen)) + return GNUNET_SYSERR; + if (0 != slen) + return GNUNET_BIO_write (h, s, slen - 1); + return GNUNET_OK; +} + + +/** + * Write metadata container to a file. + * + * @param h handle to open file + * @param m metadata to write + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h, + const struct GNUNET_CONTAINER_MetaData *m) +{ + ssize_t size; + char *buf; + + if (m == NULL) + return GNUNET_BIO_write_int32 (h, 0); + buf = NULL; + size = + GNUNET_CONTAINER_meta_data_serialize (m, &buf, MAX_META_DATA, + GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); + if (size == -1) + { + GNUNET_free (buf); + return GNUNET_SYSERR; + } + if ((GNUNET_OK != GNUNET_BIO_write_int32 (h, (uint32_t) size)) || + (GNUNET_OK != GNUNET_BIO_write (h, buf, size))) + { + GNUNET_free (buf); + return GNUNET_SYSERR; + } + GNUNET_free (buf); + return GNUNET_OK; +} + + +/** + * Write an (u)int32_t. + * + * @param h hande to open file + * @param i 32-bit integer to write + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h, int32_t i) +{ + int32_t big; + + big = htonl (i); + return GNUNET_BIO_write (h, &big, sizeof (int32_t)); +} + + +/** + * Write an (u)int64_t. + * + * @param h hande to open file + * @param i 64-bit integer to write + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h, int64_t i) +{ + int64_t big; + + big = GNUNET_htonll (i); + return GNUNET_BIO_write (h, &big, sizeof (int64_t)); +} + + +/* end of bio.c */ diff --git a/src/util/client.c b/src/util/client.c new file mode 100644 index 0000000..2f09a90 --- /dev/null +++ b/src/util/client.c @@ -0,0 +1,1216 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/client.c + * @brief code for access to services + * @author Christian Grothoff + * + * Generic TCP code for reliable, record-oriented TCP + * connections between clients and service providers. + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_client_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_server_lib.h" +#include "gnunet_scheduler_lib.h" + +#define DEBUG_CLIENT GNUNET_EXTRA_LOGGING + +/** + * How often do we re-try tranmsitting requests before giving up? + * Note that if we succeeded transmitting a request but failed to read + * a response, we do NOT re-try. + */ +#define MAX_ATTEMPTS 50 + +#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) + +/** + * Handle for a transmission request. + */ +struct GNUNET_CLIENT_TransmitHandle +{ + /** + * Connection state. + */ + struct GNUNET_CLIENT_Connection *sock; + + /** + * Function to call to get the data for transmission. + */ + GNUNET_CONNECTION_TransmitReadyNotify notify; + + /** + * Closure for notify. + */ + void *notify_cls; + + /** + * Handle to the transmission with the underlying + * connection. + */ + struct GNUNET_CONNECTION_TransmitHandle *th; + + /** + * If we are re-trying and are delaying to do so, + * handle to the scheduled task managing the delay. + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * Timeout for the operation overall. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Number of bytes requested. + */ + size_t size; + + /** + * Are we allowed to re-try to connect without telling + * the user (of this API) about the connection troubles? + */ + int auto_retry; + + /** + * Number of attempts left for transmitting the request. We may + * fail the first time (say because the service is not yet up), in + * which case (if auto_retry is set) we wait a bit and re-try + * (timeout permitting). + */ + unsigned int attempts_left; + +}; + + +/** + * Context for processing + * "GNUNET_CLIENT_transmit_and_get_response" requests. + */ +struct TransmitGetResponseContext +{ + /** + * Client handle. + */ + struct GNUNET_CLIENT_Connection *sock; + + /** + * Message to transmit; do not free, allocated + * right after this struct. + */ + const struct GNUNET_MessageHeader *hdr; + + /** + * Timeout to use. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Function to call when done. + */ + GNUNET_CLIENT_MessageHandler rn; + + /** + * Closure for "rn". + */ + void *rn_cls; +}; + +/** + * Struct to refer to a GNUnet TCP connection. + * This is more than just a socket because if the server + * drops the connection, the client automatically tries + * to reconnect (and for that needs connection information). + */ +struct GNUNET_CLIENT_Connection +{ + + /** + * the socket handle, NULL if not live + */ + struct GNUNET_CONNECTION_Handle *sock; + + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Name of the service we interact with. + */ + char *service_name; + + /** + * Context of a transmit_and_get_response operation, NULL + * if no such operation is pending. + */ + struct TransmitGetResponseContext *tag; + + /** + * Handler for current receiver task. + */ + GNUNET_CLIENT_MessageHandler receiver_handler; + + /** + * Closure for receiver_handler. + */ + void *receiver_handler_cls; + + /** + * Handle for a pending transmission request, NULL if there is + * none pending. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Handler for service test completion (NULL unless in service_test) + */ + GNUNET_SCHEDULER_Task test_cb; + + /** + * Deadline for calling 'test_cb'. + */ + struct GNUNET_TIME_Absolute test_deadline; + + /** + * If we are re-trying and are delaying to do so, + * handle to the scheduled task managing the delay. + */ + GNUNET_SCHEDULER_TaskIdentifier receive_task; + + /** + * Closure for test_cb (NULL unless in service_test) + */ + void *test_cb_cls; + + /** + * Buffer for received message. + */ + char *received_buf; + + /** + * Timeout for receiving a response (absolute time). + */ + struct GNUNET_TIME_Absolute receive_timeout; + + /** + * Current value for our incremental back-off (for + * connect re-tries). + */ + struct GNUNET_TIME_Relative back_off; + + /** + * Number of bytes in received_buf that are valid. + */ + size_t received_pos; + + /** + * Size of received_buf. + */ + unsigned int received_size; + + /** + * Do we have a complete response in received_buf? + */ + int msg_complete; + + /** + * Are we currently busy doing receive-processing? + * GNUNET_YES if so, GNUNET_NO if not. + */ + int in_receive; + + /** + * How often have we tried to connect? + */ + unsigned int attempts; + +}; + + +/** + * Try to connect to the service. + * + * @param service_name name of service to connect to + * @param cfg configuration to use + * @param attempt counter used to alternate between IP and UNIX domain sockets + * @return NULL on error + */ +static struct GNUNET_CONNECTION_Handle * +do_connect (const char *service_name, + const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int attempt) +{ + struct GNUNET_CONNECTION_Handle *sock; + char *hostname; + char *unixpath; + unsigned long long port; + + sock = NULL; +#if AF_UNIX + if (0 == (attempt % 2)) + { + /* on even rounds, try UNIX */ + unixpath = NULL; + if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) /* We have a non-NULL unixpath, does that mean it's valid? */ + { + sock = GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath); + if (sock != NULL) + { +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to unixpath `%s'!\n", + unixpath); +#endif + GNUNET_free (unixpath); + return sock; + } + } + GNUNET_free_non_null (unixpath); + } +#endif + + if (GNUNET_YES == + GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) + { + if ((GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port)) + || (port > 65535) || + (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME", + &hostname))) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _ + ("Could not determine valid hostname and port for service `%s' from configuration.\n"), + service_name); + return NULL; + } + if (0 == strlen (hostname)) + { + GNUNET_free (hostname); + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Need a non-empty hostname for service `%s'.\n"), service_name); + return NULL; + } + } + else + { + /* unspecified means 0 (disabled) */ + port = 0; + hostname = NULL; + } + if (port == 0) + { +#if AF_UNIX + if (0 != (attempt % 2)) + { + /* try UNIX */ + unixpath = NULL; + if ((GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", + &unixpath)) && + (0 < strlen (unixpath))) + { + sock = + GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath); + if (sock != NULL) + { + GNUNET_free (unixpath); + GNUNET_free_non_null (hostname); + return sock; + } + } + GNUNET_free_non_null (unixpath); + } +#endif +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Port is 0 for service `%s', UNIXPATH did not work, returning NULL!\n", + service_name); +#endif + GNUNET_free_non_null (hostname); + return NULL; + } + + sock = GNUNET_CONNECTION_create_from_connect (cfg, hostname, port); + GNUNET_free (hostname); + return sock; +} + + +/** + * Get a connection with a service. + * + * @param service_name name of the service + * @param cfg configuration to use + * @return NULL on error (service unknown to configuration) + */ +struct GNUNET_CLIENT_Connection * +GNUNET_CLIENT_connect (const char *service_name, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_CLIENT_Connection *ret; + struct GNUNET_CONNECTION_Handle *sock; + + sock = do_connect (service_name, cfg, 0); + ret = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_Connection)); + ret->attempts = 1; + ret->sock = sock; + ret->service_name = GNUNET_strdup (service_name); + ret->cfg = cfg; + ret->back_off = GNUNET_TIME_UNIT_MILLISECONDS; + return ret; +} + + +/** + * Destroy connection with the service. This will automatically + * cancel any pending "receive" request (however, the handler will + * *NOT* be called, not even with a NULL message). Any pending + * transmission request will also be cancelled UNLESS the callback for + * the transmission request has already been called, in which case the + * transmission 'finish_pending_write' argument determines whether or + * not the write is guaranteed to complete before the socket is fully + * destroyed (unless, of course, there is an error with the server in + * which case the message may still be lost). + * + * @param finish_pending_write should a transmission already passed to the + * handle be completed? + * @param sock handle to the service connection + */ +void +GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *sock, + int finish_pending_write) +{ + if (sock->in_receive == GNUNET_YES) + { + GNUNET_CONNECTION_receive_cancel (sock->sock); + sock->in_receive = GNUNET_NO; + } + if (sock->th != NULL) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (sock->th); + sock->th = NULL; + } + if (NULL != sock->sock) + { + GNUNET_CONNECTION_destroy (sock->sock, finish_pending_write); + sock->sock = NULL; + } + if (sock->receive_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (sock->receive_task); + sock->receive_task = GNUNET_SCHEDULER_NO_TASK; + } + if (sock->tag != NULL) + { + GNUNET_free (sock->tag); + sock->tag = NULL; + } + sock->receiver_handler = NULL; + GNUNET_array_grow (sock->received_buf, sock->received_size, 0); + GNUNET_free (sock->service_name); + GNUNET_free (sock); +} + + +/** + * Check if message is complete + */ +static void +check_complete (struct GNUNET_CLIENT_Connection *conn) +{ + if ((conn->received_pos >= sizeof (struct GNUNET_MessageHeader)) && + (conn->received_pos >= + ntohs (((const struct GNUNET_MessageHeader *) conn->received_buf)-> + size))) + conn->msg_complete = GNUNET_YES; +} + + +/** + * Callback function for data received from the network. Note that + * both "available" and "errCode" would be 0 if the read simply timed out. + * + * @param cls closure + * @param buf pointer to received data + * @param available number of bytes availabe in "buf", + * possibly 0 (on errors) + * @param addr address of the sender + * @param addrlen size of addr + * @param errCode value of errno (on errors receiving) + */ +static void +receive_helper (void *cls, const void *buf, size_t available, + const struct sockaddr *addr, socklen_t addrlen, int errCode) +{ + struct GNUNET_CLIENT_Connection *conn = cls; + struct GNUNET_TIME_Relative remaining; + GNUNET_CLIENT_MessageHandler receive_handler; + void *receive_handler_cls; + + GNUNET_assert (conn->msg_complete == GNUNET_NO); + conn->in_receive = GNUNET_NO; + if ((available == 0) || (conn->sock == NULL) || (errCode != 0)) + { + /* signal timeout! */ +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Timeout in receive_helper, available %u, conn->sock %s, errCode `%s'\n", + (unsigned int) available, conn->sock == NULL ? "NULL" : "non-NULL", + STRERROR (errCode)); +#endif + if (NULL != (receive_handler = conn->receiver_handler)) + { + receive_handler_cls = conn->receiver_handler_cls; + conn->receiver_handler = NULL; + receive_handler (receive_handler_cls, NULL); + } + return; + } + + /* FIXME: optimize for common fast case where buf contains the + * entire message and we need no copying... */ + + + /* slow path: append to array */ + if (conn->received_size < conn->received_pos + available) + GNUNET_array_grow (conn->received_buf, conn->received_size, + conn->received_pos + available); + memcpy (&conn->received_buf[conn->received_pos], buf, available); + conn->received_pos += available; + check_complete (conn); + /* check for timeout */ + remaining = GNUNET_TIME_absolute_get_remaining (conn->receive_timeout); + if (remaining.rel_value == 0) + { + /* signal timeout! */ + if (NULL != conn->receiver_handler) + conn->receiver_handler (conn->receiver_handler_cls, NULL); + return; + } + /* back to receive -- either for more data or to call callback! */ + GNUNET_CLIENT_receive (conn, conn->receiver_handler, + conn->receiver_handler_cls, remaining); +} + + +/** + * Continuation to call the receive callback. + * + * @param cls our handle to the client connection + * @param tc scheduler context + */ +static void +receive_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CLIENT_Connection *sock = cls; + GNUNET_CLIENT_MessageHandler handler = sock->receiver_handler; + const struct GNUNET_MessageHeader *cmsg = + (const struct GNUNET_MessageHeader *) sock->received_buf; + void *handler_cls = sock->receiver_handler_cls; + uint16_t msize = ntohs (cmsg->size); + char mbuf[msize]; + struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) mbuf; + +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u and size %u\n", + ntohs (cmsg->type), msize); +#endif + sock->receive_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (GNUNET_YES == sock->msg_complete); + GNUNET_assert (sock->received_pos >= msize); + memcpy (msg, cmsg, msize); + memmove (sock->received_buf, &sock->received_buf[msize], + sock->received_pos - msize); + sock->received_pos -= msize; + sock->msg_complete = GNUNET_NO; + sock->receiver_handler = NULL; + check_complete (sock); + if (handler != NULL) + handler (handler_cls, msg); +} + + +/** + * Read from the service. + * + * @param sock the service + * @param handler function to call with the message + * @param handler_cls closure for handler + * @param timeout how long to wait until timing out + */ +void +GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *sock, + GNUNET_CLIENT_MessageHandler handler, void *handler_cls, + struct GNUNET_TIME_Relative timeout) +{ + if (sock->sock == NULL) + { + /* already disconnected, fail instantly! */ + GNUNET_break (0); /* this should not happen in well-written code! */ + if (NULL != handler) + handler (handler_cls, NULL); + return; + } + sock->receiver_handler = handler; + sock->receiver_handler_cls = handler_cls; + sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); + if (GNUNET_YES == sock->msg_complete) + { + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->receive_task); + sock->receive_task = GNUNET_SCHEDULER_add_now (&receive_task, sock); + } + else + { + GNUNET_assert (sock->in_receive == GNUNET_NO); + sock->in_receive = GNUNET_YES; +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, "calling GNUNET_CONNECTION_receive\n"); +#endif + GNUNET_CONNECTION_receive (sock->sock, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, + timeout, &receive_helper, sock); + } +} + + +/** + * Report service unavailable. + */ +static void +service_test_error (GNUNET_SCHEDULER_Task task, void *task_cls) +{ + GNUNET_SCHEDULER_add_continuation (task, task_cls, + GNUNET_SCHEDULER_REASON_TIMEOUT); +} + + +/** + * Receive confirmation from test, service is up. + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_CLIENT_Connection *conn = cls; + + /* We may want to consider looking at the reply in more + * detail in the future, for example, is this the + * correct service? FIXME! */ + if (msg != NULL) + { +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received confirmation that service is running.\n"); +#endif + GNUNET_SCHEDULER_add_continuation (conn->test_cb, conn->test_cb_cls, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + } + else + { + service_test_error (conn->test_cb, conn->test_cb_cls); + } + GNUNET_CLIENT_disconnect (conn, GNUNET_NO); +} + + +/** + * Send the 'TEST' message to the service. If successful, prepare to + * receive the reply. + * + * @param cls the 'struct GNUNET_CLIENT_Connection' of the connection to test + * @param size number of bytes available in buf + * @param buf where to write the message + * @return number of bytes written to buf + */ +static size_t +write_test (void *cls, size_t size, void *buf) +{ + struct GNUNET_CLIENT_Connection *conn = cls; + struct GNUNET_MessageHeader *msg; + + if (size < sizeof (struct GNUNET_MessageHeader)) + { +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, _("Failure to transmit TEST request.\n")); +#endif + service_test_error (conn->test_cb, conn->test_cb_cls); + GNUNET_CLIENT_disconnect (conn, GNUNET_NO); + return 0; /* client disconnected */ + } +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "TEST"); +#endif + msg = (struct GNUNET_MessageHeader *) buf; + msg->type = htons (GNUNET_MESSAGE_TYPE_TEST); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + GNUNET_CLIENT_receive (conn, &confirm_handler, conn, + GNUNET_TIME_absolute_get_remaining + (conn->test_deadline)); + return sizeof (struct GNUNET_MessageHeader); +} + + +/** + * Test if the service is running. If we are given a UNIXPATH or a local address, + * we do this NOT by trying to connect to the service, but by trying to BIND to + * the same port. If the BIND fails, we know the service is running. + * + * @param service name of the service to wait for + * @param cfg configuration to use + * @param timeout how long to wait at most + * @param task task to run if service is running + * (reason will be "PREREQ_DONE" (service running) + * or "TIMEOUT" (service not known to be running)) + * @param task_cls closure for task + */ +void +GNUNET_CLIENT_service_test (const char *service, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TIME_Relative timeout, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ + char *hostname; + unsigned long long port; + struct GNUNET_NETWORK_Handle *sock; + struct GNUNET_CLIENT_Connection *conn; + +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, "Testing if service `%s' is running.\n", + service); +#endif +#ifdef AF_UNIX + { + /* probe UNIX support */ + struct sockaddr_un s_un; + size_t slen; + char *unixpath; + + unixpath = NULL; + if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) /* We have a non-NULL unixpath, does that mean it's valid? */ + { + if (strlen (unixpath) >= sizeof (s_un.sun_path)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, + sizeof (s_un.sun_path)); + } + else + { + sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); + if (sock != NULL) + { + memset (&s_un, 0, sizeof (s_un)); + s_un.sun_family = AF_UNIX; + slen = strlen (unixpath) + 1; + if (slen >= sizeof (s_un.sun_path)) + slen = sizeof (s_un.sun_path) - 1; + memcpy (s_un.sun_path, unixpath, slen); + s_un.sun_path[slen] = '\0'; + slen = sizeof (struct sockaddr_un); +#if LINUX + s_un.sun_path[0] = '\0'; +#endif +#if HAVE_SOCKADDR_IN_SIN_LEN + s_un.sun_len = (u_char) slen; +#endif + if (GNUNET_OK != + GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_un, + slen)) + { + /* failed to bind => service must be running */ + GNUNET_free (unixpath); + (void) GNUNET_NETWORK_socket_close (sock); + GNUNET_SCHEDULER_add_continuation (task, task_cls, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + return; + } + (void) GNUNET_NETWORK_socket_close (sock); + } + /* let's try IP */ + } + } + GNUNET_free_non_null (unixpath); + } +#endif + + hostname = NULL; + if ((GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, service, "PORT", &port)) || + (port > 65535) || + (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, service, "HOSTNAME", + &hostname))) + { + /* UNIXPATH failed (if possible) AND IP failed => error */ + service_test_error (task, task_cls); + return; + } + + if (0 == strcmp ("localhost", hostname) +#if !LINUX + && 0 +#endif + ) + { + /* can test using 'bind' */ + struct sockaddr_in s_in; + + memset (&s_in, 0, sizeof (s_in)); +#if HAVE_SOCKADDR_IN_SIN_LEN + s_in.sin_len = sizeof (struct sockaddr_in); +#endif + s_in.sin_family = AF_INET; + s_in.sin_port = htons (port); + + sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); + if (sock != NULL) + { + if (GNUNET_OK != + GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in, + sizeof (s_in))) + { + /* failed to bind => service must be running */ + GNUNET_free (hostname); + (void) GNUNET_NETWORK_socket_close (sock); + GNUNET_SCHEDULER_add_continuation (task, task_cls, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + return; + } + (void) GNUNET_NETWORK_socket_close (sock); + } + } + + if (0 == strcmp ("ip6-localhost", hostname) +#if !LINUX + && 0 +#endif + ) + { + /* can test using 'bind' */ + struct sockaddr_in6 s_in6; + + memset (&s_in6, 0, sizeof (s_in6)); +#if HAVE_SOCKADDR_IN_SIN_LEN + s_in6.sin6_len = sizeof (struct sockaddr_in6); +#endif + s_in6.sin6_family = AF_INET6; + s_in6.sin6_port = htons (port); + + sock = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0); + if (sock != NULL) + { + if (GNUNET_OK != + GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in6, + sizeof (s_in6))) + { + /* failed to bind => service must be running */ + GNUNET_free (hostname); + (void) GNUNET_NETWORK_socket_close (sock); + GNUNET_SCHEDULER_add_continuation (task, task_cls, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + return; + } + (void) GNUNET_NETWORK_socket_close (sock); + } + } + + if (((0 == strcmp ("localhost", hostname)) || + (0 == strcmp ("ip6-localhost", hostname))) +#if !LINUX + && 0 +#endif + ) + { + /* all binds succeeded => claim service not running right now */ + GNUNET_free_non_null (hostname); + service_test_error (task, task_cls); + return; + } + GNUNET_free_non_null (hostname); + + /* non-localhost, try 'connect' method */ + conn = GNUNET_CLIENT_connect (service, cfg); + if (conn == NULL) + { + LOG (GNUNET_ERROR_TYPE_INFO, + _("Could not connect to service `%s', must not be running.\n"), + service); + service_test_error (task, task_cls); + return; + } + conn->test_cb = task; + conn->test_cb_cls = task_cls; + conn->test_deadline = GNUNET_TIME_relative_to_absolute (timeout); + + if (NULL == + GNUNET_CLIENT_notify_transmit_ready (conn, + sizeof (struct GNUNET_MessageHeader), + timeout, GNUNET_YES, &write_test, + conn)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Failure to transmit request to service `%s'\n"), service); + service_test_error (task, task_cls); + GNUNET_CLIENT_disconnect (conn, GNUNET_NO); + return; + } +} + + +/** + * Connection notifies us about failure or success of + * a transmission request. Either pass it on to our + * user or, if possible, retry. + * + * @param cls our "struct GNUNET_CLIENT_TransmissionHandle" + * @param size number of bytes available for transmission + * @param buf where to write them + * @return number of bytes written to buf + */ +static size_t +client_notify (void *cls, size_t size, void *buf); + + +/** + * This task is run if we should re-try connection to the + * service after a while. + * + * @param cls our "struct GNUNET_CLIENT_TransmitHandle" of the request + * @param tc unused + */ +static void +client_delayed_retry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CLIENT_TransmitHandle *th = cls; + struct GNUNET_TIME_Relative delay; + + th->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed due to shutdown.\n"); +#endif + th->sock->th = NULL; + th->notify (th->notify_cls, 0, NULL); + GNUNET_free (th); + return; + } + th->sock->sock = + do_connect (th->sock->service_name, th->sock->cfg, th->sock->attempts++); + if (NULL == th->sock->sock) + { + /* could happen if we're out of sockets */ + delay = + GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining + (th->timeout), th->sock->back_off); + th->sock->back_off = + GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply + (th->sock->back_off, 2), + GNUNET_TIME_UNIT_SECONDS); +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmission failed %u times, trying again in %llums.\n", + MAX_ATTEMPTS - th->attempts_left, + (unsigned long long) delay.rel_value); +#endif + th->reconnect_task = + GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th); + return; + } + th->th = + GNUNET_CONNECTION_notify_transmit_ready (th->sock->sock, th->size, + GNUNET_TIME_absolute_get_remaining + (th->timeout), &client_notify, + th); + if (th->th == NULL) + { + GNUNET_break (0); + th->sock->th = NULL; + th->notify (th->notify_cls, 0, NULL); + GNUNET_free (th); + return; + } +} + + +/** + * Connection notifies us about failure or success of a transmission + * request. Either pass it on to our user or, if possible, retry. + * + * @param cls our "struct GNUNET_CLIENT_TransmissionHandle" + * @param size number of bytes available for transmission + * @param buf where to write them + * @return number of bytes written to buf + */ +static size_t +client_notify (void *cls, size_t size, void *buf) +{ + struct GNUNET_CLIENT_TransmitHandle *th = cls; + size_t ret; + struct GNUNET_TIME_Relative delay; + + th->th = NULL; + th->sock->th = NULL; + if (buf == NULL) + { + delay = GNUNET_TIME_absolute_get_remaining (th->timeout); + delay.rel_value /= 2; + if ((0 != + (GNUNET_SCHEDULER_REASON_SHUTDOWN & GNUNET_SCHEDULER_get_reason ())) || + (GNUNET_YES != th->auto_retry) || (0 == --th->attempts_left) || + (delay.rel_value < 1)) + { +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmission failed %u times, giving up.\n", + MAX_ATTEMPTS - th->attempts_left); +#endif + GNUNET_break (0 == th->notify (th->notify_cls, 0, NULL)); + GNUNET_free (th); + return 0; + } + /* auto-retry */ +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect to `%s', automatically trying again.\n", + th->sock->service_name); +#endif + GNUNET_CONNECTION_destroy (th->sock->sock, GNUNET_NO); + th->sock->sock = NULL; + delay = GNUNET_TIME_relative_min (delay, th->sock->back_off); + th->sock->back_off = + GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply + (th->sock->back_off, 2), + GNUNET_TIME_UNIT_SECONDS); +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmission failed %u times, trying again in %llums.\n", + MAX_ATTEMPTS - th->attempts_left, + (unsigned long long) delay.rel_value); +#endif + th->sock->th = th; + th->reconnect_task = + GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th); + return 0; + } + GNUNET_assert (size >= th->size); + ret = th->notify (th->notify_cls, size, buf); + GNUNET_free (th); + return ret; +} + + +/** + * Ask the client to call us once the specified number of bytes + * are free in the transmission buffer. May call the notify + * method immediately if enough space is available. + * + * @param sock connection to the service + * @param size number of bytes to send + * @param timeout after how long should we give up (and call + * notify with buf NULL and size 0)? + * @param auto_retry if the connection to the service dies, should we + * automatically re-connect and retry (within the timeout period) + * or should we immediately fail in this case? Pass GNUNET_YES + * if the caller does not care about temporary connection errors, + * for example because the protocol is stateless + * @param notify function to call + * @param notify_cls closure for notify + * @return NULL if our buffer will never hold size bytes, + * a handle if the notify callback was queued (can be used to cancel) + */ +struct GNUNET_CLIENT_TransmitHandle * +GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *sock, + size_t size, + struct GNUNET_TIME_Relative timeout, + int auto_retry, + GNUNET_CONNECTION_TransmitReadyNotify + notify, void *notify_cls) +{ + struct GNUNET_CLIENT_TransmitHandle *th; + + if (NULL != sock->th) + { + /* If this breaks, you most likley called this function twice without waiting + * for completion or canceling the request */ + GNUNET_break (0); + return NULL; + } + th = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_TransmitHandle)); + th->sock = sock; + th->size = size; + th->timeout = GNUNET_TIME_relative_to_absolute (timeout); + th->auto_retry = auto_retry; + th->notify = notify; + th->notify_cls = notify_cls; + th->attempts_left = MAX_ATTEMPTS; + sock->th = th; + if (sock->sock == NULL) + { + th->reconnect_task = + GNUNET_SCHEDULER_add_delayed (sock->back_off, &client_delayed_retry, + th); + + } + else + { + th->th = + GNUNET_CONNECTION_notify_transmit_ready (sock->sock, size, timeout, + &client_notify, th); + if (NULL == th->th) + { + GNUNET_break (0); + GNUNET_free (th); + sock->th = NULL; + return NULL; + } + } + return th; +} + + +/** + * Cancel a request for notification. + * + * @param th handle from the original request. + */ +void +GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle + *th) +{ + if (th->reconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_assert (NULL == th->th); + GNUNET_SCHEDULER_cancel (th->reconnect_task); + th->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + else + { + GNUNET_assert (NULL != th->th); + GNUNET_CONNECTION_notify_transmit_ready_cancel (th->th); + } + th->sock->th = NULL; + GNUNET_free (th); +} + + +/** + * Function called to notify a client about the socket + * begin ready to queue the message. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure of type "struct TransmitGetResponseContext*" + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_for_response (void *cls, size_t size, void *buf) +{ + struct TransmitGetResponseContext *tc = cls; + uint16_t msize; + + tc->sock->tag = NULL; + msize = ntohs (tc->hdr->size); + if (NULL == buf) + { +#if DEBUG_CLIENT + LOG (GNUNET_ERROR_TYPE_DEBUG, + _("Could not submit request, not expecting to receive a response.\n")); +#endif + if (NULL != tc->rn) + tc->rn (tc->rn_cls, NULL); + GNUNET_free (tc); + return 0; + } + GNUNET_assert (size >= msize); + memcpy (buf, tc->hdr, msize); + GNUNET_CLIENT_receive (tc->sock, tc->rn, tc->rn_cls, + GNUNET_TIME_absolute_get_remaining (tc->timeout)); + GNUNET_free (tc); + return msize; +} + + +/** + * Convenience API that combines sending a request + * to the service and waiting for a response. + * If either operation times out, the callback + * will be called with a "NULL" response (in which + * case the connection should probably be destroyed). + * + * @param sock connection to use + * @param hdr message to transmit + * @param timeout when to give up (for both transmission + * and for waiting for a response) + * @param auto_retry if the connection to the service dies, should we + * automatically re-connect and retry (within the timeout period) + * or should we immediately fail in this case? Pass GNUNET_YES + * if the caller does not care about temporary connection errors, + * for example because the protocol is stateless + * @param rn function to call with the response + * @param rn_cls closure for rn + * @return GNUNET_OK on success, GNUNET_SYSERR if a request + * is already pending + */ +int +GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *sock, + const struct GNUNET_MessageHeader *hdr, + struct GNUNET_TIME_Relative timeout, + int auto_retry, + GNUNET_CLIENT_MessageHandler rn, + void *rn_cls) +{ + struct TransmitGetResponseContext *tc; + uint16_t msize; + + if (NULL != sock->th) + return GNUNET_SYSERR; + GNUNET_assert (sock->tag == NULL); + msize = ntohs (hdr->size); + tc = GNUNET_malloc (sizeof (struct TransmitGetResponseContext) + msize); + tc->sock = sock; + tc->hdr = (const struct GNUNET_MessageHeader *) &tc[1]; + memcpy (&tc[1], hdr, msize); + tc->timeout = GNUNET_TIME_relative_to_absolute (timeout); + tc->rn = rn; + tc->rn_cls = rn_cls; + if (NULL == + GNUNET_CLIENT_notify_transmit_ready (sock, msize, timeout, auto_retry, + &transmit_for_response, tc)) + { + GNUNET_break (0); + GNUNET_free (tc); + return GNUNET_SYSERR; + } + sock->tag = tc; + return GNUNET_OK; +} + + + +/* end of client.c */ diff --git a/src/util/common_allocation.c b/src/util/common_allocation.c new file mode 100644 index 0000000..5e1f75e --- /dev/null +++ b/src/util/common_allocation.c @@ -0,0 +1,359 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/common_allocation.c + * @brief wrapper around malloc/free + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#ifndef INT_MAX +#define INT_MAX 0x7FFFFFFF +#endif + +#if 0 +#define W32_MEM_LIMIT 200000000 +#endif + +#ifdef W32_MEM_LIMIT +static LONG mem_used = 0; +#endif + +/** + * Allocate memory. Checks the return value, aborts if no more + * memory is available. + * + * @param size how many bytes of memory to allocate, do NOT use + * this function (or GNUNET_malloc) to allocate more than several MB + * of memory, if you are possibly needing a very large chunk use + * GNUNET_xmalloc_unchecked_ instead. + * @param filename where in the code was the call to GNUNET_malloc + * @param linenumber where in the code was the call to GNUNET_malloc + * @return pointer to size bytes of memory + */ +void * +GNUNET_xmalloc_ (size_t size, const char *filename, int linenumber) +{ + void *ret; + + /* As a security precaution, we generally do not allow very large + * allocations using the default 'GNUNET_malloc' macro */ + GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber); + ret = GNUNET_xmalloc_unchecked_ (size, filename, linenumber); + if (ret == NULL) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc"); + GNUNET_abort (); + } + return ret; +} + + +/** + * Allocate and initialize memory. Checks the return value, aborts if no more + * memory is available. Don't use GNUNET_xmemdup_ directly. Use the + * GNUNET_memdup macro. + * + * @param buf buffer to initialize from (must contain size bytes) + * @param size number of bytes to allocate + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + * @return allocated memory, never NULL + */ +void * +GNUNET_xmemdup_ (const void *buf, size_t size, const char *filename, + int linenumber) +{ + void *ret; + + /* As a security precaution, we generally do not allow very large + * allocations here */ + GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber); +#ifdef W32_MEM_LIMIT + size += sizeof (size_t); + if (mem_used + size > W32_MEM_LIMIT) + return NULL; +#endif + GNUNET_assert_at (size < INT_MAX, filename, linenumber); + ret = malloc (size); + if (ret == NULL) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc"); + GNUNET_abort (); + } +#ifdef W32_MEM_LIMIT + *((size_t *) ret) = size; + ret = &((size_t *) ret)[1]; + mem_used += size; +#endif + memcpy (ret, buf, size); + return ret; +} + + + +/** + * Wrapper around malloc. Allocates size bytes of memory. + * The memory will be zero'ed out. + * + * @param size the number of bytes to allocate + * @param filename where in the code was the call to GNUNET_malloc_large + * @param linenumber where in the code was the call to GNUNET_malloc_large + * @return pointer to size bytes of memory, NULL if we do not have enough memory + */ +void * +GNUNET_xmalloc_unchecked_ (size_t size, const char *filename, int linenumber) +{ + void *result; + +#ifdef W32_MEM_LIMIT + size += sizeof (size_t); + if (mem_used + size > W32_MEM_LIMIT) + return NULL; +#endif + + result = malloc (size); + if (result == NULL) + return NULL; + memset (result, 0, size); + +#ifdef W32_MEM_LIMIT + *((size_t *) result) = size; + result = &((size_t *) result)[1]; + mem_used += size; +#endif + + return result; +} + + +/** + * Reallocate memory. Checks the return value, aborts if no more + * memory is available. + * + * @param ptr the pointer to reallocate + * @param n how many bytes of memory to allocate + * @param filename where in the code was the call to GNUNET_realloc + * @param linenumber where in the code was the call to GNUNET_realloc + * @return pointer to size bytes of memory + */ +void * +GNUNET_xrealloc_ (void *ptr, size_t n, const char *filename, int linenumber) +{ +#ifdef W32_MEM_LIMIT + n += sizeof (size_t); + ptr = &((size_t *) ptr)[-1]; + mem_used = mem_used - *((size_t *) ptr) + n; +#endif + ptr = realloc (ptr, n); + if ((NULL == ptr) && (n > 0)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "realloc"); + GNUNET_abort (); + } +#ifdef W32_MEM_LIMIT + ptr = &((size_t *) ptr)[1]; +#endif + return ptr; +} + + +/** + * Free memory. Merely a wrapper for the case that we + * want to keep track of allocations. + * + * @param ptr the pointer to free + * @param filename where in the code was the call to GNUNET_array_grow + * @param linenumber where in the code was the call to GNUNET_array_grow + */ +void +GNUNET_xfree_ (void *ptr, const char *filename, int linenumber) +{ + GNUNET_assert_at (ptr != NULL, filename, linenumber); +#ifdef W32_MEM_LIMIT + ptr = &((size_t *) ptr)[-1]; + mem_used -= *((size_t *) ptr); +#endif + free (ptr); +} + +/** + * Dup a string (same semantics as strdup). + * + * @param str the string to dup + * @param filename where in the code was the call to GNUNET_strdup + * @param linenumber where in the code was the call to GNUNET_strdup + * @return strdup(str) + */ +char * +GNUNET_xstrdup_ (const char *str, const char *filename, int linenumber) +{ + char *res; + + GNUNET_assert_at (str != NULL, filename, linenumber); + res = GNUNET_xmalloc_ (strlen (str) + 1, filename, linenumber); + memcpy (res, str, strlen (str) + 1); + return res; +} + + +/** + * Dup partially a string (same semantics as strndup). + * + * @param str the string to dup + * @param len the length of the string to dup + * @param filename where in the code was the call to GNUNET_strndup + * @param linenumber where in the code was the call to GNUNET_strndup + * @return strndup(str,len) + */ +char * +GNUNET_xstrndup_ (const char *str, size_t len, const char *filename, + int linenumber) +{ + char *res; + + GNUNET_assert_at (str != NULL, filename, linenumber); + len = GNUNET_MIN (len, strlen (str)); + res = GNUNET_xmalloc_ (len + 1, filename, linenumber); + memcpy (res, str, len); + res[len] = '\0'; + return res; +} + + +/** + * Grow an array. Grows old by (*oldCount-newCount)*elementSize bytes + * and sets *oldCount to newCount. + * + * @param old address of the pointer to the array + * *old may be NULL + * @param elementSize the size of the elements of the array + * @param oldCount address of the number of elements in the *old array + * @param newCount number of elements in the new array, may be 0 + * @param filename where in the code was the call to GNUNET_array_grow + * @param linenumber where in the code was the call to GNUNET_array_grow + */ +void +GNUNET_xgrow_ (void **old, size_t elementSize, unsigned int *oldCount, + unsigned int newCount, const char *filename, int linenumber) +{ + void *tmp; + size_t size; + + GNUNET_assert_at (INT_MAX / elementSize > newCount, filename, linenumber); + size = newCount * elementSize; + if (size == 0) + { + tmp = NULL; + } + else + { + tmp = GNUNET_xmalloc_ (size, filename, linenumber); + memset (tmp, 0, size); /* client code should not rely on this, though... */ + if (*oldCount > newCount) + *oldCount = newCount; /* shrink is also allowed! */ + memcpy (tmp, *old, elementSize * (*oldCount)); + } + + if (*old != NULL) + { + GNUNET_xfree_ (*old, filename, linenumber); + } + *old = tmp; + *oldCount = newCount; +} + + +/** + * Like asprintf, just portable. + * + * @param buf set to a buffer of sufficient size (allocated, caller must free) + * @param format format string (see printf, fprintf, etc.) + * @param ... data for format string + * @return number of bytes in "*buf" excluding 0-termination + */ +int +GNUNET_asprintf (char **buf, const char *format, ...) +{ + int ret; + va_list args; + + va_start (args, format); + ret = VSNPRINTF (NULL, 0, format, args); + va_end (args); + *buf = GNUNET_malloc (ret + 1); + va_start (args, format); + ret = VSPRINTF (*buf, format, args); + va_end (args); + return ret; +} + + +/** + * Like snprintf, just aborts if the buffer is of insufficient size. + * + * @param buf pointer to buffer that is written to + * @param size number of bytes in buf + * @param format format strings + * @param ... data for format string + * @return number of bytes written to buf or negative value on error + */ +int +GNUNET_snprintf (char *buf, size_t size, const char *format, ...) +{ + int ret; + va_list args; + + va_start (args, format); + ret = VSNPRINTF (buf, size, format, args); + va_end (args); + GNUNET_assert (ret <= size); + return ret; +} + + +/** + * Create a copy of the given message. + * + * @param msg message to copy + * @return duplicate of the message + */ +struct GNUNET_MessageHeader * +GNUNET_copy_message (const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_MessageHeader *ret; + uint16_t msize; + + msize = ntohs (msg->size); + GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); + ret = GNUNET_malloc (msize); + memcpy (ret, msg, msize); + return ret; +} + + +/* end of common_allocation.c */ diff --git a/src/util/common_endian.c b/src/util/common_endian.c new file mode 100644 index 0000000..117e575 --- /dev/null +++ b/src/util/common_endian.c @@ -0,0 +1,94 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2006, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/common_endian.c + * @brief endian conversion helpers + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) + +uint64_t +GNUNET_ntohll (uint64_t n) +{ +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + return (((uint64_t) ntohl (n)) << 32) + ntohl (n >> 32); +#else + #error byteorder undefined +#endif +} + +uint64_t +GNUNET_htonll (uint64_t n) +{ +#if __BYTE_ORDER == __BIG_ENDIAN + return n; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + return (((uint64_t) htonl (n)) << 32) + htonl (n >> 32); +#else + #error byteorder undefined +#endif +} + + +/** + * Convert double to network-byte-order. + * @param d the value in network byte order + * @return the same value in host byte order + */ +double +GNUNET_hton_double (double d) +{ + double res; + uint64_t *in = (uint64_t *) &d; + uint64_t *out = (uint64_t *) &res; + + out[0] = GNUNET_htonll(in[0]); + + return res; +} + + +/** + * Convert double to host-byte-order + * @param d the value in network byte order + * @return the same value in host byte order + */ +double +GNUNET_ntoh_double (double d) +{ + double res; + uint64_t *in = (uint64_t *) &d; + uint64_t *out = (uint64_t *) &res; + + out[0] = GNUNET_ntohll(in[0]); + + return res; +} + + + +/* end of common_endian.c */ diff --git a/src/util/common_logging.c b/src/util/common_logging.c new file mode 100644 index 0000000..e19aa8c --- /dev/null +++ b/src/util/common_logging.c @@ -0,0 +1,1056 @@ +/* + This file is part of GNUnet. + (C) 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/common_logging.c + * @brief error handling API + * + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_strings_lib.h" +#include "gnunet_time_lib.h" + +#include + +/** + * After how many milliseconds do we always print + * that "message X was repeated N times"? Use 12h. + */ +#define BULK_DELAY_THRESHOLD (12 * 60 * 60 * 1000) + +/** + * After how many repetitions do we always print + * that "message X was repeated N times"? (even if + * we have not yet reached the delay threshold) + */ +#define BULK_REPEAT_THRESHOLD 1000 + +/** + * How many characters do we use for matching of + * bulk messages? + */ +#define BULK_TRACK_SIZE 256 + +/** + * How many characters do we use for matching of + * bulk components? + */ +#define COMP_TRACK_SIZE 32 + +/** + * How many characters can a date/time string + * be at most? + */ +#define DATE_STR_SIZE 64 + +/** + * Linked list of active loggers. + */ +struct CustomLogger +{ + /** + * This is a linked list. + */ + struct CustomLogger *next; + + /** + * Log function. + */ + GNUNET_Logger logger; + + /** + * Closure for logger. + */ + void *logger_cls; +}; + +/** + * The last "bulk" error message that we have been logging. + * Note that this message maybe truncated to the first BULK_TRACK_SIZE + * characters, in which case it is NOT 0-terminated! + */ +static char last_bulk[BULK_TRACK_SIZE]; + +/** + * Type of the last bulk message. + */ +static enum GNUNET_ErrorType last_bulk_kind; + +/** + * Time of the last bulk error message (0 for none) + */ +static struct GNUNET_TIME_Absolute last_bulk_time; + +/** + * Number of times that bulk message has been repeated since. + */ +static unsigned int last_bulk_repeat; + +/** + * Component when the last bulk was logged. Will be 0-terminated. + */ +static char last_bulk_comp[COMP_TRACK_SIZE + 1]; + +/** + * Running component. + */ +static char *component; + +/** + * Running component (without pid). + */ +static char *component_nopid; + +/** + * Minimum log level. + */ +static enum GNUNET_ErrorType min_level; + +/** + * Linked list of our custom loggres. + */ +static struct CustomLogger *loggers; + +/** + * Number of log calls to ignore. + */ +unsigned int skip_log; + +/** + * File descriptor to use for "stderr", or NULL for none. + */ +static FILE *GNUNET_stderr; + +/** + * Represents a single logging definition + */ +struct LogDef +{ + /** + * Component name regex + */ + regex_t component_regex; + + /** + * File name regex + */ + regex_t file_regex; + + /** + * Function name regex + */ + regex_t function_regex; + + /** + * Lowest line at which this definition matches. + * Defaults to 0. Must be <= to_line. + */ + int from_line; + + /** + * Highest line at which this definition matches. + * Defaults to INT_MAX. Must be >= from_line. + */ + int to_line; + + /** + * Maximal log level allowed for calls that match this definition. + * Calls with higher log level will be disabled. + * Must be >= 0 + */ + int level; + + /** + * 1 if this definition comes from GNUNET_FORCE_LOG, which means that it + * overrides any configuration options. 0 otherwise. + */ + int force; +}; + +/** + * Dynamic array of logging definitions + */ +struct LogDef *logdefs = NULL; + +/** + * Allocated size of logdefs array (in units) + */ +int logdefs_size = 0; + +/** + * The number of units used in logdefs array. + */ +int logdefs_len = 0; + +/** + * GNUNET_YES if GNUNET_LOG environment variable is already parsed. + */ +int gnunet_log_parsed = GNUNET_NO; + +/** + * GNUNET_YES if GNUNET_FORCE_LOG environment variable is already parsed. + */ +int gnunet_force_log_parsed = GNUNET_NO; + +/** + * GNUNET_YES if at least one definition with forced == 1 is available. + */ +int gnunet_force_log_present = GNUNET_NO; + +#ifdef WINDOWS +/** + * Contains the number of performance counts per second. + */ +LARGE_INTEGER performance_frequency; +#endif + +/** + * Convert a textual description of a loglevel + * to the respective GNUNET_GE_KIND. + * + * @param log loglevel to parse + * @return GNUNET_GE_INVALID if log does not parse + */ +static enum GNUNET_ErrorType +get_type (const char *log) +{ + if (log == NULL) + return GNUNET_ERROR_TYPE_UNSPECIFIED; + if (0 == strcasecmp (log, _("DEBUG"))) + return GNUNET_ERROR_TYPE_DEBUG; + if (0 == strcasecmp (log, _("INFO"))) + return GNUNET_ERROR_TYPE_INFO; + if (0 == strcasecmp (log, _("WARNING"))) + return GNUNET_ERROR_TYPE_WARNING; + if (0 == strcasecmp (log, _("ERROR"))) + return GNUNET_ERROR_TYPE_ERROR; + if (0 == strcasecmp (log, _("NONE"))) + return GNUNET_ERROR_TYPE_NONE; + return GNUNET_ERROR_TYPE_INVALID; +} + +#if !defined(GNUNET_CULL_LOGGING) +/** + * Utility function - reallocates logdefs array to be twice as large. + */ +static void +resize_logdefs () +{ + logdefs_size = (logdefs_size + 1) * 2; + logdefs = GNUNET_realloc (logdefs, logdefs_size * sizeof (struct LogDef)); +} + + +/** + * Abort the process, generate a core dump if possible. + */ +void +GNUNET_abort () +{ +#if WINDOWS + DebugBreak (); +#endif + abort (); +} + + +/** + * Utility function - adds a parsed definition to logdefs array. + * + * @param component see struct LogDef, can't be NULL + * @param file see struct LogDef, can't be NULL + * @param function see struct LogDef, can't be NULL + * @param from_line see struct LogDef + * @param to_line see struct LogDef + * @param level see struct LogDef, must be >= 0 + * @param force see struct LogDef + * @return 0 on success, regex-specific error otherwise + */ +static int +add_definition (char *component, char *file, char *function, int from_line, + int to_line, int level, int force) +{ + struct LogDef n; + int r; + + if (logdefs_size == logdefs_len) + resize_logdefs (); + memset (&n, 0, sizeof (n)); + if (strlen (component) == 0) + component = (char *) ".*"; + r = regcomp (&n.component_regex, (const char *) component, REG_NOSUB); + if (r != 0) + { + return r; + } + if (strlen (file) == 0) + file = (char *) ".*"; + r = regcomp (&n.file_regex, (const char *) file, REG_NOSUB); + if (r != 0) + { + regfree (&n.component_regex); + return r; + } + if ((NULL == function) || (strlen (function) == 0)) + function = (char *) ".*"; + r = regcomp (&n.function_regex, (const char *) function, REG_NOSUB); + if (r != 0) + { + regfree (&n.component_regex); + regfree (&n.file_regex); + return r; + } + n.from_line = from_line; + n.to_line = to_line; + n.level = level; + n.force = force; + logdefs[logdefs_len++] = n; + return 0; +} + + +/** + * Decides whether a particular logging call should or should not be allowed + * to be made. Used internally by GNUNET_log*() + * + * @param caller_level loglevel the caller wants to use + * @param comp component name the caller uses (NULL means that global + * component name is used) + * @param file file name containing the logging call, usually __FILE__ + * @param function function which tries to make a logging call, + * usually __FUNCTION__ + * @param line line at which the call is made, usually __LINE__ + * @return 0 to disallow the call, 1 to allow it + */ +int +GNUNET_get_log_call_status (int caller_level, const char *comp, + const char *file, const char *function, int line) +{ + struct LogDef *ld; + int i; + int force_only; + + if (comp == NULL) + /* Use default component */ + comp = component_nopid; + + /* We have no definitions to override globally configured log level, + * so just use it right away. + */ + if (min_level >= 0 && gnunet_force_log_present == GNUNET_NO) + return caller_level <= min_level; + + /* Only look for forced definitions? */ + force_only = min_level >= 0; + for (i = 0; i < logdefs_len; i++) + { + ld = &logdefs[i]; + if ((!force_only || ld->force) && + (line >= ld->from_line && line <= ld->to_line) && + (regexec (&ld->component_regex, comp, 0, NULL, 0) == 0) && + (regexec (&ld->file_regex, file, 0, NULL, 0) == 0) && + (regexec (&ld->function_regex, function, 0, NULL, 0) == 0)) + { + /* We're finished */ + return caller_level <= ld->level; + } + } + /* No matches - use global level, if defined */ + if (min_level >= 0) + return caller_level <= min_level; + /* All programs/services previously defaulted to WARNING. + * Now WE default to WARNING, and THEY default to NULL. + */ + return caller_level <= GNUNET_ERROR_TYPE_WARNING; +} + + +/** + * Utility function - parses a definition + * + * Definition format: + * component;file;function;from_line-to_line;level[/component...] + * All entries are mandatory, but may be empty. + * Empty entries for component, file and function are treated as + * "matches anything". + * Empty line entry is treated as "from 0 to INT_MAX" + * Line entry with only one line is treated as "this line only" + * Entry for level MUST NOT be empty. + * Entries for component, file and function that consist of a + * single character "*" are treated (at the moment) the same way + * empty entries are treated (wildcard matching is not implemented (yet?)). + * file entry is matched to the end of __FILE__. That is, it might be + * a base name, or a base name with leading directory names (some compilers + * define __FILE__ to absolute file path). + * + * @param constname name of the environment variable from which to get the + * string to be parsed + * @param force 1 if definitions found in constname are to be forced + * @return number of added definitions + */ +static int +parse_definitions (const char *constname, int force) +{ + char *def; + const char *tmp; + char *comp = NULL; + char *file = NULL; + char *function = NULL; + char *p; + char *start; + char *t; + short state; + int level; + int from_line, to_line; + int counter = 0; + int keep_looking = 1; + + tmp = getenv (constname); + if (tmp == NULL) + return 0; + def = GNUNET_strdup (tmp); + from_line = 0; + to_line = INT_MAX; + for (p = def, state = 0, start = def; keep_looking; p++) + { + switch (p[0]) + { + case ';': /* found a field separator */ + p[0] = '\0'; + switch (state) + { + case 0: /* within a component name */ + comp = start; + break; + case 1: /* within a file name */ + file = start; + break; + case 2: /* within a function name */ + /* after a file name there must be a function name */ + function = start; + break; + case 3: /* within a from-to line range */ + if (strlen (start) > 0) + { + errno = 0; + from_line = strtol (start, &t, 10); + if (errno != 0 || from_line < 0) + { + GNUNET_free (def); + return counter; + } + if (t < p && t[0] == '-') + { + errno = 0; + start = t + 1; + to_line = strtol (start, &t, 10); + if (errno != 0 || to_line < 0 || t != p) + { + GNUNET_free (def); + return counter; + } + } + else /* one number means "match this line only" */ + to_line = from_line; + } + else /* default to 0-max */ + { + from_line = 0; + to_line = INT_MAX; + } + break; + } + start = p + 1; + state += 1; + break; + case '\0': /* found EOL */ + keep_looking = 0; + /* fall through to '/' */ + case '/': /* found a definition separator */ + switch (state) + { + case 4: /* within a log level */ + p[0] = '\0'; + state = 0; + level = get_type ((const char *) start); + if (level == GNUNET_ERROR_TYPE_INVALID || + level == GNUNET_ERROR_TYPE_UNSPECIFIED || + 0 != add_definition (comp, file, function, from_line, to_line, + level, force)) + { + GNUNET_free (def); + return counter; + } + counter += 1; + start = p + 1; + break; + default: + break; + } + default: + break; + } + } + GNUNET_free (def); + return counter; +} + +/** + * Utility function - parses GNUNET_LOG and GNUNET_FORCE_LOG. + */ +static void +parse_all_definitions () +{ + if (gnunet_log_parsed == GNUNET_NO) + parse_definitions ("GNUNET_LOG", 0); + gnunet_log_parsed = GNUNET_YES; + if (gnunet_force_log_parsed == GNUNET_NO) + gnunet_force_log_present = + parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO; + gnunet_force_log_parsed = GNUNET_YES; +} +#endif +/** + * Setup logging. + * + * @param comp default component to use + * @param loglevel what types of messages should be logged + * @param logfile which file to write log messages to (can be NULL) + * @return GNUNET_OK on success + */ +int +GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile) +{ + FILE *altlog; + int dirwarn; + char *fn; + const char *env_logfile = NULL; + int altlog_fd; + + min_level = get_type (loglevel); +#if !defined(GNUNET_CULL_LOGGING) + parse_all_definitions (); +#endif +#ifdef WINDOWS + QueryPerformanceFrequency (&performance_frequency); +#endif + GNUNET_free_non_null (component); + GNUNET_asprintf (&component, "%s-%d", comp, getpid ()); + GNUNET_free_non_null (component_nopid); + component_nopid = GNUNET_strdup (comp); + + env_logfile = getenv ("GNUNET_FORCE_LOGFILE"); + if ((env_logfile != NULL) && (strlen (env_logfile) > 0)) + logfile = env_logfile; + + if (logfile == NULL) + return GNUNET_OK; + fn = GNUNET_STRINGS_filename_expand (logfile); + if (NULL == fn) + return GNUNET_SYSERR; + dirwarn = (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn)); + altlog_fd = OPEN (fn, O_APPEND | +#if WINDOWS + O_BINARY | +#endif + O_WRONLY | O_CREAT, +#if WINDOWS + _S_IREAD | _S_IWRITE +#else + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH +#endif + ); + if (altlog_fd != -1) + { + int dup_return; + if (GNUNET_stderr != NULL) + fclose (GNUNET_stderr); + dup_return = dup2 (altlog_fd, 2); + close (altlog_fd); + if (dup_return != -1) + { + altlog = fdopen (2, "ab"); + if (altlog == NULL) + { + close (2); + altlog_fd = -1; + } + } + else + { + altlog_fd = -1; + } + } + if (altlog_fd == -1) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); + if (dirwarn) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to create or access directory for log file `%s'\n"), + fn); + GNUNET_free (fn); + return GNUNET_SYSERR; + } + GNUNET_free (fn); + GNUNET_stderr = altlog; + return GNUNET_OK; +} + +/** + * Add a custom logger. + * + * @param logger log function + * @param logger_cls closure for logger + */ +void +GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls) +{ + struct CustomLogger *entry; + + entry = GNUNET_malloc (sizeof (struct CustomLogger)); + entry->logger = logger; + entry->logger_cls = logger_cls; + entry->next = loggers; + loggers = entry; +} + +/** + * Remove a custom logger. + * + * @param logger log function + * @param logger_cls closure for logger + */ +void +GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls) +{ + struct CustomLogger *pos; + struct CustomLogger *prev; + + prev = NULL; + pos = loggers; + while ((pos != NULL) && + ((pos->logger != logger) || (pos->logger_cls != logger_cls))) + { + prev = pos; + pos = pos->next; + } + GNUNET_assert (pos != NULL); + if (prev == NULL) + loggers = pos->next; + else + prev->next = pos->next; + GNUNET_free (pos); +} + + +/** + * Actually output the log message. + * + * @param kind how severe was the issue + * @param comp component responsible + * @param datestr current date/time + * @param msg the actual message + */ +static void +output_message (enum GNUNET_ErrorType kind, const char *comp, + const char *datestr, const char *msg) +{ + struct CustomLogger *pos; + + if (GNUNET_stderr != NULL) + { + FPRINTF (GNUNET_stderr, "%s %s %s %s", datestr, comp, + GNUNET_error_type_to_string (kind), msg); + fflush (GNUNET_stderr); + } + pos = loggers; + while (pos != NULL) + { + pos->logger (pos->logger_cls, kind, comp, datestr, msg); + pos = pos->next; + } +} + + +/** + * Flush an existing bulk report to the output. + * + * @param datestr our current timestamp + */ +static void +flush_bulk (const char *datestr) +{ + char msg[DATE_STR_SIZE + BULK_TRACK_SIZE + 256]; + int rev; + char *last; + char *ft; + + if ((last_bulk_time.abs_value == 0) || (last_bulk_repeat == 0)) + return; + rev = 0; + last = memchr (last_bulk, '\0', BULK_TRACK_SIZE); + if (last == NULL) + last = &last_bulk[BULK_TRACK_SIZE - 1]; + else if (last != last_bulk) + last--; + if (last[0] == '\n') + { + rev = 1; + last[0] = '\0'; + } + ft = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration + (last_bulk_time)); + snprintf (msg, sizeof (msg), + _("Message `%.*s' repeated %u times in the last %s\n"), + BULK_TRACK_SIZE, last_bulk, last_bulk_repeat, ft); + GNUNET_free (ft); + if (rev == 1) + last[0] = '\n'; + output_message (last_bulk_kind, last_bulk_comp, datestr, msg); + last_bulk_time = GNUNET_TIME_absolute_get (); + last_bulk_repeat = 0; +} + + +/** + * Ignore the next n calls to the log function. + * + * @param n number of log calls to ignore + * @param check_reset GNUNET_YES to assert that the log skip counter is currently zero + */ +void +GNUNET_log_skip (unsigned int n, int check_reset) +{ + if (n == 0) + { + int ok; + + ok = (0 == skip_log); + skip_log = 0; + if (check_reset) + GNUNET_assert (ok); + } + else + skip_log += n; +} + + +/** + * Output a log message using the default mechanism. + * + * @param kind how severe was the issue + * @param comp component responsible + * @param message the actual message + * @param va arguments to the format string "message" + */ +static void +mylog (enum GNUNET_ErrorType kind, const char *comp, const char *message, + va_list va) +{ + char date[DATE_STR_SIZE]; + char date2[DATE_STR_SIZE]; + time_t timetmp; + struct timeval timeofday; + struct tm *tmptr; + size_t size; + va_list vacp; + + va_copy (vacp, va); + size = VSNPRINTF (NULL, 0, message, vacp) + 1; + GNUNET_assert (0 != size); + va_end (vacp); + { + char buf[size]; + + VSNPRINTF (buf, size, message, va); + time (&timetmp); + memset (date, 0, DATE_STR_SIZE); + tmptr = localtime (&timetmp); + gettimeofday (&timeofday, NULL); + if (NULL != tmptr) + { +#ifdef WINDOWS + LARGE_INTEGER pc; + + pc.QuadPart = 0; + QueryPerformanceCounter (&pc); + strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%020llu", tmptr); + snprintf (date, sizeof (date), date2, + (long long) (pc.QuadPart / + (performance_frequency.QuadPart / 1000))); +#else + strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%06u", tmptr); + snprintf (date, sizeof (date), date2, timeofday.tv_usec); +#endif + } + else + strcpy (date, "localtime error"); + if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) && + (last_bulk_time.abs_value != 0) && + (0 == strncmp (buf, last_bulk, sizeof (last_bulk)))) + { + last_bulk_repeat++; + if ((GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value > + BULK_DELAY_THRESHOLD) || (last_bulk_repeat > BULK_REPEAT_THRESHOLD)) + flush_bulk (date); + return; + } + flush_bulk (date); + strncpy (last_bulk, buf, sizeof (last_bulk)); + last_bulk_repeat = 0; + last_bulk_kind = kind; + last_bulk_time = GNUNET_TIME_absolute_get (); + strncpy (last_bulk_comp, comp, COMP_TRACK_SIZE); + output_message (kind, comp, date, buf); + } +} + + +/** + * Main log function. + * + * @param kind how serious is the error? + * @param message what is the message (format string) + * @param ... arguments for format string + */ +void +GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...) +{ + va_list va; + + va_start (va, message); + mylog (kind, component, message, va); + va_end (va); +} + + +/** + * Log function that specifies an alternative component. + * This function should be used by plugins. + * + * @param kind how serious is the error? + * @param comp component responsible for generating the message + * @param message what is the message (format string) + * @param ... arguments for format string + */ +void +GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind, const char *comp, + const char *message, ...) +{ + va_list va; + char comp_w_pid[128]; + + if (comp == NULL) + comp = component_nopid; + + va_start (va, message); + GNUNET_snprintf (comp_w_pid, sizeof (comp_w_pid), "%s-%d", comp, getpid ()); + mylog (kind, comp_w_pid, message, va); + va_end (va); +} + + +/** + * Convert error type to string. + * + * @param kind type to convert + * @return string corresponding to the type + */ +const char * +GNUNET_error_type_to_string (enum GNUNET_ErrorType kind) +{ + if ((kind & GNUNET_ERROR_TYPE_ERROR) > 0) + return _("ERROR"); + if ((kind & GNUNET_ERROR_TYPE_WARNING) > 0) + return _("WARNING"); + if ((kind & GNUNET_ERROR_TYPE_INFO) > 0) + return _("INFO"); + if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0) + return _("DEBUG"); + if ((kind & ~GNUNET_ERROR_TYPE_BULK) == 0) + return _("NONE"); + return _("INVALID"); +} + + +/** + * Convert a hash to a string (for printing debug messages). + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param hc the hash code + * @return string form; will be overwritten by next call to GNUNET_h2s. + */ +const char * +GNUNET_h2s (const GNUNET_HashCode * hc) +{ + static struct GNUNET_CRYPTO_HashAsciiEncoded ret; + + GNUNET_CRYPTO_hash_to_enc (hc, &ret); + ret.encoding[8] = '\0'; + return (const char *) ret.encoding; +} + +/** + * Convert a hash to a string (for printing debug messages). + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param hc the hash code + * @return string form; will be overwritten by next call to GNUNET_h2s_full. + */ +const char * +GNUNET_h2s_full (const GNUNET_HashCode * hc) +{ + static struct GNUNET_CRYPTO_HashAsciiEncoded ret; + + GNUNET_CRYPTO_hash_to_enc (hc, &ret); + ret.encoding[sizeof (ret) - 1] = '\0'; + return (const char *) ret.encoding; +} + +/** + * Convert a peer identity to a string (for printing debug messages). + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param pid the peer identity + * @return string form of the pid; will be overwritten by next + * call to GNUNET_i2s. + */ +const char * +GNUNET_i2s (const struct GNUNET_PeerIdentity *pid) +{ + static struct GNUNET_CRYPTO_HashAsciiEncoded ret; + + GNUNET_CRYPTO_hash_to_enc (&pid->hashPubKey, &ret); + ret.encoding[4] = '\0'; + return (const char *) ret.encoding; +} + +/** + * Convert a peer identity to a string (for printing debug messages). + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param pid the peer identity + * @return string form of the pid; will be overwritten by next + * call to GNUNET_i2s. + */ +const char * +GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid) +{ + static struct GNUNET_CRYPTO_HashAsciiEncoded ret; + + GNUNET_CRYPTO_hash_to_enc (&pid->hashPubKey, &ret); + return (const char *) ret.encoding; +} + + +/** + * Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string + * (for printing debug messages). This is one of the very few calls + * in the entire API that is NOT reentrant! + * + * @param addr the address + * @param addrlen the length of the address + * @return nicely formatted string for the address + * will be overwritten by next call to GNUNET_a2s. + */ +const char * +GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen) +{ + static char buf[INET6_ADDRSTRLEN + 8]; + static char b2[6]; + const struct sockaddr_in *v4; + const struct sockaddr_un *un; + const struct sockaddr_in6 *v6; + unsigned int off; + + if (addr == NULL) + return _("unknown address"); + switch (addr->sa_family) + { + case AF_INET: + if (addrlen != sizeof (struct sockaddr_in)) + return ""; + v4 = (const struct sockaddr_in *) addr; + inet_ntop (AF_INET, &v4->sin_addr, buf, INET_ADDRSTRLEN); + if (0 == ntohs (v4->sin_port)) + return buf; + strcat (buf, ":"); + GNUNET_snprintf (b2, sizeof (b2), "%u", ntohs (v4->sin_port)); + strcat (buf, b2); + return buf; + case AF_INET6: + if (addrlen != sizeof (struct sockaddr_in6)) + return ""; + v6 = (const struct sockaddr_in6 *) addr; + buf[0] = '['; + inet_ntop (AF_INET6, &v6->sin6_addr, &buf[1], INET6_ADDRSTRLEN); + if (0 == ntohs (v6->sin6_port)) + return &buf[1]; + strcat (buf, "]:"); + GNUNET_snprintf (b2, sizeof (b2), "%u", ntohs (v6->sin6_port)); + strcat (buf, b2); + return buf; + case AF_UNIX: + if (addrlen <= sizeof (sa_family_t)) + return ""; + un = (const struct sockaddr_un *) addr; + off = 0; + if (un->sun_path[0] == '\0') + off++; + snprintf (buf, sizeof (buf), "%s%.*s", (off == 1) ? "@" : "", + (int) (addrlen - sizeof (sa_family_t) - 1 - off), + &un->sun_path[off]); + return buf; + default: + return _("invalid address"); + } +} + + +/** + * Initializer + */ +void __attribute__ ((constructor)) GNUNET_util_cl_init () +{ + GNUNET_stderr = stderr; +#ifdef MINGW + GNInitWinEnv (NULL); +#endif +} + + +/** + * Destructor + */ +void __attribute__ ((destructor)) GNUNET_util_cl_fini () +{ +#ifdef MINGW + GNShutdownWinEnv (); +#endif +} + +/* end of common_logging.c */ diff --git a/src/util/configuration.c b/src/util/configuration.c new file mode 100644 index 0000000..f24b2c2 --- /dev/null +++ b/src/util/configuration.c @@ -0,0 +1,1287 @@ +/* + This file is part of GNUnet. + (C) 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/util/configuration.c + * @brief configuration management + * + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_util_lib.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_strings_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +/** + * @brief configuration entry + */ +struct ConfigEntry +{ + + /** + * This is a linked list. + */ + struct ConfigEntry *next; + + /** + * key for this entry + */ + char *key; + + /** + * current, commited value + */ + char *val; +}; + + +/** + * @brief configuration section + */ +struct ConfigSection +{ + /** + * This is a linked list. + */ + struct ConfigSection *next; + + /** + * entries in the section + */ + struct ConfigEntry *entries; + + /** + * name of the section + */ + char *name; +}; + + +/** + * @brief configuration data + */ +struct GNUNET_CONFIGURATION_Handle +{ + /** + * Configuration sections. + */ + struct ConfigSection *sections; + + /** + * Modification indication since last save + * GNUNET_NO if clean, GNUNET_YES if dirty, + * GNUNET_SYSERR on error (i.e. last save failed) + */ + int dirty; + +}; + + +/** + * Used for diffing a configuration object against + * the default one + */ +struct DiffHandle +{ + const struct GNUNET_CONFIGURATION_Handle *cfgDefault; + struct GNUNET_CONFIGURATION_Handle *cfgDiff; +}; + + + +/** + * Create a GNUNET_CONFIGURATION_Handle. + * + * @return fresh configuration object + */ +struct GNUNET_CONFIGURATION_Handle * +GNUNET_CONFIGURATION_create () +{ + return GNUNET_malloc (sizeof (struct GNUNET_CONFIGURATION_Handle)); +} + + +/** + * Destroy configuration object. + * + * @param cfg configuration to destroy + */ +void +GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct ConfigSection *sec; + + while (NULL != (sec = cfg->sections)) + GNUNET_CONFIGURATION_remove_section (cfg, sec->name); + GNUNET_free (cfg); +} + + +/** + * Parse a configuration file, add all of the options in the + * file to the configuration environment. + * + * @param cfg configuration to update + * @param filename name of the configuration file + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *filename) +{ + int dirty; + char line[256]; + char tag[64]; + char value[192]; + FILE *fp; + unsigned int nr; + int i; + int emptyline; + int ret; + char *section; + char *fn; + + fn = GNUNET_STRINGS_filename_expand (filename); + if (fn == NULL) + return GNUNET_SYSERR; + dirty = cfg->dirty; /* back up value! */ + if (NULL == (fp = FOPEN (fn, "r"))) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fopen", fn); + GNUNET_free (fn); + return GNUNET_SYSERR; + } + GNUNET_free (fn); + ret = GNUNET_OK; + section = GNUNET_strdup (""); + memset (line, 0, 256); + nr = 0; + while (NULL != fgets (line, 255, fp)) + { + nr++; + for (i = 0; i < 255; i++) + if (line[i] == '\t') + line[i] = ' '; + if (line[0] == '\n' || line[0] == '#' || line[0] == '%' || line[0] == '\r') + continue; + emptyline = 1; + for (i = 0; (i < 255 && line[i] != 0); i++) + if (line[i] != ' ' && line[i] != '\n' && line[i] != '\r') + emptyline = 0; + if (emptyline == 1) + continue; + /* remove tailing whitespace */ + for (i = strlen (line) - 1; (i >= 0) && (isspace ((unsigned char) line[i])); + i--) + line[i] = '\0'; + if (1 == sscanf (line, "@INLINE@ %191[^\n]", value)) + { + /* @INLINE@ value */ + if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, value)) + ret = GNUNET_SYSERR; /* failed to parse included config */ + } + else if (1 == sscanf (line, "[%99[^]]]", value)) + { + /* [value] */ + GNUNET_free (section); + section = GNUNET_strdup (value); + } + else if (2 == sscanf (line, " %63[^= ] = %191[^\n]", tag, value)) + { + /* tag = value */ + /* Strip LF */ + i = strlen (value) - 1; + while ((i >= 0) && (isspace ((unsigned char) value[i]))) + value[i--] = '\0'; + /* remove quotes */ + i = 0; + if (value[0] == '"') + { + i = 1; + while ((value[i] != '\0') && (value[i] != '"')) + i++; + if (value[i] == '"') + { + value[i] = '\0'; + i = 1; + } + else + i = 0; + } + GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, &value[i]); + } + else if (1 == sscanf (line, " %63[^= ] =[^\n]", tag)) + { + /* tag = */ + GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, ""); + } + else + { + /* parse error */ + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Syntax error in configuration file `%s' at line %u.\n"), filename, + nr); + ret = GNUNET_SYSERR; + break; + } + } + GNUNET_assert (0 == FCLOSE (fp)); + /* restore dirty flag - anything we set in the meantime + * came from disk */ + cfg->dirty = dirty; + GNUNET_free (section); + return ret; +} + + +/** + * Test if there are configuration options that were + * changed since the last save. + * + * @param cfg configuration to inspect + * @return GNUNET_NO if clean, GNUNET_YES if dirty, GNUNET_SYSERR on error (i.e. last save failed) + */ +int +GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + return cfg->dirty; +} + + +/** + * Write configuration file. + * + * @param cfg configuration to write + * @param filename where to write the configuration + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *filename) +{ + struct ConfigSection *sec; + struct ConfigEntry *ent; + FILE *fp; + int error; + char *fn; + char *val; + char *pos; + + fn = GNUNET_STRINGS_filename_expand (filename); + if (fn == NULL) + return GNUNET_SYSERR; + if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn)) + { + GNUNET_free (fn); + return GNUNET_SYSERR; + } + if (NULL == (fp = FOPEN (fn, "w"))) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fopen", fn); + GNUNET_free (fn); + return GNUNET_SYSERR; + } + GNUNET_free (fn); + error = 0; + sec = cfg->sections; + while (sec != NULL) + { + if (0 > FPRINTF (fp, "[%s]\n", sec->name)) + { + error = 1; + break; + } + ent = sec->entries; + while (ent != NULL) + { + if (ent->val != NULL) + { + val = GNUNET_malloc (strlen (ent->val) * 2 + 1); + strcpy (val, ent->val); + while (NULL != (pos = strstr (val, "\n"))) + { + memmove (&pos[2], &pos[1], strlen (&pos[1])); + pos[0] = '\\'; + pos[1] = 'n'; + } + if (0 > FPRINTF (fp, "%s = %s\n", ent->key, val)) + { + error = 1; + GNUNET_free (val); + break; + } + GNUNET_free (val); + } + ent = ent->next; + } + if (error != 0) + break; + if (0 > FPRINTF (fp, "%s\n", "")) + { + error = 1; + break; + } + sec = sec->next; + } + if (error != 0) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", filename); + GNUNET_assert (0 == FCLOSE (fp)); + if (error != 0) + { + cfg->dirty = GNUNET_SYSERR; /* last write failed */ + return GNUNET_SYSERR; + } + cfg->dirty = GNUNET_NO; /* last write succeeded */ + return GNUNET_OK; +} + + +/** + * Iterate over all options in the configuration. + * + * @param cfg configuration to inspect + * @param iter function to call on each option + * @param iter_cls closure for iter + */ +void +GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_CONFIGURATION_Iterator iter, + void *iter_cls) +{ + struct ConfigSection *spos; + struct ConfigEntry *epos; + + spos = cfg->sections; + while (spos != NULL) + { + epos = spos->entries; + while (epos != NULL) + { + iter (iter_cls, spos->name, epos->key, epos->val); + epos = epos->next; + } + spos = spos->next; + } +} + + +/** + * Iterate over values of a section in the configuration. + * + * @param cfg configuration to inspect + * @param section the section + * @param iter function to call on each option + * @param iter_cls closure for iter + */ +void +GNUNET_CONFIGURATION_iterate_section_values (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + GNUNET_CONFIGURATION_Iterator iter, + void *iter_cls) +{ + struct ConfigSection *spos; + struct ConfigEntry *epos; + + spos = cfg->sections; + while ((spos != NULL) && (0 != strcasecmp (spos->name, section))) + spos = spos->next; + + if (spos == NULL) + return; + + epos = spos->entries; + while (epos != NULL) + { + iter (iter_cls, spos->name, epos->key, epos->val); + epos = epos->next; + } +} + + +/** + * Iterate over all sections in the configuration. + * + * @param cfg configuration to inspect + * @param iter function to call on each section + * @param iter_cls closure for iter + */ +void +GNUNET_CONFIGURATION_iterate_sections (const struct GNUNET_CONFIGURATION_Handle + *cfg, + GNUNET_CONFIGURATION_Section_Iterator + iter, void *iter_cls) +{ + struct ConfigSection *spos; + struct ConfigSection *next; + + next = cfg->sections; + while (next != NULL) + { + spos = next; + next = spos->next; + iter (iter_cls, spos->name); + } +} + +/** + * Remove the given section and all options in it. + * + * @param cfg configuration to inspect + * @param section name of the section to remove + */ +void +GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section) +{ + struct ConfigSection *spos; + struct ConfigSection *prev; + struct ConfigEntry *ent; + + prev = NULL; + spos = cfg->sections; + while (spos != NULL) + { + if (0 == strcasecmp (section, spos->name)) + { + if (prev == NULL) + cfg->sections = spos->next; + else + prev->next = spos->next; + while (NULL != (ent = spos->entries)) + { + spos->entries = ent->next; + GNUNET_free (ent->key); + GNUNET_free_non_null (ent->val); + GNUNET_free (ent); + cfg->dirty = GNUNET_YES; + } + GNUNET_free (spos->name); + GNUNET_free (spos); + return; + } + prev = spos; + spos = spos->next; + } +} + + +/** + * Copy a configuration value to the given target configuration. + * Overwrites existing entries. + * + * @param cls the destination configuration (struct GNUNET_CONFIGURATION_Handle*) + * @param section section for the value + * @param option option name of the value + * @param value value to copy + */ +static void +copy_entry (void *cls, const char *section, const char *option, + const char *value) +{ + struct GNUNET_CONFIGURATION_Handle *dst = cls; + + GNUNET_CONFIGURATION_set_value_string (dst, section, option, value); +} + + +/** + * Duplicate an existing configuration object. + * + * @param cfg configuration to duplicate + * @return duplicate configuration + */ +struct GNUNET_CONFIGURATION_Handle * +GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_CONFIGURATION_Handle *ret; + + ret = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_iterate (cfg, ©_entry, ret); + return ret; +} + + +/** + * FIXME. + * + * @param cfg FIXME + * @param section FIXME + * @return matching entry, NULL if not found + */ +static struct ConfigSection * +findSection (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section) +{ + struct ConfigSection *pos; + + pos = cfg->sections; + while ((pos != NULL) && (0 != strcasecmp (section, pos->name))) + pos = pos->next; + return pos; +} + + +/** + * Find an entry from a configuration. + * + * @param cfg handle to the configuration + * @param section section the option is in + * @param key the option + * @return matching entry, NULL if not found + */ +static struct ConfigEntry * +findEntry (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, + const char *key) +{ + struct ConfigSection *sec; + struct ConfigEntry *pos; + + sec = findSection (cfg, section); + if (sec == NULL) + return NULL; + pos = sec->entries; + while ((pos != NULL) && (0 != strcasecmp (key, pos->key))) + pos = pos->next; + return pos; +} + + +/** + * A callback function, compares entries from two configurations + * (default against a new configuration) and write the diffs in a + * diff-configuration object (the callback object). + * + * @param cls the diff configuration (struct DiffHandle*) + * @param section section for the value (of the default conf.) + * @param option option name of the value (of the default conf.) + * @param value value to copy (of the default conf.) + */ +static void +compareEntries (void *cls, const char *section, const char *option, + const char *value) +{ + struct DiffHandle *dh = cls; + struct ConfigEntry *entNew; + + entNew = findEntry (dh->cfgDefault, section, option); + if ((entNew != NULL) && (strcmp (entNew->val, value) == 0)) + return; + GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff, section, option, value); +} + + +/** + * Write only configuration entries that have been changed to configuration file + * @param cfgDefault default configuration + * @param cfgNew new configuration + * @param filename where to write the configuration diff between default and new + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_write_diffs (const struct GNUNET_CONFIGURATION_Handle + *cfgDefault, + const struct GNUNET_CONFIGURATION_Handle + *cfgNew, const char *filename) +{ + int ret; + struct DiffHandle diffHandle; + + diffHandle.cfgDiff = GNUNET_CONFIGURATION_create (); + diffHandle.cfgDefault = cfgDefault; + GNUNET_CONFIGURATION_iterate (cfgNew, compareEntries, &diffHandle); + ret = GNUNET_CONFIGURATION_write (diffHandle.cfgDiff, filename); + GNUNET_CONFIGURATION_destroy (diffHandle.cfgDiff); + return ret; +} + + +/** + * Set a configuration value that should be a string. + * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest + * @param value value to set + */ +void +GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, const char *option, + const char *value) +{ + struct ConfigSection *sec; + struct ConfigEntry *e; + + e = findEntry (cfg, section, option); + if (e != NULL) + { + GNUNET_free_non_null (e->val); + e->val = GNUNET_strdup (value); + return; + } + sec = findSection (cfg, section); + if (sec == NULL) + { + sec = GNUNET_malloc (sizeof (struct ConfigSection)); + sec->name = GNUNET_strdup (section); + sec->next = cfg->sections; + cfg->sections = sec; + } + e = GNUNET_malloc (sizeof (struct ConfigEntry)); + e->key = GNUNET_strdup (option); + e->val = GNUNET_strdup (value); + e->next = sec->entries; + sec->entries = e; +} + + +/** + * Set a configuration value that should be a number. + * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest + * @param number value to set + */ +void +GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, const char *option, + unsigned long long number) +{ + char s[64]; + + GNUNET_snprintf (s, 64, "%llu", number); + GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s); +} + + +/** + * Get a configuration value that should be a number. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param number where to store the numeric value of the option + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_number (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + unsigned long long *number) +{ + struct ConfigEntry *e; + + e = findEntry (cfg, section, option); + if (e == NULL) + return GNUNET_SYSERR; + if (1 != SSCANF (e->val, "%llu", number)) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Get a configuration value that should be a relative time. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param time set to the time value stored in the configuration + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + struct GNUNET_TIME_Relative *time) +{ + struct ConfigEntry *e; + + e = findEntry (cfg, section, option); + if (e == NULL) + return GNUNET_SYSERR; + + return GNUNET_STRINGS_fancy_time_to_relative (e->val, time); +} + + +/** + * Get a configuration value that should be a size in bytes. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param size set to the size in bytes as stored in the configuration + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_size (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + unsigned long long *size) +{ + struct ConfigEntry *e; + + e = findEntry (cfg, section, option); + if (e == NULL) + return GNUNET_SYSERR; + return GNUNET_STRINGS_fancy_size_to_bytes (e->val, size); +} + + +/** + * Get a configuration value that should be a string. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param value will be set to a freshly allocated configuration + * value, or NULL if option is not specified + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_string (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, char **value) +{ + struct ConfigEntry *e; + + e = findEntry (cfg, section, option); + if ((e == NULL) || (e->val == NULL)) + { + *value = NULL; + return GNUNET_SYSERR; + } + *value = GNUNET_strdup (e->val); + return GNUNET_OK; +} + + +/** + * Get a configuration value that should be in a set of + * predefined strings + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param choices NULL-terminated list of legal values + * @param value will be set to an entry in the legal list, + * or NULL if option is not specified and no default given + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_choice (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, const char **choices, + const char **value) +{ + struct ConfigEntry *e; + int i; + + e = findEntry (cfg, section, option); + if (e == NULL) + return GNUNET_SYSERR; + i = 0; + while (choices[i] != NULL) + { + if (0 == strcasecmp (choices[i], e->val)) + break; + i++; + } + if (choices[i] == NULL) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Configuration value '%s' for '%s'" + " in section '%s' is not in set of legal choices\n"), e->val, option, + section); + return GNUNET_SYSERR; + } + *value = choices[i]; + return GNUNET_OK; +} + + +/** + * Test if we have a value for a particular option + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @return GNUNET_YES if so, GNUNET_NO if not. + */ +int +GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, const char *option) +{ + struct ConfigEntry *e; + + if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL)) + return GNUNET_NO; + return GNUNET_YES; +} + + +/** + * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" + * where either in the "PATHS" section or the environtment + * "FOO" is set to "DIRECTORY". + * + * @param cfg configuration to use for path expansion + * @param orig string to $-expand (will be freed!) + * @return $-expanded string + */ +char * +GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle + *cfg, char *orig) +{ + int i; + char *prefix; + char *result; + const char *post; + const char *env; + + if (orig[0] != '$') + return orig; + i = 0; + while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0')) + i++; + if (orig[i] == '\0') + { + post = ""; + } + else + { + orig[i] = '\0'; + post = &orig[i + 1]; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", &orig[1], &prefix)) + { + if (NULL == (env = getenv (&orig[1]))) + { + orig[i] = DIR_SEPARATOR; + return orig; + } + prefix = GNUNET_strdup (env); + } + result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2); + strcpy (result, prefix); + if ((strlen (prefix) == 0) || + ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0))) + strcat (result, DIR_SEPARATOR_STR); + strcat (result, post); + GNUNET_free (prefix); + GNUNET_free (orig); + return result; +} + + +/** + * Get a configuration value that should be a string. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param value will be set to a freshly allocated configuration + * value, or NULL if option is not specified + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_filename (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + const char *option, char **value) +{ + char *tmp; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp)) + { + *value = NULL; + return GNUNET_SYSERR; + } + tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp); + *value = GNUNET_STRINGS_filename_expand (tmp); + GNUNET_free (tmp); + if (*value == NULL) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Get a configuration value that should be in a set of + * "GNUNET_YES" or "GNUNET_NO". + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR + */ +int +GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option) +{ + static const char *yesno[] = { "YES", "NO", NULL }; + const char *val; + int ret; + + ret = + GNUNET_CONFIGURATION_get_value_choice (cfg, section, option, yesno, &val); + if (ret == GNUNET_SYSERR) + return ret; + if (val == yesno[0]) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Iterate over the set of filenames stored in a configuration value. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param cb function to call on each filename + * @param cb_cls closure for cb + * @return number of filenames iterated over, -1 on error + */ +int +GNUNET_CONFIGURATION_iterate_value_filenames (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + const char *option, + GNUNET_FileNameCallback cb, + void *cb_cls) +{ + char *list; + char *pos; + char *end; + char old; + int ret; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list)) + return 0; + GNUNET_assert (list != NULL); + ret = 0; + pos = list; + while (1) + { + while (pos[0] == ' ') + pos++; + if (strlen (pos) == 0) + break; + end = pos + 1; + while ((end[0] != ' ') && (end[0] != '\0')) + { + if (end[0] == '\\') + { + switch (end[1]) + { + case '\\': + case ' ': + memmove (end, &end[1], strlen (&end[1]) + 1); + case '\0': + /* illegal, but just keep it */ + break; + default: + /* illegal, but just ignore that there was a '/' */ + break; + } + } + end++; + } + old = end[0]; + end[0] = '\0'; + if (strlen (pos) > 0) + { + ret++; + if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos))) + { + ret = GNUNET_SYSERR; + break; + } + } + if (old == '\0') + break; + pos = end + 1; + } + GNUNET_free (list); + return ret; +} + + +/** + * FIXME. + * + * @param value FIXME + * @return FIXME + */ +static char * +escape_name (const char *value) +{ + char *escaped; + const char *rpos; + char *wpos; + + escaped = GNUNET_malloc (strlen (value) * 2 + 1); + memset (escaped, 0, strlen (value) * 2 + 1); + rpos = value; + wpos = escaped; + while (rpos[0] != '\0') + { + switch (rpos[0]) + { + case '\\': + case ' ': + wpos[0] = '\\'; + wpos[1] = rpos[0]; + wpos += 2; + break; + default: + wpos[0] = rpos[0]; + wpos++; + } + rpos++; + } + return escaped; +} + + +/** + * FIXME. + * + * @param cls string we compare with (const char*) + * @param fn filename we are currently looking at + * @return GNUNET_OK if the names do not match, GNUNET_SYSERR if they do + */ +static int +test_match (void *cls, const char *fn) +{ + const char *of = cls; + + return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK; +} + + +/** + * Append a filename to a configuration value that + * represents a list of filenames + * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest + * @param value filename to append + * @return GNUNET_OK on success, + * GNUNET_NO if the filename already in the list + * GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + const char *value) +{ + char *escaped; + char *old; + char *nw; + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_iterate_value_filenames (cfg, section, option, + &test_match, + (void *) value)) + return GNUNET_NO; /* already exists */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old)) + old = GNUNET_strdup (""); + escaped = escape_name (value); + nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2); + strcpy (nw, old); + if (strlen (old) > 0) + strcat (nw, " "); + strcat (nw, escaped); + GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw); + GNUNET_free (old); + GNUNET_free (nw); + GNUNET_free (escaped); + return GNUNET_OK; +} + + +/** + * Remove a filename from a configuration value that + * represents a list of filenames + * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest + * @param value filename to remove + * @return GNUNET_OK on success, + * GNUNET_NO if the filename is not in the list, + * GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + const char *value) +{ + char *list; + char *pos; + char *end; + char *match; + char old; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list)) + return GNUNET_NO; + match = escape_name (value); + pos = list; + while (1) + { + while (pos[0] == ' ') + pos++; + if (strlen (pos) == 0) + break; + end = pos + 1; + while ((end[0] != ' ') && (end[0] != '\0')) + { + if (end[0] == '\\') + { + switch (end[1]) + { + case '\\': + case ' ': + end++; + break; + case '\0': + /* illegal, but just keep it */ + break; + default: + /* illegal, but just ignore that there was a '/' */ + break; + } + } + end++; + } + old = end[0]; + end[0] = '\0'; + if (0 == strcmp (pos, match)) + { + if (old != '\0') + memmove (pos, &end[1], strlen (&end[1]) + 1); + else + { + if (pos != list) + pos[-1] = '\0'; + else + pos[0] = '\0'; + } + GNUNET_CONFIGURATION_set_value_string (cfg, section, option, list); + GNUNET_free (list); + GNUNET_free (match); + return GNUNET_OK; + } + if (old == '\0') + break; + end[0] = old; + pos = end + 1; + } + GNUNET_free (list); + GNUNET_free (match); + return GNUNET_NO; +} + + +/** + * Wrapper around GNUNET_CONFIGURATION_parse. + * + * @param cls the cfg + * @param filename file to parse + * @return GNUNET_OK on success + */ +static int +parse_configuration_file (void *cls, const char *filename) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + int ret; + + ret = GNUNET_CONFIGURATION_parse (cfg, filename); + return ret; +} + + +/** + * Load configuration (starts with defaults, then loads + * system-specific configuration). + * + * @param cfg configuration to update + * @param filename name of the configuration file, NULL to load defaults + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg, + const char *filename) +{ + char *baseconfig; + char *ipath; + + ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); + if (ipath == NULL) + return GNUNET_SYSERR; + baseconfig = NULL; + GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d"); + GNUNET_free (ipath); + if (GNUNET_SYSERR == + GNUNET_DISK_directory_scan (baseconfig, &parse_configuration_file, cfg)) + { + GNUNET_free (baseconfig); + return GNUNET_SYSERR; /* no configuration at all found */ + } + GNUNET_free (baseconfig); + if ((filename != NULL) && + (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename))) + { + /* specified configuration not found */ + return GNUNET_SYSERR; + } + if (((GNUNET_YES != + GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) && + (filename != NULL)) + GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG", + filename); + if ((GNUNET_YES == + GNUNET_CONFIGURATION_have_value (cfg, "TESTING", "WEAKRANDOM")) && + (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (cfg, "TESTING", "WEAKRANDOM"))) + GNUNET_CRYPTO_random_disable_entropy_gathering (); + return GNUNET_OK; +} + + + +/* end of configuration.c */ diff --git a/src/util/connection.c b/src/util/connection.c new file mode 100644 index 0000000..8224479 --- /dev/null +++ b/src/util/connection.c @@ -0,0 +1,1626 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/connection.c + * @brief TCP connection management + * @author Christian Grothoff + * + * This code is rather complex. Only modify it if you + * 1) Have a NEW testcase showing that the new code + * is needed and correct + * 2) All EXISTING testcases pass with the new code + * These rules should apply in general, but for this + * module they are VERY, VERY important. + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_resolver_service.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" + + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +/** + * Possible functions to call after connect failed or succeeded. + */ +enum ConnectContinuations +{ + /** + * Call nothing. + */ + COCO_NONE = 0, + + /** + * Call "receive_again". + */ + COCO_RECEIVE_AGAIN = 1, + + /** + * Call "transmit_ready". + */ + COCO_TRANSMIT_READY = 2, + + /** + * Call "destroy_continuation". + */ + COCO_DESTROY_CONTINUATION = 4 +}; + + +/** + * Transmission handle. There can only be one for each connection. + */ +struct GNUNET_CONNECTION_TransmitHandle +{ + + /** + * Function to call if the send buffer has notify_size + * bytes available. + */ + GNUNET_CONNECTION_TransmitReadyNotify notify_ready; + + /** + * Closure for notify_ready. + */ + void *notify_ready_cls; + + /** + * Our socket handle. + */ + struct GNUNET_CONNECTION_Handle *sh; + + /** + * Timeout for receiving (in absolute time). + */ + struct GNUNET_TIME_Absolute transmit_timeout; + + /** + * Task called on timeout. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * At what number of bytes available in the + * write buffer should the notify method be called? + */ + size_t notify_size; + +}; + + +/** + * During connect, we try multiple possible IP addresses + * to find out which one might work. + */ +struct AddressProbe +{ + + /** + * This is a linked list. + */ + struct AddressProbe *next; + + /** + * This is a doubly-linked list. + */ + struct AddressProbe *prev; + + /** + * The address; do not free (allocated at the end of this struct). + */ + const struct sockaddr *addr; + + /** + * Underlying OS's socket. + */ + struct GNUNET_NETWORK_Handle *sock; + + /** + * Connection for which we are probing. + */ + struct GNUNET_CONNECTION_Handle *h; + + /** + * Lenth of addr. + */ + socklen_t addrlen; + + /** + * Task waiting for the socket to finish connecting. + */ + GNUNET_SCHEDULER_TaskIdentifier task; +}; + + +/** + * @brief handle for a network socket + */ +struct GNUNET_CONNECTION_Handle +{ + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Linked list of sockets we are currently trying out + * (during connect). + */ + struct AddressProbe *ap_head; + + /** + * Linked list of sockets we are currently trying out + * (during connect). + */ + struct AddressProbe *ap_tail; + + /** + * Network address of the other end-point, may be NULL. + */ + struct sockaddr *addr; + + /** + * Pointer to the hostname if socket was + * created using DNS lookup, otherwise NULL. + */ + char *hostname; + + /** + * Underlying OS's socket, set to NULL after fatal errors. + */ + struct GNUNET_NETWORK_Handle *sock; + + /** + * Function to call on data received, NULL if no receive is pending. + */ + GNUNET_CONNECTION_Receiver receiver; + + /** + * Closure for receiver. + */ + void *receiver_cls; + + /** + * Pointer to our write buffer. + */ + char *write_buffer; + + /** + * Current size of our write buffer. + */ + size_t write_buffer_size; + + /** + * Current write-offset in write buffer (where + * would we write next). + */ + size_t write_buffer_off; + + /** + * Current read-offset in write buffer (how many + * bytes have already been sent). + */ + size_t write_buffer_pos; + + /** + * Length of addr. + */ + socklen_t addrlen; + + /** + * Read task that we may need to wait for. + */ + GNUNET_SCHEDULER_TaskIdentifier read_task; + + /** + * Write task that we may need to wait for. + */ + GNUNET_SCHEDULER_TaskIdentifier write_task; + + /** + * Destroy task (if already scheduled). + */ + GNUNET_SCHEDULER_TaskIdentifier destroy_task; + + /** + * Handle to a pending DNS lookup request. + */ + struct GNUNET_RESOLVER_RequestHandle *dns_active; + + /** + * The handle we return for GNUNET_CONNECTION_notify_transmit_ready. + */ + struct GNUNET_CONNECTION_TransmitHandle nth; + + /** + * Timeout for receiving (in absolute time). + */ + struct GNUNET_TIME_Absolute receive_timeout; + + /** + * Functions to call after connect failed or succeeded. + */ + enum ConnectContinuations ccs; + + /** + * Maximum number of bytes to read (for receiving). + */ + size_t max; + + /** + * Ignore GNUNET_SCHEDULER_REASON_SHUTDOWN for this socket. + */ + int ignore_shutdown; + + /** + * Port to connect to. + */ + uint16_t port; + + /** + * When shutdown, do not ever actually close the socket, but + * free resources. Only should ever be set if using program + * termination as a signal (because only then will the leaked + * socket be freed!) + */ + int16_t persist; + +}; + +/** + * Set the persist option on this connection handle. Indicates + * that the underlying socket or fd should never really be closed. + * Used for indicating process death. + * + * @param sock the connection to set persistent + */ +void +GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *sock) +{ + sock->persist = GNUNET_YES; +} + + +/** + * Disable the "CORK" feature for communication with the given socket, + * forcing the OS to immediately flush the buffer on transmission + * instead of potentially buffering multiple messages. Essentially + * reduces the OS send buffers to zero. + * Used to make sure that the last messages sent through the connection + * reach the other side before the process is terminated. + * + * @param sock the connection to make flushing and blocking + * @return GNUNET_OK on success + */ +int +GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *sock) +{ + return GNUNET_NETWORK_socket_disable_corking (sock->sock); +} + +/** + * Create a socket handle by boxing an existing OS socket. The OS + * socket should henceforth be no longer used directly. + * GNUNET_socket_destroy will close it. + * + * @param osSocket existing socket to box + * @return the boxed socket handle + */ +struct GNUNET_CONNECTION_Handle * +GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket) +{ + struct GNUNET_CONNECTION_Handle *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); + ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; + ret->write_buffer = GNUNET_malloc (ret->write_buffer_size); + ret->sock = osSocket; + return ret; +} + + +/** + * Create a socket handle by accepting on a listen socket. This + * function may block if the listen socket has no connection ready. + * + * @param access function to use to check if access is allowed + * @param access_cls closure for access + * @param lsock listen socket + * @return the socket handle, NULL on error + */ +struct GNUNET_CONNECTION_Handle * +GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, + void *access_cls, + struct GNUNET_NETWORK_Handle *lsock) +{ + struct GNUNET_CONNECTION_Handle *ret; + char addr[128]; + socklen_t addrlen; + struct GNUNET_NETWORK_Handle *sock; + int aret; + struct sockaddr_in *v4; + struct sockaddr_in6 *v6; + struct sockaddr *sa; + void *uaddr; + struct GNUNET_CONNECTION_Credentials *gcp; + struct GNUNET_CONNECTION_Credentials gc; + +#ifdef SO_PEERCRED + struct ucred uc; + socklen_t olen; +#endif + + addrlen = sizeof (addr); + sock = + GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen); + if (NULL == sock) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept"); + return NULL; + } + if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t))) + { + GNUNET_break (0); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); + return NULL; + } + + sa = (struct sockaddr *) addr; + v6 = (struct sockaddr_in6 *) addr; + if ((sa->sa_family == AF_INET6) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr))) + { + /* convert to V4 address */ + v4 = GNUNET_malloc (sizeof (struct sockaddr_in)); + memset (v4, 0, sizeof (struct sockaddr_in)); + v4->sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + v4->sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + memcpy (&v4->sin_addr, + &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) - + sizeof (struct in_addr)], + sizeof (struct in_addr)); + v4->sin_port = v6->sin6_port; + uaddr = v4; + addrlen = sizeof (struct sockaddr_in); + } + else + { + uaddr = GNUNET_malloc (addrlen); + memcpy (uaddr, addr, addrlen); + } + gcp = NULL; + gc.uid = 0; + gc.gid = 0; + if (sa->sa_family == AF_UNIX) + { +#if HAVE_GETPEEREID + /* most BSDs */ + if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), &gc.uid, &gc.gid)) + gcp = &gc; +#else +#ifdef SO_PEERCRED + /* largely traditional GNU/Linux */ + olen = sizeof (uc); + if ((0 == + getsockopt (GNUNET_NETWORK_get_fd (sock), SOL_SOCKET, SO_PEERCRED, &uc, + &olen)) && (olen == sizeof (uc))) + { + gc.uid = uc.uid; + gc.gid = uc.gid; + gcp = &gc; + } +#else +#if HAVE_GETPEERUCRED + /* this is for Solaris 10 */ + ucred_t *uc; + + uc = NULL; + if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc)) + { + gc.uid = ucred_geteuid (uc); + gc.gid = ucred_getegid (uc); + gcp = &gc; + } + ucred_free (uc); +#endif +#endif +#endif + } + + if ((access != NULL) && + (GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen)))) + { + if (aret == GNUNET_NO) + LOG (GNUNET_ERROR_TYPE_INFO, _("Access denied to `%s'\n"), + GNUNET_a2s (uaddr, addrlen)); + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_shutdown (sock, SHUT_RDWR)); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); + GNUNET_free (uaddr); + return NULL; + } + ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); + ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; + ret->write_buffer = GNUNET_malloc (ret->write_buffer_size); + ret->addr = uaddr; + ret->addrlen = addrlen; + ret->sock = sock; + LOG (GNUNET_ERROR_TYPE_INFO, + _("Accepting connection from `%s': %p\n"), + GNUNET_a2s (uaddr, addrlen), ret); + return ret; +} + +/** + * Obtain the network address of the other party. + * + * @param sock the client to get the address for + * @param addr where to store the address + * @param addrlen where to store the length of the address + * @return GNUNET_OK on success + */ +int +GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *sock, + void **addr, size_t * addrlen) +{ + if ((sock->addr == NULL) || (sock->addrlen == 0)) + return GNUNET_NO; + *addr = GNUNET_malloc (sock->addrlen); + memcpy (*addr, sock->addr, sock->addrlen); + *addrlen = sock->addrlen; + return GNUNET_OK; +} + + +/** + * This function is called after establishing a connection either has + * succeeded or timed out. Note that it is possible that the attempt + * timed out and that we're immediately retrying. If we are retrying, + * we need to wait again (or timeout); if we succeeded, we need to + * wait for data (or timeout). + * + * @param cls our connection handle + * @param tc task context describing why we are here + */ +static void +receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Scheduler let us know that the connect task is finished (or was + * cancelled due to shutdown). Now really clean up. + * + * @param cls our "struct GNUNET_CONNECTION_Handle *" + * @param tc unused + */ +static void +destroy_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONNECTION_Handle *sock = cls; + GNUNET_CONNECTION_TransmitReadyNotify notify; + struct AddressProbe *pos; + + sock->destroy_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (sock->dns_active == NULL); + if (0 != (sock->ccs & COCO_TRANSMIT_READY)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroy waits for CCS-TR to be done (%p)\n", + sock); + sock->ccs |= COCO_DESTROY_CONTINUATION; + return; + } + if (sock->write_task != GNUNET_SCHEDULER_NO_TASK) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Destroy waits for write_task to be done (%p)\n", sock); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task); + sock->destroy_task = + GNUNET_SCHEDULER_add_after (sock->write_task, &destroy_continuation, + sock); + return; + } + if (0 != (sock->ccs & COCO_RECEIVE_AGAIN)) + { + sock->ccs |= COCO_DESTROY_CONTINUATION; + return; + } + if (sock->sock != NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down socket (%p)\n", sock); + if (sock->persist != GNUNET_YES) + { + if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR)) + && (errno != ENOTCONN) && (errno != ECONNRESET)) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown"); + } + } + if (sock->read_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task); + sock->destroy_task = + GNUNET_SCHEDULER_add_after (sock->read_task, &destroy_continuation, + sock); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroy actually runs (%p)!\n", sock); + while (NULL != (pos = sock->ap_head)) + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); + GNUNET_SCHEDULER_cancel (pos->task); + GNUNET_CONTAINER_DLL_remove (sock->ap_head, sock->ap_tail, pos); + GNUNET_free (pos); + } + GNUNET_assert (sock->nth.timeout_task == GNUNET_SCHEDULER_NO_TASK); + GNUNET_assert (sock->ccs == COCO_NONE); + if (NULL != (notify = sock->nth.notify_ready)) + { + sock->nth.notify_ready = NULL; + notify (sock->nth.notify_ready_cls, 0, NULL); + } + + if (sock->sock != NULL) + { + if (sock->persist != GNUNET_YES) + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock)); + else + GNUNET_free (sock->sock); /* at least no memory leak (we deliberately + * leak the socket in this special case) ... */ + } + GNUNET_free_non_null (sock->addr); + GNUNET_free_non_null (sock->hostname); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Freeing memory of connection %p.\n", sock); + GNUNET_free (sock->write_buffer); + GNUNET_free (sock); +} + + + +/** + * See if we are now connected. If not, wait longer for + * connect to succeed. If connected, we should be able + * to write now as well, unless we timed out. + * + * @param cls our connection handle + * @param tc task context describing why we are here + */ +static void +transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * We've failed for good to establish a connection. + * + * @param h the connection we tried to establish + */ +static void +connect_fail_continuation (struct GNUNET_CONNECTION_Handle *h) +{ + LOG ((0 != + strncmp (h->hostname, "localhost:", + 10)) ? GNUNET_ERROR_TYPE_INFO : GNUNET_ERROR_TYPE_WARNING, + _ + ("Failed to establish TCP connection to `%s:%u', no further addresses to try.\n"), + h->hostname, h->port); + /* connect failed / timed out */ + GNUNET_break (h->ap_head == NULL); + GNUNET_break (h->ap_tail == NULL); + GNUNET_break (h->dns_active == GNUNET_NO); + GNUNET_break (h->sock == NULL); + + /* trigger jobs that used to wait on "connect_task" */ + if (0 != (h->ccs & COCO_RECEIVE_AGAIN)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "connect_fail_continuation triggers receive_again (%p)\n", h); + h->ccs -= COCO_RECEIVE_AGAIN; + h->read_task = GNUNET_SCHEDULER_add_now (&receive_again, h); + } + if (0 != (h->ccs & COCO_TRANSMIT_READY)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "connect_fail_continuation cancels timeout_task, triggers transmit_ready (%p)\n", + h); + GNUNET_assert (h->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK); + GNUNET_SCHEDULER_cancel (h->nth.timeout_task); + h->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; + h->ccs -= COCO_TRANSMIT_READY; + GNUNET_assert (h->nth.notify_ready != NULL); + GNUNET_assert (h->write_task == GNUNET_SCHEDULER_NO_TASK); + h->write_task = GNUNET_SCHEDULER_add_now (&transmit_ready, h); + } + if (0 != (h->ccs & COCO_DESTROY_CONTINUATION)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "connect_fail_continuation runs destroy_continuation (%p)\n", h); + h->ccs -= COCO_DESTROY_CONTINUATION; + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task); + h->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_continuation, h); + } +} + + +/** + * We've succeeded in establishing a connection. + * + * @param h the connection we tried to establish + */ +static void +connect_success_continuation (struct GNUNET_CONNECTION_Handle *h) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' succeeded! (%p)\n", + GNUNET_a2s (h->addr, h->addrlen), h); + /* trigger jobs that waited for the connection */ + if (0 != (h->ccs & COCO_RECEIVE_AGAIN)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "connect_success_continuation runs receive_again (%p)\n", h); + h->ccs -= COCO_RECEIVE_AGAIN; + h->read_task = GNUNET_SCHEDULER_add_now (&receive_again, h); + } + if (0 != (h->ccs & COCO_TRANSMIT_READY)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "connect_success_continuation runs transmit_ready, cancels timeout_task (%p)\n", + h); + GNUNET_assert (h->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK); + GNUNET_SCHEDULER_cancel (h->nth.timeout_task); + h->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; + h->ccs -= COCO_TRANSMIT_READY; + GNUNET_assert (h->write_task == GNUNET_SCHEDULER_NO_TASK); + GNUNET_assert (h->nth.notify_ready != NULL); + h->write_task = + GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining + (h->nth.transmit_timeout), h->sock, + &transmit_ready, h); + } + if (0 != (h->ccs & COCO_DESTROY_CONTINUATION)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "connect_success_continuation runs destroy_continuation (%p)\n", h); + h->ccs -= COCO_DESTROY_CONTINUATION; + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task); + h->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_continuation, h); + } +} + + +/** + * Scheduler let us know that we're either ready to write on the + * socket OR connect timed out. Do the right thing. + * + * @param cls the "struct AddressProbe*" with the address that we are probing + * @param tc success or failure info about the connect attempt. + */ +static void +connect_probe_continuation (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct AddressProbe *ap = cls; + struct GNUNET_CONNECTION_Handle *h = ap->h; + struct AddressProbe *pos; + int error; + socklen_t len; + + GNUNET_assert (ap->sock != NULL); + GNUNET_CONTAINER_DLL_remove (h->ap_head, h->ap_tail, ap); + len = sizeof (error); + errno = 0; + error = 0; + if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) || + (GNUNET_OK != + GNUNET_NETWORK_socket_getsockopt (ap->sock, SOL_SOCKET, SO_ERROR, &error, + &len)) || (error != 0)) + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); + GNUNET_free (ap); + if ((NULL == h->ap_head) && (h->dns_active == GNUNET_NO)) + connect_fail_continuation (h); + return; + } + GNUNET_assert (h->sock == NULL); + h->sock = ap->sock; + GNUNET_assert (h->addr == NULL); + h->addr = GNUNET_malloc (ap->addrlen); + memcpy (h->addr, ap->addr, ap->addrlen); + h->addrlen = ap->addrlen; + GNUNET_free (ap); + /* cancel all other attempts */ + while (NULL != (pos = h->ap_head)) + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); + GNUNET_SCHEDULER_cancel (pos->task); + GNUNET_CONTAINER_DLL_remove (h->ap_head, h->ap_tail, pos); + GNUNET_free (pos); + } + connect_success_continuation (h); +} + + +/** + * Try to establish a socket connection given the specified address. + * This function is called by the resolver once we have a DNS reply. + * + * @param cls our "struct GNUNET_CONNECTION_Handle *" + * @param addr address to try, NULL for "last call" + * @param addrlen length of addr + */ +static void +try_connect_using_address (void *cls, const struct sockaddr *addr, + socklen_t addrlen) +{ + struct GNUNET_CONNECTION_Handle *h = cls; + struct AddressProbe *ap; + struct GNUNET_TIME_Relative delay; + + if (addr == NULL) + { + h->dns_active = NULL; + if ((NULL == h->ap_head) && (NULL == h->sock)) + connect_fail_continuation (h); + return; + } + if (h->sock != NULL) + return; /* already connected */ + GNUNET_assert (h->addr == NULL); + /* try to connect */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Trying to connect using address `%s:%u/%s:%u'\n", h->hostname, h->port, + GNUNET_a2s (addr, addrlen), h->port); + ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen); + ap->addr = (const struct sockaddr *) &ap[1]; + memcpy (&ap[1], addr, addrlen); + ap->addrlen = addrlen; + ap->h = h; + + switch (ap->addr->sa_family) + { + case AF_INET: + ((struct sockaddr_in *) ap->addr)->sin_port = htons (h->port); + break; + case AF_INET6: + ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (h->port); + break; + default: + GNUNET_break (0); + GNUNET_free (ap); + return; /* not supported by us */ + } + ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0); + if (ap->sock == NULL) + { + GNUNET_free (ap); + return; /* not supported by OS */ + } + LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"), + GNUNET_a2s (ap->addr, ap->addrlen), h); + if ((GNUNET_OK != + GNUNET_NETWORK_socket_connect (ap->sock, ap->addr, ap->addrlen)) && + (errno != EINPROGRESS)) + { + /* maybe refused / unsupported address, try next */ + LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect"); +#if 0 + LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to connect to `%s' (%p)\n"), + GNUNET_a2s (ap->addr, ap->addrlen), h); +#endif + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); + GNUNET_free (ap); + return; + } + GNUNET_CONTAINER_DLL_insert (h->ap_head, h->ap_tail, ap); + delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT; + if (h->nth.notify_ready != NULL) + delay = + GNUNET_TIME_relative_min (delay, + GNUNET_TIME_absolute_get_remaining (h-> + nth.transmit_timeout)); + if (h->receiver != NULL) + delay = + GNUNET_TIME_relative_min (delay, + GNUNET_TIME_absolute_get_remaining + (h->receive_timeout)); + ap->task = + GNUNET_SCHEDULER_add_write_net (delay, ap->sock, + &connect_probe_continuation, ap); +} + + +/** + * Create a socket handle by (asynchronously) connecting to a host. + * This function returns immediately, even if the connection has not + * yet been established. This function only creates TCP connections. + * + * @param cfg configuration to use + * @param hostname name of the host to connect to + * @param port port to connect to + * @return the socket handle + */ +struct GNUNET_CONNECTION_Handle * +GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *hostname, + uint16_t port) +{ + struct GNUNET_CONNECTION_Handle *ret; + + GNUNET_assert (0 < strlen (hostname)); /* sanity check */ + ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); + ret->cfg = cfg; + ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; + ret->write_buffer = GNUNET_malloc (ret->write_buffer_size); + ret->port = port; + ret->hostname = GNUNET_strdup (hostname); + ret->dns_active = + GNUNET_RESOLVER_ip_get (ret->hostname, AF_UNSPEC, + GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, + &try_connect_using_address, ret); + return ret; +} + + +/** + * Create a socket handle by connecting to a UNIX domain service. + * This function returns immediately, even if the connection has not + * yet been established. This function only creates UNIX connections. + * + * @param cfg configuration to use + * @param unixpath path to connect to + * @return the socket handle, NULL on systems without UNIX support + */ +struct GNUNET_CONNECTION_Handle * +GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct + GNUNET_CONFIGURATION_Handle + *cfg, const char *unixpath) +{ +#ifdef AF_UNIX + struct GNUNET_CONNECTION_Handle *ret; + struct sockaddr_un *un; + size_t slen; + + GNUNET_assert (0 < strlen (unixpath)); /* sanity check */ + un = GNUNET_malloc (sizeof (struct sockaddr_un)); + un->sun_family = AF_UNIX; + slen = strlen (unixpath); + if (slen >= sizeof (un->sun_path)) + slen = sizeof (un->sun_path) - 1; + memcpy (un->sun_path, unixpath, slen); + un->sun_path[slen] = '\0'; + slen = sizeof (struct sockaddr_un); +#if HAVE_SOCKADDR_IN_SIN_LEN + un->sun_len = (u_char) slen; +#endif +#if LINUX + un->sun_path[0] = '\0'; +#endif + ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); + ret->cfg = cfg; + ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; + ret->write_buffer = GNUNET_malloc (ret->write_buffer_size); + ret->port = 0; + ret->hostname = NULL; + ret->addr = (struct sockaddr *) un; + ret->addrlen = slen; + ret->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); + if (NULL == ret->sock) + { + GNUNET_free (ret->addr); + GNUNET_free (ret->write_buffer); + GNUNET_free (ret); + return NULL; + } + if (GNUNET_OK != + GNUNET_NETWORK_socket_connect (ret->sock, ret->addr, ret->addrlen)) + { + /* Just return; we expect everything to work eventually so don't fail HARD */ + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret->sock)); + ret->sock = NULL; + return ret; + } + connect_success_continuation (ret); + return ret; +#else + return NULL; +#endif +} + + +/** + * Create a socket handle by (asynchronously) connecting to a host. + * This function returns immediately, even if the connection has not + * yet been established. This function only creates TCP connections. + * + * @param af_family address family to use + * @param serv_addr server address + * @param addrlen length of server address + * @return the socket handle + */ +struct GNUNET_CONNECTION_Handle * +GNUNET_CONNECTION_create_from_sockaddr (int af_family, + const struct sockaddr *serv_addr, + socklen_t addrlen) +{ + struct GNUNET_NETWORK_Handle *s; + struct GNUNET_CONNECTION_Handle *ret; + + + s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0); + if (s == NULL) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "socket"); + return NULL; + } + if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) && + (errno != EINPROGRESS)) + { + /* maybe refused / unsupported address, try next */ + LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect"); + LOG (GNUNET_ERROR_TYPE_INFO, _("Attempt to connect to `%s' failed\n"), + GNUNET_a2s (serv_addr, addrlen)); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s)); + return NULL; + } + ret = GNUNET_CONNECTION_create_from_existing (s); + ret->addr = GNUNET_malloc (addrlen); + memcpy (ret->addr, serv_addr, addrlen); + ret->addrlen = addrlen; + LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"), + GNUNET_a2s (serv_addr, addrlen), ret); + return ret; +} + + +/** + * Check if socket is valid (no fatal errors have happened so far). + * Note that a socket that is still trying to connect is considered + * valid. + * + * @param sock socket to check + * @return GNUNET_YES if valid, GNUNET_NO otherwise + */ +int +GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *sock) +{ + if ((sock->ap_head != NULL) || (sock->dns_active != NULL)) + return GNUNET_YES; /* still trying to connect */ + return (sock->sock == NULL) ? GNUNET_NO : GNUNET_YES; +} + + +/** + * Close the socket and free associated resources. Pending + * transmissions may be completed or dropped depending on the + * arguments. If a receive call is pending and should + * NOT be completed, 'GNUNET_CONNECTION_receive_cancel' + * should be called explicitly first. + * + * @param sock socket to destroy + * @param finish_pending_write should pending writes be completed or aborted? + * (this applies to transmissions where the data has already been + * read from the application; all other transmissions should be + * aborted using 'GNUNET_CONNECTION_notify_transmit_ready_cancel'). + */ +void +GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *sock, + int finish_pending_write) +{ + if (GNUNET_NO == finish_pending_write) + { + if (sock->write_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (sock->write_task); + sock->write_task = GNUNET_SCHEDULER_NO_TASK; + sock->write_buffer_off = 0; + } + sock->nth.notify_ready = NULL; + } + if ((sock->write_buffer_off == 0) && (sock->dns_active != NULL)) + { + GNUNET_RESOLVER_request_cancel (sock->dns_active); + sock->dns_active = NULL; + } + + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task); + sock->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_continuation, sock); +} + + +/** + * Tell the receiver callback that a timeout was reached. + */ +static void +signal_timeout (struct GNUNET_CONNECTION_Handle *sh) +{ + GNUNET_CONNECTION_Receiver receiver; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Network signals time out to receiver (%p)!\n", + sh); + GNUNET_assert (NULL != (receiver = sh->receiver)); + sh->receiver = NULL; + receiver (sh->receiver_cls, NULL, 0, NULL, 0, 0); +} + + +/** + * Tell the receiver callback that we had an IO error. + */ +static void +signal_error (struct GNUNET_CONNECTION_Handle *sh, int errcode) +{ + GNUNET_CONNECTION_Receiver receiver; + + GNUNET_assert (NULL != (receiver = sh->receiver)); + sh->receiver = NULL; + receiver (sh->receiver_cls, NULL, 0, sh->addr, sh->addrlen, errcode); +} + + +/** + * This function is called once we either timeout + * or have data ready to read. + */ +static void +receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONNECTION_Handle *sh = cls; + struct GNUNET_TIME_Absolute now; + char buffer[sh->max]; + ssize_t ret; + GNUNET_CONNECTION_Receiver receiver; + + sh->read_task = GNUNET_SCHEDULER_NO_TASK; + if ((GNUNET_YES == sh->ignore_shutdown) && + (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))) + { + /* ignore shutdown request, go again immediately */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Ignoring shutdown signal per configuration\n"); + sh->read_task = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining + (sh->receive_timeout), sh->sock, + &receive_ready, sh); + return; + } + now = GNUNET_TIME_absolute_get (); + if ((now.abs_value > sh->receive_timeout.abs_value) || + (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) || + (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))) + { + if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Receive from `%s' encounters error: time out by %llums... (%p)\n", + GNUNET_a2s (sh->addr, sh->addrlen), + GNUNET_TIME_absolute_get_duration (sh->receive_timeout).rel_value, + sh); + signal_timeout (sh); + return; + } + if (sh->sock == NULL) + { + /* connect failed for good */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Receive encounters error, socket closed... (%p)\n", sh); + signal_error (sh, ECONNREFUSED); + return; + } + GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, sh->sock)); +RETRY: + ret = GNUNET_NETWORK_socket_recv (sh->sock, buffer, sh->max); + if (ret == -1) + { + if (errno == EINTR) + goto RETRY; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Error receiving: %s\n", STRERROR (errno)); + signal_error (sh, errno); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "receive_ready read %u/%u bytes from `%s' (%p)!\n", (unsigned int) ret, + sh->max, GNUNET_a2s (sh->addr, sh->addrlen), sh); + GNUNET_assert (NULL != (receiver = sh->receiver)); + sh->receiver = NULL; + receiver (sh->receiver_cls, buffer, ret, sh->addr, sh->addrlen, 0); +} + + +/** + * This function is called after establishing a connection either has + * succeeded or timed out. Note that it is possible that the attempt + * timed out and that we're immediately retrying. If we are retrying, + * we need to wait again (or timeout); if we succeeded, we need to + * wait for data (or timeout). + * + * @param cls our connection handle + * @param tc task context describing why we are here + */ +static void +receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONNECTION_Handle *sh = cls; + struct GNUNET_TIME_Absolute now; + + sh->read_task = GNUNET_SCHEDULER_NO_TASK; + if (sh->sock == NULL) + { + /* not connected and no longer trying */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Receive encounters error, socket closed (%p)...\n", sh); + signal_error (sh, ECONNREFUSED); + return; + } + now = GNUNET_TIME_absolute_get (); + if ((now.abs_value > sh->receive_timeout.abs_value) || + (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Receive encounters error: time out (%p)...\n", sh); + signal_timeout (sh); + return; + } + GNUNET_assert (sh->sock != NULL); + /* connect succeeded, wait for data! */ + sh->read_task = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining + (sh->receive_timeout), sh->sock, + &receive_ready, sh); +} + + +/** + * Receive data from the given socket. Note that this function will + * call "receiver" asynchronously using the scheduler. It will + * "immediately" return. Note that there MUST only be one active + * receive call per socket at any given point in time (so do not + * call receive again until the receiver callback has been invoked). + * + * @param sock socket handle + * @param max maximum number of bytes to read + * @param timeout maximum amount of time to wait (use -1 for "forever") + * @param receiver function to call with received data + * @param receiver_cls closure for receiver + */ +void +GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *sock, size_t max, + struct GNUNET_TIME_Relative timeout, + GNUNET_CONNECTION_Receiver receiver, + void *receiver_cls) +{ + struct GNUNET_SCHEDULER_TaskContext tc; + + GNUNET_assert ((sock->read_task == GNUNET_SCHEDULER_NO_TASK) && + (0 == (sock->ccs & COCO_RECEIVE_AGAIN)) && + (sock->receiver == NULL)); + sock->receiver = receiver; + sock->receiver_cls = receiver_cls; + sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); + sock->max = max; + if (sock->sock != NULL) + { + memset (&tc, 0, sizeof (tc)); + tc.reason = GNUNET_SCHEDULER_REASON_PREREQ_DONE; + receive_again (sock, &tc); + return; + } + if ((sock->dns_active == NULL) && (sock->ap_head == NULL)) + { + receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT); + return; + } + sock->ccs += COCO_RECEIVE_AGAIN; +} + + +/** + * Configure this connection to ignore shutdown signals. + * + * @param sock socket handle + * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default + */ +void +GNUNET_CONNECTION_ignore_shutdown (struct GNUNET_CONNECTION_Handle *sock, + int do_ignore) +{ + sock->ignore_shutdown = do_ignore; +} + + +/** + * Cancel receive job on the given socket. Note that the + * receiver callback must not have been called yet in order + * for the cancellation to be valid. + * + * @param sock socket handle + * @return closure of the original receiver callback closure + */ +void * +GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock) +{ + if (sock->read_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_assert (sock == GNUNET_SCHEDULER_cancel (sock->read_task)); + sock->read_task = GNUNET_SCHEDULER_NO_TASK; + } + else + { + GNUNET_assert (0 != (sock->ccs & COCO_RECEIVE_AGAIN)); + sock->ccs -= COCO_RECEIVE_AGAIN; + } + sock->receiver = NULL; + return sock->receiver_cls; +} + + +/** + * Try to call the transmit notify method (check if we do + * have enough space available first)! + * + * @param sock socket for which we should do this processing + * @return GNUNET_YES if we were able to call notify + */ +static int +process_notify (struct GNUNET_CONNECTION_Handle *sock) +{ + size_t used; + size_t avail; + size_t size; + GNUNET_CONNECTION_TransmitReadyNotify notify; + + GNUNET_assert (sock->write_task == GNUNET_SCHEDULER_NO_TASK); + if (NULL == (notify = sock->nth.notify_ready)) + return GNUNET_NO; + used = sock->write_buffer_off - sock->write_buffer_pos; + avail = sock->write_buffer_size - used; + size = sock->nth.notify_size; + if (size > avail) + return GNUNET_NO; + sock->nth.notify_ready = NULL; + if (sock->write_buffer_size - sock->write_buffer_off < size) + { + /* need to compact */ + memmove (sock->write_buffer, &sock->write_buffer[sock->write_buffer_pos], + used); + sock->write_buffer_off -= sock->write_buffer_pos; + sock->write_buffer_pos = 0; + } + avail = sock->write_buffer_size - sock->write_buffer_off; + GNUNET_assert (avail >= size); + size = + notify (sock->nth.notify_ready_cls, avail, + &sock->write_buffer[sock->write_buffer_off]); + GNUNET_assert (size <= avail); + sock->write_buffer_off += size; + return GNUNET_YES; +} + + +/** + * Task invoked by the scheduler when a call to transmit + * is timing out (we never got enough buffer space to call + * the callback function before the specified timeout + * expired). + * + * This task notifies the client about the timeout. + * + * @param cls the 'struct GNUNET_CONNECTION_Handle' + * @param tc scheduler context + */ +static void +transmit_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONNECTION_Handle *sock = cls; + GNUNET_CONNECTION_TransmitReadyNotify notify; + + sock->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmit to `%s:%u/%s' fails, time out reached (%p).\n", + sock->hostname, + sock->port, GNUNET_a2s (sock->addr, sock->addrlen), sock); + GNUNET_assert (0 != (sock->ccs & COCO_TRANSMIT_READY)); + sock->ccs -= COCO_TRANSMIT_READY; /* remove request */ + notify = sock->nth.notify_ready; + sock->nth.notify_ready = NULL; + notify (sock->nth.notify_ready_cls, 0, NULL); +} + + +/** + * Task invoked by the scheduler when we failed to connect + * at the time of being asked to transmit. + * + * This task notifies the client about the error. + * + * @param cls the 'struct GNUNET_CONNECTION_Handle' + * @param tc scheduler context + */ +static void +connect_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONNECTION_Handle *sock = cls; + GNUNET_CONNECTION_TransmitReadyNotify notify; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmission request of size %u fails (%s/%u), connection failed (%p).\n", + sock->nth.notify_size, sock->hostname, sock->port, sock); + sock->write_task = GNUNET_SCHEDULER_NO_TASK; + notify = sock->nth.notify_ready; + sock->nth.notify_ready = NULL; + notify (sock->nth.notify_ready_cls, 0, NULL); +} + + +/** + * FIXME + * + * @param sock FIXME + */ +static void +transmit_error (struct GNUNET_CONNECTION_Handle *sock) +{ + GNUNET_CONNECTION_TransmitReadyNotify notify; + + if (NULL != sock->sock) + { + GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock)); + sock->sock = NULL; + } + if (sock->read_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (sock->read_task); + sock->read_task = GNUNET_SCHEDULER_NO_TASK; + signal_timeout (sock); + return; + } + if (sock->nth.notify_ready == NULL) + return; /* nobody to tell about it */ + notify = sock->nth.notify_ready; + sock->nth.notify_ready = NULL; + notify (sock->nth.notify_ready_cls, 0, NULL); +} + + +/** + * See if we are now connected. If not, wait longer for + * connect to succeed. If connected, we should be able + * to write now as well, unless we timed out. + * + * @param cls our connection handle + * @param tc task context describing why we are here + */ +static void +transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CONNECTION_Handle *sock = cls; + GNUNET_CONNECTION_TransmitReadyNotify notify; + ssize_t ret; + size_t have; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_ready running (%p).\n", sock); + GNUNET_assert (sock->write_task != GNUNET_SCHEDULER_NO_TASK); + sock->write_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (sock->nth.timeout_task == GNUNET_SCHEDULER_NO_TASK); + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + if ((sock->ignore_shutdown == GNUNET_YES) && (NULL != sock->sock)) + goto SCHEDULE_WRITE; /* ignore shutdown, go again immediately */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmit to `%s' fails, shutdown happened (%p).\n", + GNUNET_a2s (sock->addr, sock->addrlen), sock); + notify = sock->nth.notify_ready; + if (NULL != notify) + { + sock->nth.notify_ready = NULL; + notify (sock->nth.notify_ready_cls, 0, NULL); + } + return; + } + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmit to `%s' fails, time out reached (%p).\n", + GNUNET_a2s (sock->addr, sock->addrlen), sock); + notify = sock->nth.notify_ready; + GNUNET_assert (NULL != notify); + sock->nth.notify_ready = NULL; + notify (sock->nth.notify_ready_cls, 0, NULL); + return; + } + GNUNET_assert (NULL != sock->sock); + if (tc->write_ready == NULL) + { + /* special circumstances (in particular, + * PREREQ_DONE after connect): not yet ready to write, + * but no "fatal" error either. Hence retry. */ + goto SCHEDULE_WRITE; + } + if (!GNUNET_NETWORK_fdset_isset (tc->write_ready, sock->sock)) + { + LOG (GNUNET_ERROR_TYPE_INFO, + _ + ("Could not satisfy pending transmission request, socket closed or connect failed (%p).\n"), + sock); + transmit_error (sock); + return; /* connect failed for good, we're finished */ + } + GNUNET_assert (sock->write_buffer_off >= sock->write_buffer_pos); + if ((sock->nth.notify_ready != NULL) && + (sock->write_buffer_size < sock->nth.notify_size)) + { + sock->write_buffer = + GNUNET_realloc (sock->write_buffer, sock->nth.notify_size); + sock->write_buffer_size = sock->nth.notify_size; + } + process_notify (sock); + have = sock->write_buffer_off - sock->write_buffer_pos; + if (have == 0) + { + /* no data ready for writing, terminate write loop */ + return; + } + GNUNET_assert (have <= sock->write_buffer_size); + GNUNET_assert (have + sock->write_buffer_pos <= sock->write_buffer_size); + GNUNET_assert (sock->write_buffer_pos <= sock->write_buffer_size); +RETRY: + ret = + GNUNET_NETWORK_socket_send (sock->sock, + &sock->write_buffer[sock->write_buffer_pos], + have); + if (ret == -1) + { + if (errno == EINTR) + goto RETRY; + LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "send"); + transmit_error (sock); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "transmit_ready transmitted %u/%u bytes to `%s' (%p)\n", + (unsigned int) ret, have, GNUNET_a2s (sock->addr, sock->addrlen), sock); + sock->write_buffer_pos += ret; + if (sock->write_buffer_pos == sock->write_buffer_off) + { + /* transmitted all pending data */ + sock->write_buffer_pos = 0; + sock->write_buffer_off = 0; + } + if ((sock->write_buffer_off == 0) && (NULL == sock->nth.notify_ready)) + return; /* all data sent! */ + /* not done writing, schedule more */ +SCHEDULE_WRITE: + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Re-scheduling transmit_ready (more to do) (%p).\n", sock); + have = sock->write_buffer_off - sock->write_buffer_pos; + GNUNET_assert ((sock->nth.notify_ready != NULL) || (have > 0)); + if (sock->write_task == GNUNET_SCHEDULER_NO_TASK) + sock->write_task = + GNUNET_SCHEDULER_add_write_net ((sock->nth.notify_ready == + NULL) ? GNUNET_TIME_UNIT_FOREVER_REL : + GNUNET_TIME_absolute_get_remaining + (sock->nth.transmit_timeout), + sock->sock, &transmit_ready, sock); +} + + +/** + * Ask the socket to call us once the specified number of bytes + * are free in the transmission buffer. May call the notify + * method immediately if enough space is available. + * + * @param sock socket + * @param size number of bytes to send + * @param timeout after how long should we give up (and call + * notify with buf NULL and size 0)? + * @param notify function to call + * @param notify_cls closure for notify + * @return non-NULL if the notify callback was queued, + * NULL if we are already going to notify someone else (busy) + */ +struct GNUNET_CONNECTION_TransmitHandle * +GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *sock, + size_t size, + struct GNUNET_TIME_Relative timeout, + GNUNET_CONNECTION_TransmitReadyNotify + notify, void *notify_cls) +{ + if (sock->nth.notify_ready != NULL) + { + GNUNET_assert (0); + return NULL; + } + GNUNET_assert (notify != NULL); + GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); + GNUNET_assert (sock->write_buffer_off <= sock->write_buffer_size); + GNUNET_assert (sock->write_buffer_pos <= sock->write_buffer_size); + GNUNET_assert (sock->write_buffer_pos <= sock->write_buffer_off); + sock->nth.notify_ready = notify; + sock->nth.notify_ready_cls = notify_cls; + sock->nth.sh = sock; + sock->nth.notify_size = size; + sock->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->nth.timeout_task); + if ((sock->sock == NULL) && (sock->ap_head == NULL) && + (sock->dns_active == NULL)) + { + if (sock->write_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (sock->write_task); + sock->write_task = GNUNET_SCHEDULER_add_now (&connect_error, sock); + return &sock->nth; + } + if (GNUNET_SCHEDULER_NO_TASK != sock->write_task) + return &sock->nth; + if (sock->sock != NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling transmit_ready (%p).\n", sock); + sock->write_task = + GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining + (sock->nth.transmit_timeout), + sock->sock, &transmit_ready, sock); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "CCS-Scheduling transmit_ready, adding timeout task (%p).\n", sock); + sock->ccs |= COCO_TRANSMIT_READY; + sock->nth.timeout_task = + GNUNET_SCHEDULER_add_delayed (timeout, &transmit_timeout, sock); + } + return &sock->nth; +} + + +/** + * Cancel the specified transmission-ready notification. + * + * @param th notification to cancel + */ +void +GNUNET_CONNECTION_notify_transmit_ready_cancel (struct + GNUNET_CONNECTION_TransmitHandle + *th) +{ + GNUNET_assert (th->notify_ready != NULL); + if (0 != (th->sh->ccs & COCO_TRANSMIT_READY)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "notify_transmit_ready_cancel cancels timeout_task (%p)\n", th); + GNUNET_SCHEDULER_cancel (th->timeout_task); + th->timeout_task = GNUNET_SCHEDULER_NO_TASK; + th->sh->ccs -= COCO_TRANSMIT_READY; + } + else + { + if (th->sh->write_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (th->sh->write_task); + th->sh->write_task = GNUNET_SCHEDULER_NO_TASK; + } + } + th->notify_ready = NULL; +} + +/* end of connection.c */ diff --git a/src/util/container_bloomfilter.c b/src/util/container_bloomfilter.c new file mode 100644 index 0000000..84aab6b --- /dev/null +++ b/src/util/container_bloomfilter.c @@ -0,0 +1,858 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2006, 2008, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/container_bloomfilter.c + * @brief data structure used to reduce disk accesses. + * + * The idea basically: Create a signature for each element in the + * database. Add those signatures to a bit array. When doing a lookup, + * check if the bit array matches the signature of the requested + * element. If yes, address the disk, otherwise return 'not found'. + * + * A property of the bloom filter is that sometimes we will have + * a match even if the element is not on the disk (then we do + * an unnecessary disk access), but what's most important is that + * we never get a single "false negative". + * + * To be able to delete entries from the bloom filter, we maintain + * a 4 bit counter in the file on the drive (we still use only one + * bit in memory). + * + * @author Igor Wronsky + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" +#include "gnunet_disk_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +struct GNUNET_CONTAINER_BloomFilter +{ + + /** + * The actual bloomfilter bit array + */ + char *bitArray; + + /** + * Filename of the filter + */ + char *filename; + + /** + * The bit counter file on disk + */ + struct GNUNET_DISK_FileHandle *fh; + + /** + * How many bits we set for each stored element + */ + unsigned int addressesPerElement; + + /** + * Size of bitArray in bytes + */ + size_t bitArraySize; + +}; + + + +/** + * Get size of the bloom filter. + * + * @param bf the filter + * @return number of bytes used for the data of the bloom filter + */ +size_t +GNUNET_CONTAINER_bloomfilter_get_size (const struct GNUNET_CONTAINER_BloomFilter + *bf) +{ + if (bf == NULL) + return 0; + return bf->bitArraySize; +} + + +/** + * Copy an existing memory. Any association with a file + * on-disk will be lost in the process. + * @param bf the filter to copy + * @return copy of the bf + */ +struct GNUNET_CONTAINER_BloomFilter * +GNUNET_CONTAINER_bloomfilter_copy (const struct GNUNET_CONTAINER_BloomFilter + *bf) +{ + return GNUNET_CONTAINER_bloomfilter_init (bf->bitArray, bf->bitArraySize, + bf->addressesPerElement); +} + + +/** + * Sets a bit active in the bitArray. Increment bit-specific + * usage counter on disk only if below 4bit max (==15). + * + * @param bitArray memory area to set the bit in + * @param bitIdx which bit to set + */ +static void +setBit (char *bitArray, unsigned int bitIdx) +{ + size_t arraySlot; + unsigned int targetBit; + + arraySlot = bitIdx / 8; + targetBit = (1L << (bitIdx % 8)); + bitArray[arraySlot] |= targetBit; +} + +/** + * Clears a bit from bitArray. Bit is cleared from the array + * only if the respective usage counter on the disk hits/is zero. + * + * @param bitArray memory area to set the bit in + * @param bitIdx which bit to unset + */ +static void +clearBit (char *bitArray, unsigned int bitIdx) +{ + size_t slot; + unsigned int targetBit; + + slot = bitIdx / 8; + targetBit = (1L << (bitIdx % 8)); + bitArray[slot] = bitArray[slot] & (~targetBit); +} + +/** + * Checks if a bit is active in the bitArray + * + * @param bitArray memory area to set the bit in + * @param bitIdx which bit to test + * @return GNUNET_YES if the bit is set, GNUNET_NO if not. + */ +static int +testBit (char *bitArray, unsigned int bitIdx) +{ + size_t slot; + unsigned int targetBit; + + slot = bitIdx / 8; + targetBit = (1L << (bitIdx % 8)); + if (bitArray[slot] & targetBit) + return GNUNET_YES; + else + return GNUNET_NO; +} + +/** + * Sets a bit active in the bitArray and increments + * bit-specific usage counter on disk (but only if + * the counter was below 4 bit max (==15)). + * + * @param bitArray memory area to set the bit in + * @param bitIdx which bit to test + * @param fh A file to keep the 4 bit address usage counters in + */ +static void +incrementBit (char *bitArray, unsigned int bitIdx, + const struct GNUNET_DISK_FileHandle *fh) +{ + OFF_T fileSlot; + unsigned char value; + unsigned int high; + unsigned int low; + unsigned int targetLoc; + + setBit (bitArray, bitIdx); + if (GNUNET_DISK_handle_invalid (fh)) + return; + /* Update the counter file on disk */ + fileSlot = bitIdx / 2; + targetLoc = bitIdx % 2; + + GNUNET_assert (fileSlot == + GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET)); + if (1 != GNUNET_DISK_file_read (fh, &value, 1)) + value = 0; + low = value & 0xF; + high = (value & (~0xF)) >> 4; + + if (targetLoc == 0) + { + if (low < 0xF) + low++; + } + else + { + if (high < 0xF) + high++; + } + value = ((high << 4) | low); + GNUNET_assert (fileSlot == + GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET)); + GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1)); +} + +/** + * Clears a bit from bitArray if the respective usage + * counter on the disk hits/is zero. + * + * @param bitArray memory area to set the bit in + * @param bitIdx which bit to test + * @param fh A file to keep the 4bit address usage counters in + */ +static void +decrementBit (char *bitArray, unsigned int bitIdx, + const struct GNUNET_DISK_FileHandle *fh) +{ + OFF_T fileSlot; + unsigned char value; + unsigned int high; + unsigned int low; + unsigned int targetLoc; + + if (GNUNET_DISK_handle_invalid (fh)) + return; /* cannot decrement! */ + /* Each char slot in the counter file holds two 4 bit counters */ + fileSlot = bitIdx / 2; + targetLoc = bitIdx % 2; + GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET); + if (1 != GNUNET_DISK_file_read (fh, &value, 1)) + value = 0; + low = value & 0xF; + high = (value & 0xF0) >> 4; + + /* decrement, but once we have reached the max, never go back! */ + if (targetLoc == 0) + { + if ((low > 0) && (low < 0xF)) + low--; + if (low == 0) + { + clearBit (bitArray, bitIdx); + } + } + else + { + if ((high > 0) && (high < 0xF)) + high--; + if (high == 0) + { + clearBit (bitArray, bitIdx); + } + } + value = ((high << 4) | low); + GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET); + GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1)); +} + +#define BUFFSIZE 65536 + +/** + * Creates a file filled with zeroes + * + * @param fh the file handle + * @param size the size of the file + * @return GNUNET_OK if created ok, GNUNET_SYSERR otherwise + */ +static int +make_empty_file (const struct GNUNET_DISK_FileHandle *fh, size_t size) +{ + char buffer[BUFFSIZE]; + size_t bytesleft = size; + int res = 0; + + if (GNUNET_DISK_handle_invalid (fh)) + return GNUNET_SYSERR; + memset (buffer, 0, sizeof (buffer)); + GNUNET_DISK_file_seek (fh, 0, GNUNET_DISK_SEEK_SET); + while (bytesleft > 0) + { + if (bytesleft > sizeof (buffer)) + { + res = GNUNET_DISK_file_write (fh, buffer, sizeof (buffer)); + if (res >= 0) + bytesleft -= res; + } + else + { + res = GNUNET_DISK_file_write (fh, buffer, bytesleft); + if (res >= 0) + bytesleft -= res; + } + if (GNUNET_SYSERR == res) + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +/* ************** GNUNET_CONTAINER_BloomFilter iterator ********* */ + +/** + * Iterator (callback) method to be called by the + * bloomfilter iterator on each bit that is to be + * set or tested for the key. + * + * @param cls closure + * @param bf the filter to manipulate + * @param bit the current bit + * @return GNUNET_YES to continue, GNUNET_NO to stop early + */ +typedef int (*BitIterator) (void *cls, + const struct GNUNET_CONTAINER_BloomFilter * bf, + unsigned int bit); + + +/** + * Call an iterator for each bit that the bloomfilter + * must test or set for this element. + * + * @param bf the filter + * @param callback the method to call + * @param arg extra argument to callback + * @param key the key for which we iterate over the BF bits + */ +static void +iterateBits (const struct GNUNET_CONTAINER_BloomFilter *bf, + BitIterator callback, void *arg, const GNUNET_HashCode * key) +{ + GNUNET_HashCode tmp[2]; + int bitCount; + unsigned int round; + unsigned int slot = 0; + + bitCount = bf->addressesPerElement; + tmp[0] = *key; + round = 0; + while (bitCount > 0) + { + while (slot < (sizeof (GNUNET_HashCode) / sizeof (uint32_t))) + { + if (GNUNET_YES != + callback (arg, bf, + (((uint32_t *) & tmp[round & 1])[slot]) & + ((bf->bitArraySize * 8) - 1))) + return; + slot++; + bitCount--; + if (bitCount == 0) + break; + } + if (bitCount > 0) + { + GNUNET_CRYPTO_hash (&tmp[round & 1], sizeof (GNUNET_HashCode), + &tmp[(round + 1) & 1]); + round++; + slot = 0; + } + } +} + + +/** + * Callback: increment bit + * + * @param cls pointer to writeable form of bf + * @param bf the filter to manipulate + * @param bit the bit to increment + * @return GNUNET_YES + */ +static int +incrementBitCallback (void *cls, const struct GNUNET_CONTAINER_BloomFilter *bf, + unsigned int bit) +{ + struct GNUNET_CONTAINER_BloomFilter *b = cls; + + incrementBit (b->bitArray, bit, bf->fh); + return GNUNET_YES; +} + + +/** + * Callback: decrement bit + * + * @param cls pointer to writeable form of bf + * @param bf the filter to manipulate + * @param bit the bit to decrement + * @return GNUNET_YES + */ +static int +decrementBitCallback (void *cls, const struct GNUNET_CONTAINER_BloomFilter *bf, + unsigned int bit) +{ + struct GNUNET_CONTAINER_BloomFilter *b = cls; + + decrementBit (b->bitArray, bit, bf->fh); + return GNUNET_YES; +} + + +/** + * Callback: test if all bits are set + * + * @param cls pointer set to GNUNET_NO if bit is not set + * @param bf the filter + * @param bit the bit to test + * @return YES if the bit is set, NO if not + */ +static int +testBitCallback (void *cls, const struct GNUNET_CONTAINER_BloomFilter *bf, + unsigned int bit) +{ + int *arg = cls; + + if (GNUNET_NO == testBit (bf->bitArray, bit)) + { + *arg = GNUNET_NO; + return GNUNET_NO; + } + return GNUNET_YES; +} + +/* *********************** INTERFACE **************** */ + +/** + * Load a bloom-filter from a file. + * + * @param filename the name of the file (or the prefix) + * @param size the size of the bloom-filter (number of + * bytes of storage space to use) + * @param k the number of GNUNET_CRYPTO_hash-functions to apply per + * element (number of bits set per element in the set) + * @return the bloomfilter + */ +struct GNUNET_CONTAINER_BloomFilter * +GNUNET_CONTAINER_bloomfilter_load (const char *filename, size_t size, + unsigned int k) +{ + struct GNUNET_CONTAINER_BloomFilter *bf; + char *rbuff; + OFF_T pos; + int i; + size_t ui; + OFF_T fsize; + int must_read; + + GNUNET_assert (NULL != filename); + if ((k == 0) || (size == 0)) + return NULL; + if (size < BUFFSIZE) + size = BUFFSIZE; + ui = 1; + while ( (ui < size) && + (ui * 2 > ui) ) + ui *= 2; + size = ui; /* make sure it's a power of 2 */ + + bf = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_BloomFilter)); + /* Try to open a bloomfilter file */ + if (GNUNET_YES == GNUNET_DISK_file_test (filename)) + bf->fh = + GNUNET_DISK_file_open (filename, + GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (NULL != bf->fh) + { + /* file existed, try to read it! */ + must_read = GNUNET_YES; + if (GNUNET_OK != + GNUNET_DISK_file_handle_size (bf->fh, &fsize)) + { + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf); + return NULL; + } + if (fsize == 0) + { + /* found existing empty file, just overwrite */ + if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "write"); + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf); + return NULL; + } + } + else if (fsize != size * 4LL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Size of file on disk is incorrect for this Bloom filter (want %llu, have %llu)\n"), + (unsigned long long) (size * 4LL), + (unsigned long long) fsize); + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf); + return NULL; + } + } + else + { + /* file did not exist, don't read, just create */ + must_read = GNUNET_NO; + bf->fh = + GNUNET_DISK_file_open (filename, + GNUNET_DISK_OPEN_CREATE | + GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (NULL == bf->fh) + { + GNUNET_free (bf); + return NULL; + } + if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "write"); + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf); + return NULL; + } + } + bf->filename = GNUNET_strdup (filename); + /* Alloc block */ + bf->bitArray = GNUNET_malloc_large (size); + if (bf->bitArray == NULL) + { + if (bf->fh != NULL) + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf->filename); + GNUNET_free (bf); + return NULL; + } + bf->bitArraySize = size; + bf->addressesPerElement = k; + memset (bf->bitArray, 0, bf->bitArraySize); + + if (GNUNET_YES != must_read) + return bf; /* already done! */ + /* Read from the file what bits we can */ + rbuff = GNUNET_malloc (BUFFSIZE); + pos = 0; + while (pos < size * 8LL) + { + int res; + + res = GNUNET_DISK_file_read (bf->fh, rbuff, BUFFSIZE); + if (res == -1) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", bf->filename); + GNUNET_free (rbuff); + GNUNET_free (bf->filename); + GNUNET_DISK_file_close (bf->fh); + GNUNET_free (bf); + return NULL; + } + if (res == 0) + break; /* is ok! we just did not use that many bits yet */ + for (i = 0; i < res; i++) + { + if ((rbuff[i] & 0x0F) != 0) + setBit (bf->bitArray, pos + i * 2); + if ((rbuff[i] & 0xF0) != 0) + setBit (bf->bitArray, pos + i * 2 + 1); + } + if (res < BUFFSIZE) + break; + pos += BUFFSIZE * 2; /* 2 bits per byte in the buffer */ + } + GNUNET_free (rbuff); + return bf; +} + + +/** + * Create a bloom filter from raw bits. + * + * @param data the raw bits in memory (maybe NULL, + * in which case all bits should be considered + * to be zero). + * @param size the size of the bloom-filter (number of + * bytes of storage space to use); also size of data + * -- unless data is NULL + * @param k the number of GNUNET_CRYPTO_hash-functions to apply per + * element (number of bits set per element in the set) + * @return the bloomfilter + */ +struct GNUNET_CONTAINER_BloomFilter * +GNUNET_CONTAINER_bloomfilter_init (const char *data, size_t size, + unsigned int k) +{ + struct GNUNET_CONTAINER_BloomFilter *bf; + size_t ui; + + if ((k == 0) || (size == 0)) + return NULL; + ui = 1; + while (ui < size) + ui *= 2; + if (size != ui) + { + GNUNET_break (0); + return NULL; + } + bf = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_BloomFilter)); + bf->filename = NULL; + bf->fh = NULL; + bf->bitArray = GNUNET_malloc_large (size); + if (bf->bitArray == NULL) + { + GNUNET_free (bf); + return NULL; + } + bf->bitArraySize = size; + bf->addressesPerElement = k; + if (data != NULL) + memcpy (bf->bitArray, data, size); + else + memset (bf->bitArray, 0, bf->bitArraySize); + return bf; +} + + +/** + * Copy the raw data of this bloomfilter into + * the given data array. + * + * @param bf bloomfilter to take the raw data from + * @param data where to write the data + * @param size the size of the given data array + * @return GNUNET_SYSERR if the data array is not big enough + */ +int +GNUNET_CONTAINER_bloomfilter_get_raw_data (const struct + GNUNET_CONTAINER_BloomFilter *bf, + char *data, size_t size) +{ + if (NULL == bf) + return GNUNET_SYSERR; + if (bf->bitArraySize != size) + return GNUNET_SYSERR; + memcpy (data, bf->bitArray, size); + return GNUNET_OK; +} + + +/** + * Free the space associated with a filter + * in memory, flush to drive if needed (do not + * free the space on the drive) + * + * @param bf the filter + */ +void +GNUNET_CONTAINER_bloomfilter_free (struct GNUNET_CONTAINER_BloomFilter *bf) +{ + if (NULL == bf) + return; + if (bf->fh != NULL) + GNUNET_DISK_file_close (bf->fh); + GNUNET_free_non_null (bf->filename); + GNUNET_free (bf->bitArray); + GNUNET_free (bf); +} + + +/** + * Reset a bloom filter to empty. Clears the file on disk. + * + * @param bf the filter + */ +void +GNUNET_CONTAINER_bloomfilter_clear (struct GNUNET_CONTAINER_BloomFilter *bf) +{ + if (NULL == bf) + return; + + memset (bf->bitArray, 0, bf->bitArraySize); + if (bf->filename != NULL) + make_empty_file (bf->fh, bf->bitArraySize * 4LL); +} + + +/** + * Test if an element is in the filter. + * + * @param e the element + * @param bf the filter + * @return GNUNET_YES if the element is in the filter, GNUNET_NO if not + */ +int +GNUNET_CONTAINER_bloomfilter_test (const struct GNUNET_CONTAINER_BloomFilter + *bf, const GNUNET_HashCode * e) +{ + int res; + + if (NULL == bf) + return GNUNET_YES; + res = GNUNET_YES; + iterateBits (bf, &testBitCallback, &res, e); + return res; +} + + +/** + * Add an element to the filter + * + * @param bf the filter + * @param e the element + */ +void +GNUNET_CONTAINER_bloomfilter_add (struct GNUNET_CONTAINER_BloomFilter *bf, + const GNUNET_HashCode * e) +{ + if (NULL == bf) + return; + iterateBits (bf, &incrementBitCallback, bf, e); +} + + +/** + * Or the entries of the given raw data array with the + * data of the given bloom filter. Assumes that + * the size of the data array and the current filter + * match. + * + * @param bf the filter + * @param data the data to or-in + * @param size number of bytes in data + */ +int +GNUNET_CONTAINER_bloomfilter_or (struct GNUNET_CONTAINER_BloomFilter *bf, + const char *data, size_t size) +{ + unsigned int i; + unsigned int n; + unsigned long long *fc; + const unsigned long long *dc; + + if (NULL == bf) + return GNUNET_YES; + if (bf->bitArraySize != size) + return GNUNET_SYSERR; + fc = (unsigned long long *) bf->bitArray; + dc = (const unsigned long long *) data; + n = size / sizeof (unsigned long long); + + for (i = 0; i < n; i++) + fc[i] |= dc[i]; + for (i = n * sizeof (unsigned long long); i < size; i++) + bf->bitArray[i] |= data[i]; + return GNUNET_OK; +} + +/** + * Or the entries of the given raw data array with the + * data of the given bloom filter. Assumes that + * the size of the data array and the current filter + * match. + * + * @param bf the filter + * @param to_or the bloomfilter to or-in + * @param size number of bytes in data + */ +int +GNUNET_CONTAINER_bloomfilter_or2 (struct GNUNET_CONTAINER_BloomFilter *bf, + const struct GNUNET_CONTAINER_BloomFilter + *to_or, size_t size) +{ + unsigned int i; + unsigned int n; + unsigned long long *fc; + const unsigned long long *dc; + + if (NULL == bf) + return GNUNET_YES; + if (bf->bitArraySize != size) + return GNUNET_SYSERR; + fc = (unsigned long long *) bf->bitArray; + dc = (const unsigned long long *) to_or->bitArray; + n = size / sizeof (unsigned long long); + + for (i = 0; i < n; i++) + fc[i] |= dc[i]; + for (i = n * sizeof (unsigned long long); i < size; i++) + bf->bitArray[i] |= to_or->bitArray[i]; + return GNUNET_OK; +} + +/** + * Remove an element from the filter. + * + * @param bf the filter + * @param e the element to remove + */ +void +GNUNET_CONTAINER_bloomfilter_remove (struct GNUNET_CONTAINER_BloomFilter *bf, + const GNUNET_HashCode * e) +{ + if (NULL == bf) + return; + if (bf->filename == NULL) + return; + iterateBits (bf, &decrementBitCallback, bf, e); +} + +/** + * Resize a bloom filter. Note that this operation + * is pretty costly. Essentially, the bloom filter + * needs to be completely re-build. + * + * @param bf the filter + * @param iterator an iterator over all elements stored in the BF + * @param iterator_cls argument to the iterator function + * @param size the new size for the filter + * @param k the new number of GNUNET_CRYPTO_hash-function to apply per element + */ +void +GNUNET_CONTAINER_bloomfilter_resize (struct GNUNET_CONTAINER_BloomFilter *bf, + GNUNET_HashCodeIterator iterator, + void *iterator_cls, size_t size, + unsigned int k) +{ + GNUNET_HashCode hc; + unsigned int i; + + GNUNET_free (bf->bitArray); + i = 1; + while (i < size) + i *= 2; + size = i; /* make sure it's a power of 2 */ + + bf->bitArraySize = size; + bf->bitArray = GNUNET_malloc (size); + memset (bf->bitArray, 0, bf->bitArraySize); + if (bf->filename != NULL) + make_empty_file (bf->fh, bf->bitArraySize * 4LL); + while (GNUNET_YES == iterator (iterator_cls, &hc)) + GNUNET_CONTAINER_bloomfilter_add (bf, &hc); +} + +/* end of container_bloomfilter.c */ diff --git a/src/util/container_heap.c b/src/util/container_heap.c new file mode 100644 index 0000000..c34e220 --- /dev/null +++ b/src/util/container_heap.c @@ -0,0 +1,550 @@ +/* + This file is part of GNUnet. + (C) 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/container_heap.c + * @brief Implementation of a heap + * @author Nathan Evans + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define DEBUG 0 + +/** + * Node in the heap. + */ +struct GNUNET_CONTAINER_HeapNode +{ + /** + * Heap this node belongs to. + */ + struct GNUNET_CONTAINER_Heap *heap; + + /** + * Parent node. + */ + struct GNUNET_CONTAINER_HeapNode *parent; + + /** + * Left child. + */ + struct GNUNET_CONTAINER_HeapNode *left_child; + + /** + * Right child. + */ + struct GNUNET_CONTAINER_HeapNode *right_child; + + /** + * Our element. + */ + void *element; + + /** + * Cost for this element. + */ + GNUNET_CONTAINER_HeapCostType cost; + + /** + * Number of elements below this node in the heap + * (excluding this node itself). + */ + unsigned int tree_size; + +}; + +/** + * Handle to a node in a heap. + */ +struct GNUNET_CONTAINER_Heap +{ + + /** + * Root of the heap. + */ + struct GNUNET_CONTAINER_HeapNode *root; + + /** + * Current position of our random walk. + */ + struct GNUNET_CONTAINER_HeapNode *walk_pos; + + /** + * Number of elements in the heap. + */ + unsigned int size; + + /** + * How is the heap sorted? + */ + enum GNUNET_CONTAINER_HeapOrder order; + +}; + + +#if DEBUG +/** + * Check if internal invariants hold for the given node. + * + * @param node subtree to check + */ +static void +check (const struct GNUNET_CONTAINER_HeapNode *node) +{ + if (NULL == node) + return; + GNUNET_assert (node->tree_size == + ((node->left_child == + NULL) ? 0 : 1 + node->left_child->tree_size) + + ((node->right_child == + NULL) ? 0 : 1 + node->right_child->tree_size)); + check (node->left_child); + check (node->right_child); +} + + +#define CHECK(n) check(n) +#else +#define CHECK(n) do {} while (0) +#endif + + +/** + * Create a new heap. + * + * @param order how should the heap be sorted? + * @return handle to the heap + */ +struct GNUNET_CONTAINER_Heap * +GNUNET_CONTAINER_heap_create (enum GNUNET_CONTAINER_HeapOrder order) +{ + struct GNUNET_CONTAINER_Heap *heap; + + heap = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_Heap)); + heap->order = order; + return heap; +} + + +/** + * Destroys the heap. Only call on a heap that + * is already empty. + * + * @param heap heap to destroy + */ +void +GNUNET_CONTAINER_heap_destroy (struct GNUNET_CONTAINER_Heap *heap) +{ + GNUNET_break (heap->size == 0); + GNUNET_free (heap); +} + + +/** + * Get element stored at root of heap. + * + * @param heap heap to inspect + * @return NULL if heap is empty + */ +void * +GNUNET_CONTAINER_heap_peek (const struct GNUNET_CONTAINER_Heap *heap) +{ + if (heap->root == NULL) + return NULL; + return heap->root->element; +} + + +/** + * Get the current size of the heap + * + * @param heap the heap to get the size of + * @return number of elements stored + */ +unsigned int +GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap) +{ + return heap->size; +} + + +/** + * Get the current cost of the node + * + * @param node the node to get the cost of + * @return cost of the node + */ +GNUNET_CONTAINER_HeapCostType +GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode + *node) +{ + return node->cost; +} + +/** + * Iterate over the children of the given node. + * + * @param heap argument to give to iterator + * @param node node to iterate over + * @param iterator function to call on each node + * @param iterator_cls closure for iterator + * @return GNUNET_YES to continue to iterate + */ +static int +node_iterator (const struct GNUNET_CONTAINER_Heap *heap, + struct GNUNET_CONTAINER_HeapNode *node, + GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls) +{ + if (node == NULL) + return GNUNET_YES; + if (GNUNET_YES != + node_iterator (heap, node->left_child, iterator, iterator_cls)) + return GNUNET_NO; + if (GNUNET_YES != + node_iterator (heap, node->right_child, iterator, iterator_cls)) + return GNUNET_NO; + return iterator (iterator_cls, node, node->element, node->cost); +} + + +/** + * Iterate over all entries in the heap. + * + * @param heap the heap + * @param iterator function to call on each entry + * @param iterator_cls closure for iterator + */ +void +GNUNET_CONTAINER_heap_iterate (const struct GNUNET_CONTAINER_Heap *heap, + GNUNET_CONTAINER_HeapIterator iterator, + void *iterator_cls) +{ + (void) node_iterator (heap, heap->root, iterator, iterator_cls); +} + + +/** + * Perform a random walk of the tree. The walk is biased + * towards elements closer to the root of the tree (since + * each walk starts at the root and ends at a random leaf). + * The heap internally tracks the current position of the + * walk. + * + * @param heap heap to walk + * @return data stored at the next random node in the walk; + * NULL if the tree is empty. + */ +void * +GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap) +{ + struct GNUNET_CONTAINER_HeapNode *pos; + void *element; + + if (heap->root == NULL) + return NULL; + pos = heap->walk_pos; + if (pos == NULL) + pos = heap->root; + element = pos->element; + heap->walk_pos = + (0 == + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + 2)) ? pos->right_child : pos->left_child; + return element; +} + + +/** + * Insert the given node 'node' into the subtree starting + * at 'pos' (while keeping the tree somewhat balanced). + * + * @param heap heap to modify + * @param pos existing tree + * @param node node to insert (which may be a subtree itself) + */ +static void +insert_node (struct GNUNET_CONTAINER_Heap *heap, + struct GNUNET_CONTAINER_HeapNode *pos, + struct GNUNET_CONTAINER_HeapNode *node) +{ + struct GNUNET_CONTAINER_HeapNode *parent; + + GNUNET_assert (node->parent == NULL); + while ((heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) ? (pos->cost >= + node->cost) + : (pos->cost <= node->cost)) + { + /* node is descendent of pos */ + pos->tree_size += (1 + node->tree_size); + if (pos->left_child == NULL) + { + pos->left_child = node; + node->parent = pos; + return; + } + if (pos->right_child == NULL) + { + pos->right_child = node; + node->parent = pos; + return; + } + /* keep it balanced by descending into smaller subtree */ + if (pos->left_child->tree_size < pos->right_child->tree_size) + pos = pos->left_child; + else + pos = pos->right_child; + } + /* make 'node' parent of 'pos' */ + parent = pos->parent; + pos->parent = NULL; + node->parent = parent; + if (NULL == parent) + { + heap->root = node; + } + else + { + if (parent->left_child == pos) + parent->left_child = node; + else + parent->right_child = node; + } + /* insert 'pos' below 'node' */ + insert_node (heap, node, pos); + CHECK (pos); +} + + +/** + * Inserts a new element into the heap. + * + * @param heap heap to modify + * @param element element to insert + * @param cost cost for the element + * @return node for the new element + */ +struct GNUNET_CONTAINER_HeapNode * +GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, void *element, + GNUNET_CONTAINER_HeapCostType cost) +{ + struct GNUNET_CONTAINER_HeapNode *node; + + node = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_HeapNode)); + node->heap = heap; + node->element = element; + node->cost = cost; + heap->size++; + if (NULL == heap->root) + heap->root = node; + else + insert_node (heap, heap->root, node); + GNUNET_assert (heap->size == heap->root->tree_size + 1); + CHECK (heap->root); + return node; +} + + +/** + * Remove root of the heap. + * + * @param heap heap to modify + * @return element data stored at the root node, NULL if heap is empty + */ +void * +GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap) +{ + void *ret; + struct GNUNET_CONTAINER_HeapNode *root; + + if (NULL == (root = heap->root)) + return NULL; + heap->size--; + ret = root->element; + if (root->left_child == NULL) + { + heap->root = root->right_child; + if (root->right_child != NULL) + root->right_child->parent = NULL; + } + else if (root->right_child == NULL) + { + heap->root = root->left_child; + root->left_child->parent = NULL; + } + else + { + root->left_child->parent = NULL; + root->right_child->parent = NULL; + heap->root = root->left_child; + insert_node (heap, heap->root, root->right_child); + } + GNUNET_free (root); +#if DEBUG + GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || + (heap->size == heap->root->tree_size + 1)); + CHECK (heap->root); +#endif + return ret; +} + + +/** + * Remove the given node 'node' from the tree and update + * the 'tree_size' fields accordingly. Preserves the + * children of 'node' and does NOT change the overall + * 'size' field of the tree. + */ +static void +remove_node (struct GNUNET_CONTAINER_HeapNode *node) +{ + struct GNUNET_CONTAINER_HeapNode *ancestor; + struct GNUNET_CONTAINER_Heap *heap = node->heap; + + /* update 'size' of the ancestors */ + ancestor = node; + while (NULL != (ancestor = ancestor->parent)) + ancestor->tree_size--; + + /* update 'size' of node itself */ + if (node->left_child != NULL) + node->tree_size -= (1 + node->left_child->tree_size); + if (node->right_child != NULL) + node->tree_size -= (1 + node->right_child->tree_size); + + /* unlink 'node' itself and insert children in its place */ + if (node->parent == NULL) + { + if (node->left_child != NULL) + { + heap->root = node->left_child; + node->left_child->parent = NULL; + if (node->right_child != NULL) + { + node->right_child->parent = NULL; + insert_node (heap, heap->root, node->right_child); + } + } + else + { + heap->root = node->right_child; + if (node->right_child != NULL) + node->right_child->parent = NULL; + } + } + else + { + if (node->parent->left_child == node) + node->parent->left_child = NULL; + else + node->parent->right_child = NULL; + if (node->left_child != NULL) + { + node->left_child->parent = NULL; + node->parent->tree_size -= (1 + node->left_child->tree_size); + insert_node (heap, node->parent, node->left_child); + } + if (node->right_child != NULL) + { + node->right_child->parent = NULL; + node->parent->tree_size -= (1 + node->right_child->tree_size); + insert_node (heap, node->parent, node->right_child); + } + } + node->parent = NULL; + node->left_child = NULL; + node->right_child = NULL; + GNUNET_assert (node->tree_size == 0); + CHECK (heap->root); +} + + +/** + * Removes a node from the heap. + * + * @param node node to remove + * @return element data stored at the node + */ +void * +GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node) +{ + void *ret; + struct GNUNET_CONTAINER_Heap *heap; + + heap = node->heap; + CHECK (heap->root); + if (heap->walk_pos == node) + (void) GNUNET_CONTAINER_heap_walk_get_next (heap); + remove_node (node); + heap->size--; + ret = node->element; + if (heap->walk_pos == node) + heap->walk_pos = NULL; + GNUNET_free (node); +#if DEBUG + CHECK (heap->root); + GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || + (heap->size == heap->root->tree_size + 1)); +#endif + return ret; +} + + +/** + * Updates the cost of any node in the tree + * + * @param heap heap to modify + * @param node node for which the cost is to be changed + * @param new_cost new cost for the node + */ +void +GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap, + struct GNUNET_CONTAINER_HeapNode *node, + GNUNET_CONTAINER_HeapCostType new_cost) +{ +#if DEBUG + GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || + (heap->size == heap->root->tree_size + 1)); + CHECK (heap->root); +#endif + remove_node (node); +#if DEBUG + CHECK (heap->root); + GNUNET_assert (((heap->size == 1) && (heap->root == NULL)) || + (heap->size == heap->root->tree_size + 2)); +#endif + node->cost = new_cost; + if (heap->root == NULL) + heap->root = node; + else + insert_node (heap, heap->root, node); +#if DEBUG + CHECK (heap->root); + GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || + (heap->size == heap->root->tree_size + 1)); +#endif +} + + +/* end of heap.c */ diff --git a/src/util/container_meta_data.c b/src/util/container_meta_data.c new file mode 100644 index 0000000..b1051c8 --- /dev/null +++ b/src/util/container_meta_data.c @@ -0,0 +1,1180 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/container_meta_data.c + * @brief Storing of meta data + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" +#include "gnunet_strings_lib.h" +#include "gnunet_time_lib.h" +#include +#include + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/** + * Meta data item. + */ +struct MetaItem +{ + /** + * This is a linked list. + */ + struct MetaItem *next; + + /** + * Name of the extracting plugin. + */ + char *plugin_name; + + /** + * Mime-type of data. + */ + char *mime_type; + + /** + * The actual meta data. + */ + char *data; + + /** + * Number of bytes in 'data'. + */ + size_t data_size; + + /** + * Type of the meta data. + */ + enum EXTRACTOR_MetaType type; + + /** + * Format of the meta data. + */ + enum EXTRACTOR_MetaFormat format; + +}; + +/** + * Meta data to associate with a file, directory or namespace. + */ +struct GNUNET_CONTAINER_MetaData +{ + /** + * Linked list of the meta data items. + */ + struct MetaItem *items; + + /** + * Complete serialized and compressed buffer of the items. + * NULL if we have not computed that buffer yet. + */ + char *sbuf; + + /** + * Number of bytes in 'sbuf'. 0 if the buffer is stale. + */ + size_t sbuf_size; + + /** + * Number of items in the linked list. + */ + unsigned int item_count; + +}; + + +/** + * Create a fresh struct CONTAINER_MetaData token. + * + * @return empty meta-data container + */ +struct GNUNET_CONTAINER_MetaData * +GNUNET_CONTAINER_meta_data_create () +{ + return GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_MetaData)); +} + + +/** + * Free meta data item. + * + * @param item item to free + */ +static void +meta_item_free (struct MetaItem *item) +{ + GNUNET_free_non_null (item->plugin_name); + GNUNET_free_non_null (item->mime_type); + GNUNET_free_non_null (item->data); + GNUNET_free (item); +} + + +/** + * The meta data has changed, invalidate its serialization + * buffer. + * + * @param md meta data that changed + */ +static void +invalidate_sbuf (struct GNUNET_CONTAINER_MetaData *md) +{ + if (md->sbuf == NULL) + return; + GNUNET_free (md->sbuf); + md->sbuf = NULL; + md->sbuf_size = 0; +} + + +/** + * Free meta data. + * + * @param md what to free + */ +void +GNUNET_CONTAINER_meta_data_destroy (struct GNUNET_CONTAINER_MetaData *md) +{ + struct MetaItem *item; + + if (md == NULL) + return; + while (NULL != (item = md->items)) + { + md->items = item->next; + meta_item_free (item); + } + GNUNET_free_non_null (md->sbuf); + GNUNET_free (md); +} + + +/** + * Remove all items in the container. + * + * @param md metadata to manipulate + */ +void +GNUNET_CONTAINER_meta_data_clear (struct GNUNET_CONTAINER_MetaData *md) +{ + struct MetaItem *item; + + if (md == NULL) + return; + while (NULL != (item = md->items)) + { + md->items = item->next; + meta_item_free (item); + } + GNUNET_free_non_null (md->sbuf); + memset (md, 0, sizeof (struct GNUNET_CONTAINER_MetaData)); +} + + + +/** + * Test if two MDs are equal. We consider them equal if + * the meta types, formats and content match (we do not + * include the mime types and plugins names in this + * consideration). + * + * @param md1 first value to check + * @param md2 other value to check + * @return GNUNET_YES if they are equal + */ +int +GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData + *md1, + const struct GNUNET_CONTAINER_MetaData + *md2) +{ + struct MetaItem *i; + struct MetaItem *j; + int found; + + if (md1 == md2) + return GNUNET_YES; + if (md1->item_count != md2->item_count) + return GNUNET_NO; + + i = md1->items; + while (NULL != i) + { + found = GNUNET_NO; + j = md2->items; + while (NULL != j) + { + if ((i->type == j->type) && (i->format == j->format) && + (i->data_size == j->data_size) && + (0 == memcmp (i->data, j->data, i->data_size))) + { + found = GNUNET_YES; + break; + } + j = j->next; + } + if (found == GNUNET_NO) + return GNUNET_NO; + i = i->next; + } + return GNUNET_YES; +} + + +/** + * Extend metadata. Note that the list of meta data items is + * sorted by size (largest first). + * + * @param md metadata to extend + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_len number of bytes in data + * @return GNUNET_OK on success, GNUNET_SYSERR if this entry already exists + * data_mime_type and plugin_name are not considered for "exists" checks + */ +int +GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md, + const char *plugin_name, + enum EXTRACTOR_MetaType type, + enum EXTRACTOR_MetaFormat format, + const char *data_mime_type, const char *data, + size_t data_len) +{ + struct MetaItem *prev; + struct MetaItem *pos; + struct MetaItem *i; + char *p; + + prev = NULL; + pos = md->items; + while (NULL != pos) + { + if (pos->data_size < data_len) + break; + if ((pos->type == type) && (pos->data_size == data_len) && + (0 == memcmp (pos->data, data, data_len))) + { + if ((pos->mime_type == NULL) && (data_mime_type != NULL)) + { + pos->mime_type = GNUNET_strdup (data_mime_type); + invalidate_sbuf (md); + } + if ((pos->format == EXTRACTOR_METAFORMAT_C_STRING) && + (format == EXTRACTOR_METAFORMAT_UTF8)) + { + pos->format = EXTRACTOR_METAFORMAT_UTF8; + invalidate_sbuf (md); + } + return GNUNET_SYSERR; + } + prev = pos; + pos = pos->next; + } + md->item_count++; + i = GNUNET_malloc (sizeof (struct MetaItem)); + i->type = type; + i->format = format; + i->data_size = data_len; + i->next = pos; + if (prev == NULL) + md->items = i; + else + prev->next = i; + i->mime_type = + (data_mime_type == NULL) ? NULL : GNUNET_strdup (data_mime_type); + i->plugin_name = (plugin_name == NULL) ? NULL : GNUNET_strdup (plugin_name); + i->data = GNUNET_malloc (data_len); + memcpy (i->data, data, data_len); + /* change OS native dir separators to unix '/' and others to '_' */ + if ( (type == EXTRACTOR_METATYPE_FILENAME) || + (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) ) + { + p = i->data; + while ((*p != '\0') && (p < i->data + data_len)) + { + if (*p == DIR_SEPARATOR) + *p = '/'; + else if (*p == '\\') + *p = '_'; + p++; + } + } + invalidate_sbuf (md); + return GNUNET_OK; +} + + +/** + * Merge given meta data. + * + * @param cls the 'struct GNUNET_CONTAINER_MetaData' to merge into + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_len number of bytes in data + * @return 0 (to continue) + */ +static int +merge_helper (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, + enum EXTRACTOR_MetaFormat format, const char *data_mime_type, + const char *data, size_t data_len) +{ + struct GNUNET_CONTAINER_MetaData *md = cls; + + (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format, + data_mime_type, data, data_len); + return 0; +} + + +/** + * Extend metadata. Merges the meta data from the second argument + * into the first, discarding duplicate key-value pairs. + * + * @param md metadata to extend + * @param in metadata to merge + */ +void +GNUNET_CONTAINER_meta_data_merge (struct GNUNET_CONTAINER_MetaData *md, + const struct GNUNET_CONTAINER_MetaData *in) +{ + GNUNET_CONTAINER_meta_data_iterate (in, &merge_helper, md); +} + + +/** + * Remove an item. + * + * @param md metadata to manipulate + * @param type type of the item to remove + * @param data specific value to remove, NULL to remove all + * entries of the given type + * @param data_len number of bytes in data + * @return GNUNET_OK on success, GNUNET_SYSERR if the item does not exist in md + */ +int +GNUNET_CONTAINER_meta_data_delete (struct GNUNET_CONTAINER_MetaData *md, + enum EXTRACTOR_MetaType type, + const char *data, size_t data_len) +{ + struct MetaItem *pos; + struct MetaItem *prev; + + prev = NULL; + pos = md->items; + while (NULL != pos) + { + if ((pos->type == type) && + ((data == NULL) || + ((pos->data_size == data_len) && + (0 == memcmp (pos->data, data, data_len))))) + { + if (prev == NULL) + md->items = pos->next; + else + prev->next = pos->next; + meta_item_free (pos); + md->item_count--; + invalidate_sbuf (md); + return GNUNET_OK; + } + prev = pos; + pos = pos->next; + } + return GNUNET_SYSERR; +} + + +/** + * Add the current time as the publication date + * to the meta-data. + * + * @param md metadata to modify + */ +void +GNUNET_CONTAINER_meta_data_add_publication_date (struct + GNUNET_CONTAINER_MetaData *md) +{ + char *dat; + struct GNUNET_TIME_Absolute t; + + t = GNUNET_TIME_absolute_get (); + GNUNET_CONTAINER_meta_data_delete (md, EXTRACTOR_METATYPE_PUBLICATION_DATE, + NULL, 0); + dat = GNUNET_STRINGS_absolute_time_to_string (t); + GNUNET_CONTAINER_meta_data_insert (md, "", + EXTRACTOR_METATYPE_PUBLICATION_DATE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + dat, strlen (dat) + 1); + GNUNET_free (dat); +} + + +/** + * Iterate over MD entries. + * + * @param md metadata to inspect + * @param iter function to call on each entry + * @param iter_cls closure for iterator + * @return number of entries + */ +int +GNUNET_CONTAINER_meta_data_iterate (const struct GNUNET_CONTAINER_MetaData *md, + EXTRACTOR_MetaDataProcessor iter, + void *iter_cls) +{ + struct MetaItem *pos; + + if (md == NULL) + return 0; + if (iter == NULL) + return md->item_count; + pos = md->items; + while (NULL != pos) + { + if (0 != + iter (iter_cls, pos->plugin_name, pos->type, pos->format, + pos->mime_type, pos->data, pos->data_size)) + return md->item_count; + pos = pos->next; + } + return md->item_count; +} + + +/** + * Get the first MD entry of the given type. Caller + * is responsible for freeing the return value. + * Also, only meta data items that are strings (0-terminated) + * are returned by this function. + * + * @param md metadata to inspect + * @param type type to look for + * @return NULL if no entry was found + */ +char * +GNUNET_CONTAINER_meta_data_get_by_type (const struct GNUNET_CONTAINER_MetaData + *md, enum EXTRACTOR_MetaType type) +{ + struct MetaItem *pos; + + if (md == NULL) + return NULL; + pos = md->items; + while (NULL != pos) + { + if ((type == pos->type) && + ((pos->format == EXTRACTOR_METAFORMAT_UTF8) || + (pos->format == EXTRACTOR_METAFORMAT_C_STRING))) + return GNUNET_strdup (pos->data); + pos = pos->next; + } + return NULL; +} + + +/** + * Get the first matching MD entry of the given types. Caller is + * responsible for freeing the return value. Also, only meta data + * items that are strings (0-terminated) are returned by this + * function. + * + * @param md metadata to inspect + * @param ... -1-terminated list of types + * @return NULL if we do not have any such entry, + * otherwise client is responsible for freeing the value! + */ +char * +GNUNET_CONTAINER_meta_data_get_first_by_types (const struct + GNUNET_CONTAINER_MetaData *md, + ...) +{ + char *ret; + va_list args; + enum EXTRACTOR_MetaType type; + + if (md == NULL) + return NULL; + ret = NULL; + va_start (args, md); + while (1) + { + type = va_arg (args, enum EXTRACTOR_MetaType); + + if (type == -1) + break; + ret = GNUNET_CONTAINER_meta_data_get_by_type (md, type); + if (ret != NULL) + break; + } + va_end (args); + return ret; +} + + +/** + * Get a thumbnail from the meta-data (if present). + * + * @param md metadata to get the thumbnail from + * @param thumb will be set to the thumbnail data. Must be + * freed by the caller! + * @return number of bytes in thumbnail, 0 if not available + */ +size_t +GNUNET_CONTAINER_meta_data_get_thumbnail (const struct GNUNET_CONTAINER_MetaData + * md, unsigned char **thumb) +{ + struct MetaItem *pos; + struct MetaItem *match; + + if (md == NULL) + return 0; + match = NULL; + pos = md->items; + while (NULL != pos) + { + if ((NULL != pos->mime_type) && + (0 == strncasecmp ("image/", pos->mime_type, strlen ("image/"))) && + (pos->format == EXTRACTOR_METAFORMAT_BINARY)) + { + if (match == NULL) + match = pos; + else if ((match->type != EXTRACTOR_METATYPE_THUMBNAIL) && + (pos->type == EXTRACTOR_METATYPE_THUMBNAIL)) + match = pos; + } + pos = pos->next; + } + if ((match == NULL) || (match->data_size == 0)) + return 0; + *thumb = GNUNET_malloc (match->data_size); + memcpy (*thumb, match->data, match->data_size); + return match->data_size; +} + + +/** + * Duplicate struct GNUNET_CONTAINER_MetaData. + * + * @param md what to duplicate + * @return duplicate meta-data container + */ +struct GNUNET_CONTAINER_MetaData * +GNUNET_CONTAINER_meta_data_duplicate (const struct GNUNET_CONTAINER_MetaData + *md) +{ + struct GNUNET_CONTAINER_MetaData *ret; + struct MetaItem *pos; + + if (md == NULL) + return NULL; + ret = GNUNET_CONTAINER_meta_data_create (); + pos = md->items; + while (NULL != pos) + { + GNUNET_CONTAINER_meta_data_insert (ret, pos->plugin_name, pos->type, + pos->format, pos->mime_type, pos->data, + pos->data_size); + pos = pos->next; + } + return ret; +} + + + +/** + * Try to compress the given block of data. + * + * @param data block to compress; if compression + * resulted in a smaller block, the first + * bytes of data are updated to the compressed + * data + * @param oldSize number of bytes in data + * @param result set to the compressed data + * @param newSize set to size of result + * @return GNUNET_YES if compression reduce the size, + * GNUNET_NO if compression did not help + */ +static int +try_compression (const char *data, size_t oldSize, char **result, + size_t * newSize) +{ + char *tmp; + uLongf dlen; + +#ifdef compressBound + dlen = compressBound (oldSize); +#else + dlen = oldSize + (oldSize / 100) + 20; + /* documentation says 100.1% oldSize + 12 bytes, but we + * should be able to overshoot by more to be safe */ +#endif + tmp = GNUNET_malloc (dlen); + if (Z_OK == + compress2 ((Bytef *) tmp, &dlen, (const Bytef *) data, oldSize, 9)) + { + if (dlen < oldSize) + { + *result = tmp; + *newSize = dlen; + return GNUNET_YES; + } + } + GNUNET_free (tmp); + return GNUNET_NO; +} + + +/** + * Flag in 'version' that indicates compressed meta-data. + */ +#define HEADER_COMPRESSED 0x80000000 + + +/** + * Bits in 'version' that give the version number. + */ +#define HEADER_VERSION_MASK 0x7FFFFFFF + + +/** + * Header for serialized meta data. + */ +struct MetaDataHeader +{ + /** + * The version of the MD serialization. The highest bit is used to + * indicate compression. + * + * Version 0 is traditional (pre-0.9) meta data (unsupported) + * Version is 1 for a NULL pointer + * Version 2 is for 0.9.x (and possibly higher) + * Other version numbers are not yet defined. + */ + uint32_t version; + + /** + * How many MD entries are there? + */ + uint32_t entries; + + /** + * Size of the decompressed meta data. + */ + uint32_t size; + + /** + * This is followed by 'entries' values of type 'struct MetaDataEntry' + * and then by 'entry' plugin names, mime-types and data blocks + * as specified in those meta data entries. + */ +}; + + +/** + * Entry of serialized meta data. + */ +struct MetaDataEntry +{ + /** + * Meta data type. Corresponds to an 'enum EXTRACTOR_MetaType' + */ + uint32_t type; + + /** + * Meta data format. Corresponds to an 'enum EXTRACTOR_MetaFormat' + */ + uint32_t format; + + /** + * Number of bytes of meta data. + */ + uint32_t data_size; + + /** + * Number of bytes in the plugin name including 0-terminator. 0 for NULL. + */ + uint32_t plugin_name_len; + + /** + * Number of bytes in the mime type including 0-terminator. 0 for NULL. + */ + uint32_t mime_type_len; + +}; + + +/** + * Serialize meta-data to target. + * + * @param md metadata to serialize + * @param target where to write the serialized metadata; + * *target can be NULL, in which case memory is allocated + * @param max maximum number of bytes available in target + * @param opt is it ok to just write SOME of the + * meta-data to match the size constraint, + * possibly discarding some data? + * @return number of bytes written on success, + * GNUNET_SYSERR on error (typically: not enough + * space) + */ +ssize_t +GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData + *md, char **target, size_t max, + enum + GNUNET_CONTAINER_MetaDataSerializationOptions + opt) +{ + struct GNUNET_CONTAINER_MetaData *vmd; + struct MetaItem *pos; + struct MetaDataHeader ihdr; + struct MetaDataHeader *hdr; + struct MetaDataEntry *ent; + char *dst; + unsigned int i; + uint64_t msize; + size_t off; + char *mdata; + char *cdata; + size_t mlen; + size_t plen; + size_t size; + size_t left; + size_t clen; + size_t rlen; + int comp; + + if (max < sizeof (struct MetaDataHeader)) + return GNUNET_SYSERR; /* far too small */ + if (md == NULL) + return 0; + + if (md->sbuf != NULL) + { + /* try to use serialization cache */ + if (md->sbuf_size <= max) + { + if (NULL == *target) + *target = GNUNET_malloc (md->sbuf_size); + memcpy (*target, md->sbuf, md->sbuf_size); + return md->sbuf_size; + } + if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART)) + return GNUNET_SYSERR; /* can say that this will fail */ + /* need to compute a partial serialization, sbuf useless ... */ + } + dst = NULL; + msize = 0; + pos = md->items; + while (NULL != pos) + { + msize += sizeof (struct MetaDataEntry); + msize += pos->data_size; + if (pos->plugin_name != NULL) + msize += strlen (pos->plugin_name) + 1; + if (pos->mime_type != NULL) + msize += strlen (pos->mime_type) + 1; + pos = pos->next; + } + size = (size_t) msize; + if (size != msize) + { + GNUNET_break (0); /* integer overflow */ + return GNUNET_SYSERR; + } + if (size >= GNUNET_MAX_MALLOC_CHECKED) + { + /* too large to be processed */ + return GNUNET_SYSERR; + } + ent = GNUNET_malloc (size); + mdata = (char *) &ent[md->item_count]; + off = size - (md->item_count * sizeof (struct MetaDataEntry)); + i = 0; + pos = md->items; + while (NULL != pos) + { + ent[i].type = htonl ((uint32_t) pos->type); + ent[i].format = htonl ((uint32_t) pos->format); + ent[i].data_size = htonl ((uint32_t) pos->data_size); + if (pos->plugin_name == NULL) + plen = 0; + else + plen = strlen (pos->plugin_name) + 1; + ent[i].plugin_name_len = htonl ((uint32_t) plen); + if (pos->mime_type == NULL) + mlen = 0; + else + mlen = strlen (pos->mime_type) + 1; + ent[i].mime_type_len = htonl ((uint32_t) mlen); + off -= pos->data_size; + memcpy (&mdata[off], pos->data, pos->data_size); + off -= plen; + if (pos->plugin_name != NULL) + memcpy (&mdata[off], pos->plugin_name, plen); + off -= mlen; + if (pos->mime_type != NULL) + memcpy (&mdata[off], pos->mime_type, mlen); + i++; + pos = pos->next; + } + GNUNET_assert (off == 0); + + clen = 0; + cdata = NULL; + left = size; + i = 0; + pos = md->items; + while (pos != NULL) + { + comp = GNUNET_NO; + if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS)) + comp = try_compression ((const char *) &ent[i], left, &cdata, &clen); + + if ((md->sbuf == NULL) && (i == 0)) + { + /* fill 'sbuf'; this "modifies" md, but since this is only + * an internal cache we will cast away the 'const' instead + * of making the API look strange. */ + vmd = (struct GNUNET_CONTAINER_MetaData *) md; + hdr = GNUNET_malloc (left + sizeof (struct MetaDataHeader)); + hdr->size = htonl (left); + hdr->entries = htonl (md->item_count); + if (GNUNET_YES == comp) + { + GNUNET_assert (clen < left); + hdr->version = htonl (2 | HEADER_COMPRESSED); + memcpy (&hdr[1], cdata, clen); + vmd->sbuf_size = clen + sizeof (struct MetaDataHeader); + } + else + { + hdr->version = htonl (2); + memcpy (&hdr[1], &ent[0], left); + vmd->sbuf_size = left + sizeof (struct MetaDataHeader); + } + vmd->sbuf = (char *) hdr; + } + + if (((left + sizeof (struct MetaDataHeader)) <= max) || + ((comp == GNUNET_YES) && (clen <= max))) + { + /* success, this now fits! */ + if (GNUNET_YES == comp) + { + if (dst == NULL) + dst = GNUNET_malloc (clen + sizeof (struct MetaDataHeader)); + hdr = (struct MetaDataHeader *) dst; + hdr->version = htonl (2 | HEADER_COMPRESSED); + hdr->size = htonl (left); + hdr->entries = htonl (md->item_count - i); + memcpy (&dst[sizeof (struct MetaDataHeader)], cdata, clen); + GNUNET_free (cdata); + GNUNET_free (ent); + rlen = clen + sizeof (struct MetaDataHeader); + } + else + { + if (dst == NULL) + dst = GNUNET_malloc (left + sizeof (struct MetaDataHeader)); + hdr = (struct MetaDataHeader *) dst; + hdr->version = htonl (2); + hdr->entries = htonl (md->item_count - i); + hdr->size = htonl (left); + memcpy (&dst[sizeof (struct MetaDataHeader)], &ent[i], left); + GNUNET_free (ent); + rlen = left + sizeof (struct MetaDataHeader); + } + if (NULL != *target) + { + memcpy (*target, dst, clen + sizeof (struct MetaDataHeader)); + GNUNET_free (dst); + } + else + { + *target = dst; + } + return rlen; + } + + if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART)) + { + /* does not fit! */ + GNUNET_free (ent); + return GNUNET_SYSERR; + } + + /* next iteration: ignore the corresponding meta data at the + * end and try again without it */ + left -= sizeof (struct MetaDataEntry); + left -= pos->data_size; + if (pos->plugin_name != NULL) + left -= strlen (pos->plugin_name) + 1; + if (pos->mime_type != NULL) + left -= strlen (pos->mime_type) + 1; + pos = pos->next; + i++; + } + GNUNET_free (ent); + + /* nothing fit, only write header! */ + ihdr.version = htonl (2); + ihdr.entries = htonl (0); + ihdr.size = htonl (0); + if (*target == NULL) + *target = GNUNET_malloc (sizeof (struct MetaDataHeader)); + memcpy (*target, &ihdr, sizeof (struct MetaDataHeader)); + return sizeof (struct MetaDataHeader); +} + + +/** + * Get the size of the full meta-data in serialized form. + * + * @param md metadata to inspect + * @return number of bytes needed for serialization, -1 on error + */ +ssize_t +GNUNET_CONTAINER_meta_data_get_serialized_size (const struct + GNUNET_CONTAINER_MetaData *md) +{ + ssize_t ret; + char *ptr; + + if (md->sbuf != NULL) + return md->sbuf_size; + ptr = NULL; + ret = + GNUNET_CONTAINER_meta_data_serialize (md, &ptr, GNUNET_MAX_MALLOC_CHECKED, + GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL); + if (ret != -1) + GNUNET_free (ptr); + return ret; +} + + +/** + * Decompress input, return the decompressed data + * as output, set outputSize to the number of bytes + * that were found. + * + * @param input compressed data + * @param inputSize number of bytes in input + * @param outputSize expected size of the output + * @return NULL on error + */ +static char * +decompress (const char *input, size_t inputSize, size_t outputSize) +{ + char *output; + uLongf olen; + + olen = outputSize; + output = GNUNET_malloc (olen); + if (Z_OK == + uncompress ((Bytef *) output, &olen, (const Bytef *) input, inputSize)) + { + return output; + } + else + { + GNUNET_free (output); + return NULL; + } +} + + +/** + * Deserialize meta-data. Initializes md. + * + * @param input buffer with the serialized metadata + * @param size number of bytes available in input + * @return MD on success, NULL on error (i.e. + * bad format) + */ +struct GNUNET_CONTAINER_MetaData * +GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size) +{ + struct GNUNET_CONTAINER_MetaData *md; + struct MetaDataHeader hdr; + struct MetaDataEntry ent; + uint32_t ic; + uint32_t i; + char *data; + const char *cdata; + uint32_t version; + uint32_t dataSize; + int compressed; + size_t left; + uint32_t mlen; + uint32_t plen; + uint32_t dlen; + const char *mdata; + const char *meta_data; + const char *plugin_name; + const char *mime_type; + enum EXTRACTOR_MetaFormat format; + + if (size < sizeof (struct MetaDataHeader)) + return NULL; + memcpy (&hdr, input, sizeof (struct MetaDataHeader)); + version = ntohl (hdr.version) & HEADER_VERSION_MASK; + compressed = (ntohl (hdr.version) & HEADER_COMPRESSED) != 0; + + if (version == 1) + return NULL; /* null pointer */ + if (version != 2) + { + GNUNET_break_op (0); /* unsupported version */ + return NULL; + } + + ic = ntohl (hdr.entries); + dataSize = ntohl (hdr.size); + if ((sizeof (struct MetaDataEntry) * ic) > dataSize) + { + GNUNET_break_op (0); + return NULL; + } + + if (compressed) + { + if (dataSize >= GNUNET_MAX_MALLOC_CHECKED) + { + /* make sure we don't blow our memory limit because of a mal-formed + * message... */ + GNUNET_break_op (0); + return NULL; + } + data = + decompress ((const char *) &input[sizeof (struct MetaDataHeader)], + size - sizeof (struct MetaDataHeader), dataSize); + if (data == NULL) + { + GNUNET_break_op (0); + return NULL; + } + cdata = data; + } + else + { + data = NULL; + cdata = (const char *) &input[sizeof (struct MetaDataHeader)]; + if (dataSize != size - sizeof (struct MetaDataHeader)) + { + GNUNET_break_op (0); + return NULL; + } + } + + md = GNUNET_CONTAINER_meta_data_create (); + left = dataSize - ic * sizeof (struct MetaDataEntry); + mdata = &cdata[ic * sizeof (struct MetaDataEntry)]; + for (i = 0; i < ic; i++) + { + memcpy (&ent, &cdata[i * sizeof (struct MetaDataEntry)], + sizeof (struct MetaDataEntry)); + format = (enum EXTRACTOR_MetaFormat) ntohl (ent.format); + if ((format != EXTRACTOR_METAFORMAT_UTF8) && + (format != EXTRACTOR_METAFORMAT_C_STRING) && + (format != EXTRACTOR_METAFORMAT_BINARY)) + { + GNUNET_break_op (0); + break; + } + dlen = ntohl (ent.data_size); + plen = ntohl (ent.plugin_name_len); + mlen = ntohl (ent.mime_type_len); + if (dlen > left) + { + GNUNET_break_op (0); + break; + } + left -= dlen; + meta_data = &mdata[left]; + if ((format == EXTRACTOR_METAFORMAT_UTF8) || + (format == EXTRACTOR_METAFORMAT_C_STRING)) + { + if ((dlen == 0) || (mdata[left + dlen - 1] != '\0')) + { + GNUNET_break_op (0); + break; + } + } + if (plen > left) + { + GNUNET_break_op (0); + break; + } + left -= plen; + if ((plen > 0) && (mdata[left + plen - 1] != '\0')) + { + GNUNET_break_op (0); + break; + } + if (plen == 0) + plugin_name = NULL; + else + plugin_name = &mdata[left]; + + if (mlen > left) + { + GNUNET_break_op (0); + break; + } + left -= mlen; + if ((mlen > 0) && (mdata[left + mlen - 1] != '\0')) + { + GNUNET_break_op (0); + break; + } + if (mlen == 0) + mime_type = NULL; + else + mime_type = &mdata[left]; + GNUNET_CONTAINER_meta_data_insert (md, plugin_name, + (enum EXTRACTOR_MetaType) + ntohl (ent.type), format, mime_type, + meta_data, dlen); + } + GNUNET_free_non_null (data); + return md; +} + + +/* end of container_meta_data.c */ diff --git a/src/util/container_multihashmap.c b/src/util/container_multihashmap.c new file mode 100644 index 0000000..7e53a64 --- /dev/null +++ b/src/util/container_multihashmap.c @@ -0,0 +1,493 @@ +/* + This file is part of GNUnet. + (C) 2008 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/container_multihashmap.c + * @brief hash map where the same key may be present multiple times + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" +#include "gnunet_crypto_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/** + * An entry in the hash map. + */ +struct MapEntry +{ + + /** + * Key for the entry. + */ + GNUNET_HashCode key; + + /** + * Value of the entry. + */ + void *value; + + /** + * If there is a hash collision, we create a linked list. + */ + struct MapEntry *next; + +}; + +/** + * Internal representation of the hash map. + */ +struct GNUNET_CONTAINER_MultiHashMap +{ + + /** + * All of our buckets. + */ + struct MapEntry **map; + + /** + * Number of entries in the map. + */ + unsigned int size; + + /** + * Length of the "map" array. + */ + unsigned int map_length; +}; + + +/** + * Create a multi hash map. + * + * @param len initial size (map will grow as needed) + * @return NULL on error + */ +struct GNUNET_CONTAINER_MultiHashMap * +GNUNET_CONTAINER_multihashmap_create (unsigned int len) +{ + struct GNUNET_CONTAINER_MultiHashMap *ret; + + GNUNET_assert (len > 0); + ret = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_MultiHashMap)); + ret->map = GNUNET_malloc (len * sizeof (struct MapEntry *)); + ret->map_length = len; + return ret; +} + + +/** + * Destroy a hash map. Will not free any values + * stored in the hash map! + * + * @param map the map + */ +void +GNUNET_CONTAINER_multihashmap_destroy (struct GNUNET_CONTAINER_MultiHashMap + *map) +{ + unsigned int i; + struct MapEntry *e; + + for (i = 0; i < map->map_length; i++) + { + while (NULL != (e = map->map[i])) + { + map->map[i] = e->next; + GNUNET_free (e); + } + } + GNUNET_free (map->map); + GNUNET_free (map); +} + + +/** + * Compute the index of the bucket for the given key. + * + * @param m hash map for which to compute the index + * @param key what key should the index be computed for + * @return offset into the "map" array of "m" + */ +static unsigned int +idx_of (const struct GNUNET_CONTAINER_MultiHashMap *m, + const GNUNET_HashCode * key) +{ + GNUNET_assert (m != NULL); + return (*(unsigned int *) key) % m->map_length; +} + + +/** + * Get the number of key-value pairs in the map. + * + * @param map the map + * @return the number of key value pairs + */ +unsigned int +GNUNET_CONTAINER_multihashmap_size (const struct GNUNET_CONTAINER_MultiHashMap + *map) +{ + return map->size; +} + + +/** + * Given a key find a value in the map matching the key. + * + * @param map the map + * @param key what to look for + * @return NULL if no value was found; note that + * this is indistinguishable from values that just + * happen to be NULL; use "contains" to test for + * key-value pairs with value NULL + */ +void * +GNUNET_CONTAINER_multihashmap_get (const struct GNUNET_CONTAINER_MultiHashMap + *map, const GNUNET_HashCode * key) +{ + struct MapEntry *e; + + e = map->map[idx_of (map, key)]; + while (e != NULL) + { + if (0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) + return e->value; + e = e->next; + } + return NULL; +} + + +/** + * Iterate over all entries in the map. + * + * @param map the map + * @param it function to call on each entry + * @param it_cls extra argument to it + * @return the number of key value pairs processed, + * GNUNET_SYSERR if it aborted iteration + */ +int +GNUNET_CONTAINER_multihashmap_iterate (const struct + GNUNET_CONTAINER_MultiHashMap *map, + GNUNET_CONTAINER_HashMapIterator it, + void *it_cls) +{ + int count; + unsigned int i; + struct MapEntry *e; + struct MapEntry *n; + GNUNET_HashCode kc; + + count = 0; + GNUNET_assert (map != NULL); + for (i = 0; i < map->map_length; i++) + { + n = map->map[i]; + while (NULL != (e = n)) + { + n = e->next; + if (NULL != it) + { + kc = e->key; + if (GNUNET_OK != it (it_cls, &kc, e->value)) + return GNUNET_SYSERR; + } + count++; + } + } + return count; +} + + +/** + * Remove the given key-value pair from the map. Note that if the + * key-value pair is in the map multiple times, only one of the pairs + * will be removed. + * + * @param map the map + * @param key key of the key-value pair + * @param value value of the key-value pair + * @return GNUNET_YES on success, GNUNET_NO if the key-value pair + * is not in the map + */ +int +GNUNET_CONTAINER_multihashmap_remove (struct GNUNET_CONTAINER_MultiHashMap *map, + const GNUNET_HashCode * key, void *value) +{ + struct MapEntry *e; + struct MapEntry *p; + unsigned int i; + + i = idx_of (map, key); + p = NULL; + e = map->map[i]; + while (e != NULL) + { + if ((0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) && + (value == e->value)) + { + if (p == NULL) + map->map[i] = e->next; + else + p->next = e->next; + GNUNET_free (e); + map->size--; + return GNUNET_YES; + } + p = e; + e = e->next; + } + return GNUNET_NO; +} + + +/** + * Remove all entries for the given key from the map. + * Note that the values would not be "freed". + * + * @param map the map + * @param key identifies values to be removed + * @return number of values removed + */ +int +GNUNET_CONTAINER_multihashmap_remove_all (struct GNUNET_CONTAINER_MultiHashMap + *map, const GNUNET_HashCode * key) +{ + struct MapEntry *e; + struct MapEntry *p; + unsigned int i; + int ret; + + ret = 0; + i = idx_of (map, key); + p = NULL; + e = map->map[i]; + while (e != NULL) + { + if (0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) + { + if (p == NULL) + map->map[i] = e->next; + else + p->next = e->next; + GNUNET_free (e); + map->size--; + if (p == NULL) + e = map->map[i]; + else + e = p->next; + ret++; + } + else + { + p = e; + e = e->next; + } + } + return ret; +} + + +/** + * Check if the map contains any value under the given + * key (including values that are NULL). + * + * @param map the map + * @param key the key to test if a value exists for it + * @return GNUNET_YES if such a value exists, + * GNUNET_NO if not + */ +int +GNUNET_CONTAINER_multihashmap_contains (const struct + GNUNET_CONTAINER_MultiHashMap *map, + const GNUNET_HashCode * key) +{ + struct MapEntry *e; + + e = map->map[idx_of (map, key)]; + while (e != NULL) + { + if (0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) + return GNUNET_YES; + e = e->next; + } + return GNUNET_NO; +} + + +/** + * Check if the map contains the given value under the given + * key. + * + * @param map the map + * @param key the key to test if a value exists for it + * @param value value to test for + * @return GNUNET_YES if such a value exists, + * GNUNET_NO if not + */ +int +GNUNET_CONTAINER_multihashmap_contains_value (const struct + GNUNET_CONTAINER_MultiHashMap + *map, const GNUNET_HashCode * key, + const void *value) +{ + struct MapEntry *e; + + e = map->map[idx_of (map, key)]; + while (e != NULL) + { + if ((0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) && + (e->value == value)) + return GNUNET_YES; + e = e->next; + } + return GNUNET_NO; +} + + +/** + * Grow the given map to a more appropriate size. + * + * @param map the hash map to grow + */ +static void +grow (struct GNUNET_CONTAINER_MultiHashMap *map) +{ + struct MapEntry **old_map; + struct MapEntry **new_map; + struct MapEntry *e; + unsigned int old_len; + unsigned int new_len; + unsigned int idx; + unsigned int i; + + old_map = map->map; + old_len = map->map_length; + new_len = old_len * 2; + new_map = GNUNET_malloc (sizeof (struct MapEntry *) * new_len); + map->map_length = new_len; + map->map = new_map; + for (i = 0; i < old_len; i++) + { + while (NULL != (e = old_map[i])) + { + old_map[i] = e->next; + idx = idx_of (map, &e->key); + e->next = new_map[idx]; + new_map[idx] = e; + } + } + GNUNET_free (old_map); +} + + +/** + * Store a key-value pair in the map. + * + * @param map the map + * @param key key to use + * @param value value to use + * @param opt options for put + * @return GNUNET_OK on success, + * GNUNET_NO if a value was replaced (with REPLACE) + * GNUNET_SYSERR if UNIQUE_ONLY was the option and the + * value already exists + */ +int +GNUNET_CONTAINER_multihashmap_put (struct GNUNET_CONTAINER_MultiHashMap *map, + const GNUNET_HashCode * key, void *value, + enum GNUNET_CONTAINER_MultiHashMapOption opt) +{ + struct MapEntry *e; + unsigned int i; + + i = idx_of (map, key); + if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) && + (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + e = map->map[i]; + while (e != NULL) + { + if (0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) + { + if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) + return GNUNET_SYSERR; + e->value = value; + return GNUNET_NO; + } + e = e->next; + } + } + if (map->size / 3 >= map->map_length / 4) + { + grow (map); + i = idx_of (map, key); + } + e = GNUNET_malloc (sizeof (struct MapEntry)); + e->key = *key; + e->value = value; + e->next = map->map[i]; + map->map[i] = e; + map->size++; + return GNUNET_OK; +} + + +/** + * Iterate over all entries in the map that match a particular key. + * + * @param map the map + * @param key key that the entries must correspond to + * @param it function to call on each entry + * @param it_cls extra argument to it + * @return the number of key value pairs processed, + * GNUNET_SYSERR if it aborted iteration + */ +int +GNUNET_CONTAINER_multihashmap_get_multiple (const struct + GNUNET_CONTAINER_MultiHashMap *map, + const GNUNET_HashCode * key, + GNUNET_CONTAINER_HashMapIterator it, + void *it_cls) +{ + int count; + struct MapEntry *e; + struct MapEntry *n; + + count = 0; + n = map->map[idx_of (map, key)]; + while (NULL != (e = n)) + { + n = e->next; + if (0 != memcmp (key, &e->key, sizeof (GNUNET_HashCode))) + continue; + if ((it != NULL) && (GNUNET_OK != it (it_cls, key, e->value))) + return GNUNET_SYSERR; + count++; + } + return count; +} + + +/* end of container_multihashmap.c */ diff --git a/src/util/container_slist.c b/src/util/container_slist.c new file mode 100644 index 0000000..7b85dc8 --- /dev/null +++ b/src/util/container_slist.c @@ -0,0 +1,387 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/container_slist.c + * @brief Implementation of a singly-linked list + * @author Nils Durner + */ + +#include "platform.h" +#include "gnunet_container_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/** + * Element in our linked list. + */ +struct GNUNET_CONTAINER_SList_Elem +{ + /** + * This is a linked list. + */ + struct GNUNET_CONTAINER_SList_Elem *next; + + /** + * Application data stored at this element. + */ + void *elem; + + /** + * Number of bytes stored in elem. + */ + size_t len; + + /** + * Disposition of the element. + */ + enum GNUNET_CONTAINER_SListDisposition disp; +}; + + +/** + * Handle to a singly linked list + */ +struct GNUNET_CONTAINER_SList +{ + /** + * Head of the linked list. + */ + struct GNUNET_CONTAINER_SList_Elem *head; + + /** + * Tail of the linked list. + */ + struct GNUNET_CONTAINER_SList_Elem *tail; + + /** + * Number of elements in the list. + */ + unsigned int length; +}; + + + +/** + * Create a new element that is to be inserted into the list + * @internal + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the buffer + * @return a new element + */ +static struct GNUNET_CONTAINER_SList_Elem * +create_elem (enum GNUNET_CONTAINER_SListDisposition disp, const void *buf, + size_t len) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + + if (disp == GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT) + { + e = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_SList_Elem) + len); + memcpy (&e[1], buf, len); + e->elem = (void *) &e[1]; + } + else + { + e = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_SList_Elem)); + e->elem = (void *) buf; + } + e->disp = disp; + e->len = len; + return e; +} + + +/** + * Add a new element to the list + * @param l list + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the buffer + */ +void +GNUNET_CONTAINER_slist_add (struct GNUNET_CONTAINER_SList *l, + enum GNUNET_CONTAINER_SListDisposition disp, + const void *buf, size_t len) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + + e = create_elem (disp, buf, len); + e->next = l->head; + l->head = e; + if (l->tail == NULL) + l->tail = e; + l->length++; +} + +/** + * Add a new element to the end of the list + * @param l list + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the buffer + */ +void +GNUNET_CONTAINER_slist_add_end (struct GNUNET_CONTAINER_SList *l, + enum GNUNET_CONTAINER_SListDisposition disp, + const void *buf, size_t len) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + + e = create_elem (disp, buf, len); + if (l->tail != NULL) + l->tail->next = e; + if (l->head == NULL) + l->head = e; + l->tail = e; + l->length++; +} + + +/** + * Append a singly linked list to another + * @param dst list to append to + * @param src source + */ +void +GNUNET_CONTAINER_slist_append (struct GNUNET_CONTAINER_SList *dst, + struct GNUNET_CONTAINER_SList *src) +{ + struct GNUNET_CONTAINER_SList_Iterator i; + + for (i = GNUNET_CONTAINER_slist_begin (src); + GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES; + GNUNET_CONTAINER_slist_next (&i)) + + { + GNUNET_CONTAINER_slist_add (dst, + (i.elem->disp == + GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC) ? + GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC : + GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, + i.elem->elem, i.elem->len); + } + GNUNET_CONTAINER_slist_iter_destroy (&i); +} + + +/** + * Create a new singly linked list + * @return the new list + */ +struct GNUNET_CONTAINER_SList * +GNUNET_CONTAINER_slist_create () +{ + return GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_SList)); +} + + +/** + * Destroy a singly linked list + * @param l the list to be destroyed + */ +void +GNUNET_CONTAINER_slist_destroy (struct GNUNET_CONTAINER_SList *l) +{ + GNUNET_CONTAINER_slist_clear (l); + GNUNET_free (l); +} + + +/** + * Return the beginning of a list + * @param l list + * @return iterator pointing to the beginning + */ +struct GNUNET_CONTAINER_SList_Iterator +GNUNET_CONTAINER_slist_begin (struct GNUNET_CONTAINER_SList *l) +{ + struct GNUNET_CONTAINER_SList_Iterator ret; + + memset (&ret, 0, sizeof (ret)); + ret.elem = l->head; + ret.list = l; + return ret; +} + + +/** + * Clear a list + * @param l list + */ +void +GNUNET_CONTAINER_slist_clear (struct GNUNET_CONTAINER_SList *l) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + struct GNUNET_CONTAINER_SList_Elem *n; + + e = l->head; + while (e != NULL) + { + n = e->next; + if (e->disp == GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC) + GNUNET_free (e->elem); + GNUNET_free (e); + e = n; + } + l->head = NULL; + l->tail = NULL; + l->length = 0; +} + + +/** + * Check if a list contains a certain element + * + * @param l list + * @param buf payload buffer to find + * @param len length of the payload (number of bytes in buf) + */ +int +GNUNET_CONTAINER_slist_contains (const struct GNUNET_CONTAINER_SList *l, + const void *buf, size_t len) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + + for (e = l->head; e != NULL; e = e->next) + if ((e->len == len) && (memcmp (buf, e->elem, len) == 0)) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Count the elements of a list + * @param l list + * @return number of elements in the list + */ +int +GNUNET_CONTAINER_slist_count (const struct GNUNET_CONTAINER_SList *l) +{ + return l->length; +} + + +/** + * Remove an element from the list + * + * @param i iterator that points to the element to be removed + */ +void +GNUNET_CONTAINER_slist_erase (struct GNUNET_CONTAINER_SList_Iterator *i) +{ + struct GNUNET_CONTAINER_SList_Elem *next; + + next = i->elem->next; + if (i->last != NULL) + i->last->next = next; + else + i->list->head = next; + if (next == NULL) + i->list->tail = i->last; + if (i->elem->disp == GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC) + GNUNET_free (i->elem->elem); + GNUNET_free (i->elem); + i->list->length--; + i->elem = next; +} + + +/** + * Insert an element into a list at a specific position + * @param before where to insert the new element + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the payload + */ +void +GNUNET_CONTAINER_slist_insert (struct GNUNET_CONTAINER_SList_Iterator *before, + enum GNUNET_CONTAINER_SListDisposition disp, + const void *buf, size_t len) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + + e = create_elem (disp, buf, len); + e->next = before->elem; + if (before->last != NULL) + before->last->next = e; + else + before->list->head = e; + if (e->next == NULL) + before->list->tail = e; + before->list->length++; +} + + +/** + * Advance an iterator to the next element + * @param i iterator + * @return GNUNET_YES on success, GNUNET_NO if the end has been reached + */ +int +GNUNET_CONTAINER_slist_next (struct GNUNET_CONTAINER_SList_Iterator *i) +{ + i->last = i->elem; + i->elem = i->elem->next; + + return (i->elem != NULL) ? GNUNET_YES : GNUNET_NO; +} + + +/** + * Check if an iterator points beyond the end of a list + * + * @param i iterator + * @return GNUNET_YES if the end has been reached, GNUNET_NO if the iterator + * points to a valid element + */ +int +GNUNET_CONTAINER_slist_end (struct GNUNET_CONTAINER_SList_Iterator *i) +{ + return (i->elem == NULL) ? GNUNET_YES : GNUNET_NO; +} + + +/** + * Retrieve the element at a specific position in a list + * @param i iterator + * @param len payload length + * @return payload + */ +void * +GNUNET_CONTAINER_slist_get (const struct GNUNET_CONTAINER_SList_Iterator *i, + size_t * len) +{ + if (len) + *len = i->elem->len; + return i->elem->elem; +} + +/** + * Release an iterator + * @param i iterator + */ +void +GNUNET_CONTAINER_slist_iter_destroy (struct GNUNET_CONTAINER_SList_Iterator *i) +{ +} + +/* end of container_slist.c */ diff --git a/src/util/crypto_aes.c b/src/util/crypto_aes.c new file mode 100644 index 0000000..8b031f3 --- /dev/null +++ b/src/util/crypto_aes.c @@ -0,0 +1,185 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/crypto_aes.c + * @brief Symmetric encryption services. + * @author Christian Grothoff + * @author Ioana Patrascu + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/** + * Create a new SessionKey (for AES-256). + */ +void +GNUNET_CRYPTO_aes_create_session_key (struct GNUNET_CRYPTO_AesSessionKey *key) +{ + gcry_randomize (&key->key[0], GNUNET_CRYPTO_AES_KEY_LENGTH, + GCRY_STRONG_RANDOM); + key->crc32 = + htonl (GNUNET_CRYPTO_crc32_n (key, GNUNET_CRYPTO_AES_KEY_LENGTH)); +} + +/** + * Check that a new session key is well-formed. + * + * @return GNUNET_OK if the key is valid + */ +int +GNUNET_CRYPTO_aes_check_session_key (const struct GNUNET_CRYPTO_AesSessionKey + *key) +{ + uint32_t crc; + + crc = GNUNET_CRYPTO_crc32_n (key, GNUNET_CRYPTO_AES_KEY_LENGTH); + if (ntohl (key->crc32) == crc) + return GNUNET_OK; + GNUNET_break_op (0); + return GNUNET_SYSERR; +} + + +/** + * Encrypt a block with the public key of another + * host that uses the same cyper. + * @param block the block to encrypt + * @param len the size of the block + * @param sessionkey the key used to encrypt + * @param iv the initialization vector to use, use INITVALUE + * for streams. + * @param result the output parameter in which to store the encrypted result + * @returns the size of the encrypted block, -1 for errors + */ +ssize_t +GNUNET_CRYPTO_aes_encrypt (const void *block, size_t len, + const struct GNUNET_CRYPTO_AesSessionKey * + sessionkey, + const struct GNUNET_CRYPTO_AesInitializationVector * + iv, void *result) +{ + gcry_cipher_hd_t handle; + int rc; + + if (sessionkey->crc32 != + htonl (GNUNET_CRYPTO_crc32_n (sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH))) + { + GNUNET_break (0); + return -1; + } + GNUNET_assert (0 == + gcry_cipher_open (&handle, GCRY_CIPHER_AES256, + GCRY_CIPHER_MODE_CFB, 0)); + rc = gcry_cipher_setkey (handle, sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH); + GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); + rc = gcry_cipher_setiv (handle, iv, + sizeof (struct + GNUNET_CRYPTO_AesInitializationVector)); + GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); + GNUNET_assert (0 == gcry_cipher_encrypt (handle, result, len, block, len)); + gcry_cipher_close (handle); + return len; +} + +/** + * Decrypt a given block with the sessionkey. + * + * @param block the data to decrypt, encoded as returned by encrypt + * @param size the size of the block to decrypt + * @param sessionkey the key used to decrypt + * @param iv the initialization vector to use, use INITVALUE + * for streams. + * @param result address to store the result at + * @return -1 on failure, size of decrypted block on success + */ +ssize_t +GNUNET_CRYPTO_aes_decrypt (const void *block, size_t size, + const struct GNUNET_CRYPTO_AesSessionKey * + sessionkey, + const struct GNUNET_CRYPTO_AesInitializationVector * + iv, void *result) +{ + gcry_cipher_hd_t handle; + int rc; + + if (sessionkey->crc32 != + htonl (GNUNET_CRYPTO_crc32_n (sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH))) + { + GNUNET_break (0); + return -1; + } + GNUNET_assert (0 == + gcry_cipher_open (&handle, GCRY_CIPHER_AES256, + GCRY_CIPHER_MODE_CFB, 0)); + rc = gcry_cipher_setkey (handle, sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH); + GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); + rc = gcry_cipher_setiv (handle, iv, + sizeof (struct + GNUNET_CRYPTO_AesInitializationVector)); + GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); + GNUNET_assert (0 == gcry_cipher_decrypt (handle, result, size, block, size)); + gcry_cipher_close (handle); + return size; +} + +/** + * @brief Derive an IV + * @param iv initialization vector + * @param skey session key + * @param salt salt for the derivation + * @param salt_len size of the salt + * @param ... pairs of void * & size_t for context chunks, terminated by NULL + */ +void +GNUNET_CRYPTO_aes_derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, + const struct GNUNET_CRYPTO_AesSessionKey *skey, + const void *salt, size_t salt_len, ...) +{ + va_list argp; + + va_start (argp, salt_len); + GNUNET_CRYPTO_aes_derive_iv_v (iv, skey, salt, salt_len, argp); + va_end (argp); +} + +/** + * @brief Derive an IV + * @param iv initialization vector + * @param skey session key + * @param salt salt for the derivation + * @param salt_len size of the salt + * @param argp pairs of void * & size_t for context chunks, terminated by NULL + */ +void +GNUNET_CRYPTO_aes_derive_iv_v (struct GNUNET_CRYPTO_AesInitializationVector *iv, + const struct GNUNET_CRYPTO_AesSessionKey *skey, + const void *salt, size_t salt_len, va_list argp) +{ + GNUNET_CRYPTO_kdf_v (iv->iv, sizeof (iv->iv), salt, salt_len, skey->key, + sizeof (skey->key), argp); +} + +/* end of crypto_aes.c */ diff --git a/src/util/crypto_crc.c b/src/util/crypto_crc.c new file mode 100644 index 0000000..8bccf6b --- /dev/null +++ b/src/util/crypto_crc.c @@ -0,0 +1,171 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + For the actual CRC-32 code: + Copyright abandoned; this code is in the public domain. + Provided to GNUnet by peter@horizon.com +*/ + +/** + * @file util/crypto_crc.c + * @brief implementation of CRC16 and CRC32 + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/* Avoid wasting space on 8-byte longs. */ +#if UINT_MAX >= 0xffffffff +typedef unsigned int uLong; +#elif ULONG_MAX >= 0xffffffff +typedef unsigned long uLong; +#else +#error This compiler is not ANSI-compliant! +#endif + +#define Z_NULL 0 + + +#define POLYNOMIAL (uLong)0xedb88320 +static uLong crc_table[256]; + +/* + * This routine writes each crc_table entry exactly once, + * with the ccorrect final value. Thus, it is safe to call + * even on a table that someone else is using concurrently. + */ +static void +crc_init () +{ + static int once; + unsigned int i, j; + uLong h = 1; + + if (once) + return; + once = 1; + crc_table[0] = 0; + for (i = 128; i; i >>= 1) + { + h = (h >> 1) ^ ((h & 1) ? POLYNOMIAL : 0); + /* h is now crc_table[i] */ + for (j = 0; j < 256; j += 2 * i) + crc_table[i + j] = crc_table[j] ^ h; + } +} + +/* + * This computes the standard preset and inverted CRC, as used + * by most networking standards. Start by passing in an initial + * chaining value of 0, and then pass in the return value from the + * previous crc32() call. The final return value is the CRC. + * Note that this is a little-endian CRC, which is best used with + * data transmitted lsbit-first, and it should, itself, be appended + * to data in little-endian byte and bit order to preserve the + * property of detecting all burst errors of length 32 bits or less. + */ +static uLong +crc32 (uLong crc, const char *buf, size_t len) +{ + crc_init (); + GNUNET_assert (crc_table[255] != 0); + crc ^= 0xffffffff; + while (len--) + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + return crc ^ 0xffffffff; +} + + +/** + * Compute the CRC32 checksum for the first len bytes of the buffer. + * + * @param buf the data over which we're taking the CRC + * @param len the length of the buffer + * @return the resulting CRC32 checksum + */ +int32_t +GNUNET_CRYPTO_crc32_n (const void *buf, size_t len) +{ + uLong crc; + + crc = crc32 (0L, Z_NULL, 0); + crc = crc32 (crc, (char *) buf, len); + return crc; +} + + +/** + * Perform an incremental step in a CRC16 (for TCP/IP) calculation. + * + * @param sum current sum, initially 0 + * @param buf buffer to calculate CRC over (must be 16-bit aligned) + * @param len number of bytes in hdr, must be multiple of 2 + * @return updated crc sum (must be subjected to GNUNET_CRYPTO_crc16_finish to get actual crc16) + */ +uint32_t +GNUNET_CRYPTO_crc16_step (uint32_t sum, const void *buf, size_t len) +{ + const uint16_t *hdr = buf; + for (; len >= 2; len -= 2) + sum += *(hdr++); + if (len == 1) + sum += (*hdr) & ntohs(0xFF00); + return sum; +} + + +/** + * Convert results from GNUNET_CRYPTO_crc16_step to final crc16. + * + * @param sum cummulative sum + * @return crc16 value + */ +uint16_t +GNUNET_CRYPTO_crc16_finish (uint32_t sum) +{ + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + + return ~sum; +} + + +/** + * Calculate the checksum of a buffer in one step. + * + * @param buf buffer to calculate CRC over (must be 16-bit aligned) + * @param len number of bytes in hdr, must be multiple of 2 + * @return crc16 value + */ +uint16_t +GNUNET_CRYPTO_crc16_n (const void *buf, size_t len) +{ + const uint16_t *hdr = buf; + uint32_t sum = GNUNET_CRYPTO_crc16_step (0, hdr, len); + + return GNUNET_CRYPTO_crc16_finish (sum); +} + + + +/* end of crypto_crc.c */ diff --git a/src/util/crypto_hash.c b/src/util/crypto_hash.c new file mode 100644 index 0000000..63d9654 --- /dev/null +++ b/src/util/crypto_hash.c @@ -0,0 +1,647 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + SHA-512 code by Jean-Luc Cooke + + Copyright (c) Jean-Luc Cooke + Copyright (c) Andrew McDonald + Copyright (c) 2003 Kyle McMartin +*/ + +/** + * @file util/crypto_hash.c + * @brief SHA-512 GNUNET_CRYPTO_hash related functions + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_disk_lib.h" +#include + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +/** + * Hash block of given size. + * + * @param block the data to GNUNET_CRYPTO_hash, length is given as a second argument + * @param size the length of the data to GNUNET_CRYPTO_hash + * @param ret pointer to where to write the hashcode + */ +void +GNUNET_CRYPTO_hash (const void *block, size_t size, GNUNET_HashCode * ret) +{ + gcry_md_hash_buffer (GCRY_MD_SHA512, ret, block, size); +} + + +/** + * Context used when hashing a file. + */ +struct GNUNET_CRYPTO_FileHashContext +{ + + /** + * Function to call upon completion. + */ + GNUNET_CRYPTO_HashCompletedCallback callback; + + /** + * Closure for callback. + */ + void *callback_cls; + + /** + * IO buffer. + */ + unsigned char *buffer; + + /** + * Name of the file we are hashing. + */ + char *filename; + + /** + * File descriptor. + */ + struct GNUNET_DISK_FileHandle *fh; + + /** + * Cummulated hash. + */ + gcry_md_hd_t md; + + /** + * Size of the file. + */ + uint64_t fsize; + + /** + * Current offset. + */ + uint64_t offset; + + /** + * Current task for hashing. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Priority we use. + */ + enum GNUNET_SCHEDULER_Priority priority; + + /** + * Blocksize. + */ + size_t bsize; + +}; + + +/** + * Report result of hash computation to callback + * and free associated resources. + */ +static void +file_hash_finish (struct GNUNET_CRYPTO_FileHashContext *fhc, + const GNUNET_HashCode * res) +{ + fhc->callback (fhc->callback_cls, res); + GNUNET_free (fhc->filename); + if (!GNUNET_DISK_handle_invalid (fhc->fh)) + GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh)); + gcry_md_close (fhc->md); + GNUNET_free (fhc); /* also frees fhc->buffer */ +} + + +/** + * File hashing task. + * + * @param cls closure + * @param tc context + */ +static void +file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CRYPTO_FileHashContext *fhc = cls; + GNUNET_HashCode *res; + size_t delta; + + fhc->task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (fhc->offset <= fhc->fsize); + delta = fhc->bsize; + if (fhc->fsize - fhc->offset < delta) + delta = fhc->fsize - fhc->offset; + if (delta != GNUNET_DISK_file_read (fhc->fh, fhc->buffer, delta)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", fhc->filename); + file_hash_finish (fhc, NULL); + return; + } + gcry_md_write (fhc->md, fhc->buffer, delta); + fhc->offset += delta; + if (fhc->offset == fhc->fsize) + { + res = (GNUNET_HashCode *) gcry_md_read (fhc->md, GCRY_MD_SHA512); + file_hash_finish (fhc, res); + return; + } + fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority, + &file_hash_task, fhc); +} + + +/** + * Compute the hash of an entire file. + * + * @param priority scheduling priority to use + * @param filename name of file to hash + * @param blocksize number of bytes to process in one task + * @param callback function to call upon completion + * @param callback_cls closure for callback + * @return NULL on (immediate) errror + */ +struct GNUNET_CRYPTO_FileHashContext * +GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority, + const char *filename, size_t blocksize, + GNUNET_CRYPTO_HashCompletedCallback callback, + void *callback_cls) +{ + struct GNUNET_CRYPTO_FileHashContext *fhc; + + GNUNET_assert (blocksize > 0); + fhc = + GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_FileHashContext) + blocksize); + fhc->callback = callback; + fhc->callback_cls = callback_cls; + fhc->buffer = (unsigned char *) &fhc[1]; + fhc->filename = GNUNET_strdup (filename); + if (GPG_ERR_NO_ERROR != gcry_md_open (&fhc->md, GCRY_MD_SHA512, 0)) + { + GNUNET_break (0); + GNUNET_free (fhc); + return NULL; + } + fhc->bsize = blocksize; + if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fhc->fsize, GNUNET_NO)) + { + GNUNET_free (fhc->filename); + GNUNET_free (fhc); + return NULL; + } + fhc->fh = + GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (!fhc->fh) + { + GNUNET_free (fhc->filename); + GNUNET_free (fhc); + return NULL; + } + fhc->priority = priority; + fhc->task = + GNUNET_SCHEDULER_add_with_priority (priority, &file_hash_task, fhc); + return fhc; +} + + +/** + * Cancel a file hashing operation. + * + * @param fhc operation to cancel (callback must not yet have been invoked) + */ +void +GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc) +{ + GNUNET_SCHEDULER_cancel (fhc->task); + GNUNET_free (fhc->filename); + GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh)); + GNUNET_free (fhc); +} + + + +/* ***************** binary-ASCII encoding *************** */ + +/** + * Get the numeric value corresponding to a character. + * + * @param a a character + * @return corresponding numeric value + */ +static unsigned int +getValue__ (unsigned char a) +{ + if ((a >= '0') && (a <= '9')) + return a - '0'; + if ((a >= 'A') && (a <= 'V')) + return (a - 'A' + 10); + return -1; +} + + +/** + * Convert GNUNET_CRYPTO_hash to ASCII encoding. The ASCII encoding is rather + * GNUnet specific. It was chosen such that it only uses characters + * in [0-9A-V], can be produced without complex arithmetics and uses a + * small number of characters. The GNUnet encoding uses 103 + * characters plus a null terminator. + * + * @param block the hash code + * @param result where to store the encoding (struct GNUNET_CRYPTO_HashAsciiEncoded can be + * safely cast to char*, a '\\0' termination is set). + */ +void +GNUNET_CRYPTO_hash_to_enc (const GNUNET_HashCode * block, + struct GNUNET_CRYPTO_HashAsciiEncoded *result) +{ + /** + * 32 characters for encoding (GNUNET_CRYPTO_hash => 32 characters) + */ + static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; + unsigned int wpos; + unsigned int rpos; + unsigned int bits; + unsigned int vbit; + + GNUNET_assert (block != NULL); + GNUNET_assert (result != NULL); + vbit = 0; + wpos = 0; + rpos = 0; + bits = 0; + while ((rpos < sizeof (GNUNET_HashCode)) || (vbit > 0)) + { + if ((rpos < sizeof (GNUNET_HashCode)) && (vbit < 5)) + { + bits = (bits << 8) | ((unsigned char *) block)[rpos++]; /* eat 8 more bits */ + vbit += 8; + } + if (vbit < 5) + { + bits <<= (5 - vbit); /* zero-padding */ + GNUNET_assert (vbit == 2); /* padding by 3: 512+3 mod 5 == 0 */ + vbit = 5; + } + GNUNET_assert (wpos < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1); + result->encoding[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; + vbit -= 5; + } + GNUNET_assert (wpos == sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1); + GNUNET_assert (vbit == 0); + result->encoding[wpos] = '\0'; +} + + +/** + * Convert ASCII encoding back to GNUNET_CRYPTO_hash + * + * @param enc the encoding + * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) + * @param result where to store the GNUNET_CRYPTO_hash code + * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding + */ +int +GNUNET_CRYPTO_hash_from_string2 (const char *enc, size_t enclen, + GNUNET_HashCode * result) +{ + unsigned int rpos; + unsigned int wpos; + unsigned int bits; + unsigned int vbit; + int ret; + + if (enclen != sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1) + return GNUNET_SYSERR; + + vbit = 2; /* padding! */ + wpos = sizeof (GNUNET_HashCode); + rpos = sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1; + bits = (ret = getValue__ (enc[--rpos])) >> 3; + if (-1 == ret) + return GNUNET_SYSERR; + while (wpos > 0) + { + GNUNET_assert (rpos > 0); + bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits; + if (-1 == ret) + return GNUNET_SYSERR; + vbit += 5; + if (vbit >= 8) + { + ((unsigned char *) result)[--wpos] = (unsigned char) bits; + bits >>= 8; + vbit -= 8; + } + } + GNUNET_assert (rpos == 0); + GNUNET_assert (vbit == 0); + return GNUNET_OK; +} + + +/** + * Compute the distance between 2 hashcodes. The computation must be + * fast, not involve bits[0] or bits[4] (they're used elsewhere), and be + * somewhat consistent. And of course, the result should be a positive + * number. + * + * @param a some hash code + * @param b some hash code + * @return a positive number which is a measure for + * hashcode proximity. + */ +unsigned int +GNUNET_CRYPTO_hash_distance_u32 (const GNUNET_HashCode * a, + const GNUNET_HashCode * b) +{ + unsigned int x1 = (a->bits[1] - b->bits[1]) >> 16; + unsigned int x2 = (b->bits[1] - a->bits[1]) >> 16; + + return (x1 * x2); +} + + +/** + * Create a random hash code. + * + * @param mode desired quality level + * @param result hash code that is randomized + */ +void +GNUNET_CRYPTO_hash_create_random (enum GNUNET_CRYPTO_Quality mode, + GNUNET_HashCode * result) +{ + int i; + + for (i = (sizeof (GNUNET_HashCode) / sizeof (uint32_t)) - 1; i >= 0; i--) + result->bits[i] = GNUNET_CRYPTO_random_u32 (mode, UINT32_MAX); +} + + +/** + * compute result(delta) = b - a + * + * @param a some hash code + * @param b some hash code + * @param result set to b - a + */ +void +GNUNET_CRYPTO_hash_difference (const GNUNET_HashCode * a, + const GNUNET_HashCode * b, + GNUNET_HashCode * result) +{ + int i; + + for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) + result->bits[i] = b->bits[i] - a->bits[i]; +} + + +/** + * compute result(b) = a + delta + * + * @param a some hash code + * @param delta some hash code + * @param result set to a + delta + */ +void +GNUNET_CRYPTO_hash_sum (const GNUNET_HashCode * a, + const GNUNET_HashCode * delta, GNUNET_HashCode * result) +{ + int i; + + for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) + result->bits[i] = delta->bits[i] + a->bits[i]; +} + + +/** + * compute result = a ^ b + * + * @param a some hash code + * @param b some hash code + * @param result set to a ^ b + */ +void +GNUNET_CRYPTO_hash_xor (const GNUNET_HashCode * a, const GNUNET_HashCode * b, + GNUNET_HashCode * result) +{ + int i; + + for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) + result->bits[i] = a->bits[i] ^ b->bits[i]; +} + + +/** + * Convert a hashcode into a key. + * + * @param hc hash code that serves to generate the key + * @param skey set to a valid session key + * @param iv set to a valid initialization vector + */ +void +GNUNET_CRYPTO_hash_to_aes_key (const GNUNET_HashCode * hc, + struct GNUNET_CRYPTO_AesSessionKey *skey, + struct GNUNET_CRYPTO_AesInitializationVector *iv) +{ + GNUNET_assert (sizeof (GNUNET_HashCode) >= + GNUNET_CRYPTO_AES_KEY_LENGTH + + sizeof (struct GNUNET_CRYPTO_AesInitializationVector)); + memcpy (skey, hc, GNUNET_CRYPTO_AES_KEY_LENGTH); + skey->crc32 = + htonl (GNUNET_CRYPTO_crc32_n (skey, GNUNET_CRYPTO_AES_KEY_LENGTH)); + memcpy (iv, &((char *) hc)[GNUNET_CRYPTO_AES_KEY_LENGTH], + sizeof (struct GNUNET_CRYPTO_AesInitializationVector)); +} + + +/** + * Obtain a bit from a hashcode. + * @param code the GNUNET_CRYPTO_hash to index bit-wise + * @param bit index into the hashcode, [0...511] + * @return Bit \a bit from hashcode \a code, -1 for invalid index + */ +int +GNUNET_CRYPTO_hash_get_bit (const GNUNET_HashCode * code, unsigned int bit) +{ + GNUNET_assert (bit < 8 * sizeof (GNUNET_HashCode)); + return (((unsigned char *) code)[bit >> 3] & (1 << (bit & 7))) > 0; +} + + +/** + * Determine how many low order bits match in two + * GNUNET_HashCodes. i.e. - 010011 and 011111 share + * the first two lowest order bits, and therefore the + * return value is two (NOT XOR distance, nor how many + * bits match absolutely!). + * + * @param first the first hashcode + * @param second the hashcode to compare first to + * + * @return the number of bits that match + */ +unsigned int +GNUNET_CRYPTO_hash_matching_bits (const GNUNET_HashCode * first, + const GNUNET_HashCode * second) +{ + unsigned int i; + + for (i = 0; i < sizeof (GNUNET_HashCode) * 8; i++) + if (GNUNET_CRYPTO_hash_get_bit (first, i) != + GNUNET_CRYPTO_hash_get_bit (second, i)) + return i; + return sizeof (GNUNET_HashCode) * 8; +} + + +/** + * Compare function for HashCodes, producing a total ordering + * of all hashcodes. + * + * @param h1 some hash code + * @param h2 some hash code + * @return 1 if h1 > h2, -1 if h1 < h2 and 0 if h1 == h2. + */ +int +GNUNET_CRYPTO_hash_cmp (const GNUNET_HashCode * h1, const GNUNET_HashCode * h2) +{ + unsigned int *i1; + unsigned int *i2; + int i; + + i1 = (unsigned int *) h1; + i2 = (unsigned int *) h2; + for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) + { + if (i1[i] > i2[i]) + return 1; + if (i1[i] < i2[i]) + return -1; + } + return 0; +} + + +/** + * Find out which of the two GNUNET_CRYPTO_hash codes is closer to target + * in the XOR metric (Kademlia). + * + * @param h1 some hash code + * @param h2 some hash code + * @param target some hash code + * @return -1 if h1 is closer, 1 if h2 is closer and 0 if h1==h2. + */ +int +GNUNET_CRYPTO_hash_xorcmp (const GNUNET_HashCode * h1, + const GNUNET_HashCode * h2, + const GNUNET_HashCode * target) +{ + int i; + unsigned int d1; + unsigned int d2; + + for (i = sizeof (GNUNET_HashCode) / sizeof (unsigned int) - 1; i >= 0; i--) + { + d1 = ((unsigned int *) h1)[i] ^ ((unsigned int *) target)[i]; + d2 = ((unsigned int *) h2)[i] ^ ((unsigned int *) target)[i]; + if (d1 > d2) + return 1; + else if (d1 < d2) + return -1; + } + return 0; +} + + +/** + * @brief Derive an authentication key + * @param key authentication key + * @param rkey root key + * @param salt salt + * @param salt_len size of the salt + * @param ... pair of void * & size_t for context chunks, terminated by NULL + */ +void +GNUNET_CRYPTO_hmac_derive_key (struct GNUNET_CRYPTO_AuthKey *key, + const struct GNUNET_CRYPTO_AesSessionKey *rkey, + const void *salt, size_t salt_len, ...) +{ + va_list argp; + + va_start (argp, salt_len); + GNUNET_CRYPTO_hmac_derive_key_v (key, rkey, salt, salt_len, argp); + va_end (argp); +} + + +/** + * @brief Derive an authentication key + * @param key authentication key + * @param rkey root key + * @param salt salt + * @param salt_len size of the salt + * @param argp pair of void * & size_t for context chunks, terminated by NULL + */ +void +GNUNET_CRYPTO_hmac_derive_key_v (struct GNUNET_CRYPTO_AuthKey *key, + const struct GNUNET_CRYPTO_AesSessionKey *rkey, + const void *salt, size_t salt_len, + va_list argp) +{ + GNUNET_CRYPTO_kdf_v (key->key, sizeof (key->key), salt, salt_len, rkey->key, + sizeof (rkey->key), argp); +} + + +/** + * Calculate HMAC of a message (RFC 2104) + * + * @param key secret key + * @param plaintext input plaintext + * @param plaintext_len length of plaintext + * @param hmac where to store the hmac + */ +void +GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key, + const void *plaintext, size_t plaintext_len, + GNUNET_HashCode * hmac) +{ + gcry_md_hd_t md; + const unsigned char *mc; + + GNUNET_assert (GPG_ERR_NO_ERROR == + gcry_md_open (&md, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC)); + gcry_md_setkey (md, key->key, sizeof (key->key)); + gcry_md_write (md, plaintext, plaintext_len); + mc = gcry_md_read (md, GCRY_MD_SHA512); + if (mc != NULL) + memcpy (hmac->bits, mc, sizeof (hmac->bits)); + gcry_md_close (md); +} + + +/* end of crypto_hash.c */ diff --git a/src/util/crypto_hkdf.c b/src/util/crypto_hkdf.c new file mode 100644 index 0000000..40bfa67 --- /dev/null +++ b/src/util/crypto_hkdf.c @@ -0,0 +1,299 @@ +/* + Copyright (c) 2010 Nils Durner + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/** + * @file src/util/crypto_hkdf.c + * @brief Hash-based KDF as defined in RFC 5869 + * @see http://www.rfc-editor.org/rfc/rfc5869.txt + * @todo remove GNUNET references + * @author Nils Durner + * + * The following list of people have reviewed this code and considered + * it correct on the date given (if you reviewed it, please + * have your name added to the list): + * + * - Christian Grothoff (08.10.2010) + * - Nathan Evans (08.10.2010) + * - Matthias Wachs (08.10.2010) + */ + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/** + * Set this to 0 if you compile this code outside of GNUnet. + */ +#define GNUNET_BUILD 1 + +/** + * Enable debugging. + */ +#define DEBUG_HKDF 0 + + +#if GNUNET_BUILD +#include "platform.h" +#include "gnunet_crypto_lib.h" +#else +#define GNUNET_NO 0 +#define GNUNET_YES 1 +#define GNUNET_SYSERR -1 +#include +#endif + +#include + + +/** + * @brief Compute the HMAC + * @todo use chunked buffers + * @param mac gcrypt MAC handle + * @param key HMAC key + * @param key_len length of key + * @param buf message to be processed + * @param buf_len length of buf + * @return HMAC, freed by caller via gcry_md_close/_reset + */ +static const void * +doHMAC (gcry_md_hd_t mac, const void *key, size_t key_len, const void *buf, + size_t buf_len) +{ + gcry_md_setkey (mac, key, key_len); + gcry_md_write (mac, buf, buf_len); + + return (const void *) gcry_md_read (mac, 0); +} + +/** + * @brief Generate pseudo-random key + * @param mac gcrypt HMAC handle + * @param xts salt + * @param xts_len length of the salt + * @param skm source key material + * @param skm_len length of skm + * @param prk result buffer (allocated by caller; at least gcry_md_dlen() bytes) + * @return GNUNET_YES on success + */ +static int +getPRK (gcry_md_hd_t mac, const void *xts, size_t xts_len, const void *skm, + size_t skm_len, void *prk) +{ + const void *ret; + + ret = doHMAC (mac, xts, xts_len, skm, skm_len); + if (ret == NULL) + return GNUNET_SYSERR; + memcpy (prk, ret, gcry_md_get_algo_dlen (gcry_md_get_algo (mac))); + + return GNUNET_YES; +} + + +#if DEBUG_HKDF +static void +dump (const char *src, const void *p, unsigned int l) +{ + unsigned int i; + + printf ("\n%s: ", src); + for (i = 0; i < l; i++) + { + printf ("%2x", (int) ((const unsigned char *) p)[i]); + } + printf ("\n"); +} +#endif + + +/** + * @brief Derive key + * @param result buffer for the derived key, allocated by caller + * @param out_len desired length of the derived key + * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... + * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... + * @param xts salt + * @param xts_len length of xts + * @param skm source key material + * @param skm_len length of skm + * @param argp va_list of void * & size_t pairs for context chunks + * @return GNUNET_YES on success + */ +int +GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo, + const void *xts, size_t xts_len, const void *skm, + size_t skm_len, va_list argp) +{ + const void *hc; + unsigned long i, t, d; + unsigned int k = gcry_md_get_algo_dlen (prf_algo); + unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo); + char prk[xtr_len]; + int ret; + gcry_md_hd_t xtr, prf; + size_t ctx_len; + va_list args; + + if (k == 0) + return GNUNET_SYSERR; + + if (gcry_md_open (&xtr, xtr_algo, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR) + return GNUNET_SYSERR; + + if (gcry_md_open (&prf, prf_algo, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR) + { + gcry_md_close (xtr); + return GNUNET_SYSERR; + } + + va_copy (args, argp); + + ctx_len = 0; + while (NULL != va_arg (args, void *)) + ctx_len += va_arg (args, size_t); + + va_end (args); + + memset (result, 0, out_len); + if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES) + goto hkdf_error; +#if DEBUG_HKDF + dump ("PRK", prk, xtr_len); +#endif + + t = out_len / k; + d = out_len % k; + + /* K(1) */ + { + size_t plain_len = k + ctx_len + 1; + char plain[plain_len]; + const void *ctx; + char *dst; + + dst = plain + k; + va_copy (args, argp); + while ((ctx = va_arg (args, void *))) + { + size_t len; + + len = va_arg (args, size_t); + memcpy (dst, ctx, len); + dst += len; + } + va_end (args); + + if (t > 0) + { + memset (plain + k + ctx_len, 1, 1); +#if DEBUG_HKDF + dump ("K(1)", plain, plain_len); +#endif + hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1); + if (hc == NULL) + goto hkdf_error; + memcpy (result, hc, k); + result += k; + } + + /* K(i+1) */ + for (i = 1; i < t; i++) + { + memcpy (plain, result - k, k); + memset (plain + k + ctx_len, i + 1, 1); + gcry_md_reset (prf); +#if DEBUG_HKDF + dump ("K(i+1)", plain, plain_len); +#endif + hc = doHMAC (prf, prk, xtr_len, plain, plain_len); + if (hc == NULL) + goto hkdf_error; + memcpy (result, hc, k); + result += k; + } + + /* K(t):d */ + if (d > 0) + { + if (t > 0) + { + memcpy (plain, result - k, k); + i++; + } + memset (plain + k + ctx_len, i, 1); + gcry_md_reset (prf); +#if DEBUG_HKDF + dump ("K(t):d", plain, plain_len); +#endif + if (t > 0) + hc = doHMAC (prf, prk, xtr_len, plain, plain_len); + else + hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k); + if (hc == NULL) + goto hkdf_error; + memcpy (result, hc, d); + } +#if DEBUG_HKDF + dump ("result", result - k, out_len); +#endif + + ret = GNUNET_YES; + goto hkdf_ok; + } +hkdf_error: + ret = GNUNET_SYSERR; +hkdf_ok: + gcry_md_close (prf); + gcry_md_close (xtr); + + return ret; +} + + +/** + * @brief Derive key + * @param result buffer for the derived key, allocated by caller + * @param out_len desired length of the derived key + * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... + * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... + * @param xts salt + * @param xts_len length of xts + * @param skm source key material + * @param skm_len length of skm + * @return GNUNET_YES on success + */ +int +GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo, + const void *xts, size_t xts_len, const void *skm, + size_t skm_len, ...) +{ + va_list argp; + int ret; + + va_start (argp, skm_len); + ret = + GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, xts_len, + skm, skm_len, argp); + va_end (argp); + + return ret; +} + +/* end of crypto_hkdf.c */ diff --git a/src/util/crypto_kdf.c b/src/util/crypto_kdf.c new file mode 100644 index 0000000..0e7fbbb --- /dev/null +++ b/src/util/crypto_kdf.c @@ -0,0 +1,89 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/util/crypto_kdf.c + * @brief Key derivation + * @author Nils Durner + */ + +#include + +#include "platform.h" +#include "gnunet_crypto_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/** + * @brief Derive key + * @param result buffer for the derived key, allocated by caller + * @param out_len desired length of the derived key + * @param xts salt + * @param xts_len length of xts + * @param skm source key material + * @param skm_len length of skm + * @param argp va_list of void * & size_t pairs for context chunks + * @return GNUNET_YES on success + */ +int +GNUNET_CRYPTO_kdf_v (void *result, size_t out_len, const void *xts, + size_t xts_len, const void *skm, size_t skm_len, + va_list argp) +{ + /* + * "Finally, we point out to a particularly advantageous instantiation using + * HMAC-SHA512 as XTR and HMAC-SHA256 in PRF* (in which case the output from SHA-512 is + * truncated to 256 bits). This makes sense in two ways: First, the extraction part is where we need a + * stronger hash function due to the unconventional demand from the hash function in the extraction + * setting. Second, as shown in Section 6, using HMAC with a truncated output as an extractor + * allows to prove the security of HKDF under considerably weaker assumptions on the underlying + * hash function." + * + * http://eprint.iacr.org/2010/264 + */ + + return GNUNET_CRYPTO_hkdf_v (result, out_len, GCRY_MD_SHA512, GCRY_MD_SHA256, + xts, xts_len, skm, skm_len, argp); +} + +/** + * @brief Derive key + * @param result buffer for the derived key, allocated by caller + * @param out_len desired length of the derived key + * @param xts salt + * @param xts_len length of xts + * @param skm source key material + * @param skm_len length of skm + * @param ... void * & size_t pairs for context chunks + * @return GNUNET_YES on success + */ +int +GNUNET_CRYPTO_kdf (void *result, size_t out_len, const void *xts, + size_t xts_len, const void *skm, size_t skm_len, ...) +{ + va_list argp; + int ret; + + va_start (argp, skm_len); + ret = GNUNET_CRYPTO_kdf_v (result, out_len, xts, xts_len, skm, skm_len, argp); + va_end (argp); + + return ret; +} diff --git a/src/util/crypto_ksk.c b/src/util/crypto_ksk.c new file mode 100644 index 0000000..0f5a295 --- /dev/null +++ b/src/util/crypto_ksk.c @@ -0,0 +1,769 @@ +/* + This file is part of GNUnet. + Copyright (C) 1994, 1996, 1998, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Note: This code is based on code from libgcrypt + The code was adapted for GNUnet to support RSA-key generation + based on weak, pseudo-random keys. Do NOT use to generate + ordinary RSA keys! +*/ + + +/** + * @file util/crypto_ksk.c + * @brief implementation of RSA-Key generation for KBlocks + * (do NOT use for pseudonyms or hostkeys!) + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_os_lib.h" +#include +#include + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' with the message given + * by gcry_strerror(rc). + */ +#define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0); + + +typedef struct +{ + gcry_mpi_t n; /* public modulus */ + gcry_mpi_t e; /* public exponent */ + gcry_mpi_t d; /* exponent */ + gcry_mpi_t p; /* prime p. */ + gcry_mpi_t q; /* prime q. */ + gcry_mpi_t u; /* inverse of p mod q. */ +} KBlock_secret_key; + +/** + * The private information of an RSA key pair. + * NOTE: this must match the definition in crypto_rsa.c + */ +struct GNUNET_CRYPTO_RsaPrivateKey +{ + gcry_sexp_t sexp; +}; + + +static void +mpz_randomize (gcry_mpi_t n, unsigned int nbits, GNUNET_HashCode * rnd) +{ + GNUNET_HashCode hc; + GNUNET_HashCode tmp; + int bits_per_hc = sizeof (GNUNET_HashCode) * 8; + int cnt; + int i; + + GNUNET_assert (nbits > 0); + cnt = (nbits + bits_per_hc - 1) / bits_per_hc; + gcry_mpi_set_ui (n, 0); + + tmp = *rnd; + for (i = 0; i < cnt; i++) + { + int j; + + if (i > 0) + GNUNET_CRYPTO_hash (&hc, sizeof (GNUNET_HashCode), &tmp); + for (j = 0; j < sizeof (GNUNET_HashCode) / sizeof (uint32_t); j++) + { +#if HAVE_GCRY_MPI_LSHIFT + gcry_mpi_lshift (n, n, sizeof (uint32_t) * 8); +#else + gcry_mpi_mul_ui (n, n, 1 << (sizeof (uint32_t) * 4)); + gcry_mpi_mul_ui (n, n, 1 << (sizeof (uint32_t) * 4)); +#endif + gcry_mpi_add_ui (n, n, ntohl (((uint32_t *) & tmp)[j])); + } + hc = tmp; + } + GNUNET_CRYPTO_hash (&hc, sizeof (GNUNET_HashCode), rnd); + i = gcry_mpi_get_nbits (n); + while (i > nbits) + gcry_mpi_clear_bit (n, --i); +} + +static unsigned long +mpz_trailing_zeroes (gcry_mpi_t n) +{ + unsigned int idx, cnt; + + cnt = gcry_mpi_get_nbits (n); + for (idx = 0; idx < cnt; idx++) + { + if (gcry_mpi_test_bit (n, idx) == 0) + return idx; + } + + return ULONG_MAX; +} + +static void +mpz_tdiv_q_2exp (gcry_mpi_t q, gcry_mpi_t n, unsigned int b) +{ + gcry_mpi_t u, d; + + u = gcry_mpi_set_ui (NULL, 1); + d = gcry_mpi_new (0); + gcry_mpi_mul_2exp (d, u, b); + gcry_mpi_div (q, NULL, n, d, 0); +} + +/** + * Return true if n is probably a prime + */ +static int +is_prime (gcry_mpi_t n, int steps, GNUNET_HashCode * hc) +{ + gcry_mpi_t x; + gcry_mpi_t y; + gcry_mpi_t z; + gcry_mpi_t nminus1; + gcry_mpi_t a2; + gcry_mpi_t q; + unsigned int i, j, k; + int rc = 0; + unsigned int nbits; + + x = gcry_mpi_new (0); + y = gcry_mpi_new (0); + z = gcry_mpi_new (0); + nminus1 = gcry_mpi_new (0); + a2 = gcry_mpi_set_ui (NULL, 2); + + nbits = gcry_mpi_get_nbits (n); + gcry_mpi_sub_ui (nminus1, n, 1); + + /* Find q and k, so that n = 1 + 2^k * q . */ + q = gcry_mpi_set (NULL, nminus1); + k = mpz_trailing_zeroes (q); + mpz_tdiv_q_2exp (q, q, k); + + for (i = 0; i < steps; i++) + { + if (!i) + { + gcry_mpi_set_ui (x, 2); + } + else + { + mpz_randomize (x, nbits - 1, hc); + GNUNET_assert (gcry_mpi_cmp (x, nminus1) < 0); + GNUNET_assert (gcry_mpi_cmp_ui (x, 1) > 0); + } + gcry_mpi_powm (y, x, q, n); + if (gcry_mpi_cmp_ui (y, 1) && gcry_mpi_cmp (y, nminus1)) + { + for (j = 1; j < k && gcry_mpi_cmp (y, nminus1); j++) + { + gcry_mpi_powm (y, y, a2, n); + if (!gcry_mpi_cmp_ui (y, 1)) + goto leave; /* Not a prime. */ + } + if (gcry_mpi_cmp (y, nminus1)) + goto leave; /* Not a prime. */ + } + } + rc = 1; /* May be a prime. */ + +leave: + gcry_mpi_release (x); + gcry_mpi_release (y); + gcry_mpi_release (z); + gcry_mpi_release (nminus1); + gcry_mpi_release (q); + gcry_mpi_release (a2); + + return rc; +} + +/** + * If target != size, move target bytes to the + * end of the size-sized buffer and zero out the + * first target-size bytes. + */ +static void +adjust (unsigned char *buf, size_t size, size_t target) +{ + if (size < target) + { + memmove (&buf[target - size], buf, size); + memset (buf, 0, target - size); + } +} + + +static void +gen_prime (gcry_mpi_t * ptest, unsigned int nbits, GNUNET_HashCode * hc) +{ + /* Note: 2 is not included because it can be tested more easily by + * looking at bit 0. The last entry in this list is marked by a zero */ + static const uint16_t small_prime_numbers[] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, + 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, + 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, + 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, + 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, + 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, + 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, + 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, + 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, + 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, + 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, + 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, + 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, + 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, + 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, + 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, + 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, + 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, + 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, + 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, + 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, + 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, + 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, + 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, + 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, + 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, + 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, + 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, + 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, + 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, + 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, + 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, + 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, + 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, + 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, + 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, + 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, + 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, + 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, + 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, + 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, + 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, + 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, + 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, + 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, + 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, + 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, + 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, + 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, + 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, + 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, + 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, + 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, + 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, + 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, + 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, + 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, + 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, + 4957, 4967, 4969, 4973, 4987, 4993, 4999, + 0 + }; +#define DIM(v) (sizeof(v)/sizeof((v)[0])) + static int no_of_small_prime_numbers = DIM (small_prime_numbers) - 1; + + gcry_mpi_t prime, pminus1, val_2, val_3, result; + unsigned int i; + unsigned int step; + unsigned int mods[no_of_small_prime_numbers]; + gcry_mpi_t tmp; + gcry_mpi_t sp; + + GNUNET_assert (nbits >= 16); + + /* Make nbits fit into mpz_t implementation. */ + val_2 = gcry_mpi_set_ui (NULL, 2); + val_3 = gcry_mpi_set_ui (NULL, 3); + prime = gcry_mpi_snew (0); + result = gcry_mpi_new (0); + pminus1 = gcry_mpi_new (0); + *ptest = gcry_mpi_new (0); + tmp = gcry_mpi_new (0); + sp = gcry_mpi_new (0); + while (1) + { + /* generate a random number */ + mpz_randomize (prime, nbits, hc); + /* Set high order bit to 1, set low order bit to 1. If we are + * generating a secret prime we are most probably doing that + * for RSA, to make sure that the modulus does have the + * requested key size we set the 2 high order bits. */ + gcry_mpi_set_bit (prime, nbits - 1); + gcry_mpi_set_bit (prime, nbits - 2); + gcry_mpi_set_bit (prime, 0); + + /* Calculate all remainders. */ + for (i = 0; i < no_of_small_prime_numbers; i++) + { + size_t written; + + gcry_mpi_set_ui (sp, small_prime_numbers[i]); + gcry_mpi_div (NULL, tmp, prime, sp, -1); + mods[i] = 0; + written = sizeof (unsigned int); + GNUNET_assert (0 == + gcry_mpi_print (GCRYMPI_FMT_USG, + (unsigned char *) &mods[i], written, + &written, tmp)); + adjust ((unsigned char *) &mods[i], written, sizeof (unsigned int)); + mods[i] = ntohl (mods[i]); + } + /* Now try some primes starting with prime. */ + for (step = 0; step < 20000; step += 2) + { + /* Check against all the small primes we have in mods. */ + for (i = 0; i < no_of_small_prime_numbers; i++) + { + uint16_t x = small_prime_numbers[i]; + + while (mods[i] + step >= x) + mods[i] -= x; + if (!(mods[i] + step)) + break; + } + if (i < no_of_small_prime_numbers) + continue; /* Found a multiple of an already known prime. */ + + gcry_mpi_add_ui (*ptest, prime, step); + if (!gcry_mpi_test_bit (*ptest, nbits - 2)) + break; + + /* Do a fast Fermat test now. */ + gcry_mpi_sub_ui (pminus1, *ptest, 1); + gcry_mpi_powm (result, val_2, pminus1, *ptest); + if ((!gcry_mpi_cmp_ui (result, 1)) && (is_prime (*ptest, 5, hc))) + { + /* Got it. */ + gcry_mpi_release (sp); + gcry_mpi_release (tmp); + gcry_mpi_release (val_2); + gcry_mpi_release (val_3); + gcry_mpi_release (result); + gcry_mpi_release (pminus1); + gcry_mpi_release (prime); + return; + } + } + } +} + +/** + * Generate a key pair with a key of size NBITS. + * @param sk where to store the key + * @param nbits the number of bits to use + * @param hc the HC to use for PRNG (modified!) + */ +static void +generate_kblock_key (KBlock_secret_key *sk, unsigned int nbits, + GNUNET_HashCode * hc) +{ + gcry_mpi_t t1, t2; + gcry_mpi_t phi; /* helper: (p-1)(q-1) */ + gcry_mpi_t g; + gcry_mpi_t f; + + /* make sure that nbits is even so that we generate p, q of equal size */ + if ((nbits & 1)) + nbits++; + + sk->e = gcry_mpi_set_ui (NULL, 257); + sk->n = gcry_mpi_new (0); + sk->p = gcry_mpi_new (0); + sk->q = gcry_mpi_new (0); + sk->d = gcry_mpi_new (0); + sk->u = gcry_mpi_new (0); + + t1 = gcry_mpi_new (0); + t2 = gcry_mpi_new (0); + phi = gcry_mpi_new (0); + g = gcry_mpi_new (0); + f = gcry_mpi_new (0); + + do + { + do + { + gcry_mpi_release (sk->p); + gcry_mpi_release (sk->q); + gen_prime (&sk->p, nbits / 2, hc); + gen_prime (&sk->q, nbits / 2, hc); + + if (gcry_mpi_cmp (sk->p, sk->q) > 0) /* p shall be smaller than q (for calc of u) */ + gcry_mpi_swap (sk->p, sk->q); + /* calculate the modulus */ + gcry_mpi_mul (sk->n, sk->p, sk->q); + } + while (gcry_mpi_get_nbits (sk->n) != nbits); + + /* calculate Euler totient: phi = (p-1)(q-1) */ + gcry_mpi_sub_ui (t1, sk->p, 1); + gcry_mpi_sub_ui (t2, sk->q, 1); + gcry_mpi_mul (phi, t1, t2); + gcry_mpi_gcd (g, t1, t2); + gcry_mpi_div (f, NULL, phi, g, 0); + while (0 == gcry_mpi_gcd (t1, sk->e, phi)) + { /* (while gcd is not 1) */ + gcry_mpi_add_ui (sk->e, sk->e, 2); + } + + /* calculate the secret key d = e^1 mod phi */ + } + while ((0 == gcry_mpi_invm (sk->d, sk->e, f)) || + (0 == gcry_mpi_invm (sk->u, sk->p, sk->q))); + + gcry_mpi_release (t1); + gcry_mpi_release (t2); + gcry_mpi_release (phi); + gcry_mpi_release (f); + gcry_mpi_release (g); +} + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Internal representation of the private key. + */ +struct KskRsaPrivateKeyBinaryEncoded +{ + /** + * Total size of the structure, in bytes, in big-endian! + */ + uint16_t len GNUNET_PACKED; + uint16_t sizen GNUNET_PACKED; /* in big-endian! */ + uint16_t sizee GNUNET_PACKED; /* in big-endian! */ + uint16_t sized GNUNET_PACKED; /* in big-endian! */ + uint16_t sizep GNUNET_PACKED; /* in big-endian! */ + uint16_t sizeq GNUNET_PACKED; /* in big-endian! */ + uint16_t sizedmp1 GNUNET_PACKED; /* in big-endian! */ + uint16_t sizedmq1 GNUNET_PACKED; /* in big-endian! */ + /* followed by the actual values */ +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Deterministically (!) create a hostkey using only the + * given HashCode as input to the PRNG. + */ +static struct KskRsaPrivateKeyBinaryEncoded * +makeKblockKeyInternal (const GNUNET_HashCode * hc) +{ + KBlock_secret_key sk; + GNUNET_HashCode hx; + unsigned char *pbu[6]; + gcry_mpi_t *pkv[6]; + size_t sizes[6]; + struct KskRsaPrivateKeyBinaryEncoded *retval; + int i; + size_t size; + + hx = *hc; + generate_kblock_key (&sk, 1024, /* at least 10x as fast than 2048 bits + * -- we simply cannot afford 2048 bits + * even on modern hardware, and especially + * not since clearly a dictionary attack + * will still be much cheaper + * than breaking a 1024 bit RSA key. + * If an adversary can spend the time to + * break a 1024 bit RSA key just to forge + * a signature -- SO BE IT. [ CG, 6/2005 ] */ + &hx); + pkv[0] = &sk.n; + pkv[1] = &sk.e; + pkv[2] = &sk.d; + pkv[3] = &sk.p; + pkv[4] = &sk.q; + pkv[5] = &sk.u; + size = sizeof (struct KskRsaPrivateKeyBinaryEncoded); + for (i = 0; i < 6; i++) + { + gcry_mpi_aprint (GCRYMPI_FMT_STD, &pbu[i], &sizes[i], *pkv[i]); + size += sizes[i]; + } + GNUNET_assert (size < 65536); + retval = GNUNET_malloc (size); + retval->len = htons (size); + i = 0; + retval->sizen = htons (sizes[0]); + memcpy (&((char *) &retval[1])[i], pbu[0], sizes[0]); + i += sizes[0]; + retval->sizee = htons (sizes[1]); + memcpy (&((char *) &retval[1])[i], pbu[1], sizes[1]); + i += sizes[1]; + retval->sized = htons (sizes[2]); + memcpy (&((char *) &retval[1])[i], pbu[2], sizes[2]); + i += sizes[2]; + /* swap p and q! */ + retval->sizep = htons (sizes[4]); + memcpy (&((char *) &retval[1])[i], pbu[4], sizes[4]); + i += sizes[4]; + retval->sizeq = htons (sizes[3]); + memcpy (&((char *) &retval[1])[i], pbu[3], sizes[3]); + i += sizes[3]; + retval->sizedmp1 = htons (0); + retval->sizedmq1 = htons (0); + memcpy (&((char *) &retval[1])[i], pbu[5], sizes[5]); + for (i = 0; i < 6; i++) + { + gcry_mpi_release (*pkv[i]); + free (pbu[i]); + } + return retval; +} + + +/** + * Decode the internal format into the format used + * by libgcrypt. + */ +static struct GNUNET_CRYPTO_RsaPrivateKey * +ksk_decode_key (const struct KskRsaPrivateKeyBinaryEncoded *encoding) +{ + struct GNUNET_CRYPTO_RsaPrivateKey *ret; + gcry_sexp_t res; + gcry_mpi_t n, e, d, p, q, u; + int rc; + size_t size; + int pos; + + pos = 0; + size = ntohs (encoding->sizen); + rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + pos += ntohs (encoding->sizen); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + return NULL; + } + size = ntohs (encoding->sizee); + rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + pos += ntohs (encoding->sizee); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + return NULL; + } + size = ntohs (encoding->sized); + rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + pos += ntohs (encoding->sized); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + gcry_mpi_release (e); + return NULL; + } + /* swap p and q! */ + size = ntohs (encoding->sizep); + if (size > 0) + { + rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + pos += ntohs (encoding->sizep); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + gcry_mpi_release (e); + gcry_mpi_release (d); + return NULL; + } + } + else + q = NULL; + size = ntohs (encoding->sizeq); + if (size > 0) + { + rc = gcry_mpi_scan (&p, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + pos += ntohs (encoding->sizeq); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + gcry_mpi_release (e); + gcry_mpi_release (d); + if (q != NULL) + gcry_mpi_release (q); + return NULL; + } + } + else + p = NULL; + pos += ntohs (encoding->sizedmp1); + pos += ntohs (encoding->sizedmq1); + size = + ntohs (encoding->len) - sizeof (struct KskRsaPrivateKeyBinaryEncoded) - + pos; + if (size > 0) + { + rc = gcry_mpi_scan (&u, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + gcry_mpi_release (e); + gcry_mpi_release (d); + if (p != NULL) + gcry_mpi_release (p); + if (q != NULL) + gcry_mpi_release (q); + return NULL; + } + } + else + u = NULL; + + if ((p != NULL) && (q != NULL) && (u != NULL)) + { + rc = gcry_sexp_build (&res, &size, /* erroff */ + "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)(u %m)))", + n, e, d, p, q, u); + } + else + { + if ((p != NULL) && (q != NULL)) + { + rc = gcry_sexp_build (&res, &size, /* erroff */ + "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)))", + n, e, d, p, q); + } + else + { + rc = gcry_sexp_build (&res, &size, /* erroff */ + "(private-key(rsa(n %m)(e %m)(d %m)))", n, e, d); + } + } + gcry_mpi_release (n); + gcry_mpi_release (e); + gcry_mpi_release (d); + if (p != NULL) + gcry_mpi_release (p); + if (q != NULL) + gcry_mpi_release (q); + if (u != NULL) + gcry_mpi_release (u); + + if (rc) + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); +#if EXTRA_CHECKS + if (gcry_pk_testkey (res)) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); + return NULL; + } +#endif + ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey)); + ret->sexp = res; + return ret; +} + + +struct KBlockKeyCacheLine +{ + GNUNET_HashCode hc; + struct KskRsaPrivateKeyBinaryEncoded *pke; +}; + +static struct KBlockKeyCacheLine **cache; + +static unsigned int cacheSize; + +/** + * Deterministically (!) create a hostkey using only the + * given HashCode as input to the PRNG. + */ +struct GNUNET_CRYPTO_RsaPrivateKey * +GNUNET_CRYPTO_rsa_key_create_from_hash (const GNUNET_HashCode * hc) +{ + struct GNUNET_CRYPTO_RsaPrivateKey *ret; + struct KBlockKeyCacheLine *line; + unsigned int i; + + for (i = 0; i < cacheSize; i++) + { + if (0 == memcmp (hc, &cache[i]->hc, sizeof (GNUNET_HashCode))) + { + ret = ksk_decode_key (cache[i]->pke); + return ret; + } + } + + line = GNUNET_malloc (sizeof (struct KBlockKeyCacheLine)); + line->hc = *hc; + line->pke = makeKblockKeyInternal (hc); + GNUNET_array_grow (cache, cacheSize, cacheSize + 1); + cache[cacheSize - 1] = line; + return ksk_decode_key (line->pke); +} + + +void __attribute__ ((destructor)) GNUNET_CRYPTO_ksk_fini () +{ + unsigned int i; + + for (i = 0; i < cacheSize; i++) + { + GNUNET_free (cache[i]->pke); + GNUNET_free (cache[i]); + } + GNUNET_array_grow (cache, cacheSize, 0); +} + + +/* end of crypto_ksk.c */ diff --git a/src/util/crypto_random.c b/src/util/crypto_random.c new file mode 100644 index 0000000..25226a3 --- /dev/null +++ b/src/util/crypto_random.c @@ -0,0 +1,334 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +/** + * @file util/crypto_random.c + * @brief functions to gather random numbers + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_os_lib.h" +#include + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +/* TODO: ndurner, move this to plibc? */ +/* The code is derived from glibc, obviously */ +#if MINGW +#ifdef RANDOM +#undef RANDOM +#endif +#ifdef SRANDOM +#undef SRANDOM +#endif +#define RANDOM() glibc_weak_rand32() +#define SRANDOM(s) glibc_weak_srand32(s) +static int32_t glibc_weak_rand32_state = 1; + +void +glibc_weak_srand32 (int32_t s) +{ + glibc_weak_rand32_state = s; +} + +int32_t +glibc_weak_rand32 () +{ + int32_t val = glibc_weak_rand32_state; + + val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff; + glibc_weak_rand32_state = val; + return val; +} +#endif + +/** + * Create a cryptographically weak pseudo-random number in the interval of 0 to 1. + * + * @return number between 0 and 1. + */ +static double +weak_random () +{ + return ((double) RANDOM () / RAND_MAX); +} + +/** + * Seed a weak random generator. Only GNUNET_CRYPTO_QUALITY_WEAK-mode generator + * can be seeded. + * + * @param seed the seed to use + */ +void +GNUNET_CRYPTO_seed_weak_random (int32_t seed) +{ + SRANDOM (seed); +} + +/** + * Produce a random value. + * + * @param mode desired quality of the random number + * @param i the upper limit (exclusive) for the random number + * @return a random value in the interval [0,i[. + */ +uint32_t +GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, uint32_t i) +{ +#ifdef gcry_fast_random_poll + static unsigned int invokeCount; +#endif + uint32_t ret; + uint32_t ul; + + GNUNET_assert (i > 0); + + switch (mode) + { + case GNUNET_CRYPTO_QUALITY_STRONG: + /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */ +#ifdef gcry_fast_random_poll + if ((invokeCount++ % 256) == 0) + gcry_fast_random_poll (); +#endif + ul = UINT32_MAX - (UINT32_MAX % i); + do + { + gcry_randomize ((unsigned char *) &ret, sizeof (uint32_t), + GCRY_STRONG_RANDOM); + } + while (ret >= ul); + return ret % i; + case GNUNET_CRYPTO_QUALITY_NONCE: + ul = UINT32_MAX - (UINT32_MAX % i); + do + { + gcry_create_nonce (&ret, sizeof (ret)); + } + while (ret >= ul); + return ret % i; + case GNUNET_CRYPTO_QUALITY_WEAK: + ret = i * weak_random (); + if (ret >= i) + ret = i - 1; + return ret; + default: + GNUNET_assert (0); + } + return 0; +} + + +/** + * Get an array with a random permutation of the + * numbers 0...n-1. + * @param mode GNUNET_RANDOM_QUALITY_STRONG if the strong (but expensive) + * PRNG should be used, GNUNET_RANDOM_QUALITY_WEAK otherwise + * @param n the size of the array + * @return the permutation array (allocated from heap) + */ +unsigned int * +GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode, unsigned int n) +{ + unsigned int *ret; + unsigned int i; + unsigned int tmp; + uint32_t x; + + GNUNET_assert (n > 0); + ret = GNUNET_malloc (n * sizeof (unsigned int)); + for (i = 0; i < n; i++) + ret[i] = i; + for (i = n - 1; i > 0; i--) + { + x = GNUNET_CRYPTO_random_u32 (mode, i + 1); + tmp = ret[x]; + ret[x] = ret[i]; + ret[i] = tmp; + } + return ret; +} + +/** + * Random on unsigned 64-bit values. + * + * + * @param mode desired quality of the random number + * @param max value returned will be in range [0,max) (exclusive) + * @return random 64-bit number + */ +uint64_t +GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max) +{ + uint64_t ret; + uint64_t ul; + + GNUNET_assert (max > 0); + switch (mode) + { + case GNUNET_CRYPTO_QUALITY_STRONG: + ul = UINT64_MAX - (UINT64_MAX % max); + do + { + gcry_randomize ((unsigned char *) &ret, sizeof (uint64_t), + GCRY_STRONG_RANDOM); + } + while (ret >= ul); + return ret % max; + case GNUNET_CRYPTO_QUALITY_NONCE: + ul = UINT64_MAX - (UINT64_MAX % max); + do + { + gcry_create_nonce (&ret, sizeof (ret)); + } + while (ret >= ul); + + return ret % max; + case GNUNET_CRYPTO_QUALITY_WEAK: + ret = max * weak_random (); + if (ret >= max) + ret = max - 1; + return ret; + default: + GNUNET_assert (0); + } + return 0; +} + +/** + * This function should only be called in testcases + * where strong entropy gathering is not desired + * (for example, for hostkey generation). + */ +void +GNUNET_CRYPTO_random_disable_entropy_gathering () +{ + gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); +} + + +/** + * Process ID of the "find" process that we use for + * entropy gathering. + */ +static struct GNUNET_OS_Process *genproc; + +/** + * Function called by libgcrypt whenever we are + * blocked gathering entropy. + */ +static void +entropy_generator (void *cls, const char *what, int printchar, int current, + int total) +{ + unsigned long code; + enum GNUNET_OS_ProcessStatusType type; + int ret; + + if (0 != strcmp (what, "need_entropy")) + return; + if (current == total) + { + if (genproc != NULL) + { + if (0 != GNUNET_OS_process_kill (genproc, SIGTERM)) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill"); + GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc)); + GNUNET_OS_process_close (genproc); + genproc = NULL; + } + return; + } + if (genproc != NULL) + { + ret = GNUNET_OS_process_status (genproc, &type, &code); + if (ret == GNUNET_NO) + return; /* still running */ + if (ret == GNUNET_SYSERR) + { + GNUNET_break (0); + return; + } + if (0 != GNUNET_OS_process_kill (genproc, SIGTERM)) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill"); + GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc)); + GNUNET_OS_process_close (genproc); + genproc = NULL; + } + LOG (GNUNET_ERROR_TYPE_INFO, _("Starting `%s' process to generate entropy\n"), + "find"); + genproc = + GNUNET_OS_start_process (GNUNET_NO, + NULL, NULL, "sh", "sh", "-c", + "exec find / -mount -type f -exec cp {} /dev/null \\; 2>/dev/null", + NULL); +} + + +static void +killfind () +{ + if (genproc != NULL) + { + GNUNET_OS_process_kill (genproc, SIGKILL); + GNUNET_OS_process_close (genproc); + genproc = NULL; + } +} + + +void __attribute__ ((constructor)) GNUNET_CRYPTO_random_init () +{ + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); + if (!gcry_check_version (GCRYPT_VERSION)) + { + FPRINTF (stderr, + _ + ("libgcrypt has not the expected version (version %s is required).\n"), + GCRYPT_VERSION); + GNUNET_abort (); + } +#ifdef GCRYCTL_INITIALIZATION_FINISHED + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); +#endif +#ifdef gcry_fast_random_poll + gcry_fast_random_poll (); +#endif + gcry_set_progress_handler (&entropy_generator, NULL); + atexit (&killfind); + GNUNET_CRYPTO_seed_weak_random (time (NULL) ^ + GNUNET_CRYPTO_random_u32 + (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX)); +} + + +void __attribute__ ((destructor)) GNUNET_CRYPTO_random_fini () +{ + gcry_set_progress_handler (NULL, NULL); +} + + + +/* end of crypto_random.c */ diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c new file mode 100644 index 0000000..418fe83 --- /dev/null +++ b/src/util/crypto_rsa.c @@ -0,0 +1,967 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/crypto_rsa.c + * @brief public key cryptography (RSA) with libgcrypt + * @author Christian Grothoff + * + * Note that the code locks often needlessly on the gcrypt-locking api. + * One would think that simple MPI operations should not require locking + * (since only global operations on the random pool must be locked, + * strictly speaking). But libgcrypt does sometimes require locking in + * unexpected places, so the safe solution is to always lock even if it + * is not required. The performance impact is minimal anyway. + */ + +#include "platform.h" +#include +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_disk_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +/** + * The private information of an RSA key pair. + * NOTE: this must match the definition in crypto_ksk.c + */ +struct GNUNET_CRYPTO_RsaPrivateKey +{ + gcry_sexp_t sexp; +}; + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * GNUnet mandates a certain format for the encoding + * of private RSA key information that is provided + * by the RSA implementations. This format is used + * to serialize a private RSA key (typically when + * writing it to disk). + */ +struct RsaPrivateKeyBinaryEncoded +{ + /** + * Total size of the structure, in bytes, in big-endian! + */ + uint16_t len GNUNET_PACKED; + uint16_t sizen GNUNET_PACKED; /* in big-endian! */ + uint16_t sizee GNUNET_PACKED; /* in big-endian! */ + uint16_t sized GNUNET_PACKED; /* in big-endian! */ + uint16_t sizep GNUNET_PACKED; /* in big-endian! */ + uint16_t sizeq GNUNET_PACKED; /* in big-endian! */ + uint16_t sizedmp1 GNUNET_PACKED; /* in big-endian! */ + uint16_t sizedmq1 GNUNET_PACKED; /* in big-endian! */ + /* followed by the actual values */ +}; +GNUNET_NETWORK_STRUCT_END + +#define HOSTKEY_LEN 2048 + +#define EXTRA_CHECKS ALLOW_EXTRA_CHECKS + + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' with the message given + * by gcry_strerror(rc). + */ +#define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0); + +/** + * If target != size, move target bytes to the + * end of the size-sized buffer and zero out the + * first target-size bytes. + */ +static void +adjust (unsigned char *buf, size_t size, size_t target) +{ + if (size < target) + { + memmove (&buf[target - size], buf, size); + memset (buf, 0, target - size); + } +} + +/** + * This HostKey implementation uses RSA. + */ +struct GNUNET_CRYPTO_RsaPrivateKey * +GNUNET_CRYPTO_rsa_key_create () +{ + struct GNUNET_CRYPTO_RsaPrivateKey *ret; + gcry_sexp_t s_key; + gcry_sexp_t s_keyparam; + + GNUNET_assert (0 == + gcry_sexp_build (&s_keyparam, NULL, + "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))", + HOSTKEY_LEN)); + GNUNET_assert (0 == gcry_pk_genkey (&s_key, s_keyparam)); + gcry_sexp_release (s_keyparam); +#if EXTRA_CHECKS + GNUNET_assert (0 == gcry_pk_testkey (s_key)); +#endif + ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey)); + ret->sexp = s_key; + return ret; +} + +/** + * Free memory occupied by hostkey + */ +void +GNUNET_CRYPTO_rsa_key_free (struct GNUNET_CRYPTO_RsaPrivateKey *hostkey) +{ + gcry_sexp_release (hostkey->sexp); + GNUNET_free (hostkey); +} + +static int +key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname, + const char *elems) +{ + gcry_sexp_t list, l2; + const char *s; + int i, idx; + + list = gcry_sexp_find_token (sexp, topname, 0); + if (!list) + { + return 1; + } + l2 = gcry_sexp_cadr (list); + gcry_sexp_release (list); + list = l2; + if (!list) + { + return 2; + } + + idx = 0; + for (s = elems; *s; s++, idx++) + { + l2 = gcry_sexp_find_token (list, s, 1); + if (!l2) + { + for (i = 0; i < idx; i++) + { + gcry_free (array[i]); + array[i] = NULL; + } + gcry_sexp_release (list); + return 3; /* required parameter not found */ + } + array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l2); + if (!array[idx]) + { + for (i = 0; i < idx; i++) + { + gcry_free (array[i]); + array[i] = NULL; + } + gcry_sexp_release (list); + return 4; /* required parameter is invalid */ + } + } + gcry_sexp_release (list); + return 0; +} + +/** + * Extract the public key of the host. + * @param priv the private key + * @param pub where to write the public key + */ +void +GNUNET_CRYPTO_rsa_key_get_public (const struct GNUNET_CRYPTO_RsaPrivateKey + *priv, + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *pub) +{ + gcry_mpi_t skey[2]; + size_t size; + int rc; + + rc = key_from_sexp (skey, priv->sexp, "public-key", "ne"); + if (rc) + rc = key_from_sexp (skey, priv->sexp, "private-key", "ne"); + if (rc) + rc = key_from_sexp (skey, priv->sexp, "rsa", "ne"); + GNUNET_assert (0 == rc); + pub->len = + htons (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) - + sizeof (pub->padding)); + pub->sizen = htons (GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH); + pub->padding = 0; + size = GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH; + GNUNET_assert (0 == + gcry_mpi_print (GCRYMPI_FMT_USG, &pub->key[0], size, &size, + skey[0])); + adjust (&pub->key[0], size, GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH); + size = GNUNET_CRYPTO_RSA_KEY_LENGTH - GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH; + GNUNET_assert (0 == + gcry_mpi_print (GCRYMPI_FMT_USG, + &pub->key + [GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH], size, + &size, skey[1])); + adjust (&pub->key[GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH], size, + GNUNET_CRYPTO_RSA_KEY_LENGTH - + GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH); + gcry_mpi_release (skey[0]); + gcry_mpi_release (skey[1]); +} + + +/** + * Internal: publicKey => RSA-Key. + * + * Note that the return type is not actually a private + * key but rather an sexpression for the public key! + */ +static struct GNUNET_CRYPTO_RsaPrivateKey * +public2PrivateKey (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *publicKey) +{ + struct GNUNET_CRYPTO_RsaPrivateKey *ret; + gcry_sexp_t result; + gcry_mpi_t n; + gcry_mpi_t e; + size_t size; + size_t erroff; + int rc; + + if ((ntohs (publicKey->sizen) != GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH) || + (ntohs (publicKey->len) != + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) - + sizeof (publicKey->padding))) + { + GNUNET_break (0); + return NULL; + } + size = GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH; + rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, &publicKey->key[0], size, &size); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + return NULL; + } + size = GNUNET_CRYPTO_RSA_KEY_LENGTH - GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH; + rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG, + &publicKey->key[GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH], + size, &size); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + return NULL; + } + rc = gcry_sexp_build (&result, &erroff, "(public-key(rsa(n %m)(e %m)))", n, + e); + gcry_mpi_release (n); + gcry_mpi_release (e); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */ + return NULL; + } + ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey)); + ret->sexp = result; + return ret; +} + + +/** + * Encode the private key in a format suitable for + * storing it into a file. + * @returns encoding of the private key. + * The first 4 bytes give the size of the array, as usual. + */ +static struct RsaPrivateKeyBinaryEncoded * +rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey) +{ + struct RsaPrivateKeyBinaryEncoded *retval; + gcry_mpi_t pkv[6]; + void *pbu[6]; + size_t sizes[6]; + int rc; + int i; + int size; + +#if EXTRA_CHECKS + if (gcry_pk_testkey (hostkey->sexp)) + { + GNUNET_break (0); + return NULL; + } +#endif + + memset (pkv, 0, sizeof (gcry_mpi_t) * 6); + rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpqu"); + if (rc) + rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpqu"); + if (rc) + rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpq"); + if (rc) + rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpq"); + if (rc) + rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "ned"); + if (rc) + rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "ned"); + GNUNET_assert (0 == rc); + size = sizeof (struct RsaPrivateKeyBinaryEncoded); + for (i = 0; i < 6; i++) + { + if (pkv[i] != NULL) + { + GNUNET_assert (0 == + gcry_mpi_aprint (GCRYMPI_FMT_USG, + (unsigned char **) &pbu[i], &sizes[i], + pkv[i])); + size += sizes[i]; + } + else + { + pbu[i] = NULL; + sizes[i] = 0; + } + } + GNUNET_assert (size < 65536); + retval = GNUNET_malloc (size); + retval->len = htons (size); + i = 0; + retval->sizen = htons (sizes[0]); + memcpy (&((char *) (&retval[1]))[i], pbu[0], sizes[0]); + i += sizes[0]; + retval->sizee = htons (sizes[1]); + memcpy (&((char *) (&retval[1]))[i], pbu[1], sizes[1]); + i += sizes[1]; + retval->sized = htons (sizes[2]); + memcpy (&((char *) (&retval[1]))[i], pbu[2], sizes[2]); + i += sizes[2]; + /* swap p and q! */ + retval->sizep = htons (sizes[4]); + memcpy (&((char *) (&retval[1]))[i], pbu[4], sizes[4]); + i += sizes[4]; + retval->sizeq = htons (sizes[3]); + memcpy (&((char *) (&retval[1]))[i], pbu[3], sizes[3]); + i += sizes[3]; + retval->sizedmp1 = htons (0); + retval->sizedmq1 = htons (0); + memcpy (&((char *) (&retval[1]))[i], pbu[5], sizes[5]); + for (i = 0; i < 6; i++) + { + if (pkv[i] != NULL) + gcry_mpi_release (pkv[i]); + if (pbu[i] != NULL) + free (pbu[i]); + } + return retval; +} + +/** + * Decode the private key from the file-format back + * to the "normal", internal format. + * + * @param buf the buffer where the private key data is stored + * @param len the length of the data in 'buffer' + */ +struct GNUNET_CRYPTO_RsaPrivateKey * +GNUNET_CRYPTO_rsa_decode_key (const char *buf, uint16_t len) +{ + struct GNUNET_CRYPTO_RsaPrivateKey *ret; + const struct RsaPrivateKeyBinaryEncoded *encoding = + (const struct RsaPrivateKeyBinaryEncoded *) buf; + gcry_sexp_t res; + gcry_mpi_t n, e, d, p, q, u; + int rc; + size_t size; + int pos; + uint16_t enc_len; + + enc_len = ntohs (encoding->len); + if (len != enc_len) + return NULL; + + pos = 0; + size = ntohs (encoding->sizen); + rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + pos += ntohs (encoding->sizen); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + return NULL; + } + size = ntohs (encoding->sizee); + rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + pos += ntohs (encoding->sizee); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + return NULL; + } + size = ntohs (encoding->sized); + rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + pos += ntohs (encoding->sized); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + gcry_mpi_release (e); + return NULL; + } + /* swap p and q! */ + size = ntohs (encoding->sizep); + if (size > 0) + { + rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + pos += ntohs (encoding->sizep); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + gcry_mpi_release (e); + gcry_mpi_release (d); + return NULL; + } + } + else + q = NULL; + size = ntohs (encoding->sizeq); + if (size > 0) + { + rc = gcry_mpi_scan (&p, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + pos += ntohs (encoding->sizeq); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + gcry_mpi_release (e); + gcry_mpi_release (d); + if (q != NULL) + gcry_mpi_release (q); + return NULL; + } + } + else + p = NULL; + pos += ntohs (encoding->sizedmp1); + pos += ntohs (encoding->sizedmq1); + size = + ntohs (encoding->len) - sizeof (struct RsaPrivateKeyBinaryEncoded) - pos; + if (size > 0) + { + rc = gcry_mpi_scan (&u, GCRYMPI_FMT_USG, + &((const unsigned char *) (&encoding[1]))[pos], size, + &size); + if (rc) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (n); + gcry_mpi_release (e); + gcry_mpi_release (d); + if (p != NULL) + gcry_mpi_release (p); + if (q != NULL) + gcry_mpi_release (q); + return NULL; + } + } + else + u = NULL; + + if ((p != NULL) && (q != NULL) && (u != NULL)) + { + rc = gcry_sexp_build (&res, &size, /* erroff */ + "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)(u %m)))", + n, e, d, p, q, u); + } + else + { + if ((p != NULL) && (q != NULL)) + { + rc = gcry_sexp_build (&res, &size, /* erroff */ + "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)))", + n, e, d, p, q); + } + else + { + rc = gcry_sexp_build (&res, &size, /* erroff */ + "(private-key(rsa(n %m)(e %m)(d %m)))", n, e, d); + } + } + gcry_mpi_release (n); + gcry_mpi_release (e); + gcry_mpi_release (d); + if (p != NULL) + gcry_mpi_release (p); + if (q != NULL) + gcry_mpi_release (q); + if (u != NULL) + gcry_mpi_release (u); + + if (rc) + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); +#if EXTRA_CHECKS + if (gcry_pk_testkey (res)) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); + return NULL; + } +#endif + ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey)); + ret->sexp = res; + return ret; +} + + +/** + * Create a new private key by reading it from a file. If the + * files does not exist, create a new key and write it to the + * file. Caller must free return value. Note that this function + * can not guarantee that another process might not be trying + * the same operation on the same file at the same time. + * If the contents of the file + * are invalid the old file is deleted and a fresh key is + * created. + * + * @return new private key, NULL on error (for example, + * permission denied) + */ +struct GNUNET_CRYPTO_RsaPrivateKey * +GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) +{ + struct GNUNET_CRYPTO_RsaPrivateKey *ret; + struct RsaPrivateKeyBinaryEncoded *enc; + uint16_t len; + struct GNUNET_DISK_FileHandle *fd; + unsigned int cnt; + int ec; + uint64_t fs; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; + struct GNUNET_PeerIdentity pid; + + if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) + return NULL; + while (GNUNET_YES != GNUNET_DISK_file_test (filename)) + { + fd = GNUNET_DISK_file_open (filename, + GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE + | GNUNET_DISK_OPEN_FAILIFEXISTS, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (NULL == fd) + { + if (errno == EEXIST) + { + if (GNUNET_YES != GNUNET_DISK_file_test (filename)) + { + /* must exist but not be accessible, fail for good! */ + if (0 != ACCESS (filename, R_OK)) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename); + else + GNUNET_break (0); /* what is going on!? */ + return NULL; + } + continue; + } + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename); + return NULL; + } + cnt = 0; + + while (GNUNET_YES != + GNUNET_DISK_file_lock (fd, 0, + sizeof (struct RsaPrivateKeyBinaryEncoded), + GNUNET_YES)) + { + sleep (1); + if (0 == ++cnt % 10) + { + ec = errno; + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Could not aquire lock on file `%s': %s...\n"), filename, + STRERROR (ec)); + } + } + LOG (GNUNET_ERROR_TYPE_INFO, + _("Creating a new private key. This may take a while.\n")); + ret = GNUNET_CRYPTO_rsa_key_create (); + GNUNET_assert (ret != NULL); + enc = rsa_encode_key (ret); + GNUNET_assert (enc != NULL); + GNUNET_assert (ntohs (enc->len) == + GNUNET_DISK_file_write (fd, enc, ntohs (enc->len))); + GNUNET_free (enc); + + GNUNET_DISK_file_sync (fd); + if (GNUNET_YES != + GNUNET_DISK_file_unlock (fd, 0, + sizeof (struct RsaPrivateKeyBinaryEncoded))) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); + GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); + GNUNET_CRYPTO_rsa_key_get_public (ret, &pub); + GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey); + LOG (GNUNET_ERROR_TYPE_INFO, + _("I am host `%s'. Stored new private key in `%s'.\n"), + GNUNET_i2s (&pid), filename); + return ret; + } + /* hostkey file exists already, read it! */ + fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fd) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename); + return NULL; + } + cnt = 0; + while (1) + { + if (GNUNET_YES != + GNUNET_DISK_file_lock (fd, 0, + sizeof (struct RsaPrivateKeyBinaryEncoded), + GNUNET_NO)) + { + if (0 == ++cnt % 60) + { + ec = errno; + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Could not aquire lock on file `%s': %s...\n"), filename, + STRERROR (ec)); + LOG (GNUNET_ERROR_TYPE_ERROR, + _ + ("This may be ok if someone is currently generating a hostkey.\n")); + } + sleep (1); + continue; + } + if (GNUNET_YES != GNUNET_DISK_file_test (filename)) + { + /* eh, what!? File we opened is now gone!? */ + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename); + if (GNUNET_YES != + GNUNET_DISK_file_unlock (fd, 0, + sizeof (struct RsaPrivateKeyBinaryEncoded))) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); + + return NULL; + } + if (GNUNET_YES != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES)) + fs = 0; + if (fs < sizeof (struct RsaPrivateKeyBinaryEncoded)) + { + /* maybe we got the read lock before the hostkey generating + * process had a chance to get the write lock; give it up! */ + if (GNUNET_YES != + GNUNET_DISK_file_unlock (fd, 0, + sizeof (struct RsaPrivateKeyBinaryEncoded))) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); + if (0 == ++cnt % 10) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _ + ("When trying to read hostkey file `%s' I found %u bytes but I need at least %u.\n"), + filename, (unsigned int) fs, + (unsigned int) sizeof (struct RsaPrivateKeyBinaryEncoded)); + LOG (GNUNET_ERROR_TYPE_ERROR, + _ + ("This may be ok if someone is currently generating a hostkey.\n")); + } + sleep (2); /* wait a bit longer! */ + continue; + } + break; + } + enc = GNUNET_malloc (fs); + GNUNET_assert (fs == GNUNET_DISK_file_read (fd, enc, fs)); + len = ntohs (enc->len); + ret = NULL; + if ((len != fs) || + (NULL == (ret = GNUNET_CRYPTO_rsa_decode_key ((char *) enc, len)))) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("File `%s' does not contain a valid private key. Deleting it.\n"), + filename); + if (0 != UNLINK (filename)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); + } + } + GNUNET_free (enc); + if (GNUNET_YES != + GNUNET_DISK_file_unlock (fd, 0, + sizeof (struct RsaPrivateKeyBinaryEncoded))) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); + GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); + if (ret != NULL) + { + GNUNET_CRYPTO_rsa_key_get_public (ret, &pub); + GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey); + LOG (GNUNET_ERROR_TYPE_INFO, + _("I am host `%s'. Read private key from `%s'.\n"), GNUNET_i2s (&pid), + filename); + } + return ret; +} + + +/** + * Encrypt a block with the public key of another host that uses the + * same cipher. + * + * @param block the block to encrypt + * @param size the size of block + * @param publicKey the encoded public key used to encrypt + * @param target where to store the encrypted block + * @returns GNUNET_SYSERR on error, GNUNET_OK if ok + */ +int +GNUNET_CRYPTO_rsa_encrypt (const void *block, size_t size, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *publicKey, + struct GNUNET_CRYPTO_RsaEncryptedData *target) +{ + gcry_sexp_t result; + gcry_sexp_t data; + struct GNUNET_CRYPTO_RsaPrivateKey *pubkey; + gcry_mpi_t val; + gcry_mpi_t rval; + size_t isize; + size_t erroff; + + GNUNET_assert (size <= sizeof (GNUNET_HashCode)); + pubkey = public2PrivateKey (publicKey); + if (pubkey == NULL) + return GNUNET_SYSERR; + isize = size; + GNUNET_assert (0 == + gcry_mpi_scan (&val, GCRYMPI_FMT_USG, block, isize, &isize)); + GNUNET_assert (0 == + gcry_sexp_build (&data, &erroff, + "(data (flags pkcs1)(value %m))", val)); + gcry_mpi_release (val); + GNUNET_assert (0 == gcry_pk_encrypt (&result, data, pubkey->sexp)); + gcry_sexp_release (data); + GNUNET_CRYPTO_rsa_key_free (pubkey); + + GNUNET_assert (0 == key_from_sexp (&rval, result, "rsa", "a")); + gcry_sexp_release (result); + isize = sizeof (struct GNUNET_CRYPTO_RsaEncryptedData); + GNUNET_assert (0 == + gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) target, + isize, &isize, rval)); + gcry_mpi_release (rval); + adjust (&target->encoding[0], isize, + sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); + return GNUNET_OK; +} + +/** + * Decrypt a given block with the hostkey. + * + * @param key the key with which to decrypt this block + * @param block the data to decrypt, encoded as returned by encrypt + * @param result pointer to a location where the result can be stored + * @param max the maximum number of bits to store for the result, if + * the decrypted block is bigger, an error is returned + * @return the size of the decrypted block, -1 on error + */ +ssize_t +GNUNET_CRYPTO_rsa_decrypt (const struct GNUNET_CRYPTO_RsaPrivateKey * key, + const struct GNUNET_CRYPTO_RsaEncryptedData * block, + void *result, size_t max) +{ + gcry_sexp_t resultsexp; + gcry_sexp_t data; + size_t erroff; + size_t size; + gcry_mpi_t val; + unsigned char *endp; + unsigned char *tmp; + +#if EXTRA_CHECKS + GNUNET_assert (0 == gcry_pk_testkey (key->sexp)); +#endif + size = sizeof (struct GNUNET_CRYPTO_RsaEncryptedData); + GNUNET_assert (0 == + gcry_mpi_scan (&val, GCRYMPI_FMT_USG, &block->encoding[0], + size, &size)); + GNUNET_assert (0 == + gcry_sexp_build (&data, &erroff, "(enc-val(flags)(rsa(a %m)))", + val)); + gcry_mpi_release (val); + GNUNET_assert (0 == gcry_pk_decrypt (&resultsexp, data, key->sexp)); + gcry_sexp_release (data); + /* resultsexp has format "(value %m)" */ + GNUNET_assert (NULL != + (val = gcry_sexp_nth_mpi (resultsexp, 1, GCRYMPI_FMT_USG))); + gcry_sexp_release (resultsexp); + tmp = GNUNET_malloc (max + HOSTKEY_LEN / 8); + size = max + HOSTKEY_LEN / 8; + GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, tmp, size, &size, val)); + gcry_mpi_release (val); + endp = tmp; + endp += (size - max); + size = max; + memcpy (result, endp, size); + GNUNET_free (tmp); + return size; +} + + +/** + * Sign a given block. + * + * @param key private key to use for the signing + * @param purpose what to sign (size, purpose) + * @param sig where to write the signature + * @return GNUNET_SYSERR on error, GNUNET_OK on success + */ +int +GNUNET_CRYPTO_rsa_sign (const struct GNUNET_CRYPTO_RsaPrivateKey *key, + const struct GNUNET_CRYPTO_RsaSignaturePurpose *purpose, + struct GNUNET_CRYPTO_RsaSignature *sig) +{ + gcry_sexp_t result; + gcry_sexp_t data; + size_t ssize; + gcry_mpi_t rval; + GNUNET_HashCode hc; + char *buff; + int bufSize; + + GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc); +#define FORMATSTRING "(4:data(5:flags5:pkcs1)(4:hash6:sha51264:0123456789012345678901234567890123456789012345678901234567890123))" + bufSize = strlen (FORMATSTRING) + 1; + buff = GNUNET_malloc (bufSize); + memcpy (buff, FORMATSTRING, bufSize); + memcpy (&buff + [bufSize - + strlen + ("0123456789012345678901234567890123456789012345678901234567890123))") + - 1], &hc, sizeof (GNUNET_HashCode)); + GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0)); + GNUNET_free (buff); + GNUNET_assert (0 == gcry_pk_sign (&result, data, key->sexp)); + gcry_sexp_release (data); + GNUNET_assert (0 == key_from_sexp (&rval, result, "rsa", "s")); + gcry_sexp_release (result); + ssize = sizeof (struct GNUNET_CRYPTO_RsaSignature); + GNUNET_assert (0 == + gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) sig, ssize, + &ssize, rval)); + gcry_mpi_release (rval); + adjust (sig->sig, ssize, sizeof (struct GNUNET_CRYPTO_RsaSignature)); + return GNUNET_OK; +} + + +/** + * Verify signature. + * + * @param purpose what is the purpose that the signature should have? + * @param validate block to validate (size, purpose, data) + * @param sig signature that is being validated + * @param publicKey public key of the signer + * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid + */ +int +GNUNET_CRYPTO_rsa_verify (uint32_t purpose, + const struct GNUNET_CRYPTO_RsaSignaturePurpose + *validate, + const struct GNUNET_CRYPTO_RsaSignature *sig, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded + *publicKey) +{ + gcry_sexp_t data; + gcry_sexp_t sigdata; + size_t size; + gcry_mpi_t val; + struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; + GNUNET_HashCode hc; + char *buff; + int bufSize; + size_t erroff; + int rc; + + if (purpose != ntohl (validate->purpose)) + return GNUNET_SYSERR; /* purpose mismatch */ + GNUNET_CRYPTO_hash (validate, ntohl (validate->size), &hc); + size = sizeof (struct GNUNET_CRYPTO_RsaSignature); + GNUNET_assert (0 == + gcry_mpi_scan (&val, GCRYMPI_FMT_USG, + (const unsigned char *) sig, size, &size)); + GNUNET_assert (0 == + gcry_sexp_build (&sigdata, &erroff, "(sig-val(rsa(s %m)))", + val)); + gcry_mpi_release (val); + bufSize = strlen (FORMATSTRING) + 1; + buff = GNUNET_malloc (bufSize); + memcpy (buff, FORMATSTRING, bufSize); + memcpy (&buff + [strlen (FORMATSTRING) - + strlen + ("0123456789012345678901234567890123456789012345678901234567890123))")], + &hc, sizeof (GNUNET_HashCode)); + GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0)); + GNUNET_free (buff); + hostkey = public2PrivateKey (publicKey); + if (hostkey == NULL) + { + gcry_sexp_release (data); + gcry_sexp_release (sigdata); + return GNUNET_SYSERR; + } + rc = gcry_pk_verify (sigdata, data, hostkey->sexp); + GNUNET_CRYPTO_rsa_key_free (hostkey); + gcry_sexp_release (data); + gcry_sexp_release (sigdata); + if (rc) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("RSA signature verification failed at %s:%d: %s\n"), __FILE__, + __LINE__, gcry_strerror (rc)); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/* end of crypto_rsa.c */ diff --git a/src/util/disk.c b/src/util/disk.c new file mode 100644 index 0000000..b6b458f --- /dev/null +++ b/src/util/disk.c @@ -0,0 +1,2505 @@ +/* + This file is part of GNUnet. + (C) 2001--2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/disk.c + * @brief disk IO convenience methods + * @author Christian Grothoff + * @author Nils Durner + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_directories.h" +#include "gnunet_disk_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_strings_lib.h" +#include "gnunet_crypto_lib.h" +#include "disk.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +#define DEBUG_NPIPE GNUNET_EXTRA_LOGGING + +#define DEBUG_PIPE GNUNET_EXTRA_LOGGING + +/** + * Block size for IO for copying files. + */ +#define COPY_BLK_SIZE 65536 + + + +#if defined(LINUX) || defined(CYGWIN) +#include +#else +#if defined(SOMEBSD) || defined(DARWIN) +#include +#include +#else +#ifdef SOLARIS +#include +#include +#else +#ifdef MINGW +#ifndef PIPE_BUF +#define PIPE_BUF 512 +ULONG PipeSerialNumber; +#endif +#define _IFMT 0170000 /* type of file */ +#define _IFLNK 0120000 /* symbolic link */ +#define S_ISLNK(m) (((m)&_IFMT) == _IFLNK) +#else +#error PORT-ME: need to port statfs (how much space is left on the drive?) +#endif +#endif +#endif +#endif + +#if !defined(SOMEBSD) && !defined(DARWIN) && !defined(WINDOWS) +#include +#endif +#if LINUX +#include +#endif + + +/** + * Handle used to manage a pipe. + */ +struct GNUNET_DISK_PipeHandle +{ + /** + * File descriptors for the pipe. + */ + struct GNUNET_DISK_FileHandle *fd[2]; +}; + + +/** + * Closure for the recursion to determine the file size + * of a directory. + */ +struct GetFileSizeData +{ + /** + * Set to the total file size. + */ + uint64_t total; + + /** + * GNUNET_YES if symbolic links should be included. + */ + int include_sym_links; +}; + + +static int +translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm) +{ + int mode; + + mode = 0; + if (perm & GNUNET_DISK_PERM_USER_READ) + mode |= S_IRUSR; + if (perm & GNUNET_DISK_PERM_USER_WRITE) + mode |= S_IWUSR; + if (perm & GNUNET_DISK_PERM_USER_EXEC) + mode |= S_IXUSR; + if (perm & GNUNET_DISK_PERM_GROUP_READ) + mode |= S_IRGRP; + if (perm & GNUNET_DISK_PERM_GROUP_WRITE) + mode |= S_IWGRP; + if (perm & GNUNET_DISK_PERM_GROUP_EXEC) + mode |= S_IXGRP; + if (perm & GNUNET_DISK_PERM_OTHER_READ) + mode |= S_IROTH; + if (perm & GNUNET_DISK_PERM_OTHER_WRITE) + mode |= S_IWOTH; + if (perm & GNUNET_DISK_PERM_OTHER_EXEC) + mode |= S_IXOTH; + + return mode; +} + + +/** + * Iterate over all files in the given directory and + * accumulate their size. + * + * @param cls closure of type "struct GetFileSizeData" + * @param fn current filename we are looking at + * @return GNUNET_SYSERR on serious errors, otherwise GNUNET_OK + */ +static int +getSizeRec (void *cls, const char *fn) +{ + struct GetFileSizeData *gfsd = cls; + +#ifdef HAVE_STAT64 + struct stat64 buf; +#else + struct stat buf; +#endif + +#ifdef HAVE_STAT64 + if (0 != STAT64 (fn, &buf)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat64", fn); + return GNUNET_SYSERR; + } +#else + if (0 != STAT (fn, &buf)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fn); + return GNUNET_SYSERR; + } +#endif + if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)) + gfsd->total += buf.st_size; + if ((S_ISDIR (buf.st_mode)) && (0 == ACCESS (fn, X_OK)) && + ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))) + { + if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &getSizeRec, gfsd)) + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Checks whether a handle is invalid + * + * @param h handle to check + * @return GNUNET_YES if invalid, GNUNET_NO if valid + */ +int +GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h) +{ +#ifdef MINGW + return ((!h) || (h->h == INVALID_HANDLE_VALUE)) ? GNUNET_YES : GNUNET_NO; +#else + return ((!h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO; +#endif +} + +/** + * Get the size of an open file. + * + * @param fh open file handle + * @param size where to write size of the file + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh, + OFF_T *size) +{ +#if WINDOWS + BOOL b; + LARGE_INTEGER li; + b = GetFileSizeEx (fh->h, &li); + if (!b) + { + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + *size = (OFF_T) li.QuadPart; +#else + struct stat sbuf; + + if (0 != FSTAT (fh->fd, &sbuf)) + return GNUNET_SYSERR; + *size = sbuf.st_size; +#endif + return GNUNET_OK; +} + + +/** + * Move the read/write pointer in a file + * + * @param h handle of an open file + * @param offset position to move to + * @param whence specification to which position the offset parameter relates to + * @return the new position on success, GNUNET_SYSERR otherwise + */ +OFF_T +GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, OFF_T offset, + enum GNUNET_DISK_Seek whence) +{ + if (h == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifdef MINGW + LARGE_INTEGER li, new_pos; + BOOL b; + + static DWORD t[] = {[GNUNET_DISK_SEEK_SET] = FILE_BEGIN, + [GNUNET_DISK_SEEK_CUR] = FILE_CURRENT,[GNUNET_DISK_SEEK_END] = FILE_END + }; + li.QuadPart = offset; + + b = SetFilePointerEx (h->h, li, &new_pos, t[whence]); + if (b == 0) + { + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + return (OFF_T) new_pos.QuadPart; +#else + static int t[] = {[GNUNET_DISK_SEEK_SET] = SEEK_SET, + [GNUNET_DISK_SEEK_CUR] = SEEK_CUR,[GNUNET_DISK_SEEK_END] = SEEK_END + }; + + return lseek (h->fd, offset, t[whence]); +#endif +} + + +/** + * Get the size of the file (or directory) of the given file (in + * bytes). + * + * @param filename name of the file or directory + * @param size set to the size of the file (or, + * in the case of directories, the sum + * of all sizes of files in the directory) + * @param includeSymLinks should symbolic links be + * included? + * @return GNUNET_SYSERR on error, GNUNET_OK on success + */ +int +GNUNET_DISK_file_size (const char *filename, uint64_t * size, + int includeSymLinks) +{ + struct GetFileSizeData gfsd; + int ret; + + GNUNET_assert (size != NULL); + gfsd.total = 0; + gfsd.include_sym_links = includeSymLinks; + ret = getSizeRec (&gfsd, filename); + *size = gfsd.total; + return ret; +} + + +/** + * Obtain some unique identifiers for the given file + * that can be used to identify it in the local system. + * This function is used between GNUnet processes to + * quickly check if two files with the same absolute path + * are actually identical. The two processes represent + * the same peer but may communicate over the network + * (and the file may be on an NFS volume). This function + * may not be supported on all operating systems. + * + * @param filename name of the file + * @param dev set to the device ID + * @param ino set to the inode ID + * @return GNUNET_OK on success + */ +int +GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev, + uint64_t * ino) +{ +#if LINUX + struct stat sbuf; + struct statvfs fbuf; + + if ((0 == stat (filename, &sbuf)) && (0 == statvfs (filename, &fbuf))) + { + *dev = (uint64_t) fbuf.f_fsid; + *ino = (uint64_t) sbuf.st_ino; + return GNUNET_OK; + } +#elif SOMEBSD + struct stat sbuf; + struct statfs fbuf; + + if ((0 == stat (filename, &sbuf)) && (0 == statfs (filename, &fbuf))) + { + *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 || + ((uint64_t) fbuf.f_fsid.val[1]); + *ino = (uint64_t) sbuf.st_ino; + return GNUNET_OK; + } +#elif WINDOWS + // FIXME NILS: test this + struct GNUNET_DISK_FileHandle *fh; + BY_HANDLE_FILE_INFORMATION info; + int succ; + + fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0); + if (fh == NULL) + return GNUNET_SYSERR; + succ = GetFileInformationByHandle (fh->h, &info); + GNUNET_DISK_file_close (fh); + if (succ) + { + *dev = info.dwVolumeSerialNumber; + *ino = ((((uint64_t) info.nFileIndexHigh) << (sizeof (DWORD) * 8)) | info.nFileIndexLow); + return GNUNET_OK; + } + else + return GNUNET_SYSERR; + +#endif + return GNUNET_SYSERR; +} + + +/** + * Create an (empty) temporary file on disk. If the given name is not + * an absolute path, the current 'TMPDIR' will be prepended. In any case, + * 6 random characters will be appended to the name to create a unique + * filename. + * + * @param t component to use for the name; + * does NOT contain "XXXXXX" or "/tmp/". + * @return NULL on error, otherwise name of fresh + * file on disk in directory for temporary files + */ +char * +GNUNET_DISK_mktemp (const char *t) +{ + const char *tmpdir; + int fd; + char *tmpl; + char *fn; + + if ((t[0] != '/') && (t[0] != '\\') +#if WINDOWS + && !(isalpha ((int) t[0]) && (t[0] != '\0') && (t[1] == ':')) +#endif + ) + { + /* FIXME: This uses system codepage on W32, not UTF-8 */ + tmpdir = getenv ("TMPDIR"); + tmpdir = tmpdir ? tmpdir : "/tmp"; + GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX"); + } + else + { + GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX"); + } +#ifdef MINGW + fn = (char *) GNUNET_malloc (MAX_PATH + 1); + if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn)) + { + GNUNET_free (fn); + GNUNET_free (tmpl); + return NULL; + } + GNUNET_free (tmpl); +#else + fn = tmpl; +#endif + /* FIXME: why is this not MKSTEMP()? This function is implemented in plibc. + * CG: really? If I put MKSTEMP here, I get a compilation error... + * It will assume that fn is UTF-8-encoded, if compiled with UTF-8 support. + */ + fd = mkstemp (fn); + if (fd == -1) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn); + GNUNET_free (fn); + return NULL; + } + if (0 != CLOSE (fd)) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn); + return fn; +} + + +/** + * Get the number of blocks that are left on the partition that + * contains the given file (for normal users). + * + * @param part a file on the partition to check + * @return -1 on errors, otherwise the number of free blocks + */ +long +GNUNET_DISK_get_blocks_available (const char *part) +{ +#ifdef SOLARIS + struct statvfs buf; + + if (0 != statvfs (part, &buf)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part); + return -1; + } + return buf.f_bavail; +#elif MINGW + DWORD dwDummy; + DWORD dwBlocks; + wchar_t szDrive[4]; + wchar_t wpath[MAX_PATH + 1]; + char *path; + + path = GNUNET_STRINGS_filename_expand (part); + if (path == NULL) + return -1; + /* "part" was in UTF-8, and so is "path" */ + if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath)) + { + GNUNET_free (path); + return -1; + } + GNUNET_free (path); + wcsncpy (szDrive, wpath, 3); + szDrive[3] = 0; + if (!GetDiskFreeSpaceW (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for drive `%S': %u\n"), + "GetDiskFreeSpace", szDrive, GetLastError ()); + + return -1; + } + return dwBlocks; +#else + struct statfs s; + + if (0 != statfs (part, &s)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part); + return -1; + } + return s.f_bavail; +#endif +} + + +/** + * Test if "fil" is a directory. + * Will not print an error message if the directory + * does not exist. Will log errors if GNUNET_SYSERR is + * returned (i.e., a file exists with the same name). + * + * @param fil filename to test + * @return GNUNET_YES if yes, GNUNET_NO if not, GNUNET_SYSERR if it + * does not exist + */ +int +GNUNET_DISK_directory_test (const char *fil) +{ + struct stat filestat; + int ret; + + ret = STAT (fil, &filestat); + if (ret != 0) + { + if (errno != ENOENT) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil); + return GNUNET_SYSERR; + } + return GNUNET_NO; + } + if (!S_ISDIR (filestat.st_mode)) + return GNUNET_NO; + if (ACCESS (fil, R_OK | X_OK) < 0) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil); + return GNUNET_SYSERR; + } + return GNUNET_YES; +} + + +/** + * Check that fil corresponds to a filename + * (of a file that exists and that is not a directory). + * + * @param fil filename to check + * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something + * else (will print an error message in that case, too). + */ +int +GNUNET_DISK_file_test (const char *fil) +{ + struct stat filestat; + int ret; + char *rdir; + + rdir = GNUNET_STRINGS_filename_expand (fil); + if (rdir == NULL) + return GNUNET_SYSERR; + + ret = STAT (rdir, &filestat); + if (ret != 0) + { + if (errno != ENOENT) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir); + GNUNET_free (rdir); + return GNUNET_SYSERR; + } + GNUNET_free (rdir); + return GNUNET_NO; + } + if (!S_ISREG (filestat.st_mode)) + { + GNUNET_free (rdir); + return GNUNET_NO; + } + if (ACCESS (rdir, R_OK) < 0) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir); + GNUNET_free (rdir); + return GNUNET_SYSERR; + } + GNUNET_free (rdir); + return GNUNET_YES; +} + + +/** + * Implementation of "mkdir -p" + * @param dir the directory to create + * @returns GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_DISK_directory_create (const char *dir) +{ + char *rdir; + int len; + int pos; + int ret = GNUNET_OK; + + rdir = GNUNET_STRINGS_filename_expand (dir); + if (rdir == NULL) + return GNUNET_SYSERR; + + len = strlen (rdir); +#ifndef MINGW + pos = 1; /* skip heading '/' */ +#else + /* Local or Network path? */ + if (strncmp (rdir, "\\\\", 2) == 0) + { + pos = 2; + while (rdir[pos]) + { + if (rdir[pos] == '\\') + { + pos++; + break; + } + pos++; + } + } + else + { + pos = 3; /* strlen("C:\\") */ + } +#endif + while (pos <= len) + { + if ((rdir[pos] == DIR_SEPARATOR) || (pos == len)) + { + rdir[pos] = '\0'; + ret = GNUNET_DISK_directory_test (rdir); + if (ret == GNUNET_SYSERR) + { + GNUNET_free (rdir); + return GNUNET_SYSERR; + } + if (ret == GNUNET_NO) + { +#ifndef MINGW + ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */ +#else + wchar_t wrdir[MAX_PATH + 1]; + if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir)) + ret = !CreateDirectoryW (wrdir, NULL); + else + ret = 1; +#endif + if ((ret != 0) && (errno != EEXIST)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir); + GNUNET_free (rdir); + return GNUNET_SYSERR; + } + } + rdir[pos] = DIR_SEPARATOR; + } + pos++; + } + GNUNET_free (rdir); + return GNUNET_OK; +} + + +/** + * Create the directory structure for storing + * a file. + * + * @param filename name of a file in the directory + * @returns GNUNET_OK on success, + * GNUNET_SYSERR on failure, + * GNUNET_NO if the directory + * exists but is not writeable for us + */ +int +GNUNET_DISK_directory_create_for_file (const char *filename) +{ + char *rdir; + int len; + int ret; + + rdir = GNUNET_STRINGS_filename_expand (filename); + if (rdir == NULL) + return GNUNET_SYSERR; + len = strlen (rdir); + while ((len > 0) && (rdir[len] != DIR_SEPARATOR)) + len--; + rdir[len] = '\0'; + ret = GNUNET_DISK_directory_create (rdir); + if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK))) + ret = GNUNET_NO; + GNUNET_free (rdir); + return ret; +} + + +/** + * Read the contents of a binary file into a buffer. + * @param h handle to an open file + * @param result the buffer to write the result to + * @param len the maximum number of bytes to read + * @return the number of bytes read on success, GNUNET_SYSERR on failure + */ +ssize_t +GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result, + size_t len) +{ + if (h == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifdef MINGW + DWORD bytesRead; + + if (h->type != GNUNET_PIPE) + { + if (!ReadFile (h->h, result, len, &bytesRead, NULL)) + { + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + } + else + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to read\n"); +#endif + if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead)) + { + if (GetLastError () != ERROR_IO_PENDING) + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ()); +#endif + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n"); +#endif + GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE); + } +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead); +#endif + } + return bytesRead; +#else + return read (h->fd, result, len); +#endif +} + + +/** + * Read the contents of a binary file into a buffer. + * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN + * when no data can be read). + * + * @param h handle to an open file + * @param result the buffer to write the result to + * @param len the maximum number of bytes to read + * @return the number of bytes read on success, GNUNET_SYSERR on failure + */ +ssize_t +GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h, + void *result, size_t len) +{ + if (h == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifdef MINGW + DWORD bytesRead; + + if (h->type != GNUNET_PIPE) + { + if (!ReadFile (h->h, result, len, &bytesRead, NULL)) + { + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + } + else + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe, trying to read\n"); +#endif + if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead)) + { + if (GetLastError () != ERROR_IO_PENDING) + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ()); +#endif + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + else + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "ReadFile() queued a read, cancelling\n"); +#endif + CancelIo (h->h); + errno = EAGAIN; + return GNUNET_SYSERR; + } + } +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead); +#endif + } + return bytesRead; +#else + int flags; + ssize_t ret; + + /* set to non-blocking, read, then set back */ + flags = fcntl (h->fd, F_GETFL); + if (0 == (flags & O_NONBLOCK)) + fcntl (h->fd, F_SETFL, flags | O_NONBLOCK); + ret = read (h->fd, result, len); + if (0 == (flags & O_NONBLOCK)) + fcntl (h->fd, F_SETFL, flags); + return ret; +#endif +} + + +/** + * Read the contents of a binary file into a buffer. + * + * @param fn file name + * @param result the buffer to write the result to + * @param len the maximum number of bytes to read + * @return number of bytes read, GNUNET_SYSERR on failure + */ +ssize_t +GNUNET_DISK_fn_read (const char *fn, void *result, size_t len) +{ + struct GNUNET_DISK_FileHandle *fh; + ssize_t ret; + + fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); + if (!fh) + return GNUNET_SYSERR; + ret = GNUNET_DISK_file_read (fh, result, len); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); + + return ret; +} + + +/** + * Write a buffer to a file. + * @param h handle to open file + * @param buffer the data to write + * @param n number of bytes to write + * @return number of bytes written on success, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h, + const void *buffer, size_t n) +{ + if (h == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifdef MINGW + DWORD bytesWritten; + + if (h->type != GNUNET_PIPE) + { + if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL)) + { + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + } + else + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n); +#endif + if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite)) + { + if (GetLastError () != ERROR_IO_PENDING) + { + SetErrnoFromWinError (GetLastError ()); +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", + GetLastError ()); +#endif + return GNUNET_SYSERR; + } +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n"); +#endif + if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE)) + { + SetErrnoFromWinError (GetLastError ()); +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Error getting overlapped result while writing to pipe: %u\n", + GetLastError ()); +#endif + return GNUNET_SYSERR; + } + } + else + { + DWORD ovr; + if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE)) + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Error getting control overlapped result while writing to pipe: %u\n", + GetLastError ()); +#endif + } + else + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Wrote %u bytes (ovr says %u), picking the greatest\n", + bytesWritten, ovr); +#endif + } + } + if (bytesWritten == 0) + { + if (n > 0) + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten); +#endif + errno = EAGAIN; + return GNUNET_SYSERR; + } + } +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten); +#endif + } + return bytesWritten; +#else + return write (h->fd, buffer, n); +#endif +} + + +/** + * Write a buffer to a file, blocking, if necessary. + * @param h handle to open file + * @param buffer the data to write + * @param n number of bytes to write + * @return number of bytes written on success, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h, + const void *buffer, size_t n) +{ + if (h == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifdef MINGW + DWORD bytesWritten; + /* We do a non-overlapped write, which is as blocking as it gets */ +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n); +#endif + if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL)) + { + SetErrnoFromWinError (GetLastError ()); +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", + GetLastError ()); +#endif + return GNUNET_SYSERR; + } + if (bytesWritten == 0 && n > 0) + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n"); +#endif + WaitForSingleObject (h->h, INFINITE); + if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL)) + { + SetErrnoFromWinError (GetLastError ()); +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", + GetLastError ()); +#endif + return GNUNET_SYSERR; + } + } +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten); +#endif + return bytesWritten; +#else + int flags; + ssize_t ret; + + /* set to blocking, write, then set back */ + flags = fcntl (h->fd, F_GETFL); + if (0 != (flags & O_NONBLOCK)) + fcntl (h->fd, F_SETFL, flags - O_NONBLOCK); + ret = write (h->fd, buffer, n); + if (0 == (flags & O_NONBLOCK)) + fcntl (h->fd, F_SETFL, flags); + return ret; +#endif +} + + +/** + * Write a buffer to a file. If the file is longer than the + * number of bytes that will be written, it will be truncated. + * + * @param fn file name + * @param buffer the data to write + * @param n number of bytes to write + * @param mode file permissions + * @return number of bytes written on success, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n, + enum GNUNET_DISK_AccessPermissions mode) +{ + struct GNUNET_DISK_FileHandle *fh; + ssize_t ret; + + fh = GNUNET_DISK_file_open (fn, + GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE + | GNUNET_DISK_OPEN_CREATE, mode); + if (!fh) + return GNUNET_SYSERR; + ret = GNUNET_DISK_file_write (fh, buffer, n); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); + return ret; +} + + +/** + * Scan a directory for files. + * + * @param dirName the name of the directory + * @param callback the method to call for each file, + * can be NULL, in that case, we only count + * @param callback_cls closure for callback + * @return the number of files found, GNUNET_SYSERR on error or + * ieration aborted by callback returning GNUNET_SYSERR + */ +int +GNUNET_DISK_directory_scan (const char *dirName, + GNUNET_FileNameCallback callback, + void *callback_cls) +{ + DIR *dinfo; + struct dirent *finfo; + struct stat istat; + int count = 0; + char *name; + char *dname; + unsigned int name_len; + unsigned int n_size; + + GNUNET_assert (dirName != NULL); + dname = GNUNET_STRINGS_filename_expand (dirName); + if (dname == NULL) + return GNUNET_SYSERR; + while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR)) + dname[strlen (dname) - 1] = '\0'; + if (0 != STAT (dname, &istat)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname); + GNUNET_free (dname); + return GNUNET_SYSERR; + } + if (!S_ISDIR (istat.st_mode)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"), + dirName); + GNUNET_free (dname); + return GNUNET_SYSERR; + } + errno = 0; + dinfo = OPENDIR (dname); + if ((errno == EACCES) || (dinfo == NULL)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname); + if (dinfo != NULL) + CLOSEDIR (dinfo); + GNUNET_free (dname); + return GNUNET_SYSERR; + } + name_len = 256; + n_size = strlen (dname) + name_len + 2; + name = GNUNET_malloc (n_size); + while ((finfo = READDIR (dinfo)) != NULL) + { + if ((0 == strcmp (finfo->d_name, ".")) || + (0 == strcmp (finfo->d_name, ".."))) + continue; + if (callback != NULL) + { + if (name_len < strlen (finfo->d_name)) + { + GNUNET_free (name); + name_len = strlen (finfo->d_name); + n_size = strlen (dname) + name_len + 2; + name = GNUNET_malloc (n_size); + } + /* dname can end in "/" only if dname == "/"; + * if dname does not end in "/", we need to add + * a "/" (otherwise, we must not!) */ + GNUNET_snprintf (name, n_size, "%s%s%s", dname, + (strcmp (dname, DIR_SEPARATOR_STR) == + 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name); + if (GNUNET_OK != callback (callback_cls, name)) + { + CLOSEDIR (dinfo); + GNUNET_free (name); + GNUNET_free (dname); + return GNUNET_SYSERR; + } + } + count++; + } + CLOSEDIR (dinfo); + GNUNET_free (name); + GNUNET_free (dname); + return count; +} + + +/** + * Opaque handle used for iterating over a directory. + */ +struct GNUNET_DISK_DirectoryIterator +{ + + /** + * Function to call on directory entries. + */ + GNUNET_DISK_DirectoryIteratorCallback callback; + + /** + * Closure for callback. + */ + void *callback_cls; + + /** + * Reference to directory. + */ + DIR *directory; + + /** + * Directory name. + */ + char *dirname; + + /** + * Next filename to process. + */ + char *next_name; + + /** + * Our priority. + */ + enum GNUNET_SCHEDULER_Priority priority; + +}; + + +/** + * Task used by the directory iterator. + */ +static void +directory_iterator_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_DISK_DirectoryIterator *iter = cls; + char *name; + + name = iter->next_name; + GNUNET_assert (name != NULL); + iter->next_name = NULL; + iter->callback (iter->callback_cls, iter, name, iter->dirname); + GNUNET_free (name); +} + + +/** + * This function must be called during the DiskIteratorCallback + * (exactly once) to schedule the task to process the next + * filename in the directory (if there is one). + * + * @param iter opaque handle for the iterator + * @param can set to GNUNET_YES to terminate the iteration early + * @return GNUNET_YES if iteration will continue, + * GNUNET_NO if this was the last entry (and iteration is complete), + * GNUNET_SYSERR if abort was YES + */ +int +GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter, + int can) +{ + struct dirent *finfo; + + GNUNET_assert (iter->next_name == NULL); + if (can == GNUNET_YES) + { + CLOSEDIR (iter->directory); + GNUNET_free (iter->dirname); + GNUNET_free (iter); + return GNUNET_SYSERR; + } + while (NULL != (finfo = READDIR (iter->directory))) + { + if ((0 == strcmp (finfo->d_name, ".")) || + (0 == strcmp (finfo->d_name, ".."))) + continue; + GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname, + DIR_SEPARATOR_STR, finfo->d_name); + break; + } + if (finfo == NULL) + { + GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES); + return GNUNET_NO; + } + GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task, + iter); + return GNUNET_YES; +} + + +/** + * Scan a directory for files using the scheduler to run a task for + * each entry. The name of the directory must be expanded first (!). + * If a scheduler does not need to be used, GNUNET_DISK_directory_scan + * may provide a simpler API. + * + * @param prio priority to use + * @param dirName the name of the directory + * @param callback the method to call for each file + * @param callback_cls closure for callback + * @return GNUNET_YES if directory is not empty and 'callback' + * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error. + */ +int +GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio, + const char *dirName, + GNUNET_DISK_DirectoryIteratorCallback + callback, void *callback_cls) +{ + struct GNUNET_DISK_DirectoryIterator *di; + + di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator)); + di->callback = callback; + di->callback_cls = callback_cls; + di->directory = OPENDIR (dirName); + if (di->directory == NULL) + { + GNUNET_free (di); + callback (callback_cls, NULL, NULL, NULL); + return GNUNET_SYSERR; + } + di->dirname = GNUNET_strdup (dirName); + di->priority = prio; + return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO); +} + + +/** + * Function that removes the given directory by calling + * "GNUNET_DISK_directory_remove". + * + * @param unused not used + * @param fn directory to remove + * @return GNUNET_OK + */ +static int +remove_helper (void *unused, const char *fn) +{ + (void) GNUNET_DISK_directory_remove (fn); + return GNUNET_OK; +} + + +/** + * Remove all files in a directory (rm -rf). Call with + * caution. + * + * + * @param fileName the file to remove + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_directory_remove (const char *fileName) +{ + struct stat istat; + + if (0 != LSTAT (fileName, &istat)) + return GNUNET_NO; /* file may not exist... */ + CHMOD (fileName, S_IWUSR | S_IRUSR | S_IXUSR); + if (UNLINK (fileName) == 0) + return GNUNET_OK; + if ((errno != EISDIR) && + /* EISDIR is not sufficient in all cases, e.g. + * sticky /tmp directory may result in EPERM on BSD. + * So we also explicitly check "isDirectory" */ + (GNUNET_YES != GNUNET_DISK_directory_test (fileName))) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName); + return GNUNET_SYSERR; + } + if (GNUNET_SYSERR == + GNUNET_DISK_directory_scan (fileName, &remove_helper, NULL)) + return GNUNET_SYSERR; + if (0 != RMDIR (fileName)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Copy a file. + * + * @param src file to copy + * @param dst destination file name + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_file_copy (const char *src, const char *dst) +{ + char *buf; + uint64_t pos; + uint64_t size; + size_t len; + struct GNUNET_DISK_FileHandle *in; + struct GNUNET_DISK_FileHandle *out; + + if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES)) + return GNUNET_SYSERR; + pos = 0; + in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (!in) + return GNUNET_SYSERR; + out = + GNUNET_DISK_file_open (dst, + GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | + GNUNET_DISK_OPEN_FAILIFEXISTS, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE | + GNUNET_DISK_PERM_GROUP_READ | + GNUNET_DISK_PERM_GROUP_WRITE); + if (!out) + { + GNUNET_DISK_file_close (in); + return GNUNET_SYSERR; + } + buf = GNUNET_malloc (COPY_BLK_SIZE); + while (pos < size) + { + len = COPY_BLK_SIZE; + if (len > size - pos) + len = size - pos; + if (len != GNUNET_DISK_file_read (in, buf, len)) + goto FAIL; + if (len != GNUNET_DISK_file_write (out, buf, len)) + goto FAIL; + pos += len; + } + GNUNET_free (buf); + GNUNET_DISK_file_close (in); + GNUNET_DISK_file_close (out); + return GNUNET_OK; +FAIL: + GNUNET_free (buf); + GNUNET_DISK_file_close (in); + GNUNET_DISK_file_close (out); + return GNUNET_SYSERR; +} + + +/** + * @brief Removes special characters as ':' from a filename. + * @param fn the filename to canonicalize + */ +void +GNUNET_DISK_filename_canonicalize (char *fn) +{ + char *idx; + char c; + + idx = fn; + while (*idx) + { + c = *idx; + + if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' || + c == '<' || c == '>' || c == '|') + { + *idx = '_'; + } + + idx++; + } +} + + + +/** + * @brief Change owner of a file + * + * @param filename name of file to change the owner of + * @param user name of the new owner + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_DISK_file_change_owner (const char *filename, const char *user) +{ +#ifndef MINGW + struct passwd *pws; + + pws = getpwnam (user); + if (pws == NULL) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Cannot obtain information about user `%s': %s\n"), user, + STRERROR (errno)); + return GNUNET_SYSERR; + } + if (0 != chown (filename, pws->pw_uid, pws->pw_gid)) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename); +#endif + return GNUNET_OK; +} + + +/** + * Lock a part of a file + * @param fh file handle + * @param lockStart absolute position from where to lock + * @param lockEnd absolute position until where to lock + * @param excl GNUNET_YES for an exclusive lock + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart, + OFF_T lockEnd, int excl) +{ + if (fh == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifndef MINGW + struct flock fl; + + memset (&fl, 0, sizeof (struct flock)); + fl.l_type = excl ? F_WRLCK : F_RDLCK; + fl.l_whence = SEEK_SET; + fl.l_start = lockStart; + fl.l_len = lockEnd; + + return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK; +#else + OVERLAPPED o; + OFF_T diff = lockEnd - lockStart; + DWORD diff_low, diff_high; + diff_low = (DWORD) (diff & 0xFFFFFFFF); + diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF); + + memset (&o, 0, sizeof (OVERLAPPED)); + o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);; + o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF); + + if (!LockFileEx + (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY, + 0, diff_low, diff_high, &o)) + { + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + + return GNUNET_OK; +#endif +} + + +/** + * Unlock a part of a file + * @param fh file handle + * @param unlockStart absolute position from where to unlock + * @param unlockEnd absolute position until where to unlock + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart, + OFF_T unlockEnd) +{ + if (fh == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifndef MINGW + struct flock fl; + + memset (&fl, 0, sizeof (struct flock)); + fl.l_type = F_UNLCK; + fl.l_whence = SEEK_SET; + fl.l_start = unlockStart; + fl.l_len = unlockEnd; + + return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK; +#else + OVERLAPPED o; + OFF_T diff = unlockEnd - unlockStart; + DWORD diff_low, diff_high; + diff_low = (DWORD) (diff & 0xFFFFFFFF); + diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF); + + memset (&o, 0, sizeof (OVERLAPPED)); + o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);; + o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF); + + if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o)) + { + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + + return GNUNET_OK; +#endif +} + + +/** + * Open a file. Note that the access permissions will only be + * used if a new file is created and if the underlying operating + * system supports the given permissions. + * + * @param fn file name to be opened + * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags + * @param perm permissions for the newly created file, use + * GNUNET_DISK_PERM_USER_NONE if a file could not be created by this + * call (because of flags) + * @return IO handle on success, NULL on error + */ +struct GNUNET_DISK_FileHandle * +GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags, + enum GNUNET_DISK_AccessPermissions perm) +{ + char *expfn; + struct GNUNET_DISK_FileHandle *ret; + +#ifdef MINGW + DWORD access; + DWORD disp; + HANDLE h; + wchar_t wexpfn[MAX_PATH + 1]; +#else + int oflags; + int mode; + int fd; +#endif + + expfn = GNUNET_STRINGS_filename_expand (fn); + if (NULL == expfn) + return NULL; +#ifndef MINGW + mode = 0; + if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE)) + oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */ + else if (flags & GNUNET_DISK_OPEN_READ) + oflags = O_RDONLY; + else if (flags & GNUNET_DISK_OPEN_WRITE) + oflags = O_WRONLY; + else + { + GNUNET_break (0); + GNUNET_free (expfn); + return NULL; + } + if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS) + oflags |= (O_CREAT | O_EXCL); + if (flags & GNUNET_DISK_OPEN_TRUNCATE) + oflags |= O_TRUNC; + if (flags & GNUNET_DISK_OPEN_APPEND) + oflags |= O_APPEND; + if (flags & GNUNET_DISK_OPEN_CREATE) + { + (void) GNUNET_DISK_directory_create_for_file (expfn); + oflags |= O_CREAT; + mode = translate_unix_perms (perm); + } + + fd = open (expfn, oflags | O_LARGEFILE, mode); + if (fd == -1) + { + if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn); + else + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn); + GNUNET_free (expfn); + return NULL; + } +#else + access = 0; + disp = OPEN_ALWAYS; + + if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE)) + access = FILE_READ_DATA | FILE_WRITE_DATA; + else if (flags & GNUNET_DISK_OPEN_READ) + access = FILE_READ_DATA; + else if (flags & GNUNET_DISK_OPEN_WRITE) + access = FILE_WRITE_DATA; + + if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS) + { + disp = CREATE_NEW; + } + else if (flags & GNUNET_DISK_OPEN_CREATE) + { + (void) GNUNET_DISK_directory_create_for_file (expfn); + if (flags & GNUNET_DISK_OPEN_TRUNCATE) + disp = CREATE_ALWAYS; + else + disp = OPEN_ALWAYS; + } + else if (flags & GNUNET_DISK_OPEN_TRUNCATE) + { + disp = TRUNCATE_EXISTING; + } + else + { + disp = OPEN_EXISTING; + } + + if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn)) + h = CreateFileW (wexpfn, access, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + disp, FILE_ATTRIBUTE_NORMAL, NULL); + else + h = INVALID_HANDLE_VALUE; + if (h == INVALID_HANDLE_VALUE) + { + SetErrnoFromWinError (GetLastError ()); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn); + GNUNET_free (expfn); + return NULL; + } + + if (flags & GNUNET_DISK_OPEN_APPEND) + if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER) + { + SetErrnoFromWinError (GetLastError ()); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn); + CloseHandle (h); + GNUNET_free (expfn); + return NULL; + } +#endif + + ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); +#ifdef MINGW + ret->h = h; + ret->type = GNUNET_DISK_FILE; +#else + ret->fd = fd; +#endif + GNUNET_free (expfn); + return ret; +} + + +/** + * Close an open file + * @param h file handle + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) +{ + if (h == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#if MINGW + if (!CloseHandle (h->h)) + { + SetErrnoFromWinError (GetLastError ()); + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); + GNUNET_free (h->oOverlapRead); + GNUNET_free (h->oOverlapWrite); + GNUNET_free (h); + return GNUNET_SYSERR; + } +#else + if (close (h->fd) != 0) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); + GNUNET_free (h); + return GNUNET_SYSERR; + } +#endif + GNUNET_free (h); + return GNUNET_OK; +} + + +/** + * Construct full path to a file inside of the private + * directory used by GNUnet. Also creates the corresponding + * directory. If the resulting name is supposed to be + * a directory, end the last argument in '/' (or pass + * DIR_SEPARATOR_STR as the last argument before NULL). + * + * @param cfg configuration to use (determines HOME) + * @param serviceName name of the service + * @param ... is NULL-terminated list of + * path components to append to the + * private directory name. + * @return the constructed filename + */ +char * +GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *serviceName, ...) +{ + const char *c; + char *pfx; + char *ret; + va_list ap; + unsigned int needed; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, serviceName, "HOME", &pfx)) + return NULL; + if (pfx == NULL) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("No `%s' specified for service `%s' in configuration.\n"), "HOME", + serviceName); + return NULL; + } + needed = strlen (pfx) + 2; + if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\')) + needed++; + va_start (ap, serviceName); + while (1) + { + c = va_arg (ap, const char *); + + if (c == NULL) + break; + needed += strlen (c); + if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\')) + needed++; + } + va_end (ap); + ret = GNUNET_malloc (needed); + strcpy (ret, pfx); + GNUNET_free (pfx); + va_start (ap, serviceName); + while (1) + { + c = va_arg (ap, const char *); + + if (c == NULL) + break; + if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\')) + strcat (ret, DIR_SEPARATOR_STR); + strcat (ret, c); + } + va_end (ap); + if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\')) + (void) GNUNET_DISK_directory_create_for_file (ret); + else + (void) GNUNET_DISK_directory_create (ret); + return ret; +} + + +/** + * Handle for a memory-mapping operation. + */ +struct GNUNET_DISK_MapHandle +{ + /** + * Address where the map is in memory. + */ + void *addr; + +#ifdef MINGW + /** + * Underlying OS handle. + */ + HANDLE h; +#else + /** + * Number of bytes mapped. + */ + size_t len; +#endif +}; + + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif + +/** + * Map a file into memory + * + * @param h open file handle + * @param m handle to the new mapping + * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx + * @param len size of the mapping + * @return pointer to the mapped memory region, NULL on failure + */ +void * +GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h, + struct GNUNET_DISK_MapHandle **m, + enum GNUNET_DISK_MapType access, size_t len) +{ + if (h == NULL) + { + errno = EINVAL; + return NULL; + } + +#ifdef MINGW + DWORD mapAccess, protect; + + if ((access & GNUNET_DISK_MAP_TYPE_READ) && + (access & GNUNET_DISK_MAP_TYPE_WRITE)) + { + protect = PAGE_READWRITE; + mapAccess = FILE_MAP_ALL_ACCESS; + } + else if (access & GNUNET_DISK_MAP_TYPE_READ) + { + protect = PAGE_READONLY; + mapAccess = FILE_MAP_READ; + } + else if (access & GNUNET_DISK_MAP_TYPE_WRITE) + { + protect = PAGE_READWRITE; + mapAccess = FILE_MAP_WRITE; + } + else + { + GNUNET_break (0); + return NULL; + } + + *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle)); + (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL); + if ((*m)->h == INVALID_HANDLE_VALUE) + { + SetErrnoFromWinError (GetLastError ()); + GNUNET_free (*m); + return NULL; + } + + (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len); + if (!(*m)->addr) + { + SetErrnoFromWinError (GetLastError ()); + CloseHandle ((*m)->h); + GNUNET_free (*m); + } + + return (*m)->addr; +#else + int prot; + + prot = 0; + if (access & GNUNET_DISK_MAP_TYPE_READ) + prot = PROT_READ; + if (access & GNUNET_DISK_MAP_TYPE_WRITE) + prot |= PROT_WRITE; + *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle)); + (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0); + GNUNET_assert (NULL != (*m)->addr); + if (MAP_FAILED == (*m)->addr) + { + GNUNET_free (*m); + return NULL; + } + (*m)->len = len; + return (*m)->addr; +#endif +} + +/** + * Unmap a file + * @param h mapping handle + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h) +{ + int ret; + + if (h == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifdef MINGW + ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR; + if (ret != GNUNET_OK) + SetErrnoFromWinError (GetLastError ()); + if (!CloseHandle (h->h) && (ret == GNUNET_OK)) + { + ret = GNUNET_SYSERR; + SetErrnoFromWinError (GetLastError ()); + } +#else + ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR; +#endif + GNUNET_free (h); + return ret; +} + + +/** + * Write file changes to disk + * @param h handle to an open file + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h) +{ + if (h == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifdef MINGW + int ret; + + ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR; + if (ret != GNUNET_OK) + SetErrnoFromWinError (GetLastError ()); + return ret; +#elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN) + return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK; +#else + return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK; +#endif +} + + +#if WINDOWS +/* Copyright Bob Byrnes curl.com> + http://permalink.gmane.org/gmane.os.cygwin.patches/2121 +*/ +/* Create a pipe, and return handles to the read and write ends, + just like CreatePipe, but ensure that the write end permits + FILE_READ_ATTRIBUTES access, on later versions of win32 where + this is supported. This access is needed by NtQueryInformationFile, + which is used to implement select and nonblocking writes. + Note that the return value is either NO_ERROR or GetLastError, + unlike CreatePipe, which returns a bool for success or failure. */ +static int +create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr, + LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize, + DWORD dwReadMode, DWORD dwWriteMode) +{ + /* Default to error. */ + *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE; + + HANDLE read_pipe = INVALID_HANDLE_VALUE, write_pipe = INVALID_HANDLE_VALUE; + + /* Ensure that there is enough pipe buffer space for atomic writes. */ + if (psize < PIPE_BUF) + psize = PIPE_BUF; + + char pipename[MAX_PATH]; + + /* Retry CreateNamedPipe as long as the pipe name is in use. + * Retrying will probably never be necessary, but we want + * to be as robust as possible. */ + while (1) + { + static volatile LONG pipe_unique_id; + + snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld", + getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id)); +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n", + pipename, psize); +#endif + /* Use CreateNamedPipe instead of CreatePipe, because the latter + * returns a write handle that does not permit FILE_READ_ATTRIBUTES + * access, on versions of win32 earlier than WinXP SP2. + * CreatePipe also stupidly creates a full duplex pipe, which is + * a waste, since only a single direction is actually used. + * It's important to only allow a single instance, to ensure that + * the pipe was not created earlier by some other process, even if + * the pid has been reused. We avoid FILE_FLAG_FIRST_PIPE_INSTANCE + * because that is only available for Win2k SP2 and WinXP. */ + read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */ + psize, /* output buffer size */ + psize, /* input buffer size */ + NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); + + if (read_pipe != INVALID_HANDLE_VALUE) + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe); +#endif + break; + } + + DWORD err = GetLastError (); + + switch (err) + { + case ERROR_PIPE_BUSY: + /* The pipe is already open with compatible parameters. + * Pick a new name and retry. */ +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n"); +#endif + continue; + case ERROR_ACCESS_DENIED: + /* The pipe is already open with incompatible parameters. + * Pick a new name and retry. */ +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n"); +#endif + continue; + case ERROR_CALL_NOT_IMPLEMENTED: + /* We are on an older Win9x platform without named pipes. + * Return an anonymous pipe as the best approximation. */ +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "CreateNamedPipe not implemented, resorting to " + "CreatePipe: size = %lu\n", psize); +#endif + if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize)) + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", + *read_pipe_ptr); + LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", + *write_pipe_ptr); +#endif + return GNUNET_OK; + } + err = GetLastError (); + LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err); + return err; + default: + LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err); + return err; + } + /* NOTREACHED */ + } +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename); +#endif + + /* Open the named pipe for writing. + * Be sure to permit FILE_READ_ATTRIBUTES access. */ + write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */ + sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */ + 0); /* handle to template file */ + + if (write_pipe == INVALID_HANDLE_VALUE) + { + /* Failure. */ + DWORD err = GetLastError (); + +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err); +#endif + CloseHandle (read_pipe); + return err; + } +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe); +#endif + /* Success. */ + *read_pipe_ptr = read_pipe; + *write_pipe_ptr = write_pipe; + return GNUNET_OK; +} +#endif + + +/** + * Creates an interprocess channel + * + * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO + * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO + * @param inherit_read inherit the parent processes stdin (only for windows) + * @param inherit_write inherit the parent processes stdout (only for windows) + * @return handle to the new pipe, NULL on error + */ +struct GNUNET_DISK_PipeHandle * +GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write) +{ +#ifndef MINGW + int fd[2]; + int ret; + int eno; + + ret = pipe (fd); + if (ret == -1) + { + eno = errno; + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe"); + errno = eno; + return NULL; + } + return GNUNET_DISK_pipe_from_fd (blocking_read, + blocking_write, + fd); +#else + struct GNUNET_DISK_PipeHandle *p; + struct GNUNET_DISK_FileHandle *fds; + BOOL ret; + HANDLE tmp_handle; + + + p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) + + 2 * sizeof (struct GNUNET_DISK_FileHandle)); + fds = (struct GNUNET_DISK_FileHandle *) &p[1]; + p->fd[0] = &fds[0]; + p->fd[1] = &fds[1]; + + /* All pipes are overlapped. If you want them to block - just + * call WriteFile() and ReadFile() with NULL overlapped pointer. + */ + ret = + create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0, + FILE_FLAG_OVERLAPPED, + FILE_FLAG_OVERLAPPED); + if (!ret) + { + GNUNET_free (p); + SetErrnoFromWinError (GetLastError ()); + return NULL; + } + if (!DuplicateHandle + (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0, + inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) + { + SetErrnoFromWinError (GetLastError ()); + CloseHandle (p->fd[0]->h); + CloseHandle (p->fd[1]->h); + GNUNET_free (p); + return NULL; + } + CloseHandle (p->fd[0]->h); + p->fd[0]->h = tmp_handle; + + if (!DuplicateHandle + (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0, + inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) + { + SetErrnoFromWinError (GetLastError ()); + CloseHandle (p->fd[0]->h); + CloseHandle (p->fd[1]->h); + GNUNET_free (p); + return NULL; + } + CloseHandle (p->fd[1]->h); + p->fd[1]->h = tmp_handle; + + p->fd[0]->type = GNUNET_PIPE; + p->fd[1]->type = GNUNET_PIPE; + + p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); + p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); + p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); + p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); + + p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + + p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + + return p; +#endif +} + + +/** + * Creates a pipe object from a couple of file descriptors. + * Useful for wrapping existing pipe FDs. + * + * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO + * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO + * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes + * + * @return handle to the new pipe, NULL on error + */ +struct GNUNET_DISK_PipeHandle * +GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]) +{ + struct GNUNET_DISK_PipeHandle *p; + struct GNUNET_DISK_FileHandle *fds; + + p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) + + 2 * sizeof (struct GNUNET_DISK_FileHandle)); + fds = (struct GNUNET_DISK_FileHandle *) &p[1]; + p->fd[0] = &fds[0]; + p->fd[1] = &fds[1]; +#ifndef MINGW + int ret; + int flags; + int eno = 0; /* make gcc happy */ + + p->fd[0]->fd = fd[0]; + p->fd[1]->fd = fd[1]; + ret = 0; + if (fd[0] >= 0) + { + if (!blocking_read) + { + flags = fcntl (fd[0], F_GETFL); + flags |= O_NONBLOCK; + if (0 > fcntl (fd[0], F_SETFL, flags)) + { + ret = -1; + eno = errno; + } + } + flags = fcntl (fd[0], F_GETFD); + flags |= FD_CLOEXEC; + if (0 > fcntl (fd[0], F_SETFD, flags)) + { + ret = -1; + eno = errno; + } + } + + if (fd[1] >= 0) + { + if (!blocking_write) + { + flags = fcntl (fd[1], F_GETFL); + flags |= O_NONBLOCK; + if (0 > fcntl (fd[1], F_SETFL, flags)) + { + ret = -1; + eno = errno; + } + } + flags = fcntl (fd[1], F_GETFD); + flags |= FD_CLOEXEC; + if (0 > fcntl (fd[1], F_SETFD, flags)) + { + ret = -1; + eno = errno; + } + } + if (ret == -1) + { + errno = eno; + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl"); + if (p->fd[0]->fd >= 0) + GNUNET_break (0 == close (p->fd[0]->fd)); + if (p->fd[1]->fd >= 0) + GNUNET_break (0 == close (p->fd[1]->fd)); + GNUNET_free (p); + errno = eno; + return NULL; + } +#else + if (fd[0] >= 0) + p->fd[0]->h = _get_osfhandle (fd[0]); + else + p->fd[0]->h = INVALID_HANDLE_VALUE; + if (fd[1] >= 0) + p->fd[1]->h = _get_osfhandle (fd[1]); + else + p->fd[1]->h = INVALID_HANDLE_VALUE; + + if (p->fd[0]->h != INVALID_HANDLE_VALUE) + { + p->fd[0]->type = GNUNET_PIPE; + p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); + p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); + p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + } + + if (p->fd[1]->h != INVALID_HANDLE_VALUE) + { + p->fd[1]->type = GNUNET_PIPE; + p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); + p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); + p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + } +#endif + return p; +} + + +/** + * Closes an interprocess channel + * + * @param p pipe to close + * @param end which end of the pipe to close + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p, + enum GNUNET_DISK_PipeEnd end) +{ + int ret = GNUNET_OK; + int save; + +#ifdef MINGW + if (end == GNUNET_DISK_PIPE_END_READ) + { + if (p->fd[0]->h != INVALID_HANDLE_VALUE) + { + if (!CloseHandle (p->fd[0]->h)) + { + SetErrnoFromWinError (GetLastError ()); + ret = GNUNET_SYSERR; + } + GNUNET_free (p->fd[0]->oOverlapRead); + GNUNET_free (p->fd[0]->oOverlapWrite); + p->fd[0]->h = INVALID_HANDLE_VALUE; + } + } + else if (end == GNUNET_DISK_PIPE_END_WRITE) + { + if (p->fd[0]->h != INVALID_HANDLE_VALUE) + { + if (!CloseHandle (p->fd[1]->h)) + { + SetErrnoFromWinError (GetLastError ()); + ret = GNUNET_SYSERR; + } + GNUNET_free (p->fd[1]->oOverlapRead); + GNUNET_free (p->fd[1]->oOverlapWrite); + p->fd[1]->h = INVALID_HANDLE_VALUE; + } + } + save = errno; +#else + save = 0; + if (end == GNUNET_DISK_PIPE_END_READ) + { + if (0 != close (p->fd[0]->fd)) + { + ret = GNUNET_SYSERR; + save = errno; + } + p->fd[0]->fd = -1; + } + else if (end == GNUNET_DISK_PIPE_END_WRITE) + { + if (0 != close (p->fd[1]->fd)) + { + ret = GNUNET_SYSERR; + save = errno; + } + p->fd[1]->fd = -1; + } +#endif + errno = save; + return ret; +} + + +/** + * Closes an interprocess channel + * + * @param p pipe to close + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p) +{ + int ret = GNUNET_OK; + int save; + +#ifdef MINGW + if (p->fd[0]->h != INVALID_HANDLE_VALUE) + { + if (!CloseHandle (p->fd[0]->h)) + { + SetErrnoFromWinError (GetLastError ()); + ret = GNUNET_SYSERR; + } + GNUNET_free (p->fd[0]->oOverlapRead); + GNUNET_free (p->fd[0]->oOverlapWrite); + } + if (p->fd[1]->h != INVALID_HANDLE_VALUE) + { + if (!CloseHandle (p->fd[1]->h)) + { + SetErrnoFromWinError (GetLastError ()); + ret = GNUNET_SYSERR; + } + GNUNET_free (p->fd[1]->oOverlapRead); + GNUNET_free (p->fd[1]->oOverlapWrite); + } + save = errno; +#else + save = 0; + if (p->fd[0]->fd != -1) + { + if (0 != close (p->fd[0]->fd)) + { + ret = GNUNET_SYSERR; + save = errno; + } + } + + if (p->fd[1]->fd != -1) + { + if (0 != close (p->fd[1]->fd)) + { + ret = GNUNET_SYSERR; + save = errno; + } + } +#endif + GNUNET_free (p); + errno = save; + return ret; +} + + +/** + * Get the handle to a particular pipe end + * + * @param p pipe + * @param n end to access + * @return handle for the respective end + */ +const struct GNUNET_DISK_FileHandle * +GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p, + enum GNUNET_DISK_PipeEnd n) +{ + switch (n) + { + case GNUNET_DISK_PIPE_END_READ: + case GNUNET_DISK_PIPE_END_WRITE: + return p->fd[n]; + default: + GNUNET_break (0); + return NULL; + } +} + + +/** + * Retrieve OS file handle + * @internal + * @param fh GNUnet file descriptor + * @param dst destination buffer + * @param dst_len length of dst + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh, + void *dst, size_t dst_len) +{ +#ifdef MINGW + if (dst_len < sizeof (HANDLE)) + return GNUNET_SYSERR; + *((HANDLE *) dst) = fh->h; +#else + if (dst_len < sizeof (int)) + return GNUNET_SYSERR; + *((int *) dst) = fh->fd; +#endif + + return GNUNET_OK; +} + +/* end of disk.c */ diff --git a/src/util/disk.h b/src/util/disk.h new file mode 100644 index 0000000..2c12874 --- /dev/null +++ b/src/util/disk.h @@ -0,0 +1,44 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/disk.h + * @brief Internal DISK related helper functions + * @author Nils Durner + */ +#ifndef GNUNET_DISK_H_ +#define GNUNET_DISK_H_ + +#include "gnunet_disk_lib.h" + +/** + * Retrieve OS file handle + * + * @internal + * @param fh GNUnet file descriptor + * @param dst destination buffer + * @param dst_len length of dst + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh, + void *dst, size_t dst_len); + +#endif /* GNUNET_DISK_H_ */ diff --git a/src/util/getopt.c b/src/util/getopt.c new file mode 100644 index 0000000..1699498 --- /dev/null +++ b/src/util/getopt.c @@ -0,0 +1,1050 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 + Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +USA. + + +This code was heavily modified for GNUnet. +Copyright (C) 2006 Christian Grothoff +*/ + +/** + * @file util/getopt.c + * @brief GNU style option parsing + * + * TODO: get rid of statics (make reentrant) and + * replace main GNU getopt parser with one that + * actually fits our API. + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_getopt_lib.h" + +#ifdef VMS +#include +#if HAVE_STRING_H - 0 +#include +#endif +#endif + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#if defined (WIN32) && !defined (__CYGWIN32__) +/* It's not Unix, really. See? Capital letters. */ +#include +#define getpid() GetCurrentProcessId() +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +#ifdef HAVE_LIBINTL_H +#include +#define _(msgid) gettext (msgid) +#else +#define _(msgid) (msgid) +#endif +#endif + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct GNoption' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `GNoptarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct GNoption +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + * type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +static char *GNoptarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `GNoptind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +static int GNoptind = 1; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We GNUNET_CRYPTO_random_permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect GNoptions and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `GNoptind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char * +getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int +strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +extern pid_t __libc_pid; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void GNUNET_UNUSED +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + * that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} + +text_set_element (__libc_subinit, store_args_and_env); + +#define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +#define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,GNoptind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined (__STDC__) && __STDC__ +static void +exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = GNoptind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + * That puts the shorter segment into the right place. + * It leaves the longer segment in the right place overall, + * but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + * string can work normally. Our top argument must be in the range + * of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + * presents new arguments. */ + char *new_str = malloc (top + 1); + + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len); + memset (&new_str[nonoption_flags_max_len], '\0', + top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (GNoptind - last_nonopt); + last_nonopt = GNoptind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined (__STDC__) && __STDC__ +static const char * +_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + * is the program name); the sequence of previously skipped + * non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = GNoptind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL || + __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + { + memcpy (__getopt_nonoption_flags, orig_str, len); + memset (&__getopt_nonoption_flags[len], '\0', + nonoption_flags_max_len - len); + } + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `GNoptind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `GNoptind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `GNopterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `GNoptarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `GNoptarg', otherwise `GNoptarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we GNUNET_CRYPTO_random_permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct GNoption' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +static int +GN_getopt_internal (int argc, char *const *argv, const char *optstring, + const struct GNoption *longopts, int *longind, + int long_only) +{ + static int __getopt_initialized = 0; + static int GNopterr = 1; + + GNoptarg = NULL; + + if (GNoptind == 0 || !__getopt_initialized) + { + if (GNoptind == 0) + GNoptind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[GNoptind] points to a non-option argument. + * Either it does not have option syntax, or there is an environment flag + * from the shell indicating it is not an option. The later information + * is only used when the used in the GNU libc. */ +#ifdef _LIBC +#define NONOPTION_P (argv[GNoptind][0] != '-' || argv[GNoptind][1] == '\0' \ + || (GNoptind < nonoption_flags_len \ + && __getopt_nonoption_flags[GNoptind] == '1')) +#else +#define NONOPTION_P (argv[GNoptind][0] != '-' || argv[GNoptind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if GNoptind has been + * moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > GNoptind) + last_nonopt = GNoptind; + if (first_nonopt > GNoptind) + first_nonopt = GNoptind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + * exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != GNoptind) + exchange ((char **) argv); + else if (last_nonopt != GNoptind) + first_nonopt = GNoptind; + + /* Skip any additional non-options + * and extend the range of non-options previously skipped. */ + + while (GNoptind < argc && NONOPTION_P) + GNoptind++; + last_nonopt = GNoptind; + } + + /* The special ARGV-element `--' means premature end of options. + * Skip it like a null option, + * then exchange with previous non-options as if it were an option, + * then skip everything else like a non-option. */ + if (GNoptind != argc && !strcmp (argv[GNoptind], "--")) + { + GNoptind++; + + if (first_nonopt != last_nonopt && last_nonopt != GNoptind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = GNoptind; + last_nonopt = argc; + + GNoptind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + * and back over any non-options that we skipped and permuted. */ + + if (GNoptind == argc) + { + /* Set the next-arg-index to point at the non-options + * that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + GNoptind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + * either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + GNoptarg = argv[GNoptind++]; + return 1; + } + + /* We have found another option-ARGV-element. + * Skip the initial punctuation. */ + + nextchar = + (argv[GNoptind] + 1 + (longopts != NULL && argv[GNoptind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + * + * If long_only and the ARGV-element has the form "-f", where f is + * a valid short option, don't consider it an abbreviated form of + * a long option that starts with f. Otherwise there would be no + * way to give the -f short option. + * + * On the other hand, if there's a long option "fubar" and + * the ARGV-element is "-fu", do consider that an abbreviation of + * the long option, just like "--fu", and not "-f" with arg "u". + * + * This distinction seems to be the most useful approach. */ + + if (longopts != NULL && + (argv[GNoptind][1] == '-' || + (long_only && + (argv[GNoptind][2] || !my_index (optstring, argv[GNoptind][1]))))) + { + char *nameend; + const struct GNoption *p; + const struct GNoption *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + * or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == + (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (GNopterr) + FPRINTF (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], + argv[GNoptind]); + nextchar += strlen (nextchar); + GNoptind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + GNoptind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + * allow it to be used on enums. */ + if (pfound->has_arg) + GNoptarg = nameend + 1; + else + { + if (GNopterr) + { + if (argv[GNoptind - 1][1] == '-') + /* --option */ + FPRINTF (stderr, + _("%s: option `--%s' does not allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + FPRINTF (stderr, + _("%s: option `%c%s' does not allow an argument\n"), + argv[0], argv[GNoptind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (GNoptind < argc) + { + GNoptarg = argv[GNoptind++]; + } + else + { + if (GNopterr) + { + FPRINTF (stderr, _("%s: option `%s' requires an argument\n"), + argv[0], argv[GNoptind - 1]); + } + nextchar += strlen (nextchar); + return (optstring[0] == ':') ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + * or the option starts with '--' or is not a valid short + * option, then it's an error. + * Otherwise interpret it as a short option. */ + if (!long_only || argv[GNoptind][1] == '-' || + my_index (optstring, *nextchar) == NULL) + { + if (GNopterr) + { + if (argv[GNoptind][1] == '-') + /* --option */ + FPRINTF (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], + nextchar); + else + /* +option or -option */ + FPRINTF (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], + argv[GNoptind][0], nextchar); + } + nextchar = (char *) ""; + GNoptind++; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `GNoptind' when we start to process its last character. */ + if (*nextchar == '\0') + ++GNoptind; + + if (temp == NULL || c == ':') + { + if (GNopterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + FPRINTF (stderr, _("%s: illegal option -- %c\n"), argv[0], c); + else + FPRINTF (stderr, _("%s: invalid option -- %c\n"), argv[0], c); + } + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct GNoption *p; + const struct GNoption *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + GNoptarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + * we must advance to the next element now. */ + GNoptind++; + } + else if (GNoptind == argc) + { + if (GNopterr) + { + /* 1003.2 specifies the format of this message. */ + FPRINTF (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `GNoptind' once; + * increment it again when taking next ARGV-elt as argument. */ + GNoptarg = argv[GNoptind++]; + + /* GNoptarg is now the argument, see if it's in the + * table of longopts. */ + + for (nextchar = nameend = GNoptarg; *nameend && *nameend != '='; + nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + * or abbreviated matches. */ + if (longopts != NULL) + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (GNopterr) + FPRINTF (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], + argv[GNoptind]); + nextchar += strlen (nextchar); + GNoptind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + * allow it to be used on enums. */ + if (pfound->has_arg) + GNoptarg = nameend + 1; + else + { + if (GNopterr) + FPRINTF (stderr, _("\ +%s: option `-W %s' does not allow an argument\n"), argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (GNoptind < argc) + GNoptarg = argv[GNoptind++]; + else + { + if (GNopterr) + FPRINTF (stderr, _("%s: option `%s' requires an argument\n"), + argv[0], argv[GNoptind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + GNoptarg = nextchar; + GNoptind++; + } + else + GNoptarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + GNoptarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + * we must advance to the next element now. */ + GNoptind++; + } + else if (GNoptind == argc) + { + if (GNopterr) + { + /* 1003.2 specifies the format of this message. */ + FPRINTF (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `GNoptind' once; + * increment it again when taking next ARGV-elt as argument. */ + GNoptarg = argv[GNoptind++]; + nextchar = NULL; + } + } + return c; + } +} + +static int +GNgetopt_long (int argc, char *const *argv, const char *options, + const struct GNoption *long_options, int *opt_index) +{ + return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* ******************** now the GNUnet specific modifications... ********************* */ + +/** + * Parse the command line. + * + * @param binaryOptions Name of application with option summary + * @param allOptions defined options and handlers + * @param argc number of arguments + * @param argv actual arguments + * @return index into argv with first non-option + * argument, or -1 on error + */ +int +GNUNET_GETOPT_run (const char *binaryOptions, + const struct GNUNET_GETOPT_CommandLineOption *allOptions, + unsigned int argc, char *const *argv) +{ + struct GNoption *long_options; + struct GNUNET_GETOPT_CommandLineProcessorContext clpc; + int count; + int i; + char *shorts; + int spos; + int cont; + int c; + + GNUNET_assert (argc > 0); + GNoptind = 0; + clpc.binaryName = argv[0]; + clpc.binaryOptions = binaryOptions; + clpc.allOptions = allOptions; + clpc.argv = argv; + clpc.argc = argc; + count = 0; + while (allOptions[count].name != NULL) + count++; + long_options = GNUNET_malloc (sizeof (struct GNoption) * (count + 1)); + shorts = GNUNET_malloc (count * 2 + 1); + spos = 0; + for (i = 0; i < count; i++) + { + long_options[i].name = allOptions[i].name; + long_options[i].has_arg = allOptions[i].require_argument; + long_options[i].flag = NULL; + long_options[i].val = allOptions[i].shortName; + shorts[spos++] = allOptions[i].shortName; + if (allOptions[i].require_argument != 0) + shorts[spos++] = ':'; + } + long_options[count].name = NULL; + long_options[count].has_arg = 0; + long_options[count].flag = NULL; + long_options[count].val = '\0'; + shorts[spos] = '\0'; + cont = GNUNET_OK; + /* main getopt loop */ + while (cont == GNUNET_OK) + { + int option_index = 0; + + c = GNgetopt_long (argc, argv, shorts, long_options, &option_index); + + if (c == GNUNET_SYSERR) + break; /* No more flags to process */ + + for (i = 0; i < count; i++) + { + clpc.currentArgument = GNoptind - 1; + if ((char) c == allOptions[i].shortName) + { + cont = + allOptions[i].processor (&clpc, allOptions[i].scls, + allOptions[i].name, GNoptarg); + break; + } + } + if (i == count) + { + FPRINTF (stderr, _("Use %s to get a list of options.\n"), "--help"); + cont = GNUNET_SYSERR; + } + } + + GNUNET_free (shorts); + GNUNET_free (long_options); + if (cont == GNUNET_SYSERR) + return GNUNET_SYSERR; + return GNoptind; +} + +/* end of getopt.c */ diff --git a/src/util/getopt_helpers.c b/src/util/getopt_helpers.c new file mode 100644 index 0000000..8fb3673 --- /dev/null +++ b/src/util/getopt_helpers.c @@ -0,0 +1,290 @@ +/* + This file is part of GNUnet + (C) 2006, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/util/getopt_helpers.c + * @brief implements command line that sets option + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_getopt_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + + +/** + * Print out program version (implements --version). + * + * @param ctx command line processing context + * @param scls additional closure (points to version string) + * @param option name of the option + * @param value not used (NULL) + * @return GNUNET_SYSERR (do not continue) + */ +int +GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext + *ctx, void *scls, const char *option, + const char *value) +{ + const char *version = scls; + + printf ("%s v%s\n", ctx->binaryName, version); + return GNUNET_SYSERR; +} + + + +#define BORDER 29 + +/** + * Print out details on command line options (implements --help). + * + * @param ctx command line processing context + * @param scls additional closure (points to about text) + * @param option name of the option + * @param value not used (NULL) + * @return GNUNET_SYSERR (do not continue) + */ +int +GNUNET_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext + *ctx, void *scls, const char *option, + const char *value) +{ + const char *about = scls; + size_t slen; + unsigned int i; + int j; + size_t ml; + size_t p; + char *scp; + const char *trans; + const struct GNUNET_GETOPT_CommandLineOption *opt; + + printf ("%s\n%s\n", ctx->binaryOptions, gettext (about)); + printf (_ + ("Arguments mandatory for long options are also mandatory for short options.\n")); + i = 0; + opt = ctx->allOptions; + while (opt[i].description != NULL) + { + if (opt[i].shortName == '\0') + printf (" "); + else + printf (" -%c, ", opt[i].shortName); + printf ("--%s", opt[i].name); + slen = 8 + strlen (opt[i].name); + if (opt[i].argumentHelp != NULL) + { + printf ("=%s", opt[i].argumentHelp); + slen += 1 + strlen (opt[i].argumentHelp); + } + if (slen > BORDER) + { + printf ("\n%*s", BORDER, ""); + slen = BORDER; + } + if (slen < BORDER) + { + printf ("%*s", (int) (BORDER - slen), ""); + slen = BORDER; + } + if (0 < strlen (opt[i].description)) + trans = gettext (opt[i].description); + else + trans = ""; + ml = strlen (trans); + p = 0; +OUTER: + while (ml - p > 78 - slen) + { + for (j = p + 78 - slen; j > p; j--) + { + if (isspace ((unsigned char) trans[j])) + { + scp = GNUNET_malloc (j - p + 1); + memcpy (scp, &trans[p], j - p); + scp[j - p] = '\0'; + printf ("%s\n%*s", scp, BORDER + 2, ""); + GNUNET_free (scp); + p = j + 1; + slen = BORDER + 2; + goto OUTER; + } + } + /* could not find space to break line */ + scp = GNUNET_malloc (78 - slen + 1); + memcpy (scp, &trans[p], 78 - slen); + scp[78 - slen] = '\0'; + printf ("%s\n%*s", scp, BORDER + 2, ""); + GNUNET_free (scp); + slen = BORDER + 2; + p = p + 78 - slen; + } + /* print rest */ + if (p < ml) + printf ("%s\n", &trans[p]); + if (strlen (trans) == 0) + printf ("\n"); + i++; + } + printf ("Report bugs to gnunet-developers@gnu.org.\n" + "GNUnet home page: http://www.gnu.org/software/gnunet/\n" + "General help using GNU software: http://www.gnu.org/gethelp/\n"); + return GNUNET_SYSERR; +} + + +/** + * Set an option of type 'unsigned int' from the command line. Each + * time the option flag is given, the value is incremented by one. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'int'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'int') + * @param option name of the option + * @param value not used (NULL) + * @return GNUNET_OK + */ +int +GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext + *ctx, void *scls, const char *option, + const char *value) +{ + int *val = scls; + + (*val)++; + return GNUNET_OK; +} + + +/** + * Set an option of type 'int' from the command line to 1 if the + * given option is present. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'int'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'int') + * @param option name of the option + * @param value not used (NULL) + * @return GNUNET_OK + */ +int +GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, + void *scls, const char *option, const char *value) +{ + int *val = scls; + + *val = 1; + return GNUNET_OK; +} + + +/** + * Set an option of type 'char *' from the command line. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'char *'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'char *', + * which will be allocated) + * @param option name of the option + * @param value actual value of the option (a string) + * @return GNUNET_OK + */ +int +GNUNET_GETOPT_set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, + void *scls, const char *option, const char *value) +{ + char **val = scls; + + GNUNET_assert (value != NULL); + GNUNET_free_non_null (*val); + *val = GNUNET_strdup (value); + return GNUNET_OK; +} + + +/** + * Set an option of type 'unsigned long long' from the command line. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'unsigned long long'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'unsigned long long') + * @param option name of the option + * @param value actual value of the option as a string. + * @return GNUNET_OK if parsing the value worked + */ +int +GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, + void *scls, const char *option, const char *value) +{ + unsigned long long *val = scls; + + if (1 != SSCANF (value, "%llu", val)) + { + FPRINTF (stderr, _("You must pass a number to the `%s' option.\n"), option); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Set an option of type 'unsigned int' from the command line. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'unsigned int'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'unsigned int') + * @param option name of the option + * @param value actual value of the option as a string. + * @return GNUNET_OK if parsing the value worked + */ +int +GNUNET_GETOPT_set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, + void *scls, const char *option, const char *value) +{ + unsigned int *val = scls; + + if (1 != SSCANF (value, "%u", val)) + { + FPRINTF (stderr, _("You must pass a number to the `%s' option.\n"), option); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/* end of getopt_helpers.c */ diff --git a/src/util/gnunet-config-diff.c b/src/util/gnunet-config-diff.c new file mode 100644 index 0000000..207b951 --- /dev/null +++ b/src/util/gnunet-config-diff.c @@ -0,0 +1,23 @@ +#include "platform.h" +#include + +int +main (int argc, char **argv) +{ + struct GNUNET_CONFIGURATION_Handle *i1; + struct GNUNET_CONFIGURATION_Handle *i2; + + if (argc != 3) + { + fprintf (stderr, "Invoke using `%s DEFAULTS-IN DIFFS'\n", argv[0]); + return 1; + } + i1 = GNUNET_CONFIGURATION_create (); + i2 = GNUNET_CONFIGURATION_create (); + if ((GNUNET_OK != GNUNET_CONFIGURATION_load (i1, argv[1])) || + (GNUNET_OK != GNUNET_CONFIGURATION_load (i2, argv[2]))) + return 1; + if (GNUNET_OK != GNUNET_CONFIGURATION_write_diffs (i1, i2, argv[2])) + return 2; + return 0; +} diff --git a/src/util/gnunet-resolver.c b/src/util/gnunet-resolver.c new file mode 100644 index 0000000..142dd0d --- /dev/null +++ b/src/util/gnunet-resolver.c @@ -0,0 +1,158 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/gnunet-resolver.c + * @brief tool to test resolver + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_resolver_service.h" + +#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * Flag for reverse lookup. + */ +static int reverse; + + +/** + * Prints each hostname obtained from DNS. + * + * @param cls closure (unused) + * @param hostname one of the names for the host, NULL + * on the last call to the callback + */ +static void +print_hostname (void *cls, + const char *hostname) +{ + if (NULL == hostname) + return; + FPRINTF (stdout, "%s\n", hostname); +} + + +/** + * Callback function to display address. + * + * @param cls closure (unused) + * @param addr one of the addresses of the host, NULL for the last address + * @param addrlen length of the address + */ +static void +print_sockaddr (void *cls, const struct sockaddr *addr, socklen_t addrlen) +{ + if (NULL == addr) + return; + FPRINTF (stdout, "%s\n", GNUNET_a2s (addr, addrlen)); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + const struct sockaddr *sa; + socklen_t salen; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + + if (args[0] == NULL) + return; + if (! reverse) + { + GNUNET_RESOLVER_ip_get (args[0], AF_UNSPEC, GET_TIMEOUT, &print_sockaddr, NULL); + return; + } + + sa = NULL; + memset (&v4, 0, sizeof (v4)); + v4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + v4.sin_len = sizeof (v4); +#endif + if (1 == inet_pton (AF_INET, + args[0], + &v4.sin_addr)) + { + sa = (struct sockaddr *) &v4; + salen = sizeof (v4); + } + memset (&v6, 0, sizeof (v6)); + v6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + v6.sin6_len = sizeof (v6); +#endif + if (1 == inet_pton (AF_INET6, + args[0], + &v6.sin6_addr)) + { + sa = (struct sockaddr *) &v6; + salen = sizeof (v6); + } + if (NULL == sa) + { + fprintf (stderr, + "`%s' is not a valid IP: %s\n", + args[0], + strerror (errno)); + return; + } + GNUNET_RESOLVER_hostname_get (sa, salen, + GNUNET_YES, + GET_TIMEOUT, + &print_hostname, + NULL); +} + +/** + * The main function to obtain statistics in GNUnet. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + { 'r', "reverse", NULL, + gettext_noop ("perform a reverse lookup"), + 0, &GNUNET_GETOPT_set_one, &reverse }, + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-resolver [hostname]", + gettext_noop ("Use build-in GNUnet stub resolver"), + options, &run, NULL)) ? 0 : 1; +} + +/* end of gnunet-resolver.c */ diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c new file mode 100644 index 0000000..f20666a --- /dev/null +++ b/src/util/gnunet-service-resolver.c @@ -0,0 +1,584 @@ +/* + This file is part of GNUnet. + (C) 2007, 2008, 2009, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/gnunet-service-resolver.c + * @brief code to do DNS resolution + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_statistics_service.h" +#include "resolver.h" + +/** + * A cached DNS lookup result. + */ +struct IPCache +{ + /** + * This is a doubly linked list. + */ + struct IPCache *next; + + /** + * This is a doubly linked list. + */ + struct IPCache *prev; + + /** + * Hostname in human-readable form. + */ + char *addr; + + /** + * Binary IP address, allocated at the end of this struct. + */ + const void *ip; + + /** + * Last time this entry was updated. + */ + struct GNUNET_TIME_Absolute last_refresh; + + /** + * Last time this entry was requested. + */ + struct GNUNET_TIME_Absolute last_request; + + /** + * Number of bytes in ip. + */ + size_t ip_len; + + /** + * Address family of the IP. + */ + int af; +}; + + +/** + * Start of the linked list of cached DNS lookup results. + */ +static struct IPCache *cache_head; + +/** + * Tail of the linked list of cached DNS lookup results. + */ +static struct IPCache *cache_tail; + + +#if HAVE_GETNAMEINFO +/** + * Resolve the given request using getnameinfo + * + * @param cache the request to resolve (and where to store the result) + */ +static void +getnameinfo_resolve (struct IPCache *cache) +{ + char hostname[256]; + const struct sockaddr *sa; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + size_t salen; + + switch (cache->af) + { + case AF_INET: + GNUNET_assert (cache->ip_len == sizeof (struct in_addr)); + sa = (const struct sockaddr*) &v4; + memset (&v4, 0, sizeof (v4)); + v4.sin_addr = * (const struct in_addr*) cache->ip; + v4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + v4.sin_len = sizeof (v4); +#endif + salen = sizeof (v4); + break; + case AF_INET6: + GNUNET_assert (cache->ip_len == sizeof (struct in6_addr)); + sa = (const struct sockaddr*) &v6; + memset (&v6, 0, sizeof (v6)); + v6.sin6_addr = * (const struct in6_addr*) cache->ip; + v6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + v6.sin6_len = sizeof (v6); +#endif + salen = sizeof (v6); + break; + default: + GNUNET_assert (0); + } + + if (0 == + getnameinfo (sa, salen, hostname, sizeof (hostname), NULL, + 0, 0)) + cache->addr = GNUNET_strdup (hostname); +} +#endif + + +#if HAVE_GETHOSTBYADDR +/** + * Resolve the given request using gethostbyaddr + * + * @param cache the request to resolve (and where to store the result) + */ +static void +gethostbyaddr_resolve (struct IPCache *cache) +{ + struct hostent *ent; + + ent = gethostbyaddr (cache->ip, + cache->ip_len, + cache->af); + if (ent != NULL) + cache->addr = GNUNET_strdup (ent->h_name); +} +#endif + + +/** + * Resolve the given request using the available methods. + * + * @param cache the request to resolve (and where to store the result) + */ +static void +cache_resolve (struct IPCache *cache) +{ +#if HAVE_GETNAMEINFO + if (cache->addr == NULL) + getnameinfo_resolve (cache); +#endif +#if HAVE_GETHOSTBYADDR + if (cache->addr == NULL) + gethostbyaddr_resolve (cache); +#endif +} + + +/** + * Get an IP address as a string (works for both IPv4 and IPv6). Note + * that the resolution happens asynchronously and that the first call + * may not immediately result in the FQN (but instead in a + * human-readable IP address). + * + * @param client handle to the client making the request (for sending the reply) + * @param af AF_INET or AF_INET6 + * @param ip 'struct in_addr' or 'struct in6_addr' + */ +static void +get_ip_as_string (struct GNUNET_SERVER_Client *client, + int af, + const void *ip) +{ + struct IPCache *pos; + struct IPCache *next; + struct GNUNET_TIME_Absolute now; + struct GNUNET_SERVER_TransmitContext *tc; + size_t ip_len; + + switch (af) + { + case AF_INET: + ip_len = sizeof (struct in_addr); + break; + case AF_INET6: + ip_len = sizeof (struct in6_addr); + break; + default: + GNUNET_assert (0); + } + now = GNUNET_TIME_absolute_get (); + next = cache_head; + while ( (NULL != (pos = next)) && + ( (pos->af != af) || + (pos->ip_len != ip_len) || + (0 != memcmp (pos->ip, ip, ip_len))) ) + { + next = pos->next; + if (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value < + 60 * 60 * 1000) + { + GNUNET_CONTAINER_DLL_remove (cache_head, + cache_tail, + pos); + GNUNET_free_non_null (pos->addr); + GNUNET_free (pos); + continue; + } + } + if (pos != NULL) + { + pos->last_request = now; + if (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value < + 60 * 60 * 1000) + { + GNUNET_free_non_null (pos->addr); + pos->addr = NULL; + cache_resolve (pos); + } + } + else + { + pos = GNUNET_malloc (sizeof (struct IPCache) + ip_len); + pos->ip = &pos[1]; + memcpy (&pos[1], ip, ip_len); + pos->last_request = now; + pos->last_refresh = now; + pos->ip_len = ip_len; + pos->af = af; + GNUNET_CONTAINER_DLL_insert (cache_head, + cache_tail, + pos); + cache_resolve (pos); + } + tc = GNUNET_SERVER_transmit_context_create (client); + if (pos->addr != NULL) + GNUNET_SERVER_transmit_context_append_data (tc, pos->addr, + strlen (pos->addr) + 1, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); +} + + +#if HAVE_GETADDRINFO +static int +getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc, + const char *hostname, int af) +{ + int s; + struct addrinfo hints; + struct addrinfo *result; + struct addrinfo *pos; + + memset (&hints, 0, sizeof (struct addrinfo)); +// FIXME in PlibC +#ifndef MINGW + hints.ai_family = af; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_STREAM; /* go for TCP */ + + if (0 != (s = getaddrinfo (hostname, NULL, &hints, &result))) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Could not resolve `%s' (%s): %s\n"), + hostname, + (af == + AF_INET) ? "IPv4" : ((af == AF_INET6) ? "IPv6" : "any"), + gai_strerror (s)); + if ((s == EAI_BADFLAGS) || (s == EAI_MEMORY) +#ifndef MINGW + || (s == EAI_SYSTEM) +#else + // FIXME NILS + || 1 +#endif + ) + return GNUNET_NO; /* other function may still succeed */ + return GNUNET_SYSERR; + } + if (result == NULL) + return GNUNET_SYSERR; + pos = result; + while (pos != NULL) + { + switch (pos->ai_family) + { + case AF_INET: + GNUNET_SERVER_transmit_context_append_data (tc, + &((struct sockaddr_in*) pos->ai_addr)->sin_addr, + sizeof (struct in_addr), + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + break; + case AF_INET6: + GNUNET_SERVER_transmit_context_append_data (tc, + &((struct sockaddr_in6*) pos->ai_addr)->sin6_addr, + sizeof (struct in6_addr), + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + break; + default: + /* unsupported, skip */ + break; + } + pos = pos->ai_next; + } + freeaddrinfo (result); + return GNUNET_OK; +} +#endif + + +#if HAVE_GETHOSTBYNAME2 +static int +gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc, + const char *hostname, int af) +{ + struct hostent *hp; + int ret1; + int ret2; + + if (af == AF_UNSPEC) + { + ret1 = gethostbyname2_resolve (tc, hostname, AF_INET); + ret2 = gethostbyname2_resolve (tc, hostname, AF_INET6); + if ((ret1 == GNUNET_OK) || (ret2 == GNUNET_OK)) + return GNUNET_OK; + if ((ret1 == GNUNET_SYSERR) || (ret2 == GNUNET_SYSERR)) + return GNUNET_SYSERR; + return GNUNET_NO; + } + hp = gethostbyname2 (hostname, af); + if (hp == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Could not find IP of host `%s': %s\n"), hostname, + hstrerror (h_errno)); + return GNUNET_SYSERR; + } + GNUNET_assert (hp->h_addrtype == af); + switch (af) + { + case AF_INET: + GNUNET_assert (hp->h_length == sizeof (struct in_addr)); + GNUNET_SERVER_transmit_context_append_data (tc, + hp->h_addr_list[0], + hp->h_length, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + break; + case AF_INET6: + GNUNET_assert (hp->h_length == sizeof (struct in6_addr)); + GNUNET_SERVER_transmit_context_append_data (tc, + hp->h_addr_list[0], + hp->h_length, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + break; + default: + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} +#endif + + +#if HAVE_GETHOSTBYNAME +static int +gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc, + const char *hostname) +{ + struct hostent *hp; + + hp = GETHOSTBYNAME (hostname); + if (hp == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Could not find IP of host `%s': %s\n"), hostname, + hstrerror (h_errno)); + return GNUNET_SYSERR; + } + if (hp->h_addrtype != AF_INET) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + GNUNET_assert (hp->h_length == sizeof (struct in_addr)); + GNUNET_SERVER_transmit_context_append_data (tc, + hp->h_addr_list[0], + hp->h_length, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + return GNUNET_OK; +} +#endif + + +/** + * Convert a string to an IP address. + * + * @param client where to send the IP address + * @param hostname the hostname to resolve + * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" + */ +static void +get_ip_from_hostname (struct GNUNET_SERVER_Client *client, const char *hostname, + int af) +{ + int ret; + struct GNUNET_SERVER_TransmitContext *tc; + + tc = GNUNET_SERVER_transmit_context_create (client); + ret = GNUNET_NO; +#if HAVE_GETADDRINFO + if (ret == GNUNET_NO) + ret = getaddrinfo_resolve (tc, hostname, af); +#endif +#if HAVE_GETHOSTBYNAME2 + if (ret == GNUNET_NO) + ret = gethostbyname2_resolve (tc, hostname, af); +#endif +#if HAVE_GETHOSTBYNAME + if ((ret == GNUNET_NO) && ((af == AF_UNSPEC) || (af == PF_INET))) + gethostbyname_resolve (tc, hostname); +#endif + GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); +} + + +/** + * Handle GET-message. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_get (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + uint16_t msize; + const struct GNUNET_RESOLVER_GetMessage *msg; + const void *ip; + uint16_t size; + int direction; + int af; + + msize = ntohs (message->size); + if (msize < sizeof (struct GNUNET_RESOLVER_GetMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msg = (const struct GNUNET_RESOLVER_GetMessage *) message; + size = msize - sizeof (struct GNUNET_RESOLVER_GetMessage); + direction = ntohl (msg->direction); + af = ntohl (msg->af); + if (direction == GNUNET_NO) + { + /* IP from hostname */ + const char *hostname; + + hostname = (const char *) &msg[1]; + if (hostname[size - 1] != '\0') + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver asked to look up `%s'.\n"), + hostname); +#endif + get_ip_from_hostname (client, hostname, af); + return; + } + ip = &msg[1]; + switch (af) + { + case AF_INET: + if (size != sizeof (struct in_addr)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + break; + case AF_INET6: + if (size != sizeof (struct in6_addr)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + break; + default: + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } +#if DEBUG_RESOLVER + { + char buf[INET6_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Resolver asked to look up IP address `%s'.\n"), + inet_ntop (af, ip, buf, sizeof (buf))); + } +#endif + get_ip_as_string (client, af, ip); +} + + +/** + * Process resolver requests. + * + * @param cls closure + * @param server the initialized server + * @param cfg configuration to use + */ +static void +run (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_get, NULL, GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST, 0}, + {NULL, NULL, 0, 0} + }; + GNUNET_SERVER_add_handlers (server, handlers); +} + + +/** + * The main function for the resolver service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + struct IPCache *pos; + int ret; + + ret = + (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "resolver", GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; + while (NULL != (pos = cache_head)) + { + GNUNET_CONTAINER_DLL_remove (cache_head, + cache_tail, + pos); + GNUNET_free_non_null (pos->addr); + GNUNET_free (pos); + } + return ret; +} + +/* end of gnunet-service-resolver.c */ diff --git a/src/util/helper.c b/src/util/helper.c new file mode 100644 index 0000000..43ec23a --- /dev/null +++ b/src/util/helper.c @@ -0,0 +1,506 @@ +/* + This file is part of GNUnet. + (C) 2011, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/helper.c + * @brief API for dealing with (SUID) helper processes that communicate via GNUNET_MessageHeaders on stdin/stdout + * @author Philipp Toelke + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" + + +/** + * Entry in the queue of messages we need to transmit to the helper. + */ +struct HelperMessageQueueEntry +{ + + /** + * This is an entry in a DLL. + */ + struct HelperMessageQueueEntry *next; + + /** + * This is an entry in a DLL. + */ + struct HelperMessageQueueEntry *prev; + + /** + * Message to transmit (allocated at the end of this struct) + */ + const struct GNUNET_MessageHeader *msg; + + /** + * Function to call upon completion. + */ + GNUNET_HELPER_Continuation cont; + + /** + * Closure to 'cont'. + */ + void *cont_cls; + + /** + * Current write position. + */ + unsigned int wpos; + +}; + + +/** + * The handle to a helper process. + */ +struct GNUNET_HELPER_Handle +{ + + /** + * PipeHandle to receive data from the helper + */ + struct GNUNET_DISK_PipeHandle *helper_in; + + /** + * PipeHandle to send data to the helper + */ + struct GNUNET_DISK_PipeHandle *helper_out; + + /** + * FileHandle to receive data from the helper + */ + const struct GNUNET_DISK_FileHandle *fh_from_helper; + + /** + * FileHandle to send data to the helper + */ + const struct GNUNET_DISK_FileHandle *fh_to_helper; + + /** + * The process id of the helper + */ + struct GNUNET_OS_Process *helper_proc; + + /** + * The Message-Tokenizer that tokenizes the messages comming from the helper + */ + struct GNUNET_SERVER_MessageStreamTokenizer *mst; + + /** + * First message queued for transmission to helper. + */ + struct HelperMessageQueueEntry *mq_head; + + /** + * Last message queued for transmission to helper. + */ + struct HelperMessageQueueEntry *mq_tail; + + /** + * Binary to run. + */ + const char *binary_name; + + /** + * NULL-terminated list of command-line arguments. + */ + char *const *binary_argv; + + /** + * Task to read from the helper. + */ + GNUNET_SCHEDULER_TaskIdentifier read_task; + + /** + * Task to read from the helper. + */ + GNUNET_SCHEDULER_TaskIdentifier write_task; + + /** + * Restart task. + */ + GNUNET_SCHEDULER_TaskIdentifier restart_task; +}; + + +/** + * Stop the helper process, we're closing down or had an error. + * + * @param h handle to the helper process + */ +static void +stop_helper (struct GNUNET_HELPER_Handle *h) +{ + struct HelperMessageQueueEntry *qe; + + if (NULL != h->helper_proc) + { + GNUNET_break (0 == GNUNET_OS_process_kill (h->helper_proc, SIGTERM)); + GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (h->helper_proc)); + GNUNET_OS_process_close (h->helper_proc); + h->helper_proc = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != h->restart_task) + { + GNUNET_SCHEDULER_cancel (h->restart_task); + h->restart_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != h->read_task) + { + GNUNET_SCHEDULER_cancel (h->read_task); + h->read_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != h->write_task) + { + GNUNET_SCHEDULER_cancel (h->write_task); + h->write_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != h->helper_in) + { + GNUNET_DISK_pipe_close (h->helper_in); + h->helper_in = NULL; + h->fh_to_helper = NULL; + } + if (NULL != h->helper_out) + { + GNUNET_DISK_pipe_close (h->helper_out); + h->helper_out = NULL; + h->fh_from_helper = NULL; + } + while (NULL != (qe = h->mq_head)) + { + GNUNET_CONTAINER_DLL_remove (h->mq_head, + h->mq_tail, + qe); + if (NULL != qe->cont) + qe->cont (qe->cont_cls, GNUNET_NO); + GNUNET_free (qe); + } + /* purge MST buffer */ + (void) GNUNET_SERVER_mst_receive (h->mst, NULL, NULL, 0, GNUNET_YES, GNUNET_NO); +} + + +/** + * Restart the helper process. + * + * @param cls handle to the helper process + * @param tc scheduler context + */ +static void +restart_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Read from the helper-process + * + * @param cls handle to the helper process + * @param tc scheduler context + */ +static void +helper_read (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_HELPER_Handle *h = cls; + char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE]; + ssize_t t; + + h->read_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + /* try again */ + h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + h->fh_from_helper, &helper_read, h); + return; + } + t = GNUNET_DISK_file_read (h->fh_from_helper, &buf, sizeof (buf)); + if (t < 0) + { + /* On read-error, restart the helper */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Error reading from `%s': %s\n"), + h->binary_name, + STRERROR (errno)); + stop_helper (h); + /* Restart the helper */ + h->restart_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &restart_task, h); + return; + } + if (0 == t) + { + /* this happens if the helper is shut down via a + signal, so it is not a "hard" error */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Got 0 bytes from helper `%s' (EOF)\n"), + h->binary_name); + stop_helper (h); + /* Restart the helper */ + h->restart_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &restart_task, h); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Got %u bytes from helper `%s'\n"), + (unsigned int) t, + h->binary_name); + h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + h->fh_from_helper, &helper_read, h); + if (GNUNET_SYSERR == + GNUNET_SERVER_mst_receive (h->mst, NULL, buf, t, GNUNET_NO, GNUNET_NO)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to parse inbound message from helper `%s'\n"), + h->binary_name); + stop_helper (h); + /* Restart the helper */ + h->restart_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &restart_task, h); + return; + } +} + + +/** + * Start the helper process. + * + * @param h handle to the helper process + */ +static void +start_helper (struct GNUNET_HELPER_Handle *h) +{ + h->helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); + h->helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); + if ( (h->helper_in == NULL) || (h->helper_out == NULL)) + { + /* out of file descriptors? try again later... */ + stop_helper (h); + h->restart_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &restart_task, h); + return; + } + h->fh_from_helper = + GNUNET_DISK_pipe_handle (h->helper_out, GNUNET_DISK_PIPE_END_READ); + h->fh_to_helper = + GNUNET_DISK_pipe_handle (h->helper_in, GNUNET_DISK_PIPE_END_WRITE); + h->helper_proc = + GNUNET_OS_start_process_vap (GNUNET_NO, + h->helper_in, h->helper_out, + h->binary_name, + h->binary_argv); + if (NULL == h->helper_proc) + { + /* failed to start process? try again later... */ + stop_helper (h); + h->restart_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &restart_task, h); + return; + } + GNUNET_DISK_pipe_close_end (h->helper_out, GNUNET_DISK_PIPE_END_WRITE); + GNUNET_DISK_pipe_close_end (h->helper_in, GNUNET_DISK_PIPE_END_READ); + h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + h->fh_from_helper, + &helper_read, + h); +} + + +/** + * Restart the helper process. + * + * @param cls handle to the helper process + * @param tc scheduler context + */ +static void +restart_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_HELPER_Handle*h = cls; + + h->restart_task = GNUNET_SCHEDULER_NO_TASK; + start_helper (h); +} + + +/** + * @brief Starts a helper and begins reading from it + * + * @param binary_name name of the binary to run + * @param binary_argv NULL-terminated list of arguments to give when starting the binary (this + * argument must not be modified by the client for + * the lifetime of the helper h) + * @param cb function to call if we get messages from the helper + * @param cb_cls Closure for the callback + * @return the new H, NULL on error + */ +struct GNUNET_HELPER_Handle* +GNUNET_HELPER_start (const char *binary_name, + char *const binary_argv[], + GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls) +{ + struct GNUNET_HELPER_Handle*h; + + h = GNUNET_malloc (sizeof (struct GNUNET_HELPER_Handle)); + h->binary_name = binary_name; + h->binary_argv = binary_argv; + h->mst = GNUNET_SERVER_mst_create (cb, cb_cls); + start_helper (h); + return h; +} + + +/** + * @brief Kills the helper, closes the pipe and frees the h + * + * @param h h to helper to stop + */ +void +GNUNET_HELPER_stop (struct GNUNET_HELPER_Handle *h) +{ + struct HelperMessageQueueEntry *qe; + + /* signal pending writes that we were stopped */ + while (NULL != (qe = h->mq_head)) + { + GNUNET_CONTAINER_DLL_remove (h->mq_head, + h->mq_tail, + qe); + if (NULL != qe->cont) + qe->cont (qe->cont_cls, GNUNET_SYSERR); + GNUNET_free (qe); + } + stop_helper (h); + GNUNET_SERVER_mst_destroy (h->mst); + GNUNET_free (h); +} + + +/** + * Write to the helper-process + * + * @param cls handle to the helper process + * @param tc scheduler context + */ +static void +helper_write (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_HELPER_Handle *h = cls; + struct HelperMessageQueueEntry *qe; + const char *buf; + ssize_t t; + + h->write_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + /* try again */ + h->write_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + h->fh_to_helper, &helper_write, h); + return; + } + if (NULL == (qe = h->mq_head)) + return; /* how did this happen? */ + buf = (const char*) qe->msg; + t = GNUNET_DISK_file_write (h->fh_to_helper, &buf[qe->wpos], ntohs (qe->msg->size) - qe->wpos); + if (t <= 0) + { + /* On write-error, restart the helper */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Error writing to `%s': %s\n"), + h->binary_name, + STRERROR (errno)); + stop_helper (h); + /* Restart the helper */ + h->restart_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &restart_task, h); + return; + } + qe->wpos += t; + if (qe->wpos == ntohs (qe->msg->size)) + { + GNUNET_CONTAINER_DLL_remove (h->mq_head, + h->mq_tail, + qe); + if (NULL != qe->cont) + qe->cont (qe->cont_cls, GNUNET_YES); + GNUNET_free (qe); + } + if (NULL != h->mq_head) + h->write_task = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + h->fh_to_helper, + &helper_write, + h); +} + + +/** + * Send an message to the helper. + * + * @param h helper to send message to + * @param msg message to send + * @param can_drop can the message be dropped if there is already one in the queue? + * @param cont continuation to run once the message is out (PREREQ_DONE on succees, CANCEL + * if the helper process died, NULL during GNUNET_HELPER_stop). + * @param cont_cls closure for 'cont' + * @return GNUNET_YES if the message will be sent + * GNUNET_NO if the message was dropped + */ +int +GNUNET_HELPER_send (struct GNUNET_HELPER_Handle *h, + const struct GNUNET_MessageHeader *msg, + int can_drop, + GNUNET_HELPER_Continuation cont, + void *cont_cls) +{ + struct HelperMessageQueueEntry *qe; + uint16_t mlen; + + if (NULL == h->fh_to_helper) + return GNUNET_NO; + if ( (GNUNET_YES == can_drop) && + (h->mq_head != NULL) ) + return GNUNET_NO; + mlen = ntohs (msg->size); + qe = GNUNET_malloc (sizeof (struct HelperMessageQueueEntry) + mlen); + qe->msg = (const struct GNUNET_MessageHeader*) &qe[1]; + memcpy (&qe[1], msg, mlen); + qe->cont = cont; + qe->cont_cls = cont_cls; + GNUNET_CONTAINER_DLL_insert_tail (h->mq_head, + h->mq_tail, + qe); + if (GNUNET_SCHEDULER_NO_TASK == h->write_task) + h->write_task = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + h->fh_to_helper, + &helper_write, + h); + + return GNUNET_YES; +} + + +/* end of helper.c */ diff --git a/src/util/load.c b/src/util/load.c new file mode 100644 index 0000000..e978a95 --- /dev/null +++ b/src/util/load.c @@ -0,0 +1,260 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/load.c + * @brief functions related to load calculations + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_load_lib.h" + +#define DEBUG_LOAD GNUNET_EXTRA_LOGGING + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/** + * Values we track for load calculations. + */ +struct GNUNET_LOAD_Value +{ + + /** + * How fast should the load decline if no values are added? + */ + struct GNUNET_TIME_Relative autodecline; + + /** + * Last time this load value was updated by an event. + */ + struct GNUNET_TIME_Absolute last_update; + + /** + * Sum of all datastore delays ever observed (in ms). Note that + * delays above 64k ms are excluded (to avoid overflow within + * first 4 billion requests). + */ + uint64_t cummulative_delay; + + /** + * Sum of squares of all datastore delays ever observed (in ms). Note that + * delays above 64k ms are excluded (to avoid overflow within + * first 4 billion requests). + */ + uint64_t cummulative_squared_delay; + + /** + * Total number of requests included in the cummulative datastore delay values. + */ + uint64_t cummulative_request_count; + + /** + * Current running average datastore delay. Its relation to the + * average datastore delay and it std. dev. (as calcualted from the + * cummulative values) tells us our current load. + */ + double runavg_delay; + + /** + * How high is the load? 0 for below average, otherwise + * the number of std. devs we are above average, or 100 if the + * load is so high that we currently cannot calculate it. + */ + double load; + +}; + + +static void +internal_update (struct GNUNET_LOAD_Value *load) +{ + struct GNUNET_TIME_Relative delta; + unsigned int n; + + if (load->autodecline.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) + return; + delta = GNUNET_TIME_absolute_get_duration (load->last_update); + if (delta.rel_value < load->autodecline.rel_value) + return; + if (load->autodecline.rel_value == 0) + { + load->runavg_delay = 0.0; + load->load = 0; + return; + } + n = delta.rel_value / load->autodecline.rel_value; + if (n > 16) + { + load->runavg_delay = 0.0; + load->load = 0; + return; + } + while (n > 0) + { + n--; + load->runavg_delay = (load->runavg_delay * 7.0) / 8.0; + } +} + + +/** + * Create a new load value. + * + * @param autodecline speed at which this value should automatically + * decline in the absence of external events; at the given + * frequency, 0-load values will be added to the load + * @return the new load value + */ +struct GNUNET_LOAD_Value * +GNUNET_LOAD_value_init (struct GNUNET_TIME_Relative autodecline) +{ + struct GNUNET_LOAD_Value *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_LOAD_Value)); + ret->autodecline = autodecline; + ret->last_update = GNUNET_TIME_absolute_get (); + return ret; +} + + +/** + * Change the value by which the load automatically declines. + * + * @param load load to update + * @param autodecline frequency of load decline + */ +void +GNUNET_LOAD_value_set_decline (struct GNUNET_LOAD_Value *load, + struct GNUNET_TIME_Relative autodecline) +{ + internal_update (load); + load->autodecline = autodecline; +} + + +/** + * Recalculate our load value. + * + * @param load load to update + */ +static void +calculate_load (struct GNUNET_LOAD_Value *load) +{ + double stddev; + double avgdel; + double sum_val_i; + double n; + double nm1; + + if (load->cummulative_request_count <= 1) + return; + /* calcuate std dev of latency; we have for n values of "i" that: + * + * avg = (sum val_i) / n + * stddev = (sum (val_i - avg)^2) / (n-1) + * = (sum (val_i^2 - 2 avg val_i + avg^2) / (n-1) + * = (sum (val_i^2) - 2 avg sum (val_i) + n * avg^2) / (n-1) + */ + sum_val_i = (double) load->cummulative_delay; + n = ((double) load->cummulative_request_count); + nm1 = n - 1.0; + avgdel = sum_val_i / n; + stddev = + (((double) load->cummulative_squared_delay) - 2.0 * avgdel * sum_val_i + + n * avgdel * avgdel) / nm1; + if (stddev <= 0) + stddev = 0.01; /* must have been rounding error or zero; prevent division by zero */ + /* now calculate load based on how far out we are from + * std dev; or if we are below average, simply assume load zero */ + if (load->runavg_delay < avgdel) + load->load = 0.0; + else + load->load = (load->runavg_delay - avgdel) / stddev; +} + + +/** + * Get the current load. + * + * @param load load handle + * @return zero for below-average load, otherwise + * number of std. devs we are above average; + * 100 if the latest updates were so large + * that we could not do proper calculations + */ +double +GNUNET_LOAD_get_load (struct GNUNET_LOAD_Value *load) +{ + internal_update (load); + calculate_load (load); + return load->load; +} + + +/** + * Get the average value given to update so far. + * + * @param load load handle + * @return zero if update was never called + */ +double +GNUNET_LOAD_get_average (struct GNUNET_LOAD_Value *load) +{ + double n; + double sum_val_i; + + internal_update (load); + if (load->cummulative_request_count == 0) + return 0.0; + n = ((double) load->cummulative_request_count); + sum_val_i = (double) load->cummulative_delay; + return sum_val_i / n; +} + + +/** + * Update the current load. + * + * @param load to update + * @param data latest measurement value (for example, delay) + */ +void +GNUNET_LOAD_update (struct GNUNET_LOAD_Value *load, uint64_t data) +{ + uint32_t dv; + + internal_update (load); + load->last_update = GNUNET_TIME_absolute_get (); + if (data > 64 * 1024) + { + /* very large */ + load->load = 100.0; + return; + } + dv = (uint32_t) data; + load->cummulative_delay += dv; + load->cummulative_squared_delay += dv * dv; + load->cummulative_request_count++; + load->runavg_delay = ((load->runavg_delay * 7.0) + dv) / 8.0; +} + + + +/* end of load.c */ diff --git a/src/util/network.c b/src/util/network.c new file mode 100644 index 0000000..e530ab7 --- /dev/null +++ b/src/util/network.c @@ -0,0 +1,1662 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/network.c + * @brief basic, low-level networking interface + * @author Nils Durner + */ + +#include "platform.h" +#include "gnunet_disk_lib.h" +#include "disk.h" +#include "gnunet_container_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#define DEBUG_NETWORK GNUNET_EXTRA_LOGGING + + +#ifndef INVALID_SOCKET +#define INVALID_SOCKET -1 +#endif + + +struct GNUNET_NETWORK_Handle +{ +#ifndef MINGW + int fd; +#else + SOCKET fd; +#endif + + /** + * Address family / domain. + */ + int af; + + /** + * Number of bytes in addr. + */ + socklen_t addrlen; + + /** + * Address we were bound to, or NULL. + */ + struct sockaddr *addr; + +}; + + +#ifndef FD_COPY +#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set))) +#endif + + +/** + * Set if a socket should use blocking or non-blocking IO. + * @param fd socket + * @param doBlock blocking mode + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock) +{ + +#if MINGW + u_long mode; + + mode = !doBlock; + if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR) + + { + SetErrnoFromWinsockError (WSAGetLastError ()); + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket"); + return GNUNET_SYSERR; + } + return GNUNET_OK; + +#else + /* not MINGW */ + int flags = fcntl (fd->fd, F_GETFL); + + if (flags == -1) + + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "fcntl"); + return GNUNET_SYSERR; + } + if (doBlock) + flags &= ~O_NONBLOCK; + + else + flags |= O_NONBLOCK; + if (0 != fcntl (fd->fd, F_SETFL, flags)) + + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "fcntl"); + return GNUNET_SYSERR; + } + return GNUNET_OK; +#endif +} + + +#ifndef MINGW +/** + * Make a socket non-inheritable to child processes + * + * @param h the socket to make non-inheritable + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + * @warning Not implemented on Windows + */ +static int +socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h) +{ + int i; + + i = fcntl (h->fd, F_GETFD); + if (i < 0) + return GNUNET_SYSERR; + if (i == (i | FD_CLOEXEC)) + return GNUNET_OK; + i |= FD_CLOEXEC; + if (fcntl (h->fd, F_SETFD, i) < 0) + return GNUNET_SYSERR; + return GNUNET_OK; +} +#endif + + +#ifdef DARWIN +/** + * The MSG_NOSIGNAL equivalent on Mac OS X + * + * @param h the socket to make non-delaying + */ +static void +socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h) +{ + int abs_value = 1; + + if (0 != + setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &abs_value, + sizeof (abs_value))) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); +} +#endif + + +/** + * Disable delays when sending data via the socket. + * (GNUnet makes sure that messages are as big as + * possible already). + * + * @param h the socket to make non-delaying + */ +static void +socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h) +{ +#ifndef WINDOWS + int value = 1; + + if (0 != setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof (value))) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); +#else + const char *abs_value = "1"; + + if (0 != + setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, abs_value, + sizeof (abs_value))) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); +#endif +} + + +/** + * accept a new connection on a socket + * + * @param desc bound socket + * @param address address of the connecting peer, may be NULL + * @param address_len length of address + * @return client socket + */ +struct GNUNET_NETWORK_Handle * +GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc, + struct sockaddr *address, socklen_t * address_len) +{ + struct GNUNET_NETWORK_Handle *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); +#if DEBUG_NETWORK + { + struct sockaddr name; + socklen_t namelen = sizeof (name); + int gsn = getsockname (desc->fd, &name, &namelen); + + if (gsn == 0) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Accepting connection on `%s'\n", + GNUNET_a2s (&name, namelen)); + } +#endif + ret->fd = accept (desc->fd, address, address_len); + if (address != NULL) + ret->af = address->sa_family; + else + ret->af = desc->af; + if (ret->fd == INVALID_SOCKET) + { +#ifdef MINGW + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + GNUNET_free (ret); + return NULL; + } +#ifndef MINGW + if (ret->fd >= FD_SETSIZE) + { + GNUNET_break (0 == close (ret->fd)); + GNUNET_free (ret); + errno = EMFILE; + return NULL; + } +#endif + if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO)) + + { + + /* we might want to treat this one as fatal... */ + GNUNET_break (0); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret)); + return NULL; + } + +#ifndef MINGW + if (GNUNET_OK != socket_set_inheritable (ret)) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "socket_set_inheritable"); +#endif +#ifdef DARWIN + socket_set_nosigpipe (ret); +#endif +#ifdef AF_UNIX + if (ret->af != AF_UNIX) +#endif + socket_set_nodelay (ret); + return ret; +} + + +/** + * Bind to a connected socket + * @param desc socket + * @param address address to be bound + * @param address_len length of address + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc, + const struct sockaddr *address, + socklen_t address_len) +{ + int ret; + +#ifdef IPV6_V6ONLY +#ifdef IPPROTO_IPV6 + const int on = 1; + + if (desc->af == AF_INET6) + if (0 != setsockopt (desc->fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on))) + LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "setsockopt"); +#endif +#endif +#ifndef WINDOWS + /* This is required, and required here, but only on UNIX */ + if (0 != setsockopt (desc->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on))) + LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "setsockopt"); +#endif +#ifndef LINUX +#ifndef MINGW + if (address->sa_family == AF_UNIX) + { + const struct sockaddr_un *un = (const struct sockaddr_un *) address; + + (void) unlink (un->sun_path); + } +#endif +#endif + ret = bind (desc->fd, address, address_len); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + if (ret != 0) + return GNUNET_SYSERR; +#ifndef MINGW +#ifndef LINUX + desc->addr = GNUNET_malloc (address_len); + memcpy (desc->addr, address, address_len); + desc->addrlen = address_len; +#endif +#endif + return GNUNET_OK; +} + + +/** + * Close a socket + * @param desc socket + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc) +{ + int ret; + +#ifdef MINGW + DWORD error = 0; + + SetLastError (0); + ret = closesocket (desc->fd); + error = WSAGetLastError (); + SetErrnoFromWinsockError (error); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Closed 0x%x, closesocket() returned %d, GLE is %u\n", desc->fd, ret, + error); +#else + ret = close (desc->fd); +#endif +#ifndef LINUX +#ifndef MINGW + if ((desc->af == AF_UNIX) && (NULL != desc->addr)) + { + const struct sockaddr_un *un = (const struct sockaddr_un *) desc->addr; + + if (0 != unlink (un->sun_path)) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", un->sun_path); + } +#endif +#endif + GNUNET_free_non_null (desc->addr); + GNUNET_free (desc); + return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR; +} + + +/** + * Box a native socket (and check that it is a socket). + * + * @param fd socket to box + * @return NULL on error (including not supported on target platform) + */ +struct GNUNET_NETWORK_Handle * +GNUNET_NETWORK_socket_box_native (SOCKTYPE fd) +{ + struct GNUNET_NETWORK_Handle *ret; +#if MINGW + unsigned long i; + DWORD d; + /* FIXME: Find a better call to check that FD is valid */ + if (WSAIoctl (fd, FIONBIO, (void *) &i, sizeof (i), NULL, 0, &d, NULL, NULL) != 0) + return NULL; /* invalid FD */ + ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); + ret->fd = fd; + ret->af = AF_UNSPEC; + return ret; +#else + if (fcntl (fd, F_GETFD) < 0) + return NULL; /* invalid FD */ + ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); + ret->fd = fd; + ret->af = AF_UNSPEC; + return ret; +#endif +} + + +/** + * Connect a socket + * @param desc socket + * @param address peer address + * @param address_len length of address + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc, + const struct sockaddr *address, + socklen_t address_len) +{ + int ret; + + ret = connect (desc->fd, address, address_len); + +#ifdef MINGW + if (SOCKET_ERROR == ret) + { + SetErrnoFromWinsockError (WSAGetLastError ()); + if (errno == EWOULDBLOCK) + errno = EINPROGRESS; + } +#endif + return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; +} + + +/** + * Get socket options + * + * @param desc socket + * @param level protocol level of the option + * @param optname identifier of the option + * @param optval options + * @param optlen length of optval + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc, + int level, int optname, void *optval, + socklen_t * optlen) +{ + int ret; + + ret = getsockopt (desc->fd, level, optname, optval, optlen); + +#ifdef MINGW + if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR) + *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval)); + + else if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; +} + + +/** + * Listen on a socket + * @param desc socket + * @param backlog length of the listen queue + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, + int backlog) +{ + int ret; + + ret = listen (desc->fd, backlog); + +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); + +#endif + return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; +} + + +/** + * How much data is available to be read on this descriptor? + * + * Returns GNUNET_NO if no data is available, or on error! + * @param desc socket + */ +ssize_t +GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle * + desc) +{ + int error; + + /* How much is there to be read? */ +#ifndef WINDOWS + int pending; + + error = ioctl (desc->fd, FIONREAD, &pending); + if (error == 0) +#else + u_long pending; + + error = ioctlsocket (desc->fd, FIONREAD, &pending); + if (error != SOCKET_ERROR) +#endif + return pending; + else + return GNUNET_NO; +} + + +/** + * Read data from a connected socket (always non-blocking). + * @param desc socket + * @param buffer buffer + * @param length length of buffer + * @param src_addr either the source to recv from, or all zeroes + * to be filled in by recvfrom + * @param addrlen length of the addr + */ +ssize_t +GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle * desc, + void *buffer, size_t length, + struct sockaddr * src_addr, socklen_t * addrlen) +{ + int ret; + int flags; + + flags = 0; + +#ifdef MSG_DONTWAIT + flags |= MSG_DONTWAIT; + +#endif + ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + return ret; +} + + +/** + * Read data from a connected socket (always non-blocking). + * @param desc socket + * @param buffer buffer + * @param length length of buffer + */ +ssize_t +GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc, + void *buffer, size_t length) +{ + int ret; + int flags; + + flags = 0; + +#ifdef MSG_DONTWAIT + flags |= MSG_DONTWAIT; +#endif + ret = recv (desc->fd, buffer, length, flags); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + return ret; +} + + +/** + * Send data (always non-blocking). + * + * @param desc socket + * @param buffer data to send + * @param length size of the buffer + * @return number of bytes sent, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle * desc, + const void *buffer, size_t length) +{ + int ret; + int flags; + + flags = 0; + +#ifdef MSG_DONTWAIT + flags |= MSG_DONTWAIT; + +#endif +#ifdef MSG_NOSIGNAL + flags |= MSG_NOSIGNAL; + +#endif + ret = send (desc->fd, buffer, length, flags); + +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); + +#endif + return ret; +} + + +/** + * Send data to a particular destination (always non-blocking). + * This function only works for UDP sockets. + * + * @param desc socket + * @param message data to send + * @param length size of the data + * @param dest_addr destination address + * @param dest_len length of address + * @return number of bytes sent, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle * desc, + const void *message, size_t length, + const struct sockaddr * dest_addr, + socklen_t dest_len) +{ + int ret; + int flags; + + flags = 0; + +#ifdef MSG_DONTWAIT + flags |= MSG_DONTWAIT; +#endif +#ifdef MSG_NOSIGNAL + flags |= MSG_NOSIGNAL; +#endif + ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + return ret; +} + + +/** + * Set socket option + * @param fd socket + * @param level protocol level of the option + * @param option_name option identifier + * @param option_value value to set + * @param option_len size of option_value + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd, int level, + int option_name, const void *option_value, + socklen_t option_len) +{ + int ret; + + ret = setsockopt (fd->fd, level, option_name, option_value, option_len); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; +} + + +/** + * Create a new socket. Configure it for non-blocking IO and + * mark it as non-inheritable to child processes (set the + * close-on-exec flag). + * + * @param domain domain of the socket + * @param type socket type + * @param protocol network protocol + * @return new socket, NULL on error + */ +struct GNUNET_NETWORK_Handle * +GNUNET_NETWORK_socket_create (int domain, int type, int protocol) +{ + struct GNUNET_NETWORK_Handle *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); + ret->af = domain; + ret->fd = socket (domain, type, protocol); + if (INVALID_SOCKET == ret->fd) + { +#ifdef MINGW + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + GNUNET_free (ret); + return NULL; + } + +#ifndef MINGW + if (ret->fd >= FD_SETSIZE) + { + GNUNET_break (0 == close (ret->fd)); + GNUNET_free (ret); + errno = EMFILE; + return NULL; + } + +#endif + if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO)) + { + /* we might want to treat this one as fatal... */ + GNUNET_break (0); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret)); + return NULL; + } + +#ifndef MINGW + if (GNUNET_OK != socket_set_inheritable (ret)) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "socket_set_inheritable"); +#endif +#ifdef DARWIN + socket_set_nosigpipe (ret); +#endif + if ((type == SOCK_STREAM) +#ifdef AF_UNIX + && (domain != AF_UNIX) +#endif + ) + socket_set_nodelay (ret); + return ret; +} + + +/** + * Shut down socket operations + * @param desc socket + * @param how type of shutdown + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, int how) +{ + int ret; + + ret = shutdown (desc->fd, how); +#ifdef MINGW + if (ret != 0) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; +} + + +/** + * Disable the "CORK" feature for communication with the given socket, + * forcing the OS to immediately flush the buffer on transmission + * instead of potentially buffering multiple messages. Essentially + * reduces the OS send buffers to zero. + * + * @param desc socket + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_NETWORK_socket_disable_corking (struct GNUNET_NETWORK_Handle *desc) +{ + int ret = 0; + +#if WINDOWS + int value = 0; + + if (0 != + (ret = + setsockopt (desc->fd, SOL_SOCKET, SO_SNDBUF, (char *) &value, + sizeof (value)))) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); + if (0 != + (ret = + setsockopt (desc->fd, SOL_SOCKET, SO_RCVBUF, (char *) &value, + sizeof (value)))) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); +#elif LINUX + int value = 0; + + if (0 != + (ret = + setsockopt (desc->fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof (value)))) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); + if (0 != + (ret = + setsockopt (desc->fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof (value)))) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); +#endif + return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; +} + + +/** + * Reset FD set + * @param fds fd set + */ +void +GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds) +{ + FD_ZERO (&fds->sds); + fds->nsds = 0; +#ifdef MINGW + GNUNET_CONTAINER_slist_clear (fds->handles); +#endif +} + +/** + * Add a socket to the FD set + * @param fds fd set + * @param desc socket to add + */ +void +GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_NETWORK_Handle *desc) +{ + FD_SET (desc->fd, &fds->sds); + if (desc->fd + 1 > fds->nsds) + fds->nsds = desc->fd + 1; +} + + +/** + * Check whether a socket is part of the fd set + * @param fds fd set + * @param desc socket + * @return 0 if the FD is not set + */ +int +GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_NETWORK_Handle *desc) +{ + return FD_ISSET (desc->fd, &fds->sds); +} + + +/** + * Add one fd set to another + * @param dst the fd set to add to + * @param src the fd set to add from + */ +void +GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst, + const struct GNUNET_NETWORK_FDSet *src) +{ + int nfds; + + for (nfds = src->nsds; nfds > 0; nfds--) + if (FD_ISSET (nfds, &src->sds)) + + { + FD_SET (nfds, &dst->sds); + if (nfds + 1 > dst->nsds) + dst->nsds = nfds + 1; + } +#ifdef MINGW + GNUNET_CONTAINER_slist_append (dst->handles, src->handles); +#endif +} + + +/** + * Copy one fd set to another + * + * @param to destination + * @param from source + */ +void +GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, + const struct GNUNET_NETWORK_FDSet *from) +{ + FD_COPY (&from->sds, &to->sds); + to->nsds = from->nsds; + +#ifdef MINGW + GNUNET_CONTAINER_slist_clear (to->handles); + GNUNET_CONTAINER_slist_append (to->handles, from->handles); +#endif +} + + +/** + * Return file descriptor for this network handle + * + * @param desc wrapper to process + * @return POSIX file descriptor + */ +int +GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc) +{ + return desc->fd; +} + + +/** + * Copy a native fd set + * + * @param to destination + * @param from native source set + * @param nfds the biggest socket number in from + 1 + */ +void +GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to, + const fd_set * from, int nfds) +{ + FD_COPY (from, &to->sds); + to->nsds = nfds; +} + + +/** + * Set a native fd in a set + * + * @param to destination + * @param nfd native FD to set + */ +void +GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to, int nfd) +{ + GNUNET_assert ((nfd >= 0) && (nfd < FD_SETSIZE)); + FD_SET (nfd, &to->sds); + to->nsds = GNUNET_MAX (nfd + 1, to->nsds); +} + + +/** + * Test native fd in a set + * + * @param to set to test, NULL for empty set + * @param nfd native FD to test, or -1 for none + * @return GNUNET_YES if FD is set in the set + */ +int +GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to, + int nfd) +{ + if ((nfd == -1) || (to == NULL)) + return GNUNET_NO; + return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO; +} + + +/** + * Add a file handle to the fd set + * @param fds fd set + * @param h the file handle to add + */ +void +GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_DISK_FileHandle *h) +{ +#ifdef MINGW + GNUNET_CONTAINER_slist_add (fds->handles, + GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, h, + sizeof (struct GNUNET_DISK_FileHandle)); + +#else + int fd; + + GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int)); + FD_SET (fd, &fds->sds); + if (fd + 1 > fds->nsds) + fds->nsds = fd + 1; + +#endif +} + + +/** + * Check if a file handle is part of an fd set + * @param fds fd set + * @param h file handle + * @return GNUNET_YES if the file handle is part of the set + */ +int +GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_DISK_FileHandle *h) +{ + +#ifdef MINGW + return GNUNET_CONTAINER_slist_contains (fds->handles, h, + sizeof (struct + GNUNET_DISK_FileHandle)); +#else + return FD_ISSET (h->fd, &fds->sds); +#endif +} + + +/** + * Checks if two fd sets overlap + * @param fds1 first fd set + * @param fds2 second fd set + * @return GNUNET_YES if they do overlap, GNUNET_NO otherwise + */ +int +GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1, + const struct GNUNET_NETWORK_FDSet *fds2) +{ +#ifndef MINGW + int nfds; + + nfds = fds1->nsds; + if (nfds > fds2->nsds) + nfds = fds2->nsds; + while (nfds > 0) + { + nfds--; + if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds)) + return GNUNET_YES; + } +#else + struct GNUNET_CONTAINER_SList_Iterator it; + struct GNUNET_DISK_FileHandle *h; + int i; + int j; + + /*This code is somewhat hacky, we are not supposed to know what's + * inside of fd_set; also the O(n^2) is really bad... */ + + for (i = 0; i < fds1->sds.fd_count; i++) + { + for (j = 0; j < fds2->sds.fd_count; j++) + { + if (fds1->sds.fd_array[i] == fds2->sds.fd_array[j]) + return GNUNET_YES; + } + } + it = GNUNET_CONTAINER_slist_begin (fds1->handles); + while (GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES) + { +#if DEBUG_NETWORK + struct GNUNET_CONTAINER_SList_Iterator t; +#endif + h = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&it, + NULL); +#if DEBUG_NETWORK + LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking that FD 0x%x is in another set:\n", + h->h); + for (t = GNUNET_CONTAINER_slist_begin (fds2->handles); + GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES; + GNUNET_CONTAINER_slist_next (&t)) + { + struct GNUNET_DISK_FileHandle *fh; + + fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t, + NULL); + LOG (GNUNET_ERROR_TYPE_DEBUG, "0x%x\n", fh->h); + } +#endif + if (GNUNET_CONTAINER_slist_contains + (fds2->handles, h, sizeof (struct GNUNET_DISK_FileHandle))) + { +#if DEBUG_NETWORK + LOG (GNUNET_ERROR_TYPE_DEBUG, "Match!\n"); +#endif + return GNUNET_YES; + } + GNUNET_CONTAINER_slist_next (&it); + } +#endif + return GNUNET_NO; +} + + +/** + * Creates an fd set + * @return a new fd set + */ +struct GNUNET_NETWORK_FDSet * +GNUNET_NETWORK_fdset_create () +{ + struct GNUNET_NETWORK_FDSet *fds; + + fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet)); +#ifdef MINGW + fds->handles = GNUNET_CONTAINER_slist_create (); +#endif + GNUNET_NETWORK_fdset_zero (fds); + return fds; +} + + +/** + * Releases the associated memory of an fd set + * @param fds fd set + */ +void +GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds) +{ +#ifdef MINGW + GNUNET_CONTAINER_slist_destroy (fds->handles); +#endif + GNUNET_free (fds); +} + +/** + * Check if sockets meet certain conditions + * @param rfds set of sockets to be checked for readability + * @param wfds set of sockets to be checked for writability + * @param efds set of sockets to be checked for exceptions + * @param timeout relative value when to return + * @return number of selected sockets, GNUNET_SYSERR on error + */ +int +GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, + struct GNUNET_NETWORK_FDSet *wfds, + struct GNUNET_NETWORK_FDSet *efds, + const struct GNUNET_TIME_Relative timeout) +{ + int nfds = 0; + +#ifdef MINGW + int handles = 0; + int ex_handles = 0; + int read_handles = 0; + int write_handles = 0; + + int i = 0; + int retcode = 0; + DWORD ms_total = 0; + + int nsock = 0, nhandles = 0, nSockEvents = 0; + + static HANDLE hEventRead = 0; + static HANDLE hEventWrite = 0; + static HANDLE hEventException = 0; + static HANDLE hEventPipeWrite = 0; + static HANDLE hEventReadReady = 0; + + int readPipes = 0; + int writePipePos = 0; + + HANDLE handle_array[FD_SETSIZE + 2]; + int returncode = -1; + DWORD newretcode = 0; + int returnedpos = 0; + + struct GNUNET_CONTAINER_SList *handles_read, *handles_write, *handles_except; + + fd_set aread, awrite, aexcept; + +#if DEBUG_NETWORK + fd_set bread, bwrite, bexcept; +#endif + + /* TODO: Make this growable */ + struct GNUNET_DISK_FileHandle *readArray[50]; +#else + struct timeval tv; +#endif + if (NULL != rfds) + { + nfds = rfds->nsds; +#ifdef MINGW + handles += read_handles = GNUNET_CONTAINER_slist_count (rfds->handles); +#if DEBUG_NETWORK + { + struct GNUNET_CONTAINER_SList_Iterator t; + + for (t = GNUNET_CONTAINER_slist_begin (rfds->handles); + GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES; + GNUNET_CONTAINER_slist_next (&t)) + { + struct GNUNET_DISK_FileHandle *fh; + + fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t, + NULL); + LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x (0x%x) is SET in rfds\n", fh->h, + fh); + } + } +#endif +#endif + } + if (NULL != wfds) + { + nfds = GNUNET_MAX (nfds, wfds->nsds); +#ifdef MINGW + handles += write_handles = GNUNET_CONTAINER_slist_count (wfds->handles); +#endif + } + if (NULL != efds) + { + nfds = GNUNET_MAX (nfds, efds->nsds); +#ifdef MINGW + handles += ex_handles = GNUNET_CONTAINER_slist_count (efds->handles); +#endif + } + + if ((nfds == 0) && + (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) +#ifdef MINGW + && handles == 0 +#endif + ) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _ + ("Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"), + "select"); + GNUNET_break (0); + } +#ifndef MINGW + tv.tv_sec = timeout.rel_value / GNUNET_TIME_UNIT_SECONDS.rel_value; + tv.tv_usec = + 1000 * (timeout.rel_value - + (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value)); + return select (nfds, (rfds != NULL) ? &rfds->sds : NULL, + (wfds != NULL) ? &wfds->sds : NULL, + (efds != NULL) ? &efds->sds : NULL, + (timeout.rel_value == + GNUNET_TIME_UNIT_FOREVER_REL.rel_value) ? NULL : &tv); + +#else +#define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set)) + /* calculate how long we need to wait in milliseconds */ + if (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) + ms_total = INFINITE; + else + ms_total = timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value; + /* select() may be used as a portable way to sleep */ + if (!(rfds || wfds || efds)) + { + Sleep (ms_total); + return 0; + } + + /* Events for sockets */ + if (!hEventRead) + hEventRead = CreateEvent (NULL, TRUE, FALSE, NULL); + else + ResetEvent (hEventRead); + if (!hEventReadReady) + hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL); + if (!hEventWrite) + hEventWrite = CreateEvent (NULL, TRUE, FALSE, NULL); + else + ResetEvent (hEventWrite); + if (!hEventException) + hEventException = CreateEvent (NULL, TRUE, FALSE, NULL); + else + ResetEvent (hEventException); + + /* Event for pipes */ + if (!hEventPipeWrite) + hEventPipeWrite = CreateEvent (NULL, TRUE, TRUE, NULL); + readPipes = 0; + writePipePos = -1; + + handles_read = GNUNET_CONTAINER_slist_create (); + handles_write = GNUNET_CONTAINER_slist_create (); + handles_except = GNUNET_CONTAINER_slist_create (); + FD_ZERO (&aread); + FD_ZERO (&awrite); + FD_ZERO (&aexcept); +#if DEBUG_NETWORK + FD_ZERO (&bread); + FD_ZERO (&bwrite); + FD_ZERO (&bexcept); +#endif + if (rfds) + { + FD_COPY (&rfds->sds, &aread); +#if DEBUG_NETWORK + FD_COPY (&rfds->sds, &bread); +#endif + } + if (wfds) + { + FD_COPY (&wfds->sds, &awrite); +#if DEBUG_NETWORK + FD_COPY (&wfds->sds, &bwrite); +#endif + } + if (efds) + { + FD_COPY (&efds->sds, &aexcept); +#if DEBUG_NETWORK + FD_COPY (&efds->sds, &bexcept); +#endif + } + /* We will first Add the PIPES to the events */ + /* Read Pipes */ + if (rfds && read_handles) + { + struct GNUNET_CONTAINER_SList_Iterator i; + + for (i = GNUNET_CONTAINER_slist_begin (rfds->handles); + GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES; + GNUNET_CONTAINER_slist_next (&i)) + { + struct GNUNET_DISK_FileHandle *fh; + + fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i, + NULL); + if (fh->type == GNUNET_PIPE) + { + /* Read zero bytes to check the status of the pipe */ + LOG (GNUNET_ERROR_TYPE_DEBUG, "Reading 0 bytes from the pipe 0x%x\n", + fh->h); + if (!ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead)) + { + DWORD error_code = GetLastError (); + + if (error_code == ERROR_IO_PENDING) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding the pipe's 0x%x overlapped event to the array as %d\n", + fh->h, nhandles); + handle_array[nhandles++] = fh->oOverlapRead->hEvent; + readArray[readPipes++] = fh; + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Read failed, adding the read ready event to the array as %d\n", nhandles); + handle_array[nhandles++] = hEventReadReady; + readArray[readPipes++] = fh; + } + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding the read ready event to the array as %d\n", nhandles); + handle_array[nhandles++] = hEventReadReady; + readArray[readPipes++] = fh; + } + } + else + { + GNUNET_CONTAINER_slist_add (handles_read, + GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, + fh, sizeof (struct GNUNET_DISK_FileHandle)); + } + } + } + if (wfds && write_handles) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding the write ready event to the array as %d\n", nhandles); + handle_array[nhandles++] = hEventPipeWrite; + writePipePos = nhandles; + } + if (efds && ex_handles) + { + struct GNUNET_CONTAINER_SList_Iterator i; + + for (i = GNUNET_CONTAINER_slist_begin (efds->handles); + GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES; + GNUNET_CONTAINER_slist_next (&i)) + { + struct GNUNET_DISK_FileHandle *fh; + DWORD dwBytes; + + fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i, + NULL); + if (fh->type == GNUNET_PIPE) + { + if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL)) + { + GNUNET_CONTAINER_slist_add (handles_except, + GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, + fh, + sizeof (struct GNUNET_DISK_FileHandle)); + newretcode++; + } + } + } + } + if (nfds > 0) + { + if (rfds) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding the socket read event to the array as %d\n", nhandles); + handle_array[nhandles++] = hEventRead; + nSockEvents++; + for (i = 0; i < rfds->sds.fd_count; i++) + { + WSAEventSelect (rfds->sds.fd_array[i], hEventRead, + FD_ACCEPT | FD_READ | FD_CLOSE); + nsock++; + } + } + if (wfds) + { + int wakeup = 0; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding the socket write event to the array as %d\n", nhandles); + handle_array[nhandles++] = hEventWrite; + nSockEvents++; + for (i = 0; i < wfds->sds.fd_count; i++) + { + DWORD error; + int status; + + status = send (wfds->sds.fd_array[i], NULL, 0, 0); + error = GetLastError (); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "pre-send to the socket %d returned %d (%u)\n", i, status, error); + if (status == 0 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN)) + wakeup = 1; + WSAEventSelect (wfds->sds.fd_array[i], hEventWrite, + FD_WRITE | FD_CONNECT | FD_CLOSE); + nsock++; + } + if (wakeup) + SetEvent (hEventWrite); + } + if (efds) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding the socket error event to the array as %d\n", nhandles); + handle_array[nhandles++] = hEventException; + nSockEvents++; + for (i = 0; i < efds->sds.fd_count; i++) + { + WSAEventSelect (efds->sds.fd_array[i], hEventException, + FD_OOB | FD_CLOSE); + nsock++; + } + } + } + + handle_array[nhandles] = NULL; + +#if DEBUG_NETWORK + LOG (GNUNET_ERROR_TYPE_DEBUG, "Number nfds : %d\n", nfds); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Number of handles : %d\n", nhandles); + LOG (GNUNET_ERROR_TYPE_DEBUG, "retcode : %d\n", newretcode); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Will wait : %d\n", ms_total); +#endif + + if (nhandles) + returncode = + WaitForMultipleObjects (nhandles, handle_array, FALSE, ms_total); +#if DEBUG_NETWORK + LOG (GNUNET_ERROR_TYPE_DEBUG, "WaitForMultipleObjects Returned : %d\n", + returncode); +#endif + + returnedpos = returncode - WAIT_OBJECT_0; + LOG (GNUNET_ERROR_TYPE_DEBUG, "return pos is : %d\n", returnedpos); + + /* FIXME: THIS LINE IS WRONG !! We should add to handles only handles that fired the events, not all ! */ + /* + * if(rfds) + * GNUNET_CONTAINER_slist_append (handles_read, rfds->handles); + */ + if (nhandles && (returnedpos < nhandles)) + { + DWORD waitstatus; + + /* Do the select */ + if (nfds) + { + struct timeval tvslice; + + tvslice.tv_sec = 0; + tvslice.tv_usec = 10; + retcode = select (nfds, &aread, &awrite, &aexcept, &tvslice); + if (retcode == -1) + retcode = 0; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Select retcode : %d\n", retcode); + } + /* FIXME: <= writePipePos? Really? */ + if ((writePipePos != -1) && (returnedpos <= writePipePos)) + { + GNUNET_CONTAINER_slist_append (handles_write, wfds->handles); + retcode += write_handles; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Added write pipe\n"); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "ReadPipes is : %d\n", readPipes); + /* We have some pipes ready for read. */ + /* FIXME: it is supposed to work !! Only choose the Pipes who fired the event, but it is not working */ + + if (returnedpos < readPipes) + { + /* + * for (i = 0; i < readPipes; i++) + * { + * waitstatus = WaitForSingleObject (handle_array[i], 0); + * LOG (GNUNET_ERROR_TYPE_DEBUG, "Read pipe %d wait status is : %d\n", i, waitstatus); + * if (waitstatus != WAIT_OBJECT_0) + * continue; + * GNUNET_CONTAINER_slist_add (handles_read, + * GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, + * readArray[i], sizeof (struct GNUNET_DISK_FileHandle)); + * retcode++; + * LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe\n"); + * } + */ + for (i = 0; i < readPipes; i++) + { + DWORD error; + BOOL bret; + + SetLastError (0); + waitstatus = 0; + bret = + PeekNamedPipe (readArray[i]->h, NULL, 0, NULL, &waitstatus, NULL); + error = GetLastError (); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n", + i, readArray[i]->h, bret, waitstatus, error); + if (bret == 0) + { + if (error != ERROR_BROKEN_PIPE) + continue; + } + else if (waitstatus <= 0) + continue; + GNUNET_CONTAINER_slist_add (handles_read, + GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, + readArray[i], + sizeof (struct GNUNET_DISK_FileHandle)); + retcode++; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n", + readArray[i], readArray[i]->h); + } + } + waitstatus = WaitForSingleObject (hEventWrite, 0); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Wait for the write event returned %d\n", + waitstatus); + if (waitstatus == WAIT_OBJECT_0) + { + for (i = 0; i < wfds->sds.fd_count; i++) + { + DWORD error; + int status; + int so_error = 0; + int sizeof_so_error = sizeof (so_error); + int gso_result = + getsockopt (wfds->sds.fd_array[i], SOL_SOCKET, SO_ERROR, + (char *) &so_error, &sizeof_so_error); + + status = send (wfds->sds.fd_array[i], NULL, 0, 0); + error = GetLastError (); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "send to the socket %d returned %d (%u)\n", i, status, error); + if (status == 0 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN) || + (status == -1 && gso_result == 0 && error == WSAENOTCONN && + so_error == WSAECONNREFUSED)) + { + FD_SET (wfds->sds.fd_array[i], &awrite); + retcode += 1; + } + } + } + } +#if DEBUG_NETWORK + if (!nhandles || (returnedpos >= nhandles)) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning from _select() with nothing!\n"); +#endif + if (rfds) + { + struct GNUNET_CONTAINER_SList_Iterator t; + + for (i = 0; i < rfds->sds.fd_count; i++) + { + WSAEventSelect (rfds->sds.fd_array[i], hEventRead, 0); + nsock++; + } + for (t = GNUNET_CONTAINER_slist_begin (rfds->handles); + GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES; + GNUNET_CONTAINER_slist_next (&t)) + { + struct GNUNET_DISK_FileHandle *fh; + + fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t, + NULL); + if (fh->type == GNUNET_PIPE) + { + CancelIo (fh->h); + } + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing rfds\n"); + GNUNET_NETWORK_fdset_zero (rfds); + if (retcode != -1 && nhandles && (returnedpos < nhandles)) + GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode); + GNUNET_CONTAINER_slist_append (rfds->handles, handles_read); + } + if (wfds) + { + for (i = 0; i < wfds->sds.fd_count; i++) + { + WSAEventSelect (wfds->sds.fd_array[i], hEventWrite, 0); + nsock++; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing wfds\n"); + GNUNET_NETWORK_fdset_zero (wfds); + if (retcode != -1 && nhandles && (returnedpos < nhandles)) + GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode); + GNUNET_CONTAINER_slist_append (wfds->handles, handles_write); + } + if (efds) + { + for (i = 0; i < efds->sds.fd_count; i++) + { + WSAEventSelect (efds->sds.fd_array[i], hEventException, 0); + nsock++; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing efds\n"); + GNUNET_NETWORK_fdset_zero (efds); + if (retcode != -1 && nhandles && (returnedpos < nhandles)) + GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode); + GNUNET_CONTAINER_slist_append (efds->handles, handles_except); + } + GNUNET_CONTAINER_slist_destroy (handles_read); + GNUNET_CONTAINER_slist_destroy (handles_write); + GNUNET_CONTAINER_slist_destroy (handles_except); +#if DEBUG_NETWORK + if (rfds) + { + struct GNUNET_CONTAINER_SList_Iterator t; + + for (i = 0; i < bread.fd_count; i++) + { + if (bread.fd_array[i] != 0) + LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is %s in rfds\n", + bread.fd_array[i], + (SAFE_FD_ISSET (bread.fd_array[i], rfds)) ? "SET" : "NOT SET"); + } + for (t = GNUNET_CONTAINER_slist_begin (rfds->handles); + GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES; + GNUNET_CONTAINER_slist_next (&t)) + { + struct GNUNET_DISK_FileHandle *fh; + + fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t, + NULL); + LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is SET in rfds\n", fh->h); + } + } + if (wfds) + { + for (i = 0; i < bwrite.fd_count; i++) + { + if (bwrite.fd_array[i] != 0) + LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is %s in wfds\n", + bwrite.fd_array[i], + (SAFE_FD_ISSET (bwrite.fd_array[i], rfds)) ? "SET" : "NOT SET"); + } + } + if (efds) + { + for (i = 0; i < bexcept.fd_count; i++) + { + if (bexcept.fd_array[i] != 0) + LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is %s in efds\n", + bexcept.fd_array[i], + (SAFE_FD_ISSET (bexcept.fd_array[i], rfds)) ? "SET" : "NOT SET"); + } + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning %d or 0\n", retcode); +#endif + if (nhandles && (returnedpos < nhandles)) + return retcode; + else +#endif + return 0; +} + +/* end of network.c */ diff --git a/src/util/os_installation.c b/src/util/os_installation.c new file mode 100644 index 0000000..b82813d --- /dev/null +++ b/src/util/os_installation.c @@ -0,0 +1,538 @@ +/* + This file is part of GNUnet. + (C) 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/util/os_installation.c + * @brief get paths used by the program + * @author Milan + */ +#include +#include +#include +#include + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_disk_lib.h" +#include "gnunet_os_lib.h" +#if DARWIN +#include +#include +#endif + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +#if LINUX +/** + * Try to determine path by reading /proc/PID/exe + */ +static char * +get_path_from_proc_maps () +{ + char fn[64]; + char line[1024]; + char dir[1024]; + FILE *f; + char *lgu; + + GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ()); + f = FOPEN (fn, "r"); + if (f == NULL) + return NULL; + while (NULL != fgets (line, sizeof (line), f)) + { + if ((1 == + sscanf (line, "%*x-%*x %*c%*c%*c%*c %*x %*2u:%*2u %*u%*[ ]%s", dir)) && + (NULL != (lgu = strstr (dir, "libgnunetutil")))) + { + lgu[0] = '\0'; + FCLOSE (f); + return GNUNET_strdup (dir); + } + } + FCLOSE (f); + return NULL; +} + +/** + * Try to determine path by reading /proc/PID/exe + */ +static char * +get_path_from_proc_exe () +{ + char fn[64]; + char lnk[1024]; + ssize_t size; + + GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/exe", getpid ()); + size = readlink (fn, lnk, sizeof (lnk) - 1); + if (size <= 0) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn); + return NULL; + } + GNUNET_assert (size < sizeof (lnk)); + lnk[size] = '\0'; + while ((lnk[size] != '/') && (size > 0)) + size--; + if ((size < 4) || (lnk[size - 4] != '/')) + { + /* not installed in "/bin/" -- binary path probably useless */ + return NULL; + } + lnk[size] = '\0'; + return GNUNET_strdup (lnk); +} +#endif + +#if WINDOWS +/** + * Try to determine path with win32-specific function + */ +static char * +get_path_from_module_filename () +{ + wchar_t path[4097]; + char upath[4097]; + wchar_t *idx; + + GetModuleFileNameW (NULL, path, sizeof (path) - 1); + idx = path + wcslen (path); + while ((idx > path) && (*idx != L'\\') && (*idx != L'/')) + idx--; + *idx = L'\0'; + upath[0] = '\0'; + WideCharToMultiByte (CP_UTF8, 0, path, -1, upath, 4097, NULL, NULL); + + return GNUNET_strdup (upath); +} +#endif + +#if DARWIN +typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize); + +static char * +get_path_from_NSGetExecutablePath () +{ + static char zero = '\0'; + char *path; + size_t len; + MyNSGetExecutablePathProto func; + int ret; + + path = NULL; + func = + (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath"); + if (!func) + return NULL; + path = &zero; + len = 0; + /* get the path len, including the trailing \0 */ + func (path, &len); + if (len == 0) + return NULL; + path = GNUNET_malloc (len); + ret = func (path, &len); + if (ret != 0) + { + GNUNET_free (path); + return NULL; + } + len = strlen (path); + while ((path[len] != '/') && (len > 0)) + len--; + path[len] = '\0'; + return path; +} + +static char * +get_path_from_dyld_image () +{ + const char *path; + char *p, *s; + int i; + int c; + + p = NULL; + c = _dyld_image_count (); + for (i = 0; i < c; i++) + { + if (_dyld_get_image_header (i) == &_mh_dylib_header) + { + path = _dyld_get_image_name (i); + if (path != NULL && strlen (path) > 0) + { + p = GNUNET_strdup (path); + s = p + strlen (p); + while ((s > p) && (*s != '/')) + s--; + s++; + *s = '\0'; + } + break; + } + } + return p; +} +#endif + +/** + * Return the actual path to a file found in the current + * PATH environment variable. + * + * @param binary the name of the file to find + * @return path to binary, NULL if not found + */ +static char * +get_path_from_PATH (const char *binary) +{ + char *path; + char *pos; + char *end; + char *buf; + const char *p; + + p = getenv ("PATH"); + if (p == NULL) + return NULL; + path = GNUNET_strdup (p); /* because we write on it */ + buf = GNUNET_malloc (strlen (path) + 20); + pos = path; + while (NULL != (end = strchr (pos, PATH_SEPARATOR))) + { + *end = '\0'; + sprintf (buf, "%s/%s", pos, binary); + if (GNUNET_DISK_file_test (buf) == GNUNET_YES) + { + pos = GNUNET_strdup (pos); + GNUNET_free (buf); + GNUNET_free (path); + return pos; + } + pos = end + 1; + } + sprintf (buf, "%s/%s", pos, binary); + if (GNUNET_DISK_file_test (buf) == GNUNET_YES) + { + pos = GNUNET_strdup (pos); + GNUNET_free (buf); + GNUNET_free (path); + return pos; + } + GNUNET_free (buf); + GNUNET_free (path); + return NULL; +} + +static char * +get_path_from_GNUNET_PREFIX () +{ + const char *p; + + p = getenv ("GNUNET_PREFIX"); + if (p != NULL) + return GNUNET_strdup (p); + return NULL; +} + +/** + * @brief get the path to GNUnet bin/ or lib/, prefering the lib/ path + * @author Milan + * + * @return a pointer to the executable path, or NULL on error + */ +static char * +os_get_gnunet_path () +{ + char *ret; + + ret = get_path_from_GNUNET_PREFIX (); + if (ret != NULL) + return ret; +#if LINUX + ret = get_path_from_proc_maps (); + if (ret != NULL) + return ret; + ret = get_path_from_proc_exe (); + if (ret != NULL) + return ret; +#endif +#if WINDOWS + ret = get_path_from_module_filename (); + if (ret != NULL) + return ret; +#endif +#if DARWIN + ret = get_path_from_dyld_image (); + if (ret != NULL) + return ret; + ret = get_path_from_NSGetExecutablePath (); + if (ret != NULL) + return ret; +#endif + ret = get_path_from_PATH ("gnunet-arm"); + if (ret != NULL) + return ret; + /* other attempts here */ + LOG (GNUNET_ERROR_TYPE_ERROR, + _ + ("Could not determine installation path for %s. Set `%s' environment variable.\n"), + "GNUnet", "GNUNET_PREFIX"); + return NULL; +} + +/* + * @brief get the path to current app's bin/ + * @author Milan + * + * @return a pointer to the executable path, or NULL on error + */ +static char * +os_get_exec_path () +{ + char *ret; + + ret = NULL; +#if LINUX + ret = get_path_from_proc_exe (); + if (ret != NULL) + return ret; +#endif +#if WINDOWS + ret = get_path_from_module_filename (); + if (ret != NULL) + return ret; +#endif +#if DARWIN + ret = get_path_from_NSGetExecutablePath (); + if (ret != NULL) + return ret; +#endif + /* other attempts here */ + return ret; +} + + + +/** + * @brief get the path to a specific GNUnet installation directory or, + * with GNUNET_IPK_SELF_PREFIX, the current running apps installation directory + * @author Milan + * @return a pointer to the dir path (to be freed by the caller) + */ +char * +GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind) +{ + size_t n; + const char *dirname; + char *execpath = NULL; + char *tmp; + int isbasedir; + + /* if wanted, try to get the current app's bin/ */ + if (dirkind == GNUNET_OS_IPK_SELF_PREFIX) + execpath = os_get_exec_path (); + + /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some + * guess for the current app */ + if (execpath == NULL) + execpath = os_get_gnunet_path (); + + if (execpath == NULL) + return NULL; + + n = strlen (execpath); + if (n == 0) + { + /* should never happen, but better safe than sorry */ + GNUNET_free (execpath); + return NULL; + } + /* remove filename itself */ + while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR)) + execpath[--n] = '\0'; + + isbasedir = 1; + if ((n > 5) && + ((0 == strcasecmp (&execpath[n - 5], "lib32")) || + (0 == strcasecmp (&execpath[n - 5], "lib64")))) + { + if (dirkind != GNUNET_OS_IPK_LIBDIR) + { + /* strip '/lib32' or '/lib64' */ + execpath[n - 5] = '\0'; + n -= 5; + } + else + isbasedir = 0; + } + else if ((n > 3) && + ((0 == strcasecmp (&execpath[n - 3], "bin")) || + (0 == strcasecmp (&execpath[n - 3], "lib")))) + { + /* strip '/bin' or '/lib' */ + execpath[n - 3] = '\0'; + n -= 3; + } + /* in case this was a directory named foo-bin, remove "foo-" */ + while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR)) + execpath[--n] = '\0'; + switch (dirkind) + { + case GNUNET_OS_IPK_PREFIX: + case GNUNET_OS_IPK_SELF_PREFIX: + dirname = DIR_SEPARATOR_STR; + break; + case GNUNET_OS_IPK_BINDIR: + dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR; + break; + case GNUNET_OS_IPK_LIBDIR: + if (isbasedir) + dirname = + DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR; + else + dirname = DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR; + break; + case GNUNET_OS_IPK_DATADIR: + dirname = + DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR; + break; + case GNUNET_OS_IPK_LOCALEDIR: + dirname = + DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale" DIR_SEPARATOR_STR; + break; + case GNUNET_OS_IPK_ICONDIR: + dirname = + DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR; + break; + case GNUNET_OS_IPK_DOCDIR: + dirname = + DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \ + "gnunet" DIR_SEPARATOR_STR; + break; + default: + GNUNET_free (execpath); + return NULL; + } + tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1); + sprintf (tmp, "%s%s", execpath, dirname); + GNUNET_free (execpath); + return tmp; +} + + +/** + * Check whether an executable exists and possibly + * if the suid bit is set on the file. + * Attempts to find the file using the current + * PATH environment variable as a search path. + * + * @param binary the name of the file to check + * @return GNUNET_YES if the file is SUID, + * GNUNET_NO if not SUID (but binary exists) + * GNUNET_SYSERR on error (no such binary or not executable) + */ +int +GNUNET_OS_check_helper_binary (const char *binary) +{ + struct stat statbuf; + char *p; + char *pf; + +#ifdef MINGW + SOCKET rawsock; + char *binaryexe; + + GNUNET_asprintf (&binaryexe, "%s.exe", binary); + p = get_path_from_PATH (binaryexe); + if (p != NULL) + { + GNUNET_asprintf (&pf, "%s/%s", p, binaryexe); + GNUNET_free (p); + p = pf; + } + GNUNET_free (binaryexe); +#else + p = get_path_from_PATH (binary); + if (p != NULL) + { + GNUNET_asprintf (&pf, "%s/%s", p, binary); + GNUNET_free (p); + p = pf; + } +#endif + if (p == NULL) + { + LOG (GNUNET_ERROR_TYPE_INFO, _("Could not find binary `%s' in PATH!\n"), + binary); + return GNUNET_SYSERR; + } + if (0 != ACCESS (p, X_OK)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, _("access (%s, X_OK) failed: %s\n"), p, + STRERROR (errno)); + GNUNET_free (p); + return GNUNET_SYSERR; + } +#ifndef MINGW + if (0 == getuid ()) + { + /* as we run as root, we don't insist on SUID */ + GNUNET_free (p); + return GNUNET_OK; + } +#endif + if (0 != STAT (p, &statbuf)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, _("stat (%s) failed: %s\n"), p, + STRERROR (errno)); + GNUNET_free (p); + return GNUNET_SYSERR; + } +#ifndef MINGW + if ((0 != (statbuf.st_mode & S_ISUID)) && (statbuf.st_uid == 0)) + { + GNUNET_free (p); + return GNUNET_YES; + } + /* binary exists, but not SUID */ + GNUNET_free (p); + return GNUNET_NO; +#else + GNUNET_free (p); + rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (INVALID_SOCKET == rawsock) + { + DWORD err = GetLastError (); + + LOG (GNUNET_ERROR_TYPE_INFO, + "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) failed! GLE = %d\n", err); + return GNUNET_NO; /* not running as administrator */ + } + closesocket (rawsock); + return GNUNET_YES; +#endif +} + + +/* end of os_installation.c */ diff --git a/src/util/os_network.c b/src/util/os_network.c new file mode 100644 index 0000000..b0490ef --- /dev/null +++ b/src/util/os_network.c @@ -0,0 +1,270 @@ +/* + This file is part of GNUnet. + (C) 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +/** + * @file util/os_network.c + * @brief function to determine available network interfaces + * @author Nils Durner + * @author Heikki Lindholm + * @author Jake Dust + * @author LRN + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_os_lib.h" + + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +/** + * @brief Enumerate all network interfaces + * + * @param proc the callback function + * @param proc_cls closure for proc + */ +void +GNUNET_OS_network_interfaces_list (GNUNET_OS_NetworkInterfaceProcessor proc, + void *proc_cls) +{ +#ifdef MINGW + int r; + int i; + struct EnumNICs3_results *results = NULL; + int results_count; + + r = EnumNICs3 (&results, &results_count); + if (r != GNUNET_OK) + return; + + for (i = 0; i < results_count; i++) + { + if (GNUNET_OK != + proc (proc_cls, results[i].pretty_name, results[i].is_default, + (const struct sockaddr *) &results[i].address, + results[i]. + flags & ENUMNICS3_BCAST_OK ? + (const struct sockaddr *) &results[i].broadcast : NULL, + results[i].flags & ENUMNICS3_MASK_OK ? + (const struct sockaddr *) &results[i].mask : NULL, + results[i].addr_size)) + break; + } + EnumNICs3_free (results); + return; + +#elif HAVE_GETIFADDRS && HAVE_FREEIFADDRS + + struct ifaddrs *ifa_first; + struct ifaddrs *ifa_ptr; + socklen_t alen; + + if (getifaddrs (&ifa_first) == 0) + { + for (ifa_ptr = ifa_first; ifa_ptr != NULL; ifa_ptr = ifa_ptr->ifa_next) + { + if (ifa_ptr->ifa_name != NULL && ifa_ptr->ifa_addr != NULL && + (ifa_ptr->ifa_flags & IFF_UP) != 0) + { + if ((ifa_ptr->ifa_addr->sa_family != AF_INET) && + (ifa_ptr->ifa_addr->sa_family != AF_INET6)) + continue; + if (ifa_ptr->ifa_addr->sa_family == AF_INET) + alen = sizeof (struct sockaddr_in); + else + alen = sizeof (struct sockaddr_in6); + if (GNUNET_OK != + proc (proc_cls, ifa_ptr->ifa_name, + 0 == strcmp (ifa_ptr->ifa_name, GNUNET_DEFAULT_INTERFACE), + ifa_ptr->ifa_addr, ifa_ptr->ifa_broadaddr, + ifa_ptr->ifa_netmask, alen)) + break; + } + } + freeifaddrs (ifa_first); + } +#else + int i; + char line[1024]; + char *replace; + const char *start; + char ifc[12]; + char addrstr[128]; + char bcstr[128]; + char netmaskstr[128]; + FILE *f; + int have_ifc; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + struct in_addr v4; + struct in6_addr v6; + struct sockaddr_in bcaddr; + struct sockaddr_in netmask; + struct sockaddr_in6 netmask6; + struct sockaddr *pass_bcaddr; + struct sockaddr *pass_netmask; + int prefixlen; + + if (system ("ifconfig -a > /dev/null 2> /dev/null")) + if (system ("/sbin/ifconfig -a > /dev/null 2> /dev/null") == 0) + f = popen ("/sbin/ifconfig -a 2> /dev/null", "r"); + else + f = NULL; + else + f = popen ("ifconfig -a 2> /dev/null", "r"); + if (!f) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "popen", "ifconfig"); + return; + } + + have_ifc = GNUNET_NO; + ifc[11] = '\0'; + while (NULL != fgets (line, sizeof (line), f)) + { + if (strlen (line) == 0) + { + have_ifc = GNUNET_NO; + continue; + } + if (!isspace (line[0])) + { + have_ifc = (1 == SSCANF (line, "%11s", ifc)) ? GNUNET_YES : GNUNET_NO; + /* would end with ':' on OSX, fix it! */ + if (ifc[strlen (ifc) - 1] == ':') + ifc[strlen (ifc) - 1] = '\0'; + continue; + } + if (!have_ifc) + continue; /* strange input, hope for the best */ + + /* make parsing of ipv6 addresses easier */ + for (replace = line; *replace != '\0'; replace++) + { + if (*replace == '/') + *replace = ' '; + } + prefixlen = -1; + + start = line; + while (('\0' != *start) && (isspace (*start))) + start++; + + /* Zero-out stack allocated values */ + memset (addrstr, 0, 128); + memset (netmaskstr, 0, 128); + memset (bcstr, 0, 128); + prefixlen = 0; + + if ( /* Linux */ + (3 == SSCANF (start, "inet addr:%127s Bcast:%127s Mask:%127s", addrstr, bcstr, netmaskstr)) || + (2 == SSCANF (start, "inet addr:%127s Mask:%127s", addrstr, netmaskstr)) || + (2 == SSCANF (start, "inet6 addr:%127s %d", addrstr, &prefixlen)) || + /* Solaris, OS X */ + (1 == SSCANF (start, "inet %127s", addrstr)) || + (1 == SSCANF (start, "inet6 %127s", addrstr))) + { + /* IPv4 */ + if (1 == inet_pton (AF_INET, addrstr, &v4)) + { + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + a4.sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + a4.sin_addr = v4; + + pass_bcaddr = NULL; + pass_netmask = NULL; + if (1 == inet_pton (AF_INET, bcstr, &v4)) + { + memset (&bcaddr, 0, sizeof (bcaddr)); + bcaddr.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + bcaddr.sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + bcaddr.sin_addr = v4; + pass_bcaddr = (struct sockaddr *) &bcaddr; + } + if (1 == inet_pton (AF_INET, netmaskstr, &v4)) + { + memset (&netmask, 0, sizeof (netmask)); + netmask.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + netmask.sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + netmask.sin_addr = v4; + pass_netmask = (struct sockaddr *) &netmask; + } + + + if (GNUNET_OK != + proc (proc_cls, ifc, 0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE), + (const struct sockaddr *) &a4, + pass_bcaddr, pass_netmask, sizeof (a4))) + break; + continue; + } + /* IPv6 */ + if (1 == inet_pton (AF_INET6, addrstr, &v6)) + { + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + a6.sin6_len = (u_char) sizeof (struct sockaddr_in6); +#endif + a6.sin6_addr = v6; + + pass_netmask = NULL; + if (prefixlen != -1) + { + memset (v6.s6_addr, 0, sizeof (v6.s6_addr)); + for (i = 0; i < prefixlen; i++) + { + v6.s6_addr[i >> 3] |= 1 << (i & 7); + } + memset (&netmask6, 0, sizeof (netmask6)); + netmask6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + netmask6.sin6_len = (u_char) sizeof (struct sockaddr_in6); +#endif + netmask6.sin6_addr = v6; + + pass_netmask = (struct sockaddr *) &netmask6; + } + + if (GNUNET_OK != + proc (proc_cls, ifc, 0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE), + (const struct sockaddr *) &a6, + NULL, pass_netmask, sizeof (a6))) + break; + continue; + } + } + } + pclose (f); +#endif +} + + +/* end of os_network.c */ diff --git a/src/util/os_priority.c b/src/util/os_priority.c new file mode 100644 index 0000000..a1f173a --- /dev/null +++ b/src/util/os_priority.c @@ -0,0 +1,1826 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/os_priority.c + * @brief Methods to set process priority + * @author Nils Durner + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_os_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_strings_lib.h" +#include "gnunet_crypto_lib.h" +#include "disk.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +#define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE" + +struct GNUNET_OS_Process +{ + /** + * PID of the process. + */ + pid_t pid; + +#if WINDOWS + /** + * Process handle. + */ + HANDLE handle; +#endif + + /** + * Pipe we use to signal the process (if used). + */ + struct GNUNET_DISK_FileHandle *control_pipe; + + /** + * Name of the pipe, NULL for none. + */ + char *childpipename; +}; + + +/** + * Handle for 'this' process. + */ +static struct GNUNET_OS_Process current_process; + + +/* MinGW version of named pipe API */ +#ifdef MINGW +/** + * Creates a named pipe/FIFO and opens it + * + * @param fn pointer to the name of the named pipe or to NULL + * @param flags open flags + * @param perm access permissions + * @return pipe handle on success, NULL on error + */ +static struct GNUNET_DISK_FileHandle * +npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags, + enum GNUNET_DISK_AccessPermissions perm) +{ + struct GNUNET_DISK_FileHandle *ret; + HANDLE h = NULL; + DWORD openMode; + char *name; + + openMode = 0; + if (flags & GNUNET_DISK_OPEN_READWRITE) + openMode = PIPE_ACCESS_DUPLEX; + else if (flags & GNUNET_DISK_OPEN_READ) + openMode = PIPE_ACCESS_INBOUND; + else if (flags & GNUNET_DISK_OPEN_WRITE) + openMode = PIPE_ACCESS_OUTBOUND; + if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS) + openMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; + + while (h == NULL) + { + DWORD error_code; + + name = NULL; + if (*fn != NULL) + { + GNUNET_asprintf (&name, "\\\\.\\pipe\\%.246s", fn); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Trying to create an instance of named pipe `%s'\n", name); + /* 1) This might work just fine with UTF-8 strings as it is. + * 2) This is only used by GNUnet itself, and only with latin names. + */ + h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, + NULL); + } + else + { + GNUNET_asprintf (fn, "\\\\.\\pipe\\gnunet-%llu", + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to create unique named pipe `%s'\n", + *fn); + h = CreateNamedPipe (*fn, + openMode | FILE_FLAG_OVERLAPPED | + FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, + NULL); + } + error_code = GetLastError (); + if (name) + GNUNET_free (name); + /* don't re-set name to NULL yet */ + if (h == INVALID_HANDLE_VALUE) + { + SetErrnoFromWinError (error_code); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Pipe creation have failed because of %d, errno is %d\n", error_code, + errno); + if (name == NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Pipe was to be unique, considering re-creation\n"); + GNUNET_free (*fn); + *fn = NULL; + if (error_code != ERROR_ACCESS_DENIED && error_code != ERROR_PIPE_BUSY) + { + return NULL; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Pipe name was not unique, trying again\n"); + h = NULL; + } + else + return NULL; + } + } + errno = 0; + + ret = GNUNET_malloc (sizeof (*ret)); + ret->h = h; + ret->type = GNUNET_PIPE; + ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); + ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); + ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + return ret; +} + + +/** + * Opens already existing named pipe/FIFO + * + * @param fn name of an existing named pipe + * @param flags open flags + * @return pipe handle on success, NULL on error + */ +static struct GNUNET_DISK_FileHandle * +npipe_open (const char *fn, enum GNUNET_DISK_OpenFlags flags) +{ + struct GNUNET_DISK_FileHandle *ret; + HANDLE h; + DWORD openMode; + + openMode = 0; + if (flags & GNUNET_DISK_OPEN_READWRITE) + openMode = GENERIC_WRITE | GENERIC_READ; + else if (flags & GNUNET_DISK_OPEN_READ) + openMode = GENERIC_READ; + else if (flags & GNUNET_DISK_OPEN_WRITE) + openMode = GENERIC_WRITE; + + h = CreateFile (fn, openMode, 0, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL); + if (h == INVALID_HANDLE_VALUE) + { + SetErrnoFromWinError (GetLastError ()); + return NULL; + } + + ret = GNUNET_malloc (sizeof (*ret)); + ret->h = h; + ret->type = GNUNET_PIPE; + ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); + ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); + ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + + return ret; +} + +#else +/* UNIX version of named-pipe API */ + +/** + * Clean up a named pipe and the directory it was placed in. + * + * @param fn name of the pipe + */ +static void +cleanup_npipe (const char *fn) +{ + char *dn; + char *dp; + + if (0 != unlink (fn)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); + dn = GNUNET_strdup (fn); + dp = dirname (dn); + if (0 != rmdir (dp)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dp); + GNUNET_free (dn); +} + + +/** + * Setup a named pipe. + * + * @param fn where to store the name of the new pipe, + * if *fn is non-null, the name of the pipe to setup + * @return GNUNET_OK on success + */ +static int +npipe_setup (char **fn) +{ + if (NULL == *fn) + { + /* FIXME: hardwired '/tmp' path... is bad */ + char dir[] = "/tmp/gnunet-pipe-XXXXXX"; + + if (NULL == mkdtemp (dir)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "mkdtemp"); + return GNUNET_SYSERR; + } + GNUNET_asprintf (fn, "%s/child-control", dir); + } + if (-1 == mkfifo (*fn, S_IRUSR | S_IWUSR)) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Open an existing named pipe. + * + * @param fn name of the file + * @param flags flags to use + * @return NULL on error + */ +static struct GNUNET_DISK_FileHandle * +npipe_open (const char *fn, + enum GNUNET_DISK_OpenFlags flags) +{ + struct GNUNET_DISK_FileHandle *ret; + int fd; + struct timespec req; + int i; + + /* 200 * 5ms = 1s at most */ + for (i=0;i<200;i++) + { + fd = open (fn, O_NONBLOCK | ((flags == GNUNET_DISK_OPEN_READ) ? O_RDONLY : O_WRONLY)); + if ( (-1 != fd) || (9 == i) || (flags == GNUNET_DISK_OPEN_READ)) + break; + /* as this is for killing a child process via pipe and it is conceivable that + the child process simply didn't finish starting yet, we do some sleeping + (which is obviously usually not allowed). We can't select on the FD as + 'open' fails, and we probably shouldn't just "ignore" the error, so wait + and retry a few times is likely the best method; our process API doesn't + support continuations, so we need to sleep directly... */ + req.tv_sec = 0; + req.tv_nsec = 5000000; /* 5ms */ + (void) nanosleep (&req, NULL); + } + if (-1 == fd) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + (flags == GNUNET_DISK_OPEN_READ) + ? _("Failed to open named pipe `%s' for reading: %s\n") + : _("Failed to open named pipe `%s' for writing: %s\n"), + fn, + STRERROR (errno)); + return NULL; + } + ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); + ret->fd = fd; + return ret; +} +#endif + + +/** + * This handler is called when there are control data to be read on the pipe + * + * @param cls the 'struct GNUNET_DISK_FileHandle' of the control pipe + * @param tc scheduler context + */ +static void +parent_control_handler (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_DISK_FileHandle *control_pipe = cls; + int sig; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION__, + tc->reason); + if (tc->reason & + (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | + GNUNET_SCHEDULER_REASON_PREREQ_DONE)) + { + GNUNET_DISK_file_close (control_pipe); + return; + } + if (GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig)) != + sizeof (sig)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read"); + GNUNET_DISK_file_close (control_pipe); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n", sig); + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + control_pipe, &parent_control_handler, + control_pipe); + raise (sig); +} + + +/** + * Task that connects this process to its parent via pipe; + * essentially, the parent control handler will read signal numbers + * from the 'GNUNET_OS_CONTROL_PIPE' (as given in an environment + * variable) and raise those signals. + * + * @param cls closure (unused) + * @param tc scheduler context (unused) + */ +void +GNUNET_OS_install_parent_control_handler (void *cls, + const struct + GNUNET_SCHEDULER_TaskContext *tc) +{ + const char *env_buf; + struct GNUNET_DISK_FileHandle *control_pipe; + + env_buf = getenv (GNUNET_OS_CONTROL_PIPE); + if ( (env_buf == NULL) || (strlen (env_buf) <= 0) ) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Not installing a handler because $%s is empty\n", + GNUNET_OS_CONTROL_PIPE); + putenv ("GNUNET_OS_CONTROL_PIPE="); + return; + } + control_pipe = + npipe_open (env_buf, GNUNET_DISK_OPEN_READ); + if (NULL == control_pipe) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf); + putenv ("GNUNET_OS_CONTROL_PIPE="); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding parent control handler pipe `%s' to the scheduler\n", env_buf); + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe, + &parent_control_handler, control_pipe); + putenv ("GNUNET_OS_CONTROL_PIPE="); +} + + +/** + * Get process structure for current process + * + * The pointer it returns points to static memory location and must not be + * deallocated/closed + * + * @return pointer to the process sturcutre for this process + */ +struct GNUNET_OS_Process * +GNUNET_OS_process_current () +{ +#if WINDOWS + current_process.pid = GetCurrentProcessId (); + current_process.handle = GetCurrentProcess (); +#else + current_process.pid = 0; +#endif + return ¤t_process; +} + + +/** + * Sends a signal to the process + * + * @param proc pointer to process structure + * @param sig signal + * @return 0 on success, -1 on error + */ +int +GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig) +{ + int ret; + +#if !WINDOWS + if ( (NULL == proc->control_pipe) && + (NULL != proc->childpipename) ) + proc->control_pipe = npipe_open (proc->childpipename, + GNUNET_DISK_OPEN_WRITE); +#endif + if (NULL == proc->control_pipe) + { +#if WINDOWS + /* no pipe and windows? can't do this */ + errno = EINVAL; + return -1; +#else + return kill (proc->pid, sig); +#endif + } + ret = GNUNET_DISK_file_write (proc->control_pipe, &sig, sizeof (sig)); + if (ret == sizeof (sig)) + return 0; + /* pipe failed, try other methods */ + switch (sig) + { +#if !WINDOWS + case SIGHUP: +#endif + case SIGINT: + case SIGKILL: + case SIGTERM: +#if WINDOWS && !defined(__CYGWIN__) + if (0 == TerminateProcess (proc->handle, 0)) + { + /* FIXME: set 'errno' */ + return -1; + } + return 0; +#else + return PLIBC_KILL (proc->pid, sig); +#endif + default: +#if WINDOWS + errno = EINVAL; + return -1; +#else + return kill (proc->pid, sig); +#endif + } +} + +/** + * Get the pid of the process in question + * + * @param proc the process to get the pid of + * + * @return the current process id + */ +pid_t +GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc) +{ + return proc->pid; +} + + +void +GNUNET_OS_process_close (struct GNUNET_OS_Process *proc) +{ +#if ENABLE_WINDOWS_WORKAROUNDS + if (proc->control_pipe) + GNUNET_DISK_file_close (proc->control_pipe); +#endif +// FIXME NILS +#ifdef WINDOWS + if (proc->handle != NULL) + CloseHandle (proc->handle); +#endif + if (NULL != proc->childpipename) + { +#if !WINDOWS + cleanup_npipe (proc->childpipename); +#endif + GNUNET_free (proc->childpipename); + } + GNUNET_free (proc); +} + +// FIXME NILS +#if WINDOWS +#include "gnunet_signal_lib.h" + +extern GNUNET_SIGNAL_Handler w32_sigchld_handler; + +/** + * Make seaspider happy. + */ +#define DWORD_WINAPI DWORD WINAPI + +/** + * @brief Waits for a process to terminate and invokes the SIGCHLD handler + * @param proc pointer to process structure + */ +static DWORD_WINAPI +child_wait_thread (void *arg) +{ + struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg; + + WaitForSingleObject (proc->handle, INFINITE); + + if (w32_sigchld_handler) + w32_sigchld_handler (); + + return 0; +} +#endif + +/** + * Set process priority + * + * @param proc pointer to process structure + * @param prio priority value + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc, + enum GNUNET_SCHEDULER_Priority prio) +{ + int rprio; + + GNUNET_assert (prio < GNUNET_SCHEDULER_PRIORITY_COUNT); + if (prio == GNUNET_SCHEDULER_PRIORITY_KEEP) + return GNUNET_OK; + + /* convert to MINGW/Unix values */ + switch (prio) + { + case GNUNET_SCHEDULER_PRIORITY_UI: + case GNUNET_SCHEDULER_PRIORITY_URGENT: +#ifdef MINGW + rprio = HIGH_PRIORITY_CLASS; +#else + rprio = 0; +#endif + break; + + case GNUNET_SCHEDULER_PRIORITY_HIGH: +#ifdef MINGW + rprio = ABOVE_NORMAL_PRIORITY_CLASS; +#else + rprio = 5; +#endif + break; + + case GNUNET_SCHEDULER_PRIORITY_DEFAULT: +#ifdef MINGW + rprio = NORMAL_PRIORITY_CLASS; +#else + rprio = 7; +#endif + break; + + case GNUNET_SCHEDULER_PRIORITY_BACKGROUND: +#ifdef MINGW + rprio = BELOW_NORMAL_PRIORITY_CLASS; +#else + rprio = 10; +#endif + break; + + case GNUNET_SCHEDULER_PRIORITY_IDLE: +#ifdef MINGW + rprio = IDLE_PRIORITY_CLASS; +#else + rprio = 19; +#endif + break; + default: + GNUNET_assert (0); + return GNUNET_SYSERR; + } + + /* Set process priority */ +#ifdef MINGW + { + HANDLE h = proc->handle; + + GNUNET_assert (h != NULL); + SetPriorityClass (h, rprio); + } +#elif LINUX + pid_t pid; + + pid = proc->pid; + if ((0 == pid) || (pid == getpid ())) + { + int have = nice (0); + int delta = rprio - have; + + errno = 0; + if ((delta != 0) && (rprio == nice (delta)) && (errno != 0)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "nice"); + return GNUNET_SYSERR; + } + } + else + { + if (0 != setpriority (PRIO_PROCESS, pid, rprio)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "setpriority"); + return GNUNET_SYSERR; + } + } +#else + LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Priority management not availabe for this platform\n"); +#endif + return GNUNET_OK; +} + +#if MINGW +static char * +CreateCustomEnvTable (char **vars) +{ + char *win32_env_table, *ptr, **var_ptr, *result, *result_ptr; + size_t tablesize = 0; + size_t items_count = 0; + size_t n_found = 0, n_var; + char *index = NULL; + size_t c; + size_t var_len; + char *var; + char *val; + + win32_env_table = GetEnvironmentStringsA (); + if (win32_env_table == NULL) + return NULL; + for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++) ; + n_var = c; + index = GNUNET_malloc (sizeof (char *) * n_var); + for (c = 0; c < n_var; c++) + index[c] = 0; + for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++) + { + size_t len = strlen (ptr); + int found = 0; + + for (var_ptr = vars; *var_ptr; var_ptr++) + { + var = *var_ptr++; + val = *var_ptr; + var_len = strlen (var); + if (strncmp (var, ptr, var_len) == 0) + { + found = 1; + index[c] = 1; + tablesize += var_len + strlen (val) + 1; + break; + } + } + if (!found) + tablesize += len + 1; + ptr += len + 1; + } + for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++) + { + var = *var_ptr++; + val = *var_ptr; + if (index[c] != 1) + n_found += strlen (var) + strlen (val) + 1; + } + result = GNUNET_malloc (tablesize + n_found + 1); + for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;) + { + size_t len = strlen (ptr); + int found = 0; + + for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++) + { + var = *var_ptr++; + val = *var_ptr; + var_len = strlen (var); + if (strncmp (var, ptr, var_len) == 0) + { + found = 1; + break; + } + } + if (!found) + { + strcpy (result_ptr, ptr); + result_ptr += len + 1; + } + else + { + strcpy (result_ptr, var); + result_ptr += var_len; + strcpy (result_ptr, val); + result_ptr += strlen (val) + 1; + } + ptr += len + 1; + } + for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++) + { + var = *var_ptr++; + val = *var_ptr; + var_len = strlen (var); + if (index[c] != 1) + { + strcpy (result_ptr, var); + result_ptr += var_len; + strcpy (result_ptr, val); + result_ptr += strlen (val) + 1; + } + } + FreeEnvironmentStrings (win32_env_table); + GNUNET_free (index); + *result_ptr = 0; + return result; +} +#endif + + +/** + * Start a process. + * + * @param pipe_control should a pipe be used to send signals to the child? + * @param pipe_stdin pipe to use to send input to child process (or NULL) + * @param pipe_stdout pipe to use to get output from child process (or NULL) + * @param filename name of the binary + * @param argv NULL-terminated array of arguments to the process + * @return pointer to process structure of the new process, NULL on error + */ +struct GNUNET_OS_Process * +GNUNET_OS_start_process_vap (int pipe_control, + struct GNUNET_DISK_PipeHandle *pipe_stdin, + struct GNUNET_DISK_PipeHandle *pipe_stdout, + const char *filename, + char *const argv[]) +{ +#ifndef MINGW + char *childpipename = NULL; + struct GNUNET_OS_Process *gnunet_proc = NULL; + pid_t ret; + int fd_stdout_write; + int fd_stdout_read; + int fd_stdin_read; + int fd_stdin_write; + + if ( (GNUNET_YES == pipe_control) && + (GNUNET_OK != + npipe_setup (&childpipename)) ) + return NULL; + if (pipe_stdout != NULL) + { + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle + (pipe_stdout, + GNUNET_DISK_PIPE_END_WRITE), + &fd_stdout_write, sizeof (int))); + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle + (pipe_stdout, GNUNET_DISK_PIPE_END_READ), + &fd_stdout_read, sizeof (int))); + } + if (pipe_stdin != NULL) + { + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle + (pipe_stdin, GNUNET_DISK_PIPE_END_READ), + &fd_stdin_read, sizeof (int))); + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle + (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE), + &fd_stdin_write, sizeof (int))); + } + + ret = fork (); + if (-1 == ret) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); + GNUNET_free_non_null (childpipename); + return NULL; + } + if (0 != ret) + { + gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); + gnunet_proc->pid = ret; + gnunet_proc->childpipename = childpipename; + return gnunet_proc; + } + if (NULL != childpipename) + { + setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1); + GNUNET_free (childpipename); + } + if (pipe_stdout != NULL) + { + GNUNET_break (0 == close (fd_stdout_read)); + if (-1 == dup2 (fd_stdout_write, 1)) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); + GNUNET_break (0 == close (fd_stdout_write)); + } + + if (pipe_stdin != NULL) + { + + GNUNET_break (0 == close (fd_stdin_write)); + if (-1 == dup2 (fd_stdin_read, 0)) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); + GNUNET_break (0 == close (fd_stdin_read)); + } + execvp (filename, argv); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename); + _exit (1); +#else + char *childpipename = NULL; + struct GNUNET_OS_Process *gnunet_proc = NULL; + char *arg; + unsigned int cmdlen; + char *cmd, *idx; + STARTUPINFOW start; + PROCESS_INFORMATION proc; + int argc, arg_count; + HANDLE stdin_handle; + HANDLE stdout_handle; + struct GNUNET_DISK_FileHandle *control_pipe; + + char path[MAX_PATH + 1]; + + char *our_env[3] = { NULL, NULL, NULL }; + char *env_block = NULL; + char *pathbuf; + DWORD pathbuf_len, alloc_len; + char *self_prefix; + char *bindir; + char *libdir; + char *ptr; + char *non_const_filename; + wchar_t wpath[MAX_PATH + 1], wcmd[32768]; + + /* Search in prefix dir (hopefully - the directory from which + * the current module was loaded), bindir and libdir, then in PATH + */ + self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX); + bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); + libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); + + pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0); + + alloc_len = + pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 + + strlen (libdir); + + pathbuf = GNUNET_malloc (alloc_len * sizeof (char)); + + ptr = pathbuf; + ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir); + GNUNET_free (self_prefix); + GNUNET_free (bindir); + GNUNET_free (libdir); + + alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len); + GNUNET_assert (alloc_len == (pathbuf_len - 1)); + + cmdlen = strlen (filename); + if (cmdlen < 5 || strcmp (&filename[cmdlen - 4], ".exe") != 0) + GNUNET_asprintf (&non_const_filename, "%s.exe", filename); + else + GNUNET_asprintf (&non_const_filename, "%s", filename); + + /* Check that this is the full path. If it isn't, search. */ + if (non_const_filename[1] == ':') + snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename); + else if (!SearchPathA + (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char), + path, NULL)) + { + SetErrnoFromWinError (GetLastError ()); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath", + non_const_filename); + GNUNET_free (non_const_filename); + GNUNET_free (pathbuf); + return NULL; + } + GNUNET_free (pathbuf); + GNUNET_free (non_const_filename); + + cmdlen = 0; + argc = 0; + while (NULL != (arg = argv[argc++])) + { + if (cmdlen == 0) + cmdlen = cmdlen + strlen (path) + 4; + else + cmdlen = cmdlen + strlen (arg) + 4; + } + arg_count = argc; + + cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1)); + argc = 0; + while (NULL != (arg = argv[argc++])) + { + /* This is to escape trailing slash */ + char arg_lastchar = arg[strlen (arg) - 1]; + if (idx == cmd) + idx += sprintf (idx, "\"%s%s\"%s", path, + arg_lastchar == '\\' ? "\\" : "", argc + 1 == arg_count ? "" : " "); + else + idx += sprintf (idx, "\"%s%s\"%s", arg, + arg_lastchar == '\\' ? "\\" : "", argc + 1 == arg_count ? "" : " "); + } + + memset (&start, 0, sizeof (start)); + start.cb = sizeof (start); + + if ((pipe_stdin != NULL) || (pipe_stdout != NULL)) + start.dwFlags |= STARTF_USESTDHANDLES; + + if (pipe_stdin != NULL) + { + GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle + (pipe_stdin, GNUNET_DISK_PIPE_END_READ), + &stdin_handle, sizeof (HANDLE)); + start.hStdInput = stdin_handle; + } + + if (pipe_stdout != NULL) + { + GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle + (pipe_stdout, + GNUNET_DISK_PIPE_END_WRITE), + &stdout_handle, sizeof (HANDLE)); + start.hStdOutput = stdout_handle; + } + if (GNUNET_YES == pipe_control) + { + control_pipe = + npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (control_pipe == NULL) + { + GNUNET_free (cmd); + GNUNET_free (path); + return NULL; + } + } + if (NULL != childpipename) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n", + childpipename); + GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE); + GNUNET_asprintf (&our_env[1], "%s", childpipename); + our_env[2] = NULL; + } + else + { + our_env[0] = NULL; + } + env_block = CreateCustomEnvTable (our_env); + GNUNET_free (our_env[0]); + GNUNET_free (our_env[1]); + + if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath) + || ERROR_SUCCESS != plibc_conv_to_win_pathwconv(cmd, wcmd) + || !CreateProcessW + (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, + env_block, NULL, &start, &proc)) + { + SetErrnoFromWinError (GetLastError ()); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path); + GNUNET_free (env_block); + GNUNET_free (cmd); + return NULL; + } + + GNUNET_free (env_block); + + gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); + gnunet_proc->pid = proc.dwProcessId; + gnunet_proc->handle = proc.hProcess; + gnunet_proc->control_pipe = control_pipe; + + CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL); + + ResumeThread (proc.hThread); + CloseHandle (proc.hThread); + + GNUNET_free (cmd); + + return gnunet_proc; +#endif +} + + +/** + * Start a process. + * + * @param pipe_control should a pipe be used to send signals to the child? + * @param pipe_stdin pipe to use to send input to child process (or NULL) + * @param pipe_stdout pipe to use to get output from child process (or NULL) + * @param filename name of the binary + * @param va NULL-terminated list of arguments to the process + * @return pointer to process structure of the new process, NULL on error + */ +struct GNUNET_OS_Process * +GNUNET_OS_start_process_va (int pipe_control, + struct GNUNET_DISK_PipeHandle *pipe_stdin, + struct GNUNET_DISK_PipeHandle *pipe_stdout, + const char *filename, va_list va) +{ + struct GNUNET_OS_Process *ret; + va_list ap; + char **argv; + int argc; + + argc = 0; + va_copy (ap, va); + while (NULL != va_arg (ap, char *)) + argc++; + va_end (ap); + argv = GNUNET_malloc (sizeof (char *) * (argc + 1)); + argc = 0; + va_copy (ap, va); + while (NULL != (argv[argc] = va_arg (ap, char *))) + argc++; + va_end (ap); + ret = GNUNET_OS_start_process_vap (pipe_control, + pipe_stdin, + pipe_stdout, + filename, + argv); + GNUNET_free (argv); + return ret; +} + + + +/** + * Start a process. + * + * @param pipe_control should a pipe be used to send signals to the child? + * @param pipe_stdin pipe to use to send input to child process (or NULL) + * @param pipe_stdout pipe to use to get output from child process (or NULL) + * @param filename name of the binary + * @param ... NULL-terminated list of arguments to the process + * + * @return pointer to process structure of the new process, NULL on error + * + */ +struct GNUNET_OS_Process * +GNUNET_OS_start_process (int pipe_control, + struct GNUNET_DISK_PipeHandle *pipe_stdin, + struct GNUNET_DISK_PipeHandle *pipe_stdout, + const char *filename, ...) +{ + struct GNUNET_OS_Process *ret; + va_list ap; + + va_start (ap, filename); + ret = GNUNET_OS_start_process_va (pipe_control, pipe_stdin, pipe_stdout, filename, ap); + va_end (ap); + return ret; +} + + +/** + * Start a process. + * + * @param pipe_control should a pipe be used to send signals to the child? + * @param lsocks array of listen sockets to dup systemd-style (or NULL); + * must be NULL on platforms where dup is not supported + * @param filename name of the binary + * @param argv NULL-terminated list of arguments to the process + * @return process ID of the new process, -1 on error + */ +struct GNUNET_OS_Process * +GNUNET_OS_start_process_v (int pipe_control, + const SOCKTYPE *lsocks, + const char *filename, + char *const argv[]) +{ +#ifndef MINGW + pid_t ret; + char lpid[16]; + char fds[16]; + struct GNUNET_OS_Process *gnunet_proc = NULL; + char *childpipename = NULL; + int i; + int j; + int k; + int tgt; + int flags; + int *lscp; + unsigned int ls; + + if ( (GNUNET_YES == pipe_control) && + (GNUNET_OK != npipe_setup (&childpipename)) ) + return NULL; + lscp = NULL; + ls = 0; + if (lsocks != NULL) + { + i = 0; + while (-1 != (k = lsocks[i++])) + GNUNET_array_append (lscp, ls, k); + GNUNET_array_append (lscp, ls, -1); + } + ret = fork (); + if (-1 == ret) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); + GNUNET_free_non_null (childpipename); + GNUNET_array_grow (lscp, ls, 0); + return NULL; + } + if (0 != ret) + { + gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); + gnunet_proc->pid = ret; + gnunet_proc->childpipename = childpipename; + GNUNET_array_grow (lscp, ls, 0); + return gnunet_proc; + } + if (NULL != childpipename) + { + setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1); + GNUNET_free (childpipename); + } + if (lscp != NULL) + { + /* read systemd documentation... */ + GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ()); + setenv ("LISTEN_PID", lpid, 1); + i = 0; + tgt = 3; + while (-1 != lscp[i]) + { + j = i + 1; + while (-1 != lscp[j]) + { + if (lscp[j] == tgt) + { + /* dup away */ + k = dup (lscp[j]); + GNUNET_assert (-1 != k); + GNUNET_assert (0 == close (lscp[j])); + lscp[j] = k; + break; + } + j++; + } + if (lscp[i] != tgt) + { + /* Bury any existing FD, no matter what; they should all be closed + * on exec anyway and the important onces have been dup'ed away */ + (void) close (tgt); + GNUNET_assert (-1 != dup2 (lscp[i], tgt)); + } + /* unset close-on-exec flag */ + flags = fcntl (tgt, F_GETFD); + GNUNET_assert (flags >= 0); + flags &= ~FD_CLOEXEC; + fflush (stderr); + (void) fcntl (tgt, F_SETFD, flags); + tgt++; + i++; + } + GNUNET_snprintf (fds, sizeof (fds), "%u", i); + setenv ("LISTEN_FDS", fds, 1); + } + GNUNET_array_grow (lscp, ls, 0); + execvp (filename, argv); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename); + _exit (1); +#else + struct GNUNET_DISK_FileHandle *control_pipe = NULL; + char *childpipename = NULL; + char **arg, **non_const_argv; + unsigned int cmdlen; + char *cmd, *idx; + STARTUPINFOW start; + PROCESS_INFORMATION proc; + int argcount = 0; + struct GNUNET_OS_Process *gnunet_proc = NULL; + char path[MAX_PATH + 1]; + char *our_env[5] = { NULL, NULL, NULL, NULL, NULL }; + char *env_block = NULL; + char *pathbuf; + DWORD pathbuf_len, alloc_len; + char *self_prefix; + char *bindir; + char *libdir; + char *ptr; + char *non_const_filename; + struct GNUNET_DISK_PipeHandle *lsocks_pipe; + const struct GNUNET_DISK_FileHandle *lsocks_write_fd; + HANDLE lsocks_read; + HANDLE lsocks_write; + wchar_t wpath[MAX_PATH + 1], wcmd[32768]; + int env_off; + int fail; + + /* Search in prefix dir (hopefully - the directory from which + * the current module was loaded), bindir and libdir, then in PATH + */ + self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX); + bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); + libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); + + pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0); + + alloc_len = + pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 + + strlen (libdir); + + pathbuf = GNUNET_malloc (alloc_len * sizeof (char)); + + ptr = pathbuf; + ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir); + GNUNET_free (self_prefix); + GNUNET_free (bindir); + GNUNET_free (libdir); + + alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len); + if (alloc_len != pathbuf_len - 1) + { + GNUNET_free (pathbuf); + errno = ENOSYS; /* PATH changed on the fly. What kind of error is that? */ + return NULL; + } + + cmdlen = strlen (filename); + if (cmdlen < 5 || strcmp (&filename[cmdlen - 4], ".exe") != 0) + GNUNET_asprintf (&non_const_filename, "%s.exe", filename); + else + GNUNET_asprintf (&non_const_filename, "%s", filename); + + /* Check that this is the full path. If it isn't, search. */ + if (non_const_filename[1] == ':') + snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename); + else if (!SearchPathA + (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char), + path, NULL)) + { + SetErrnoFromWinError (GetLastError ()); + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath", + non_const_filename); + GNUNET_free (non_const_filename); + GNUNET_free (pathbuf); + return NULL; + } + GNUNET_free (pathbuf); + GNUNET_free (non_const_filename); + + /* Count the number of arguments */ + arg = (char **) argv; + while (*arg) + { + arg++; + argcount++; + } + + /* Allocate a copy argv */ + non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1)); + + /* Copy all argv strings */ + argcount = 0; + arg = (char **) argv; + while (*arg) + { + if (arg == argv) + non_const_argv[argcount] = GNUNET_strdup (path); + else + non_const_argv[argcount] = GNUNET_strdup (*arg); + arg++; + argcount++; + } + non_const_argv[argcount] = NULL; + + /* Count cmd len */ + cmdlen = 1; + arg = non_const_argv; + while (*arg) + { + cmdlen = cmdlen + strlen (*arg) + 4; + arg++; + } + + /* Allocate and create cmd */ + cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen); + arg = non_const_argv; + while (*arg) + { + char arg_last_char = (*arg)[strlen (*arg) - 1]; + idx += sprintf (idx, "\"%s%s\"%s", *arg, + arg_last_char == '\\' ? "\\" : "", *(arg + 1) ? " " : ""); + arg++; + } + + while (argcount > 0) + GNUNET_free (non_const_argv[--argcount]); + GNUNET_free (non_const_argv); + + memset (&start, 0, sizeof (start)); + start.cb = sizeof (start); + + if (GNUNET_YES == pipe_control) + { + control_pipe = + npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (control_pipe == NULL) + { + GNUNET_free (cmd); + GNUNET_free (path); + return NULL; + } + } + if (lsocks != NULL && lsocks[0] != INVALID_SOCKET) + { + lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); + + if (lsocks_pipe == NULL) + { + GNUNET_free (cmd); + GNUNET_free (path); + GNUNET_DISK_pipe_close (lsocks_pipe); + return NULL; + } + lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe, + GNUNET_DISK_PIPE_END_WRITE); + GNUNET_DISK_internal_file_handle_ (lsocks_write_fd, + &lsocks_write, sizeof (HANDLE)); + GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle + (lsocks_pipe, GNUNET_DISK_PIPE_END_READ), + &lsocks_read, sizeof (HANDLE)); + } + + env_off = 0; + if (NULL != childpipename) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n", + childpipename); + GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE); + GNUNET_asprintf (&our_env[env_off++], "%s", childpipename); + GNUNET_free (childpipename); + } + if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET)) + { + /*This will tell the child that we're going to send lsocks over the pipe*/ + GNUNET_asprintf (&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS"); + GNUNET_asprintf (&our_env[env_off++], "%lu", lsocks_read); + } + our_env[env_off++] = NULL; + env_block = CreateCustomEnvTable (our_env); + while (0 > env_off) + GNUNET_free_non_null (our_env[--env_off]); + if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath) + || ERROR_SUCCESS != plibc_conv_to_win_pathwconv(cmd, wcmd) + || !CreateProcessW + (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, + env_block, NULL, &start, &proc)) + { + SetErrnoFromWinError (GetLastError ()); + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess"); + if (NULL != control_pipe) + GNUNET_DISK_file_close (control_pipe); + if (NULL != lsocks) + GNUNET_DISK_pipe_close (lsocks_pipe); + GNUNET_free (env_block); + GNUNET_free (cmd); + return NULL; + } + + GNUNET_free (env_block); + + gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); + gnunet_proc->pid = proc.dwProcessId; + gnunet_proc->handle = proc.hProcess; + gnunet_proc->control_pipe = control_pipe; + + CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL); + + ResumeThread (proc.hThread); + CloseHandle (proc.hThread); + GNUNET_free (cmd); + + if (lsocks == NULL || lsocks[0] == INVALID_SOCKET) + return gnunet_proc; + + GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ); + + /* This is a replacement for "goto error" that doesn't use goto */ + fail = 1; + do + { + int wrote; + uint64_t size, count, i; + + /* Tell the number of sockets */ + for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++); + + wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count)); + if (wrote != sizeof (count)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u count bytes to the child: %u\n", sizeof (count), GetLastError ()); + break; + } + for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++) + { + WSAPROTOCOL_INFOA pi; + /* Get a socket duplication info */ + if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate an socket[%llu]: %u\n", i, GetLastError ()); + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess"); + break; + } + /* Synchronous I/O is not nice, but we can't schedule this: + * lsocks will be closed/freed by the caller soon, and until + * the child creates a duplicate, closing a socket here will + * close it for good. + */ + /* Send the size of the structure + * (the child might be built with different headers...) + */ + size = sizeof (pi); + wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size)); + if (wrote != sizeof (size)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u size[%llu] bytes to the child: %u\n", sizeof (size), i, GetLastError ()); + break; + } + /* Finally! Send the data */ + wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi)); + if (wrote != sizeof (pi)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u socket[%llu] bytes to the child: %u\n", sizeof (pi), i, GetLastError ()); + break; + } + } + /* This will block us until the child makes a final read or closes + * the pipe (hence no 'wrote' check), since we have to wait for it + * to duplicate the last socket, before we return and start closing + * our own copies) + */ + wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count)); + fail = 0; + } + while (fail); + + GNUNET_DISK_file_sync (lsocks_write_fd); + GNUNET_DISK_pipe_close (lsocks_pipe); + + if (fail) + { + /* If we can't pass on the socket(s), the child will block forever, + * better put it out of its misery. + */ + TerminateProcess (gnunet_proc->handle, 0); + CloseHandle (gnunet_proc->handle); + if (NULL != gnunet_proc->control_pipe) + GNUNET_DISK_file_close (gnunet_proc->control_pipe); + GNUNET_free (gnunet_proc); + return NULL; + } + return gnunet_proc; +#endif +} + + +/** + * Retrieve the status of a process + * @param proc process ID + * @param type status type + * @param code return code/signal number + * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise + */ +int +GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, + enum GNUNET_OS_ProcessStatusType *type, + unsigned long *code) +{ +#ifndef MINGW + int status; + int ret; + + GNUNET_assert (0 != proc); + ret = waitpid (proc->pid, &status, WNOHANG); + if (ret < 0) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + return GNUNET_SYSERR; + } + if (0 == ret) + { + *type = GNUNET_OS_PROCESS_RUNNING; + *code = 0; + return GNUNET_NO; + } + if (proc->pid != ret) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + return GNUNET_SYSERR; + } + if (WIFEXITED (status)) + { + *type = GNUNET_OS_PROCESS_EXITED; + *code = WEXITSTATUS (status); + } + else if (WIFSIGNALED (status)) + { + *type = GNUNET_OS_PROCESS_SIGNALED; + *code = WTERMSIG (status); + } + else if (WIFSTOPPED (status)) + { + *type = GNUNET_OS_PROCESS_SIGNALED; + *code = WSTOPSIG (status); + } +#ifdef WIFCONTINUED + else if (WIFCONTINUED (status)) + { + *type = GNUNET_OS_PROCESS_RUNNING; + *code = 0; + } +#endif + else + { + *type = GNUNET_OS_PROCESS_UNKNOWN; + *code = 0; + } +#else + HANDLE h; + DWORD c, error_code, ret; + + h = proc->handle; + ret = proc->pid; + if (h == NULL || ret == 0) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n", + ret, h); + return GNUNET_SYSERR; + } + if (h == NULL) + h = GetCurrentProcess (); + + SetLastError (0); + ret = GetExitCodeProcess (h, &c); + error_code = GetLastError (); + if (ret == 0 || error_code != NO_ERROR) + { + SetErrnoFromWinError (error_code); + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess"); + return GNUNET_SYSERR; + } + if (STILL_ACTIVE == c) + { + *type = GNUNET_OS_PROCESS_RUNNING; + *code = 0; + return GNUNET_NO; + } + *type = GNUNET_OS_PROCESS_EXITED; + *code = c; +#endif + + return GNUNET_OK; +} + + +/** + * Wait for a process + * @param proc pointer to process structure + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc) +{ + +#ifndef MINGW + pid_t pid = proc->pid; + pid_t ret; + + while ( (pid != (ret = waitpid (pid, NULL, 0))) && + (EINTR == errno) ) ; + if (pid != ret) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + return GNUNET_SYSERR; + } + return GNUNET_OK; +#else + HANDLE h; + int ret; + + h = proc->handle; + if (NULL == h) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n", + proc->pid, h); + return GNUNET_SYSERR; + } + if (h == NULL) + h = GetCurrentProcess (); + + if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE)) + { + SetErrnoFromWinError (GetLastError ()); + ret = GNUNET_SYSERR; + } + else + ret = GNUNET_OK; + + return ret; +#endif +} + + +/** + * Handle to a command. + */ +struct GNUNET_OS_CommandHandle +{ + + /** + * Process handle. + */ + struct GNUNET_OS_Process *eip; + + /** + * Handle to the output pipe. + */ + struct GNUNET_DISK_PipeHandle *opipe; + + /** + * Read-end of output pipe. + */ + const struct GNUNET_DISK_FileHandle *r; + + /** + * Function to call on each line of output. + */ + GNUNET_OS_LineProcessor proc; + + /** + * Closure for 'proc'. + */ + void *proc_cls; + + /** + * Buffer for the output. + */ + char buf[1024]; + + /** + * Task reading from pipe. + */ + GNUNET_SCHEDULER_TaskIdentifier rtask; + + /** + * When to time out. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Current read offset in buf. + */ + size_t off; +}; + + +/** + * Stop/kill a command. Must ONLY be called either from + * the callback after 'NULL' was passed for 'line' *OR* + * from an independent task (not within the line processor). + * + * @param cmd handle to the process + */ +void +GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd) +{ + + if (cmd->proc != NULL) + { + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cmd->rtask); + GNUNET_SCHEDULER_cancel (cmd->rtask); + } + (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL); + GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip)); + GNUNET_OS_process_close (cmd->eip); + GNUNET_DISK_pipe_close (cmd->opipe); + GNUNET_free (cmd); +} + + +/** + * Read from the process and call the line processor. + * + * @param cls the 'struct GNUNET_OS_CommandHandle' + * @param tc scheduler context + */ +static void +cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_OS_CommandHandle *cmd = cls; + GNUNET_OS_LineProcessor proc; + char *end; + ssize_t ret; + + cmd->rtask = GNUNET_SCHEDULER_NO_TASK; + if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r)) + { + /* timeout, shutdown, etc. */ + proc = cmd->proc; + cmd->proc = NULL; + proc (cmd->proc_cls, NULL); + return; + } + ret = + GNUNET_DISK_file_read (cmd->r, &cmd->buf[cmd->off], + sizeof (cmd->buf) - cmd->off); + if (ret <= 0) + { + if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf))) + { + cmd->buf[cmd->off] = '\0'; + cmd->proc (cmd->proc_cls, cmd->buf); + } + proc = cmd->proc; + cmd->proc = NULL; + proc (cmd->proc_cls, NULL); + return; + } + end = memchr (&cmd->buf[cmd->off], '\n', ret); + cmd->off += ret; + while (end != NULL) + { + *end = '\0'; + cmd->proc (cmd->proc_cls, cmd->buf); + memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf)); + cmd->off -= (end + 1 - cmd->buf); + end = memchr (cmd->buf, '\n', cmd->off); + } + cmd->rtask = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining + (cmd->timeout), cmd->r, &cmd_read, cmd); +} + + +/** + * Run the given command line and call the given function + * for each line of the output. + * + * @param proc function to call for each line of the output + * @param proc_cls closure for proc + * @param timeout when to time out + * @param binary command to run + * @param ... arguments to command + * @return NULL on error + */ +struct GNUNET_OS_CommandHandle * +GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls, + struct GNUNET_TIME_Relative timeout, const char *binary, + ...) +{ + struct GNUNET_OS_CommandHandle *cmd; + struct GNUNET_OS_Process *eip; + struct GNUNET_DISK_PipeHandle *opipe; + va_list ap; + + opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); + if (NULL == opipe) + return NULL; + va_start (ap, binary); + eip = GNUNET_OS_start_process_va (GNUNET_NO, NULL, opipe, binary, ap); + va_end (ap); + if (NULL == eip) + { + GNUNET_DISK_pipe_close (opipe); + return NULL; + } + GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE); + cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle)); + cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout); + cmd->eip = eip; + cmd->opipe = opipe; + cmd->proc = proc; + cmd->proc_cls = proc_cls; + cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ); + cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd); + return cmd; +} + + + + +/* end of os_priority.c */ diff --git a/src/util/peer.c b/src/util/peer.c new file mode 100644 index 0000000..2444cb9 --- /dev/null +++ b/src/util/peer.c @@ -0,0 +1,241 @@ +/* + This file is part of GNUnet + (C) 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +/** + * @file util/peer.c + * @brief peer-ID table that assigns integer IDs to peer-IDs to save memory + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_peer_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + + +struct PeerEntry +{ + /** + * The identifier itself + */ + struct GNUNET_PeerIdentity id; + + /** + * Short version of the identifier; if the RC==0, then index of next + * free slot in table, otherwise equal to this slot in the table. + */ + GNUNET_PEER_Id pid; + + /** + * Reference counter, 0 if this slot is not used. + */ + unsigned int rc; +}; + + +/** + * Table with our interned peer IDs. + */ +static struct PeerEntry *table; + +/** + * Hashmap of PeerIdentities to "struct PeerEntry" + * (for fast lookup). NULL until the library + * is actually being used. + */ +static struct GNUNET_CONTAINER_MultiHashMap *map; + +/** + * Size of the "table". + */ +static unsigned int size; + +/** + * Index of the beginning of the free list in the table; set to "size" + * if no slots are free in the table. + */ +static unsigned int free_list_start; + + +/** + * Search for a peer identity. The reference counter is not changed. + * + * @param pid identity to find + * @return the interned identity or 0. + */ +GNUNET_PEER_Id +GNUNET_PEER_search (const struct GNUNET_PeerIdentity *pid) +{ + struct PeerEntry *e; + long off; + + if (pid == NULL) + return 0; + if (NULL == map) + return 0; + off = (long) GNUNET_CONTAINER_multihashmap_get (map, &pid->hashPubKey); + e = (off == 0) ? NULL : &table[off]; + if (e == NULL) + return 0; + GNUNET_assert (e->rc > 0); + return e->pid; +} + + +/** + * Intern an peer identity. If the identity is already known, its + * reference counter will be increased by one. + * + * @param pid identity to intern + * @return the interned identity. + */ +GNUNET_PEER_Id +GNUNET_PEER_intern (const struct GNUNET_PeerIdentity *pid) +{ + GNUNET_PEER_Id ret; + struct PeerEntry *e; + unsigned int i; + long off; + + if (pid == NULL) + return 0; + if (NULL == map) + map = GNUNET_CONTAINER_multihashmap_create (32); + off = (long) GNUNET_CONTAINER_multihashmap_get (map, &pid->hashPubKey); + e = (off == 0) ? NULL : &table[off]; + if (e != NULL) + { + GNUNET_assert (e->rc > 0); + e->rc++; + return e->pid; + } + ret = free_list_start; + if (ret == size) + { + GNUNET_array_grow (table, size, size + 16); + for (i = ret; i < size; i++) + table[i].pid = i + 1; + } + if (ret == 0) + { + table[0].pid = 0; + table[0].rc = 1; + ret = 1; + } + GNUNET_assert (ret < size); + GNUNET_assert (table[ret].rc == 0); + free_list_start = table[ret].pid; + table[ret].id = *pid; + table[ret].rc = 1; + table[ret].pid = ret; + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (map, &pid->hashPubKey, + (void *) (long) ret, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + return ret; +} + + +/** + * Decrement multiple RCs of peer identities by one. + * + * @param ids array of PIDs to decrement the RCs of + * @param count size of the ids array + */ +void +GNUNET_PEER_decrement_rcs (const GNUNET_PEER_Id *ids, unsigned int count) +{ + int i; + GNUNET_PEER_Id id; + + if (count == 0) + return; + for (i = count - 1; i >= 0; i--) + { + id = ids[i]; + if (id == 0) + continue; + GNUNET_assert (id < size); + GNUNET_assert (table[id].rc > 0); + table[id].rc--; + if (table[id].rc == 0) + { + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (map, + &table[id]. + id.hashPubKey, + (void *) (long) id)); + table[id].pid = free_list_start; + free_list_start = id; + } + } +} + + +/** + * Change the reference counter of an interned PID. + * + * @param id identity to change the RC of + * @param delta how much to change the RC + */ +void +GNUNET_PEER_change_rc (GNUNET_PEER_Id id, int delta) +{ + if (id == 0) + return; + GNUNET_assert (id < size); + GNUNET_assert (table[id].rc > 0); + GNUNET_assert ((delta >= 0) || (table[id].rc >= -delta)); + table[id].rc += delta; + if (table[id].rc == 0) + { + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (map, + &table[id]. + id.hashPubKey, + (void *) (long) id)); + table[id].pid = free_list_start; + free_list_start = id; + } +} + + +/** + * Convert an interned PID to a normal peer identity. + * + * @param id interned PID to convert + * @param pid where to write the normal peer identity + */ +void +GNUNET_PEER_resolve (GNUNET_PEER_Id id, struct GNUNET_PeerIdentity *pid) +{ + if (id == 0) + { + memset (pid, 0, sizeof (struct GNUNET_PeerIdentity)); + GNUNET_break (0); + return; + } + GNUNET_assert (id < size); + GNUNET_assert (table[id].rc > 0); + *pid = table[id].id; +} + + +/* end of peer.c */ diff --git a/src/util/perf_crypto_hash.c b/src/util/perf_crypto_hash.c new file mode 100644 index 0000000..d883776 --- /dev/null +++ b/src/util/perf_crypto_hash.c @@ -0,0 +1,70 @@ +/* + This file is part of GNUnet. + (C) 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Christian Grothoff + * @file util/perf_crypto_hash.c + * @brief measure performance of hash function + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_time_lib.h" +#include + +static void +perfHash () +{ + GNUNET_HashCode hc1; + GNUNET_HashCode hc2; + GNUNET_HashCode hc3; + int i; + char *buf; + + buf = GNUNET_malloc (1024 * 64); + memset (buf, 1, 1024 * 64); + GNUNET_CRYPTO_hash ("foo", 3, &hc1); + for (i = 0; i < 1024; i++) + { + GNUNET_CRYPTO_hash (&hc1, sizeof (GNUNET_HashCode), &hc2); + GNUNET_CRYPTO_hash (&hc2, sizeof (GNUNET_HashCode), &hc1); + GNUNET_CRYPTO_hash (buf, 1024 * 64, &hc3); + } + GNUNET_free (buf); +} + +int +main (int argc, char *argv[]) +{ + struct GNUNET_TIME_Absolute start; + + start = GNUNET_TIME_absolute_get (); + perfHash (); + printf ("Hash perf took %llu ms\n", + (unsigned long long) + GNUNET_TIME_absolute_get_duration (start).rel_value); + GAUGER ("UTIL", "Cryptographic hashing", + 1024 * 64 * 1024 / (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value), "kb/s"); + return 0; +} + +/* end of hashperf.c */ diff --git a/src/util/plugin.c b/src/util/plugin.c new file mode 100644 index 0000000..4e0385a --- /dev/null +++ b/src/util/plugin.c @@ -0,0 +1,361 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/plugin.c + * @brief Methods to access plugins + * @author Christian Grothoff + */ + +#include "platform.h" +#include +#include "gnunet_common.h" +#include "gnunet_os_lib.h" +#include "gnunet_plugin_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/** + * Linked list of active plugins. + */ +struct PluginList +{ + /** + * This is a linked list. + */ + struct PluginList *next; + + /** + * Name of the library. + */ + char *name; + + /** + * System handle. + */ + void *handle; +}; + + +/** + * Have we been initialized? + */ +static int initialized; + + +/** + * Libtool search path before we started. + */ +static char *old_dlsearchpath; + + +/** + * List of plugins we have loaded. + */ +static struct PluginList *plugins; + + +/** + * Setup libtool paths. + */ +static void +plugin_init () +{ + int err; + const char *opath; + char *path; + char *cpath; + + err = lt_dlinit (); + if (err > 0) + { + FPRINTF (stderr, _("Initialization of plugin mechanism failed: %s!\n"), + lt_dlerror ()); + return; + } + opath = lt_dlgetsearchpath (); + if (opath != NULL) + old_dlsearchpath = GNUNET_strdup (opath); + path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); + if (path != NULL) + { + if (opath != NULL) + { + GNUNET_asprintf (&cpath, "%s:%s", opath, path); + lt_dlsetsearchpath (cpath); + GNUNET_free (path); + GNUNET_free (cpath); + } + else + { + lt_dlsetsearchpath (path); + GNUNET_free (path); + } + } +} + + +/** + * Shutdown libtool. + */ +static void +plugin_fini () +{ + lt_dlsetsearchpath (old_dlsearchpath); + if (old_dlsearchpath != NULL) + { + GNUNET_free (old_dlsearchpath); + old_dlsearchpath = NULL; + } + lt_dlexit (); +} + + +/** + * Lookup a function in the plugin. + */ +static GNUNET_PLUGIN_Callback +resolve_function (struct PluginList *plug, const char *name) +{ + char *initName; + void *mptr; + + GNUNET_asprintf (&initName, "_%s_%s", plug->name, name); + mptr = lt_dlsym (plug->handle, &initName[1]); + if (mptr == NULL) + mptr = lt_dlsym (plug->handle, initName); + if (mptr == NULL) + LOG (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed to resolve method '%s' with error: %s\n"), "lt_dlsym", + &initName[1], lt_dlerror ()); + GNUNET_free (initName); + return mptr; +} + +/** + * Test if a plugin exists. + * + * Note that the library must export a symbol called + * "library_name_init" for the test to succeed. + * + * @param library_name name of the plugin to test if it is installed + * @return GNUNET_YES if the plugin exists, GNUNET_NO if not + */ +int +GNUNET_PLUGIN_test (const char *library_name) +{ + void *libhandle; + GNUNET_PLUGIN_Callback init; + struct PluginList plug; + + if (!initialized) + { + initialized = GNUNET_YES; + plugin_init (); + } + libhandle = lt_dlopenext (library_name); + if (libhandle == NULL) + return GNUNET_NO; + plug.handle = libhandle; + plug.name = (char *) library_name; + init = resolve_function (&plug, "init"); + if (init == NULL) + { + GNUNET_break (0); + lt_dlclose (libhandle); + return GNUNET_NO; + } + lt_dlclose (libhandle); + return GNUNET_YES; +} + + +/** + * Setup plugin (runs the "init" callback and returns whatever "init" + * returned). If "init" returns NULL, the plugin is unloaded. + * + * Note that the library must export symbols called + * "library_name_init" and "library_name_done". These will be called + * when the library is loaded and unloaded respectively. + * + * @param library_name name of the plugin to load + * @param arg argument to the plugin initialization function + * @return whatever the initialization function returned + */ +void * +GNUNET_PLUGIN_load (const char *library_name, void *arg) +{ + void *libhandle; + struct PluginList *plug; + GNUNET_PLUGIN_Callback init; + void *ret; + + if (!initialized) + { + initialized = GNUNET_YES; + plugin_init (); + } + libhandle = lt_dlopenext (library_name); + if (libhandle == NULL) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("`%s' failed for library `%s' with error: %s\n"), "lt_dlopenext", + library_name, lt_dlerror ()); + return NULL; + } + plug = GNUNET_malloc (sizeof (struct PluginList)); + plug->handle = libhandle; + plug->name = GNUNET_strdup (library_name); + plug->next = plugins; + plugins = plug; + init = resolve_function (plug, "init"); + if ((init == NULL) || (NULL == (ret = init (arg)))) + { + lt_dlclose (libhandle); + GNUNET_free (plug->name); + plugins = plug->next; + GNUNET_free (plug); + return NULL; + } + return ret; +} + + +/** + * Unload plugin (runs the "done" callback and returns whatever "done" + * returned). The plugin is then unloaded. + * + * @param library_name name of the plugin to unload + * @param arg argument to the plugin shutdown function + * @return whatever the shutdown function returned + */ +void * +GNUNET_PLUGIN_unload (const char *library_name, void *arg) +{ + struct PluginList *pos; + struct PluginList *prev; + GNUNET_PLUGIN_Callback done; + void *ret; + + prev = NULL; + pos = plugins; + while ((pos != NULL) && (0 != strcmp (pos->name, library_name))) + { + prev = pos; + pos = pos->next; + } + if (pos == NULL) + return NULL; + + done = resolve_function (pos, "done"); + ret = NULL; + if (done != NULL) + ret = done (arg); + if (prev == NULL) + plugins = pos->next; + else + prev->next = pos->next; + lt_dlclose (pos->handle); + GNUNET_free (pos->name); + GNUNET_free (pos); + if (plugins == NULL) + { + plugin_fini (); + initialized = GNUNET_NO; + } + return ret; +} + + +struct LoadAllContext +{ + const char *basename; + void *arg; + GNUNET_PLUGIN_LoaderCallback cb; + void *cb_cls; +}; + + +static int +find_libraries (void *cls, const char *filename) +{ + struct LoadAllContext *lac = cls; + const char *slashpos; + const char *libname; + char *basename; + char *dot; + void *lib_ret; + size_t n; + + libname = filename; + while (NULL != (slashpos = strstr (libname, DIR_SEPARATOR_STR))) + libname = slashpos + 1; + n = strlen (libname); + if (0 != strncmp (lac->basename, libname, strlen (lac->basename))) + return GNUNET_OK; /* wrong name */ + if ((n > 3) && (0 == strcmp (&libname[n - 3], ".la"))) + return GNUNET_OK; /* .la file */ + basename = GNUNET_strdup (libname); + if (NULL != (dot = strstr (basename, "."))) + *dot = '\0'; + lib_ret = GNUNET_PLUGIN_load (basename, lac->arg); + if (NULL != lib_ret) + lac->cb (lac->cb_cls, basename, lib_ret); + GNUNET_free (basename); + return GNUNET_OK; +} + + +/** + * Load all compatible plugins with the given base name. + * + * Note that the library must export symbols called + * "basename_ANYTHING_init" and "basename_ANYTHING__done". These will + * be called when the library is loaded and unloaded respectively. + * + * @param basename basename of the plugins to load + * @param arg argument to the plugin initialization function + * @param cb function to call for each plugin found + * @param cb_cls closure for 'cb' + */ +void +GNUNET_PLUGIN_load_all (const char *basename, void *arg, + GNUNET_PLUGIN_LoaderCallback cb, void *cb_cls) +{ + struct LoadAllContext lac; + char *path; + + path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); + if (path == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not determine plugin installation path.\n")); + return; + } + lac.basename = basename; + lac.arg = arg; + lac.cb = cb; + lac.cb_cls = cb_cls; + GNUNET_DISK_directory_scan (path, &find_libraries, &lac); + GNUNET_free (path); +} + + +/* end of plugin.c */ diff --git a/src/util/program.c b/src/util/program.c new file mode 100644 index 0000000..6a0e5a5 --- /dev/null +++ b/src/util/program.c @@ -0,0 +1,261 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/program.c + * @brief standard code for GNUnet startup and shutdown + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_directories.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_resolver_service.h" +#include "gnunet_scheduler_lib.h" +#include + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +/** + * Context for the command. + */ +struct CommandContext +{ + /** + * Argv argument. + */ + char *const *args; + + /** + * Name of the configuration file used, can be NULL! + */ + char *cfgfile; + + /** + * Main function to run. + */ + GNUNET_PROGRAM_Main task; + + /** + * Closure for task. + */ + void *task_cls; + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + +}; + + +/** + * Initial task called by the scheduler for each + * program. Runs the program-specific main task. + */ +static void +program_main (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CommandContext *cc = cls; + + GNUNET_RESOLVER_connect (cc->cfg); + cc->task (cc->task_cls, cc->args, cc->cfgfile, cc->cfg); +} + + +/** + * Compare function for 'qsort' to sort command-line arguments by the + * short option. + * + * @param a1 first command line option + * @param a2 second command line option + */ +static int +cmd_sorter (__const void *a1, __const void *a2) +{ + __const struct GNUNET_GETOPT_CommandLineOption *c1 = a1; + __const struct GNUNET_GETOPT_CommandLineOption *c2 = a2; + + if (toupper ((unsigned char) c1->shortName) > + toupper ((unsigned char) c2->shortName)) + return 1; + if (toupper ((unsigned char) c1->shortName) < + toupper ((unsigned char) c2->shortName)) + return -1; + if (c1->shortName > c2->shortName) + return 1; + if (c1->shortName < c2->shortName) + return -1; + return 0; +} + + +/** + * Run a standard GNUnet command startup sequence (initialize loggers + * and configuration, parse options). + * + * @param argc number of command line arguments + * @param argv command line arguments + * @param binaryName our expected name + * @param binaryHelp help text for the program + * @param options command line options + * @param task main function to run + * @param task_cls closure for task + * @return GNUNET_SYSERR on error, GNUNET_OK on success + */ +int +GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName, + const char *binaryHelp, + const struct GNUNET_GETOPT_CommandLineOption *options, + GNUNET_PROGRAM_Main task, void *task_cls) +{ + struct CommandContext cc; + char *path; + char *loglev; + char *logfile; + int ret; + unsigned int cnt; + unsigned long long skew_offset; + unsigned long long skew_variance; + long long clock_offset; + struct GNUNET_CONFIGURATION_Handle *cfg; + + struct GNUNET_GETOPT_CommandLineOption defoptions[] = { + GNUNET_GETOPT_OPTION_CFG_FILE (&cc.cfgfile), + GNUNET_GETOPT_OPTION_HELP (binaryHelp), + GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), + GNUNET_GETOPT_OPTION_LOGFILE (&logfile), + GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION) + }; + struct GNUNET_GETOPT_CommandLineOption *allopts; + const char *gargs; + char *lpfx; + char *spc; + + logfile = NULL; + gargs = getenv ("GNUNET_ARGS"); + if (gargs != NULL) + { + char **gargv; + unsigned int gargc; + int i; + char *tok; + char *cargs; + + gargv = NULL; + gargc = 0; + for (i = 0; i < argc; i++) + GNUNET_array_append (gargv, gargc, GNUNET_strdup (argv[i])); + cargs = GNUNET_strdup (gargs); + tok = strtok (cargs, " "); + while (NULL != tok) + { + GNUNET_array_append (gargv, gargc, GNUNET_strdup (tok)); + tok = strtok (NULL, " "); + } + GNUNET_free (cargs); + GNUNET_array_append (gargv, gargc, NULL); + argv = (char *const *) gargv; + argc = gargc - 1; + } + memset (&cc, 0, sizeof (cc)); + loglev = NULL; + cc.task = task; + cc.task_cls = task_cls; + cc.cfg = cfg = GNUNET_CONFIGURATION_create (); + + /* prepare */ +#if ENABLE_NLS + setlocale (LC_ALL, ""); + path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR); + if (path != NULL) + { + BINDTEXTDOMAIN ("GNUnet", path); + GNUNET_free (path); + } + textdomain ("GNUnet"); +#endif + cnt = 0; + while (options[cnt].name != NULL) + cnt++; + allopts = + GNUNET_malloc ((cnt + + 1) * sizeof (struct GNUNET_GETOPT_CommandLineOption) + + sizeof (defoptions)); + memcpy (allopts, defoptions, sizeof (defoptions)); + memcpy (&allopts + [sizeof (defoptions) / + sizeof (struct GNUNET_GETOPT_CommandLineOption)], options, + (cnt + 1) * sizeof (struct GNUNET_GETOPT_CommandLineOption)); + cnt += sizeof (defoptions) / sizeof (struct GNUNET_GETOPT_CommandLineOption); + qsort (allopts, cnt, sizeof (struct GNUNET_GETOPT_CommandLineOption), + &cmd_sorter); + loglev = NULL; + cc.cfgfile = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE); + lpfx = GNUNET_strdup (binaryName); + if (NULL != (spc = strstr (lpfx, " "))) + *spc = '\0'; + if ((-1 == + (ret = + GNUNET_GETOPT_run (binaryName, allopts, (unsigned int) argc, argv))) || + (GNUNET_OK != GNUNET_log_setup (lpfx, loglev, logfile))) + { + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free_non_null (cc.cfgfile); + GNUNET_free_non_null (loglev); + GNUNET_free_non_null (logfile); + GNUNET_free (allopts); + GNUNET_free (lpfx); + return GNUNET_SYSERR; + } + (void) GNUNET_CONFIGURATION_load (cfg, cc.cfgfile); + GNUNET_free (allopts); + GNUNET_free (lpfx); + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cc.cfg, "testing", "skew_offset", + &skew_offset) && + (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cc.cfg, "testing", + "skew_variance", &skew_variance))) + { + clock_offset = skew_offset - skew_variance; + GNUNET_TIME_set_offset (clock_offset); + } + /* run */ + cc.args = &argv[ret]; + GNUNET_SCHEDULER_run (&program_main, &cc); + + /* clean up */ + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free_non_null (cc.cfgfile); + GNUNET_free_non_null (loglev); + GNUNET_free_non_null (logfile); + return GNUNET_OK; +} + + +/* end of program.c */ diff --git a/src/util/pseudonym.c b/src/util/pseudonym.c new file mode 100644 index 0000000..782a405 --- /dev/null +++ b/src/util/pseudonym.c @@ -0,0 +1,602 @@ +/* + This file is part of GNUnet + (C) 2003, 2004, 2005, 2006, 2007, 2008 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/pseudonym.c + * @brief helper functions + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" +#include "gnunet_disk_lib.h" +#include "gnunet_pseudonym_lib.h" +#include "gnunet_bio_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +/** + * Name of the directory which stores meta data for pseudonym + */ +#define PS_METADATA_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonyms" DIR_SEPARATOR_STR "metadata" DIR_SEPARATOR_STR + +/** + * Name of the directory which stores names for pseudonyms + */ +#define PS_NAMES_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonyms" DIR_SEPARATOR_STR "names" DIR_SEPARATOR_STR + + +/** + * Configuration section we use. + */ +#define GNUNET_CLIENT_SERVICE_NAME "client" + + + +/** + * Registered callbacks for discovery of pseudonyms. + */ +struct DiscoveryCallback +{ + /** + * This is a linked list. + */ + struct DiscoveryCallback *next; + + /** + * Function to call each time a pseudonym is discovered. + */ + GNUNET_PSEUDONYM_Iterator callback; + + /** + * Closure for callback. + */ + void *closure; +}; + + +/** + * Head of the linked list of functions to call when + * new pseudonyms are added. + */ +static struct DiscoveryCallback *head; + +/** + * Internal notification about new tracked URI. + * @param id a point to the hash code of pseudonym + * @param md meta data to be written + * @param rating rating of pseudonym + */ +static void +internal_notify (const GNUNET_HashCode * id, + const struct GNUNET_CONTAINER_MetaData *md, int rating) +{ + struct DiscoveryCallback *pos; + + pos = head; + while (pos != NULL) + { + pos->callback (pos->closure, id, md, rating); + pos = pos->next; + } +} + +/** + * Register callback to be invoked whenever we discover + * a new pseudonym. + * @param cfg configuration to use + * @param iterator iterator over pseudonym + * @param closure point to a closure + */ +int +GNUNET_PSEUDONYM_discovery_callback_register (const struct + GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_PSEUDONYM_Iterator + iterator, void *closure) +{ + struct DiscoveryCallback *list; + + list = GNUNET_malloc (sizeof (struct DiscoveryCallback)); + list->callback = iterator; + list->closure = closure; + list->next = head; + head = list; + GNUNET_PSEUDONYM_list_all (cfg, iterator, closure); + return GNUNET_OK; +} + +/** + * Unregister pseudonym discovery callback. + * @param iterator iterator over pseudonym + * @param closure point to a closure + */ +int +GNUNET_PSEUDONYM_discovery_callback_unregister (GNUNET_PSEUDONYM_Iterator + iterator, void *closure) +{ + struct DiscoveryCallback *prev; + struct DiscoveryCallback *pos; + + prev = NULL; + pos = head; + while ((pos != NULL) && + ((pos->callback != iterator) || (pos->closure != closure))) + { + prev = pos; + pos = pos->next; + } + if (pos == NULL) + return GNUNET_SYSERR; + if (prev == NULL) + head = pos->next; + else + prev->next = pos->next; + GNUNET_free (pos); + return GNUNET_OK; +} + + +/** + * Get the filename (or directory name) for the given + * pseudonym identifier and directory prefix. + * @param cfg configuration to use + * @param prefix path components to append to the private directory name + * @param psid hash code of pseudonym, can be NULL + * @return filename of the pseudonym (if psid != NULL) or directory with the data (if psid == NULL) + */ +static char * +get_data_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *prefix, const GNUNET_HashCode * psid) +{ + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + + if (psid != NULL) + GNUNET_CRYPTO_hash_to_enc (psid, &enc); + return GNUNET_DISK_get_home_filename (cfg, GNUNET_CLIENT_SERVICE_NAME, prefix, + (psid == + NULL) ? NULL : (const char *) &enc, + NULL); +} + + +/** + * Write the pseudonym infomation into a file + * @param cfg configuration to use + * @param nsid hash code of a pseudonym + * @param meta meta data to be written into a file + * @param ranking ranking of a pseudonym + * @param ns_name name of a pseudonym + */ +static void +write_pseudonym_info (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * nsid, + const struct GNUNET_CONTAINER_MetaData *meta, + int32_t ranking, const char *ns_name) +{ + char *fn; + struct GNUNET_BIO_WriteHandle *fileW; + + fn = get_data_filename (cfg, PS_METADATA_DIR, nsid); + GNUNET_assert (fn != NULL); + fileW = GNUNET_BIO_write_open (fn); + if (NULL != fileW) + { + if ((GNUNET_OK != GNUNET_BIO_write_int32 (fileW, ranking)) || + (GNUNET_OK != GNUNET_BIO_write_string (fileW, ns_name)) || + (GNUNET_OK != GNUNET_BIO_write_meta_data (fileW, meta))) + { + (void) GNUNET_BIO_write_close (fileW); + GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); + GNUNET_free (fn); + return; + } + if (GNUNET_OK != GNUNET_BIO_write_close (fileW)) + { + GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); + GNUNET_free (fn); + return; + } + } + GNUNET_free (fn); + /* create entry for pseudonym name in names */ + /* FIXME: 90% of what this call does is not needed + * here => refactor code to only create the entry! */ + GNUNET_free_non_null (GNUNET_PSEUDONYM_id_to_name (cfg, nsid)); +} + + +/** + * read the pseudonym infomation from a file + * @param cfg configuration to use + * @param nsid hash code of a pseudonym + * @param meta meta data to be read from a file + * @param ranking ranking of a pseudonym + * @param ns_name name of a pseudonym + */ +static int +read_info (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * nsid, + struct GNUNET_CONTAINER_MetaData **meta, int32_t * ranking, + char **ns_name) +{ + char *fn; + char *emsg; + struct GNUNET_BIO_ReadHandle *fileR; + + fn = get_data_filename (cfg, PS_METADATA_DIR, nsid); + GNUNET_assert (fn != NULL); + fileR = GNUNET_BIO_read_open (fn); + if (fileR == NULL) + { + GNUNET_free (fn); + return GNUNET_SYSERR; + } + emsg = NULL; + *ns_name = NULL; + if ((GNUNET_OK != GNUNET_BIO_read_int32 (fileR, ranking)) || + (GNUNET_OK != + GNUNET_BIO_read_string (fileR, "Read string error!", ns_name, 200)) || + (GNUNET_OK != + GNUNET_BIO_read_meta_data (fileR, "Read meta data error!", meta))) + { + (void) GNUNET_BIO_read_close (fileR, &emsg); + GNUNET_free_non_null (emsg); + GNUNET_free_non_null (*ns_name); + *ns_name = NULL; + GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); + GNUNET_free (fn); + return GNUNET_SYSERR; + } + if (GNUNET_OK != GNUNET_BIO_read_close (fileR, &emsg)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Failed to parse metadata about pseudonym from file `%s': %s\n"), fn, + emsg); + GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); + GNUNET_CONTAINER_meta_data_destroy (*meta); + *meta = NULL; + GNUNET_free_non_null (*ns_name); + *ns_name = NULL; + GNUNET_free_non_null (emsg); + GNUNET_free (fn); + return GNUNET_SYSERR; + } + GNUNET_free (fn); + return GNUNET_OK; +} + + + +/** + * Return the unique, human readable name for the given namespace. + * + * @param cfg configuration + * @param nsid cryptographic ID of the namespace + * @return NULL on failure (should never happen) + */ +char * +GNUNET_PSEUDONYM_id_to_name (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * nsid) +{ + struct GNUNET_CONTAINER_MetaData *meta; + char *name; + GNUNET_HashCode nh; + char *fn; + uint64_t len; + struct GNUNET_DISK_FileHandle *fh; + unsigned int i; + unsigned int idx; + char *ret; + struct stat sbuf; + int32_t temp = 0; + int32_t *rank = &temp; + + meta = NULL; + name = NULL; + if (GNUNET_OK == read_info (cfg, nsid, &meta, rank, &name)) + { + if ((meta != NULL) && (name == NULL)) + name = + GNUNET_CONTAINER_meta_data_get_first_by_types (meta, + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, + EXTRACTOR_METATYPE_FILENAME, + EXTRACTOR_METATYPE_DESCRIPTION, + EXTRACTOR_METATYPE_SUBJECT, + EXTRACTOR_METATYPE_PUBLISHER, + EXTRACTOR_METATYPE_AUTHOR_NAME, + EXTRACTOR_METATYPE_COMMENT, + EXTRACTOR_METATYPE_SUMMARY, + -1); + if (meta != NULL) + { + GNUNET_CONTAINER_meta_data_destroy (meta); + meta = NULL; + } + } + if (name == NULL) + name = GNUNET_strdup (_("no-name")); + GNUNET_CRYPTO_hash (name, strlen (name), &nh); + fn = get_data_filename (cfg, PS_NAMES_DIR, &nh); + GNUNET_assert (fn != NULL); + + len = 0; + if (0 == STAT (fn, &sbuf)) + GNUNET_DISK_file_size (fn, &len, GNUNET_YES); + fh = GNUNET_DISK_file_open (fn, + GNUNET_DISK_OPEN_CREATE | + GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + i = 0; + idx = -1; + while ((len >= sizeof (GNUNET_HashCode)) && + (sizeof (GNUNET_HashCode) == + GNUNET_DISK_file_read (fh, &nh, sizeof (GNUNET_HashCode)))) + { + if (0 == memcmp (&nh, nsid, sizeof (GNUNET_HashCode))) + { + idx = i; + break; + } + i++; + len -= sizeof (GNUNET_HashCode); + } + if (idx == -1) + { + idx = i; + if (sizeof (GNUNET_HashCode) != + GNUNET_DISK_file_write (fh, nsid, sizeof (GNUNET_HashCode))) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "write", fn); + } + GNUNET_DISK_file_close (fh); + ret = GNUNET_malloc (strlen (name) + 32); + GNUNET_snprintf (ret, strlen (name) + 32, "%s-%u", name, idx); + GNUNET_free (name); + GNUNET_free (fn); + return ret; +} + +/** + * Get the namespace ID belonging to the given namespace name. + * + * @param cfg configuration to use + * @param ns_uname human-readable name for the namespace + * @param nsid set to namespace ID based on 'ns_uname' + * @return GNUNET_OK on success + */ +int +GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *ns_uname, GNUNET_HashCode * nsid) +{ + size_t slen; + uint64_t len; + unsigned int idx; + char *name; + GNUNET_HashCode nh; + char *fn; + struct GNUNET_DISK_FileHandle *fh; + + idx = -1; + slen = strlen (ns_uname); + while ((slen > 0) && (1 != sscanf (&ns_uname[slen - 1], "-%u", &idx))) + slen--; + if (slen == 0) + return GNUNET_SYSERR; + name = GNUNET_strdup (ns_uname); + name[slen - 1] = '\0'; + GNUNET_CRYPTO_hash (name, strlen (name), &nh); + GNUNET_free (name); + fn = get_data_filename (cfg, PS_NAMES_DIR, &nh); + GNUNET_assert (fn != NULL); + + if ((GNUNET_OK != GNUNET_DISK_file_test (fn) || + (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES))) || + ((idx + 1) * sizeof (GNUNET_HashCode) > len)) + { + GNUNET_free (fn); + return GNUNET_SYSERR; + } + fh = GNUNET_DISK_file_open (fn, + GNUNET_DISK_OPEN_CREATE | + GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + GNUNET_free (fn); + GNUNET_DISK_file_seek (fh, idx * sizeof (GNUNET_HashCode), + GNUNET_DISK_SEEK_SET); + if (sizeof (GNUNET_HashCode) != + GNUNET_DISK_file_read (fh, nsid, sizeof (GNUNET_HashCode))) + { + GNUNET_DISK_file_close (fh); + return GNUNET_SYSERR; + } + GNUNET_DISK_file_close (fh); + return GNUNET_OK; +} + + + +/** + * struct used to list the pseudonym + */ +struct ListPseudonymClosure +{ + + /** + * iterator over pseudonym + */ + GNUNET_PSEUDONYM_Iterator iterator; + + /** + * Closure for iterator. + */ + void *closure; + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + + + +/** + * the help function to list all available pseudonyms + * @param cls point to a struct ListPseudonymClosure + * @param fullname name of pseudonym + */ +static int +list_pseudonym_helper (void *cls, const char *fullname) +{ + struct ListPseudonymClosure *c = cls; + int ret; + GNUNET_HashCode id; + int rating; + struct GNUNET_CONTAINER_MetaData *meta; + const char *fn; + char *str; + + if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) + return GNUNET_OK; + fn = &fullname[strlen (fullname) + 1 - + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + if (fn[-1] != DIR_SEPARATOR) + return GNUNET_OK; + ret = GNUNET_OK; + if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (fn, &id)) + return GNUNET_OK; /* invalid name */ + str = NULL; + if (GNUNET_OK != read_info (c->cfg, &id, &meta, &rating, &str)) + return GNUNET_OK; /* ignore entry */ + GNUNET_free_non_null (str); + if (c->iterator != NULL) + ret = c->iterator (c->closure, &id, meta, rating); + GNUNET_CONTAINER_meta_data_destroy (meta); + return ret; +} + + +/** + * List all available pseudonyms. + * + * @param cfg overall configuration + * @param iterator function to call for each pseudonym + * @param closure closure for iterator + * @return number of pseudonyms found + */ +int +GNUNET_PSEUDONYM_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_PSEUDONYM_Iterator iterator, void *closure) +{ + struct ListPseudonymClosure cls; + char *fn; + int ret; + + cls.iterator = iterator; + cls.closure = closure; + cls.cfg = cfg; + fn = get_data_filename (cfg, PS_METADATA_DIR, NULL); + GNUNET_assert (fn != NULL); + GNUNET_DISK_directory_create (fn); + ret = GNUNET_DISK_directory_scan (fn, &list_pseudonym_helper, &cls); + GNUNET_free (fn); + return ret; +} + + +/** + * Change the ranking of a pseudonym. + * + * @param cfg overall configuration + * @param nsid id of the pseudonym + * @param delta by how much should the rating be + * changed? + * @return new rating of the pseudonym + */ +int +GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * nsid, int delta) +{ + struct GNUNET_CONTAINER_MetaData *meta; + int ret; + int32_t ranking; + char *name; + + name = NULL; + ret = read_info (cfg, nsid, &meta, &ranking, &name); + if (ret == GNUNET_SYSERR) + { + ranking = 0; + meta = GNUNET_CONTAINER_meta_data_create (); + } + ranking += delta; + write_pseudonym_info (cfg, nsid, meta, ranking, name); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_free_non_null (name); + return ranking; +} + + +/** + * Add a pseudonym to the set of known pseudonyms. + * For all pseudonym advertisements that we discover + * FS should automatically call this function. + * + * @param cfg overall configuration + * @param id the pseudonym identifier + * @param meta metadata for the pseudonym + */ +void +GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, + const GNUNET_HashCode * id, + const struct GNUNET_CONTAINER_MetaData *meta) +{ + char *name; + int32_t ranking; + struct GNUNET_CONTAINER_MetaData *old; + char *fn; + struct stat sbuf; + + ranking = 0; + fn = get_data_filename (cfg, PS_METADATA_DIR, id); + GNUNET_assert (fn != NULL); + + if ((0 == STAT (fn, &sbuf)) && + (GNUNET_OK == read_info (cfg, id, &old, &ranking, &name))) + { + GNUNET_CONTAINER_meta_data_merge (old, meta); + write_pseudonym_info (cfg, id, old, ranking, name); + GNUNET_CONTAINER_meta_data_destroy (old); + GNUNET_free_non_null (name); + } + else + { + write_pseudonym_info (cfg, id, meta, ranking, NULL); + } + GNUNET_free (fn); + internal_notify (id, meta, ranking); +} + + +/* end of pseudonym.c */ diff --git a/src/util/resolver.conf.in b/src/util/resolver.conf.in new file mode 100644 index 0000000..671ea0e --- /dev/null +++ b/src/util/resolver.conf.in @@ -0,0 +1,22 @@ +[resolver] +AUTOSTART = YES +@UNIXONLY@ PORT = 2089 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-resolver +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-resolver.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = NO +# DISABLE_SOCKET_FORWARDING = NO +# USERNAME = +# MAXBUF = +# TIMEOUT = +# DISABLEV6 = +# BINDTO = +# REJECT_FROM = +# REJECT_FROM6 = +# PREFIX = + diff --git a/src/util/resolver.h b/src/util/resolver.h new file mode 100644 index 0000000..2c0de99 --- /dev/null +++ b/src/util/resolver.h @@ -0,0 +1,69 @@ +/* + This file is part of GNUnet. + (C) 2009, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Christian Grothoff + * @file util/resolver.h + */ +#ifndef RESOLVER_H +#define RESOLVER_H + +#include "gnunet_common.h" + +#define DEBUG_RESOLVER GNUNET_EXTRA_LOGGING + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Request for the resolver. Followed by either the "struct sockaddr" + * or the 0-terminated hostname. + * + * The response will be one or more messages of type + * RESOLVER_RESPONSE, each with the message header immediately + * followed by the requested data (0-terminated hostname or struct + * in[6]_addr, depending on direction). The last RESOLVER_RESPONSE + * will just be a header without any data (used to indicate the end of + * the list). + */ +struct GNUNET_RESOLVER_GetMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST + */ + struct GNUNET_MessageHeader header; + + /** + * GNUNET_YES to get hostname from IP, + * GNUNET_NO to get IP from hostname. + */ + int32_t direction GNUNET_PACKED; + + /** + * Address family to use (AF_INET, AF_INET6 or AF_UNSPEC). + */ + int32_t af GNUNET_PACKED; + + /* followed by 0-terminated string for A/AAAA-lookup or + by 'struct in_addr' / 'struct in6_addr' for reverse lookup */ + +}; +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c new file mode 100644 index 0000000..9d5ae6c --- /dev/null +++ b/src/util/resolver_api.c @@ -0,0 +1,972 @@ +/* + This file is part of GNUnet. + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/resolver_api.c + * @brief resolver for writing a tool + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_client_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_resolver_service.h" +#include "gnunet_server_lib.h" +#include "resolver.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "resolver-api", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "resolver-api", syscall) + +/** + * Maximum supported length for a hostname + */ +#define MAX_HOSTNAME 1024 + + +/** + * Possible hostnames for "loopback". + */ +static const char *loopback[] = { + "localhost", + "ip6-localnet", + NULL +}; + + +/** + * Configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *resolver_cfg; + +/** + * Our connection to the resolver service, created on-demand, but then + * persists until error or shutdown. + */ +static struct GNUNET_CLIENT_Connection *client; + +/** + * Head of DLL of requests. + */ +static struct GNUNET_RESOLVER_RequestHandle *req_head; + +/** + * Tail of DLL of requests. + */ +static struct GNUNET_RESOLVER_RequestHandle *req_tail; + +/** + * How long should we wait to reconnect? + */ +static struct GNUNET_TIME_Relative backoff; + +/** + * Task for reconnecting. + */ +static GNUNET_SCHEDULER_TaskIdentifier r_task; + +/** + * Task ID of shutdown task; only present while we have a + * connection to the resolver service. + */ +static GNUNET_SCHEDULER_TaskIdentifier s_task; + + +/** + * Handle to a request given to the resolver. Can be used to cancel + * the request prior to the timeout or successful execution. Also + * used to track our internal state for the request. + */ +struct GNUNET_RESOLVER_RequestHandle +{ + + /** + * Next entry in DLL of requests. + */ + struct GNUNET_RESOLVER_RequestHandle *next; + + /** + * Previous entry in DLL of requests. + */ + struct GNUNET_RESOLVER_RequestHandle *prev; + + /** + * Callback if this is an name resolution request, + * otherwise NULL. + */ + GNUNET_RESOLVER_AddressCallback addr_callback; + + /** + * Callback if this is a reverse lookup request, + * otherwise NULL. + */ + GNUNET_RESOLVER_HostnameCallback name_callback; + + /** + * Closure for the respective "callback". + */ + void *cls; + + /** + * When should this request time out? + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Task handle for numeric lookups. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Desired address family. + */ + int af; + + /** + * Has this request been transmitted to the service? + * GNUNET_YES if transmitted + * GNUNET_YES if not transmitted + * GNUNET_SYSERR when request was canceled + */ + int was_transmitted; + + /** + * Did we add this request to the queue? + */ + int was_queued; + + /** + * Desired direction (IP to name or name to IP) + */ + int direction; + + /** + * GNUNET_YES if a response was received + */ + int received_response; + + /** + * Length of the data that follows this struct. + */ + size_t data_len; +}; + + +/** + * Check that the resolver service runs on localhost + * (or equivalent). + */ +static void +check_config () +{ + char *hostname; + unsigned int i; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + + memset (&v4, 0, sizeof (v4)); + v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + v4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + v4.sin_len = sizeof (v4); +#endif + memset (&v6, 0, sizeof (v6)); + v6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + v6.sin6_len = sizeof (v6); +#endif + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (resolver_cfg, "resolver", + "HOSTNAME", &hostname)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Must specify `%s' for `%s' in configuration!\n"), "HOSTNAME", + "resolver"); + GNUNET_assert (0); + } + if ((1 != inet_pton (AF_INET, hostname, &v4)) || + (1 != inet_pton (AF_INET6, hostname, &v6))) + { + GNUNET_free (hostname); + return; + } + i = 0; + while (loopback[i] != NULL) + if (0 == strcasecmp (loopback[i++], hostname)) + { + GNUNET_free (hostname); + return; + } + LOG (GNUNET_ERROR_TYPE_ERROR, + _ + ("Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n"), + "localhost", "HOSTNAME", "resolver"); + GNUNET_free (hostname); + GNUNET_assert (0); +} + + +/** + * Create the connection to the resolver service. + * + * @param cfg configuration to use + */ +void +GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_assert (NULL != cfg); + backoff = GNUNET_TIME_UNIT_MILLISECONDS; + resolver_cfg = cfg; + check_config (); +} + + +/** + * Destroy the connection to the resolver service. + */ +void +GNUNET_RESOLVER_disconnect () +{ + GNUNET_assert (NULL == req_head); + GNUNET_assert (NULL == req_tail); + if (NULL != client) + { +#if DEBUG_RESOLVER + LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from DNS service\n"); +#endif + GNUNET_CLIENT_disconnect (client, GNUNET_NO); + client = NULL; + } + if (r_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (r_task); + r_task = GNUNET_SCHEDULER_NO_TASK; + } + if (s_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (s_task); + s_task = GNUNET_SCHEDULER_NO_TASK; + } +} + + +/** + * Convert IP address to string without DNS resolution. + * + * @param af address family + * @param ip the address + * @param ip_len number of bytes in ip + * @return address as a string, NULL on error + */ +static char * +no_resolve (int af, + const void *ip, socklen_t ip_len) +{ + char buf[INET6_ADDRSTRLEN]; + + switch (af) + { + case AF_INET: + if (ip_len != sizeof (struct in_addr)) + return NULL; + if (NULL == + inet_ntop (AF_INET, ip, buf, sizeof (buf))) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); + return NULL; + } + break; + case AF_INET6: + if (ip_len != sizeof (struct in6_addr)) + return NULL; + if (NULL == + inet_ntop (AF_INET6, ip, buf, sizeof (buf))) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); + return NULL; + } + break; + default: + GNUNET_break (0); + return NULL; + } + return GNUNET_strdup (buf); +} + + +/** + * Adjust exponential back-off and reconnect to the service. + */ +static void +reconnect (); + + +/** + * Process pending requests to the resolver. + */ +static void +process_requests (); + + +/** + * Process response with a hostname for a DNS lookup. + * + * @param cls our "struct GNUNET_RESOLVER_RequestHandle" context + * @param msg message with the hostname, NULL on error + */ +static void +handle_response (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_RESOLVER_RequestHandle *rh = cls; + uint16_t size; + +#if DEBUG_RESOLVER + LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving response from DNS service\n"); +#endif + if (msg == NULL) + { + char buf[INET6_ADDRSTRLEN]; + + if (NULL != rh->name_callback) + LOG (GNUNET_ERROR_TYPE_INFO, + _("Timeout trying to resolve IP address `%s'.\n"), + inet_ntop (rh->af, (const void *) &rh[1], buf, sizeof(buf))); + else + LOG (GNUNET_ERROR_TYPE_INFO, + _("Timeout trying to resolve hostname `%s'.\n"), + (const char *) &rh[1]); + /* check if request was canceled */ + if (rh->was_transmitted != GNUNET_SYSERR) + { + if (NULL != rh->name_callback) + { + /* no reverse lookup was successful, return ip as string */ + if (rh->received_response == GNUNET_NO) + rh->name_callback (rh->cls, + no_resolve (rh->af, + &rh[1], + rh->data_len)); + /* at least one reverse lookup was successful */ + else + rh->name_callback (rh->cls, NULL); + } + if (NULL != rh->addr_callback) + rh->addr_callback (rh->cls, NULL, 0); + } + GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); + GNUNET_free (rh); + GNUNET_CLIENT_disconnect (client, GNUNET_NO); + client = NULL; + reconnect (); + return; + } + if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type)) + { + GNUNET_break (0); + GNUNET_CLIENT_disconnect (client, GNUNET_NO); + client = NULL; + reconnect (); + return; + } + size = ntohs (msg->size); + /* message contains not data, just header */ + if (size == sizeof (struct GNUNET_MessageHeader)) + { + /* check if request was canceled */ + if (rh->was_transmitted != GNUNET_SYSERR) + { + if (NULL != rh->name_callback) + rh->name_callback (rh->cls, NULL); + if (NULL != rh->addr_callback) + rh->addr_callback (rh->cls, NULL, 0); + } + GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); + GNUNET_free (rh); + process_requests (); + return; + } + /* return reverse lookup results to caller */ + if (NULL != rh->name_callback) + { + const char *hostname; + + hostname = (const char *) &msg[1]; + if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0') + { + GNUNET_break (0); + if (rh->was_transmitted != GNUNET_SYSERR) + rh->name_callback (rh->cls, NULL); + GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); + GNUNET_free (rh); + GNUNET_CLIENT_disconnect (client, GNUNET_NO); + client = NULL; + reconnect (); + return; + } +#if DEBUG_RESOLVER + LOG (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s' for IP `%s'.\n"), + hostname, GNUNET_a2s ((const void *) &rh[1], rh->data_len)); +#endif + if (rh->was_transmitted != GNUNET_SYSERR) + rh->name_callback (rh->cls, hostname); + rh->received_response = GNUNET_YES; + GNUNET_CLIENT_receive (client, &handle_response, rh, + GNUNET_TIME_absolute_get_remaining (rh->timeout)); + } + /* return lookup results to caller */ + if (NULL != rh->addr_callback) + { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + const struct sockaddr *sa; + socklen_t salen; + const void *ip; + size_t ip_len; + + ip = &msg[1]; + ip_len = size - sizeof (struct GNUNET_MessageHeader); + if (ip_len == sizeof (struct in_addr)) + { + memset (&v4, 0, sizeof (v4)); + v4.sin_family = AF_INET; + v4.sin_addr = *(struct in_addr*) ip; +#if HAVE_SOCKADDR_IN_SIN_LEN + v4.sin_len = sizeof (v4); +#endif + salen = sizeof (v4); + sa = (const struct sockaddr *) &v4; + } + else if (ip_len == sizeof (struct in6_addr)) + { + memset (&v6, 0, sizeof (v6)); + v6.sin6_family = AF_INET6; + v6.sin6_addr = *(struct in6_addr*) ip; +#if HAVE_SOCKADDR_IN_SIN_LEN + v6.sin6_len = sizeof (v6); +#endif + salen = sizeof (v6); + sa = (const struct sockaddr *) &v6; + } + else + { + GNUNET_break (0); + if (rh->was_transmitted != GNUNET_SYSERR) + rh->addr_callback (rh->cls, NULL, 0); + GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); + GNUNET_free (rh); + GNUNET_CLIENT_disconnect (client, GNUNET_NO); + client = NULL; + reconnect (); + return; + } + rh->addr_callback (rh->cls, sa, salen); + GNUNET_CLIENT_receive (client, &handle_response, rh, + GNUNET_TIME_absolute_get_remaining (rh->timeout)); + } +} + + +/** + * We've been asked to lookup the address for a hostname and were + * given a valid numeric string. Perform the callbacks for the + * numeric addresses. + * + * @param cls struct GNUNET_RESOLVER_RequestHandle for the request + * @param tc unused scheduler context + */ +static void +numeric_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_RESOLVER_RequestHandle *rh = cls; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + const char *hostname; + + memset (&v4, 0, sizeof (v4)); + v4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + v4.sin_len = sizeof (v4); +#endif + memset (&v6, 0, sizeof (v6)); + v6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + v6.sin6_len = sizeof (v6); +#endif + hostname = (const char *) &rh[1]; + if (((rh->af == AF_UNSPEC) || (rh->af == AF_INET)) && + (1 == inet_pton (AF_INET, hostname, &v4.sin_addr))) + { + rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4)); + if ((rh->af == AF_UNSPEC) && + (1 == inet_pton (AF_INET6, hostname, &v6.sin6_addr))) + { + /* this can happen on some systems IF "hostname" is "localhost" */ + rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6)); + } + rh->addr_callback (rh->cls, NULL, 0); + GNUNET_free (rh); + return; + } + if (((rh->af == AF_UNSPEC) || (rh->af == AF_INET6)) && + (1 == inet_pton (AF_INET6, hostname, &v6.sin6_addr))) + { + rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6)); + rh->addr_callback (rh->cls, NULL, 0); + GNUNET_free (rh); + return; + } + /* why are we here? this task should not have been scheduled! */ + GNUNET_assert (0); + GNUNET_free (rh); +} + + +/** + * We've been asked to lookup the address for a hostname and were + * given a variant of "loopback". Perform the callbacks for the + * respective loopback numeric addresses. + * + * @param cls struct GNUNET_RESOLVER_RequestHandle for the request + * @param tc unused scheduler context + */ +static void +loopback_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_RESOLVER_RequestHandle *rh = cls; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + + memset (&v4, 0, sizeof (v4)); + v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + v4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + v4.sin_len = sizeof (v4); +#endif + memset (&v6, 0, sizeof (v6)); + v6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + v6.sin6_len = sizeof (v6); +#endif + v6.sin6_addr = in6addr_loopback; + switch (rh->af) + { + case AF_INET: + rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4)); + break; + case AF_INET6: + rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6)); + break; + case AF_UNSPEC: + rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6)); + rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4)); + break; + default: + GNUNET_break (0); + break; + } + rh->addr_callback (rh->cls, NULL, 0); + GNUNET_free (rh); +} + + +/** + * Task executed on system shutdown. + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + s_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_RESOLVER_disconnect (); +} + + +/** + * Process pending requests to the resolver. + */ +static void +process_requests () +{ + struct GNUNET_RESOLVER_GetMessage *msg; + char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + struct GNUNET_RESOLVER_RequestHandle *rh; + + if (NULL == client) + { + reconnect (); + return; + } + rh = req_head; + if (NULL == rh) + { + /* nothing to do, release socket really soon if there is nothing + * else happening... */ + s_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, + &shutdown_task, NULL); + return; + } + if (GNUNET_YES == rh->was_transmitted) + return; /* waiting for reply */ + msg = (struct GNUNET_RESOLVER_GetMessage *) buf; + msg->header.size = + htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + rh->data_len); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); + msg->direction = htonl (rh->direction); + msg->af = htonl (rh->af); + memcpy (&msg[1], &rh[1], rh->data_len); +#if DEBUG_RESOLVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting DNS resolution request to DNS service\n"); +#endif + if (GNUNET_OK != + GNUNET_CLIENT_transmit_and_get_response (client, &msg->header, + GNUNET_TIME_absolute_get_remaining + (rh->timeout), GNUNET_YES, + &handle_response, rh)) + { + GNUNET_CLIENT_disconnect (client, GNUNET_NO); + client = NULL; + reconnect (); + return; + } + rh->was_transmitted = GNUNET_YES; +} + + +/** + * Now try to reconnect to the resolver service. + * + * @param cls NULL + * @param tc scheduler context + */ +static void +reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + r_task = GNUNET_SCHEDULER_NO_TASK; + if (NULL == req_head) + return; /* no work pending */ + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; +#if DEBUG_RESOLVER + LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to DNS service\n"); +#endif + client = GNUNET_CLIENT_connect ("resolver", resolver_cfg); + if (NULL == client) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect, will try again later\n"); + reconnect (); + return; + } + process_requests (); +} + + +/** + * Adjust exponential back-off and reconnect to the service. + */ +static void +reconnect () +{ + struct GNUNET_RESOLVER_RequestHandle *rh; + + if (GNUNET_SCHEDULER_NO_TASK != r_task) + return; + GNUNET_assert (NULL == client); + if (NULL != (rh = req_head)) + { + switch (rh->was_transmitted) + { + case GNUNET_NO: + /* nothing more to do */ + break; + case GNUNET_YES: + /* disconnected, transmit again! */ + rh->was_transmitted = GNUNET_NO; + break; + case GNUNET_SYSERR: + /* request was cancelled, remove entirely */ + GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); + GNUNET_free (rh); + break; + default: + GNUNET_assert (0); + break; + } + } +#if DEBUG_RESOLVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Will try to connect to DNS service in %llu ms\n", + (unsigned long long) backoff.rel_value); +#endif + GNUNET_assert (NULL != resolver_cfg); + r_task = GNUNET_SCHEDULER_add_delayed (backoff, &reconnect_task, NULL); + backoff = GNUNET_TIME_relative_multiply (backoff, 2); +} + + +/** + * Convert a string to one or more IP addresses. + * + * @param hostname the hostname to resolve + * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" + * @param callback function to call with addresses + * @param callback_cls closure for callback + * @param timeout how long to try resolving + * @return handle that can be used to cancel the request, NULL on error + */ +struct GNUNET_RESOLVER_RequestHandle * +GNUNET_RESOLVER_ip_get (const char *hostname, int af, + struct GNUNET_TIME_Relative timeout, + GNUNET_RESOLVER_AddressCallback callback, + void *callback_cls) +{ + struct GNUNET_RESOLVER_RequestHandle *rh; + size_t slen; + unsigned int i; + struct in_addr v4; + struct in6_addr v6; + + slen = strlen (hostname) + 1; + if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >= + GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return NULL; + } + rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen); + rh->af = af; + rh->addr_callback = callback; + rh->cls = callback_cls; + memcpy (&rh[1], hostname, slen); + rh->data_len = slen; + rh->timeout = GNUNET_TIME_relative_to_absolute (timeout); + rh->direction = GNUNET_NO; + /* first, check if this is a numeric address */ + if (((1 == inet_pton (AF_INET, hostname, &v4)) && + ((af == AF_INET) || (af == AF_UNSPEC))) || + ((1 == inet_pton (AF_INET6, hostname, &v6)) && + ((af == AF_INET6) || (af == AF_UNSPEC)))) + { + rh->task = GNUNET_SCHEDULER_add_now (&numeric_resolution, rh); + return rh; + } + /* then, check if this is a loopback address */ + i = 0; + while (loopback[i] != NULL) + if (0 == strcasecmp (loopback[i++], hostname)) + { + rh->task = GNUNET_SCHEDULER_add_now (&loopback_resolution, rh); + return rh; + } + GNUNET_CONTAINER_DLL_insert_tail (req_head, req_tail, rh); + rh->was_queued = GNUNET_YES; + if (s_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (s_task); + s_task = GNUNET_SCHEDULER_NO_TASK; + } + process_requests (); + return rh; +} + + +/** + * We've been asked to convert an address to a string without + * a reverse lookup. Do it. + * + * @param cls struct GNUNET_RESOLVER_RequestHandle for the request + * @param tc unused scheduler context + */ +static void +numeric_reverse (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_RESOLVER_RequestHandle *rh = cls; + char *result; + + result = no_resolve (rh->af, &rh[1], rh->data_len); +#if DEBUG_RESOLVER + LOG (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), result); +#endif + if (result != NULL) + { + rh->name_callback (rh->cls, result); + GNUNET_free (result); + } + rh->name_callback (rh->cls, NULL); + GNUNET_free (rh); +} + + +/** + * Get an IP address as a string. + * + * @param sa host address + * @param salen length of host address + * @param do_resolve use GNUNET_NO to return numeric hostname + * @param timeout how long to try resolving + * @param callback function to call with hostnames + * last callback is NULL when finished + * @param cls closure for callback + * @return handle that can be used to cancel the request + */ +struct GNUNET_RESOLVER_RequestHandle * +GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa, socklen_t salen, + int do_resolve, + struct GNUNET_TIME_Relative timeout, + GNUNET_RESOLVER_HostnameCallback callback, + void *cls) +{ + struct GNUNET_RESOLVER_RequestHandle *rh; + size_t ip_len; + const void *ip; + + check_config (); + switch (sa->sa_family) + { + case AF_INET: + ip_len = sizeof (struct in_addr); + ip = &((const struct sockaddr_in*)sa)->sin_addr; + break; + case AF_INET6: + ip_len = sizeof (struct in6_addr); + ip = &((const struct sockaddr_in6*)sa)->sin6_addr; + break; + default: + GNUNET_break (0); + return NULL; + } + rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen); + rh->name_callback = callback; + rh->cls = cls; + rh->af = sa->sa_family; + rh->timeout = GNUNET_TIME_relative_to_absolute (timeout); + memcpy (&rh[1], ip, ip_len); + rh->data_len = ip_len; + rh->direction = GNUNET_YES; + rh->received_response = GNUNET_NO; + if (GNUNET_NO == do_resolve) + { + rh->task = GNUNET_SCHEDULER_add_now (&numeric_reverse, rh); + return rh; + } + GNUNET_CONTAINER_DLL_insert_tail (req_head, req_tail, rh); + rh->was_queued = GNUNET_YES; + if (s_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (s_task); + s_task = GNUNET_SCHEDULER_NO_TASK; + } + process_requests (); + return rh; +} + + +/** + * Get local fully qualified af name + * + * @return fqdn + */ +char * +GNUNET_RESOLVER_local_fqdn_get () +{ + struct hostent *host; + char hostname[GNUNET_OS_get_hostname_max_length () + 1]; + + if (0 != gethostname (hostname, sizeof (hostname) - 1)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "gethostname"); + return NULL; + } +#if DEBUG_RESOLVER + LOG (GNUNET_ERROR_TYPE_DEBUG, _("Resolving our FQDN `%s'\n"), hostname); +#endif + host = gethostbyname (hostname); + if (NULL == host) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not resolve our FQDN : %s\n"), + hstrerror (h_errno)); + return NULL; + } + return GNUNET_strdup (host->h_name); +} + + +/** + * Looking our own hostname. + * + * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" + * @param callback function to call with addresses + * @param cls closure for callback + * @param timeout how long to try resolving + * @return handle that can be used to cancel the request, NULL on error + */ +struct GNUNET_RESOLVER_RequestHandle * +GNUNET_RESOLVER_hostname_resolve (int af, + struct GNUNET_TIME_Relative timeout, + GNUNET_RESOLVER_AddressCallback callback, + void *cls) +{ + char hostname[GNUNET_OS_get_hostname_max_length () + 1]; + + if (0 != gethostname (hostname, sizeof (hostname) - 1)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "gethostname"); + return NULL; + } +#if DEBUG_RESOLVER + LOG (GNUNET_ERROR_TYPE_DEBUG, _("Resolving our hostname `%s'\n"), hostname); +#endif + return GNUNET_RESOLVER_ip_get (hostname, af, timeout, callback, cls); +} + + +/** + * Cancel a request that is still pending with the resolver. + * Note that a client MUST NOT cancel a request that has + * been completed (i.e, the callback has been called to + * signal timeout or the final result). + * + * @param rh handle of request to cancel + */ +void +GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh) +{ + if (rh->task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (rh->task); + rh->task = GNUNET_SCHEDULER_NO_TASK; + } + if (rh->was_transmitted == GNUNET_NO) + { + if (rh->was_queued == GNUNET_YES) + GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); + GNUNET_free (rh); + return; + } + GNUNET_assert (rh->was_transmitted == GNUNET_YES); + rh->was_transmitted = GNUNET_SYSERR; /* mark as cancelled */ +} + + +/* end of resolver_api.c */ diff --git a/src/util/scheduler.c b/src/util/scheduler.c new file mode 100644 index 0000000..c54672f --- /dev/null +++ b/src/util/scheduler.c @@ -0,0 +1,1696 @@ +/* + This file is part of GNUnet + (C) 2009, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file util/scheduler.c + * @brief schedule computations using continuation passing style + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_os_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_signal_lib.h" +#include "gnunet_time_lib.h" +#include "disk.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util-scheduler", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-scheduler", syscall) + + +#ifdef LINUX +#include "execinfo.h" + +/** + * Use lsof to generate file descriptor reports on select error? + * (turn off for stable releases). + */ +#define USE_LSOF GNUNET_NO + +/** + * Obtain trace information for all scheduler calls that schedule tasks. + */ +#define EXECINFO GNUNET_NO + +/** + * Check each file descriptor before adding + */ +#define DEBUG_FDS GNUNET_NO + +/** + * Depth of the traces collected via EXECINFO. + */ +#define MAX_TRACE_DEPTH 50 +#endif + +/** + * Should we figure out which tasks are delayed for a while + * before they are run? (Consider using in combination with EXECINFO). + */ +#define PROFILE_DELAYS GNUNET_NO + +/** + * Task that were in the queue for longer than this are reported if + * PROFILE_DELAYS is active. + */ +#define DELAY_THRESHOLD GNUNET_TIME_UNIT_SECONDS + + +/** + * Linked list of pending tasks. + */ +struct Task +{ + /** + * This is a linked list. + */ + struct Task *next; + + /** + * Function to run when ready. + */ + GNUNET_SCHEDULER_Task callback; + + /** + * Closure for the callback. + */ + void *callback_cls; + + /** + * Set of file descriptors this task is waiting + * for for reading. Once ready, this is updated + * to reflect the set of file descriptors ready + * for operation. + */ + struct GNUNET_NETWORK_FDSet *read_set; + + /** + * Set of file descriptors this task is waiting for for writing. + * Once ready, this is updated to reflect the set of file + * descriptors ready for operation. + */ + struct GNUNET_NETWORK_FDSet *write_set; + + /** + * Unique task identifier. + */ + GNUNET_SCHEDULER_TaskIdentifier id; + + /** + * Identifier of a prerequisite task. + */ + GNUNET_SCHEDULER_TaskIdentifier prereq_id; + + /** + * Absolute timeout value for the task, or + * GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout". + */ + struct GNUNET_TIME_Absolute timeout; + +#if PROFILE_DELAYS + /** + * When was the task scheduled? + */ + struct GNUNET_TIME_Absolute start_time; +#endif + + /** + * Why is the task ready? Set after task is added to ready queue. + * Initially set to zero. All reasons that have already been + * satisfied (i.e. read or write ready) will be set over time. + */ + enum GNUNET_SCHEDULER_Reason reason; + + /** + * Task priority. + */ + enum GNUNET_SCHEDULER_Priority priority; + + /** + * Set if we only wait for reading from a single FD, otherwise -1. + */ + int read_fd; + + /** + * Set if we only wait for writing to a single FD, otherwise -1. + */ + int write_fd; + + /** + * Should the existence of this task in the queue be counted as + * reason to not shutdown the scheduler? + */ + int lifeness; + +#if EXECINFO + /** + * Array of strings which make up a backtrace from the point when this + * task was scheduled (essentially, who scheduled the task?) + */ + char **backtrace_strings; + + /** + * Size of the backtrace_strings array + */ + int num_backtrace_strings; +#endif + + +}; + + +/** + * List of tasks waiting for an event. + */ +static struct Task *pending; + +/** + * List of tasks waiting ONLY for a timeout event. + * Sorted by timeout (earliest first). Used so that + * we do not traverse the list of these tasks when + * building select sets (we just look at the head + * to determine the respective timeout ONCE). + */ +static struct Task *pending_timeout; + +/** + * Last inserted task waiting ONLY for a timeout event. + * Used to (heuristically) speed up insertion. + */ +static struct Task *pending_timeout_last; + +/** + * ID of the task that is running right now. + */ +static struct Task *active_task; + +/** + * List of tasks ready to run right now, + * grouped by importance. + */ +static struct Task *ready[GNUNET_SCHEDULER_PRIORITY_COUNT]; + +/** + * Identity of the last task queued. Incremented for each task to + * generate a unique task ID (it is virtually impossible to start + * more than 2^64 tasks during the lifetime of a process). + */ +static GNUNET_SCHEDULER_TaskIdentifier last_id; + +/** + * Highest number so that all tasks with smaller identifiers + * have already completed. Also the lowest number of a task + * still waiting to be executed. + */ +static GNUNET_SCHEDULER_TaskIdentifier lowest_pending_id; + +/** + * Number of tasks on the ready list. + */ +static unsigned int ready_count; + +/** + * How many tasks have we run so far? + */ +static unsigned long long tasks_run; + +/** + * Priority of the task running right now. Only + * valid while a task is running. + */ +static enum GNUNET_SCHEDULER_Priority current_priority; + +/** + * Priority of the highest task added in the current select + * iteration. + */ +static enum GNUNET_SCHEDULER_Priority max_priority_added; + +/** + * Value of the 'lifeness' flag for the current task. + */ +static int current_lifeness; + +/** + * Function to use as a select() in the scheduler. + * If NULL, we use GNUNET_NETWORK_socket_select (). + */ +static GNUNET_SCHEDULER_select scheduler_select; + +/** + * Closure for 'scheduler_select'. + */ +static void *scheduler_select_cls; + +/** + * Sets the select function to use in the scheduler (scheduler_select). + * + * @param new_select new select function to use + * @param new_select_cls closure for 'new_select' + * @return previously used select function, NULL for default + */ +void +GNUNET_SCHEDULER_set_select (GNUNET_SCHEDULER_select new_select, + void *new_select_cls) +{ + scheduler_select = new_select; + scheduler_select_cls = new_select_cls; +} + + +/** + * Check that the given priority is legal (and return it). + * + * @param p priority value to check + * @return p on success, 0 on error + */ +static enum GNUNET_SCHEDULER_Priority +check_priority (enum GNUNET_SCHEDULER_Priority p) +{ + if ((p >= 0) && (p < GNUNET_SCHEDULER_PRIORITY_COUNT)) + return p; + GNUNET_assert (0); + return 0; /* make compiler happy */ +} + + +/** + * Is a task with this identifier still pending? Also updates + * "lowest_pending_id" as a side-effect (for faster checks in the + * future), but only if the return value is "GNUNET_NO" (and + * the "lowest_pending_id" check failed). + * + * @param id which task are we checking for + * @return GNUNET_YES if so, GNUNET_NO if not + */ +static int +is_pending (GNUNET_SCHEDULER_TaskIdentifier id) +{ + struct Task *pos; + enum GNUNET_SCHEDULER_Priority p; + GNUNET_SCHEDULER_TaskIdentifier min; + + if (id < lowest_pending_id) + return GNUNET_NO; + min = -1; /* maximum value */ + pos = pending; + while (pos != NULL) + { + if (pos->id == id) + return GNUNET_YES; + if (pos->id < min) + min = pos->id; + pos = pos->next; + } + pos = pending_timeout; + while (pos != NULL) + { + if (pos->id == id) + return GNUNET_YES; + if (pos->id < min) + min = pos->id; + pos = pos->next; + } + for (p = 0; p < GNUNET_SCHEDULER_PRIORITY_COUNT; p++) + { + pos = ready[p]; + while (pos != NULL) + { + if (pos->id == id) + return GNUNET_YES; + if (pos->id < min) + min = pos->id; + pos = pos->next; + } + } + lowest_pending_id = min; + return GNUNET_NO; +} + + +/** + * Update all sets and timeout for select. + * + * @param rs read-set, set to all FDs we would like to read (updated) + * @param ws write-set, set to all FDs we would like to write (updated) + * @param timeout next timeout (updated) + */ +static void +update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws, + struct GNUNET_TIME_Relative *timeout) +{ + struct Task *pos; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Relative to; + + now = GNUNET_TIME_absolute_get (); + pos = pending_timeout; + if (pos != NULL) + { + to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); + if (timeout->rel_value > to.rel_value) + *timeout = to; + if (pos->reason != 0) + *timeout = GNUNET_TIME_UNIT_ZERO; + } + pos = pending; + while (pos != NULL) + { + if ((pos->prereq_id != GNUNET_SCHEDULER_NO_TASK) && + (GNUNET_YES == is_pending (pos->prereq_id))) + { + pos = pos->next; + continue; + } + if (pos->timeout.abs_value != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) + { + to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); + if (timeout->rel_value > to.rel_value) + *timeout = to; + } + if (pos->read_fd != -1) + GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); + if (pos->write_fd != -1) + GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); + if (pos->read_set != NULL) + GNUNET_NETWORK_fdset_add (rs, pos->read_set); + if (pos->write_set != NULL) + GNUNET_NETWORK_fdset_add (ws, pos->write_set); + if (pos->reason != 0) + *timeout = GNUNET_TIME_UNIT_ZERO; + pos = pos->next; + } +} + + +/** + * Check if the ready set overlaps with the set we want to have ready. + * If so, update the want set (set all FDs that are ready). If not, + * return GNUNET_NO. + * + * @param ready set that is ready + * @param want set that we want to be ready + * @return GNUNET_YES if there was some overlap + */ +static int +set_overlaps (const struct GNUNET_NETWORK_FDSet *ready, + struct GNUNET_NETWORK_FDSet *want) +{ + if ((NULL == want) || (NULL == ready)) + return GNUNET_NO; + if (GNUNET_NETWORK_fdset_overlap (ready, want)) + { + /* copy all over (yes, there maybe unrelated bits, + * but this should not hurt well-written clients) */ + GNUNET_NETWORK_fdset_copy (want, ready); + return GNUNET_YES; + } + return GNUNET_NO; +} + + +/** + * Check if the given task is eligible to run now. + * Also set the reason why it is eligible. + * + * @param task task to check if it is ready + * @param now the current time + * @param rs set of FDs ready for reading + * @param ws set of FDs ready for writing + * @return GNUNET_YES if we can run it, GNUNET_NO if not. + */ +static int +is_ready (struct Task *task, struct GNUNET_TIME_Absolute now, + const struct GNUNET_NETWORK_FDSet *rs, + const struct GNUNET_NETWORK_FDSet *ws) +{ + enum GNUNET_SCHEDULER_Reason reason; + + reason = task->reason; + if (now.abs_value >= task->timeout.abs_value) + reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; + if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) && + (((task->read_fd != -1) && + (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (rs, task->read_fd))) || + (set_overlaps (rs, task->read_set)))) + reason |= GNUNET_SCHEDULER_REASON_READ_READY; + if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && + (((task->write_fd != -1) && + (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (ws, task->write_fd))) + || (set_overlaps (ws, task->write_set)))) + reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; + if (reason == 0) + return GNUNET_NO; /* not ready */ + if (task->prereq_id != GNUNET_SCHEDULER_NO_TASK) + { + if (GNUNET_YES == is_pending (task->prereq_id)) + { + task->reason = reason; + return GNUNET_NO; /* prereq waiting */ + } + reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; + } + task->reason = reason; + return GNUNET_YES; +} + + +/** + * Put a task that is ready for execution into the ready queue. + * + * @param task task ready for execution + */ +static void +queue_ready_task (struct Task *task) +{ + enum GNUNET_SCHEDULER_Priority p = task->priority; + + if (0 != (task->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + p = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN; + task->next = ready[check_priority (p)]; + ready[check_priority (p)] = task; + ready_count++; +} + + +/** + * Check which tasks are ready and move them + * to the respective ready queue. + * + * @param rs FDs ready for reading + * @param ws FDs ready for writing + */ +static void +check_ready (const struct GNUNET_NETWORK_FDSet *rs, + const struct GNUNET_NETWORK_FDSet *ws) +{ + struct Task *pos; + struct Task *prev; + struct Task *next; + struct GNUNET_TIME_Absolute now; + + now = GNUNET_TIME_absolute_get (); + prev = NULL; + pos = pending_timeout; + while (pos != NULL) + { + next = pos->next; + if (now.abs_value >= pos->timeout.abs_value) + pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; + if (0 == pos->reason) + break; + pending_timeout = next; + if (pending_timeout_last == pos) + pending_timeout_last = NULL; + queue_ready_task (pos); + pos = next; + } + pos = pending; + while (pos != NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Checking readiness of task: %llu / %p\n", + pos->id, pos->callback_cls); + next = pos->next; + if (GNUNET_YES == is_ready (pos, now, rs, ws)) + { + if (prev == NULL) + pending = next; + else + prev->next = next; + queue_ready_task (pos); + pos = next; + continue; + } + prev = pos; + pos = next; + } +} + + +/** + * Request the shutdown of a scheduler. Marks all currently + * pending tasks as ready because of shutdown. This will + * cause all tasks to run (as soon as possible, respecting + * priorities and prerequisite tasks). Note that tasks + * scheduled AFTER this call may still be delayed arbitrarily. + */ +void +GNUNET_SCHEDULER_shutdown () +{ + struct Task *pos; + int i; + + pos = pending_timeout; + while (pos != NULL) + { + pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; + /* we don't move the task into the ready queue yet; check_ready + * will do that later, possibly adding additional + * readiness-factors */ + pos = pos->next; + } + pos = pending; + while (pos != NULL) + { + pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; + /* we don't move the task into the ready queue yet; check_ready + * will do that later, possibly adding additional + * readiness-factors */ + pos = pos->next; + } + for (i = 0; i < GNUNET_SCHEDULER_PRIORITY_COUNT; i++) + { + pos = ready[i]; + while (pos != NULL) + { + pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; + /* we don't move the task into the ready queue yet; check_ready + * will do that later, possibly adding additional + * readiness-factors */ + pos = pos->next; + } + } +} + + +/** + * Destroy a task (release associated resources) + * + * @param t task to destroy + */ +static void +destroy_task (struct Task *t) +{ + if (NULL != t->read_set) + GNUNET_NETWORK_fdset_destroy (t->read_set); + if (NULL != t->write_set) + GNUNET_NETWORK_fdset_destroy (t->write_set); +#if EXECINFO + GNUNET_free (t->backtrace_strings); +#endif + GNUNET_free (t); +} + + +/** + * Run at least one task in the highest-priority queue that is not + * empty. Keep running tasks until we are either no longer running + * "URGENT" tasks or until we have at least one "pending" task (which + * may become ready, hence we should select on it). Naturally, if + * there are no more ready tasks, we also return. + * + * @param rs FDs ready for reading + * @param ws FDs ready for writing + */ +static void +run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws) +{ + enum GNUNET_SCHEDULER_Priority p; + struct Task *pos; + struct GNUNET_SCHEDULER_TaskContext tc; + + max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP; + do + { + if (ready_count == 0) + return; + GNUNET_assert (ready[GNUNET_SCHEDULER_PRIORITY_KEEP] == NULL); + /* yes, p>0 is correct, 0 is "KEEP" which should + * always be an empty queue (see assertion)! */ + for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--) + { + pos = ready[p]; + if (pos != NULL) + break; + } + GNUNET_assert (pos != NULL); /* ready_count wrong? */ + ready[p] = pos->next; + ready_count--; + if (current_priority != pos->priority) + { + current_priority = pos->priority; + (void) GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), + pos->priority); + } + current_lifeness = pos->lifeness; + active_task = pos; +#if PROFILE_DELAYS + if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value > + DELAY_THRESHOLD.rel_value) + { + LOG (GNUNET_ERROR_TYPE_ERROR, "Task %llu took %llums to be scheduled\n", + pos->id, + (unsigned long long) + GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value); + } +#endif + tc.reason = pos->reason; + tc.read_ready = (pos->read_set == NULL) ? rs : pos->read_set; + if ((pos->read_fd != -1) && + (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY))) + GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); + tc.write_ready = (pos->write_set == NULL) ? ws : pos->write_set; + if ((pos->write_fd != -1) && + (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))) + GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); + if (((tc.reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) && + (pos->write_fd != -1) && + (!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd))) + GNUNET_abort (); // added to ready in previous select loop! + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Running task: %llu / %p\n", pos->id, + pos->callback_cls); + pos->callback (pos->callback_cls, &tc); +#if EXECINFO + int i; + + for (i = 0; i < pos->num_backtrace_strings; i++) + LOG (GNUNET_ERROR_TYPE_ERROR, "Task %llu trace %d: %s\n", pos->id, i, + pos->backtrace_strings[i]); +#endif + active_task = NULL; + destroy_task (pos); + tasks_run++; + } + while ((pending == NULL) || (p >= max_priority_added)); +} + +/** + * Pipe used to communicate shutdown via signal. + */ +static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle; + +/** + * Process ID of this process at the time we installed the various + * signal handlers. + */ +static pid_t my_pid; + +/** + * Signal handler called for SIGPIPE. + */ +#ifndef MINGW +static void +sighandler_pipe () +{ + return; +} +#endif +/** + * Signal handler called for signals that should cause us to shutdown. + */ +static void +sighandler_shutdown () +{ + static char c; + int old_errno = errno; /* backup errno */ + + if (getpid () != my_pid) + exit (1); /* we have fork'ed since the signal handler was created, + * ignore the signal, see https://gnunet.org/vfork discussion */ + GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle + (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE), + &c, sizeof (c)); + errno = old_errno; +} + + +/** + * Check if the system is still life. Trigger shutdown if we + * have tasks, but none of them give us lifeness. + * + * @return GNUNET_OK to continue the main loop, + * GNUNET_NO to exit + */ +static int +check_lifeness () +{ + struct Task *t; + + if (ready_count > 0) + return GNUNET_OK; + for (t = pending; NULL != t; t = t->next) + if (t->lifeness == GNUNET_YES) + return GNUNET_OK; + for (t = pending_timeout; NULL != t; t = t->next) + if (t->lifeness == GNUNET_YES) + return GNUNET_OK; + if ((NULL != pending) || (NULL != pending_timeout)) + { + GNUNET_SCHEDULER_shutdown (); + return GNUNET_OK; + } + return GNUNET_NO; +} + + +/** + * Initialize and run scheduler. This function will return when all + * tasks have completed. On systems with signals, receiving a SIGTERM + * (and other similar signals) will cause "GNUNET_SCHEDULER_shutdown" + * to be run after the active task is complete. As a result, SIGTERM + * causes all active tasks to be scheduled with reason + * "GNUNET_SCHEDULER_REASON_SHUTDOWN". (However, tasks added + * afterwards will execute normally!). Note that any particular signal + * will only shut down one scheduler; applications should always only + * create a single scheduler. + * + * @param task task to run immediately + * @param task_cls closure of task + */ +void +GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls) +{ + struct GNUNET_NETWORK_FDSet *rs; + struct GNUNET_NETWORK_FDSet *ws; + struct GNUNET_TIME_Relative timeout; + int ret; + struct GNUNET_SIGNAL_Context *shc_int; + struct GNUNET_SIGNAL_Context *shc_term; + +#ifndef MINGW + struct GNUNET_SIGNAL_Context *shc_quit; + struct GNUNET_SIGNAL_Context *shc_hup; + struct GNUNET_SIGNAL_Context *shc_pipe; +#endif + unsigned long long last_tr; + unsigned int busy_wait_warning; + const struct GNUNET_DISK_FileHandle *pr; + char c; + + GNUNET_assert (active_task == NULL); + rs = GNUNET_NETWORK_fdset_create (); + ws = GNUNET_NETWORK_fdset_create (); + GNUNET_assert (shutdown_pipe_handle == NULL); + shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); + GNUNET_assert (shutdown_pipe_handle != NULL); + pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, + GNUNET_DISK_PIPE_END_READ); + GNUNET_assert (pr != NULL); + my_pid = getpid (); + shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown); + shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown); +#ifndef MINGW + shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, &sighandler_pipe); + shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, &sighandler_shutdown); + shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown); +#endif + current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; + current_lifeness = GNUNET_YES; + GNUNET_SCHEDULER_add_continuation (task, task_cls, + GNUNET_SCHEDULER_REASON_STARTUP); + active_task = (void *) (long) -1; /* force passing of sanity check */ + GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, + &GNUNET_OS_install_parent_control_handler, + NULL); + active_task = NULL; + last_tr = 0; + busy_wait_warning = 0; + while (GNUNET_OK == check_lifeness ()) + { + GNUNET_NETWORK_fdset_zero (rs); + GNUNET_NETWORK_fdset_zero (ws); + timeout = GNUNET_TIME_UNIT_FOREVER_REL; + update_sets (rs, ws, &timeout); + GNUNET_NETWORK_fdset_handle_set (rs, pr); + if (ready_count > 0) + { + /* no blocking, more work already ready! */ + timeout = GNUNET_TIME_UNIT_ZERO; + } + if (NULL == scheduler_select) + ret = GNUNET_NETWORK_socket_select (rs, ws, NULL, timeout); + else + ret = scheduler_select (scheduler_select_cls, rs, ws, NULL, timeout); + if (ret == GNUNET_SYSERR) + { + if (errno == EINTR) + continue; + + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "select"); +#ifndef MINGW +#if USE_LSOF + char lsof[512]; + + snprintf (lsof, sizeof (lsof), "lsof -p %d", getpid ()); + (void) close (1); + (void) dup2 (2, 1); + if (0 != system (lsof)) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "system"); +#endif +#endif + GNUNET_abort (); + break; + } + if ((ret == 0) && (timeout.rel_value == 0) && (busy_wait_warning > 16)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, _("Looks like we're busy waiting...\n")); + sleep (1); /* mitigate */ + } + check_ready (rs, ws); + run_ready (rs, ws); + if (GNUNET_NETWORK_fdset_handle_isset (rs, pr)) + { + /* consume the signal */ + GNUNET_DISK_file_read (pr, &c, sizeof (c)); + /* mark all active tasks as ready due to shutdown */ + GNUNET_SCHEDULER_shutdown (); + } + if (last_tr == tasks_run) + { + busy_wait_warning++; + } + else + { + last_tr = tasks_run; + busy_wait_warning = 0; + } + } + GNUNET_SIGNAL_handler_uninstall (shc_int); + GNUNET_SIGNAL_handler_uninstall (shc_term); +#ifndef MINGW + GNUNET_SIGNAL_handler_uninstall (shc_pipe); + GNUNET_SIGNAL_handler_uninstall (shc_quit); + GNUNET_SIGNAL_handler_uninstall (shc_hup); +#endif + GNUNET_DISK_pipe_close (shutdown_pipe_handle); + shutdown_pipe_handle = NULL; + GNUNET_NETWORK_fdset_destroy (rs); + GNUNET_NETWORK_fdset_destroy (ws); +} + + +/** + * Obtain the reason code for why the current task was + * started. Will return the same value as + * the GNUNET_SCHEDULER_TaskContext's reason field. + * + * @return reason(s) why the current task is run + */ +enum GNUNET_SCHEDULER_Reason +GNUNET_SCHEDULER_get_reason () +{ + GNUNET_assert (active_task != NULL); + return active_task->reason; +} + + +/** + * Get information about the current load of this scheduler. Use this + * function to determine if an elective task should be added or simply + * dropped (if the decision should be made based on the number of + * tasks ready to run). + * + * @param p priority level to look at + * @return number of tasks pending right now + */ +unsigned int +GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p) +{ + struct Task *pos; + unsigned int ret; + + GNUNET_assert (active_task != NULL); + if (p == GNUNET_SCHEDULER_PRIORITY_COUNT) + return ready_count; + if (p == GNUNET_SCHEDULER_PRIORITY_KEEP) + p = current_priority; + ret = 0; + pos = ready[check_priority (p)]; + while (pos != NULL) + { + pos = pos->next; + ret++; + } + return ret; +} + + +/** + * Cancel the task with the specified identifier. + * The task must not yet have run. + * + * @param task id of the task to cancel + * @return original closure of the task + */ +void * +GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_TaskIdentifier task) +{ + struct Task *t; + struct Task *prev; + enum GNUNET_SCHEDULER_Priority p; + int to; + void *ret; + + GNUNET_assert (active_task != NULL); + to = 0; + prev = NULL; + t = pending; + while (t != NULL) + { + if (t->id == task) + break; + prev = t; + t = t->next; + } + if (t == NULL) + { + prev = NULL; + to = 1; + t = pending_timeout; + while (t != NULL) + { + if (t->id == task) + break; + prev = t; + t = t->next; + } + if (pending_timeout_last == t) + pending_timeout_last = NULL; + } + p = 0; + while (t == NULL) + { + p++; + if (p >= GNUNET_SCHEDULER_PRIORITY_COUNT) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Attempt to cancel dead task %llu!\n"), + (unsigned long long) task); + GNUNET_assert (0); + } + prev = NULL; + t = ready[p]; + while (t != NULL) + { + if (t->id == task) + { + ready_count--; + break; + } + prev = t; + t = t->next; + } + } + if (prev == NULL) + { + if (p == 0) + { + if (to == 0) + { + pending = t->next; + } + else + { + pending_timeout = t->next; + } + } + else + { + ready[p] = t->next; + } + } + else + { + prev->next = t->next; + } + ret = t->callback_cls; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Canceling task: %llu / %p\n", task, + t->callback_cls); + destroy_task (t); + return ret; +} + + +/** + * Continue the current execution with the given function. This is + * similar to the other "add" functions except that there is no delay + * and the reason code can be specified. + * + * @param task main function of the task + * @param task_cls closure for 'main' + * @param reason reason for task invocation + * @param priority priority to use for the task + */ +void +GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, void *task_cls, + enum GNUNET_SCHEDULER_Reason reason, + enum GNUNET_SCHEDULER_Priority priority) +{ + struct Task *t; + +#if EXECINFO + void *backtrace_array[50]; +#endif + + GNUNET_assert (NULL != task); + GNUNET_assert ((active_task != NULL) || + (reason == GNUNET_SCHEDULER_REASON_STARTUP)); + t = GNUNET_malloc (sizeof (struct Task)); +#if EXECINFO + t->num_backtrace_strings = backtrace (backtrace_array, 50); + t->backtrace_strings = + backtrace_symbols (backtrace_array, t->num_backtrace_strings); +#endif + t->read_fd = -1; + t->write_fd = -1; + t->callback = task; + t->callback_cls = task_cls; + t->id = ++last_id; +#if PROFILE_DELAYS + t->start_time = GNUNET_TIME_absolute_get (); +#endif + t->reason = reason; + t->priority = priority; + t->lifeness = current_lifeness; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding continuation task: %llu / %p\n", t->id, + t->callback_cls); + queue_ready_task (t); +} + + +/** + * Continue the current execution with the given function. This is + * similar to the other "add" functions except that there is no delay + * and the reason code can be specified. + * + * @param task main function of the task + * @param task_cls closure for 'main' + * @param reason reason for task invocation + */ +void +GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls, + enum GNUNET_SCHEDULER_Reason reason) +{ + GNUNET_SCHEDULER_add_continuation_with_priority (task, task_cls, + reason, + GNUNET_SCHEDULER_PRIORITY_DEFAULT); +} + + +/** + * Schedule a new task to be run after the specified prerequisite task + * has completed. It will be run with the DEFAULT priority. + * + * @param prerequisite_task run this task after the task with the given + * task identifier completes (and any of our other + * conditions, such as delay, read or write-readiness + * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency + * on completion of other tasks (this will cause the task to run as + * soon as possible). + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ + return GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + prerequisite_task, GNUNET_TIME_UNIT_ZERO, + NULL, NULL, task, task_cls); +} + + +/** + * Schedule a new task to be run with a specified priority. + * + * @param prio how important is the new task? + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ + return GNUNET_SCHEDULER_add_select (prio, GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_ZERO, NULL, NULL, task, + task_cls); +} + + + +/** + * Schedule a new task to be run with a specified delay. The task + * will be scheduled for execution once the delay has expired. + * + * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param priority priority to use for the task + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay, + enum GNUNET_SCHEDULER_Priority priority, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ + struct Task *t; + struct Task *pos; + struct Task *prev; + +#if EXECINFO + void *backtrace_array[MAX_TRACE_DEPTH]; +#endif + + GNUNET_assert (active_task != NULL); + GNUNET_assert (NULL != task); + t = GNUNET_malloc (sizeof (struct Task)); + t->callback = task; + t->callback_cls = task_cls; +#if EXECINFO + t->num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH); + t->backtrace_strings = + backtrace_symbols (backtrace_array, t->num_backtrace_strings); +#endif + t->read_fd = -1; + t->write_fd = -1; + t->id = ++last_id; +#if PROFILE_DELAYS + t->start_time = GNUNET_TIME_absolute_get (); +#endif + t->timeout = GNUNET_TIME_relative_to_absolute (delay); + t->priority = priority; + t->lifeness = current_lifeness; + /* try tail first (optimization in case we are + * appending to a long list of tasks with timeouts) */ + prev = pending_timeout_last; + if (prev != NULL) + { + if (prev->timeout.abs_value > t->timeout.abs_value) + prev = NULL; + else + pos = prev->next; /* heuristic success! */ + } + if (prev == NULL) + { + /* heuristic failed, do traversal of timeout list */ + pos = pending_timeout; + } + while ((pos != NULL) && + ((pos->timeout.abs_value <= t->timeout.abs_value) || + (pos->reason != 0))) + { + prev = pos; + pos = pos->next; + } + if (prev == NULL) + pending_timeout = t; + else + prev->next = t; + t->next = pos; + /* hyper-optimization... */ + pending_timeout_last = t; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id, + t->callback_cls); +#if EXECINFO + int i; + + for (i = 0; i < t->num_backtrace_strings; i++) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i, + t->backtrace_strings[i]); +#endif + return t->id; +} + + +/** + * Schedule a new task to be run with a specified delay. The task + * will be scheduled for execution once the delay has expired. It + * will be run with the DEFAULT priority. + * + * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ + return GNUNET_SCHEDULER_add_delayed_with_priority (delay, + GNUNET_SCHEDULER_PRIORITY_DEFAULT, + task, task_cls); +} + + +/** + * Schedule a new task to be run as soon as possible. The task + * will be run with the DEFAULT priority. + * + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task, void *task_cls) +{ + return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, task, task_cls); +} + + +/** + * Schedule a new task to be run as soon as possible with the + * (transitive) ignore-shutdown flag either explicitly set or + * explicitly enabled. This task (and all tasks created from it, + * other than by another call to this function) will either count or + * not count for the 'lifeness' of the process. This API is only + * useful in a few special cases. + * + * @param lifeness GNUNET_YES if the task counts for lifeness, GNUNET_NO if not. + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness, + GNUNET_SCHEDULER_Task task, + void *task_cls) +{ + GNUNET_SCHEDULER_TaskIdentifier ret; + + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_ZERO, NULL, NULL, task, + task_cls); + GNUNET_assert (pending->id == ret); + pending->lifeness = lifeness; + return ret; +} + + +/** + * Schedule a new task to be run with a specified delay or when any of + * the specified file descriptor sets is ready. The delay can be used + * as a timeout on the socket(s) being ready. The task will be + * scheduled for execution once either the delay has expired or any of + * the socket operations is ready. This is the most general + * function of the "add" family. Note that the "prerequisite_task" + * must be satisfied in addition to any of the other conditions. In + * other words, the task will be started when + * + * (prerequisite-run) + * && (delay-ready + * || any-rs-ready + * || any-ws-ready + * || shutdown-active ) + * + * + * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", + * which means that the task will only be run after we receive SIGTERM + * @param priority priority to use + * @param rfd file descriptor we want to read (can be -1) + * @param wfd file descriptors we want to write (can be -1) + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +#ifndef MINGW +static GNUNET_SCHEDULER_TaskIdentifier +add_without_sets (struct GNUNET_TIME_Relative delay, + enum GNUNET_SCHEDULER_Priority priority, + int rfd, int wfd, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ + struct Task *t; + +#if EXECINFO + void *backtrace_array[MAX_TRACE_DEPTH]; +#endif + + GNUNET_assert (active_task != NULL); + GNUNET_assert (NULL != task); + t = GNUNET_malloc (sizeof (struct Task)); + t->callback = task; + t->callback_cls = task_cls; +#if EXECINFO + t->num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH); + t->backtrace_strings = + backtrace_symbols (backtrace_array, t->num_backtrace_strings); +#endif +#if DEBUG_FDS + if (-1 != rfd) + { + int flags = fcntl (rfd, F_GETFD); + + if ((flags == -1) && (errno == EBADF)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n", rfd); +#if EXECINFO + int i; + + for (i = 0; i < t->num_backtrace_strings; i++) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n", t->backtrace_strings[i]); +#endif + GNUNET_assert (0); + } + } + if (-1 != wfd) + { + int flags = fcntl (wfd, F_GETFD); + + if (flags == -1 && errno == EBADF) + { + LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n", wfd); +#if EXECINFO + int i; + + for (i = 0; i < t->num_backtrace_strings; i++) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n", t->backtrace_strings[i]); +#endif + GNUNET_assert (0); + } + } +#endif + t->read_fd = rfd; + GNUNET_assert (wfd >= -1); + t->write_fd = wfd; + t->id = ++last_id; +#if PROFILE_DELAYS + t->start_time = GNUNET_TIME_absolute_get (); +#endif + t->prereq_id = GNUNET_SCHEDULER_NO_TASK; + t->timeout = GNUNET_TIME_relative_to_absolute (delay); + t->priority = check_priority ((priority == GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority : priority); + t->lifeness = current_lifeness; + t->next = pending; + pending = t; + max_priority_added = GNUNET_MAX (max_priority_added, t->priority); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id, + t->callback_cls); +#if EXECINFO + int i; + + for (i = 0; i < t->num_backtrace_strings; i++) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i, + t->backtrace_strings[i]); +#endif + return t->id; +} +#endif + + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for reading. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. It will be run with the DEFAULT priority. + * + * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param rfd read file-descriptor + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, + struct GNUNET_NETWORK_Handle *rfd, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ +#if MINGW + struct GNUNET_NETWORK_FDSet *rs; + GNUNET_SCHEDULER_TaskIdentifier ret; + + GNUNET_assert (rfd != NULL); + rs = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_set (rs, rfd); + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, delay, rs, NULL, + task, task_cls); + GNUNET_NETWORK_fdset_destroy (rs); + return ret; +#else + return add_without_sets (delay, + GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_NETWORK_get_fd (rfd), -1, task, + task_cls); +#endif +} + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for writing. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. It will be run with the priority of + * the calling task. + * + * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param wfd write file-descriptor + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, + struct GNUNET_NETWORK_Handle *wfd, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ +#if MINGW + struct GNUNET_NETWORK_FDSet *ws; + GNUNET_SCHEDULER_TaskIdentifier ret; + + GNUNET_assert (wfd != NULL); + ws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_set (ws, wfd); + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, delay, NULL, ws, + task, task_cls); + GNUNET_NETWORK_fdset_destroy (ws); + return ret; +#else + GNUNET_assert (GNUNET_NETWORK_get_fd (wfd) >= 0); + return add_without_sets (delay, + GNUNET_SCHEDULER_PRIORITY_DEFAULT, + -1, GNUNET_NETWORK_get_fd (wfd), task, + task_cls); +#endif +} + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for reading. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. It will be run with the DEFAULT priority. + * + * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param rfd read file-descriptor + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, + const struct GNUNET_DISK_FileHandle *rfd, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ +#if MINGW + struct GNUNET_NETWORK_FDSet *rs; + GNUNET_SCHEDULER_TaskIdentifier ret; + + GNUNET_assert (rfd != NULL); + rs = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_handle_set (rs, rfd); + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, delay, rs, NULL, + task, task_cls); + GNUNET_NETWORK_fdset_destroy (rs); + return ret; +#else + int fd; + + GNUNET_DISK_internal_file_handle_ (rfd, &fd, sizeof (int)); + return add_without_sets (delay, + GNUNET_SCHEDULER_PRIORITY_DEFAULT, + fd, -1, task, task_cls); + +#endif +} + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for writing. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. It will be run with the DEFAULT priority. + * + * @param delay when should this operation time out? Use + * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" + * @param wfd write file-descriptor + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, + const struct GNUNET_DISK_FileHandle *wfd, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ +#if MINGW + struct GNUNET_NETWORK_FDSet *ws; + GNUNET_SCHEDULER_TaskIdentifier ret; + + GNUNET_assert (wfd != NULL); + ws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_handle_set (ws, wfd); + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, delay, NULL, ws, + task, task_cls); + GNUNET_NETWORK_fdset_destroy (ws); + return ret; +#else + int fd; + + GNUNET_DISK_internal_file_handle_ (wfd, &fd, sizeof (int)); + GNUNET_assert (fd >= 0); + return add_without_sets (delay, + GNUNET_SCHEDULER_PRIORITY_DEFAULT, + -1, fd, task, task_cls); + +#endif +} + + + +/** + * Schedule a new task to be run with a specified delay or when any of + * the specified file descriptor sets is ready. The delay can be used + * as a timeout on the socket(s) being ready. The task will be + * scheduled for execution once either the delay has expired or any of + * the socket operations is ready. This is the most general + * function of the "add" family. Note that the "prerequisite_task" + * must be satisfied in addition to any of the other conditions. In + * other words, the task will be started when + * + * (prerequisite-run) + * && (delay-ready + * || any-rs-ready + * || any-ws-ready + * || (shutdown-active && run-on-shutdown) ) + * + * + * @param prio how important is this task? + * @param prerequisite_task run this task after the task with the given + * task identifier completes (and any of our other + * conditions, such as delay, read or write-readiness + * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency + * on completion of other tasks. + * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", + * which means that the task will only be run after we receive SIGTERM + * @param rs set of file descriptors we want to read (can be NULL) + * @param ws set of file descriptors we want to write (can be NULL) + * @param task main function of the task + * @param task_cls closure of task + * @return unique task identifier for the job + * only valid until "task" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, + GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, + struct GNUNET_TIME_Relative delay, + const struct GNUNET_NETWORK_FDSet *rs, + const struct GNUNET_NETWORK_FDSet *ws, + GNUNET_SCHEDULER_Task task, void *task_cls) +{ + struct Task *t; + +#if EXECINFO + void *backtrace_array[MAX_TRACE_DEPTH]; +#endif + + GNUNET_assert (active_task != NULL); + GNUNET_assert (NULL != task); + t = GNUNET_malloc (sizeof (struct Task)); + t->callback = task; + t->callback_cls = task_cls; +#if EXECINFO + t->num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH); + t->backtrace_strings = + backtrace_symbols (backtrace_array, t->num_backtrace_strings); +#endif + t->read_fd = -1; + t->write_fd = -1; + if (rs != NULL) + { + t->read_set = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy (t->read_set, rs); + } + if (ws != NULL) + { + t->write_set = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy (t->write_set, ws); + } + t->id = ++last_id; +#if PROFILE_DELAYS + t->start_time = GNUNET_TIME_absolute_get (); +#endif + t->prereq_id = prerequisite_task; + t->timeout = GNUNET_TIME_relative_to_absolute (delay); + t->priority = + check_priority ((prio == + GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority : + prio); + t->lifeness = current_lifeness; + t->next = pending; + pending = t; + max_priority_added = GNUNET_MAX (max_priority_added, t->priority); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id, + t->callback_cls); +#if EXECINFO + int i; + + for (i = 0; i < t->num_backtrace_strings; i++) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i, + t->backtrace_strings[i]); +#endif + return t->id; +} + +/* end of scheduler.c */ diff --git a/src/util/server.c b/src/util/server.c new file mode 100644 index 0000000..24804d2 --- /dev/null +++ b/src/util/server.c @@ -0,0 +1,1415 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/server.c + * @brief library for building GNUnet network servers + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_disk_lib.h" +#include "gnunet_protocols.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +#define DEBUG_SERVER GNUNET_EXTRA_LOGGING + +/** + * List of arrays of message handlers. + */ +struct HandlerList +{ + /** + * This is a linked list. + */ + struct HandlerList *next; + + /** + * NULL-terminated array of handlers. + */ + const struct GNUNET_SERVER_MessageHandler *handlers; +}; + + +/** + * List of arrays of message handlers. + */ +struct NotifyList +{ + /** + * This is a linked list. + */ + struct NotifyList *next; + + /** + * Function to call. + */ + GNUNET_SERVER_DisconnectCallback callback; + + /** + * Closure for callback. + */ + void *callback_cls; +}; + + +/** + * @brief handle for a server + */ +struct GNUNET_SERVER_Handle +{ + /** + * List of handlers for incoming messages. + */ + struct HandlerList *handlers; + + /** + * List of our current clients. + */ + struct GNUNET_SERVER_Client *clients; + + /** + * Linked list of functions to call on disconnects by clients. + */ + struct NotifyList *disconnect_notify_list; + + /** + * Function to call for access control. + */ + GNUNET_CONNECTION_AccessCheck access; + + /** + * Closure for access. + */ + void *access_cls; + + /** + * NULL-terminated array of sockets used to listen for new + * connections. + */ + struct GNUNET_NETWORK_Handle **listen_sockets; + + /** + * After how long should an idle connection time + * out (on write). + */ + struct GNUNET_TIME_Relative idle_timeout; + + /** + * Task scheduled to do the listening. + */ + GNUNET_SCHEDULER_TaskIdentifier listen_task; + + /** + * Do we ignore messages of types that we do not understand or do we + * require that a handler is found (and if not kill the connection)? + */ + int require_found; + + /** + * Should all of the clients of this server continue to process + * connections as usual even if we get a shutdown request? (the + * listen socket always ignores shutdown). + */ + int clients_ignore_shutdown; + + GNUNET_SERVER_MstCreateCallback mst_create; + GNUNET_SERVER_MstDestroyCallback mst_destroy; + GNUNET_SERVER_MstReceiveCallback mst_receive; + void *mst_cls; +}; + + +/** + * @brief handle for a client of the server + */ +struct GNUNET_SERVER_Client +{ + + /** + * This is a linked list. + */ + struct GNUNET_SERVER_Client *next; + + /** + * Processing of incoming data. + */ + void *mst; + + /** + * Server that this client belongs to. + */ + struct GNUNET_SERVER_Handle *server; + + /** + * Client closure for callbacks. + */ + struct GNUNET_CONNECTION_Handle *connection; + + /** + * ID of task used to restart processing. + */ + GNUNET_SCHEDULER_TaskIdentifier restart_task; + + /** + * Task that warns about missing calls to 'GNUNET_SERVER_receive_done'. + */ + GNUNET_SCHEDULER_TaskIdentifier warn_task; + + /** + * Time when the warn task was started. + */ + struct GNUNET_TIME_Absolute warn_start; + + /** + * Last activity on this socket (used to time it out + * if reference_count == 0). + */ + struct GNUNET_TIME_Absolute last_activity; + + /** + * + */ + GNUNET_CONNECTION_TransmitReadyNotify callback; + + /** + * callback + */ + void *callback_cls; + + /** + * After how long should an idle connection time + * out (on write). + */ + struct GNUNET_TIME_Relative idle_timeout; + + /** + * Number of external entities with a reference to + * this client object. + */ + unsigned int reference_count; + + /** + * Was processing if incoming messages suspended while + * we were still processing data already received? + * This is a counter saying how often processing was + * suspended (once per handler invoked). + */ + unsigned int suspended; + + /** + * Are we currently in the "process_client_buffer" function (and + * will hence restart the receive job on exit if suspended == 0 once + * we are done?). If this is set, then "receive_done" will + * essentially only decrement suspended; if this is not set, then + * "receive_done" may need to restart the receive process (either + * from the side-buffer or via select/recv). + */ + int in_process_client_buffer; + + /** + * We're about to close down this client due to some serious + * error. + */ + int shutdown_now; + + /** + * Are we currently trying to receive? (YES if we are, NO if we are not, + * SYSERR if data is already available in MST). + */ + int receive_pending; + + /** + * Finish pending write when disconnecting? + */ + int finish_pending_write; + + /** + * Persist the file handle for this client no matter what happens, + * force the OS to close once the process actually dies. Should only + * be used in special cases! + */ + int persist; + + /** + * Type of last message processed (for warn_no_receive_done). + */ + uint16_t warn_type; +}; + + +/** + * Scheduler says our listen socket is ready. Process it! + * + * @param cls handle to our server for which we are processing the listen + * socket + * @param tc reason why we are running right now + */ +static void +process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_SERVER_Handle *server = cls; + struct GNUNET_CONNECTION_Handle *sock; + struct GNUNET_SERVER_Client *client; + struct GNUNET_NETWORK_FDSet *r; + unsigned int i; + + server->listen_task = GNUNET_SCHEDULER_NO_TASK; + r = GNUNET_NETWORK_fdset_create (); + i = 0; + while (NULL != server->listen_sockets[i]) + GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]); + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + /* ignore shutdown, someone else will take care of it! */ + server->listen_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, r, NULL, + &process_listen_socket, server); + GNUNET_NETWORK_fdset_destroy (r); + return; + } + i = 0; + while (NULL != server->listen_sockets[i]) + { + if (GNUNET_NETWORK_fdset_isset (tc->read_ready, server->listen_sockets[i])) + { + sock = + GNUNET_CONNECTION_create_from_accept (server->access, + server->access_cls, + server->listen_sockets[i]); + if (sock != NULL) + { +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, "Server accepted incoming connection.\n"); +#endif + client = GNUNET_SERVER_connect_socket (server, sock); + GNUNET_CONNECTION_ignore_shutdown (sock, + server->clients_ignore_shutdown); + /* decrement reference count, we don't keep "client" alive */ + GNUNET_SERVER_client_drop (client); + } + } + i++; + } + /* listen for more! */ + server->listen_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, r, NULL, + &process_listen_socket, server); + GNUNET_NETWORK_fdset_destroy (r); +} + + +/** + * Create and initialize a listen socket for the server. + * + * @param serverAddr address to listen on + * @param socklen length of address + * @return NULL on error, otherwise the listen socket + */ +static struct GNUNET_NETWORK_Handle * +open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) +{ + const static int on = 1; + struct GNUNET_NETWORK_Handle *sock; + uint16_t port; + int eno; + + switch (serverAddr->sa_family) + { + case AF_INET: + port = ntohs (((const struct sockaddr_in *) serverAddr)->sin_port); + break; + case AF_INET6: + port = ntohs (((const struct sockaddr_in6 *) serverAddr)->sin6_port); + break; + case AF_UNIX: + port = 0; + break; + default: + GNUNET_break (0); + port = 0; + break; + } + sock = GNUNET_NETWORK_socket_create (serverAddr->sa_family, SOCK_STREAM, 0); + if (NULL == sock) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); + errno = 0; + return NULL; + } + if (port != 0) + { + if (GNUNET_NETWORK_socket_setsockopt + (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "setsockopt"); +#ifdef IPV6_V6ONLY + if ((serverAddr->sa_family == AF_INET6) && + (GNUNET_NETWORK_socket_setsockopt + (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "setsockopt"); +#endif + } + /* bind the socket */ + if (GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen) != GNUNET_OK) + { + eno = errno; + if (errno != EADDRINUSE) + { + /* we don't log 'EADDRINUSE' here since an IPv4 bind may + * fail if we already took the port on IPv6; if both IPv4 and + * IPv6 binds fail, then our caller will log using the + * errno preserved in 'eno' */ + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind"); + if (port != 0) + LOG (GNUNET_ERROR_TYPE_ERROR, _("`%s' failed for port %d (%s).\n"), + "bind", port, + (serverAddr->sa_family == AF_INET) ? "IPv4" : "IPv6"); + eno = 0; + } + else + { + if (port != 0) + LOG (GNUNET_ERROR_TYPE_WARNING, + _("`%s' failed for port %d (%s): address already in use\n"), + "bind", port, + (serverAddr->sa_family == AF_INET) ? "IPv4" : "IPv6"); + else if (serverAddr->sa_family == AF_UNIX) + LOG (GNUNET_ERROR_TYPE_WARNING, + _("`%s' failed for `%s': address already in use\n"), "bind", + ((const struct sockaddr_un *) serverAddr)->sun_path); + + } + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); + errno = eno; + return NULL; + } + if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "listen"); + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); + errno = 0; + return NULL; + } +#if DEBUG_SERVER + if (port != 0) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Server starts to listen on port %u.\n", + port); +#endif + return sock; +} + + +/** + * Create a new server. + * + * @param access function for access control + * @param access_cls closure for access + * @param lsocks NULL-terminated array of listen sockets + * @param idle_timeout after how long should we timeout idle connections? + * @param require_found if YES, connections sending messages of unknown type + * will be closed + * @return handle for the new server, NULL on error + * (typically, "port" already in use) + */ +struct GNUNET_SERVER_Handle * +GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access, + void *access_cls, + struct GNUNET_NETWORK_Handle **lsocks, + struct GNUNET_TIME_Relative idle_timeout, + int require_found) +{ + struct GNUNET_SERVER_Handle *ret; + struct GNUNET_NETWORK_FDSet *r; + int i; + + ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle)); + ret->idle_timeout = idle_timeout; + ret->listen_sockets = lsocks; + ret->access = access; + ret->access_cls = access_cls; + ret->require_found = require_found; + if (lsocks != NULL) + { + r = GNUNET_NETWORK_fdset_create (); + i = 0; + while (NULL != ret->listen_sockets[i]) + GNUNET_NETWORK_fdset_set (r, ret->listen_sockets[i++]); + ret->listen_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + GNUNET_SCHEDULER_NO_TASK, + GNUNET_TIME_UNIT_FOREVER_REL, r, NULL, + &process_listen_socket, ret); + GNUNET_NETWORK_fdset_destroy (r); + } + return ret; +} + + +/** + * Create a new server. + * + * @param access function for access control + * @param access_cls closure for access + * @param serverAddr address to listen on (including port), NULL terminated array + * @param socklen length of serverAddr + * @param idle_timeout after how long should we timeout idle connections? + * @param require_found if YES, connections sending messages of unknown type + * will be closed + * @return handle for the new server, NULL on error + * (typically, "port" already in use) + */ +struct GNUNET_SERVER_Handle * +GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access, void *access_cls, + struct sockaddr *const *serverAddr, + const socklen_t * socklen, + struct GNUNET_TIME_Relative idle_timeout, + int require_found) +{ + struct GNUNET_NETWORK_Handle **lsocks; + unsigned int i; + unsigned int j; + + i = 0; + while (serverAddr[i] != NULL) + i++; + if (i > 0) + { + lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1)); + i = 0; + j = 0; + while (serverAddr[i] != NULL) + { + lsocks[j] = open_listen_socket (serverAddr[i], socklen[i]); + if (lsocks[j] != NULL) + j++; + i++; + } + if (j == 0) + { + if (errno != 0) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind"); + GNUNET_free (lsocks); + lsocks = NULL; + } + } + else + { + lsocks = NULL; + } + return GNUNET_SERVER_create_with_sockets (access, access_cls, lsocks, + idle_timeout, require_found); +} + + +/** + * Free resources held by this server. + * + * @param s server to destroy + */ +void +GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s) +{ + struct HandlerList *hpos; + struct NotifyList *npos; + unsigned int i; + +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, "Server shutting down.\n"); +#endif + if (GNUNET_SCHEDULER_NO_TASK != s->listen_task) + { + GNUNET_SCHEDULER_cancel (s->listen_task); + s->listen_task = GNUNET_SCHEDULER_NO_TASK; + } + if (s->listen_sockets != NULL) + { + i = 0; + while (s->listen_sockets[i] != NULL) + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (s->listen_sockets[i++])); + GNUNET_free (s->listen_sockets); + s->listen_sockets = NULL; + } + while (s->clients != NULL) + GNUNET_SERVER_client_disconnect (s->clients); + while (NULL != (hpos = s->handlers)) + { + s->handlers = hpos->next; + GNUNET_free (hpos); + } + while (NULL != (npos = s->disconnect_notify_list)) + { + npos->callback (npos->callback_cls, NULL); + s->disconnect_notify_list = npos->next; + GNUNET_free (npos); + } + GNUNET_free (s); +} + + +/** + * Add additional handlers to an existing server. + * + * @param server the server to add handlers to + * @param handlers array of message handlers for + * incoming messages; the last entry must + * have "NULL" for the "callback"; multiple + * entries for the same type are allowed, + * they will be called in order of occurence. + * These handlers can be removed later; + * the handlers array must exist until removed + * (or server is destroyed). + */ +void +GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server, + const struct GNUNET_SERVER_MessageHandler *handlers) +{ + struct HandlerList *p; + + p = GNUNET_malloc (sizeof (struct HandlerList)); + p->handlers = handlers; + p->next = server->handlers; + server->handlers = p; +} + + +void +GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server, + GNUNET_SERVER_MstCreateCallback create, + GNUNET_SERVER_MstDestroyCallback destroy, + GNUNET_SERVER_MstReceiveCallback receive, + void *cls) +{ + server->mst_create = create; + server->mst_destroy = destroy; + server->mst_receive = receive; + server->mst_cls = cls; +} + + +/** + * Task run to warn about missing calls to 'GNUNET_SERVER_receive_done'. + * + * @param cls our 'struct GNUNET_SERVER_Client*' to process more requests from + * @param tc scheduler context (unused) + */ +static void +warn_no_receive_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_SERVER_Client *client = cls; + + client->warn_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &warn_no_receive_done, client); + if (0 == (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + LOG (GNUNET_ERROR_TYPE_WARNING, + _ + ("Processing code for message of type %u did not call GNUNET_SERVER_receive_done after %llums\n"), + (unsigned int) client->warn_type, + (unsigned long long) + GNUNET_TIME_absolute_get_duration (client->warn_start).rel_value); +} + + +/** + * Disable the warning the server issues if a message is not acknowledged + * in a timely fashion. Use this call if a client is intentionally delayed + * for a while. Only applies to the current message. + * + * @param client client for which to disable the warning + */ +void +GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client) +{ + if (GNUNET_SCHEDULER_NO_TASK != client->warn_task) + { + GNUNET_SCHEDULER_cancel (client->warn_task); + client->warn_task = GNUNET_SCHEDULER_NO_TASK; + } +} + + +/** + * Inject a message into the server, pretend it came + * from the specified client. Delivery of the message + * will happen instantly (if a handler is installed; + * otherwise the call does nothing). + * + * @param server the server receiving the message + * @param sender the "pretended" sender of the message + * can be NULL! + * @param message message to transmit + * @return GNUNET_OK if the message was OK and the + * connection can stay open + * GNUNET_SYSERR if the connection to the + * client should be shut down + */ +int +GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server, + struct GNUNET_SERVER_Client *sender, + const struct GNUNET_MessageHeader *message) +{ + struct HandlerList *pos; + const struct GNUNET_SERVER_MessageHandler *mh; + unsigned int i; + uint16_t type; + uint16_t size; + int found; + + type = ntohs (message->type); + size = ntohs (message->size); +#if DEBUG_SERVER + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server schedules transmission of %u-byte message of type %u to client.\n", + size, type); +#endif + pos = server->handlers; + found = GNUNET_NO; + while (pos != NULL) + { + i = 0; + while (pos->handlers[i].callback != NULL) + { + mh = &pos->handlers[i]; + if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL)) + { + if ((mh->expected_size != 0) && (mh->expected_size != size)) + { +#if GNUNET8_NETWORK_IS_DEAD + LOG (GNUNET_ERROR_TYPE_WARNING, + "Expected %u bytes for message of type %u, got %u\n", + mh->expected_size, mh->type, size); + GNUNET_break_op (0); +#endif + return GNUNET_SYSERR; + } + if (sender != NULL) + { + if (0 == sender->suspended) + { + sender->warn_start = GNUNET_TIME_absolute_get (); + sender->warn_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &warn_no_receive_done, sender); + sender->warn_type = type; + } + sender->suspended++; + } + mh->callback (mh->callback_cls, sender, message); + found = GNUNET_YES; + } + i++; + } + pos = pos->next; + } + if (found == GNUNET_NO) + { + LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Received message of unknown type %d\n", type); + if (server->require_found == GNUNET_YES) + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * We are receiving an incoming message. Process it. + * + * @param cls our closure (handle for the client) + * @param buf buffer with data received from network + * @param available number of bytes available in buf + * @param addr address of the sender + * @param addrlen length of addr + * @param errCode code indicating errors receiving, 0 for success + */ +static void +process_incoming (void *cls, const void *buf, size_t available, + const struct sockaddr *addr, socklen_t addrlen, int errCode); + + +/** + * Process messages from the client's message tokenizer until either + * the tokenizer is empty (and then schedule receiving more), or + * until some handler is not immediately done (then wait for restart_processing) + * or shutdown. + * + * @param client the client to process, RC must have already been increased + * using GNUNET_SERVER_client_keep and will be decreased by one in this + * function + * @param ret GNUNET_NO to start processing from the buffer, + * GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving + * GNUNET_SYSERR if we should instantly abort due to error in a previous step + */ +static void +process_mst (struct GNUNET_SERVER_Client *client, int ret) +{ + while ((ret != GNUNET_SYSERR) && (client->server != NULL) && + (GNUNET_YES != client->shutdown_now) && (0 == client->suspended)) + { + if (ret == GNUNET_OK) + { + client->receive_pending = GNUNET_YES; +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server re-enters receive loop, timeout: %llu.\n", + client->idle_timeout.rel_value); +#endif + GNUNET_CONNECTION_receive (client->connection, + GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, + client->idle_timeout, &process_incoming, + client); + break; + } +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server processes additional messages instantly.\n"); +#endif + if (client->server->mst_receive != NULL) + ret = + client->server->mst_receive (client->server->mst_cls, client->mst, + client, NULL, 0, GNUNET_NO, GNUNET_YES); + else + ret = + GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO, + GNUNET_YES); + } +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n", + ret, client->server, client->shutdown_now, client->suspended); +#endif + + if (ret == GNUNET_NO) + { +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server has more data pending but is suspended.\n"); +#endif + client->receive_pending = GNUNET_SYSERR; /* data pending */ + } + if ((ret == GNUNET_SYSERR) || (GNUNET_YES == client->shutdown_now)) + GNUNET_SERVER_client_disconnect (client); + GNUNET_SERVER_client_drop (client); +} + + +/** + * We are receiving an incoming message. Process it. + * + * @param cls our closure (handle for the client) + * @param buf buffer with data received from network + * @param available number of bytes available in buf + * @param addr address of the sender + * @param addrlen length of addr + * @param errCode code indicating errors receiving, 0 for success + */ +static void +process_incoming (void *cls, const void *buf, size_t available, + const struct sockaddr *addr, socklen_t addrlen, int errCode) +{ + struct GNUNET_SERVER_Client *client = cls; + struct GNUNET_SERVER_Handle *server = client->server; + struct GNUNET_TIME_Absolute end; + struct GNUNET_TIME_Absolute now; + int ret; + + GNUNET_assert (client->receive_pending == GNUNET_YES); + client->receive_pending = GNUNET_NO; + now = GNUNET_TIME_absolute_get (); + end = GNUNET_TIME_absolute_add (client->last_activity, client->idle_timeout); + + if ((buf == NULL) && (available == 0) && (addr == NULL) && (errCode == 0) && + (client->shutdown_now != GNUNET_YES) && (server != NULL) && + (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) && + (end.abs_value > now.abs_value)) + { + /* wait longer, timeout changed (i.e. due to us sending) */ +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Receive time out, but no disconnect due to sending (%p)\n", + GNUNET_a2s (addr, addrlen)); +#endif + client->receive_pending = GNUNET_YES; + GNUNET_CONNECTION_receive (client->connection, + GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, + GNUNET_TIME_absolute_get_remaining (end), + &process_incoming, client); + return; + } + if ((buf == NULL) || (available == 0) || (errCode != 0) || (server == NULL) || + (client->shutdown_now == GNUNET_YES) || + (GNUNET_YES != GNUNET_CONNECTION_check (client->connection))) + { + /* other side closed connection, error connecting, etc. */ + GNUNET_SERVER_client_disconnect (client); + return; + } +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, "Server receives %u bytes from `%s'.\n", + (unsigned int) available, GNUNET_a2s (addr, addrlen)); +#endif + GNUNET_SERVER_client_keep (client); + client->last_activity = now; + + if (server->mst_receive != NULL) + ret = + client->server->mst_receive (client->server->mst_cls, client->mst, + client, buf, available, GNUNET_NO, GNUNET_YES); + else + ret = + GNUNET_SERVER_mst_receive (client->mst, client, buf, available, GNUNET_NO, + GNUNET_YES); + + process_mst (client, ret); +} + + +/** + * Task run to start again receiving from the network + * and process requests. + * + * @param cls our 'struct GNUNET_SERVER_Client*' to process more requests from + * @param tc scheduler context (unused) + */ +static void +restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_SERVER_Client *client = cls; + struct GNUNET_SERVER_Handle *server = client->server; + + client->restart_task = GNUNET_SCHEDULER_NO_TASK; + if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) && + (GNUNET_NO == server->clients_ignore_shutdown)) + { + GNUNET_SERVER_client_disconnect (client); + return; + } + if (client->receive_pending == GNUNET_NO) + { +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n"); +#endif + client->receive_pending = GNUNET_YES; + GNUNET_CONNECTION_receive (client->connection, + GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, + client->idle_timeout, &process_incoming, client); + return; + } +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server continues processing messages still in the buffer.\n"); +#endif + GNUNET_SERVER_client_keep (client); + client->receive_pending = GNUNET_NO; + process_mst (client, GNUNET_NO); +} + + +/** + * This function is called whenever our inbound message tokenizer has + * received a complete message. + * + * @param cls closure (struct GNUNET_SERVER_Handle) + * @param client identification of the client (struct GNUNET_SERVER_Client*) + * @param message the actual message + */ +static void +client_message_tokenizer_callback (void *cls, void *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_SERVER_Handle *server = cls; + struct GNUNET_SERVER_Client *sender = client; + int ret; + +#if DEBUG_SERVER + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tokenizer gives server message of type %u from client\n", + ntohs (message->type)); +#endif + sender->in_process_client_buffer = GNUNET_YES; + ret = GNUNET_SERVER_inject (server, sender, message); + sender->in_process_client_buffer = GNUNET_NO; + if (GNUNET_OK != ret) + GNUNET_SERVER_client_disconnect (sender); +} + + +/** + * Add a TCP socket-based connection to the set of handles managed by + * this server. Use this function for outgoing (P2P) connections that + * we initiated (and where this server should process incoming + * messages). + * + * @param server the server to use + * @param connection the connection to manage (client must + * stop using this connection from now on) + * @return the client handle (client should call + * "client_drop" on the return value eventually) + */ +struct GNUNET_SERVER_Client * +GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server, + struct GNUNET_CONNECTION_Handle *connection) +{ + struct GNUNET_SERVER_Client *client; + + client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client)); + client->connection = connection; + client->mst = + GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, server); + client->reference_count = 1; + client->server = server; + client->last_activity = GNUNET_TIME_absolute_get (); + client->next = server->clients; + client->idle_timeout = server->idle_timeout; + server->clients = client; + client->receive_pending = GNUNET_YES; + client->callback = NULL; + client->callback_cls = NULL; + + if (server->mst_create != NULL) + client->mst = + server->mst_create (server->mst_cls, client); + else + client->mst = + GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, server); + + GNUNET_CONNECTION_receive (client->connection, + GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, + client->idle_timeout, &process_incoming, client); + return client; +} + + +/** + * Change the timeout for a particular client. Decreasing the timeout + * may not go into effect immediately (only after the previous timeout + * times out or activity happens on the socket). + * + * @param client the client to update + * @param timeout new timeout for activities on the socket + */ +void +GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client, + struct GNUNET_TIME_Relative timeout) +{ + client->idle_timeout = timeout; +} + + +void +GNUNET_SERVER_client_set_finish_pending_write (struct GNUNET_SERVER_Client *client, + int finish) +{ + client->finish_pending_write = finish; +} + + +/** + * Notify the server that the given client handle should + * be kept (keeps the connection up if possible, increments + * the internal reference counter). + * + * @param client the client to keep + */ +void +GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client) +{ + client->reference_count++; +} + + +/** + * Notify the server that the given client handle is no + * longer required. Decrements the reference counter. If + * that counter reaches zero an inactive connection maybe + * closed. + * + * @param client the client to drop + */ +void +GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client) +{ + GNUNET_assert (client->reference_count > 0); + client->reference_count--; + if ((client->shutdown_now == GNUNET_YES) && (client->reference_count == 0)) + GNUNET_SERVER_client_disconnect (client); +} + + +/** + * Obtain the network address of the other party. + * + * @param client the client to get the address for + * @param addr where to store the address + * @param addrlen where to store the length of the address + * @return GNUNET_OK on success + */ +int +GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client, + void **addr, size_t * addrlen) +{ + return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen); +} + + +/** + * Ask the server to notify us whenever a client disconnects. + * This function is called whenever the actual network connection + * is closed; the reference count may be zero or larger than zero + * at this point. + * + * @param server the server manageing the clients + * @param callback function to call on disconnect + * @param callback_cls closure for callback + */ +void +GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server, + GNUNET_SERVER_DisconnectCallback callback, + void *callback_cls) +{ + struct NotifyList *n; + + n = GNUNET_malloc (sizeof (struct NotifyList)); + n->callback = callback; + n->callback_cls = callback_cls; + n->next = server->disconnect_notify_list; + server->disconnect_notify_list = n; +} + + +/** + * Ask the server to stop notifying us whenever a client disconnects. + * + * @param server the server manageing the clients + * @param callback function to call on disconnect + * @param callback_cls closure for callback + */ +void +GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, + GNUNET_SERVER_DisconnectCallback + callback, void *callback_cls) +{ + struct NotifyList *pos; + struct NotifyList *prev; + + prev = NULL; + pos = server->disconnect_notify_list; + while (pos != NULL) + { + if ((pos->callback == callback) && (pos->callback_cls == callback_cls)) + break; + prev = pos; + pos = pos->next; + } + if (pos == NULL) + { + GNUNET_break (0); + return; + } + if (prev == NULL) + server->disconnect_notify_list = pos->next; + else + prev->next = pos->next; + GNUNET_free (pos); +} + + +/** + * Ask the server to disconnect from the given client. + * This is the same as returning GNUNET_SYSERR from a message + * handler, except that it allows dropping of a client even + * when not handling a message from that client. + * + * @param client the client to disconnect from + */ +void +GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client) +{ + struct GNUNET_SERVER_Client *prev; + struct GNUNET_SERVER_Client *pos; + struct GNUNET_SERVER_Handle *server; + struct NotifyList *n; + unsigned int rc; + +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Client is being disconnected from the server.\n"); +#endif + if (client->restart_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (client->restart_task); + client->restart_task = GNUNET_SCHEDULER_NO_TASK; + } + if (client->warn_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (client->warn_task); + client->warn_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_YES == client->receive_pending) + { + GNUNET_CONNECTION_receive_cancel (client->connection); + client->receive_pending = GNUNET_NO; + } + + rc = client->reference_count; + if (client->shutdown_now != GNUNET_YES) + { + server = client->server; + client->shutdown_now = GNUNET_YES; + prev = NULL; + pos = server->clients; + while ((pos != NULL) && (pos != client)) + { + prev = pos; + pos = pos->next; + } + GNUNET_assert (pos != NULL); + if (prev == NULL) + server->clients = pos->next; + else + prev->next = pos->next; + if (client->restart_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (client->restart_task); + client->restart_task = GNUNET_SCHEDULER_NO_TASK; + } + if (client->warn_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (client->warn_task); + client->warn_task = GNUNET_SCHEDULER_NO_TASK; + } + n = server->disconnect_notify_list; + while (n != NULL) + { + n->callback (n->callback_cls, client); + n = n->next; + } + } + if (rc > 0) + { +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "RC still positive, not destroying everything.\n"); +#endif + return; + } + if (client->in_process_client_buffer == GNUNET_YES) + { +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Still processing inputs, not destroying everything.\n"); +#endif + return; + } + + if (client->persist == GNUNET_YES) + GNUNET_CONNECTION_persist_ (client->connection); + GNUNET_CONNECTION_destroy (client->connection, client->finish_pending_write); + + if (client->server->mst_destroy != NULL) + client->server->mst_destroy (client->server->mst_cls, client->mst); + else + GNUNET_SERVER_mst_destroy (client->mst); + + GNUNET_free (client); +} + + +/** + * Disable the "CORK" feature for communication with the given client, + * forcing the OS to immediately flush the buffer on transmission + * instead of potentially buffering multiple messages. + * + * @param client handle to the client + * @return GNUNET_OK on success + */ +int +GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client) +{ + return GNUNET_CONNECTION_disable_corking (client->connection); +} + + +/** + * Wrapper for transmission notification that calls the original + * callback and update the last activity time for our connection. + * + * @param cls the 'struct GNUNET_SERVER_Client' + * @param size number of bytes we can transmit + * @param buf where to copy the message + * @return number of bytes actually transmitted + */ +static size_t +transmit_ready_callback_wrapper (void *cls, size_t size, void *buf) +{ + struct GNUNET_SERVER_Client *client = cls; + size_t ret; + + ret = client->callback (client->callback_cls, size, buf); + if (ret > 0) + client->last_activity = GNUNET_TIME_absolute_get (); + return ret; +} + + +/** + * Notify us when the server has enough space to transmit + * a message of the given size to the given client. + * + * @param client client to transmit message to + * @param size requested amount of buffer space + * @param timeout after how long should we give up (and call + * notify with buf NULL and size 0)? + * @param callback function to call when space is available + * @param callback_cls closure for callback + * @return non-NULL if the notify callback was queued; can be used + * to cancel the request using + * GNUNET_CONNECTION_notify_transmit_ready_cancel. + * NULL if we are already going to notify someone else (busy) + */ +struct GNUNET_CONNECTION_TransmitHandle * +GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client, + size_t size, + struct GNUNET_TIME_Relative timeout, + GNUNET_CONNECTION_TransmitReadyNotify + callback, void *callback_cls) +{ + client->callback_cls = callback_cls; + client->callback = callback; + return GNUNET_CONNECTION_notify_transmit_ready (client->connection, size, + timeout, + &transmit_ready_callback_wrapper, + client); +} + + +/** + * Set the persistent flag on this client, used to setup client connection + * to only be killed when the service it's connected to is actually dead. + * + * @param client the client to set the persistent flag on + */ +void +GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client) +{ + client->persist = GNUNET_YES; +} + + +/** + * Resume receiving from this client, we are done processing the + * current request. This function must be called from within each + * GNUNET_SERVER_MessageCallback (or its respective continuations). + * + * @param client client we were processing a message of + * @param success GNUNET_OK to keep the connection open and + * continue to receive + * GNUNET_NO to close the connection (normal behavior) + * GNUNET_SYSERR to close the connection (signal + * serious error) + */ +void +GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success) +{ + if (client == NULL) + return; + GNUNET_assert (client->suspended > 0); + client->suspended--; + if (success != GNUNET_OK) + { +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "GNUNET_SERVER_receive_done called with failure indication\n"); +#endif + GNUNET_SERVER_client_disconnect (client); + return; + } + if (client->suspended > 0) + { +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "GNUNET_SERVER_receive_done called, but more clients pending\n"); +#endif + return; + } + if (GNUNET_SCHEDULER_NO_TASK != client->warn_task) + { + GNUNET_SCHEDULER_cancel (client->warn_task); + client->warn_task = GNUNET_SCHEDULER_NO_TASK; + } + if (client->in_process_client_buffer == GNUNET_YES) + { +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "GNUNET_SERVER_receive_done called while still in processing loop\n"); +#endif + return; + } + if ((client->server == NULL) || (GNUNET_YES == client->shutdown_now)) + { + GNUNET_SERVER_client_disconnect (client); + return; + } +#if DEBUG_SERVER + LOG (GNUNET_ERROR_TYPE_DEBUG, + "GNUNET_SERVER_receive_done causes restart in reading from the socket\n"); +#endif + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == client->restart_task); + client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing, client); +} + + +/** + * Configure this server's connections to continue handling client + * requests as usual even after we get a shutdown signal. The change + * only applies to clients that connect to the server from the outside + * using TCP after this call. Clients managed previously or those + * added using GNUNET_SERVER_connect_socket and + * GNUNET_SERVER_connect_callback are not affected by this option. + * + * @param h server handle + * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default + */ +void +GNUNET_SERVER_ignore_shutdown (struct GNUNET_SERVER_Handle *h, int do_ignore) +{ + h->clients_ignore_shutdown = do_ignore; +} + +/* end of server.c */ diff --git a/src/util/server_mst.c b/src/util/server_mst.c new file mode 100644 index 0000000..6161770 --- /dev/null +++ b/src/util/server_mst.c @@ -0,0 +1,321 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/server_mst.c + * @brief convenience functions for handling inbound message buffers + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" + +#define DEBUG_SERVER_MST GNUNET_EXTRA_LOGGING + +#if HAVE_UNALIGNED_64_ACCESS +#define ALIGN_FACTOR 4 +#else +#define ALIGN_FACTOR 8 +#endif + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + + +/** + * Handle to a message stream tokenizer. + */ +struct GNUNET_SERVER_MessageStreamTokenizer +{ + + /** + * Function to call on completed messages. + */ + GNUNET_SERVER_MessageTokenizerCallback cb; + + /** + * Closure for cb. + */ + void *cb_cls; + + /** + * Size of the buffer (starting at 'hdr'). + */ + size_t curr_buf; + + /** + * How many bytes in buffer have we already processed? + */ + size_t off; + + /** + * How many bytes in buffer are valid right now? + */ + size_t pos; + + /** + * Beginning of the buffer. Typed like this to force alignment. + */ + struct GNUNET_MessageHeader *hdr; + +}; + + + +/** + * Create a message stream tokenizer. + * + * @param cb function to call on completed messages + * @param cb_cls closure for cb + * @return handle to tokenizer + */ +struct GNUNET_SERVER_MessageStreamTokenizer * +GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb, + void *cb_cls) +{ + struct GNUNET_SERVER_MessageStreamTokenizer *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_MessageStreamTokenizer)); + ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE); + ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE; + ret->cb = cb; + ret->cb_cls = cb_cls; + return ret; +} + + +/** + * Add incoming data to the receive buffer and call the + * callback for all complete messages. + * + * @param mst tokenizer to use + * @param client_identity ID of client for which this is a buffer + * @param buf input data to add + * @param size number of bytes in buf + * @param purge should any excess bytes in the buffer be discarded + * (i.e. for packet-based services like UDP) + * @param one_shot only call callback once, keep rest of message in buffer + * @return GNUNET_OK if we are done processing (need more data) + * GNUNET_NO if one_shot was set and we have another message ready + * GNUNET_SYSERR if the data stream is corrupt + */ +int +GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst, + void *client_identity, const char *buf, size_t size, + int purge, int one_shot) +{ + const struct GNUNET_MessageHeader *hdr; + size_t delta; + uint16_t want; + char *ibuf; + int need_align; + unsigned long offset; + int ret; + + GNUNET_assert (mst->off <= mst->pos); + GNUNET_assert (mst->pos <= mst->curr_buf); +#if DEBUG_SERVER_MST + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server-mst receives %u bytes with %u bytes already in private buffer\n", + (unsigned int) size, (unsigned int) (mst->pos - mst->off)); +#endif + ret = GNUNET_OK; + ibuf = (char *) mst->hdr; + while (mst->pos > 0) + { +do_align: + GNUNET_assert (mst->pos >= mst->off); + if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) || + (0 != (mst->off % ALIGN_FACTOR))) + { + /* need to align or need more space */ + mst->pos -= mst->off; + memmove (ibuf, &ibuf[mst->off], mst->pos); + mst->off = 0; + } + if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) + { + delta = + GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) - + (mst->pos - mst->off), size); + memcpy (&ibuf[mst->pos], buf, delta); + mst->pos += delta; + buf += delta; + size -= delta; + } + if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) + { + if (purge) + { + mst->off = 0; + mst->pos = 0; + } + return GNUNET_OK; + } + hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; + want = ntohs (hdr->size); + if (want < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if ( (mst->curr_buf - mst->off < want) && + (mst->off > 0) ) + { + /* can get more space by moving */ + mst->pos -= mst->off; + memmove (ibuf, &ibuf[mst->off], mst->pos); + mst->off = 0; + } + if (mst->curr_buf < want) + { + /* need to get more space by growing buffer */ + GNUNET_assert (0 == mst->off); + mst->hdr = GNUNET_realloc (mst->hdr, want); + ibuf = (char *) mst->hdr; + mst->curr_buf = want; + } + hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; + if (mst->pos - mst->off < want) + { + delta = GNUNET_MIN (want - (mst->pos - mst->off), size); + GNUNET_assert (mst->pos + delta <= mst->curr_buf); + memcpy (&ibuf[mst->pos], buf, delta); + mst->pos += delta; + buf += delta; + size -= delta; + } + if (mst->pos - mst->off < want) + { + if (purge) + { + mst->off = 0; + mst->pos = 0; + } + return GNUNET_OK; + } + if (one_shot == GNUNET_SYSERR) + { + /* cannot call callback again, but return value saying that + * we have another full message in the buffer */ + ret = GNUNET_NO; + goto copy; + } + if (one_shot == GNUNET_YES) + one_shot = GNUNET_SYSERR; + mst->off += want; + mst->cb (mst->cb_cls, client_identity, hdr); + if (mst->off == mst->pos) + { + /* reset to beginning of buffer, it's free right now! */ + mst->off = 0; + mst->pos = 0; + } + } + GNUNET_assert (0 == mst->pos); + while (size > 0) + { +#if DEBUG_SERVER_MST + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server-mst has %u bytes left in inbound buffer\n", + (unsigned int) size); +#endif + if (size < sizeof (struct GNUNET_MessageHeader)) + break; + offset = (unsigned long) buf; + need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO; + if (GNUNET_NO == need_align) + { + /* can try to do zero-copy and process directly from original buffer */ + hdr = (const struct GNUNET_MessageHeader *) buf; + want = ntohs (hdr->size); + if (want < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + mst->off = 0; + return GNUNET_SYSERR; + } + if (size < want) + break; /* or not: buffer incomplete, so copy to private buffer... */ + if (one_shot == GNUNET_SYSERR) + { + /* cannot call callback again, but return value saying that + * we have another full message in the buffer */ + ret = GNUNET_NO; + goto copy; + } + if (one_shot == GNUNET_YES) + one_shot = GNUNET_SYSERR; + mst->cb (mst->cb_cls, client_identity, hdr); + buf += want; + size -= want; + } + else + { + /* need to copy to private buffer to align; + * yes, we go a bit more spagetti than usual here */ + goto do_align; + } + } +copy: + if ((size > 0) && (!purge)) + { + if (size + mst->pos > mst->curr_buf) + { + mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos); + ibuf = (char *) mst->hdr; + mst->curr_buf = size + mst->pos; + } + GNUNET_assert (size + mst->pos <= mst->curr_buf); + memcpy (&ibuf[mst->pos], buf, size); + mst->pos += size; + } + if (purge) + { + mst->off = 0; + mst->pos = 0; + } +#if DEBUG_SERVER_MST + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server-mst leaves %u bytes in private buffer\n", + (unsigned int) (mst->pos - mst->off)); +#endif + return ret; +} + + +/** + * Destroys a tokenizer. + * + * @param mst tokenizer to destroy + */ +void +GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst) +{ + GNUNET_free (mst->hdr); + GNUNET_free (mst); +} + + + +/* end of server_mst.c */ diff --git a/src/util/server_nc.c b/src/util/server_nc.c new file mode 100644 index 0000000..08ffd4b --- /dev/null +++ b/src/util/server_nc.c @@ -0,0 +1,450 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/server_nc.c + * @brief convenience functions for transmission of + * a notification stream + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + + +#define DEBUG_SERVER_NC GNUNET_EXTRA_LOGGING + +/** + * Entry in list of messages pending to be transmitted. + */ +struct PendingMessageList +{ + + /** + * This is a doubly-linked list. + */ + struct PendingMessageList *next; + + /** + * This is a doubly-linked list. + */ + struct PendingMessageList *prev; + + /** + * Message to transmit (allocated at the end of this + * struct, do not free) + */ + const struct GNUNET_MessageHeader *msg; + + /** + * Can this message be dropped? + */ + int can_drop; + +}; + + +/** + * Lists of clients we manage for notifications. + */ +struct ClientList +{ + + /** + * This is a linked list. + */ + struct ClientList *next; + + /** + * Overall context this client belongs to. + */ + struct GNUNET_SERVER_NotificationContext *nc; + + /** + * Handle to the client. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Handle for pending transmission request to the client (or NULL). + */ + struct GNUNET_CONNECTION_TransmitHandle *th; + + /** + * Head of linked list of requests queued for transmission. + */ + struct PendingMessageList *pending_head; + + /** + * Tail of linked list of requests queued for transmission. + */ + struct PendingMessageList *pending_tail; + + /** + * Number of messages currently in the list. + */ + unsigned int num_pending; + +}; + + +/** + * The notification context is the key datastructure for a convenience + * API used for transmission of notifications to the client until the + * client disconnects (or the notification context is destroyed, in + * which case we disconnect these clients). Essentially, all + * (notification) messages are queued up until the client is able to + * read them. + */ +struct GNUNET_SERVER_NotificationContext +{ + + /** + * Server we do notifications for. + */ + struct GNUNET_SERVER_Handle *server; + + /** + * List of clients receiving notifications. + */ + struct ClientList *clients; + + /** + * Maximum number of optional messages to queue per client. + */ + unsigned int queue_length; + +}; + + +/** + * Client has disconnected, clean up. + * + * @param cls our 'struct GNUNET_SERVER_NotificationContext *' + * @param client handle of client that disconnected + */ +static void +handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct GNUNET_SERVER_NotificationContext *nc = cls; + struct ClientList *pos; + struct ClientList *prev; + struct PendingMessageList *pml; + + if (client == NULL) + { + nc->server = NULL; + return; + } + prev = NULL; + pos = nc->clients; + while (NULL != pos) + { + if (pos->client == client) + break; + prev = pos; + pos = pos->next; + } + if (pos == NULL) + return; +#if DEBUG_SERVER_NC + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Client disconnected, cleaning up %u messages in NC queue\n", + pos->num_pending); +#endif + if (prev == NULL) + nc->clients = pos->next; + else + prev->next = pos->next; + while (NULL != (pml = pos->pending_head)) + { + GNUNET_CONTAINER_DLL_remove (pos->pending_head, pos->pending_tail, pml); + GNUNET_free (pml); + } + if (pos->th != NULL) + { + GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th); + pos->th = NULL; + } + GNUNET_SERVER_client_drop (client); + GNUNET_free (pos); +} + + +/** + * Create a new notification context. + * + * @param server server for which this function creates the context + * @param queue_length maximum number of messages to keep in + * the notification queue; optional messages are dropped + * it the queue gets longer than this number of messages + * @return handle to the notification context + */ +struct GNUNET_SERVER_NotificationContext * +GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server, + unsigned int queue_length) +{ + struct GNUNET_SERVER_NotificationContext *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_NotificationContext)); + ret->server = server; + ret->queue_length = queue_length; + GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, ret); + return ret; +} + + +/** + * Destroy the context, force disconnect for all clients. + * + * @param nc context to destroy. + */ +void +GNUNET_SERVER_notification_context_destroy (struct + GNUNET_SERVER_NotificationContext + *nc) +{ + struct ClientList *pos; + struct PendingMessageList *pml; + + while (NULL != (pos = nc->clients)) + { + nc->clients = pos->next; + GNUNET_SERVER_client_drop (pos->client); + while (NULL != (pml = pos->pending_head)) + { + GNUNET_CONTAINER_DLL_remove (pos->pending_head, pos->pending_tail, pml); + GNUNET_free (pml); + } + GNUNET_free (pos); + } + if (nc->server != NULL) + GNUNET_SERVER_disconnect_notify_cancel (nc->server, + &handle_client_disconnect, nc); + GNUNET_free (nc); +} + + +/** + * Add a client to the notification context. + * + * @param nc context to modify + * @param client client to add + */ +void +GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext + *nc, + struct GNUNET_SERVER_Client *client) +{ + struct ClientList *cl; + + for (cl = nc->clients; NULL != cl; cl = cl->next) + if (cl->client == client) + return; /* already present */ + cl = GNUNET_malloc (sizeof (struct ClientList)); + cl->next = nc->clients; + cl->nc = nc; + cl->client = client; + GNUNET_SERVER_client_keep (client); + nc->clients = cl; +} + + +/** + * Function called to notify a client about the socket begin ready to + * queue more data. "buf" will be NULL and "size" zero if the socket + * was closed for writing in the meantime. + * + * @param cls the 'struct ClientList *' + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_message (void *cls, size_t size, void *buf) +{ + struct ClientList *cl = cls; + char *cbuf = buf; + struct PendingMessageList *pml; + uint16_t msize; + size_t ret; + + cl->th = NULL; + if (buf == NULL) + { + /* 'cl' should be freed via disconnect notification shortly */ +#if DEBUG_SERVER_NC + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Failed to transmit message from NC queue to client\n"); +#endif + return 0; + } + ret = 0; + while (NULL != (pml = cl->pending_head)) + { + msize = ntohs (pml->msg->size); + if (size < msize) + break; + GNUNET_CONTAINER_DLL_remove (cl->pending_head, cl->pending_tail, pml); +#if DEBUG_SERVER_NC + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Copying message of type %u and size %u from pending queue to transmission buffer\n", + ntohs (pml->msg->type), msize); +#endif + memcpy (&cbuf[ret], pml->msg, msize); + ret += msize; + size -= msize; + GNUNET_free (pml); + cl->num_pending--; + } + if (pml != NULL) + { +#if DEBUG_SERVER_NC + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Have %u messages left in NC queue, will try transmission again\n", + cl->num_pending); +#endif + cl->th = + GNUNET_SERVER_notify_transmit_ready (cl->client, ntohs (pml->msg->size), + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_message, cl); + } + else + GNUNET_assert (cl->num_pending == 0); + return ret; +} + + +/** + * Send a message to a particular client. + * + * @param nc context to modify + * @param client client to transmit to + * @param msg message to send + * @param can_drop can this message be dropped due to queue length limitations + */ +static void +do_unicast (struct GNUNET_SERVER_NotificationContext *nc, + struct ClientList *client, const struct GNUNET_MessageHeader *msg, + int can_drop) +{ + struct PendingMessageList *pml; + uint16_t size; + + if ((client->num_pending > nc->queue_length) && (GNUNET_YES == can_drop)) + { + LOG (GNUNET_ERROR_TYPE_INFO, + "Dropping message of type %u and size %u due to full queue (%u entries)\n", + ntohs (msg->type), ntohs (msg->size), (unsigned int) nc->queue_length); + return; /* drop! */ + } + if (client->num_pending > nc->queue_length) + { + /* FIXME: consider checking for other messages in the + * queue that are 'droppable' */ + } + client->num_pending++; + size = ntohs (msg->size); + pml = GNUNET_malloc (sizeof (struct PendingMessageList) + size); + pml->msg = (const struct GNUNET_MessageHeader *) &pml[1]; + pml->can_drop = can_drop; +#if DEBUG_SERVER_NC + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Adding message of type %u and size %u to pending queue (which has %u entries)\n", + ntohs (msg->type), ntohs (msg->size), (unsigned int) nc->queue_length); +#endif + memcpy (&pml[1], msg, size); + /* append */ + GNUNET_CONTAINER_DLL_insert_tail (client->pending_head, client->pending_tail, + pml); + if (client->th == NULL) + client->th = + GNUNET_SERVER_notify_transmit_ready (client->client, + ntohs (client->pending_head-> + msg->size), + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_message, client); +} + + +/** + * Send a message to a particular client; must have + * already been added to the notification context. + * + * @param nc context to modify + * @param client client to transmit to + * @param msg message to send + * @param can_drop can this message be dropped due to queue length limitations + */ +void +GNUNET_SERVER_notification_context_unicast (struct + GNUNET_SERVER_NotificationContext + *nc, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader + *msg, int can_drop) +{ + struct ClientList *pos; + + pos = nc->clients; + while (NULL != pos) + { + if (pos->client == client) + break; + pos = pos->next; + } + GNUNET_assert (pos != NULL); + do_unicast (nc, pos, msg, can_drop); +} + + +/** + * Send a message to all clients of this context. + * + * @param nc context to modify + * @param msg message to send + * @param can_drop can this message be dropped due to queue length limitations + */ +void +GNUNET_SERVER_notification_context_broadcast (struct + GNUNET_SERVER_NotificationContext + *nc, + const struct GNUNET_MessageHeader + *msg, int can_drop) +{ + struct ClientList *pos; + + pos = nc->clients; + while (NULL != pos) + { + do_unicast (nc, pos, msg, can_drop); + pos = pos->next; + } +} + + +/* end of server_nc.c */ diff --git a/src/util/server_tc.c b/src/util/server_tc.c new file mode 100644 index 0000000..ce40db1 --- /dev/null +++ b/src/util/server_tc.c @@ -0,0 +1,247 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/server_tc.c + * @brief convenience functions for transmission of + * complex responses as a server + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" + + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + + +/** + * How much buffer space do we want to have at least + * before transmitting another increment? + */ +#define MIN_BLOCK_SIZE 128 + + + +struct GNUNET_SERVER_TransmitContext +{ + /** + * Which client are we transmitting to? + */ + struct GNUNET_SERVER_Client *client; + + /** + * Transmission buffer. (current offset for writing). + */ + char *buf; + + /** + * Number of bytes in buf. + */ + size_t total; + + /** + * Offset for writing in buf. + */ + size_t off; + + /** + * Timeout for this request. + */ + struct GNUNET_TIME_Absolute timeout; +}; + + +/** + * Helper function for incremental transmission of the response. + */ +static size_t +transmit_response (void *cls, size_t size, void *buf) +{ + struct GNUNET_SERVER_TransmitContext *tc = cls; + size_t msize; + + if (buf == NULL) + { + GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); + return 0; + } + if (tc->total - tc->off > size) + msize = size; + else + msize = tc->total - tc->off; + memcpy (buf, &tc->buf[tc->off], msize); + tc->off += msize; + if (tc->total == tc->off) + { + + GNUNET_SERVER_receive_done (tc->client, GNUNET_OK); + GNUNET_SERVER_client_drop (tc->client); + GNUNET_free_non_null (tc->buf); + GNUNET_free (tc); + } + else + { + if (NULL == + GNUNET_SERVER_notify_transmit_ready (tc->client, + GNUNET_MIN (MIN_BLOCK_SIZE, + tc->total - tc->off), + GNUNET_TIME_absolute_get_remaining + (tc->timeout), &transmit_response, + tc)) + { + GNUNET_break (0); + GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); + } + } + return msize; +} + + +/** + * Create a new transmission context for the + * given client. + * + * @param client client to create the context for. + * @return NULL on error + */ +struct GNUNET_SERVER_TransmitContext * +GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client) +{ + struct GNUNET_SERVER_TransmitContext *tc; + + GNUNET_assert (client != NULL); + tc = GNUNET_malloc (sizeof (struct GNUNET_SERVER_TransmitContext)); + GNUNET_SERVER_client_keep (client); + tc->client = client; + return tc; +} + + +/** + * Append a message to the transmission context. + * All messages in the context will be sent by + * the transmit_context_run method. + * + * @param tc context to use + * @param data what to append to the result message + * @param length length of data + * @param type type of the message + */ +void +GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext + *tc, const void *data, + size_t length, uint16_t type) +{ + struct GNUNET_MessageHeader *msg; + size_t size; + + GNUNET_assert (length < GNUNET_SERVER_MAX_MESSAGE_SIZE); + size = length + sizeof (struct GNUNET_MessageHeader); + GNUNET_assert (size > length); + tc->buf = GNUNET_realloc (tc->buf, tc->total + size); + msg = (struct GNUNET_MessageHeader *) &tc->buf[tc->total]; + tc->total += size; + msg->size = htons (size); + msg->type = htons (type); + memcpy (&msg[1], data, length); +} + + +/** + * Append a message to the transmission context. + * All messages in the context will be sent by + * the transmit_context_run method. + * + * @param tc context to use + * @param msg message to append + */ +void +GNUNET_SERVER_transmit_context_append_message (struct + GNUNET_SERVER_TransmitContext + *tc, + const struct GNUNET_MessageHeader + *msg) +{ + struct GNUNET_MessageHeader *m; + uint16_t size; + + size = ntohs (msg->size); + tc->buf = GNUNET_realloc (tc->buf, tc->total + size); + m = (struct GNUNET_MessageHeader *) &tc->buf[tc->total]; + tc->total += size; + memcpy (m, msg, size); +} + + +/** + * Execute a transmission context. If there is + * an error in the transmission, the receive_done + * method will be called with an error code (GNUNET_SYSERR), + * otherwise with GNUNET_OK. + * + * @param tc transmission context to use + * @param timeout when to time out and abort the transmission + */ +void +GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc, + struct GNUNET_TIME_Relative timeout) +{ + tc->timeout = GNUNET_TIME_relative_to_absolute (timeout); + if (NULL == + GNUNET_SERVER_notify_transmit_ready (tc->client, + GNUNET_MIN (MIN_BLOCK_SIZE, + tc->total), timeout, + &transmit_response, tc)) + { + GNUNET_break (0); + GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); + } +} + + +/** + * Destroy a transmission context. This function must not be called + * after 'GNUNET_SERVER_transmit_context_run'. + * + * @param tc transmission context to destroy + * @param success code to give to 'GNUNET_SERVER_receive_done' for + * the client: GNUNET_OK to keep the connection open and + * continue to receive + * GNUNET_NO to close the connection (normal behavior) + * GNUNET_SYSERR to close the connection (signal + * serious error) + */ +void +GNUNET_SERVER_transmit_context_destroy (struct GNUNET_SERVER_TransmitContext + *tc, int success) +{ + GNUNET_SERVER_receive_done (tc->client, success); + GNUNET_SERVER_client_drop (tc->client); + GNUNET_free_non_null (tc->buf); + GNUNET_free (tc); +} + + +/* end of server_tc.c */ diff --git a/src/util/service.c b/src/util/service.c new file mode 100644 index 0000000..243e7da --- /dev/null +++ b/src/util/service.c @@ -0,0 +1,1840 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/service.c + * @brief functions related to starting services + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_directories.h" +#include "gnunet_disk_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_resolver_service.h" +#include "gnunet_server_lib.h" +#include "gnunet_service_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +#define DEBUG_SERVICE GNUNET_EXTRA_LOGGING + +/* ******************* access control ******************** */ + +/** + * @brief IPV4 network in CIDR notation. + */ +struct IPv4NetworkSet +{ + struct in_addr network; + struct in_addr netmask; +}; + +/** + * @brief network in CIDR notation for IPV6. + */ +struct IPv6NetworkSet +{ + struct in6_addr network; + struct in6_addr netmask; +}; + + +/** + * Parse a network specification. The argument specifies + * a list of networks. The format is + * [network/netmask;]* (no whitespace, must be terminated + * with a semicolon). The network must be given in dotted-decimal + * notation. The netmask can be given in CIDR notation (/16) or + * in dotted-decimal (/255.255.0.0). + *

+ * @param routeList a string specifying the forbidden networks + * @return the converted list, NULL if the synatx is flawed + */ +static struct IPv4NetworkSet * +parse_ipv4_specification (const char *routeList) +{ + unsigned int count; + unsigned int i; + unsigned int j; + unsigned int len; + int cnt; + unsigned int pos; + unsigned int temps[8]; + int slash; + struct IPv4NetworkSet *result; + + if (routeList == NULL) + return NULL; + len = strlen (routeList); + if (len == 0) + return NULL; + count = 0; + for (i = 0; i < len; i++) + if (routeList[i] == ';') + count++; + result = GNUNET_malloc (sizeof (struct IPv4NetworkSet) * (count + 1)); + /* add termination */ + memset (result, 0, sizeof (struct IPv4NetworkSet) * (count + 1)); + i = 0; + pos = 0; + while (i < count) + { + cnt = + sscanf (&routeList[pos], "%u.%u.%u.%u/%u.%u.%u.%u;", &temps[0], + &temps[1], &temps[2], &temps[3], &temps[4], &temps[5], + &temps[6], &temps[7]); + if (cnt == 8) + { + for (j = 0; j < 8; j++) + if (temps[j] > 0xFF) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), + &routeList[pos]); + GNUNET_free (result); + return NULL; + } + result[i].network.s_addr = + htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + + temps[3]); + result[i].netmask.s_addr = + htonl ((temps[4] << 24) + (temps[5] << 16) + (temps[6] << 8) + + temps[7]); + while (routeList[pos] != ';') + pos++; + pos++; + i++; + continue; + } + /* try second notation */ + cnt = + sscanf (&routeList[pos], "%u.%u.%u.%u/%u;", &temps[0], &temps[1], + &temps[2], &temps[3], &slash); + if (cnt == 5) + { + for (j = 0; j < 4; j++) + if (temps[j] > 0xFF) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), + &routeList[pos]); + GNUNET_free (result); + return NULL; + } + result[i].network.s_addr = + htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + + temps[3]); + if ((slash <= 32) && (slash >= 0)) + { + result[i].netmask.s_addr = 0; + while (slash > 0) + { + result[i].netmask.s_addr = + (result[i].netmask.s_addr >> 1) + 0x80000000; + slash--; + } + result[i].netmask.s_addr = htonl (result[i].netmask.s_addr); + while (routeList[pos] != ';') + pos++; + pos++; + i++; + continue; + } + else + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."), + slash); + GNUNET_free (result); + return NULL; /* error */ + } + } + /* try third notation */ + slash = 32; + cnt = + sscanf (&routeList[pos], "%u.%u.%u.%u;", &temps[0], &temps[1], + &temps[2], &temps[3]); + if (cnt == 4) + { + for (j = 0; j < 4; j++) + if (temps[j] > 0xFF) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), + &routeList[pos]); + GNUNET_free (result); + return NULL; + } + result[i].network.s_addr = + htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + + temps[3]); + result[i].netmask.s_addr = 0; + while (slash > 0) + { + result[i].netmask.s_addr = (result[i].netmask.s_addr >> 1) + 0x80000000; + slash--; + } + result[i].netmask.s_addr = htonl (result[i].netmask.s_addr); + while (routeList[pos] != ';') + pos++; + pos++; + i++; + continue; + } + LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), + &routeList[pos]); + GNUNET_free (result); + return NULL; /* error */ + } + if (pos < strlen (routeList)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), + &routeList[pos]); + GNUNET_free (result); + return NULL; /* oops */ + } + return result; /* ok */ +} + + +/** + * Parse a network specification. The argument specifies + * a list of networks. The format is + * [network/netmask;]* (no whitespace, must be terminated + * with a semicolon). The network must be given in colon-hex + * notation. The netmask must be given in CIDR notation (/16) or + * can be omitted to specify a single host. + *

+ * @param routeListX a string specifying the forbidden networks + * @return the converted list, NULL if the synatx is flawed + */ +static struct IPv6NetworkSet * +parse_ipv6_specification (const char *routeListX) +{ + unsigned int count; + unsigned int i; + unsigned int len; + unsigned int pos; + int start; + int slash; + int ret; + char *routeList; + struct IPv6NetworkSet *result; + unsigned int bits; + unsigned int off; + int save; + + if (routeListX == NULL) + return NULL; + len = strlen (routeListX); + if (len == 0) + return NULL; + routeList = GNUNET_strdup (routeListX); + count = 0; + for (i = 0; i < len; i++) + if (routeList[i] == ';') + count++; + if (routeList[len - 1] != ';') + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Invalid network notation (does not end with ';': `%s')\n"), + routeList); + GNUNET_free (routeList); + return NULL; + } + + result = GNUNET_malloc (sizeof (struct IPv6NetworkSet) * (count + 1)); + memset (result, 0, sizeof (struct IPv6NetworkSet) * (count + 1)); + i = 0; + pos = 0; + while (i < count) + { + start = pos; + while (routeList[pos] != ';') + pos++; + slash = pos; + while ((slash >= start) && (routeList[slash] != '/')) + slash--; + if (slash < start) + { + memset (&result[i].netmask, 0xFF, sizeof (struct in6_addr)); + slash = pos; + } + else + { + routeList[pos] = '\0'; + ret = inet_pton (AF_INET6, &routeList[slash + 1], &result[i].netmask); + if (ret <= 0) + { + save = errno; + if ((1 != SSCANF (&routeList[slash + 1], "%u", &bits)) || (bits >= 128)) + { + if (ret == 0) + LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for netmask\n"), + &routeList[slash + 1]); + else + { + errno = save; + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton"); + } + GNUNET_free (result); + GNUNET_free (routeList); + return NULL; + } + off = 0; + while (bits > 8) + { + result[i].netmask.s6_addr[off++] = 0xFF; + bits -= 8; + } + while (bits > 0) + { + result[i].netmask.s6_addr[off] = + (result[i].netmask.s6_addr[off] >> 1) + 0x80; + bits--; + } + } + } + routeList[slash] = '\0'; + ret = inet_pton (AF_INET6, &routeList[start], &result[i].network); + if (ret <= 0) + { + if (ret == 0) + LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for network\n"), + &routeList[slash + 1]); + else + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton"); + GNUNET_free (result); + GNUNET_free (routeList); + return NULL; + } + pos++; + i++; + } + GNUNET_free (routeList); + return result; +} + + +/** + * Check if the given IP address is in the list of IP addresses. + * + * @param list a list of networks + * @param add the IP to check (in network byte order) + * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is + */ +static int +check_ipv4_listed (const struct IPv4NetworkSet *list, const struct in_addr *add) +{ + int i; + + i = 0; + if (list == NULL) + return GNUNET_NO; + + while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0)) + { + if ((add->s_addr & list[i].netmask.s_addr) == + (list[i].network.s_addr & list[i].netmask.s_addr)) + return GNUNET_YES; + i++; + } + return GNUNET_NO; +} + +/** + * Check if the given IP address is in the list of IP addresses. + * + * @param list a list of networks + * @param ip the IP to check (in network byte order) + * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is + */ +static int +check_ipv6_listed (const struct IPv6NetworkSet *list, const struct in6_addr *ip) +{ + unsigned int i; + unsigned int j; + struct in6_addr zero; + + if (list == NULL) + return GNUNET_NO; + + memset (&zero, 0, sizeof (struct in6_addr)); + i = 0; +NEXT: + while (memcmp (&zero, &list[i].network, sizeof (struct in6_addr)) != 0) + { + for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++) + if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) != + (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j])) + { + i++; + goto NEXT; + } + return GNUNET_YES; + } + return GNUNET_NO; +} + + +/* ****************** service struct ****************** */ + + +/** + * Context for "service_task". + */ +struct GNUNET_SERVICE_Context +{ + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Handle for the server. + */ + struct GNUNET_SERVER_Handle *server; + + /** + * NULL-terminated array of addresses to bind to, NULL if we got pre-bound + * listen sockets. + */ + struct sockaddr **addrs; + + /** + * Name of our service. + */ + const char *serviceName; + + /** + * Main service-specific task to run. + */ + GNUNET_SERVICE_Main task; + + /** + * Closure for task. + */ + void *task_cls; + + /** + * IPv4 addresses that are not allowed to connect. + */ + struct IPv4NetworkSet *v4_denied; + + /** + * IPv6 addresses that are not allowed to connect. + */ + struct IPv6NetworkSet *v6_denied; + + /** + * IPv4 addresses that are allowed to connect (if not + * set, all are allowed). + */ + struct IPv4NetworkSet *v4_allowed; + + /** + * IPv6 addresses that are allowed to connect (if not + * set, all are allowed). + */ + struct IPv6NetworkSet *v6_allowed; + + /** + * My (default) message handlers. Adjusted copy + * of "defhandlers". + */ + struct GNUNET_SERVER_MessageHandler *my_handlers; + + /** + * Array of the lengths of the entries in addrs. + */ + socklen_t *addrlens; + + /** + * NULL-terminated array of listen sockets we should take over. + */ + struct GNUNET_NETWORK_Handle **lsocks; + + /** + * Idle timeout for server. + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Overall success/failure of the service start. + */ + int ret; + + /** + * If we are daemonizing, this FD is set to the + * pipe to the parent. Send '.' if we started + * ok, '!' if not. -1 if we are not daemonizing. + */ + int ready_confirm_fd; + + /** + * Do we close connections if we receive messages + * for which we have no handler? + */ + int require_found; + + /** + * Do we require a matching UID for UNIX domain socket connections? + * GNUNET_NO means that the UID does not have to match (however, + * "match_gid" may still impose other access control checks). + */ + int match_uid; + + /** + * Do we require a matching GID for UNIX domain socket connections? + * Ignored if "match_uid" is GNUNET_YES. Note that this is about + * checking that the client's UID is in our group OR that the + * client's GID is our GID. If both "match_gid" and "match_uid" are + * "GNUNET_NO", all users on the local system have access. + */ + int match_gid; + + /** + * Our options. + */ + enum GNUNET_SERVICE_Options options; + +}; + + +/* ****************** message handlers ****************** */ + +static size_t +write_test (void *cls, size_t size, void *buf) +{ + struct GNUNET_SERVER_Client *client = cls; + struct GNUNET_MessageHeader *msg; + + if (size < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return 0; /* client disconnected */ + } + msg = (struct GNUNET_MessageHeader *) buf; + msg->type = htons (GNUNET_MESSAGE_TYPE_TEST); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return sizeof (struct GNUNET_MessageHeader); +} + +/** + * Handler for TEST message. + * + * @param cls closure (refers to service) + * @param client identification of the client + * @param message the actual message + */ +static void +handle_test (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + /* simply bounce message back to acknowledge */ + if (NULL == + GNUNET_SERVER_notify_transmit_ready (client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_UNIT_FOREVER_REL, + &write_test, client)) + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); +} + + +/** + * Default handlers for all services. Will be copied and the + * "callback_cls" fields will be replaced with the specific service + * struct. + */ +static const struct GNUNET_SERVER_MessageHandler defhandlers[] = { + {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST, + sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} +}; + + + +/* ****************** service core routines ************** */ + + +/** + * Check if access to the service is allowed from the given address. + * + * @param cls closure + * @param uc credentials, if available, otherwise NULL + * @param addr address + * @param addrlen length of address + * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR + * for unknown address family (will be denied). + */ +static int +check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc, + const struct sockaddr *addr, socklen_t addrlen) +{ + struct GNUNET_SERVICE_Context *sctx = cls; + const struct sockaddr_in *i4; + const struct sockaddr_in6 *i6; + int ret; + + switch (addr->sa_family) + { + case AF_INET: + GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); + i4 = (const struct sockaddr_in *) addr; + ret = ((sctx->v4_allowed == NULL) || + (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) && + ((sctx->v4_denied == NULL) || + (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr))); + break; + case AF_INET6: + GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); + i6 = (const struct sockaddr_in6 *) addr; + ret = ((sctx->v6_allowed == NULL) || + (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) && + ((sctx->v6_denied == NULL) || + (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr))); + break; +#ifndef WINDOWS + case AF_UNIX: + ret = GNUNET_OK; /* always OK for now */ + if (sctx->match_uid == GNUNET_YES) + { + /* UID match required */ + ret = (uc != NULL) && (uc->uid == geteuid ()); + } + else if (sctx->match_gid == GNUNET_YES) + { + /* group match required */ + if (uc == NULL) + { + /* no credentials, group match not possible */ + ret = GNUNET_NO; + } + else + { + struct group *grp; + unsigned int i; + + if (uc->gid != getegid()) + { + /* default group did not match, but maybe the user is in our group, let's check */ + grp = getgrgid (getegid ()); + if (NULL == grp) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "getgrgid"); + return GNUNET_NO; + } + ret = GNUNET_NO; + for (i=0; NULL != grp->gr_mem[i]; i++) + { + struct passwd *nam = getpwnam (grp->gr_mem[i]); + if (NULL == nam) + continue; /* name in group that is not in user DB !? */ + if (nam->pw_uid == uc->uid) + { + /* yes, uid is in our group, allow! */ + ret = GNUNET_YES; + break; + } + } + } + } + } + if (GNUNET_NO == ret) + LOG (GNUNET_ERROR_TYPE_WARNING, _("Access denied to UID %d / GID %d\n"), + (uc == NULL) ? -1 : uc->uid, (uc == NULL) ? -1 : uc->gid); + break; +#endif + default: + LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"), + addr->sa_family); + return GNUNET_SYSERR; + } + if (ret != GNUNET_OK) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Access from `%s' denied to service `%s'\n"), GNUNET_a2s (addr, + addrlen), + sctx->serviceName); + } + return ret; +} + + +/** + * Get the name of the file where we will + * write the PID of the service. + */ +static char * +get_pid_file_name (struct GNUNET_SERVICE_Context *sctx) +{ + + char *pif; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->serviceName, + "PIDFILE", &pif)) + return NULL; + return pif; +} + + +/** + * Parse an IPv4 access control list. + */ +static int +process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, + const char *option) +{ + char *opt; + + if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, option)) + return GNUNET_OK; + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (sctx->cfg, + sctx->serviceName, + option, &opt)); + if (NULL == (*ret = parse_ipv4_specification (opt))) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), + opt, sctx->serviceName, option); + GNUNET_free (opt); + return GNUNET_SYSERR; + } + GNUNET_free (opt); + return GNUNET_OK; +} + + +/** + * Parse an IPv4 access control list. + */ +static int +process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, + const char *option) +{ + char *opt; + + if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, option)) + return GNUNET_OK; + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (sctx->cfg, + sctx->serviceName, + option, &opt)); + if (NULL == (*ret = parse_ipv6_specification (opt))) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"), + opt, sctx->serviceName, option); + GNUNET_free (opt); + return GNUNET_SYSERR; + } + GNUNET_free (opt); + return GNUNET_OK; +} + +/** + * Add the given UNIX domain path as an address to the + * list (as the first entry). + * + * @param saddrs array to update + * @param saddrlens where to store the address length + * @param unixpath path to add + */ +static void +add_unixpath (struct sockaddr **saddrs, socklen_t * saddrlens, + const char *unixpath) +{ +#ifdef AF_UNIX + struct sockaddr_un *un; + size_t slen; + + un = GNUNET_malloc (sizeof (struct sockaddr_un)); + un->sun_family = AF_UNIX; + slen = strlen (unixpath) + 1; + if (slen >= sizeof (un->sun_path)) + slen = sizeof (un->sun_path) - 1; + memcpy (un->sun_path, unixpath, slen); + un->sun_path[slen] = '\0'; + slen = sizeof (struct sockaddr_un); +#if LINUX + un->sun_path[0] = '\0'; +#endif +#if HAVE_SOCKADDR_IN_SIN_LEN + un->sun_len = (u_char) slen; +#endif + *saddrs = (struct sockaddr *) un; + *saddrlens = slen; +#else + /* this function should never be called + * unless AF_UNIX is defined! */ + GNUNET_assert (0); +#endif +} + + +/** + * Get the list of addresses that a server for the given service + * should bind to. + * + * @param serviceName name of the service + * @param cfg configuration (which specifies the addresses) + * @param addrs set (call by reference) to an array of pointers to the + * addresses the server should bind to and listen on; the + * array will be NULL-terminated (on success) + * @param addr_lens set (call by reference) to an array of the lengths + * of the respective 'struct sockaddr' struct in the 'addrs' + * array (on success) + * @return number of addresses found on success, + * GNUNET_SYSERR if the configuration + * did not specify reasonable finding information or + * if it specified a hostname that could not be resolved; + * GNUNET_NO if the number of addresses configured is + * zero (in this case, '*addrs' and '*addr_lens' will be + * set to NULL). + */ +int +GNUNET_SERVICE_get_server_addresses (const char *serviceName, + const struct GNUNET_CONFIGURATION_Handle + *cfg, struct sockaddr ***addrs, + socklen_t ** addr_lens) +{ + int disablev6; + struct GNUNET_NETWORK_Handle *desc; + unsigned long long port; + char *unixpath; + struct addrinfo hints; + struct addrinfo *res; + struct addrinfo *pos; + struct addrinfo *next; + unsigned int i; + int resi; + int ret; + struct sockaddr **saddrs; + socklen_t *saddrlens; + char *hostname; + + *addrs = NULL; + *addr_lens = NULL; + desc = NULL; + if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "DISABLEV6")) + { + if (GNUNET_SYSERR == + (disablev6 = + GNUNET_CONFIGURATION_get_value_yesno (cfg, serviceName, "DISABLEV6"))) + return GNUNET_SYSERR; + } + else + disablev6 = GNUNET_NO; + + if (!disablev6) + { + /* probe IPv6 support */ + desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); + if (NULL == desc) + { + if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || + (errno == EACCES)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); + return GNUNET_SYSERR; + } + LOG (GNUNET_ERROR_TYPE_INFO, + _ + ("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), + serviceName, STRERROR (errno)); + disablev6 = GNUNET_YES; + } + else + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); + desc = NULL; + } + } + + port = 0; + if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT")) + { + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, serviceName, + "PORT", &port)); + if (port > 65535) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Require valid port number for service `%s' in configuration!\n"), + serviceName); + return GNUNET_SYSERR; + } + } + + if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO")) + { + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, serviceName, + "BINDTO", &hostname)); + } + else + hostname = NULL; + + unixpath = NULL; +#ifdef AF_UNIX + if ((GNUNET_YES == + GNUNET_CONFIGURATION_have_value (cfg, serviceName, "UNIXPATH")) && + (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, serviceName, "UNIXPATH", + &unixpath)) && + (0 < strlen (unixpath))) + { + /* probe UNIX support */ + struct sockaddr_un s_un; + + if (strlen (unixpath) >= sizeof (s_un.sun_path)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, + sizeof (s_un.sun_path)); + GNUNET_free_non_null (hostname); + GNUNET_free (unixpath); + return GNUNET_SYSERR; + } + + desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); + if (NULL == desc) + { + if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || + (errno == EACCES)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); + GNUNET_free_non_null (hostname); + GNUNET_free (unixpath); + return GNUNET_SYSERR; + } + LOG (GNUNET_ERROR_TYPE_INFO, + _ + ("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"), + serviceName, STRERROR (errno)); + GNUNET_free (unixpath); + unixpath = NULL; + } + else + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); + desc = NULL; + } + } +#endif + + if ((port == 0) && (unixpath == NULL)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _ + ("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"), + serviceName); + GNUNET_free_non_null (hostname); + return GNUNET_SYSERR; + } + if (port == 0) + { + saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *)); + saddrlens = GNUNET_malloc (2 * sizeof (socklen_t)); + add_unixpath (saddrs, saddrlens, unixpath); + GNUNET_free_non_null (unixpath); + GNUNET_free_non_null (hostname); + *addrs = saddrs; + *addr_lens = saddrlens; + return 1; + } + + if (hostname != NULL) + { +#if DEBUG_SERVICE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Resolving `%s' since that is where `%s' will bind to.\n", hostname, + serviceName); +#endif + memset (&hints, 0, sizeof (struct addrinfo)); + if (disablev6) + hints.ai_family = AF_INET; + if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || + (res == NULL)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"), hostname, + gai_strerror (ret)); + GNUNET_free (hostname); + GNUNET_free_non_null (unixpath); + return GNUNET_SYSERR; + } + next = res; + i = 0; + while (NULL != (pos = next)) + { + next = pos->ai_next; + if ((disablev6) && (pos->ai_family == AF_INET6)) + continue; + i++; + } + if (0 == i) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to find %saddress for `%s'.\n"), + disablev6 ? "IPv4 " : "", hostname); + freeaddrinfo (res); + GNUNET_free (hostname); + GNUNET_free_non_null (unixpath); + return GNUNET_SYSERR; + } + resi = i; + if (NULL != unixpath) + resi++; + saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); + saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); + i = 0; + if (NULL != unixpath) + { + add_unixpath (saddrs, saddrlens, unixpath); + i++; + } + next = res; + while (NULL != (pos = next)) + { + next = pos->ai_next; + if ((disablev6) && (pos->ai_family == AF_INET6)) + continue; + if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0)) + continue; /* not TCP */ + if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0)) + continue; /* huh? */ +#if DEBUG_SERVICE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n", + serviceName, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); +#endif + if (pos->ai_family == AF_INET) + { + GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in)); + saddrlens[i] = pos->ai_addrlen; + saddrs[i] = GNUNET_malloc (saddrlens[i]); + memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); + ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); + } + else + { + GNUNET_assert (pos->ai_family == AF_INET6); + GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6)); + saddrlens[i] = pos->ai_addrlen; + saddrs[i] = GNUNET_malloc (saddrlens[i]); + memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); + ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); + } + i++; + } + GNUNET_free (hostname); + freeaddrinfo (res); + resi = i; + } + else + { + /* will bind against everything, just set port */ + if (disablev6) + { + /* V4-only */ + resi = 1; + if (NULL != unixpath) + resi++; + i = 0; + saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); + saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); + if (NULL != unixpath) + { + add_unixpath (saddrs, saddrlens, unixpath); + i++; + } + saddrlens[i] = sizeof (struct sockaddr_in); + saddrs[i] = GNUNET_malloc (saddrlens[i]); +#if HAVE_SOCKADDR_IN_SIN_LEN + ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; +#endif + ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; + ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); + } + else + { + /* dual stack */ + resi = 2; + if (NULL != unixpath) + resi++; + saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); + saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); + i = 0; + if (NULL != unixpath) + { + add_unixpath (saddrs, saddrlens, unixpath); + i++; + } + saddrlens[i] = sizeof (struct sockaddr_in6); + saddrs[i] = GNUNET_malloc (saddrlens[i]); +#if HAVE_SOCKADDR_IN_SIN_LEN + ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; +#endif + ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; + ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); + i++; + saddrlens[i] = sizeof (struct sockaddr_in); + saddrs[i] = GNUNET_malloc (saddrlens[i]); +#if HAVE_SOCKADDR_IN_SIN_LEN + ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; +#endif + ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; + ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); + } + } + GNUNET_free_non_null (unixpath); + *addrs = saddrs; + *addr_lens = saddrlens; + return resi; +} + + +#ifdef MINGW +/** + * @return GNUNET_YES if ok, GNUNET_NO if not ok (must bind yourself), + * and GNUNET_SYSERR on error. + */ +static int +receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) +{ + const char *env_buf; + int fail; + uint64_t count, i; + HANDLE lsocks_pipe; + + env_buf = getenv ("GNUNET_OS_READ_LSOCKS"); + if ((env_buf == NULL) || (strlen (env_buf) <= 0)) + { + return GNUNET_NO; + } + /* Using W32 API directly here, because this pipe will + * never be used outside of this function, and it's just too much of a bother + * to create a GNUnet API that boxes a HANDLE (the way it is done with socks) + */ + lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10); + if (lsocks_pipe == 0 || lsocks_pipe == INVALID_HANDLE_VALUE) + return GNUNET_NO; + + fail = 1; + do + { + int ret; + int fail2; + DWORD rd; + + ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL); + if (ret == 0 || rd != sizeof (count) || count == 0) + break; + sctx->lsocks = + GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1)); + + fail2 = 1; + for (i = 0; i < count; i++) + { + WSAPROTOCOL_INFOA pi; + uint64_t size; + SOCKET s; + ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL); + if (ret == 0 || rd != sizeof (size) || size != sizeof (pi)) + break; + ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL); + if (ret == 0 || rd != sizeof (pi)) + break; + s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED); + sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s); + if (sctx->lsocks[i] == NULL) + break; + else if (i == count - 1) + fail2 = 0; + } + if (fail2) + break; + sctx->lsocks[count] = NULL; + fail = 0; + } + while (fail); + + CloseHandle (lsocks_pipe); + + if (fail) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Could not access a pre-bound socket, will try to bind myself\n")); + for (i = 0; i < count && sctx->lsocks[i] != NULL; i++) + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i])); + GNUNET_free_non_null (sctx->lsocks); + sctx->lsocks = NULL; + return GNUNET_NO; + } + + return GNUNET_YES; +} +#endif + + +/** + * Setup addr, addrlen, idle_timeout + * based on configuration! + * + * Configuration may specify: + * - PORT (where to bind to for TCP) + * - UNIXPATH (where to bind to for UNIX domain sockets) + * - TIMEOUT (after how many ms does an inactive service timeout); + * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack) + * - BINDTO (hostname or IP address to bind to, otherwise we take everything) + * - ACCEPT_FROM (only allow connections from specified IPv4 subnets) + * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets) + * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) + * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) + * + * @return GNUNET_OK if configuration succeeded + */ +static int +setup_service (struct GNUNET_SERVICE_Context *sctx) +{ + struct GNUNET_TIME_Relative idleout; + int tolerant; + +#ifndef MINGW + const char *lpid; + unsigned int pid; + const char *nfds; + unsigned int cnt; + int flags; +#endif + + if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, "TIMEOUT")) + { + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->serviceName, + "TIMEOUT", &idleout)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Specified value for `%s' of service `%s' is invalid\n"), + "TIMEOUT", sctx->serviceName); + return GNUNET_SYSERR; + } + sctx->timeout = idleout; + } + else + sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + + if (GNUNET_CONFIGURATION_have_value + (sctx->cfg, sctx->serviceName, "TOLERANT")) + { + if (GNUNET_SYSERR == + (tolerant = + GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName, + "TOLERANT"))) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Specified value for `%s' of service `%s' is invalid\n"), + "TOLERANT", sctx->serviceName); + return GNUNET_SYSERR; + } + } + else + tolerant = GNUNET_NO; + +#ifndef MINGW + errno = 0; + if ((NULL != (lpid = getenv ("LISTEN_PID"))) && + (1 == sscanf (lpid, "%u", &pid)) && (getpid () == (pid_t) pid) && + (NULL != (nfds = getenv ("LISTEN_FDS"))) && + (1 == sscanf (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) && + (cnt + 4 < FD_SETSIZE)) + { + sctx->lsocks = + GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1)); + while (0 < cnt--) + { + flags = fcntl (3 + cnt, F_GETFD); + if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) || + (NULL == + (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt)))) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _ + ("Could not access pre-bound socket %u, will try to bind myself\n"), + (unsigned int) 3 + cnt); + cnt++; + while (sctx->lsocks[cnt] != NULL) + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++])); + GNUNET_free (sctx->lsocks); + sctx->lsocks = NULL; + break; + } + } + unsetenv ("LISTEN_PID"); + unsetenv ("LISTEN_FDS"); + } +#else + if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL) + { + receive_sockets_from_parent (sctx); + putenv ("GNUNET_OS_READ_LSOCKS="); + } +#endif + + if ((sctx->lsocks == NULL) && + (GNUNET_SYSERR == + GNUNET_SERVICE_get_server_addresses (sctx->serviceName, sctx->cfg, + &sctx->addrs, &sctx->addrlens))) + return GNUNET_SYSERR; + sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES; + sctx->match_uid = + GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName, + "UNIX_MATCH_UID"); + sctx->match_gid = + GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName, + "UNIX_MATCH_GID"); + process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM"); + process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM"); + process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6"); + process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6"); + + return GNUNET_OK; +} + + +/** + * Get the name of the user that'll be used + * to provide the service. + */ +static char * +get_user_name (struct GNUNET_SERVICE_Context *sctx) +{ + + char *un; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->serviceName, + "USERNAME", &un)) + return NULL; + return un; +} + +/** + * Write PID file. + */ +static int +write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid) +{ + FILE *pidfd; + char *pif; + char *user; + char *rdir; + int len; + + if (NULL == (pif = get_pid_file_name (sctx))) + return GNUNET_OK; /* no file desired */ + user = get_user_name (sctx); + rdir = GNUNET_strdup (pif); + len = strlen (rdir); + while ((len > 0) && (rdir[len] != DIR_SEPARATOR)) + len--; + rdir[len] = '\0'; + if (0 != ACCESS (rdir, F_OK)) + { + /* we get to create a directory -- and claim it + * as ours! */ + GNUNET_DISK_directory_create (rdir); + if ((user != NULL) && (0 < strlen (user))) + GNUNET_DISK_file_change_owner (rdir, user); + } + if (0 != ACCESS (rdir, W_OK | X_OK)) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir); + GNUNET_free (rdir); + GNUNET_free_non_null (user); + GNUNET_free (pif); + return GNUNET_SYSERR; + } + GNUNET_free (rdir); + pidfd = FOPEN (pif, "w"); + if (pidfd == NULL) + { + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif); + GNUNET_free (pif); + GNUNET_free_non_null (user); + return GNUNET_SYSERR; + } + if (0 > FPRINTF (pidfd, "%u", pid)) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif); + GNUNET_break (0 == FCLOSE (pidfd)); + if ((user != NULL) && (0 < strlen (user))) + GNUNET_DISK_file_change_owner (pif, user); + GNUNET_free_non_null (user); + GNUNET_free (pif); + return GNUNET_OK; +} + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_SERVER_Handle *server = cls; + + GNUNET_SERVER_destroy (server); +} + + +/** + * Initial task for the service. + */ +static void +service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_SERVICE_Context *sctx = cls; + unsigned int i; + + GNUNET_RESOLVER_connect (sctx->cfg); + if (sctx->lsocks != NULL) + sctx->server = + GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks, + sctx->timeout, sctx->require_found); + else + sctx->server = + GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens, + sctx->timeout, sctx->require_found); + if (sctx->server == NULL) + { + if (sctx->addrs != NULL) + { + i = 0; + while (sctx->addrs[i] != NULL) + { + LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to start `%s' at `%s'\n"), + sctx->serviceName, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); + i++; + } + } + sctx->ret = GNUNET_SYSERR; + return; + } + if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN)) + { + /* install a task that will kill the server + * process if the scheduler ever gets a shutdown signal */ + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + sctx->server); + } + sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers)); + memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers)); + i = 0; + while ((sctx->my_handlers[i].callback != NULL)) + sctx->my_handlers[i++].callback_cls = sctx; + GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers); + if (sctx->ready_confirm_fd != -1) + { + GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1)); + GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd)); + sctx->ready_confirm_fd = -1; + write_pid_file (sctx, getpid ()); + } + if (sctx->addrs != NULL) + { + i = 0; + while (sctx->addrs[i] != NULL) + { + LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"), + sctx->serviceName, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); + i++; + } + } + sctx->task (sctx->task_cls, sctx->server, sctx->cfg); +} + + +/** + * Detach from terminal. + */ +static int +detach_terminal (struct GNUNET_SERVICE_Context *sctx) +{ +#ifndef MINGW + pid_t pid; + int nullfd; + int filedes[2]; + + if (0 != PIPE (filedes)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe"); + return GNUNET_SYSERR; + } + pid = fork (); + if (pid < 0) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); + return GNUNET_SYSERR; + } + if (pid != 0) + { + /* Parent */ + char c; + + GNUNET_break (0 == CLOSE (filedes[1])); + c = 'X'; + if (1 != READ (filedes[0], &c, sizeof (char))) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read"); + fflush (stdout); + switch (c) + { + case '.': + exit (0); + case 'I': + LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n")); + break; + case 'S': + LOG (GNUNET_ERROR_TYPE_INFO, + _("Service process could not initialize server function\n")); + break; + case 'X': + LOG (GNUNET_ERROR_TYPE_INFO, + _("Service process failed to report status\n")); + break; + } + exit (1); /* child reported error */ + } + GNUNET_break (0 == CLOSE (0)); + GNUNET_break (0 == CLOSE (1)); + GNUNET_break (0 == CLOSE (filedes[0])); + nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND); + if (nullfd < 0) + return GNUNET_SYSERR; + /* set stdin/stdout to /dev/null */ + if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); + (void) CLOSE (nullfd); + return GNUNET_SYSERR; + } + (void) CLOSE (nullfd); + /* Detach from controlling terminal */ + pid = setsid (); + if (pid == -1) + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid"); + sctx->ready_confirm_fd = filedes[1]; +#else + /* FIXME: we probably need to do something else + * elsewhere in order to fork the process itself... */ + FreeConsole (); +#endif + return GNUNET_OK; +} + + +/** + * Set user ID. + */ +static int +set_user_id (struct GNUNET_SERVICE_Context *sctx) +{ + char *user; + + if (NULL == (user = get_user_name (sctx))) + return GNUNET_OK; /* keep */ +#ifndef MINGW + struct passwd *pws; + + errno = 0; + pws = getpwnam (user); + if (pws == NULL) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Cannot obtain information about user `%s': %s\n"), user, + errno == 0 ? _("No such user") : STRERROR (errno)); + GNUNET_free (user); + return GNUNET_SYSERR; + } + if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) || +#if HAVE_INITGROUPS + (0 != initgroups (user, pws->pw_gid)) || +#endif + (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid))) + { + if ((0 != setregid (pws->pw_gid, pws->pw_gid)) || + (0 != setreuid (pws->pw_uid, pws->pw_uid))) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"), + user, STRERROR (errno)); + GNUNET_free (user); + return GNUNET_SYSERR; + } + } +#endif + GNUNET_free (user); + return GNUNET_OK; +} + + +/** + * Delete the PID file that was created by our parent. + */ +static void +pid_file_delete (struct GNUNET_SERVICE_Context *sctx) +{ + char *pif = get_pid_file_name (sctx); + + if (pif == NULL) + return; /* no PID file */ + if (0 != UNLINK (pif)) + LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif); + GNUNET_free (pif); +} + + +/** + * Run a standard GNUnet service startup sequence (initialize loggers + * and configuration, parse options). + * + * @param argc number of command line arguments + * @param argv command line arguments + * @param serviceName our service name + * @param opt service options + * @param task main task of the service + * @param task_cls closure for task + * @return GNUNET_SYSERR on error, GNUNET_OK + * if we shutdown nicely + */ +int +GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName, + enum GNUNET_SERVICE_Options opt, GNUNET_SERVICE_Main task, + void *task_cls) +{ +#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0) + + int err; + char *cfg_fn; + char *loglev; + char *logfile; + int do_daemonize; + unsigned int i; + unsigned long long skew_offset; + unsigned long long skew_variance; + long long clock_offset; + struct GNUNET_SERVICE_Context sctx; + struct GNUNET_CONFIGURATION_Handle *cfg; + + struct GNUNET_GETOPT_CommandLineOption service_options[] = { + GNUNET_GETOPT_OPTION_CFG_FILE (&cfg_fn), + {'d', "daemonize", NULL, + gettext_noop ("do daemonize (detach from terminal)"), 0, + GNUNET_GETOPT_set_one, &do_daemonize}, + GNUNET_GETOPT_OPTION_HELP (serviceName), + GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), + GNUNET_GETOPT_OPTION_LOGFILE (&logfile), + GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION), + GNUNET_GETOPT_OPTION_END + }; + err = 1; + do_daemonize = 0; + logfile = NULL; + loglev = NULL; + cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE); + memset (&sctx, 0, sizeof (sctx)); + sctx.options = opt; + sctx.ready_confirm_fd = -1; + sctx.ret = GNUNET_OK; + sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL; + sctx.task = task; + sctx.task_cls = task_cls; + sctx.serviceName = serviceName; + sctx.cfg = cfg = GNUNET_CONFIGURATION_create (); + /* setup subsystems */ + if (GNUNET_SYSERR == + GNUNET_GETOPT_run (serviceName, service_options, argc, argv)) + goto shutdown; + if (GNUNET_OK != GNUNET_log_setup (serviceName, loglev, logfile)) + HANDLE_ERROR; + if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_fn)) + goto shutdown; + if (GNUNET_OK != setup_service (&sctx)) + goto shutdown; + if ((do_daemonize == 1) && (GNUNET_OK != detach_terminal (&sctx))) + HANDLE_ERROR; + if (GNUNET_OK != set_user_id (&sctx)) + goto shutdown; +#if DEBUG_SERVICE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Service `%s' runs with configuration from `%s'\n", serviceName, cfg_fn); +#endif + if ((GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", + "SKEW_OFFSET", &skew_offset)) && + (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", + "SKEW_VARIANCE", &skew_variance))) + { + clock_offset = skew_offset - skew_variance; + GNUNET_TIME_set_offset (clock_offset); +#if DEBUG_SERVICE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset); +#endif + } + /* actually run service */ + err = 0; + GNUNET_SCHEDULER_run (&service_task, &sctx); + + /* shutdown */ + if ((do_daemonize == 1) && (sctx.server != NULL)) + pid_file_delete (&sctx); + GNUNET_free_non_null (sctx.my_handlers); + +shutdown: + if (sctx.ready_confirm_fd != -1) + { + if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1)) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write"); + GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd)); + } + + GNUNET_CONFIGURATION_destroy (cfg); + i = 0; + if (sctx.addrs != NULL) + while (sctx.addrs[i] != NULL) + GNUNET_free (sctx.addrs[i++]); + GNUNET_free_non_null (sctx.addrs); + GNUNET_free_non_null (sctx.addrlens); + GNUNET_free_non_null (logfile); + GNUNET_free_non_null (loglev); + GNUNET_free (cfg_fn); + GNUNET_free_non_null (sctx.v4_denied); + GNUNET_free_non_null (sctx.v6_denied); + GNUNET_free_non_null (sctx.v4_allowed); + GNUNET_free_non_null (sctx.v6_allowed); + + return err ? GNUNET_SYSERR : sctx.ret; +} + + +/** + * Run a service startup sequence within an existing + * initialized system. + * + * @param serviceName our service name + * @param cfg configuration to use + * @return NULL on error, service handle + */ +struct GNUNET_SERVICE_Context * +GNUNET_SERVICE_start (const char *serviceName, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + int i; + struct GNUNET_SERVICE_Context *sctx; + + sctx = GNUNET_malloc (sizeof (struct GNUNET_SERVICE_Context)); + sctx->ready_confirm_fd = -1; /* no daemonizing */ + sctx->ret = GNUNET_OK; + sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + sctx->serviceName = serviceName; + sctx->cfg = cfg; + + /* setup subsystems */ + if (GNUNET_OK != setup_service (sctx)) + { + GNUNET_SERVICE_stop (sctx); + return NULL; + } + if (sctx->lsocks != NULL) + sctx->server = + GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks, + sctx->timeout, sctx->require_found); + else + sctx->server = + GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens, + sctx->timeout, sctx->require_found); + + if (NULL == sctx->server) + { + GNUNET_SERVICE_stop (sctx); + return NULL; + } + sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers)); + memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers)); + i = 0; + while ((sctx->my_handlers[i].callback != NULL)) + sctx->my_handlers[i++].callback_cls = sctx; + GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers); + return sctx; +} + +/** + * Obtain the server used by a service. Note that the server must NOT + * be destroyed by the caller. + * + * @param ctx the service context returned from the start function + * @return handle to the server for this service, NULL if there is none + */ +struct GNUNET_SERVER_Handle * +GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx) +{ + return ctx->server; +} + + +/** + * Stop a service that was started with "GNUNET_SERVICE_start". + * + * @param sctx the service context returned from the start function + */ +void +GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx) +{ + unsigned int i; + + if (NULL != sctx->server) + GNUNET_SERVER_destroy (sctx->server); + GNUNET_free_non_null (sctx->my_handlers); + if (sctx->addrs != NULL) + { + i = 0; + while (sctx->addrs[i] != NULL) + GNUNET_free (sctx->addrs[i++]); + GNUNET_free (sctx->addrs); + } + GNUNET_free_non_null (sctx->addrlens); + GNUNET_free_non_null (sctx->v4_denied); + GNUNET_free_non_null (sctx->v6_denied); + GNUNET_free_non_null (sctx->v4_allowed); + GNUNET_free_non_null (sctx->v6_allowed); + GNUNET_free (sctx); +} + + +/* end of service.c */ diff --git a/src/util/signal.c b/src/util/signal.c new file mode 100644 index 0000000..c3bb718 --- /dev/null +++ b/src/util/signal.c @@ -0,0 +1,98 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/signal.c + * @brief code for installing and uninstalling signal handlers + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_signal_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + + +struct GNUNET_SIGNAL_Context +{ + int sig; + + GNUNET_SIGNAL_Handler method; + +#ifndef MINGW + struct sigaction oldsig; +#endif +}; + +#ifdef WINDOWS +GNUNET_SIGNAL_Handler w32_sigchld_handler = NULL; +#endif + +struct GNUNET_SIGNAL_Context * +GNUNET_SIGNAL_handler_install (int signum, GNUNET_SIGNAL_Handler handler) +{ + struct GNUNET_SIGNAL_Context *ret; + +#ifndef MINGW + struct sigaction sig; +#endif + + ret = GNUNET_malloc (sizeof (struct GNUNET_SIGNAL_Context)); + ret->sig = signum; + ret->method = handler; +#ifndef MINGW + memset (&sig, 0, sizeof (sig)); + sig.sa_handler = (void *) handler; + sigemptyset (&sig.sa_mask); +#ifdef SA_INTERRUPT + sig.sa_flags = SA_INTERRUPT; /* SunOS */ +#else + sig.sa_flags = SA_RESTART; +#endif + sigaction (signum, &sig, &ret->oldsig); +#else + if (signum == GNUNET_SIGCHLD) + w32_sigchld_handler = handler; + else + { + __p_sig_fn_t sigret = signal (signum, (__p_sig_fn_t) handler); + + if (sigret == SIG_ERR) + { + LOG (GNUNET_ERROR_TYPE_WARNING, _("signal (%d, %p) returned %d.\n"), + signum, handler, sigret); + } + } +#endif + return ret; +} + +void +GNUNET_SIGNAL_handler_uninstall (struct GNUNET_SIGNAL_Context *ctx) +{ +#ifndef MINGW + struct sigaction sig; + + sigemptyset (&sig.sa_mask); + sigaction (ctx->sig, &ctx->oldsig, &sig); +#endif + GNUNET_free (ctx); +} diff --git a/src/util/strings.c b/src/util/strings.c new file mode 100644 index 0000000..8000a93 --- /dev/null +++ b/src/util/strings.c @@ -0,0 +1,633 @@ +/* + This file is part of GNUnet. + (C) 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/strings.c + * @brief string functions + * @author Nils Durner + * @author Christian Grothoff + */ + +#include "platform.h" +#if HAVE_ICONV +#include +#endif +#include "gnunet_common.h" +#include "gnunet_strings_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + + +/** + * Fill a buffer of the given size with + * count 0-terminated strings (given as varargs). + * If "buffer" is NULL, only compute the amount of + * space required (sum of "strlen(arg)+1"). + * + * Unlike using "snprintf" with "%s", this function + * will add 0-terminators after each string. The + * "GNUNET_string_buffer_tokenize" function can be + * used to parse the buffer back into individual + * strings. + * + * @param buffer the buffer to fill with strings, can + * be NULL in which case only the necessary + * amount of space will be calculated + * @param size number of bytes available in buffer + * @param count number of strings that follow + * @param ... count 0-terminated strings to copy to buffer + * @return number of bytes written to the buffer + * (or number of bytes that would have been written) + */ +size_t +GNUNET_STRINGS_buffer_fill (char *buffer, size_t size, unsigned int count, ...) +{ + size_t needed; + size_t slen; + const char *s; + va_list ap; + + needed = 0; + va_start (ap, count); + while (count > 0) + { + s = va_arg (ap, const char *); + + slen = strlen (s) + 1; + if (buffer != NULL) + { + GNUNET_assert (needed + slen <= size); + memcpy (&buffer[needed], s, slen); + } + needed += slen; + count--; + } + va_end (ap); + return needed; +} + + +/** + * Given a buffer of a given size, find "count" + * 0-terminated strings in the buffer and assign + * the count (varargs) of type "const char**" to the + * locations of the respective strings in the + * buffer. + * + * @param buffer the buffer to parse + * @param size size of the buffer + * @param count number of strings to locate + * @return offset of the character after the last 0-termination + * in the buffer, or 0 on error. + */ +unsigned int +GNUNET_STRINGS_buffer_tokenize (const char *buffer, size_t size, + unsigned int count, ...) +{ + unsigned int start; + unsigned int needed; + const char **r; + va_list ap; + + needed = 0; + va_start (ap, count); + while (count > 0) + { + r = va_arg (ap, const char **); + + start = needed; + while ((needed < size) && (buffer[needed] != '\0')) + needed++; + if (needed == size) + { + va_end (ap); + return 0; /* error */ + } + *r = &buffer[start]; + needed++; /* skip 0-termination */ + count--; + } + va_end (ap); + return needed; +} + + +/** + * Convert a given filesize into a fancy human-readable format. + * + * @param size number of bytes + * @return fancy representation of the size (possibly rounded) for humans + */ +char * +GNUNET_STRINGS_byte_size_fancy (unsigned long long size) +{ + const char *unit = _( /* size unit */ "b"); + char *ret; + + if (size > 5 * 1024) + { + size = size / 1024; + unit = "KiB"; + if (size > 5 * 1024) + { + size = size / 1024; + unit = "MiB"; + if (size > 5 * 1024) + { + size = size / 1024; + unit = "GiB"; + if (size > 5 * 1024) + { + size = size / 1024; + unit = "TiB"; + } + } + } + } + ret = GNUNET_malloc (32); + GNUNET_snprintf (ret, 32, "%llu %s", size, unit); + return ret; +} + + +/** + * Convert a given fancy human-readable size to bytes. + * + * @param fancy_size human readable string (i.e. 1 MB) + * @param size set to the size in bytes + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, + unsigned long long *size) +{ + struct + { + const char *name; + unsigned long long value; + } table[] = + { + { + "B", 1}, + { + "KiB", 1024}, + { + "kB", 1000}, + { + "MiB", 1024 * 1024}, + { + "MB", 1000 * 1000}, + { + "GiB", 1024 * 1024 * 1024}, + { + "GB", 1000 * 1000 * 1000}, + { + "TiB", 1024LL * 1024LL * 1024LL * 1024LL}, + { + "TB", 1000LL * 1000LL * 1000LL * 1024LL}, + { + "PiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL}, + { + "PB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL}, + { + "EiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL}, + { + "EB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL * 1000LL}, + { + NULL, 0} + }; + unsigned long long ret; + char *in; + const char *tok; + unsigned long long last; + unsigned int i; + + ret = 0; + last = 0; + in = GNUNET_strdup (fancy_size); + for (tok = strtok (in, " "); tok != NULL; tok = strtok (NULL, " ")) + { + i = 0; + while ((table[i].name != NULL) && (0 != strcasecmp (table[i].name, tok))) + i++; + if (table[i].name != NULL) + last *= table[i].value; + else + { + ret += last; + last = 0; + if (1 != sscanf (tok, "%llu", &last)) + { + GNUNET_free (in); + return GNUNET_SYSERR; /* expected number */ + } + } + } + ret += last; + *size = ret; + GNUNET_free (in); + return GNUNET_OK; +} + + +/** + * Convert a given fancy human-readable time to our internal + * representation. + * + * @param fancy_size human readable string (i.e. 1 minute) + * @param rtime set to the relative time + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_size, + struct GNUNET_TIME_Relative *rtime) +{ + struct + { + const char *name; + unsigned long long value; + } table[] = + { + { + "ms", 1}, + { + "s", 1000}, + { + "\"", 1000}, + { + "min", 60 * 1000}, + { + "minutes", 60 * 1000}, + { + "'", 60 * 1000}, + { + "h", 60 * 60 * 1000}, + { + "d", 24 * 60 * 60 * 1000}, + { + "a", 31557600 /* year */ }, + { + NULL, 0} + }; + unsigned long long ret; + char *in; + const char *tok; + unsigned long long last; + unsigned int i; + + if ((0 == strcasecmp (fancy_size, "infinity")) || + (0 == strcasecmp (fancy_size, "forever"))) + { + *rtime = GNUNET_TIME_UNIT_FOREVER_REL; + return GNUNET_OK; + } + ret = 0; + last = 0; + in = GNUNET_strdup (fancy_size); + for (tok = strtok (in, " "); tok != NULL; tok = strtok (NULL, " ")) + { + i = 0; + while ((table[i].name != NULL) && (0 != strcasecmp (table[i].name, tok))) + i++; + if (table[i].name != NULL) + last *= table[i].value; + else + { + ret += last; + last = 0; + if (1 != sscanf (tok, "%llu", &last)) + { + GNUNET_free (in); + return GNUNET_SYSERR; /* expected number */ + } + } + } + ret += last; + rtime->rel_value = (uint64_t) ret; + GNUNET_free (in); + return GNUNET_OK; +} + +/** + * Convert the len characters long character sequence + * given in input that is in the given input charset + * to a string in given output charset. + * @return the converted string (0-terminated), + * if conversion fails, a copy of the orignal + * string is returned. + */ +char * +GNUNET_STRINGS_conv (const char *input, size_t len, const char *input_charset, const char *output_charset) +{ + char *ret; + +#if ENABLE_NLS && HAVE_ICONV + size_t tmpSize; + size_t finSize; + char *tmp; + char *itmp; + iconv_t cd; + + cd = iconv_open (output_charset, input_charset); + if (cd == (iconv_t) - 1) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "iconv_open"); + LOG (GNUNET_ERROR_TYPE_WARNING, _("Character sets requested were `%s'->`%s'\n"), + input_charset, output_charset); + ret = GNUNET_malloc (len + 1); + memcpy (ret, input, len); + ret[len] = '\0'; + return ret; + } + tmpSize = 3 * len + 4; + tmp = GNUNET_malloc (tmpSize); + itmp = tmp; + finSize = tmpSize; + if (iconv (cd, +#if FREEBSD || DARWIN || WINDOWS + (const char **) &input, +#else + (char **) &input, +#endif + &len, &itmp, &finSize) == SIZE_MAX) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "iconv"); + iconv_close (cd); + GNUNET_free (tmp); + ret = GNUNET_malloc (len + 1); + memcpy (ret, input, len); + ret[len] = '\0'; + return ret; + } + ret = GNUNET_malloc (tmpSize - finSize + 1); + memcpy (ret, tmp, tmpSize - finSize); + ret[tmpSize - finSize] = '\0'; + GNUNET_free (tmp); + if (0 != iconv_close (cd)) + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "iconv_close"); + return ret; +#else + ret = GNUNET_malloc (len + 1); + memcpy (ret, input, len); + ret[len] = '\0'; + return ret; +#endif +} + + +/** + * Convert the len characters long character sequence + * given in input that is in the given charset + * to UTF-8. + * @return the converted string (0-terminated), + * if conversion fails, a copy of the orignal + * string is returned. + */ +char * +GNUNET_STRINGS_to_utf8 (const char *input, size_t len, const char *charset) +{ + return GNUNET_STRINGS_conv (input, len, charset, "UTF-8"); +} + +/** + * Convert the len bytes-long UTF-8 string + * given in input to the given charset. + + * @return the converted string (0-terminated), + * if conversion fails, a copy of the orignal + * string is returned. + */ +char * +GNUNET_STRINGS_from_utf8 (const char *input, size_t len, const char *charset) +{ + return GNUNET_STRINGS_conv (input, len, "UTF-8", charset); +} + + + +/** + * Complete filename (a la shell) from abbrevition. + * @param fil the name of the file, may contain ~/ or + * be relative to the current directory + * @returns the full file name, + * NULL is returned on error + */ +char * +GNUNET_STRINGS_filename_expand (const char *fil) +{ + char *buffer; + +#ifndef MINGW + size_t len; + size_t n; + char *fm; + const char *fil_ptr; +#else + char *fn; + long lRet; +#endif + + if (fil == NULL) + return NULL; + +#ifndef MINGW + if (fil[0] == DIR_SEPARATOR) + /* absolute path, just copy */ + return GNUNET_strdup (fil); + if (fil[0] == '~') + { + fm = getenv ("HOME"); + if (fm == NULL) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Failed to expand `$HOME': environment variable `HOME' not set")); + return NULL; + } + fm = GNUNET_strdup (fm); + /* do not copy '~' */ + fil_ptr = fil + 1; + + /* skip over dir seperator to be consistent */ + if (fil_ptr[0] == DIR_SEPARATOR) + fil_ptr++; + } + else + { + /* relative path */ + fil_ptr = fil; + len = 512; + fm = NULL; + while (1) + { + buffer = GNUNET_malloc (len); + if (getcwd (buffer, len) != NULL) + { + fm = buffer; + break; + } + if ((errno == ERANGE) && (len < 1024 * 1024 * 4)) + { + len *= 2; + GNUNET_free (buffer); + continue; + } + GNUNET_free (buffer); + break; + } + if (fm == NULL) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "getcwd"); + buffer = getenv ("PWD"); /* alternative */ + if (buffer != NULL) + fm = GNUNET_strdup (buffer); + } + if (fm == NULL) + fm = GNUNET_strdup ("./"); /* give up */ + } + n = strlen (fm) + 1 + strlen (fil_ptr) + 1; + buffer = GNUNET_malloc (n); + GNUNET_snprintf (buffer, n, "%s%s%s", fm, + (fm[strlen (fm) - 1] == + DIR_SEPARATOR) ? "" : DIR_SEPARATOR_STR, fil_ptr); + GNUNET_free (fm); + return buffer; +#else + fn = GNUNET_malloc (MAX_PATH + 1); + + if ((lRet = plibc_conv_to_win_path (fil, fn)) != ERROR_SUCCESS) + { + SetErrnoFromWinError (lRet); + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "plibc_conv_to_win_path"); + return NULL; + } + /* is the path relative? */ + if ((strncmp (fn + 1, ":\\", 2) != 0) && (strncmp (fn, "\\\\", 2) != 0)) + { + char szCurDir[MAX_PATH + 1]; + + lRet = GetCurrentDirectory (MAX_PATH + 1, szCurDir); + if (lRet + strlen (fn) + 1 > (MAX_PATH + 1)) + { + SetErrnoFromWinError (ERROR_BUFFER_OVERFLOW); + LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetCurrentDirectory"); + return NULL; + } + buffer = GNUNET_malloc (MAX_PATH + 1); + GNUNET_snprintf (buffer, MAX_PATH + 1, "%s\\%s", szCurDir, fn); + GNUNET_free (fn); + fn = buffer; + } + + return fn; +#endif +} + + +/** + * Give relative time in human-readable fancy format. + * + * @param delta time in milli seconds + * @return time as human-readable string + */ +char * +GNUNET_STRINGS_relative_time_to_string (struct GNUNET_TIME_Relative delta) +{ + const char *unit = _( /* time unit */ "ms"); + char *ret; + uint64_t dval = delta.rel_value; + + if (delta.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) + return GNUNET_strdup (_("eternity")); + if (dval > 5 * 1000) + { + dval = dval / 1000; + unit = _( /* time unit */ "s"); + if (dval > 5 * 60) + { + dval = dval / 60; + unit = _( /* time unit */ "m"); + if (dval > 5 * 60) + { + dval = dval / 60; + unit = _( /* time unit */ "h"); + if (dval > 5 * 24) + { + dval = dval / 24; + unit = _( /* time unit */ " days"); + } + } + } + } + GNUNET_asprintf (&ret, "%llu %s", dval, unit); + return ret; +} + + +/** + * "man ctime_r", except for GNUnet time; also, unlike ctime, the + * return value does not include the newline character. + * + * @param t time to convert + * @return absolute time in human-readable format + */ +char * +GNUNET_STRINGS_absolute_time_to_string (struct GNUNET_TIME_Absolute t) +{ + time_t tt; + char *ret; + + if (t.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) + return GNUNET_strdup (_("end of time")); + tt = t.abs_value / 1000; +#ifdef ctime_r + ret = ctime_r (&tt, GNUNET_malloc (32)); +#else + ret = GNUNET_strdup (ctime (&tt)); +#endif + ret[strlen (ret) - 1] = '\0'; + return ret; +} + + +/** + * "man basename" + * Returns a pointer to a part of filename (allocates nothing)! + * + * @param filename filename to extract basename from + * @return short (base) name of the file (that is, everything following the + * last directory separator in filename. If filename ends with a + * directory separator, the result will be a zero-length string. + * If filename has no directory separators, the result is filename + * itself. + */ +const char * +GNUNET_STRINGS_get_short_name (const char *filename) +{ + const char *short_fn = filename; + const char *ss; + while (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR)) + && (ss[1] != '\0')) + short_fn = 1 + ss; + return short_fn; +} + +/* end of strings.c */ diff --git a/src/util/test_bio.c b/src/util/test_bio.c new file mode 100644 index 0000000..9b18258 --- /dev/null +++ b/src/util/test_bio.c @@ -0,0 +1,417 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_bio.c + * @brief testcase for the buffered IO module + * @author Ji Lu + */ + + +#include "platform.h" +#include "gnunet_util_lib.h" +#define TESTSTRING "testString" +#define TESTNUMBER64 ((int64_t)100000L) + +static int +test_normal_rw () +{ + char *msg; + int64_t testNum; + char *readResultString; + char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); + struct GNUNET_BIO_WriteHandle *fileW; + struct GNUNET_BIO_ReadHandle *fileR; + struct GNUNET_CONTAINER_MetaData *metaDataW; + struct GNUNET_CONTAINER_MetaData *metaDataR; + + metaDataW = GNUNET_CONTAINER_meta_data_create (); + metaDataR = NULL; + GNUNET_CONTAINER_meta_data_add_publication_date (metaDataW); + + fileW = GNUNET_BIO_write_open (fileName); + GNUNET_assert (NULL != fileW); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, TESTSTRING)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_meta_data (fileW, metaDataW)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int64 (fileW, TESTNUMBER64)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); + + fileR = GNUNET_BIO_read_open (fileName); + GNUNET_assert (NULL != fileR); + readResultString = NULL; + GNUNET_assert (GNUNET_OK == + GNUNET_BIO_read_string (fileR, "Read string error", + &readResultString, 200)); + GNUNET_assert (NULL != readResultString); + GNUNET_assert (0 == strcmp (TESTSTRING, readResultString)); + GNUNET_free (readResultString); + GNUNET_assert (GNUNET_OK == + GNUNET_BIO_read_meta_data (fileR, "Read meta error", + &metaDataR)); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_meta_data_test_equal (metaDataR, metaDataW)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_int64 (fileR, &testNum)); + GNUNET_BIO_read_close (fileR, &msg); + GNUNET_CONTAINER_meta_data_destroy (metaDataW); + GNUNET_CONTAINER_meta_data_destroy (metaDataR); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); + GNUNET_free (fileName); + return 0; +} + +static int +test_nullstring_rw () +{ + char *msg; + char *readResultString = (char *) "not null"; + struct GNUNET_BIO_WriteHandle *fileW; + struct GNUNET_BIO_ReadHandle *fileR; + char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); + + fileW = GNUNET_BIO_write_open (fileName); + GNUNET_assert (NULL != fileW); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, NULL)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); + + fileR = GNUNET_BIO_read_open (fileName); + GNUNET_assert (NULL != fileR); + GNUNET_assert (GNUNET_OK == + GNUNET_BIO_read_string (fileR, "Read string error", + &readResultString, 200)); + GNUNET_assert (NULL == readResultString); + GNUNET_BIO_read_close (fileR, &msg); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); + GNUNET_free (fileName); + + return 0; +} + +static int +test_emptystring_rw () +{ + char *msg; + char *readResultString; + struct GNUNET_BIO_WriteHandle *fileW; + struct GNUNET_BIO_ReadHandle *fileR; + char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); + + fileW = GNUNET_BIO_write_open (fileName); + GNUNET_assert (NULL != fileW); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, "")); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); + + fileR = GNUNET_BIO_read_open (fileName); + GNUNET_assert (NULL != fileR); + readResultString = NULL; + GNUNET_assert (GNUNET_OK == + GNUNET_BIO_read_string (fileR, "Read string error", + &readResultString, 200)); + GNUNET_free (readResultString); + GNUNET_BIO_read_close (fileR, &msg); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); + GNUNET_free (fileName); + return 0; +} + +static int +test_bigstring_rw () +{ + char *msg; + char *readResultString; + struct GNUNET_BIO_WriteHandle *fileW; + struct GNUNET_BIO_ReadHandle *fileR; + char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); + + fileW = GNUNET_BIO_write_open (fileName); + GNUNET_assert (NULL != fileW); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, TESTSTRING)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); + + fileR = GNUNET_BIO_read_open (fileName); + GNUNET_assert (NULL != fileR); + readResultString = NULL; + GNUNET_assert (GNUNET_SYSERR == + GNUNET_BIO_read_string (fileR, "Read string error", + &readResultString, 1)); + GNUNET_assert (NULL == readResultString); + msg = NULL; + GNUNET_BIO_read_close (fileR, &msg); + GNUNET_free (msg); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); + GNUNET_free (fileName); + return 0; +} + +static int +test_bigmeta_rw () +{ + char *msg; + static char meta[1024 * 1024 * 10]; + struct GNUNET_BIO_WriteHandle *fileW; + struct GNUNET_BIO_ReadHandle *fileR; + char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); + struct GNUNET_CONTAINER_MetaData *metaDataR; + + memset (meta, 'b', sizeof (meta)); + meta[sizeof (meta) - 1] = '\0'; + fileW = GNUNET_BIO_write_open (fileName); + GNUNET_assert (NULL != fileW); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, sizeof (meta))); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write (fileW, meta, sizeof (meta))); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); + + fileR = GNUNET_BIO_read_open (fileName); + GNUNET_assert (NULL != fileR); + metaDataR = NULL; + GNUNET_assert (GNUNET_SYSERR == + GNUNET_BIO_read_meta_data (fileR, "Read meta error", + &metaDataR)); + msg = NULL; + GNUNET_BIO_read_close (fileR, &msg); + GNUNET_free (msg); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); + GNUNET_assert (NULL == metaDataR); + GNUNET_free (fileName); + return 0; +} + +static int +test_directory_r () +{ +#if LINUX + char *msg; + char readResult[200]; + struct GNUNET_BIO_ReadHandle *fileR; + + fileR = GNUNET_BIO_read_open ("/dev"); + GNUNET_assert (NULL != fileR); + GNUNET_assert (GNUNET_SYSERR == + GNUNET_BIO_read (fileR, "Read error", readResult, + sizeof (readResult))); + msg = NULL; + GNUNET_BIO_read_close (fileR, &msg); + GNUNET_free (msg); +#endif + return 0; +} + +static int +test_nullfile_rw () +{ + static char fileNameNO[102401]; + struct GNUNET_BIO_WriteHandle *fileWNO; + struct GNUNET_BIO_ReadHandle *fileRNO; + + memset (fileNameNO, 'a', sizeof (fileNameNO)); + fileNameNO[sizeof (fileNameNO) - 1] = '\0'; + + GNUNET_log_skip (1, GNUNET_NO); + fileWNO = GNUNET_BIO_write_open (fileNameNO); + GNUNET_log_skip (0, GNUNET_YES); + GNUNET_assert (NULL == fileWNO); + + GNUNET_log_skip (1, GNUNET_NO); + fileRNO = GNUNET_BIO_read_open (fileNameNO); + GNUNET_log_skip (0, GNUNET_YES); + GNUNET_assert (NULL == fileRNO); + return 0; +} + + +static int +test_fullfile_rw () +{ +#ifdef LINUX + /* /dev/full only seems to exist on Linux */ + char *msg; + int64_t testNum; + char *readResultString; + char readResult[200]; + struct GNUNET_BIO_WriteHandle *fileW; + struct GNUNET_BIO_ReadHandle *fileR; + struct GNUNET_CONTAINER_MetaData *metaDataW; + struct GNUNET_CONTAINER_MetaData *metaDataR; + + metaDataW = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_add_publication_date (metaDataW); + + fileW = GNUNET_BIO_write_open ("/dev/full"); + GNUNET_assert (NULL != fileW); + (void) GNUNET_BIO_write (fileW, TESTSTRING, strlen (TESTSTRING)); + (void) GNUNET_BIO_write_string (fileW, TESTSTRING); + (void) GNUNET_BIO_write_meta_data (fileW, metaDataW); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_write_close (fileW)); + GNUNET_CONTAINER_meta_data_destroy (metaDataW); + + fileW = GNUNET_BIO_write_open ("/dev/full"); + GNUNET_assert (NULL != fileW); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_write_close (fileW)); + + fileR = GNUNET_BIO_read_open ("/dev/null"); + GNUNET_assert (NULL != fileR); + GNUNET_assert (GNUNET_SYSERR == + GNUNET_BIO_read (fileR, "Read error", readResult, + sizeof (readResult))); + readResultString = NULL; + GNUNET_assert (GNUNET_SYSERR == + GNUNET_BIO_read_string (fileR, "Read string error", + &readResultString, 200)); + GNUNET_assert (NULL == readResultString); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_int64 (fileR, &testNum)); + metaDataR = NULL; + GNUNET_assert (GNUNET_SYSERR == + GNUNET_BIO_read_meta_data (fileR, "Read meta error", + &metaDataR)); + msg = NULL; + GNUNET_BIO_read_close (fileR, &msg); + GNUNET_free (msg); + GNUNET_assert (NULL == metaDataR); +#endif + return 0; +} + +static int +test_fakestring_rw () +{ + char *msg; + int32_t tmpInt = 2; + char *readResult; + struct GNUNET_BIO_WriteHandle *fileW; + struct GNUNET_BIO_ReadHandle *fileR; + char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); + + fileW = GNUNET_BIO_write_open (fileName); + GNUNET_assert (NULL != fileW); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, tmpInt)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); + + fileR = GNUNET_BIO_read_open (fileName); + GNUNET_assert (NULL != fileR); + GNUNET_assert (GNUNET_SYSERR == + GNUNET_BIO_read_string (fileR, "Read string error", + &readResult, 200)); + msg = NULL; + GNUNET_BIO_read_close (fileR, &msg); + GNUNET_free (msg); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); + GNUNET_free (fileName); + return 0; +} + +static int +test_fakemeta_rw () +{ + char *msg; + int32_t tmpInt = 2; + struct GNUNET_BIO_WriteHandle *fileW; + struct GNUNET_BIO_ReadHandle *fileR; + char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); + struct GNUNET_CONTAINER_MetaData *metaDataR; + + fileW = GNUNET_BIO_write_open (fileName); + GNUNET_assert (NULL != fileW); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, tmpInt)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); + + fileR = GNUNET_BIO_read_open (fileName); + GNUNET_assert (NULL != fileR); + metaDataR = NULL; + GNUNET_assert (GNUNET_SYSERR == + GNUNET_BIO_read_meta_data (fileR, "Read meta error", + &metaDataR)); + GNUNET_assert (NULL == metaDataR); + msg = NULL; + GNUNET_BIO_read_close (fileR, &msg); + GNUNET_free (msg); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); + GNUNET_free (fileName); + return 0; +} + +static int +test_fakebigmeta_rw () +{ + char *msg; + int32_t tmpInt = 1024 * 1024 * 10; + struct GNUNET_BIO_WriteHandle *fileW; + struct GNUNET_BIO_ReadHandle *fileR; + char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); + struct GNUNET_CONTAINER_MetaData *metaDataR; + + fileW = GNUNET_BIO_write_open (fileName); + GNUNET_assert (NULL != fileW); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, tmpInt)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); + + fileR = GNUNET_BIO_read_open (fileName); + GNUNET_assert (NULL != fileR); + metaDataR = NULL; + GNUNET_assert (GNUNET_SYSERR == + GNUNET_BIO_read_meta_data (fileR, "Read meta error", + &metaDataR)); + msg = NULL; + GNUNET_BIO_read_close (fileR, &msg); + GNUNET_free (msg); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); + GNUNET_assert (NULL == metaDataR); + GNUNET_free (fileName); + return 0; +} + +static int +check_string_rw () +{ + GNUNET_assert (0 == test_nullstring_rw ()); + GNUNET_assert (0 == test_emptystring_rw ()); + GNUNET_assert (0 == test_bigstring_rw ()); + GNUNET_assert (0 == test_fakestring_rw ()); + return 0; +} + +static int +check_metadata_rw () +{ + GNUNET_assert (0 == test_fakebigmeta_rw ()); + GNUNET_assert (0 == test_fakemeta_rw ()); + GNUNET_assert (0 == test_bigmeta_rw ()); + return 0; +} + +static int +check_file_rw () +{ + GNUNET_assert (0 == test_normal_rw ()); + GNUNET_assert (0 == test_nullfile_rw ()); + GNUNET_assert (0 == test_fullfile_rw ()); + GNUNET_assert (0 == test_directory_r ()); + return 0; +} + +int +main (int argc, char *argv[]) +{ + GNUNET_log_setup ("test-bio", "WARNING", NULL); + GNUNET_assert (0 == check_file_rw ()); + GNUNET_assert (0 == check_metadata_rw ()); + GNUNET_assert (0 == check_string_rw ()); + return 0; +} + +/* end of test_bio.c */ diff --git a/src/util/test_client.c b/src/util/test_client.c new file mode 100644 index 0000000..f9d961a --- /dev/null +++ b/src/util/test_client.c @@ -0,0 +1,210 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_client.c + * @brief tests for client.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_client_lib.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define PORT 14325 + +#define MYNAME "test_client" + +static struct GNUNET_CLIENT_Connection *client; + +static struct GNUNET_SERVER_Handle *server; + +static struct GNUNET_CONFIGURATION_Handle *cfg; + +#define MY_TYPE 130 + +struct CopyContext +{ + struct GNUNET_SERVER_Client *client; + struct GNUNET_MessageHeader *cpy; +}; + +static size_t +copy_msg (void *cls, size_t size, void *buf) +{ + struct CopyContext *ctx = cls; + struct GNUNET_MessageHeader *cpy = ctx->cpy; + + GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (cpy->size)); + GNUNET_assert (size >= ntohs (cpy->size)); + memcpy (buf, cpy, ntohs (cpy->size)); + GNUNET_SERVER_receive_done (ctx->client, GNUNET_OK); + GNUNET_free (cpy); + GNUNET_free (ctx); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message bounced back to client\n"); + return sizeof (struct GNUNET_MessageHeader); +} + + +/** + * Callback that just bounces the message back to the sender. + */ +static void +echo_cb (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct CopyContext *cc; + struct GNUNET_MessageHeader *cpy; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Receiving message from client, bouncing back\n"); + GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); + cc = GNUNET_malloc (sizeof (struct CopyContext)); + cc->client = client; + cpy = GNUNET_malloc (ntohs (message->size)); + memcpy (cpy, message, ntohs (message->size)); + cc->cpy = cpy; + GNUNET_assert (NULL != + GNUNET_SERVER_notify_transmit_ready (client, + ntohs (message->size), + GNUNET_TIME_UNIT_SECONDS, + ©_msg, cc)); +} + + +static struct GNUNET_SERVER_MessageHandler handlers[] = { + {&echo_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} +}; + + +static void +recv_bounce (void *cls, const struct GNUNET_MessageHeader *got) +{ + int *ok = cls; + struct GNUNET_MessageHeader msg; + + GNUNET_assert (got != NULL); /* timeout */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving bounce, checking content\n"); + msg.type = htons (MY_TYPE); + msg.size = htons (sizeof (struct GNUNET_MessageHeader)); + GNUNET_assert (0 == memcmp (got, &msg, sizeof (struct GNUNET_MessageHeader))); + GNUNET_CLIENT_disconnect (client, GNUNET_YES); + client = NULL; + GNUNET_SERVER_destroy (server); + server = NULL; + *ok = 0; +} + + +static size_t +make_msg (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg = buf; + + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + msg->type = htons (MY_TYPE); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating message for transmission\n"); + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct sockaddr_in sa; + struct sockaddr *sap[2]; + socklen_t slens[2]; + + sap[0] = (struct sockaddr *) &sa; + slens[0] = sizeof (sa); + sap[1] = NULL; + slens[1] = 0; + memset (&sa, 0, sizeof (sa)); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_family = AF_INET; + sa.sin_port = htons (PORT); + server = + GNUNET_SERVER_create (NULL, NULL, sap, slens, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 10000), GNUNET_NO); + GNUNET_assert (server != NULL); + handlers[0].callback_cls = cls; + handlers[1].callback_cls = cls; + GNUNET_SERVER_add_handlers (server, handlers); + client = GNUNET_CLIENT_connect (MYNAME, cfg); + GNUNET_assert (client != NULL); + GNUNET_assert (NULL != + GNUNET_CLIENT_notify_transmit_ready (client, + sizeof (struct + GNUNET_MessageHeader), + GNUNET_TIME_UNIT_SECONDS, + GNUNET_NO, &make_msg, + NULL)); + GNUNET_CLIENT_receive (client, &recv_bounce, cls, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 10000)); +} + + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check () +{ + int ok; + + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_number (cfg, MYNAME, "PORT", PORT); + GNUNET_CONFIGURATION_set_value_string (cfg, MYNAME, "HOSTNAME", "localhost"); + GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", + "localhost"); + ok = 1; + GNUNET_SCHEDULER_run (&task, &ok); + GNUNET_CONFIGURATION_destroy (cfg); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_client", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret += check (); + + return ret; +} + +/* end of test_client.c */ diff --git a/src/util/test_common_allocation.c b/src/util/test_common_allocation.c new file mode 100644 index 0000000..438d397 --- /dev/null +++ b/src/util/test_common_allocation.c @@ -0,0 +1,112 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_common_allocation.c + * @brief testcase for common_allocation.c + */ +#include "platform.h" +#include "gnunet_common.h" + +static int +check () +{ +#define MAX_TESTVAL 1024 + char *ptrs[MAX_TESTVAL]; + int i; + int j; + int k; + unsigned int ui; + + /* GNUNET_malloc/GNUNET_free test */ + k = 352; /* random start value */ + for (i = 1; i < MAX_TESTVAL; i++) + { + ptrs[i] = GNUNET_malloc (i); + for (j = 0; j < i; j++) + ptrs[i][j] = k++; + } + + for (i = MAX_TESTVAL - 1; i >= 1; i--) + { + for (j = i - 1; j >= 0; j--) + if (ptrs[i][j] != (char) --k) + return 1; + GNUNET_free (ptrs[i]); + } + + /* GNUNET_free_non_null test */ + GNUNET_free_non_null (NULL); + GNUNET_free_non_null (GNUNET_malloc (4)); + + /* GNUNET_strdup tests */ + ptrs[0] = GNUNET_strdup ("bar"); + if (0 != strcmp (ptrs[0], "bar")) + return 3; + /* now realloc */ + ptrs[0] = GNUNET_realloc (ptrs[0], 12); + strcpy (ptrs[0], "Hello World"); + + GNUNET_free (ptrs[0]); + GNUNET_asprintf (&ptrs[0], "%s %s", "Hello", "World"); + GNUNET_assert (strlen (ptrs[0]) == 11); + GNUNET_free (ptrs[0]); + + /* GNUNET_array_grow tests */ + ptrs[0] = NULL; + ui = 0; + GNUNET_array_grow (ptrs[0], ui, 42); + if (ui != 42) + return 4; + GNUNET_array_grow (ptrs[0], ui, 22); + if (ui != 22) + return 5; + for (j = 0; j < 22; j++) + ptrs[0][j] = j; + GNUNET_array_grow (ptrs[0], ui, 32); + for (j = 0; j < 22; j++) + if (ptrs[0][j] != j) + return 6; + for (j = 22; j < 32; j++) + if (ptrs[0][j] != 0) + return 7; + GNUNET_array_grow (ptrs[0], ui, 0); + if (i != 0) + return 8; + if (ptrs[0] != NULL) + return 9; + + + return 0; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-common-allocation", "WARNING", NULL); + ret = check (); + if (ret != 0) + FPRINTF (stderr, "ERROR %d.\n", ret); + return ret; +} + +/* end of test_common_allocation.c */ diff --git a/src/util/test_common_endian.c b/src/util/test_common_endian.c new file mode 100644 index 0000000..a709abe --- /dev/null +++ b/src/util/test_common_endian.c @@ -0,0 +1,42 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_common_endian.c + * @brief testcase for common_endian.c + */ +#include "platform.h" +#include "gnunet_common.h" + +#define CHECK(n) if (n != GNUNET_htonll(GNUNET_ntohll(n))) return 1; + +int +main (int argc, char *argv[]) +{ + GNUNET_log_setup ("test-common-endian", "WARNING", NULL); + CHECK (1); + CHECK (0x12345678); + CHECK (123456789012345LL); + if ((0x1234567890ABCDEFLL != GNUNET_htonll (0xEFCDAB9078563412LL)) && + 42 != htonl (42)) + return 1; + return 0; +} + +/* end of test_common_endian.c */ diff --git a/src/util/test_common_logging.c b/src/util/test_common_logging.c new file mode 100644 index 0000000..9345869 --- /dev/null +++ b/src/util/test_common_logging.c @@ -0,0 +1,99 @@ +/* + This file is part of GNUnet. + (C) 2008 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_common_logging.c + * @brief testcase for the logging module + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_common.h" + +static void +my_log (void *ctx, enum GNUNET_ErrorType kind, const char *component, + const char *date, const char *msg) +{ + unsigned int *c = ctx; + + (*c)++; +} + + + +int +main (int argc, char *argv[]) +{ + unsigned int failureCount = 0; + unsigned int logs = 0; + + if (0 != putenv ("GNUNET_FORCE_LOG=")) + FPRINTF (stderr, "Failed to putenv: %s\n", strerror (errno)); + GNUNET_log_setup ("test-common-logging", "DEBUG", "/dev/null"); + GNUNET_logger_add (&my_log, &logs); + GNUNET_logger_add (&my_log, &logs); + GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); + GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); + GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); + GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); + GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); + GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); + GNUNET_logger_remove (&my_log, &logs); + GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Flusher...\n"); + /* the last 6 calls should be merged (repated bulk messages!) */ + GNUNET_logger_remove (&my_log, &logs); + if (logs != 4) + { + FPRINTF (stdout, "Expected 4 log calls, got %u\n", logs); + failureCount++; + } + GNUNET_break (0 == + strcmp (_("ERROR"), + GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_ERROR))); + GNUNET_break (0 == + strcmp (_("WARNING"), + GNUNET_error_type_to_string + (GNUNET_ERROR_TYPE_WARNING))); + GNUNET_break (0 == + strcmp (_("INFO"), + GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_INFO))); + GNUNET_break (0 == + strcmp (_("DEBUG"), + GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_DEBUG))); + GNUNET_log_setup ("test_common_logging", "WARNING", "/dev/null"); + logs = 0; + GNUNET_logger_add (&my_log, &logs); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Checker...\n"); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Drop me...\n"); + GNUNET_logger_remove (&my_log, &logs); + if (logs != 1) + { + FPRINTF (stdout, "Expected 1 log call, got %u\n", logs); + failureCount++; + } + + if (failureCount != 0) + { + FPRINTF (stdout, "%u TESTS FAILED!\n", failureCount); + return -1; + } + return 0; +} /* end of main */ + +/* end of test_common_logging.c */ diff --git a/src/util/test_common_logging_dummy.c b/src/util/test_common_logging_dummy.c new file mode 100644 index 0000000..a1f4799 --- /dev/null +++ b/src/util/test_common_logging_dummy.c @@ -0,0 +1,98 @@ +/* + This file is part of GNUnet. + (C) 2008 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_common_logging_dummy.c + * @brief dummy labrat for the testcase for the logging module (runtime + * log level adjustment) + * @author LRN + */ +#include "platform.h" +#undef GNUNET_EXTRA_LOGGING +#define GNUNET_EXTRA_LOGGING GNUNET_YES + +#include "gnunet_common.h" +#include "gnunet_time_lib.h" +#include "gnunet_network_lib.h" + +/** + * Delay introduced between operations, useful for debugging. + */ +#define OUTPUT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 0) + +static void +my_log (void *ctx, enum GNUNET_ErrorType kind, const char *component, + const char *date, const char *msg) +{ + if (strncmp ("test-common-logging-dummy", component, 25) != 0) + return; + FPRINTF (stdout, "%s", msg); + fflush (stdout); +} + +static int +expensive_func () +{ + return GNUNET_NETWORK_socket_select (NULL, NULL, NULL, OUTPUT_DELAY); +} + +#define pr(kind,lvl) {\ + struct GNUNET_TIME_Absolute t1, t2;\ + t1 = GNUNET_TIME_absolute_get ();\ + GNUNET_log (kind, "L%s %d\n", lvl, expensive_func());\ + t2 = GNUNET_TIME_absolute_get ();\ + printf ("1%s %llu\n", lvl,\ + (unsigned long long) GNUNET_TIME_absolute_get_difference (t1, t2).rel_value); \ +} + +#define pr2(kind,lvl) {\ + struct GNUNET_TIME_Absolute t1, t2;\ + t1 = GNUNET_TIME_absolute_get ();\ + GNUNET_log (kind, "L%s %d\n", lvl, expensive_func());\ + t2 = GNUNET_TIME_absolute_get ();\ + printf ("2%s %llu\n", lvl,\ + (unsigned long long) GNUNET_TIME_absolute_get_difference (t1, t2).rel_value); \ +} + +int +main (int argc, char *argv[]) +{ + /* We set up logging with NULL level - will be overrided by + * GNUNET_LOG or GNUNET_FORCE_LOG at runtime. + */ + GNUNET_log_setup ("test-common-logging-dummy", NULL, "/dev/null"); + GNUNET_logger_add (&my_log, NULL); + pr (GNUNET_ERROR_TYPE_ERROR, "ERROR"); + pr (GNUNET_ERROR_TYPE_WARNING, "WARNING"); + pr (GNUNET_ERROR_TYPE_INFO, "INFO"); + pr (GNUNET_ERROR_TYPE_DEBUG, "DEBUG"); + + /* We set up logging with WARNING level - will onle be overrided by + * GNUNET_FORCE_LOG at runtime. + */ + GNUNET_log_setup ("test-common-logging-dummy", "WARNING", "/dev/null"); + pr2 (GNUNET_ERROR_TYPE_ERROR, "ERROR"); + pr2 (GNUNET_ERROR_TYPE_WARNING, "WARNING"); + pr2 (GNUNET_ERROR_TYPE_INFO, "INFO"); + pr2 (GNUNET_ERROR_TYPE_DEBUG, "DEBUG"); + return 0; +} /* end of main */ + +/* end of test_common_logging_dummy.c */ diff --git a/src/util/test_common_logging_runtime_loglevels.c b/src/util/test_common_logging_runtime_loglevels.c new file mode 100644 index 0000000..cdf1f66 --- /dev/null +++ b/src/util/test_common_logging_runtime_loglevels.c @@ -0,0 +1,384 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_common_logging_runtime_loglevels.c + * @brief testcase for the logging module (runtime log level adjustment) + * @author LRN + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_network_lib.h" +#include "gnunet_disk_lib.h" +#include "gnunet_os_lib.h" + +#define VERBOSE GNUNET_NO + +static int ok; +static int phase = 0; + +static struct GNUNET_OS_Process *proc; + +/* Pipe to read from started processes stdout (on read end) */ +static struct GNUNET_DISK_PipeHandle *pipe_stdout; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static void +runone (void); + +static void +end_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending phase %d, ok is %d\n", phase, + ok); + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; + GNUNET_DISK_pipe_close (pipe_stdout); + if (ok == 1) + { + if (phase < 9) + { + phase += 1; + runone (); + } + else + ok = 0; + } + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failing\n"); +} + +static char * +read_output_line (int phase_from1, int phase_to1, int phase_from2, + int phase_to2, char c, char *expect_level, + long delay_morethan, long delay_lessthan, int phase, char *p, + int *len, long *delay, char level[8]) +{ + char *r = p; + char t[7]; + int i, j, stop = 0; + + j = 0; + int stage = 0; + + if (!(phase >= phase_from1 && phase <= phase_to1) && + !(phase >= phase_from2 && phase <= phase_to2)) + return p; +#if 0 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying to match '%c%s \\d\\r\\n' on %s\n", c, expect_level, p); +#endif + for (i = 0; i < *len && !stop; i++) + { + switch (stage) + { + case 0: /* read first char */ + if (r[i] != c) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected '%c', but got '%c'\n", c, + r[i]); + GNUNET_break (0); + return NULL; + } + stage += 1; + break; + case 1: /* read at most 7 char-long error level string, finished by ' ' */ + if (r[i] == ' ') + { + level[j] = '\0'; + stage += 1; + j = 0; + } + else if (i == 8) + { + GNUNET_break (0); + ok = 2; + return NULL; + } + else + level[j++] = r[i]; + break; + case 2: /* read the delay, finished by '\n' */ + t[j++] = r[i]; +#if WINDOWS + if (r[i] == '\r' && r[i + 1] == '\n') + { + i += 1; + t[j - 1] = '\0'; + *delay = strtol (t, NULL, 10); + stop = 1; + } +#else + if (r[i] == '\n') + { + t[j - 1] = '\0'; + *delay = strtol (t, NULL, 10); + stop = 1; + } +#endif + break; + } + } + if (!stop || strcmp (expect_level, level) != 0 || *delay < 0 || *delay > 1000 + || (!((*delay < delay_lessthan) || !(*delay > delay_morethan)) && c != '1' + && c != '2')) + return NULL; + *len = *len - i; + return &r[i]; +} + +char buf[20 * 16]; +char *buf_ptr; +int bytes; + +static void +read_call (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_DISK_FileHandle *stdout_read_handle = cls; + char level[8]; + long delay; + long delays[8]; + int rd; + + rd = GNUNET_DISK_file_read (stdout_read_handle, buf_ptr, + sizeof (buf) - bytes); + if (rd > 0) + { + buf_ptr += rd; + bytes += rd; +#if VERBOSE + FPRINTF (stderr, "got %d bytes, reading more\n", rd); +#endif + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdout_read_handle, &read_call, + (void *) stdout_read_handle); + return; + } + +#if VERBOSE + FPRINTF (stderr, "bytes is %d:%s\n", bytes, buf); +#endif + + /* +------CHILD OUTPUT-- + * | SOFT HARD + * | E W I D E W I D + * | 0E * * * + * | 1W * * * * + * P 2I * * * * * + * H 3D * * * * * * + * A + * S 4E * * + * E 5W * * * * + * | 6I * * * * * * + * | 7D * * * * * * * * + * | 8 * * * * + * | 9 * * * * + */ + char *p = buf; + + if (bytes == 20 * 16 || + !(p = + read_output_line (0, 3, 4, 9, 'L', "ERROR", -1, 1, phase, p, &bytes, + &delay, level)) || + !(p = + read_output_line (0, 3, 4, 9, '1', "ERROR", 200, 400, phase, p, &bytes, + &delays[0], level)) || + !(p = + read_output_line (1, 3, 5, 9, 'L', "WARNING", -1, 1, phase, p, &bytes, + &delay, level)) || + !(p = + read_output_line (0, 3, 4, 9, '1', "WARNING", 200, 400, phase, p, + &bytes, &delays[1], level)) || + !(p = + read_output_line (2, 3, 6, 7, 'L', "INFO", -1, 1, phase, p, &bytes, + &delay, level)) || + !(p = + read_output_line (0, 3, 4, 9, '1', "INFO", 200, 400, phase, p, &bytes, + &delays[2], level)) || + !(p = + read_output_line (3, 3, 7, 7, 'L', "DEBUG", -1, 1, phase, p, &bytes, + &delay, level)) || + !(p = + read_output_line (0, 3, 4, 9, '1', "DEBUG", 200, 400, phase, p, &bytes, + &delays[3], level)) || + !(p = + read_output_line (0, 3, 4, 9, 'L', "ERROR", -1, 1, phase, p, &bytes, + &delay, level)) || + !(p = + read_output_line (0, 3, 4, 9, '2', "ERROR", 200, 400, phase, p, &bytes, + &delays[4], level)) || + !(p = + read_output_line (0, 3, 5, 9, 'L', "WARNING", -1, 1, phase, p, &bytes, + &delay, level)) || + !(p = + read_output_line (0, 3, 4, 9, '2', "WARNING", 200, 400, phase, p, + &bytes, &delays[5], level)) || + !(p = + read_output_line (-1, -1, 6, 7, 'L', "INFO", -1, 1, phase, p, &bytes, + &delay, level)) || + !(p = + read_output_line (0, 3, 4, 9, '2', "INFO", 200, 400, phase, p, &bytes, + &delays[6], level)) || + !(p = + read_output_line (-1, -1, 7, 7, 'L', "DEBUG", -1, 1, phase, p, &bytes, + &delay, level)) || + !(p = + read_output_line (0, 3, 4, 9, '2', "DEBUG", 200, 400, phase, p, &bytes, + &delays[7], level))) + { + if (bytes == 20 * 16) + FPRINTF (stderr, "%s", "Ran out of buffer space!\n"); + GNUNET_break (0); + ok = 2; + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_task, NULL); + return; + } + + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_task, NULL); +} + +static void +runone () +{ + const struct GNUNET_DISK_FileHandle *stdout_read_handle; + + pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); + + if (pipe_stdout == NULL) + { + GNUNET_break (0); + ok = 2; + return; + } + + putenv ("GNUNET_LOG="); + putenv ("GNUNET_FORCE_LOG="); + putenv ("GNUNET_FORCE_LOGFILE="); + switch (phase) + { + case 0: + putenv ("GNUNET_LOG=;;;;ERROR"); + break; + case 1: + putenv ("GNUNET_LOG=;;;;WARNING"); + break; + case 2: + putenv ("GNUNET_LOG=;;;;INFO"); + break; + case 3: + putenv ("GNUNET_LOG=;;;;DEBUG"); + break; + case 4: + putenv ("GNUNET_FORCE_LOG=;;;;ERROR"); + break; + case 5: + putenv ("GNUNET_FORCE_LOG=;;;;WARNING"); + break; + case 6: + putenv ("GNUNET_FORCE_LOG=;;;;INFO"); + break; + case 7: + putenv ("GNUNET_FORCE_LOG=;;;;DEBUG"); + break; + case 8: + putenv ("GNUNET_LOG=blah;;;;ERROR"); + break; + case 9: + putenv ("GNUNET_FORCE_LOG=blah;;;;ERROR"); + break; + } + + proc = GNUNET_OS_start_process (GNUNET_NO, NULL, pipe_stdout, +#if MINGW + "test_common_logging_dummy", +#else + "./test_common_logging_dummy", +#endif + "test_common_logging_dummy", NULL); + putenv ("GNUNET_FORCE_LOG="); + putenv ("GNUNET_LOG="); + + /* Close the write end of the read pipe */ + GNUNET_DISK_pipe_close_end (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); + + stdout_read_handle = + GNUNET_DISK_pipe_handle (pipe_stdout, GNUNET_DISK_PIPE_END_READ); + + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 10), &end_task, + NULL); + + bytes = 0; + buf_ptr = buf; + memset (&buf, 0, sizeof (buf)); + + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdout_read_handle, &read_call, + (void *) stdout_read_handle); +} + +static void +task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + phase = 0; + runone (); +} + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check () +{ + ok = 1; + GNUNET_SCHEDULER_run (&task, &ok); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-common-logging-runtime-loglevels", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + return ret; +} + +/* end of test_common_logging_runtime_loglevels.c */ diff --git a/src/util/test_configuration.c b/src/util/test_configuration.c new file mode 100644 index 0000000..b1a446f --- /dev/null +++ b/src/util/test_configuration.c @@ -0,0 +1,553 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2005, 2006, 2007 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_configuration.c + * @brief Test that the configuration module works. + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_disk_lib.h" + +#define DEBUG GNUNET_EXTRA_LOGGING + +/* Test Configuration Diffs Options */ +enum +{ + EDIT_NOTHING, + EDIT_SECTION, + EDIT_ALL, + ADD_NEW_SECTION, + ADD_NEW_ENTRY, + REMOVE_SECTION, + REMOVE_ENTRY, + COMPARE +#if DEBUG + , PRINT +#endif +}; + +static struct GNUNET_CONFIGURATION_Handle *cfg; +static struct GNUNET_CONFIGURATION_Handle *cfgDefault; + +struct DiffsCBData +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_CONFIGURATION_Handle *cfgDiffs; + const char *section; + int callBackOption; + int status; +}; + + +static void +initDiffsCBData (struct DiffsCBData *cbData) +{ + cbData->section = NULL; + cbData->cfg = NULL; + cbData->cfgDiffs = NULL; + cbData->callBackOption = -1; + cbData->status = 0; +} + + +/** + * callback function for modifying + * and comparing configuration +*/ +static void +diffsCallBack (void *cls, const char *section, const char *option, + const char *value) +{ + struct DiffsCBData *cbData = cls; + int cbOption = cbData->callBackOption; + + switch (cbOption) + { + case EDIT_SECTION: + if (NULL == cbData->section) + cbData->section = section; + if (strcmp (cbData->section, section) == 0) + { + GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, option, + "new-value"); + GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section, option, + "new-value"); + } + break; + case EDIT_ALL: + GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, option, + "new-value"); + GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section, option, + "new-value"); + break; + case ADD_NEW_ENTRY: + { + static int hit = 0; + + if (hit == 0) + { + hit = 1; + GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, "new-key", + "new-value"); + GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section, + "new-key", "new-value"); + } + break; + } + case COMPARE: + { + int ret; + char *diffValue; + + diffValue = NULL; + ret = + GNUNET_CONFIGURATION_get_value_string (cbData->cfgDiffs, section, + option, &diffValue); + if (NULL != diffValue) + { + if (ret == GNUNET_SYSERR || strcmp (diffValue, value) != 0) + cbData->status = 1; + } + else + cbData->status = 1; + GNUNET_free_non_null (diffValue); + break; + } +#if 0 + case PRINT: + if (NULL == cbData->section) + { + cbData->section = section; + printf ("\nSection: %s\n", section); + } + else if (strcmp (cbData->section, section) != 0) + { + cbData->section = section; + printf ("\nSection: %s\n", section); + } + printf ("%s = %s\n", option, value); +#endif + default: + break; + } +} + + +static struct GNUNET_CONFIGURATION_Handle * +editConfiguration (struct GNUNET_CONFIGURATION_Handle *cfg, int option) +{ + struct DiffsCBData diffsCB; + + initDiffsCBData (&diffsCB); + diffsCB.cfgDiffs = GNUNET_CONFIGURATION_create (); + + switch (option) + { + case EDIT_SECTION: + case EDIT_ALL: + case ADD_NEW_ENTRY: + diffsCB.callBackOption = option; + diffsCB.cfg = cfg; + GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &diffsCB); + break; + case EDIT_NOTHING: + /* Do nothing */ + break; + case ADD_NEW_SECTION: + { + int i; + char *key; + + for (i = 0; i < 5; i++) + { + GNUNET_asprintf (&key, "key%d", i); + GNUNET_CONFIGURATION_set_value_string (cfg, "new-section", key, + "new-value"); + GNUNET_CONFIGURATION_set_value_string (diffsCB.cfgDiffs, "new-section", + key, "new-value"); + GNUNET_free (key); + } + break; + } + case REMOVE_SECTION: + break; + case REMOVE_ENTRY: + break; + default: + break; + } + + return diffsCB.cfgDiffs; +} + +/** + * Checking configuration diffs + */ +static int +checkDiffs (struct GNUNET_CONFIGURATION_Handle *cfgDefault, int option) +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_CONFIGURATION_Handle *cfgDiffs; + struct DiffsCBData cbData; + int ret; + char *diffsFileName; + + initDiffsCBData (&cbData); + + cfg = GNUNET_CONFIGURATION_create (); + /* load defaults */ + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (cfg, NULL)); + + /* Modify configuration and save it */ + cfgDiffs = editConfiguration (cfg, option); + diffsFileName = GNUNET_DISK_mktemp ("gnunet-test-configurations-diffs.conf"); + if (diffsFileName == NULL) + { + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_CONFIGURATION_destroy (cfgDiffs); + return 1; + } + GNUNET_CONFIGURATION_write_diffs (cfgDefault, cfg, diffsFileName); + GNUNET_CONFIGURATION_destroy (cfg); + + /* Compare the dumped configuration with modifications done */ + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, diffsFileName)); + remove (diffsFileName); + cbData.callBackOption = COMPARE; + cbData.cfgDiffs = cfgDiffs; + GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &cbData); + if (1 == (ret = cbData.status)) + { + FPRINTF (stderr, "%s", + "Incorrect Configuration Diffs: Diffs may contain data not actually edited\n"); + goto housekeeping; + } + cbData.cfgDiffs = cfg; + GNUNET_CONFIGURATION_iterate (cfgDiffs, diffsCallBack, &cbData); + if ((ret = cbData.status) == 1) + FPRINTF (stderr, "%s", + "Incorrect Configuration Diffs: Data may be missing in diffs\n"); + +housekeeping: +#if 0 + cbData.section = NULL; + cbData.callBackOption = PRINT; + printf ("\nExpected Diffs:\n"); + GNUNET_CONFIGURATION_iterate (cfgDiffs, diffsCallBack, &cbData); + cbData.section = NULL; + printf ("\nActual Diffs:\n"); + GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &cbData); +#endif + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_CONFIGURATION_destroy (cfgDiffs); + GNUNET_free (diffsFileName); + return ret; +} + + +static int +testConfig () +{ + char *c; + unsigned long long l; + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "test", "b", &c)) + return 1; + if (0 != strcmp ("b", c)) + { + FPRINTF (stderr, "Got `%s'\n", c); + GNUNET_free (c); + return 2; + } + GNUNET_free (c); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "test", "five", &l)) + { + GNUNET_break (0); + return 3; + } + if (5 != l) + { + GNUNET_break (0); + return 4; + } + GNUNET_CONFIGURATION_set_value_string (cfg, "more", "c", "YES"); + if (GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno (cfg, "more", "c")) + { + GNUNET_break (0); + return 5; + } + GNUNET_CONFIGURATION_set_value_number (cfg, "NUMBERS", "TEN", 10); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "NUMBERS", "TEN", &c)) + { + GNUNET_break (0); + return 6; + } + if (0 != strcmp (c, "10")) + { + GNUNET_free (c); + GNUNET_break (0); + return 7; + } + GNUNET_free (c); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "last", "test", &c)) + { + GNUNET_break (0); + return 8; + } +#ifndef MINGW + if (0 != strcmp (c, "/hello/world")) +#else +#define HI "\\hello\\world" + if (strstr (c, HI) != c + strlen (c) - strlen (HI)) +#endif + { + GNUNET_break (0); + GNUNET_free (c); + return 9; + } + GNUNET_free (c); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_size (cfg, "last", "size", &l)) + { + GNUNET_break (0); + return 10; + } + if (l != 512 * 1024) + { + GNUNET_break (0); + return 11; + } + return 0; +} + +static const char *want[] = { + "/Hello", + "/File Name", + "/World", + NULL, + NULL, +}; + +static int +check (void *data, const char *fn) +{ + int *idx = data; + + if (0 == strcmp (want[*idx], fn)) + { + (*idx)++; + return GNUNET_OK; + } + GNUNET_break (0); + return GNUNET_SYSERR; +} + +static int +testConfigFilenames () +{ + int idx; + + idx = 0; + if (3 != + GNUNET_CONFIGURATION_iterate_value_filenames (cfg, "FILENAMES", "test", + &check, &idx)) + { + GNUNET_break (0); + return 8; + } + if (idx != 3) + return 16; + if (GNUNET_OK != + GNUNET_CONFIGURATION_remove_value_filename (cfg, "FILENAMES", "test", + "/File Name")) + { + GNUNET_break (0); + return 24; + } + + if (GNUNET_NO != + GNUNET_CONFIGURATION_remove_value_filename (cfg, "FILENAMES", "test", + "/File Name")) + { + GNUNET_break (0); + return 32; + } + if (GNUNET_NO != + GNUNET_CONFIGURATION_remove_value_filename (cfg, "FILENAMES", "test", + "Stuff")) + { + GNUNET_break (0); + return 40; + } + + if (GNUNET_NO != + GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test", + "/Hello")) + { + GNUNET_break (0); + return 48; + } + if (GNUNET_NO != + GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test", + "/World")) + { + GNUNET_break (0); + return 56; + } + + if (GNUNET_YES != + GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test", + "/File 1")) + { + GNUNET_break (0); + return 64; + } + + if (GNUNET_YES != + GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test", + "/File 2")) + { + GNUNET_break (0); + return 72; + } + + idx = 0; + want[1] = "/World"; + want[2] = "/File 1"; + want[3] = "/File 2"; + if (4 != + GNUNET_CONFIGURATION_iterate_value_filenames (cfg, "FILENAMES", "test", + &check, &idx)) + { + GNUNET_break (0); + return 80; + } + if (idx != 4) + { + GNUNET_break (0); + return 88; + } + return 0; +} + + +int +main (int argc, char *argv[]) +{ + int failureCount = 0; + char *c; + + GNUNET_log_setup ("test_configuration", "WARNING", NULL); + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_assert (cfg != NULL); + if (GNUNET_OK != + GNUNET_CONFIGURATION_parse (cfg, "test_configuration_data.conf")) + { + FPRINTF (stderr, "%s", "Failed to parse configuration file\n"); + GNUNET_CONFIGURATION_destroy (cfg); + return 1; + } + failureCount += testConfig (); + if (failureCount > 0) + goto error; + + failureCount = testConfigFilenames (); + if (failureCount > 0) + goto error; + + if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, "/tmp/gnunet-test.conf")) + { + FPRINTF (stderr, "%s", "Failed to write configuration file\n"); + GNUNET_CONFIGURATION_destroy (cfg); + return 1; + } + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_assert (0 == UNLINK ("/tmp/gnunet-test.conf")); + + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_load (cfg, "test_configuration_data.conf")) + { + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfg); + return 1; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "WEAKRANDOM", &c)) + { + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfg); + return 1; + } + if (0 != strcmp (c, "YES")) + { + GNUNET_break (0); + GNUNET_free (c); + GNUNET_CONFIGURATION_destroy (cfg); + return 1; + } + + GNUNET_free (c); + GNUNET_CONFIGURATION_destroy (cfg); + + /* Testing configuration diffs */ + cfgDefault = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfgDefault, NULL)) + { + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfgDefault); + return 1; + } + + /* Nothing changed in the new configuration */ + failureCount += checkDiffs (cfgDefault, EDIT_NOTHING); + + /* Modify all entries of the last section */ + failureCount += checkDiffs (cfgDefault, EDIT_SECTION); + + /* Add a new section */ + failureCount += checkDiffs (cfgDefault, ADD_NEW_SECTION); + + /* Add a new entry to the last section */ + failureCount += checkDiffs (cfgDefault, ADD_NEW_ENTRY); + + /* Modify all entries in the configuration */ + failureCount += checkDiffs (cfgDefault, EDIT_ALL); + + GNUNET_CONFIGURATION_destroy (cfgDefault); + +error: + if (failureCount != 0) + { + FPRINTF (stderr, "Test failed: %u\n", failureCount); + return 1; + } + return 0; +} diff --git a/src/util/test_configuration_data.conf b/src/util/test_configuration_data.conf new file mode 100644 index 0000000..517cbf0 --- /dev/null +++ b/src/util/test_configuration_data.conf @@ -0,0 +1,30 @@ +[PATHS] +SUBST=/hello + +[GNUNET] +SUBST=hello +GNUNET_HOME=/tmp + +[test] +a=a +b=b +five=5 + +[more] +c=c +five=42 + + +[last] +test = $SUBST/world +boom = "1 2 3 testing" +trailing = YES +size = 512 KiB + +[FILENAMES] +test = "/Hello /File\ Name /World" + + +[TESTING] +WEAKRANDOM = YES + diff --git a/src/util/test_connection.c b/src/util/test_connection.c new file mode 100644 index 0000000..cb69f40 --- /dev/null +++ b/src/util/test_connection.c @@ -0,0 +1,208 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_connection.c + * @brief tests for connection.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define PORT 12435 + + +static struct GNUNET_CONNECTION_Handle *csock; + +static struct GNUNET_CONNECTION_Handle *asock; + +static struct GNUNET_CONNECTION_Handle *lsock; + +static size_t sofar; + +static struct GNUNET_NETWORK_Handle *ls; + +static struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Create and initialize a listen socket for the server. + * + * @return -1 on error, otherwise the listen socket + */ +static struct GNUNET_NETWORK_Handle * +open_listen_socket () +{ + const static int on = 1; + struct sockaddr_in sa; + struct GNUNET_NETWORK_Handle *desc; + + memset (&sa, 0, sizeof (sa)); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_port = htons (PORT); + sa.sin_family = AF_INET; + desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); + GNUNET_assert (desc != NULL); + if (GNUNET_NETWORK_socket_setsockopt + (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); + GNUNET_assert (GNUNET_NETWORK_socket_bind + (desc, (const struct sockaddr *) &sa, + sizeof (sa)) == GNUNET_OK); + GNUNET_NETWORK_socket_listen (desc, 5); + return desc; +} + +static void +receive_check (void *cls, const void *buf, size_t available, + const struct sockaddr *addr, socklen_t addrlen, int errCode) +{ + int *ok = cls; + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive validates incoming data\n"); +#endif + GNUNET_assert (buf != NULL); /* no timeout */ + if (0 == memcmp (&"Hello World"[sofar], buf, available)) + sofar += available; + if (sofar < 12) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive needs more data\n"); +#endif + GNUNET_CONNECTION_receive (asock, 1024, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, + cls); + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive closes accepted socket\n"); +#endif + *ok = 0; + GNUNET_CONNECTION_destroy (asock, GNUNET_YES); + } +} + + +static void +run_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test accepts connection\n"); +#endif + asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls); + GNUNET_assert (asock != NULL); + GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys listen socket\n"); +#endif + GNUNET_CONNECTION_destroy (lsock, GNUNET_YES); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test asks to receive on accepted socket\n"); +#endif + GNUNET_CONNECTION_receive (asock, 1024, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, + cls); +} + +static size_t +make_hello (void *cls, size_t size, void *buf) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Test prepares to transmit on connect socket\n"); +#endif + GNUNET_assert (size >= 12); + strcpy ((char *) buf, "Hello World"); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys client socket\n"); +#endif + GNUNET_CONNECTION_destroy (csock, GNUNET_YES); + return 12; +} + +static void +task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + ls = open_listen_socket (); + lsock = GNUNET_CONNECTION_create_from_existing (ls); + GNUNET_assert (lsock != NULL); + csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); + GNUNET_assert (csock != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks for write notification\n"); +#endif + GNUNET_assert (NULL != + GNUNET_CONNECTION_notify_transmit_ready (csock, 12, + GNUNET_TIME_UNIT_SECONDS, + &make_hello, NULL)); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test prepares to accept\n"); +#endif + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept, + cls); +} + + +/** + * Main method, starts scheduler with task , + * checks that "ok" is correct at the end. + */ +static int +check () +{ + int ok; + + ok = 1; + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", + "localhost"); + GNUNET_SCHEDULER_run (&task, &ok); + GNUNET_CONFIGURATION_destroy (cfg); + return ok; +} + + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_connection", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret += check (); + return ret; +} + +/* end of test_connection.c */ diff --git a/src/util/test_connection_addressing.c b/src/util/test_connection_addressing.c new file mode 100644 index 0000000..2d08acc --- /dev/null +++ b/src/util/test_connection_addressing.c @@ -0,0 +1,208 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_connection_addressing.c + * @brief tests for connection.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define PORT 12435 + + +static struct GNUNET_CONNECTION_Handle *csock; + +static struct GNUNET_CONNECTION_Handle *asock; + +static struct GNUNET_CONNECTION_Handle *lsock; + +static size_t sofar; + +static struct GNUNET_NETWORK_Handle *ls; + + + +/** + * Create and initialize a listen socket for the server. + * + * @return NULL on error, otherwise the listen socket + */ +static struct GNUNET_NETWORK_Handle * +open_listen_socket () +{ + const static int on = 1; + struct sockaddr_in sa; + struct GNUNET_NETWORK_Handle *desc; + + memset (&sa, 0, sizeof (sa)); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_family = AF_INET; + sa.sin_port = htons (PORT); + desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); + GNUNET_assert (desc != 0); + if (GNUNET_NETWORK_socket_setsockopt + (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); + if (GNUNET_OK != + GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa, + sizeof (sa))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "bind"); + GNUNET_assert (0); + } + GNUNET_NETWORK_socket_listen (desc, 5); + return desc; +} + + +static void +receive_check (void *cls, const void *buf, size_t available, + const struct sockaddr *addr, socklen_t addrlen, int errCode) +{ + int *ok = cls; + + GNUNET_assert (buf != NULL); /* no timeout */ + if (0 == memcmp (&"Hello World"[sofar], buf, available)) + sofar += available; + if (sofar < 12) + { + GNUNET_CONNECTION_receive (asock, 1024, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, + cls); + } + else + { + *ok = 0; + GNUNET_CONNECTION_destroy (asock, GNUNET_YES); + } +} + + +static void +run_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + void *addr; + size_t alen; + struct sockaddr_in *v4; + struct sockaddr_in expect; + + asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls); + GNUNET_assert (asock != NULL); + GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONNECTION_get_address (asock, &addr, &alen)); + GNUNET_assert (alen == sizeof (struct sockaddr_in)); + v4 = addr; + memset (&expect, 0, sizeof (expect)); +#if HAVE_SOCKADDR_IN_SIN_LEN + expect.sin_len = sizeof (expect); +#endif + expect.sin_family = AF_INET; + expect.sin_port = v4->sin_port; + expect.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + GNUNET_assert (0 == memcmp (&expect, v4, alen)); + GNUNET_free (addr); + GNUNET_CONNECTION_destroy (lsock, GNUNET_YES); + GNUNET_CONNECTION_receive (asock, 1024, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, + cls); +} + +static size_t +make_hello (void *cls, size_t size, void *buf) +{ + GNUNET_assert (size >= 12); + strcpy ((char *) buf, "Hello World"); + return 12; +} + +static void +task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct sockaddr_in v4; + + ls = open_listen_socket (); + lsock = GNUNET_CONNECTION_create_from_existing (ls); + GNUNET_assert (lsock != NULL); + +#if HAVE_SOCKADDR_IN_SIN_LEN + v4.sin_len = sizeof (v4); +#endif + v4.sin_family = AF_INET; + v4.sin_port = htons (PORT); + v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + csock = + GNUNET_CONNECTION_create_from_sockaddr (AF_INET, + (const struct sockaddr *) &v4, + sizeof (v4)); + GNUNET_assert (csock != NULL); + GNUNET_assert (NULL != + GNUNET_CONNECTION_notify_transmit_ready (csock, 12, + GNUNET_TIME_UNIT_SECONDS, + &make_hello, NULL)); + GNUNET_CONNECTION_destroy (csock, GNUNET_YES); + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept, + cls); +} + + +/** + * Main method, starts scheduler with task , + * checks that "ok" is correct at the end. + */ +static int +check () +{ + int ok; + + ok = 1; + GNUNET_SCHEDULER_run (&task, &ok); + return ok; +} + + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_connection_addressing", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret += check (); + return ret; +} + +/* end of test_connection_addressing.c */ diff --git a/src/util/test_connection_receive_cancel.c b/src/util/test_connection_receive_cancel.c new file mode 100644 index 0000000..aa16724 --- /dev/null +++ b/src/util/test_connection_receive_cancel.c @@ -0,0 +1,158 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_connection_receive_cancel.c + * @brief tests for connection.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define PORT 12435 + + +static struct GNUNET_CONNECTION_Handle *csock; + +static struct GNUNET_CONNECTION_Handle *asock; + +static struct GNUNET_CONNECTION_Handle *lsock; + +static struct GNUNET_NETWORK_Handle *ls; + +static struct GNUNET_CONFIGURATION_Handle *cfg; + + +/** + * Create and initialize a listen socket for the server. + * + * @return NULL on error, otherwise the listen socket + */ +static struct GNUNET_NETWORK_Handle * +open_listen_socket () +{ + const static int on = 1; + struct sockaddr_in sa; + struct GNUNET_NETWORK_Handle *desc; + + memset (&sa, 0, sizeof (sa)); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_family = AF_INET; + sa.sin_port = htons (PORT); + desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); + GNUNET_assert (desc != NULL); + if (GNUNET_NETWORK_socket_setsockopt + (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); + GNUNET_assert (GNUNET_NETWORK_socket_bind + (desc, (const struct sockaddr *) &sa, + sizeof (sa)) == GNUNET_OK); + GNUNET_NETWORK_socket_listen (desc, 5); + return desc; +} + + + +static void +dead_receive (void *cls, const void *buf, size_t available, + const struct sockaddr *addr, socklen_t addrlen, int errCode) +{ + GNUNET_assert (0); +} + + +static void +run_accept_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls); + GNUNET_assert (asock != NULL); + GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); + GNUNET_CONNECTION_destroy (lsock, GNUNET_YES); + GNUNET_CONNECTION_receive (asock, 1024, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 5), &dead_receive, cls); +} + + +static void +receive_cancel_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + + GNUNET_CONNECTION_receive_cancel (asock); + GNUNET_CONNECTION_destroy (csock, GNUNET_YES); + GNUNET_CONNECTION_destroy (asock, GNUNET_YES); + *ok = 0; +} + + + +static void +task_receive_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + ls = open_listen_socket (); + lsock = GNUNET_CONNECTION_create_from_existing (ls); + GNUNET_assert (lsock != NULL); + csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); + GNUNET_assert (csock != NULL); + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, + &run_accept_cancel, cls); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &receive_cancel_task, + cls); +} + + + +/** + * Main method, starts scheduler with task_timeout. + */ +static int +check_receive_cancel () +{ + int ok; + + ok = 1; + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", + "localhost"); + GNUNET_SCHEDULER_run (&task_receive_cancel, &ok); + GNUNET_CONFIGURATION_destroy (cfg); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_connection_receive_cancel", "WARNING", NULL); + ret += check_receive_cancel (); + + return ret; +} + +/* end of test_connection_receive_cancel.c */ diff --git a/src/util/test_connection_timeout.c b/src/util/test_connection_timeout.c new file mode 100644 index 0000000..2338665 --- /dev/null +++ b/src/util/test_connection_timeout.c @@ -0,0 +1,154 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_connection_timeout.c + * @brief tests for connection.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define PORT 12435 + +static struct GNUNET_CONNECTION_Handle *csock; + +static struct GNUNET_CONNECTION_Handle *lsock; + +static struct GNUNET_NETWORK_Handle *ls; + +static struct GNUNET_CONFIGURATION_Handle *cfg; + + +/** + * Create and initialize a listen socket for the server. + * + * @return NULL on error, otherwise the listen socket + */ +static struct GNUNET_NETWORK_Handle * +open_listen_socket () +{ + const static int on = 1; + struct sockaddr_in sa; + struct GNUNET_NETWORK_Handle *desc; + + memset (&sa, 0, sizeof (sa)); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_family = AF_INET; + sa.sin_port = htons (PORT); + desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); + GNUNET_assert (desc != NULL); + if (GNUNET_NETWORK_socket_setsockopt + (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); + GNUNET_assert (GNUNET_NETWORK_socket_bind + (desc, (const struct sockaddr *) &sa, + sizeof (sa)) == GNUNET_OK); + GNUNET_NETWORK_socket_listen (desc, 5); + return desc; +} + + +static size_t +send_kilo (void *cls, size_t size, void *buf) +{ + int *ok = cls; + + if (size == 0) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got the desired timeout!\n"); +#endif + GNUNET_assert (buf == NULL); + *ok = 0; + GNUNET_CONNECTION_destroy (lsock, GNUNET_YES); + GNUNET_CONNECTION_destroy (csock, GNUNET_YES); + return 0; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending kilo to fill buffer.\n"); +#endif + GNUNET_assert (size >= 1024); + memset (buf, 42, 1024); + + GNUNET_assert (NULL != + GNUNET_CONNECTION_notify_transmit_ready (csock, 1024, + GNUNET_TIME_UNIT_SECONDS, + &send_kilo, cls)); + return 1024; +} + + +static void +task_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + ls = open_listen_socket (); + lsock = GNUNET_CONNECTION_create_from_existing (ls); + GNUNET_assert (lsock != NULL); + csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); + GNUNET_assert (csock != NULL); + GNUNET_assert (NULL != + GNUNET_CONNECTION_notify_transmit_ready (csock, 1024, + GNUNET_TIME_UNIT_SECONDS, + &send_kilo, cls)); +} + + + +/** + * Main method, starts scheduler with task_timeout. + */ +static int +check_timeout () +{ + int ok; + + ok = 1; + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", + "localhost"); + GNUNET_SCHEDULER_run (&task_timeout, &ok); + GNUNET_CONFIGURATION_destroy (cfg); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_connection_timeout", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret += check_timeout (); + return ret; +} + +/* end of test_connection_timeout.c */ diff --git a/src/util/test_connection_timeout_no_connect.c b/src/util/test_connection_timeout_no_connect.c new file mode 100644 index 0000000..2e8f9be --- /dev/null +++ b/src/util/test_connection_timeout_no_connect.c @@ -0,0 +1,101 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_connection_timeout_no_connect.c + * @brief tests for connection.c, doing timeout which connect failure + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define PORT 13425 + +static struct GNUNET_CONNECTION_Handle *csock; + +static struct GNUNET_CONFIGURATION_Handle *cfg; + +static size_t +handle_timeout (void *cls, size_t size, void *buf) +{ + int *ok = cls; + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received timeout signal.\n"); +#endif + + GNUNET_assert (size == 0); + GNUNET_assert (buf == NULL); + *ok = 0; + return 0; +} + + +static void +task_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); + GNUNET_assert (csock != NULL); + GNUNET_assert (NULL != + GNUNET_CONNECTION_notify_transmit_ready (csock, 1024, + GNUNET_TIME_UNIT_SECONDS, + &handle_timeout, + cls)); +} + + + +/** + * Main method, starts scheduler with task_timeout. + */ +static int +check_timeout () +{ + int ok; + + ok = 1; + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", + "localhost"); + GNUNET_SCHEDULER_run (&task_timeout, &ok); + GNUNET_CONFIGURATION_destroy (cfg); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_connection_timeout_no_connect", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret += check_timeout (); + return ret; +} + +/* end of test_connection_timeout_no_connect.c */ diff --git a/src/util/test_connection_transmit_cancel.c b/src/util/test_connection_transmit_cancel.c new file mode 100644 index 0000000..d81c32a --- /dev/null +++ b/src/util/test_connection_transmit_cancel.c @@ -0,0 +1,101 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_connection_transmit_cancel.c + * @brief tests for connection.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define PORT 12435 + +static struct GNUNET_CONFIGURATION_Handle *cfg; + + +static size_t +not_run (void *cls, size_t size, void *buf) +{ + GNUNET_assert (0); + return 0; +} + + +static void +task_transmit_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + struct GNUNET_CONNECTION_TransmitHandle *th; + struct GNUNET_CONNECTION_Handle *csock; + + csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); + GNUNET_assert (csock != NULL); + th = GNUNET_CONNECTION_notify_transmit_ready (csock, 12, + GNUNET_TIME_UNIT_MINUTES, + ¬_run, cls); + GNUNET_assert (NULL != th); + GNUNET_CONNECTION_notify_transmit_ready_cancel (th); + GNUNET_CONNECTION_destroy (csock, GNUNET_YES); + *ok = 0; +} + + + + +/** + * Main method, starts scheduler with task_timeout. + */ +static int +check_transmit_cancel () +{ + int ok; + + ok = 1; + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", + "localhost"); + GNUNET_SCHEDULER_run (&task_transmit_cancel, &ok); + GNUNET_CONFIGURATION_destroy (cfg); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_connection_transmit_cancel", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret += check_transmit_cancel (); + + return ret; +} + +/* end of test_connection_transmit_cancel.c */ diff --git a/src/util/test_container_bloomfilter.c b/src/util/test_container_bloomfilter.c new file mode 100644 index 0000000..f881bb3 --- /dev/null +++ b/src/util/test_container_bloomfilter.c @@ -0,0 +1,244 @@ +/* + This file is part of GNUnet. + (C) 2004, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_container_bloomfilter.c + * @brief Testcase for the bloomfilter. + * @author Christian Grothoff + * @author Igor Wronsky + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" + +#define K 4 +#define SIZE 65536 +#define TESTFILE "/tmp/bloomtest.dat" + +/** + * Generate a random hashcode. + */ +static void +nextHC (GNUNET_HashCode * hc) +{ + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, hc); +} + +static int +add_iterator (void *cls, GNUNET_HashCode * next) +{ + int *ret = cls; + GNUNET_HashCode pos; + + if (0 == (*ret)--) + return GNUNET_NO; + nextHC (&pos); + *next = pos; + return GNUNET_YES; +} + +int +main (int argc, char *argv[]) +{ + struct GNUNET_CONTAINER_BloomFilter *bf; + struct GNUNET_CONTAINER_BloomFilter *bfi; + GNUNET_HashCode tmp; + int i; + int ok1; + int ok2; + int falseok; + char buf[SIZE]; + struct stat sbuf; + + GNUNET_log_setup ("test-container-bloomfilter", "WARNING", NULL); + GNUNET_CRYPTO_seed_weak_random (1); + if (0 == STAT (TESTFILE, &sbuf)) + if (0 != UNLINK (TESTFILE)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", TESTFILE); + bf = GNUNET_CONTAINER_bloomfilter_load (TESTFILE, SIZE, K); + + for (i = 0; i < 200; i++) + { + nextHC (&tmp); + GNUNET_CONTAINER_bloomfilter_add (bf, &tmp); + } + GNUNET_CRYPTO_seed_weak_random (1); + ok1 = 0; + for (i = 0; i < 200; i++) + { + nextHC (&tmp); + if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) + ok1++; + } + if (ok1 != 200) + { + printf ("Got %d elements out of" "200 expected after insertion.\n", ok1); + GNUNET_CONTAINER_bloomfilter_free (bf); + return -1; + } + if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_get_raw_data (bf, buf, SIZE)) + { + GNUNET_CONTAINER_bloomfilter_free (bf); + return -1; + } + + GNUNET_CONTAINER_bloomfilter_free (bf); + + bf = GNUNET_CONTAINER_bloomfilter_load (TESTFILE, SIZE, K); + GNUNET_assert (bf != NULL); + bfi = GNUNET_CONTAINER_bloomfilter_init (buf, SIZE, K); + GNUNET_assert (bfi != NULL); + + GNUNET_CRYPTO_seed_weak_random (1); + ok1 = 0; + ok2 = 0; + for (i = 0; i < 200; i++) + { + nextHC (&tmp); + if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) + ok1++; + if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES) + ok2++; + } + if (ok1 != 200) + { + printf ("Got %d elements out of 200 " "expected after reloading.\n", ok1); + GNUNET_CONTAINER_bloomfilter_free (bf); + GNUNET_CONTAINER_bloomfilter_free (bfi); + return -1; + } + + if (ok2 != 200) + { + printf ("Got %d elements out of 200 " "expected after initialization.\n", + ok2); + GNUNET_CONTAINER_bloomfilter_free (bf); + GNUNET_CONTAINER_bloomfilter_free (bfi); + return -1; + } + + GNUNET_CRYPTO_seed_weak_random (1); + for (i = 0; i < 100; i++) + { + nextHC (&tmp); + GNUNET_CONTAINER_bloomfilter_remove (bf, &tmp); + GNUNET_CONTAINER_bloomfilter_remove (bfi, &tmp); + } + + GNUNET_CRYPTO_seed_weak_random (1); + + ok1 = 0; + ok2 = 0; + for (i = 0; i < 200; i++) + { + nextHC (&tmp); + if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) + ok1++; + if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES) + ok2++; + } + + if (ok1 != 100) + { + printf ("Expected 100 elements in loaded filter" + " after adding 200 and deleting 100, got %d\n", ok1); + GNUNET_CONTAINER_bloomfilter_free (bf); + GNUNET_CONTAINER_bloomfilter_free (bfi); + return -1; + } + if (ok2 != 200) + { + printf ("Expected 200 elements in initialized filter" + " after adding 200 and deleting 100 " + "(which should do nothing for a filter not backed by a file), got %d\n", + ok2); + GNUNET_CONTAINER_bloomfilter_free (bf); + GNUNET_CONTAINER_bloomfilter_free (bfi); + return -1; + } + + GNUNET_CRYPTO_seed_weak_random (3); + + GNUNET_CONTAINER_bloomfilter_clear (bf); + falseok = 0; + for (i = 0; i < 1000; i++) + { + nextHC (&tmp); + if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) + falseok++; + } + if (falseok > 0) + { + GNUNET_CONTAINER_bloomfilter_free (bf); + GNUNET_CONTAINER_bloomfilter_free (bfi); + return -1; + } + + if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_or (bf, buf, SIZE)) + { + GNUNET_CONTAINER_bloomfilter_free (bf); + GNUNET_CONTAINER_bloomfilter_free (bfi); + return -1; + } + + GNUNET_CRYPTO_seed_weak_random (2); + i = 20; + GNUNET_CONTAINER_bloomfilter_resize (bfi, &add_iterator, &i, SIZE * 2, K); + + GNUNET_CRYPTO_seed_weak_random (2); + i = 20; + GNUNET_CONTAINER_bloomfilter_resize (bf, &add_iterator, &i, SIZE * 2, K); + GNUNET_CRYPTO_seed_weak_random (2); + + ok1 = 0; + ok2 = 0; + for (i = 0; i < 20; i++) + { + nextHC (&tmp); + if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) + ok1++; + if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES) + ok2++; + } + + if (ok1 != 20) + { + printf ("Expected 20 elements in resized file-backed filter" + " after adding 20, got %d\n", ok1); + GNUNET_CONTAINER_bloomfilter_free (bf); + GNUNET_CONTAINER_bloomfilter_free (bfi); + return -1; + } + if (ok2 != 20) + { + printf ("Expected 20 elements in resized filter" + " after adding 20, got %d\n", ok2); + GNUNET_CONTAINER_bloomfilter_free (bf); + GNUNET_CONTAINER_bloomfilter_free (bfi); + return -1; + } + + + GNUNET_CONTAINER_bloomfilter_free (bf); + GNUNET_CONTAINER_bloomfilter_free (bfi); + + GNUNET_break (0 == UNLINK (TESTFILE)); + return 0; +} diff --git a/src/util/test_container_heap.c b/src/util/test_container_heap.c new file mode 100644 index 0000000..a2a004a --- /dev/null +++ b/src/util/test_container_heap.c @@ -0,0 +1,290 @@ +/* + This file is part of GNUnet. + (C) 2008 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @author Nathan Evans + * @file util/test_container_heap.c + * @brief Test of heap operations + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" + +static int +iterator_callback (void *cls, struct GNUNET_CONTAINER_HeapNode *node, + void *element, GNUNET_CONTAINER_HeapCostType cost) +{ + return GNUNET_OK; +} + +static int +nstrcmp (const char *a, const char *b) +{ + GNUNET_assert (a != NULL); + GNUNET_assert (b != NULL); + return strcmp (a, b); +} + +static int +check () +{ + struct GNUNET_CONTAINER_Heap *myHeap; + struct GNUNET_CONTAINER_HeapNode *n1; + struct GNUNET_CONTAINER_HeapNode *n2; + struct GNUNET_CONTAINER_HeapNode *n3; + struct GNUNET_CONTAINER_HeapNode *n4; + struct GNUNET_CONTAINER_HeapNode *n5; + struct GNUNET_CONTAINER_HeapNode *n6; + struct GNUNET_CONTAINER_HeapNode *n7; + struct GNUNET_CONTAINER_HeapNode *n8; + const char *r; + + myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + + // GNUNET_CONTAINER_heap_remove_root heap empty, taking if-branch + n1 = GNUNET_CONTAINER_heap_remove_root (myHeap); + GNUNET_assert (NULL == n1); + + // GNUNET_CONTAINER_heap_peek heap empty, taking if-branch + n1 = GNUNET_CONTAINER_heap_peek (myHeap); + GNUNET_assert (NULL == n1); + + // GNUNET_CONTAINER_heap_walk_get_next: heap empty, taking if-branch + n1 = GNUNET_CONTAINER_heap_walk_get_next (myHeap); + GNUNET_assert (NULL == n1); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "11", 11); + GNUNET_assert (NULL != n1); + + + // GNUNET_CONTAINER_heap_peek not empty, taking if-branch + n2 = NULL; + n2 = GNUNET_CONTAINER_heap_peek (myHeap); + GNUNET_assert (NULL != n2); + + // GNUNET_CONTAINER_heap_walk_get_next: 1 element + n1 = NULL; + n1 = GNUNET_CONTAINER_heap_walk_get_next (myHeap); + GNUNET_assert (NULL != n1); + + GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); + GNUNET_assert (1 == GNUNET_CONTAINER_heap_get_size (myHeap)); + n2 = GNUNET_CONTAINER_heap_insert (myHeap, "78", 78); + GNUNET_assert (2 == GNUNET_CONTAINER_heap_get_size (myHeap)); + GNUNET_assert (0 == strcmp ("78", GNUNET_CONTAINER_heap_remove_node (n2))); + GNUNET_assert (1 == GNUNET_CONTAINER_heap_get_size (myHeap)); + GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); + + n3 = GNUNET_CONTAINER_heap_insert (myHeap, "15", 5); + GNUNET_CONTAINER_heap_update_cost (myHeap, n3, 15); + GNUNET_assert (2 == GNUNET_CONTAINER_heap_get_size (myHeap)); + GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); + + n4 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50); + GNUNET_CONTAINER_heap_update_cost (myHeap, n4, 50); + GNUNET_assert (3 == GNUNET_CONTAINER_heap_get_size (myHeap)); + GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); + + n5 = GNUNET_CONTAINER_heap_insert (myHeap, "100", 100); + n6 = GNUNET_CONTAINER_heap_insert (myHeap, "30/200", 30); + GNUNET_assert (5 == GNUNET_CONTAINER_heap_get_size (myHeap)); + GNUNET_CONTAINER_heap_remove_node (n5); + r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n1 */ + GNUNET_assert (NULL != r); + GNUNET_assert (0 == strcmp ("11", r)); + GNUNET_CONTAINER_heap_update_cost (myHeap, n6, 200); + GNUNET_CONTAINER_heap_remove_node (n3); + r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n4 */ + GNUNET_assert (NULL != r); + GNUNET_assert (0 == strcmp ("50", r)); + r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n6 */ + GNUNET_assert (NULL != r); + GNUNET_assert (0 == strcmp ("30/200", r)); + GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (myHeap)); + + GNUNET_CONTAINER_heap_destroy (myHeap); + + // My additions to a complete testcase + // Testing a GNUNET_CONTAINER_HEAP_ORDER_MIN + // Testing remove_node + + myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + GNUNET_CONTAINER_heap_update_cost (myHeap, n1, 15); + + r = GNUNET_CONTAINER_heap_remove_node (n1); + GNUNET_assert (NULL != r); + GNUNET_assert (0 == strcmp ("10", r)); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); + + GNUNET_CONTAINER_heap_walk_get_next (myHeap); + r = GNUNET_CONTAINER_heap_remove_node (n2); + GNUNET_assert (NULL != r); + GNUNET_assert (0 == strcmp ("20", r)); + r = GNUNET_CONTAINER_heap_remove_node (n1); + GNUNET_assert (NULL != r); + GNUNET_assert (0 == strcmp ("10", r)); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); + n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); + + GNUNET_CONTAINER_heap_remove_node (n2); + GNUNET_CONTAINER_heap_remove_node (n1); + r = GNUNET_CONTAINER_heap_remove_root (myHeap); + GNUNET_assert (NULL != r); + GNUNET_assert (0 == strcmp ("30", r)); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); + n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); + + GNUNET_CONTAINER_heap_remove_node (n2); + GNUNET_CONTAINER_heap_remove_node (n1); + r = GNUNET_CONTAINER_heap_remove_node (n3); + GNUNET_assert (NULL != r); + GNUNET_assert (0 == strcmp ("30", r)); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20); + n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30); + + GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); + GNUNET_assert (0 == + nstrcmp ("10", GNUNET_CONTAINER_heap_remove_root (myHeap))); + GNUNET_assert (0 == + nstrcmp ("30", GNUNET_CONTAINER_heap_remove_root (myHeap))); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20); + n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30); + n4 = GNUNET_CONTAINER_heap_insert (myHeap, "40", 40); + n5 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50); + n6 = GNUNET_CONTAINER_heap_insert (myHeap, "60", 60); + + // Inserting nodes deeper in the tree with lower costs + n7 = GNUNET_CONTAINER_heap_insert (myHeap, "70", 10); + n8 = GNUNET_CONTAINER_heap_insert (myHeap, "80", 10); + + GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3))); + + // Cleaning up... + GNUNET_assert (0 == nstrcmp ("60", GNUNET_CONTAINER_heap_remove_node (n6))); + GNUNET_assert (0 == nstrcmp ("50", GNUNET_CONTAINER_heap_remove_node (n5))); + + // Testing heap_walk_get_next + GNUNET_CONTAINER_heap_walk_get_next (myHeap); + GNUNET_CONTAINER_heap_walk_get_next (myHeap); + GNUNET_CONTAINER_heap_walk_get_next (myHeap);; + GNUNET_CONTAINER_heap_walk_get_next (myHeap); + GNUNET_CONTAINER_heap_walk_get_next (myHeap); + + GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); + GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); + GNUNET_assert (0 == nstrcmp ("40", GNUNET_CONTAINER_heap_remove_node (n4))); + GNUNET_assert (0 == nstrcmp ("70", GNUNET_CONTAINER_heap_remove_node (n7))); + GNUNET_assert (0 == nstrcmp ("80", GNUNET_CONTAINER_heap_remove_node (n8))); + + // End Testing remove_node + + // Testing a GNUNET_CONTAINER_HEAP_ORDER_MAX + GNUNET_CONTAINER_heap_destroy (myHeap); + + myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + GNUNET_CONTAINER_heap_update_cost (myHeap, n1, 15); + + GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); + + GNUNET_CONTAINER_heap_walk_get_next (myHeap); + GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); + GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); + n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); + + GNUNET_CONTAINER_heap_remove_node (n2); + GNUNET_CONTAINER_heap_remove_node (n1); + GNUNET_assert (0 == + nstrcmp ("30", GNUNET_CONTAINER_heap_remove_root (myHeap))); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); + n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); + + GNUNET_CONTAINER_heap_remove_node (n2); + GNUNET_CONTAINER_heap_remove_node (n1); + GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3))); + + n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); + n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20); + n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30); + n4 = GNUNET_CONTAINER_heap_insert (myHeap, "40", 40); + n5 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50); + n6 = GNUNET_CONTAINER_heap_insert (myHeap, "60", 60); + + // Inserting nodes deeper in the tree with lower costs + n7 = GNUNET_CONTAINER_heap_insert (myHeap, "70", 10); + n8 = GNUNET_CONTAINER_heap_insert (myHeap, "80", 10); + + GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3))); + + // Cleaning up... + GNUNET_assert (0 == nstrcmp ("60", GNUNET_CONTAINER_heap_remove_node (n6))); + GNUNET_assert (0 == nstrcmp ("50", GNUNET_CONTAINER_heap_remove_node (n5))); + + // Testing heap_walk_get_next + GNUNET_CONTAINER_heap_walk_get_next (myHeap); + GNUNET_CONTAINER_heap_walk_get_next (myHeap); + GNUNET_CONTAINER_heap_walk_get_next (myHeap);; + GNUNET_CONTAINER_heap_walk_get_next (myHeap); + GNUNET_CONTAINER_heap_walk_get_next (myHeap); + + GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); + GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); + GNUNET_assert (0 == nstrcmp ("40", GNUNET_CONTAINER_heap_remove_node (n4))); + GNUNET_assert (0 == nstrcmp ("70", GNUNET_CONTAINER_heap_remove_node (n7))); + GNUNET_assert (0 == nstrcmp ("80", GNUNET_CONTAINER_heap_remove_node (n8))); + + // End Testing remove_node + + GNUNET_CONTAINER_heap_destroy (myHeap); + + return 0; +} + + +int +main (int argc, char **argv) +{ + GNUNET_log_setup ("test-container-heap", "WARNING", NULL); + return check (); +} + +/* end of test_container_heap.c */ diff --git a/src/util/test_container_meta_data.c b/src/util/test_container_meta_data.c new file mode 100644 index 0000000..fe1dd79 --- /dev/null +++ b/src/util/test_container_meta_data.c @@ -0,0 +1,347 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2006, 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_container_meta_data.c + * @brief Test for container_meta_data.c + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" + +#define ABORT(m) { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); if (m != NULL) GNUNET_CONTAINER_meta_data_destroy(m); return 1; } + +static int +testMeta (int i) +{ + struct GNUNET_CONTAINER_MetaData *m; + char val[256]; + char *sval; + int j; + unsigned int size; + + m = GNUNET_CONTAINER_meta_data_create (); + if (GNUNET_OK != + GNUNET_CONTAINER_meta_data_insert (m, "", EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", "TestTitle", + strlen ("TestTitle") + 1)) + ABORT (m); + if (GNUNET_OK != + GNUNET_CONTAINER_meta_data_insert (m, "", + EXTRACTOR_METATYPE_AUTHOR_NAME, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", "TestTitle", + strlen ("TestTitle") + 1)) + ABORT (m); + if (GNUNET_OK == GNUNET_CONTAINER_meta_data_insert (m, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "TestTitle", strlen ("TestTitle") + 1)) /* dup! */ + ABORT (m); + if (GNUNET_OK == GNUNET_CONTAINER_meta_data_insert (m, "", EXTRACTOR_METATYPE_AUTHOR_NAME, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "TestTitle", strlen ("TestTitle") + 1)) /* dup! */ + ABORT (m); + if (2 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL)) + ABORT (m); + if (GNUNET_OK != + GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_AUTHOR_NAME, + "TestTitle", strlen ("TestTitle") + 1)) + ABORT (m); + if (GNUNET_OK == GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_AUTHOR_NAME, "TestTitle", strlen ("TestTitle") + 1)) /* already gone */ + ABORT (m); + if (1 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL)) + ABORT (m); + if (GNUNET_OK != + GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_TITLE, + "TestTitle", strlen ("TestTitle") + 1)) + ABORT (m); + if (GNUNET_OK == GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_TITLE, "TestTitle", strlen ("TestTitle") + 1)) /* already gone */ + ABORT (m); + if (0 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL)) + ABORT (m); + for (j = 0; j < i; j++) + { + GNUNET_snprintf (val, sizeof (val), "%s.%d", + "A teststring that should compress well.", j); + if (GNUNET_OK != + GNUNET_CONTAINER_meta_data_insert (m, "", + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", val, strlen (val) + 1)) + ABORT (m); + } + if (i != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL)) + ABORT (m); + + size = GNUNET_CONTAINER_meta_data_get_serialized_size (m); + sval = NULL; + if (size != + GNUNET_CONTAINER_meta_data_serialize (m, &sval, size, + GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL)) + { + GNUNET_free_non_null (sval); + ABORT (m); + } + GNUNET_CONTAINER_meta_data_destroy (m); + m = GNUNET_CONTAINER_meta_data_deserialize (sval, size); + GNUNET_free (sval); + if (m == NULL) + ABORT (m); + for (j = 0; j < i; j++) + { + GNUNET_snprintf (val, sizeof (val), "%s.%d", + "A teststring that should compress well.", j); + if (GNUNET_OK != + GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_UNKNOWN, val, + strlen (val) + 1)) + { + ABORT (m); + } + } + if (0 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL)) + ABORT (m); + GNUNET_CONTAINER_meta_data_destroy (m); + return 0; +} + +int +testMetaMore (int i) +{ + struct GNUNET_CONTAINER_MetaData *meta; + int q; + char txt[128]; + char *data; + unsigned long long size; + + meta = GNUNET_CONTAINER_meta_data_create (); + for (q = 0; q <= i; q++) + { + GNUNET_snprintf (txt, 128, "%u -- %u\n", i, q); + GNUNET_CONTAINER_meta_data_insert (meta, "", + q % EXTRACTOR_metatype_get_max (), + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + txt, strlen (txt) + 1); + } + size = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); + data = GNUNET_malloc (size * 4); + if (size != + GNUNET_CONTAINER_meta_data_serialize (meta, &data, size * 4, + GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL)) + { + GNUNET_free (data); + ABORT (meta); + } + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_free (data); + return 0; +} + +static int +testMetaLink () +{ + struct GNUNET_CONTAINER_MetaData *m; + char *val; + unsigned int size; + + m = GNUNET_CONTAINER_meta_data_create (); + if (GNUNET_OK != + GNUNET_CONTAINER_meta_data_insert (m, "", + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", "link", + strlen ("link") + 1)) + ABORT (m); + if (GNUNET_OK != + GNUNET_CONTAINER_meta_data_insert (m, "", + EXTRACTOR_METATYPE_FILENAME, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", "lib-link.m4", + strlen ("lib-link.m4") + 1)) + ABORT (m); + val = NULL; + size = + GNUNET_CONTAINER_meta_data_serialize (m, &val, (size_t) - 1, + GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL); + GNUNET_CONTAINER_meta_data_destroy (m); + m = GNUNET_CONTAINER_meta_data_deserialize (val, size); + GNUNET_free (val); + if (m == NULL) + ABORT (m); + GNUNET_CONTAINER_meta_data_destroy (m); + return 0; +} + +int +check () +{ + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_CONTAINER_MetaData *meta2; + int q; + int i = 100; + char txt[128]; + char *str; + unsigned char *thumb; + + meta = GNUNET_CONTAINER_meta_data_create (); + meta2 = GNUNET_CONTAINER_meta_data_create (); + for (q = 0; q <= i; q++) + { + GNUNET_snprintf (txt, 128, "%u -- %u\n", i, q); + GNUNET_CONTAINER_meta_data_insert (meta, "", + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "TestTitle", strlen ("TestTitle") + 1); + GNUNET_CONTAINER_meta_data_insert (meta2, "", + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "TestTitle", strlen ("TestTitle") + 1); + } + + //check meta_data_test_equal + if (GNUNET_YES != GNUNET_CONTAINER_meta_data_test_equal (meta, meta2)) + { + GNUNET_CONTAINER_meta_data_destroy (meta2); + ABORT (meta); + } + + //check meta_data_clear + GNUNET_CONTAINER_meta_data_clear (meta2); + if (0 != GNUNET_CONTAINER_meta_data_iterate (meta2, NULL, NULL)) + { + GNUNET_CONTAINER_meta_data_destroy (meta2); + ABORT (meta); + } + // check equal branch in meta_data_test_equal + if (GNUNET_YES != GNUNET_CONTAINER_meta_data_test_equal (meta, meta)) + { + GNUNET_CONTAINER_meta_data_destroy (meta2); + ABORT (meta); + } + // check "count" branch in meta_data_test_equal + if (GNUNET_NO != GNUNET_CONTAINER_meta_data_test_equal (meta, meta2)) + { + GNUNET_CONTAINER_meta_data_destroy (meta2); + ABORT (meta); + } + + // check meta_data_add_publication_date + GNUNET_CONTAINER_meta_data_add_publication_date (meta2); + + // check meta_data_merge + GNUNET_CONTAINER_meta_data_clear (meta2); + GNUNET_CONTAINER_meta_data_merge (meta2, meta); + if (100 == GNUNET_CONTAINER_meta_data_iterate (meta2, NULL, NULL)) + { + GNUNET_CONTAINER_meta_data_destroy (meta2); + ABORT (meta); + } + + // check meta_data_get_by_type + GNUNET_CONTAINER_meta_data_clear (meta2); + if (NULL != + (str = + GNUNET_CONTAINER_meta_data_get_by_type (meta2, + EXTRACTOR_METATYPE_UNKNOWN))) + { + GNUNET_CONTAINER_meta_data_destroy (meta2); + GNUNET_free (str); + ABORT (meta); + } + + str = + GNUNET_CONTAINER_meta_data_get_by_type (meta, EXTRACTOR_METATYPE_UNKNOWN); + GNUNET_assert (NULL != str); + if (str[0] != 'T') + { + GNUNET_CONTAINER_meta_data_destroy (meta2); + GNUNET_free (str); + ABORT (meta); + } + GNUNET_free (str); + + // check branch + if (NULL != + (str = + GNUNET_CONTAINER_meta_data_get_by_type (meta, + EXTRACTOR_METATYPE_PUBLICATION_DATE))) + { + GNUNET_free (str); + GNUNET_CONTAINER_meta_data_destroy (meta2); + ABORT (meta); + } + + //check meta_data_get_first_by_types + str = + GNUNET_CONTAINER_meta_data_get_first_by_types (meta, + EXTRACTOR_METATYPE_UNKNOWN, + -1); + GNUNET_assert (NULL != str); + if (str[0] != 'T') + { + GNUNET_CONTAINER_meta_data_destroy (meta2); + GNUNET_free (str); + ABORT (meta); + } + GNUNET_free (str); + + //check meta_data_get_thumbnail + if (GNUNET_CONTAINER_meta_data_get_thumbnail (meta, &thumb) != 0) + { + GNUNET_free (thumb); + GNUNET_CONTAINER_meta_data_destroy (meta2); + ABORT (meta); + } + GNUNET_CONTAINER_meta_data_destroy (meta2); + //check meta_data_duplicate + meta2 = GNUNET_CONTAINER_meta_data_duplicate (meta); + if (200 == GNUNET_CONTAINER_meta_data_iterate (meta2, NULL, NULL)) + { + GNUNET_CONTAINER_meta_data_destroy (meta2); + ABORT (meta); + } + GNUNET_CONTAINER_meta_data_destroy (meta2); + GNUNET_CONTAINER_meta_data_destroy (meta); + return 0; +} + + +int +main (int argc, char *argv[]) +{ + int failureCount = 0; + int i; + + GNUNET_log_setup ("test-container-meta-data", "WARNING", NULL); + for (i = 0; i < 255; i++) + failureCount += testMeta (i); + for (i = 1; i < 255; i++) + failureCount += testMetaMore (i); + failureCount += testMetaLink (); + + int ret = check (); + + if (ret == 1) + return 1; + + if (failureCount != 0) + return 1; + return 0; +} + +/* end of test_container_meta_data.c */ diff --git a/src/util/test_container_multihashmap.c b/src/util/test_container_multihashmap.c new file mode 100644 index 0000000..ba621c1 --- /dev/null +++ b/src/util/test_container_multihashmap.c @@ -0,0 +1,105 @@ +/* + This file is part of GNUnet. + (C) 2008 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_container_multihashmap.c + * @brief Test for container_multihashmap.c + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" + +#define ABORT() { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); if (m != NULL) GNUNET_CONTAINER_multihashmap_destroy(m); return 1; } +#define CHECK(c) { if (! (c)) ABORT(); } + +static int +testMap (int i) +{ + struct GNUNET_CONTAINER_MultiHashMap *m; + GNUNET_HashCode k1; + GNUNET_HashCode k2; + const char *ret; + int j; + + CHECK (NULL != (m = GNUNET_CONTAINER_multihashmap_create (i))); + memset (&k1, 0, sizeof (k1)); + memset (&k2, 1, sizeof (k2)); + CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k1)); + CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k2)); + CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (m, &k1, NULL)); + CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (m, &k2, NULL)); + CHECK (NULL == GNUNET_CONTAINER_multihashmap_get (m, &k1)); + CHECK (NULL == GNUNET_CONTAINER_multihashmap_get (m, &k2)); + CHECK (0 == GNUNET_CONTAINER_multihashmap_remove_all (m, &k1)); + CHECK (0 == GNUNET_CONTAINER_multihashmap_size (m)); + CHECK (0 == GNUNET_CONTAINER_multihashmap_iterate (m, NULL, NULL)); + CHECK (0 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k1, NULL, NULL)); + + CHECK (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (m, &k1, "v1", + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); + CHECK (1 == GNUNET_CONTAINER_multihashmap_size (m)); + ret = GNUNET_CONTAINER_multihashmap_get (m, &k1); + GNUNET_assert (ret != NULL); + CHECK (0 == strcmp ("v1", ret)); + CHECK (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_put (m, &k1, "v1", + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); + CHECK (1 == GNUNET_CONTAINER_multihashmap_size (m)); + CHECK (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (m, &k1, "v2", + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + CHECK (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (m, &k1, "v3", + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + CHECK (3 == GNUNET_CONTAINER_multihashmap_size (m)); + CHECK (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (m, &k1, "v3")); + CHECK (2 == GNUNET_CONTAINER_multihashmap_size (m)); + CHECK (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (m, &k1)); + CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k2)); + CHECK (2 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k1, NULL, NULL)); + CHECK (0 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k2, NULL, NULL)); + CHECK (2 == GNUNET_CONTAINER_multihashmap_iterate (m, NULL, NULL)); + CHECK (2 == GNUNET_CONTAINER_multihashmap_remove_all (m, &k1)); + for (j = 0; j < 1024; j++) + CHECK (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (m, &k1, "v2", + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + GNUNET_CONTAINER_multihashmap_destroy (m); + return 0; +} + +int +main (int argc, char *argv[]) +{ + int failureCount = 0; + int i; + + GNUNET_log_setup ("test-container-multihashmap", "WARNING", NULL); + for (i = 1; i < 255; i++) + failureCount += testMap (i); + if (failureCount != 0) + return 1; + return 0; +} + +/* end of test_container_multihashmap.c */ diff --git a/src/util/test_container_slist.c b/src/util/test_container_slist.c new file mode 100644 index 0000000..1b63d3d --- /dev/null +++ b/src/util/test_container_slist.c @@ -0,0 +1,160 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_container_slist.c + * @brief Testcases for singly linked lists + * @author Nils Durner + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" + +int +main (int argc, char *argv[]) +{ + struct GNUNET_CONTAINER_SList *l; + struct GNUNET_CONTAINER_SList_Iterator it; + unsigned int i; + int *ip; + unsigned int j; + size_t s; + const void *p; + + GNUNET_log_setup ("test-container-slist", "WARNING", NULL); + + l = GNUNET_CONTAINER_slist_create (); + GNUNET_assert (l != NULL); + GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 0); + + for (i = 0; i < 100; i++) + GNUNET_CONTAINER_slist_add (l, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, + &i, sizeof (i)); + GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 100); + + for (it = GNUNET_CONTAINER_slist_begin (l), i = 99; + GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES; + GNUNET_CONTAINER_slist_next (&it), i--) + { + p = GNUNET_CONTAINER_slist_get (&it, &s); + + if ((p == NULL) || (i != (j = *(int *) p)) || (s != sizeof (i))) + { + GNUNET_CONTAINER_slist_iter_destroy (&it); + GNUNET_assert (0); + } + j *= 2; + GNUNET_CONTAINER_slist_insert (&it, + GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, + &j, sizeof (j)); + } + GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 200); + i = 198; + GNUNET_assert (GNUNET_CONTAINER_slist_contains (l, &i, sizeof (i))); + + for (it = GNUNET_CONTAINER_slist_begin (l); + GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES;) + { + p = GNUNET_CONTAINER_slist_get (&it, &s); + GNUNET_assert (p != NULL); + GNUNET_assert (s == sizeof (i)); + i = *(int *) p; + + GNUNET_assert (GNUNET_CONTAINER_slist_next (&it) == GNUNET_YES); + GNUNET_assert (GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES); + + p = GNUNET_CONTAINER_slist_get (&it, &s); + GNUNET_assert (p != NULL); + GNUNET_assert (s == sizeof (j)); + j = *(int *) p; + + GNUNET_assert (j * 2 == i); + + GNUNET_CONTAINER_slist_erase (&it); + } + GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 100); + i = 99; + GNUNET_assert (GNUNET_CONTAINER_slist_contains (l, &i, sizeof (i)) == + GNUNET_NO); + i = 198; + GNUNET_assert (GNUNET_CONTAINER_slist_contains (l, &i, sizeof (i)) == + GNUNET_YES); + + GNUNET_CONTAINER_slist_clear (l); + GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 0); + + for (i = 0; i < 100; i++) + GNUNET_CONTAINER_slist_add (l, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, + &i, sizeof (i)); + /*check slist_append */ + GNUNET_CONTAINER_slist_append (l, l); + GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 200); + + GNUNET_CONTAINER_slist_destroy (l); + + /*check slist_add_end */ + l = GNUNET_CONTAINER_slist_create (); + for (i = 0; i < 100; i++) + GNUNET_CONTAINER_slist_add_end (l, + GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, + &i, sizeof (i)); + + GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 100); + + for (it = GNUNET_CONTAINER_slist_begin (l), i = 0; + GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES; + GNUNET_CONTAINER_slist_next (&it), i++) + { + p = GNUNET_CONTAINER_slist_get (&it, &s); + + if ((p == NULL) || (i != *(int *) p) || (s != sizeof (i))) + { + GNUNET_assert (0); + } + } + GNUNET_CONTAINER_slist_destroy (l); + + /*check if disp = GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC */ + l = GNUNET_CONTAINER_slist_create (); + + for (i = 0; i < 100; i++) + { + ip = GNUNET_malloc (sizeof (int)); + *ip = i; + GNUNET_CONTAINER_slist_add (l, GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC, + ip, sizeof (int)); + } + //creat_add + it = GNUNET_CONTAINER_slist_begin (l); + p = GNUNET_CONTAINER_slist_get (&it, &s); + GNUNET_assert (p != NULL); + //slist_erase + GNUNET_assert (GNUNET_CONTAINER_slist_next (&it) == GNUNET_YES); + GNUNET_CONTAINER_slist_erase (&it); + GNUNET_CONTAINER_slist_iter_destroy (&it); + GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 99); + //slist_clear + GNUNET_CONTAINER_slist_clear (l); + GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 0); + GNUNET_CONTAINER_slist_destroy (l); + + return 0; +} diff --git a/src/util/test_crypto_aes.c b/src/util/test_crypto_aes.c new file mode 100644 index 0000000..971e9af --- /dev/null +++ b/src/util/test_crypto_aes.c @@ -0,0 +1,175 @@ +/* + This file is part of GNUnet. + (C) 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +/** + * @author Christian Grothoff + * @file util/test_crypto_aes.c + * @brief test for AES ciphers + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" + +#define TESTSTRING "Hello World!" +#define INITVALUE "InitializationVectorValue" + +static int +testSymcipher () +{ + struct GNUNET_CRYPTO_AesSessionKey key; + char result[100]; + int size; + char res[100]; + + GNUNET_CRYPTO_aes_create_session_key (&key); + size = + GNUNET_CRYPTO_aes_encrypt (TESTSTRING, strlen (TESTSTRING) + 1, &key, + (const struct + GNUNET_CRYPTO_AesInitializationVector *) + INITVALUE, result); + if (size == -1) + { + printf ("symciphertest failed: encryptBlock returned %d\n", size); + return 1; + } + size = + GNUNET_CRYPTO_aes_decrypt (result, size, &key, + (const struct + GNUNET_CRYPTO_AesInitializationVector *) + INITVALUE, res); + if (strlen (TESTSTRING) + 1 != size) + { + printf ("symciphertest failed: decryptBlock returned %d\n", size); + return 1; + } + if (0 != strcmp (res, TESTSTRING)) + { + printf ("symciphertest failed: %s != %s\n", res, TESTSTRING); + return 1; + } + else + return 0; +} + +int +verifyCrypto () +{ + struct GNUNET_CRYPTO_AesSessionKey key; + char result[GNUNET_CRYPTO_AES_KEY_LENGTH]; + char *res; + int ret; + + unsigned char plain[] = + { 29, 128, 192, 253, 74, 171, 38, 187, 84, 219, 76, 76, 209, 118, 33, 249, + 172, 124, 96, 9, 157, 110, 8, 215, 200, 63, 69, 230, 157, 104, 247, 164 + }; + unsigned char raw_key[] = + { 106, 74, 209, 88, 145, 55, 189, 135, 125, 180, 225, 108, 183, 54, 25, + 169, 129, 188, 131, 75, 227, 245, 105, 10, 225, 15, 115, 159, 148, 184, + 34, 191 + }; + unsigned char encrresult[] = + { 167, 102, 230, 233, 127, 195, 176, 107, 17, 91, 199, 127, 96, 113, 75, + 195, 245, 217, 61, 236, 159, 165, 103, 121, 203, 99, 202, 41, 23, 222, 25, + 102 + }; + + res = NULL; + ret = 0; + + memcpy (key.key, raw_key, GNUNET_CRYPTO_AES_KEY_LENGTH); + key.crc32 = + htonl (GNUNET_CRYPTO_crc32_n (&key, GNUNET_CRYPTO_AES_KEY_LENGTH)); + + if (ntohl (key.crc32) != (unsigned int) 38125195LL) + { + printf ("Static key has different CRC: %u - %u\n", ntohl (key.crc32), + key.crc32); + + ret = 1; + goto error; + } + + if (GNUNET_CRYPTO_AES_KEY_LENGTH != + GNUNET_CRYPTO_aes_encrypt (plain, GNUNET_CRYPTO_AES_KEY_LENGTH, &key, + (const struct + GNUNET_CRYPTO_AesInitializationVector *) + "testtesttesttest", result)) + { + printf ("Wrong return value from encrypt block.\n"); + ret = 1; + goto error; + } + + if (memcmp (encrresult, result, GNUNET_CRYPTO_AES_KEY_LENGTH) != 0) + { + printf ("Encrypted result wrong.\n"); + ret = 1; + goto error; + } + + res = GNUNET_malloc (GNUNET_CRYPTO_AES_KEY_LENGTH); + + if (GNUNET_CRYPTO_AES_KEY_LENGTH != + GNUNET_CRYPTO_aes_decrypt (result, GNUNET_CRYPTO_AES_KEY_LENGTH, &key, + (const struct + GNUNET_CRYPTO_AesInitializationVector *) + "testtesttesttest", res)) + { + printf ("Wrong return value from decrypt block.\n"); + ret = 1; + goto error; + } + + if (memcmp (res, plain, GNUNET_CRYPTO_AES_KEY_LENGTH) != 0) + { + printf ("Decrypted result does not match input.\n"); + + ret = 1; + } + +error: + + GNUNET_free_non_null (res); + + return ret; +} + +int +main (int argc, char *argv[]) +{ + int failureCount = 0; + + GNUNET_log_setup ("test-crypto-aes", "WARNING", NULL); + GNUNET_CRYPTO_random_disable_entropy_gathering (); + GNUNET_assert (strlen (INITVALUE) > + sizeof (struct GNUNET_CRYPTO_AesInitializationVector)); + failureCount += testSymcipher (); + failureCount += verifyCrypto (); + + if (failureCount != 0) + { + printf ("%d TESTS FAILED!\n", failureCount); + return -1; + } + return 0; +} + +/* end of test_crypto_aes.c */ diff --git a/src/util/test_crypto_aes_weak.c b/src/util/test_crypto_aes_weak.c new file mode 100644 index 0000000..0b7ba5c --- /dev/null +++ b/src/util/test_crypto_aes_weak.c @@ -0,0 +1,202 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +/** + * @author Krista Bennett + * @author Christian Grothoff + * @file util/test_crypto_aes_weak.c + * @brief AES weak key test. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include + +#define MAX_WEAK_KEY_TRIALS 100000 +#define GENERATE_WEAK_KEYS GNUNET_NO +#define WEAK_KEY_TESTSTRING "I hate weak keys." + +static void +printWeakKey (struct GNUNET_CRYPTO_AesSessionKey *key) +{ + int i; + + for (i = 0; i < GNUNET_CRYPTO_AES_KEY_LENGTH; i++) + { + printf ("%x ", (int) (key->key[i])); + } +} + +static int +testWeakKey () +{ + char result[100]; + char res[100]; + int size; + struct GNUNET_CRYPTO_AesSessionKey weak_key; + struct GNUNET_CRYPTO_AesInitializationVector INITVALUE; + + memset (&INITVALUE, 42, + sizeof (struct GNUNET_CRYPTO_AesInitializationVector)); + /* sorry, this is not a weak key -- I don't have + * any at the moment! */ + weak_key.key[0] = (char) (0x4c); + weak_key.key[1] = (char) (0x31); + weak_key.key[2] = (char) (0xc6); + weak_key.key[3] = (char) (0x2b); + weak_key.key[4] = (char) (0xc1); + weak_key.key[5] = (char) (0x5f); + weak_key.key[6] = (char) (0x4d); + weak_key.key[7] = (char) (0x1f); + weak_key.key[8] = (char) (0x31); + weak_key.key[9] = (char) (0xaa); + weak_key.key[10] = (char) (0x12); + weak_key.key[11] = (char) (0x2e); + weak_key.key[12] = (char) (0xb7); + weak_key.key[13] = (char) (0x82); + weak_key.key[14] = (char) (0xc0); + weak_key.key[15] = (char) (0xb6); + weak_key.key[16] = (char) (0x4d); + weak_key.key[17] = (char) (0x1f); + weak_key.key[18] = (char) (0x31); + weak_key.key[19] = (char) (0xaa); + weak_key.key[20] = (char) (0x4c); + weak_key.key[21] = (char) (0x31); + weak_key.key[22] = (char) (0xc6); + weak_key.key[23] = (char) (0x2b); + weak_key.key[24] = (char) (0xc1); + weak_key.key[25] = (char) (0x5f); + weak_key.key[26] = (char) (0x4d); + weak_key.key[27] = (char) (0x1f); + weak_key.key[28] = (char) (0x31); + weak_key.key[29] = (char) (0xaa); + weak_key.key[30] = (char) (0xaa); + weak_key.key[31] = (char) (0xaa); + /* memset(&weak_key, 0, 32); */ + weak_key.crc32 = + htonl (GNUNET_CRYPTO_crc32_n (&weak_key, GNUNET_CRYPTO_AES_KEY_LENGTH)); + + size = + GNUNET_CRYPTO_aes_encrypt (WEAK_KEY_TESTSTRING, + strlen (WEAK_KEY_TESTSTRING) + 1, &weak_key, + &INITVALUE, result); + + if (size == -1) + { + GNUNET_break (0); + return 1; + } + + size = GNUNET_CRYPTO_aes_decrypt (result, size, &weak_key, &INITVALUE, res); + + if ((strlen (WEAK_KEY_TESTSTRING) + 1) != size) + { + GNUNET_break (0); + return 1; + } + if (0 != strcmp (res, WEAK_KEY_TESTSTRING)) + { + GNUNET_break (0); + return 1; + } + else + return 0; +} + +static int +getWeakKeys () +{ + struct GNUNET_CRYPTO_AesSessionKey sessionkey; + int number_of_weak_keys = 0; + int number_of_runs; + + gcry_cipher_hd_t handle; + int rc; + + for (number_of_runs = 0; number_of_runs < MAX_WEAK_KEY_TRIALS; + number_of_runs++) + { + + if (number_of_runs % 1000 == 0) + FPRINTF (stderr, "%s", "."); + /*printf("Got to run number %d.\n", number_of_runs); */ + GNUNET_CRYPTO_aes_create_session_key (&sessionkey); + + rc = gcry_cipher_open (&handle, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB, + 0); + + if (rc) + { + printf ("testweakkey: gcry_cipher_open failed on trial %d. %s\n", + number_of_runs, gcry_strerror (rc)); + continue; + } + + rc = gcry_cipher_setkey (handle, &sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH); + + if ((char) rc == GPG_ERR_WEAK_KEY) + { + printf ("\nWeak key (in hex): "); + printWeakKey (&sessionkey); + printf ("\n"); + number_of_weak_keys++; + } + else if (rc) + { + printf ("\nUnexpected error generating keys. Error is %s\n", + gcry_strerror (rc)); + } + + gcry_cipher_close (handle); + + } + + return number_of_weak_keys; +} + +int +main (int argc, char *argv[]) +{ + int weak_keys; + + GNUNET_log_setup ("test-crypto-aes-weak", "WARNING", NULL); + GNUNET_CRYPTO_random_disable_entropy_gathering (); + if (GENERATE_WEAK_KEYS) + { + weak_keys = getWeakKeys (); + + if (weak_keys == 0) + { + printf ("\nNo weak keys found in %d runs.\n", MAX_WEAK_KEY_TRIALS); + } + else + { + printf ("\n%d weak keys found in %d runs.\n", weak_keys, + MAX_WEAK_KEY_TRIALS); + } + } + + if (testWeakKey () != 0) + return -1; + return 0; +} + +/* end of weakkeytest.c */ diff --git a/src/util/test_crypto_crc.c b/src/util/test_crypto_crc.c new file mode 100644 index 0000000..99eca0c --- /dev/null +++ b/src/util/test_crypto_crc.c @@ -0,0 +1,221 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + For the actual CRC code: + Copyright abandoned; this code is in the public domain. + Provided to GNUnet by peter@horizon.com +*/ + +/** + * @file util/test_crypto_crc.c + * @brief testcase for crypto_crc.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" + +static int expected[] = { + -1223996378, 929797997, -1048047323, 1791081351, -425765913, 2138425902, + 82584863, 1939615314, 1806463044, -1505003452, 1878277636, -997353517, + 201238705, 1723258694, -1107452366, -344562561, -1102247383, 1973035265, + 715213337, -1886586005, 2021214515, -1387332962, 593019378, -571088044, + 1412577760, 412164558, -1626111170, 1556494863, -289796528, -850404775, + 2066714587, -911838105, -1426027382, 499684507, -835420055, 1817119454, + -1221795958, 1516966784, -1038806877, -2115880691, 532627620, 1984437415, + -396341583, -1345366324, -590766745, -1801923449, 1752427988, -386896390, + 453906317, 1552589433, -858925718, 1160445643, -740188079, -486609040, + 1102529269, -515846212, -1614217202, 1572162207, 943558923, -467330358, + -1870764193, 1477005328, -793029208, -888983175, -696956020, 842706021, + 1642390067, -805889494, 1284862057, 1562545388, 2091626273, 1852404553, + -2076508101, 370903003, 1186422975, 1936085227, 769358463, 180401058, + 2032612572, -105461719, -1119935472, 617249831, 1169304728, 1771205256, + -2042554284, 653270859, -918610713, 336081663, -913685370, 1962213744, + -505406126, -838622649, -1141518710, 893143582, -1330296611, 122119483, + 1111564496, 688811976, 1016241049, -1803438473, 359630107, 1034798954, + -581359286, 1590946527, -389997034, 2020318460, 1695967527, -464069727, + -862641495, -1405012109, -771244841, 738226150, -1035328134, -933945474, + 1254965774, 1661863830, -884127998, 1800460481, 814702567, -1214068102, + -541120421, 1898656429, -236825530, 1505866267, 1252462132, -981007520, + 1502096471, -2134644056, 483221797, 1276403836, 541133290, -1234093967, + 350748780, 257941070, 1030457090, 434988890, -1098135432, -1000556640, + -577128022, 644806294, -787536281, -1288346343, 998079404, 1259353935, + 955771631, -958377466, 1746756252, 451579658, 1913409243, -952026299, + -1556035958, -830279881, 834744289, -1878491428, 700000962, -1027245802, + 1393574384, -1260409147, -841420884, 892132797, 1494730226, -1649181766, + 1651097838, -1041807403, -1916675721, -1324525963, 157405899, -655788033, + -1943555237, -79747022, 339721623, -138341083, 1111902411, -435322914, + -533294200, -190220608, -1718346014, -1631301894, 1706265243, 745533899, + 1351941230, 1803009594, -1218191958, 1467751062, 84368433, -711251880, + 1699423788, -768792716, 846639904, 2103267723, -2095288070, -440571408, + -362144485, 2020468971, 352105963, -849211036, -1272592429, 1743440467, + 2020667861, -1649992312, 172682343, 816705364, -1990206923, 902689869, + -298510060, 164207498, 190378213, 242531543, 113383268, 304810777, + -1081099373, 819221134, -1100982926, -855941239, 1091308887, -934548124, + 520508733, -1381763773, -491593287, -2143492665, 700894653, -2049034808, + -160942046, -2009323577, 1464245054, 1584746011, -768646852, -993282698, + 1265838699, -1873820824, 575704373, -986682955, 1270688416, 88587481, + -1723991633, -409928242, 866669946, -483811323, -181759253, -963525431, + -1686612238, -1663460076, -1128449775, -1368922329, 122318131, 795862385, + 528576131, -19927090, 1369299478, 1285665642, -738964611, 1328292127, + 552041252, -1431494354, -1205275362, 42768297, -1329537238, -449177266, + 943925221, 987016465, -945138414, -270064876, 1650366626, -369252552, + 582030210, -1229235374, 147901387, -517510506, -1609742888, -1086838308, + 1391998445, -313975512, -613392078, 855706229, 1475706341, -1112105406, + 2032001400, 1565777625, 2030937777, 435522421, 1823527907, -691390605, + -827253664, 1057171580, -314146639, -630099999, -1347514552, 478716232, + -1533658804, -1425371979, 761987780, 1560243817, -1945893959, 1205759225, + -959343783, -576742354, -154125407, -1158108776, 1183788580, 1354198127, + -1534207721, -823991517, -170534462, -912524170, 1858513573, 467072185, + 2091040157, -1765027018, -1659401643, -1173890143, -1912754057, -84568053, + 2010781784, -921970156, 944508352, -922040609, 1055102010, 1018688871, + -1186761311, -2012263648, 1311654161, 277659086, 2029602288, 1127061510, + 1029452642, 285677123, -188521091, -641039012, 653836416, -805916340, + -1644860596, 1352872213, 691634876, -1477113308, -748430369, 1030697363, + -2007864449, -1196662616, 1313997192, 177342476, -566676450, -1118618118, + 1697953104, 344671484, -1489783116, -889507873, 1259591310, -716567168, + 2116447062, 324368527, 1789366816, 1558930442, 1950250221, -785460151, + 1174714258, -430047304, -859487565, -580633932, 607732845, -1128150220, + 1544355315, 1460298016, -1771194297, 1215703690, 277231808, -416020628, + -418936577, -1724839216, 404731389, 1058730508, -1508366681, 229883053, + -572310243, 1883189553, 931286849, 1659300867, -94236383, -241524462, + 548020458, -302406981, 579986475, 73468197, -984957614, 1554382245, + 2084807492, -1456802798, -1105192593, 629440327, -16313961, -2102585261, + 1873675206, 161035128, 1497033351, 1990150811, -499405222, 304019482, + 41935663, -805987182, -571699268, 1748462913, 2096239823, -116359807, + -1871127553, -1074832534, -1558866192, 231353861, 2122854560, -2102323721, + -281462361, -343403210, -673268171, 1776058383, 1581561150, 2059580579, + 768848632, 1347190372, -1701705879, 245282007, -563267886, -592558289, + 1662399958, 1390406821, -1522485580, -706446863, 2069516289, -301855859, + -778346387, -1454093198, 1249083752, -1760506745, 262193320, 630751125, + -1495939124, -29980580, -1989626563, 659039376, -329477132, -1003507166, + -1322549020, 358606508, -2052572059, 1848014133, 1826958586, -1004948862, + -1775370541, 2134177912, -1739214473, 1892700918, 926629675, -1042761322, + 2020075900, 606370962, -1256609305, 117577265, -586848924, 191368285, + 1653535275, -1329269701, -375879127, -1089901406, 1206489978, 534223924, + -1042752982, -1178316881, -445594741, -1501682065, -1598136839, + -467688289, 750784023, 1781080461, 1729380226, 16906088, 862168532, + -2037752683, 1455274138, -1491220107, 1058323960, 1711530558, 1355062750, + 227640096, 396568027, -173579098, -408975801, -993618329, -1470751562, + 371076647, 209563718, 2015405719, -723460281, -1423934420, -2089643958, + 353260489, 2084264341, -792676687, 701391030, -1440658244, 1479321011, + 1907822880, 1232524257, -256712289, 401077577, 621808069, 868263613, + 1244930119, 2020996902, 117483907, 1341376744, -1936988014, -445200547, + -843751811, -435291191, 1041695743, 476132726, -1226874735, -1436046747, + -297047422, 1739645396, 1948680937, -718144374, 1141983978, 1673650568, + -197244350, 1604464002, 1424069853, -485626505, 1708710014, -849136541, + 1573778103, 530360999, 1777767203, 1376958336, -1088364352, 1826167753, + 742735448, -1386211659, -1991323164, -444115655, -443055378, -1586901006, + -1741686587, 1925818034, -2118916824, 803890920, -1481793154, 992278937, + 1302616410, 444517030, 1393144770, -2025632978, 1902300505, -1683582981, + 800654133, 873850324, -619580878, -2002070410, -2024936385, 1978986634, + 2012024264, 675768872, 389435615, -867217540, 231209167, -303917385, + 1445676969, -1385982721, 1310476490, 580273453, -160600202, -1330895874, + 487110497, 1124384798, 227637416, -1829783306, 1014818058, -1336870683, + -1042199518, -468525587, -1186267363, -472843891, 1215617600, -2056648329, + -873216891, 156780951, -1883246047, -842549253, -717684332, 760531638, + 1074787431, 786267513, 814031289, -561255343, -110302255, -1837376592, + 989669060, -81350614, 546038730, 222899882, 1298746805, 1791615733, + 1565630269, 1516024174, 421691479, 1860326051, -1973359550, 1854393443, + -1401468528, -158562295, 1509929255, -124024738, -462937489, 259890715, + -1515121317, -289511197, -913738664, 698079062, -1631229382, -507275144, + 1897739663, -1118192766, -1687033399, 61405556, -1913606579, -473308896, + -259107170, -576944609, -1689355510, 322156799, 545090192, 127425176, + -1815211748, -2070235628, -1172529316, 599259550, -910906653, 1797380363, + -938649427, 142991392, 504559631, 1208867355, -807699247, -616021271, + -254935281, -57151221, -1095534993, 1998380318, 1772459584, 713271407, + -1197898266, 808881935, -308133481, -1314455137, 284321772, -743117625, + -1622364240, -1667535152, 118713606, 1053615347, -2072876023, -178189072, + -828319551, 2047304928, -1311435786, -1970672907, -747972100, 86806159, + -436088421, 1464645587, 735840899, 32600466, -190473426, -735703440, + 482872155, 475662392, -713681085, 1424078728, -150668609, -1137197868, + -1682762563, -48035649, 1143959866, -1542015129, 284920371, -1587695586, + -625236551, -753893357, -433976266, -1329796037, -1636712478, 1686783454, + 27839146, 1748631474, -879528256, 2057796026, 773734654, 112269667, + -2011541314, 1517797297, -1943171794, 268166111, -1037010413, -1945824504, + -1672323792, 306260758, -692968628, -701704965, -462980996, 939188824, + 553289792, 1790245000, 2093793129, -658085781, -186055037, -2130433650, + -1013235433, 1190870089, -2126586963, -1509655742, -1291895256, + -1427857845, 309538950, 388316741, 259659733, -1895092434, 110126220, + -170175575, -419430224, -696234084, -832170948, -353431720, -797675726, + -1644136054, 715163272, -1305904349, -145786463, -99586244, -695450446, + -871327102, -725496060, 952863853, -688441983, -1729929460, -103732092, + 1059054528, 568873585, -982665223, -128672783, 2099418320, 1508239336, + -2089480835, -390935727, 664306522, -1607364342, -163246802, -1121295140, + -128375779, -615694409, -2079391797, 760542037, 677761593, -750117849, + -1060525080, 2128437080, 525250908, 1987657172, 2032530557, -2011247936, + 1942775263, 1681562788, 688229491, -803856505, 684707948, 1308988965, + 1455480037, 790659611, 1557968784, -383203149, -361510986, -742575828, + 558837193, -1214977424, 1253274105, -119513513, -993964385, -33438767, + -177452803, 1186928041, -2073533871, 1188528559, 1896514695, 1200128512, + 1930588755, -1914141443, 1534656032, -1192989829, -1848274656, -220848455, + 1001806509, 1298797392, 1533031884, -1912322446, 1705583815, 1568094347, + -1397640627, 807828512, -1852996497, -1529733505, -1575634185, + -1280270160, -1567624159, -1861904922, 1276738579, 1163432999, 626879833, + 316942006, -1871138342, 1341039701, 1595907877, 1950911580, 1634717748, + 1071476055, -809354290, -1161553341, -2081621710, -2085557943, 19360224, + 322135580, -698485151, 1267663094, -233890834, -126361189, -1426257522, + 1094007921, 500179855, -283548002, -1678987343, 1946999943, 1489410849, + 2089571262, 1430799093, 1961848046, -99462663, -552833264, 1168700661, + -1783882181, 2089196401, 1092839657, 914488673, 80263859, -2140947098, + -726384741, -1022448237, 2113887675, 1485770846, -112922517, 1995461466, + 774613726, 944068011, 1521975359, 289086919, -386920759, -1960513175, + 358460021, -238698524, -1913640563, -1000324864, 1731755224, -1271586254, + -1917469655, 2134162829, -828097534, -1089292503, -1514835999, 1682931514, + -482307169, 2110243841, 115744834, -2038340170, 65889188, -539445712, + -1713206408, -1842396726, -1659545588, -909558923, 860164922, 1328713040, + 1044007120, -2103807103, -1073990344, -1312783785, -884980824, -705318011, + -1263408788, -2032228692, -1732844111, -1813827156, 1462566279, + 1179250845, 1732421772, 604429013, -92284336, -1192166516, 304654351, + 1998552034, -1802461575, -1802704071, -1704833934, -976264396, 1005840702, + 2108843914, 1363909309, 843040834, -1039625241, 1285007226, 91610001, + 418426329, 678422358, -945360697, -440008081, -1053091357, 425719777, + -1372778676, 591912153, 1229089037, -56663158, 2140251400, 830257037, + 763914157, 175610373, -2105655963, -1040826150, 1174443038, 339290593, + 346618443, -180504100, -1363190515, 210620018, 1028894425, 573529714, + 698460117, 136999397, 1015621712, -1401813739, -297990684, -1820934845, + -1299093313, 1299361369, -366522415, 91527707, 1113466178, -956229484, + 22204763, -1394374195, -1912666711, -1453789804, 1613408399, -169509567, + 1350520309, 540761213, -2086682848, 1095131491, -812787911, 1860108594, + -1121378737, -1667252487, -486084366, 166519760, 1609891237, 728218405, + 291075010, 646168382, 108462277, -1616661910, 1016600360, 2099958568, + 27934736, 183821196, 13660496, -805589719, 936068730, -439037934, + 1414622584, 215845485, -1352304469, -1817427526, -1318710977, -110207199, + 228524335, 1704746590, 998293651, -1521016702, -641956531, -2089808167, + 2094404052, -1446381065, -662186492, 1670154584, 9637833, 493925511, + 660047318, 1197537103, 1696017374, -204994399, -1104145601, -852330465, + -1936369658, -829716674, -1255255217, 1264013799, 1642611772, -652520861, + 777247164, 2028895987, -1424241853, -54367829, -1940161761, -1802831079, + -449405299, 838242661, -323055438, 794295411, -136989378, -446686673, + -421252799, -16777216, +}; + +int +main (int argc, char *argv[]) +{ + char buf[1024]; + int i; + + GNUNET_log_setup ("test-crypto-crc", "WARNING", NULL); + for (i = 0; i < 1024; i++) + buf[i] = (char) i; + for (i = 0; i < 1024; i++) + if (expected[i] != GNUNET_CRYPTO_crc32_n (&buf[i], 1024 - i)) + return 1; + return 0; +} diff --git a/src/util/test_crypto_hash.c b/src/util/test_crypto_hash.c new file mode 100644 index 0000000..bc04114 --- /dev/null +++ b/src/util/test_crypto_hash.c @@ -0,0 +1,166 @@ +/* + This file is part of GNUnet. + (C) 2002, 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Christian Grothoff + * @file util/test_crypto_hash.c + * @brief Test for crypto_hash.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_scheduler_lib.h" + +static char block[65536]; + +#define FILENAME "testblock.dat" + +static int +test (int number) +{ + GNUNET_HashCode h1; + GNUNET_HashCode h2; + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + + memset (&h1, number, sizeof (GNUNET_HashCode)); + GNUNET_CRYPTO_hash_to_enc (&h1, &enc); + if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &h2)) + { + printf ("enc2hash failed!\n"); + return 1; + } + if (0 != memcmp (&h1, &h2, sizeof (GNUNET_HashCode))) + return 1; + return 0; +} + +static int +testEncoding () +{ + int i; + + for (i = 0; i < 255; i++) + if (0 != test (i)) + return 1; + return 0; +} + +static int +testArithmetic () +{ + static struct GNUNET_CRYPTO_AesSessionKey zskey; + static struct GNUNET_CRYPTO_AesInitializationVector ziv; + GNUNET_HashCode h1; + GNUNET_HashCode h2; + GNUNET_HashCode d; + GNUNET_HashCode s; + struct GNUNET_CRYPTO_AesSessionKey skey; + struct GNUNET_CRYPTO_AesInitializationVector iv; + + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &h1); + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &h2); + if (GNUNET_CRYPTO_hash_distance_u32 (&h1, &h2) != + GNUNET_CRYPTO_hash_distance_u32 (&h2, &h1)) + return 1; + GNUNET_CRYPTO_hash_difference (&h1, &h2, &d); + GNUNET_CRYPTO_hash_sum (&h1, &d, &s); + if (0 != GNUNET_CRYPTO_hash_cmp (&s, &h2)) + return 1; + GNUNET_CRYPTO_hash_xor (&h1, &h2, &d); + GNUNET_CRYPTO_hash_xor (&h1, &d, &s); + if (0 != GNUNET_CRYPTO_hash_cmp (&s, &h2)) + return 1; + if (0 != GNUNET_CRYPTO_hash_xorcmp (&s, &h2, &h1)) + return 1; + if (-1 != GNUNET_CRYPTO_hash_xorcmp (&h1, &h2, &h1)) + return 1; + if (1 != GNUNET_CRYPTO_hash_xorcmp (&h1, &h2, &h2)) + return 1; + memset (&d, 0xF0, sizeof (d)); + if (0 != GNUNET_CRYPTO_hash_get_bit (&d, 3)) + return 1; + if (1 != GNUNET_CRYPTO_hash_get_bit (&d, 6)) + return 1; + memset (&d, 0, sizeof (d)); + GNUNET_CRYPTO_hash_to_aes_key (&d, &skey, &iv); + if ((0 != memcmp (&skey, &zskey, sizeof (skey) - sizeof (unsigned int))) || + (0 != memcmp (&iv, &ziv, sizeof (iv)))) + return 1; + return 0; +} + +static void +finished_task (void *cls, const GNUNET_HashCode * res) +{ + int *ret = cls; + GNUNET_HashCode want; + + GNUNET_CRYPTO_hash (block, sizeof (block), &want); + if (0 != memcmp (res, &want, sizeof (want))) + *ret = 2; + else + *ret = 0; +} + + +static void +file_hasher (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (NULL != + GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + FILENAME, 1024, &finished_task, cls)); +} + + +static int +testFileHash () +{ + int ret; + FILE *f; + + memset (block, 42, sizeof (block) / 2); + memset (&block[sizeof (block) / 2], 43, sizeof (block) / 2); + GNUNET_assert (NULL != (f = FOPEN (FILENAME, "w+"))); + GNUNET_break (sizeof (block) == fwrite (block, 1, sizeof (block), f)); + GNUNET_break (0 == FCLOSE (f)); + ret = 1; + GNUNET_SCHEDULER_run (&file_hasher, &ret); + GNUNET_break (0 == UNLINK (FILENAME)); + return ret; +} + + +int +main (int argc, char *argv[]) +{ + int failureCount = 0; + int i; + + GNUNET_log_setup ("test-crypto-hash", "WARNING", NULL); + for (i = 0; i < 10; i++) + failureCount += testEncoding (); + failureCount += testArithmetic (); + failureCount += testFileHash (); + if (failureCount != 0) + return 1; + return 0; +} + +/* end of hashingtest.c */ diff --git a/src/util/test_crypto_hkdf.c b/src/util/test_crypto_hkdf.c new file mode 100644 index 0000000..7521161 --- /dev/null +++ b/src/util/test_crypto_hkdf.c @@ -0,0 +1,351 @@ +/* + Copyright (c) 2010 Nils Durner + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/** + * @file src/util/test_crypt_hkdf.c + * @brief Testcases for HKDF + * @todo: test for out_len < hash_len + * @author Nils Durner + */ + +#include + +#include "platform.h" +#include "gnunet_crypto_lib.h" + +void +tc1 () +{ + unsigned char ikm[22] = + { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b + }; + unsigned char salt[13] = + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c + }; + unsigned char info[10] = + { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; + unsigned char okm[42] = + { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, + 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, + 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, + 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65 + }; + unsigned char result[44]; + int l = 42; + + memset (result, 0, sizeof (result)); + GNUNET_assert (GNUNET_CRYPTO_hkdf + (result, l, GCRY_MD_SHA256, GCRY_MD_SHA256, salt, + sizeof (salt), ikm, sizeof (ikm), info, sizeof (info), + NULL) == GNUNET_YES); + GNUNET_assert (memcmp (result, okm, l) == 0); + GNUNET_assert (memcmp (result + l, "\0", 2) == 0); +} + +void +tc2 () +{ + unsigned char ikm[80] = + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f + }; + unsigned char salt[80] = + { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, + 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf + }; + unsigned char info[80] = + { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, + 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, + 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }; + unsigned char okm[82] = + { 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, + 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, + 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, + 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, + 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, + 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, + 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87 + }; + char result[84]; + int l = 82; + + memset (result, 0, sizeof (result)); + GNUNET_assert (GNUNET_CRYPTO_hkdf + (result, l, GCRY_MD_SHA256, GCRY_MD_SHA256, salt, + sizeof (salt), ikm, sizeof (ikm), info, sizeof (info), + NULL) == GNUNET_YES); + GNUNET_assert (memcmp (result, okm, l) == 0); + GNUNET_assert (memcmp (result + l, "\0", 2) == 0); +} + +void +tc3 () +{ + unsigned char ikm[22] = + { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b + }; + unsigned char okm[42] = + { 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, + 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, + 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, + 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8 + }; + unsigned char result[44]; + int l = 42; + + memset (result, 0, sizeof (result)); + GNUNET_assert (GNUNET_CRYPTO_hkdf + (result, l, GCRY_MD_SHA256, GCRY_MD_SHA256, NULL, 0, ikm, + sizeof (ikm), NULL, 0, NULL) == GNUNET_YES); + GNUNET_assert (memcmp (result, okm, l) == 0); + GNUNET_assert (memcmp (result + l, "\0", 2) == 0); +} + +void +tc4 () +{ + unsigned char ikm[11] = + { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b + }; + unsigned char salt[13] = + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c + }; + unsigned char info[10] = + { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; + unsigned char okm[42] = + { 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, 0x33, 0x06, + 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81, 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, + 0x09, 0x15, 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2, 0xc2, 0x2e, + 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, 0xf8, 0x96 + }; + char result[84]; + int l = 42; + + memset (result, 0, sizeof (result)); + GNUNET_assert (GNUNET_CRYPTO_hkdf + (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, salt, sizeof (salt), + ikm, sizeof (ikm), info, sizeof (info), NULL) == GNUNET_YES); + GNUNET_assert (memcmp (result, okm, l) == 0); + GNUNET_assert (memcmp (result + l, "\0", 2) == 0); +} + +void +tc5 () +{ + unsigned char ikm[80] = + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f + }; + unsigned char salt[80] = + { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, + 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf + }; + unsigned char info[80] = + { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, + 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, + 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }; + unsigned char okm[82] = + { 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, + 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, + 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3, + 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, + 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c, + 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, + 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4 + }; + char result[84]; + int l = 82; + + memset (result, 0, sizeof (result)); + GNUNET_assert (GNUNET_CRYPTO_hkdf + (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, salt, sizeof (salt), + ikm, sizeof (ikm), info, sizeof (info), NULL) == GNUNET_YES); + GNUNET_assert (memcmp (result, okm, l) == 0); + GNUNET_assert (memcmp (result + l, "\0", 2) == 0); +} + +void +tc6 () +{ + unsigned char ikm[22] = + { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b + }; + unsigned char okm[42] = + { 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, 0xd1, 0xe5, + 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06, 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, + 0xa3, 0x06, 0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0, 0xea, 0x00, + 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3, 0x49, 0x18 + }; + char result[44]; + int l = 42; + + memset (result, 0, sizeof (result)); + GNUNET_assert (GNUNET_CRYPTO_hkdf + (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, NULL, 0, ikm, + sizeof (ikm), NULL, 0, NULL) == GNUNET_YES); + GNUNET_assert (memcmp (result, okm, l) == 0); + GNUNET_assert (memcmp (result + l, "\0", 2) == 0); +} + +void +tc7 () +{ + unsigned char ikm[80] = + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f + }; + unsigned char salt[80] = + { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, + 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf + }; + unsigned char info1[34] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1 + }; + unsigned char info2[46] = { 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, + 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, + 0xfe, 0xff + }; + unsigned char okm[82] = + { 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, + 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, + 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3, + 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, + 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c, + 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, + 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4 + }; + char result[84]; + int l = 82; + + memset (result, 0, sizeof (result)); + GNUNET_assert (GNUNET_CRYPTO_hkdf + (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, salt, sizeof (salt), + ikm, sizeof (ikm), info1, sizeof (info1), info2, + sizeof (info2), NULL) == GNUNET_YES); + GNUNET_assert (memcmp (result, okm, l) == 0); + GNUNET_assert (memcmp (result + l, "\0", 2) == 0); +} + +void +tc8 () +{ + unsigned char ikm[32] = + { 0xbf, 0x16, 0x6e, 0x46, 0x3a, 0x6c, 0xf3, 0x93, 0xa7, 0x72, + 0x11, 0xa1, 0xdc, 0x0b, 0x07, 0xdb, 0x1a, 0x5e, 0xd9, 0xb9, 0x81, 0xbe, + 0xea, 0xe4, 0x31, 0x5f, 0x24, 0xff, 0xfe, 0x50, 0x8a, 0xde + }; + unsigned char salt[4] = { 0xfc, 0x62, 0x76, 0x35 }; + unsigned char info[86] = + { 0x8c, 0x0d, 0xcf, 0xb3, 0x25, 0x6e, 0x88, 0x0d, 0xc1, 0x0b, + 0x1d, 0x33, 0x15, 0x3e, 0x52, 0x0b, 0xb0, 0x77, 0xff, 0x7d, 0xc3, 0xc7, + 0xef, 0xe5, 0x8e, 0x3c, 0xc4, 0x4e, 0x8b, 0x41, 0x46, 0x1f, 0x02, 0x94, + 0x82, 0x35, 0xc5, 0xa6, 0x5e, 0x91, 0xd8, 0xa2, 0x90, 0xfd, 0x6f, 0xb4, + 0x07, 0xc9, 0xed, 0x6b, 0x18, 0x90, 0x31, 0xab, 0x0f, 0xb5, 0x6b, 0xec, + 0x9e, 0x45, 0xa2, 0x83, 0x65, 0x41, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, + 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x00 + }; + unsigned char okm[16] = + { 0xd6, 0x90, 0xec, 0x9e, 0x62, 0xdf, 0xb9, 0x41, 0xff, 0x92, + 0x4f, 0xd2, 0xf6, 0x1d, 0x67, 0xe0 + }; + char result[18]; + int l = 16; + + memset (result, 0, sizeof (result)); + GNUNET_assert (GNUNET_CRYPTO_hkdf + (result, l, GCRY_MD_SHA512, GCRY_MD_SHA256, salt, + sizeof (salt), ikm, sizeof (ikm), info, sizeof (info), + NULL) == GNUNET_YES); + GNUNET_assert (memcmp (result, okm, l) == 0); + GNUNET_assert (memcmp (result + l, "\0", 2) == 0); +} + +int +main () +{ + GNUNET_log_setup ("test-crypto-hkdf", "WARNING", NULL); + + /* Official test vectors */ + tc1 (); + tc2 (); + tc3 (); + tc4 (); + tc5 (); + tc6 (); + + /* Additional tests */ + tc7 (); + tc8 (); + + return 0; +} diff --git a/src/util/test_crypto_ksk.c b/src/util/test_crypto_ksk.c new file mode 100644 index 0000000..58c4595 --- /dev/null +++ b/src/util/test_crypto_ksk.c @@ -0,0 +1,260 @@ +/* + This file is part of GNUnet. + Copyright (C) 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_crypto_ksk.c + * @brief testcase for util/crypto_ksk.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_signatures.h" +#include "gnunet_time_lib.h" + +#define TESTSTRING "Hello World\0" +#define MAX_TESTVAL 20 +#define UNIQUE_ITER 6 +#define ITER 25 + + +static int +testCorrectKey () +{ + const char *want = + "010601000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b73c215f7a5e6b09bec55713c901786c09324a150980e014bdb0d04426934929c3b4971a9711af5455536cd6eeb8bfa004ee904972a737455f53c752987d8c82b755bc02882b44950c4acdc1672ba74c3b94d81a4c1ea3d74e7700ae5594c3a4f3c559e4bff2df6844fac302e4b66175e14dc8bad3ce44281d2fec1a1abef06301010000"; + GNUNET_HashCode in; + struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + int i; + char out[3]; + + FPRINTF (stderr, "%s", "Testing KBlock key correctness"); + GNUNET_CRYPTO_hash ("X", strlen ("X"), &in); + hostkey = GNUNET_CRYPTO_rsa_key_create_from_hash (&in); + if (hostkey == NULL) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); + GNUNET_CRYPTO_rsa_key_free (hostkey); +#if 0 + for (i = 0; i < sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded); i++) + printf ("%02x", ((unsigned char *) &pkey)[i]); + printf ("\n"); +#endif + for (i = 0; i < sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded); i++) + { + snprintf (out, sizeof (out), "%02x", ((unsigned char *) &pkey)[i]); + if (0 != strncmp (out, &want[i * 2], 2)) + { + FPRINTF (stderr, " Failed! Wanted %.2s but got %2s at %d\n", &want[i * 2], + out, i); + return GNUNET_SYSERR; + } + } + FPRINTF (stderr, "%s", " OK\n"); + return GNUNET_OK; +} + + +static int +testMultiKey (const char *word) +{ + GNUNET_HashCode in; + struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey1; + int i; + + FPRINTF (stderr, "Testing KBlock key uniqueness (%s) ", word); + GNUNET_CRYPTO_hash (word, strlen (word), &in); + hostkey = GNUNET_CRYPTO_rsa_key_create_from_hash (&in); + if (hostkey == NULL) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); + /* + * for (i=0;i (buf[i] = GNUNET_CRYPTO_random_u32 (mode, 1024))); + for (i = 0; i < 10; i++) + { + b2 = GNUNET_CRYPTO_random_permute (mode, 1024); + if (0 == memcmp (b2, buf, sizeof (buf))) + { + FPRINTF (stderr, "%s", "!"); + GNUNET_free (b2); + continue; + } + GNUNET_free (b2); + break; + } + if (i == 10) + return 1; /* virtually impossible... */ + + for (n = 10; n < 1024LL * 1024LL * 1024LL; n *= 10) + GNUNET_break (n > GNUNET_CRYPTO_random_u64 (mode, n)); + return 0; +} + +int +main (int argc, char *argv[]) +{ + GNUNET_log_setup ("test-crypto-random", "WARNING", NULL); + if (0 != test (GNUNET_CRYPTO_QUALITY_WEAK)) + return 1; + if (0 != test (GNUNET_CRYPTO_QUALITY_STRONG)) + return 1; + + return 0; +} diff --git a/src/util/test_crypto_rsa.c b/src/util/test_crypto_rsa.c new file mode 100644 index 0000000..f6800af --- /dev/null +++ b/src/util/test_crypto_rsa.c @@ -0,0 +1,334 @@ +/* + This file is part of GNUnet. + (C) 2002, 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +/** + * @file util/test_crypto_rsa.c + * @brief testcase for RSA public key crypto + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_signatures.h" +#include "gnunet_time_lib.h" + +#define TESTSTRING "Hello World\0" +#define MAX_TESTVAL sizeof(struct GNUNET_CRYPTO_AesSessionKey) +#define ITER 25 +#define KEYFILE "/tmp/test-gnunet-crypto-rsa.key" + +#define PERF GNUNET_YES + +static int +testEncryptDecrypt () +{ + struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + struct GNUNET_CRYPTO_RsaEncryptedData target; + char result[MAX_TESTVAL]; + int i; + struct GNUNET_TIME_Absolute start; + int ok; + + FPRINTF (stderr, "%s", "W"); + hostkey = GNUNET_CRYPTO_rsa_key_create (); + GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); + + ok = 0; + start = GNUNET_TIME_absolute_get (); + for (i = 0; i < ITER; i++) + { + FPRINTF (stderr, "%s", "."); + if (GNUNET_SYSERR == + GNUNET_CRYPTO_rsa_encrypt (TESTSTRING, strlen (TESTSTRING) + 1, &pkey, + &target)) + { + FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_encrypt returned SYSERR\n"); + ok++; + continue; + } + if (-1 == + GNUNET_CRYPTO_rsa_decrypt (hostkey, &target, result, + strlen (TESTSTRING) + 1)) + { + FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_decrypt returned SYSERR\n"); + ok++; + continue; + + } + if (strncmp (TESTSTRING, result, strlen (TESTSTRING)) != 0) + { + printf ("%s != %.*s - testEncryptDecrypt failed!\n", TESTSTRING, + (int) MAX_TESTVAL, result); + ok++; + continue; + } + } + printf ("%d RSA encrypt/decrypt operations %llums (%d failures)\n", ITER, + (unsigned long long) + GNUNET_TIME_absolute_get_duration (start).rel_value, ok); + GNUNET_CRYPTO_rsa_key_free (hostkey); + if (ok == 0) + return GNUNET_OK; + else + return GNUNET_SYSERR; +} + +#if PERF +static int +testEncryptPerformance () +{ + struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + struct GNUNET_CRYPTO_RsaEncryptedData target; + int i; + struct GNUNET_TIME_Absolute start; + int ok; + + FPRINTF (stderr, "%s", "W"); + hostkey = GNUNET_CRYPTO_rsa_key_create (); + GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); + + ok = 0; + start = GNUNET_TIME_absolute_get (); + for (i = 0; i < ITER; i++) + { + FPRINTF (stderr, "%s", "."); + if (GNUNET_SYSERR == + GNUNET_CRYPTO_rsa_encrypt (TESTSTRING, strlen (TESTSTRING) + 1, &pkey, + &target)) + { + FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_encrypt returned SYSERR\n"); + ok++; + continue; + } + } + printf ("%d RSA encrypt operations %llu ms (%d failures)\n", ITER, + (unsigned long long) + GNUNET_TIME_absolute_get_duration (start).rel_value, ok); + GNUNET_CRYPTO_rsa_key_free (hostkey); + if (ok != 0) + return GNUNET_SYSERR; + return GNUNET_OK; +} +#endif + +static int +testEncryptDecryptSK () +{ + struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + struct GNUNET_CRYPTO_RsaEncryptedData target; + struct GNUNET_CRYPTO_AesSessionKey insk; + struct GNUNET_CRYPTO_AesSessionKey outsk; + int i; + struct GNUNET_TIME_Absolute start; + int ok; + + FPRINTF (stderr, "%s", "W"); + hostkey = GNUNET_CRYPTO_rsa_key_create (); + GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); + + ok = 0; + start = GNUNET_TIME_absolute_get (); + for (i = 0; i < ITER; i++) + { + FPRINTF (stderr, "%s", "."); + GNUNET_CRYPTO_aes_create_session_key (&insk); + if (GNUNET_SYSERR == + GNUNET_CRYPTO_rsa_encrypt (&insk, + sizeof (struct GNUNET_CRYPTO_AesSessionKey), + &pkey, &target)) + { + FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_encrypt returned SYSERR\n"); + ok++; + continue; + } + if (-1 == + GNUNET_CRYPTO_rsa_decrypt (hostkey, &target, &outsk, + sizeof (struct GNUNET_CRYPTO_AesSessionKey))) + { + FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_decrypt returned SYSERR\n"); + ok++; + continue; + } + if (0 != + memcmp (&insk, &outsk, sizeof (struct GNUNET_CRYPTO_AesSessionKey))) + { + printf ("testEncryptDecryptSK failed!\n"); + ok++; + continue; + } + } + printf ("%d RSA encrypt/decrypt SK operations %llums (%d failures)\n", ITER, + (unsigned long long) + GNUNET_TIME_absolute_get_duration (start).rel_value, ok); + GNUNET_CRYPTO_rsa_key_free (hostkey); + if (ok != 0) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +static int +testSignVerify () +{ + struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; + struct GNUNET_CRYPTO_RsaSignature sig; + struct GNUNET_CRYPTO_RsaSignaturePurpose purp; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + int i; + struct GNUNET_TIME_Absolute start; + int ok = GNUNET_OK; + + FPRINTF (stderr, "%s", "W"); + hostkey = GNUNET_CRYPTO_rsa_key_create (); + GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); + start = GNUNET_TIME_absolute_get (); + purp.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)); + purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST); + + for (i = 0; i < ITER; i++) + { + FPRINTF (stderr, "%s", "."); + if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_sign (hostkey, &purp, &sig)) + { + FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_sign returned SYSERR\n"); + ok = GNUNET_SYSERR; + continue; + } + if (GNUNET_SYSERR == + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TEST, &purp, &sig, + &pkey)) + { + printf ("GNUNET_CRYPTO_rsa_verify failed!\n"); + ok = GNUNET_SYSERR; + continue; + } + if (GNUNET_SYSERR != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN, + &purp, &sig, &pkey)) + { + printf ("GNUNET_CRYPTO_rsa_verify failed to fail!\n"); + ok = GNUNET_SYSERR; + continue; + } + } + printf ("%d RSA sign/verify operations %llums\n", ITER, + (unsigned long long) + GNUNET_TIME_absolute_get_duration (start).rel_value); + GNUNET_CRYPTO_rsa_key_free (hostkey); + return ok; +} + + +#if PERF +static int +testSignPerformance () +{ + struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; + struct GNUNET_CRYPTO_RsaSignaturePurpose purp; + struct GNUNET_CRYPTO_RsaSignature sig; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + int i; + struct GNUNET_TIME_Absolute start; + int ok = GNUNET_OK; + + purp.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)); + purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST); + FPRINTF (stderr, "%s", "W"); + hostkey = GNUNET_CRYPTO_rsa_key_create (); + GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); + start = GNUNET_TIME_absolute_get (); + for (i = 0; i < ITER; i++) + { + FPRINTF (stderr, "%s", "."); + if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_sign (hostkey, &purp, &sig)) + { + FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_sign returned SYSERR\n"); + ok = GNUNET_SYSERR; + continue; + } + } + printf ("%d RSA sign operations %llu ms\n", ITER, + (unsigned long long) + GNUNET_TIME_absolute_get_duration (start).rel_value); + GNUNET_CRYPTO_rsa_key_free (hostkey); + return ok; +} +#endif + + +static int +testCreateFromFile () +{ + struct GNUNET_CRYPTO_RsaPrivateKey *key; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded p1; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded p2; + + key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE); + GNUNET_assert (NULL != key); + GNUNET_CRYPTO_rsa_key_get_public (key, &p1); + GNUNET_CRYPTO_rsa_key_free (key); + key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE); + GNUNET_assert (NULL != key); + GNUNET_CRYPTO_rsa_key_get_public (key, &p2); + GNUNET_assert (0 == memcmp (&p1, &p2, sizeof (p1))); + GNUNET_CRYPTO_rsa_key_free (key); + GNUNET_assert (0 == UNLINK (KEYFILE)); + key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE); + GNUNET_assert (NULL != key); + GNUNET_CRYPTO_rsa_key_get_public (key, &p2); + GNUNET_assert (0 != memcmp (&p1, &p2, sizeof (p1))); + GNUNET_CRYPTO_rsa_key_free (key); + GNUNET_assert (0 == UNLINK (KEYFILE)); + return GNUNET_OK; +} + + +int +main (int argc, char *argv[]) +{ + int failureCount = 0; + + GNUNET_log_setup ("test-crypto-rsa", "WARNING", NULL); + GNUNET_CRYPTO_random_disable_entropy_gathering (); + if (GNUNET_OK != testCreateFromFile ()) + failureCount++; +#if PERF + if (GNUNET_OK != testEncryptPerformance ()) + failureCount++; + if (GNUNET_OK != testSignPerformance ()) + failureCount++; +#endif + if (GNUNET_OK != testEncryptDecryptSK ()) + failureCount++; + if (GNUNET_OK != testEncryptDecrypt ()) + failureCount++; + if (GNUNET_OK != testSignVerify ()) + failureCount++; + + if (failureCount != 0) + { + printf ("\n\n%d TESTS FAILED!\n\n", failureCount); + return -1; + } + return 0; +} /* end of main */ diff --git a/src/util/test_disk.c b/src/util/test_disk.c new file mode 100644 index 0000000..5462772 --- /dev/null +++ b/src/util/test_disk.c @@ -0,0 +1,283 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_disk.c + * @brief testcase for the storage module + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_disk_lib.h" +#include "gnunet_scheduler_lib.h" + +#define TESTSTRING "Hello World\0" + +static int +testReadWrite () +{ + char tmp[100 + 1]; + int ret; + + if (strlen (TESTSTRING) != + GNUNET_DISK_fn_write (".testfile", TESTSTRING, strlen (TESTSTRING), + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE)) + return 1; + if (GNUNET_OK != GNUNET_DISK_file_test (".testfile")) + return 1; + ret = GNUNET_DISK_fn_read (".testfile", tmp, sizeof (tmp) - 1); + if (ret < 0) + { + FPRINTF (stderr, "Error reading file `%s' in testReadWrite\n", ".testfile"); + return 1; + } + tmp[ret] = '\0'; + if (0 != memcmp (tmp, TESTSTRING, strlen (TESTSTRING) + 1)) + { + FPRINTF (stderr, "Error in testReadWrite: *%s* != *%s* for file %s\n", tmp, + TESTSTRING, ".testfile"); + return 1; + } + GNUNET_DISK_file_copy (".testfile", ".testfile2"); + memset (tmp, 0, sizeof (tmp)); + ret = GNUNET_DISK_fn_read (".testfile2", tmp, sizeof (tmp) - 1); + if (ret < 0) + { + FPRINTF (stderr, "Error reading file `%s' in testReadWrite\n", + ".testfile2"); + return 1; + } + tmp[ret] = '\0'; + if (0 != memcmp (tmp, TESTSTRING, strlen (TESTSTRING) + 1)) + { + FPRINTF (stderr, "Error in testReadWrite: *%s* != *%s* for file %s\n", tmp, + TESTSTRING, ".testfile2"); + return 1; + } + + GNUNET_break (0 == UNLINK (".testfile")); + GNUNET_break (0 == UNLINK (".testfile2")); + if (GNUNET_NO != GNUNET_DISK_file_test (".testfile")) + return 1; + + return 0; +} + +static int +testOpenClose () +{ + struct GNUNET_DISK_FileHandle *fh; + uint64_t size; + long avail; + + fh = GNUNET_DISK_file_open (".testfile", + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + GNUNET_assert (GNUNET_NO == GNUNET_DISK_handle_invalid (fh)); + GNUNET_break (5 == GNUNET_DISK_file_write (fh, "Hello", 5)); + GNUNET_DISK_file_close (fh); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_size (".testfile", &size, GNUNET_NO)); + if (size != 5) + return 1; + GNUNET_break (0 == UNLINK (".testfile")); + + /* test that avail goes down as we fill the disk... */ + GNUNET_log_skip (1, GNUNET_NO); + avail = GNUNET_DISK_get_blocks_available (".testfile"); + GNUNET_log_skip (0, GNUNET_NO); + fh = GNUNET_DISK_file_open (".testfile", + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_WRITE | + GNUNET_DISK_PERM_USER_READ); + GNUNET_assert (GNUNET_NO == GNUNET_DISK_handle_invalid (fh)); + while ((avail == GNUNET_DISK_get_blocks_available (".testfile")) && + (avail != -1)) + if (16 != GNUNET_DISK_file_write (fh, "HelloWorld123456", 16)) + { + GNUNET_DISK_file_close (fh); + GNUNET_break (0 == UNLINK (".testfile")); + return 1; + } + GNUNET_DISK_file_close (fh); + GNUNET_break (0 == UNLINK (".testfile")); + + return 0; +} + +static int ok; + +static int +scan_callback (void *want, const char *filename) +{ + if (NULL != strstr (filename, want)) + ok++; + return GNUNET_OK; +} + +static int +testDirScan () +{ + if (GNUNET_OK != + GNUNET_DISK_directory_create ("test" DIR_SEPARATOR_STR "entry")) + return 1; + if (GNUNET_OK != + GNUNET_DISK_directory_create ("test" DIR_SEPARATOR_STR "entry_more")) + return 1; + GNUNET_DISK_directory_scan ("test", &scan_callback, + "test" DIR_SEPARATOR_STR "entry"); + if (GNUNET_OK != GNUNET_DISK_directory_remove ("test")) + return 1; + if (ok < 2) + return 1; + return 0; +} + +static void +iter_callback (void *cls, struct GNUNET_DISK_DirectoryIterator *di, + const char *filename, const char *dirname) +{ + int *i = cls; + + (*i)++; + GNUNET_DISK_directory_iterator_next (di, GNUNET_NO); +} + +static void +iter_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_DISK_directory_iterator_start (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + "test", &iter_callback, cls); +} + +static int +testDirIter () +{ + int i; + + i = 0; + if (GNUNET_OK != GNUNET_DISK_directory_create ("test/entry")) + return 1; + if (GNUNET_OK != GNUNET_DISK_directory_create ("test/entry_many")) + return 1; + if (GNUNET_OK != GNUNET_DISK_directory_create ("test/entry_more")) + return 1; + GNUNET_SCHEDULER_run (&iter_task, &i); + if (GNUNET_OK != GNUNET_DISK_directory_remove ("test")) + return 1; + if (i < 3) + return 1; + return 0; +} + + +static int +testGetHome () +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + char *fn; + int ret; + + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_assert (cfg != NULL); + GNUNET_CONFIGURATION_set_value_string (cfg, "service", "HOME", + "/tmp/test-gnunet-disk-a/b/c"); + fn = GNUNET_DISK_get_home_filename (cfg, "service", "d", "e", NULL); + GNUNET_assert (fn != NULL); + GNUNET_CONFIGURATION_destroy (cfg); + ret = strcmp ("/tmp/test-gnunet-disk-a/b/c/d/e", fn); + GNUNET_free (fn); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-disk-a")); + return ret; +} + +static int +testCanonicalize () +{ + char *fn = GNUNET_strdup ("ab?><|cd*ef:/g\""); + + GNUNET_DISK_filename_canonicalize (fn); + if (0 != strcmp (fn, "ab____cd_ef__g_")) + { + GNUNET_free (fn); + return 1; + } + GNUNET_free (fn); + return 0; +} + +static int +testChangeOwner () +{ + GNUNET_log_skip (1, GNUNET_NO); + if (GNUNET_OK == GNUNET_DISK_file_change_owner ("/dev/null", "unknownuser")) + return 1; + return 0; +} + +static int +testDirMani () +{ + if (GNUNET_OK != GNUNET_DISK_directory_create_for_file ("test/ing")) + return 1; + if (GNUNET_NO != GNUNET_DISK_file_test ("test")) + return 1; + if (GNUNET_NO != GNUNET_DISK_file_test ("test/ing")) + return 1; + if (GNUNET_OK != GNUNET_DISK_directory_remove ("test")) + return 1; + if (GNUNET_OK != GNUNET_DISK_directory_create ("test")) + return 1; + if (GNUNET_YES != GNUNET_DISK_directory_test ("test")) + return 1; + if (GNUNET_OK != GNUNET_DISK_directory_remove ("test")) + return 1; + + + return 0; +} + + +int +main (int argc, char *argv[]) +{ + unsigned int failureCount = 0; + + GNUNET_log_setup ("test-disk", "WARNING", NULL); + failureCount += testReadWrite (); + failureCount += testOpenClose (); + failureCount += testDirScan (); + failureCount += testDirIter (); + failureCount += testGetHome (); + failureCount += testCanonicalize (); + failureCount += testChangeOwner (); + failureCount += testDirMani (); + if (failureCount != 0) + { + FPRINTF (stderr, "\n%u TESTS FAILED!\n", failureCount); + return -1; + } + return 0; +} /* end of main */ diff --git a/src/util/test_getopt.c b/src/util/test_getopt.c new file mode 100644 index 0000000..a517887 --- /dev/null +++ b/src/util/test_getopt.c @@ -0,0 +1,216 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_getopt.c + * @brief testcase for util/getopt.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_getopt_lib.h" + +#define VERBOSE 0 + +static int +testMinimal () +{ + char *const emptyargv[] = { + "test", + NULL + }; + const struct GNUNET_GETOPT_CommandLineOption emptyoptionlist[] = { + GNUNET_GETOPT_OPTION_END + }; + + if (1 != GNUNET_GETOPT_run ("test", emptyoptionlist, 1, emptyargv)) + return 1; + + return 0; +} + +static int +testVerbose () +{ + char *const myargv[] = { + "test", + "-V", + "-V", + "more", + NULL + }; + unsigned int vflags = 0; + + const struct GNUNET_GETOPT_CommandLineOption verboseoptionlist[] = { + GNUNET_GETOPT_OPTION_VERBOSE (&vflags), + GNUNET_GETOPT_OPTION_END + }; + + if (3 != GNUNET_GETOPT_run ("test", verboseoptionlist, 4, myargv)) + { + GNUNET_break (0); + return 1; + } + if (vflags != 2) + { + GNUNET_break (0); + return 1; + } + return 0; +} + +static int +testVersion () +{ + char *const myargv[] = { + "test_getopt", + "-v", + NULL + }; + const struct GNUNET_GETOPT_CommandLineOption versionoptionlist[] = { + GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION), + GNUNET_GETOPT_OPTION_END + }; + + if (-1 != GNUNET_GETOPT_run ("test_getopt", versionoptionlist, 2, myargv)) + { + GNUNET_break (0); + return 1; + } + return 0; +} + +static int +testAbout () +{ + char *const myargv[] = { + "test_getopt", + "-h", + NULL + }; + const struct GNUNET_GETOPT_CommandLineOption aboutoptionlist[] = { + GNUNET_GETOPT_OPTION_HELP ("Testing"), + GNUNET_GETOPT_OPTION_END + }; + + if (-1 != GNUNET_GETOPT_run ("test_getopt", aboutoptionlist, 2, myargv)) + { + GNUNET_break (0); + return 1; + } + return 0; +} + +static int +testLogOpts () +{ + char *const myargv[] = { + "test_getopt", + "-l", "filename", + "-L", "WARNING", + NULL + }; + char *level = GNUNET_strdup ("stuff"); + char *fn = NULL; + + const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = { + GNUNET_GETOPT_OPTION_LOGFILE (&fn), + GNUNET_GETOPT_OPTION_LOGLEVEL (&level), + GNUNET_GETOPT_OPTION_END + }; + + if (5 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 5, myargv)) + { + GNUNET_break (0); + return 1; + } + GNUNET_assert (fn != NULL); + if ((0 != strcmp (level, "WARNING")) || (0 != strcmp (fn, "filename"))) + { + GNUNET_break (0); + GNUNET_free (level); + GNUNET_free (fn); + return 1; + } + GNUNET_free (level); + GNUNET_free (fn); + return 0; +} + +static int +testFlagNum () +{ + char *const myargv[] = { + "test_getopt", + "-f", + "-n", "42", + "-N", "42", + NULL + }; + int flag = 0; + unsigned int num = 0; + unsigned long long lnum = 0; + + const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = { + {'f', "--flag", NULL, "helptext", 0, &GNUNET_GETOPT_set_one, + (void *) &flag}, + {'n', "--num", "ARG", "helptext", 1, &GNUNET_GETOPT_set_uint, + (void *) &num}, + {'N', "--lnum", "ARG", "helptext", 1, &GNUNET_GETOPT_set_ulong, + (void *) &lnum}, + GNUNET_GETOPT_OPTION_END + }; + + if (6 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 6, myargv)) + { + GNUNET_break (0); + return 1; + } + if ((1 != flag) || (42 != num) || (42 != lnum)) + { + GNUNET_break (0); + return 1; + } + return 0; +} + +int +main (int argc, char *argv[]) +{ + int errCnt = 0; + + GNUNET_log_setup ("test_getopt", "WARNING", NULL); + /* suppress output from -h, -v options */ +#ifndef MINGW + GNUNET_break (0 == CLOSE (1)); +#endif + if (0 != testMinimal ()) + errCnt++; + if (0 != testVerbose ()) + errCnt++; + if (0 != testVersion ()) + errCnt++; + if (0 != testAbout ()) + errCnt++; + if (0 != testLogOpts ()) + errCnt++; + if (0 != testFlagNum ()) + errCnt++; + return errCnt; +} diff --git a/src/util/test_os_network.c b/src/util/test_os_network.c new file mode 100644 index 0000000..4486e6a --- /dev/null +++ b/src/util/test_os_network.c @@ -0,0 +1,86 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_os_network.c + * @brief testcase for util/os_network.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_configuration_lib.h" +#include "gnunet_os_lib.h" + +#define VERBOSE 1 + +/** + * Check if the address we got is IPv4 or IPv6 loopback (which should + * be present on all systems at all times); if so, set ok to 0 + * (success). + */ +static int +proc (void *cls, const char *name, int isDefault, const struct sockaddr *addr, + const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, + socklen_t addrlen) +{ + int *ok = cls; + char buf[INET6_ADDRSTRLEN]; + + if (NULL == addr) + return GNUNET_OK; +#if VERBOSE + const char * protocol; + if (addrlen == sizeof (struct sockaddr_in)) + protocol = "IPv4"; + else + protocol = "IPv6"; + printf ("%s Address `%s'\n", protocol, GNUNET_a2s ((const struct sockaddr *) addr,addrlen) ); + printf (" Netmask `%s'\n", GNUNET_a2s ((const struct sockaddr *) netmask, addrlen) ); + printf (" Broadcast `%s'\n", GNUNET_a2s ((const struct sockaddr *) broadcast_addr,addrlen) ); +#endif + + inet_ntop (addr->sa_family, + (addr->sa_family == + AF_INET) ? (void *) &((struct sockaddr_in *) addr)->sin_addr + : (void *) &((struct sockaddr_in6 *) addr)->sin6_addr, buf, + sizeof (buf)); + if ((0 == strcmp ("::1", buf)) || (0 == strcmp ("127.0.0.1", buf))) + *ok = 0; + return GNUNET_OK; +} + +static int +testifcs () +{ + int ret; + + ret = 1; + GNUNET_OS_network_interfaces_list (&proc, &ret); + return ret; +} + +int +main (int argc, char *argv[]) +{ + int errCnt = 0; + + GNUNET_log_setup ("test-os-network", "WARNING", NULL); + if (0 != testifcs ()) + errCnt++; + return errCnt; +} diff --git a/src/util/test_os_priority.c b/src/util/test_os_priority.c new file mode 100644 index 0000000..94e2719 --- /dev/null +++ b/src/util/test_os_priority.c @@ -0,0 +1,69 @@ +/* + This file is part of GNUnet. + (C) 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_os_priority.c + * @brief testcase for util/os_priority.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_os_lib.h" + +#define VERBOSE 0 + +static int +testprio () +{ + if (GNUNET_OK != + GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), + GNUNET_SCHEDULER_PRIORITY_DEFAULT)) + return 1; + if (GNUNET_OK != + GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), + GNUNET_SCHEDULER_PRIORITY_UI)) + return 1; + if (GNUNET_OK != + GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), + GNUNET_SCHEDULER_PRIORITY_IDLE)) + return 1; + if (GNUNET_OK != + GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), + GNUNET_SCHEDULER_PRIORITY_BACKGROUND)) + return 1; + if (GNUNET_OK != + GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), + GNUNET_SCHEDULER_PRIORITY_HIGH)) + return 1; + if (GNUNET_OK != + GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), + GNUNET_SCHEDULER_PRIORITY_HIGH)) + return 1; + return 0; +} + +int +main (int argc, char *argv[]) +{ + int errCnt = 0; + + GNUNET_log_setup ("test_os_priority", "WARNING", NULL); + if (0 != testprio ()) + errCnt++; + return errCnt; +} diff --git a/src/util/test_os_start_process.c b/src/util/test_os_start_process.c new file mode 100644 index 0000000..54638c1 --- /dev/null +++ b/src/util/test_os_start_process.c @@ -0,0 +1,194 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_os_start_process.c + * @brief testcase for os start process code + * + * This testcase simply calls the os start process code + * giving a file descriptor to write stdout to. If the + * correct data "HELLO" is read then all is well. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "disk.h" + +#define VERBOSE GNUNET_NO + +static char *test_phrase = "HELLO WORLD"; +static int ok; + +static struct GNUNET_OS_Process *proc; + +/* Pipe to write to started processes stdin (on write end) */ +static struct GNUNET_DISK_PipeHandle *hello_pipe_stdin; + +/* Pipe to read from started processes stdout (on read end) */ +static struct GNUNET_DISK_PipeHandle *hello_pipe_stdout; + +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static void +end_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; + GNUNET_DISK_pipe_close (hello_pipe_stdout); + GNUNET_DISK_pipe_close (hello_pipe_stdin); +} + +static void +read_call (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_DISK_FileHandle *stdout_read_handle = cls; + char buf[16]; + + memset (&buf, 0, sizeof (buf)); + int bytes; + + bytes = GNUNET_DISK_file_read (stdout_read_handle, &buf, sizeof (buf)); + +#if VERBOSE + FPRINTF (stderr, "bytes is %d\n", bytes); +#endif + + if (bytes < 1) + { + GNUNET_break (0); + ok = 1; + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_task, NULL); + return; + } + + ok = strncmp (&buf[0], test_phrase, strlen (test_phrase)); +#if VERBOSE + FPRINTF (stderr, "read %s\n", &buf[0]); +#endif + if (ok == 0) + { + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_SCHEDULER_add_now (&end_task, NULL); + return; + } + + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdout_read_handle, &read_call, + stdout_read_handle); + +} + + +static void +task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *fn; + const struct GNUNET_DISK_FileHandle *stdout_read_handle; + const struct GNUNET_DISK_FileHandle *wh; + + GNUNET_asprintf (&fn, "cat"); + + hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); + hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); + + if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL)) + { + GNUNET_break (0); + ok = 1; + GNUNET_free (fn); + return; + } + + proc = + GNUNET_OS_start_process (GNUNET_NO, hello_pipe_stdin, hello_pipe_stdout, fn, + "test_gnunet_echo_hello", "-", NULL); + GNUNET_free (fn); + + /* Close the write end of the read pipe */ + GNUNET_DISK_pipe_close_end (hello_pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); + /* Close the read end of the write pipe */ + GNUNET_DISK_pipe_close_end (hello_pipe_stdin, GNUNET_DISK_PIPE_END_READ); + + wh = GNUNET_DISK_pipe_handle (hello_pipe_stdin, GNUNET_DISK_PIPE_END_WRITE); + + /* Write the test_phrase to the cat process */ + if (GNUNET_DISK_file_write (wh, test_phrase, strlen (test_phrase) + 1) != + strlen (test_phrase) + 1) + { + GNUNET_break (0); + ok = 1; + return; + } + + /* Close the write end to end the cycle! */ + GNUNET_DISK_pipe_close_end (hello_pipe_stdin, GNUNET_DISK_PIPE_END_WRITE); + + stdout_read_handle = + GNUNET_DISK_pipe_handle (hello_pipe_stdout, GNUNET_DISK_PIPE_END_READ); + + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 1), &end_task, + NULL); + + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdout_read_handle, &read_call, + (void *) stdout_read_handle); + +} + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check () +{ + ok = 1; + GNUNET_SCHEDULER_run (&task, &ok); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-os-start-process", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + return ret; +} diff --git a/src/util/test_peer.c b/src/util/test_peer.c new file mode 100644 index 0000000..2a48401 --- /dev/null +++ b/src/util/test_peer.c @@ -0,0 +1,139 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_peer.c + * @brief testcase for peer.c + * @author Safey Mohammed + */ + +#include "platform.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_peer_lib.h" + +#define NUMBER_OF_PEERS 10 + +#define VERBOSE GNUNET_NO + +/** + * A list of Peer ID's to play with + */ +static struct GNUNET_PeerIdentity pidArr[NUMBER_OF_PEERS]; + + +static void +generatePeerIdList () +{ + int i; + + for (i = 0; i < NUMBER_OF_PEERS; i++) + { + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, + &pidArr[i].hashPubKey); +#if VERBOSE + printf ("Peer %d: %s\n", i, GNUNET_i2s (&pidArr[i])); +#endif + } +} + + +static int +check () +{ + int i; + GNUNET_PEER_Id pid; + struct GNUNET_PeerIdentity res; + struct GNUNET_PeerIdentity zero; + GNUNET_PEER_Id ids[] = { 1, 2, 3 }; + + GNUNET_assert (0 == GNUNET_PEER_intern (NULL)); + /* Insert Peers into PeerEntry table and hashmap */ + for (i = 0; i < NUMBER_OF_PEERS; i++) + { + pid = GNUNET_PEER_intern (&pidArr[i]); + if (pid != (i + 1)) + { + FPRINTF (stderr, "%s", "Unexpected Peer ID returned by intern function\n"); + return 1; + } + } + + /* Referencing the first 3 peers once again */ + for (i = 0; i < 3; i++) + { + pid = GNUNET_PEER_intern (&pidArr[i]); + if (pid != (i + 1)) + { + FPRINTF (stderr, "%s", "Unexpected Peer ID returned by intern function\n"); + return 1; + } + } + + /* Dereferencing the first 3 peers once [decrementing their reference count] */ + GNUNET_PEER_decrement_rcs (ids, 3); + + /* re-referencing the first 3 peers using the change_rc function */ + for (i = 1; i <= 3; i++) + GNUNET_PEER_change_rc (i, 1); + + /* Removing the second Peer from the PeerEntry hash map */ + GNUNET_PEER_change_rc (2, -2); + + /* convert the pid of the first PeerEntry into that of the third */ + GNUNET_PEER_resolve (1, &res); + GNUNET_assert (0 == memcmp (&res, &pidArr[0], sizeof (res))); + + /* + * Attempt to convert pid = 0 (which is reserved) + * into a peer identity object, the peer identity memory + * is expected to be set to zero + */ + memset (&zero, 0, sizeof (struct GNUNET_PeerIdentity)); + GNUNET_log_skip (1, GNUNET_YES); + GNUNET_PEER_resolve (0, &res); + GNUNET_assert (0 == memcmp (&res, &zero, sizeof (res))); + + /* Removing peer entries 1 and 3 from table using the list decrement function */ + /* If count = 0, nothing should be done whatsoever */ + GNUNET_PEER_decrement_rcs (ids, 0); + + ids[1] = 3; + GNUNET_PEER_decrement_rcs (ids, 2); + GNUNET_PEER_decrement_rcs (ids, 2); + + return 0; +} + + +int +main () +{ + int i; + + GNUNET_log_setup ("test-peer", "ERROR", NULL); + for (i = 0; i < 1; i++) + { + generatePeerIdList (); + if (0 != check ()) + return 1; + } + return 0; +} + +/* end of test_peer.c */ diff --git a/src/util/test_plugin.c b/src/util/test_plugin.c new file mode 100644 index 0000000..428cdaf --- /dev/null +++ b/src/util/test_plugin.c @@ -0,0 +1,79 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_plugin.c + * @brief testcase for plugin.c + */ +#include "platform.h" +#include "gnunet_plugin_lib.h" + +#define VERBOSE GNUNET_NO + +static void +test_cb (void *cls, const char *libname, void *lib_ret) +{ + void *ret; + + GNUNET_assert (0 == strcmp (cls, "test")); + GNUNET_assert (0 == strcmp (lib_ret, "Hello")); + ret = GNUNET_PLUGIN_unload (libname, "out"); + GNUNET_assert (NULL != ret); + GNUNET_assert (0 == strcmp (ret, "World")); +} + + +static int +check () +{ + void *ret; + + GNUNET_log_skip (1, GNUNET_NO); + ret = GNUNET_PLUGIN_load ("libgnunet_plugin_missing", NULL); + GNUNET_log_skip (0, GNUNET_NO); + if (ret != NULL) + return 1; + ret = GNUNET_PLUGIN_load ("libgnunet_plugin_test", "in"); + if (ret == NULL) + return 1; + if (0 != strcmp (ret, "Hello")) + return 2; + ret = GNUNET_PLUGIN_unload ("libgnunet_plugin_test", "out"); + if (ret == NULL) + return 3; + if (0 != strcmp (ret, "World")) + return 4; + free (ret); + + GNUNET_PLUGIN_load_all ("libgnunet_plugin_tes", "in", &test_cb, "test"); + return 0; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-plugin", "WARNING", NULL); + ret = check (); + + return ret; +} + +/* end of test_plugin.c */ diff --git a/src/util/test_plugin_plug.c b/src/util/test_plugin_plug.c new file mode 100644 index 0000000..beb78d2 --- /dev/null +++ b/src/util/test_plugin_plug.c @@ -0,0 +1,42 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_plugin_plug.c + * @brief plugin for testing + */ +#include "platform.h" + +void * +libgnunet_plugin_test_init (void *arg) +{ + if (0 == strcmp (arg, "in")) + return "Hello"; + return NULL; +} + +void * +libgnunet_plugin_test_done (void *arg) +{ + if (0 == strcmp (arg, "out")) + return strdup ("World"); + return NULL; +} + +/* end of test_plugin_plug.c */ diff --git a/src/util/test_program.c b/src/util/test_program.c new file mode 100644 index 0000000..faeb4e7 --- /dev/null +++ b/src/util/test_program.c @@ -0,0 +1,121 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_program.c + * @brief tests for program.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +static int setme1, setme2; + +static struct GNUNET_GETOPT_CommandLineOption options1[] = { + {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, + GNUNET_GETOPT_OPTION_END +}; + +static struct GNUNET_GETOPT_CommandLineOption options2[] = { + {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, + {'N', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2}, + GNUNET_GETOPT_OPTION_END +}; + +static struct GNUNET_GETOPT_CommandLineOption options3[] = { + {'N', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, + {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2}, + GNUNET_GETOPT_OPTION_END +}; + +static struct GNUNET_GETOPT_CommandLineOption options4[] = { + {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, + {'n', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2}, + GNUNET_GETOPT_OPTION_END +}; + +/** + * Main function that will be run. + */ + +static void +runner (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + int *ok = cls; + + GNUNET_assert (setme1 == 1); + GNUNET_assert (0 == strcmp (args[0], "extra")); + GNUNET_assert (args[1] == NULL); + GNUNET_assert (0 == strcmp (cfgfile, "test_program_data.conf")); + + *ok = 0; +} + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check () +{ + int ok = 1; + + char *const argv[] = { + "test_program", + "-c", + "test_program_data.conf", + "-L", + "WARNING", + "-n", + "extra", + NULL + }; + + GNUNET_assert (GNUNET_OK == + GNUNET_PROGRAM_run (7, argv, "test_program", "A test", + options1, &runner, &ok)); + + GNUNET_assert (GNUNET_OK == + GNUNET_PROGRAM_run (7, argv, "test_program", "A test", + options2, &runner, &ok)); + GNUNET_assert (GNUNET_OK == + GNUNET_PROGRAM_run (7, argv, "test_program", "A test", + options3, &runner, &ok)); + GNUNET_assert (GNUNET_OK == + GNUNET_PROGRAM_run (7, argv, "test_program", "A test", + options4, &runner, &ok)); + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_program", "WARNING", NULL); + ret += check (); + + return ret; +} + +/* end of test_program.c */ diff --git a/src/util/test_program_data.conf b/src/util/test_program_data.conf new file mode 100644 index 0000000..e69de29 diff --git a/src/util/test_pseudonym.c b/src/util/test_pseudonym.c new file mode 100644 index 0000000..20a3d3d --- /dev/null +++ b/src/util/test_pseudonym.c @@ -0,0 +1,191 @@ +/* + This file is part of GNUnet. + (C) 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_pseudonym.c + * @brief testcase for pseudonym.c + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" +#include "gnunet_crypto_lib.h" +#include "gnunet_disk_lib.h" +#include "gnunet_pseudonym_lib.h" + +#define CHECK(a) do { if (!(a)) { ok = GNUNET_NO; GNUNET_break(0); goto FAILURE; } } while (0) + +static struct GNUNET_CONTAINER_MetaData *meta; + +static GNUNET_HashCode id1; + +static int +iter (void *cls, const GNUNET_HashCode * pseudonym, + const struct GNUNET_CONTAINER_MetaData *md, int rating) +{ + int *ok = cls; + + if ((0 == memcmp (pseudonym, &id1, sizeof (GNUNET_HashCode))) && + (!GNUNET_CONTAINER_meta_data_test_equal (md, meta))) + { + *ok = GNUNET_NO; + GNUNET_break (0); + } + return GNUNET_OK; +} + +static int +noti_callback (void *cls, const GNUNET_HashCode * pseudonym, + const struct GNUNET_CONTAINER_MetaData *md, int rating) +{ + int *ret = cls; + + (*ret)++; + return GNUNET_OK; +} + +static int +fake_noti_callback (void *cls, const GNUNET_HashCode * pseudonym, + const struct GNUNET_CONTAINER_MetaData *md, int rating) +{ + int *ret = cls; + + (*ret)++; + return GNUNET_OK; +} + +static int +false_callback (void *cls, const GNUNET_HashCode * pseudonym, + const struct GNUNET_CONTAINER_MetaData *md, int rating) +{ + return GNUNET_OK; +} + +int +main (int argc, char *argv[]) +{ + int ok; + GNUNET_HashCode rid1; + GNUNET_HashCode id2; + GNUNET_HashCode rid2; + GNUNET_HashCode fid; + GNUNET_HashCode id3; + + int old; + int newVal; + struct GNUNET_CONFIGURATION_Handle *cfg; + char *name1; + char *name2; + char *name3; + char *noname; + int notiCount, fakenotiCount; + int count; + static char m[1024 * 1024 * 10]; + + memset (m, 'b', sizeof (m)); + m[sizeof (m) - 1] = '\0'; + + GNUNET_log_setup ("test-pseudonym", "WARNING", NULL); + ok = GNUNET_YES; + GNUNET_CRYPTO_random_disable_entropy_gathering (); + (void) GNUNET_DISK_directory_remove ("/tmp/gnunet-pseudonym-test"); + cfg = GNUNET_CONFIGURATION_create (); + if (-1 == GNUNET_CONFIGURATION_parse (cfg, "test_pseudonym_data.conf")) + { + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_break (0); + return -1; + } + notiCount = 0; + fakenotiCount = 0; + count = 0; + GNUNET_PSEUDONYM_discovery_callback_register (cfg, &fake_noti_callback, + &fakenotiCount); + GNUNET_PSEUDONYM_discovery_callback_register (cfg, ¬i_callback, + ¬iCount); + GNUNET_PSEUDONYM_discovery_callback_unregister (&false_callback, &count); + GNUNET_PSEUDONYM_discovery_callback_unregister (&fake_noti_callback, + &fakenotiCount); + + /* ACTUAL TEST CODE */ + old = GNUNET_PSEUDONYM_list_all (cfg, NULL, NULL); + meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "test", strlen ("test") + 1); + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id1); + GNUNET_PSEUDONYM_add (cfg, &id1, meta); + CHECK (notiCount == 1); + GNUNET_PSEUDONYM_add (cfg, &id1, meta); + CHECK (notiCount == 2); + newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok); + CHECK (old < newVal); + old = newVal; + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id2); + GNUNET_PSEUDONYM_add (cfg, &id2, meta); + CHECK (notiCount == 3); + newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok); + CHECK (old < newVal); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_meta_data_insert (meta, "", + EXTRACTOR_METATYPE_COMMENT, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", m, + strlen (m) + 1)); + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id3); + GNUNET_PSEUDONYM_add (cfg, &id3, meta); + name3 = GNUNET_PSEUDONYM_id_to_name (cfg, &id3); + name2 = GNUNET_PSEUDONYM_id_to_name (cfg, &id2); + CHECK (name2 != NULL); + name1 = GNUNET_PSEUDONYM_id_to_name (cfg, &id1); + CHECK (name1 != NULL); + CHECK (0 != strcmp (name1, name2)); + CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, "fake", &rid2)); + CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name2, &rid2)); + CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name1, &rid1)); + CHECK (0 == memcmp (&id1, &rid1, sizeof (GNUNET_HashCode))); + CHECK (0 == memcmp (&id2, &rid2, sizeof (GNUNET_HashCode))); + + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &fid); + GNUNET_log_skip (1, GNUNET_NO); + CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &fid, 0)); + GNUNET_log_skip (0, GNUNET_YES); + noname = GNUNET_PSEUDONYM_id_to_name (cfg, &fid); + CHECK (noname != NULL); + CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 0)); + CHECK (5 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5)); + CHECK (-5 == GNUNET_PSEUDONYM_rank (cfg, &id1, -10)); + CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5)); + GNUNET_free (name1); + GNUNET_free (name2); + GNUNET_free (name3); + GNUNET_free (noname); + /* END OF TEST CODE */ +FAILURE: + GNUNET_PSEUDONYM_discovery_callback_unregister (¬i_callback, ¬iCount); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_directory_remove ("/tmp/gnunet-pseudonym-test")); + return (ok == GNUNET_YES) ? 0 : 1; +} + +/* end of test_pseudoynm.c */ diff --git a/src/util/test_pseudonym_data.conf b/src/util/test_pseudonym_data.conf new file mode 100644 index 0000000..5523007 --- /dev/null +++ b/src/util/test_pseudonym_data.conf @@ -0,0 +1,7 @@ +# General settings +[client] +HOME = "/tmp/gnunet-pseudonym-test" + +[TESTING] +WEAKRANDOM = YES + diff --git a/src/util/test_resolver_api.c b/src/util/test_resolver_api.c new file mode 100644 index 0000000..67d5f46 --- /dev/null +++ b/src/util/test_resolver_api.c @@ -0,0 +1,437 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ +/** + * @file resolver/test_resolver_api.c + * @brief testcase for resolver_api.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_resolver_service.h" +#include "resolver.h" + +#define VERBOSE GNUNET_NO + +/** + * Using DNS root servers to check gnunet's resolver service + * a.root-servers.net <-> 198.41.0.4 is a fix 1:1 mapping that should not change over years + * For more information have a look at IANA's website http://www.root-servers.org/ + */ +#define ROOTSERVER_NAME "a.root-servers.net" +#define ROOTSERVER_IP "198.41.0.4" + +static void +check_hostname (void *cls, const struct sockaddr *sa, socklen_t salen) +{ + int *ok = cls; + + if (salen == 0) + { + (*ok) &= ~8; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Got IP address `%s' for our host.\n"), + GNUNET_a2s (sa, salen)); +} + + +static void +check_localhost_num (void *cls, const char *hostname) +{ + int *ok = cls; + + if (hostname == NULL) + return; + if (0 == strcmp (hostname, "127.0.0.1")) + { +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct hostname `%s'.\n", + hostname); +#endif + (*ok) &= ~4; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received invalid hostname `%s'.\n", + hostname); + GNUNET_break (0); + } +} + + +static void +check_localhost (void *cls, const char *hostname) +{ + int *ok = cls; + + if (hostname == NULL) + return; + if (0 == strcmp (hostname, "localhost")) + { +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct hostname `%s'.\n", + hostname); +#endif + (*ok) &= ~2; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Received unexpected hostname `%s', expected `localhost' (this could be OK).\n", + hostname); + } +} + +static void +check_127 (void *cls, const struct sockaddr *sa, socklen_t salen) +{ + int *ok = cls; + const struct sockaddr_in *sai = (const struct sockaddr_in *) sa; + + if (sa == NULL) + return; + GNUNET_assert (sizeof (struct sockaddr_in) == salen); + if (sai->sin_addr.s_addr == htonl (INADDR_LOOPBACK)) + { +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct address.\n"); +#endif + (*ok) &= ~1; + } + else + { + char buf[INET_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received incorrect address`%s'.\n", + inet_ntop (AF_INET, &sai->sin_addr, buf, sizeof (buf))); + GNUNET_break (0); + } +} + +static void +check_local_fqdn (void *cls, const char *gnunet_fqdn) +{ + int result = 0; + + struct hostent *host; + char hostname[GNUNET_OS_get_hostname_max_length () + 1]; + + if (0 != gethostname (hostname, sizeof (hostname) - 1)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "gethostname"); + return; + } +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolving our FQDN `%s'\n"), + hostname); +#endif + host = gethostbyname (hostname); + if (NULL == host) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not resolve our FQDN: %s %u\n"), hstrerror (h_errno), + h_errno); + return; + } + + GNUNET_assert (0 != host); + + result = strcmp (host->h_name, gnunet_fqdn); + if (0 != result) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Local resolved and resolver resolved fqdns are not equal\n"); + } + GNUNET_assert (0 == result); +} + + + +static void +check_rootserver_ip (void *cls, const struct sockaddr *sa, socklen_t salen) +{ + int *ok = cls; + const struct sockaddr_in *sai = (const struct sockaddr_in *) sa; + + if (sa == NULL) + return; + GNUNET_assert (sizeof (struct sockaddr_in) == salen); + + if (0 == strcmp (inet_ntoa (sai->sin_addr), ROOTSERVER_IP)) + { +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received correct rootserver ip address.\n"); +#endif + (*ok) &= ~1; + } + else + { +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received incorrect rootserver ip address.\n"); +#endif + GNUNET_break (0); + } +} + +static void +check_rootserver_name (void *cls, const char *hostname) +{ + int *ok = cls; + + if (hostname == NULL) + return; + + if (0 == strcmp (hostname, ROOTSERVER_NAME)) + { +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received correct rootserver hostname `%s'.\n", hostname); +#endif + (*ok) &= ~2; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Received invalid rootserver hostname `%s'.\n", hostname); + GNUNET_break (0); + } +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + int *ok = cls; + struct sockaddr_in sa; + struct GNUNET_TIME_Relative timeout = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30); + int count_ips = 0; + char *own_fqdn; + + memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = (u_char) sizeof (sa); +#endif + sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + /* + * Looking up our own fqdn + */ + own_fqdn = GNUNET_RESOLVER_local_fqdn_get (); + check_local_fqdn (NULL, own_fqdn); + GNUNET_free_non_null (own_fqdn); + + /* + * Testing non-local DNS resolution + * DNS rootserver to test: a.root-servers.net - 198.41.0.4 + */ + const char *rootserver_name = ROOTSERVER_NAME; + struct hostent *rootserver; + + rootserver = gethostbyname (rootserver_name); + if (rootserver == NULL) + { + /* Error: resolving ip addresses does not work */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("gethostbyname() could not lookup IP address: %s\n"), + hstrerror (h_errno)); + FPRINTF (stderr, + "%s", "System seems to be off-line, will not run all DNS tests\n"); + *ok = 0; /* mark test as passing anyway */ + return; + } + + /* Counting returned IP addresses */ + while (rootserver->h_addr_list[count_ips] != NULL) + count_ips++; + if (count_ips > 1) + { +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "IP received range for root name server, but a root name server has only 1 IP\n"); +#endif + GNUNET_break (0); + } + + /* Comparing to resolved address to the address the root name server should have */ + if (strcmp + (inet_ntoa (*(struct in_addr *) rootserver->h_addr_list[0]), + ROOTSERVER_IP) != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "IP received and IP for root name server differ\n"); + GNUNET_break (0); + } +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "System's own forward name resolution is working\n"); +#endif + + /* Resolve the same using GNUNET */ + GNUNET_RESOLVER_ip_get (ROOTSERVER_NAME, AF_INET, timeout, + &check_rootserver_ip, cls); + + /* + * Success: forward lookups work as expected + * Next step: reverse lookups + */ + + struct in_addr rootserver_addr; + + rootserver->h_name = ""; + if (1 != inet_pton (AF_INET, ROOTSERVER_IP, &rootserver_addr)) + { +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Could not transform root name server IP address\n"); +#endif + GNUNET_break (0); + } + + rootserver = + gethostbyaddr (&rootserver_addr, sizeof (rootserver_addr), AF_INET); + if (rootserver == NULL) + { + /* Error: resolving IP addresses does not work */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("gethostbyaddr() could not lookup hostname: %s\n"), + hstrerror (h_errno)); + GNUNET_break (0); + } + else + { + if (0 != strcmp (rootserver->h_name, ROOTSERVER_NAME)) + { +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received hostname and hostname for root name server differ\n"); +#endif + GNUNET_break (0); + } + } + +#if DEBUG_RESOLVER + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "System's own reverse name resolution is working\n"); +#endif + + /* Resolve the same using GNUNET */ + memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = (u_char) sizeof (sa); +#endif +#ifndef MINGW + inet_aton (ROOTSERVER_IP, &sa.sin_addr); +#else + sa.sin_addr.S_un.S_addr = inet_addr (ROOTSERVER_IP); +#endif + GNUNET_RESOLVER_hostname_get ((const struct sockaddr *) &sa, + sizeof (struct sockaddr), GNUNET_YES, timeout, + &check_rootserver_name, cls); + + memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = (u_char) sizeof (sa); +#endif + sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + GNUNET_RESOLVER_ip_get ("localhost", AF_INET, timeout, &check_127, cls); + GNUNET_RESOLVER_hostname_get ((const struct sockaddr *) &sa, + sizeof (struct sockaddr), GNUNET_YES, timeout, + &check_localhost, cls); + + GNUNET_RESOLVER_hostname_get ((const struct sockaddr *) &sa, + sizeof (struct sockaddr), GNUNET_NO, timeout, + &check_localhost_num, cls); + GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, timeout, &check_hostname, cls); + +} + +static int +check () +{ + int ok = 1 + 2 + 4 + 8; + char *fn; + char *pfx; + struct GNUNET_OS_Process *proc; + + char *const argv[] = + { "test-resolver-api", "-c", "test_resolver_api_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = + { GNUNET_GETOPT_OPTION_END }; + pfx = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); + GNUNET_asprintf (&fn, "%s%cgnunet-service-resolver", pfx, DIR_SEPARATOR); + GNUNET_free (pfx); + proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, fn, "gnunet-service-resolver", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", "test_resolver_api_data.conf", NULL); + GNUNET_assert (NULL != proc); + GNUNET_free (fn); + GNUNET_assert (GNUNET_OK == + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, + argv, "test-resolver-api", "nohelp", + options, &run, &ok)); + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + ok = 1; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_close (proc); + proc = NULL; + if (ok != 0) + FPRINTF (stderr, "Missed some resolutions: %u\n", ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-resolver-api", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + return ret; +} + +/* end of test_resolver_api.c */ diff --git a/src/util/test_resolver_api_data.conf b/src/util/test_resolver_api_data.conf new file mode 100644 index 0000000..745cb7b --- /dev/null +++ b/src/util/test_resolver_api_data.conf @@ -0,0 +1,8 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunetd-statistics/ + +[resolver] +PORT = 22354 +HOSTNAME = localhost +DEBUG = YES + diff --git a/src/util/test_scheduler.c b/src/util/test_scheduler.c new file mode 100644 index 0000000..01982ee --- /dev/null +++ b/src/util/test_scheduler.c @@ -0,0 +1,266 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_scheduler.c + * @brief tests for the scheduler + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_disk_lib.h" + +#define VERBOSE GNUNET_NO + +static void +task3 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + + /* t4 should be ready (albeit with lower priority) */ + GNUNET_assert (1 == + GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_COUNT)); + GNUNET_assert (3 == *ok); + (*ok) = 4; +} + + +static void +task2 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + + GNUNET_assert (2 == *ok); + (*ok) = 3; + /* t3 will go before t4: higher priority */ + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, &task3, + cls); +} + +static void +task4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + + GNUNET_assert (4 == *ok); + (*ok) = 5; +} + +struct GNUNET_DISK_PipeHandle *p; +static const struct GNUNET_DISK_FileHandle *fds[2]; + + +static void +taskWrt (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static char c; + int *ok = cls; + + GNUNET_assert (6 == *ok); + GNUNET_assert (GNUNET_NETWORK_fdset_handle_isset (tc->write_ready, fds[1])); + (*ok) = 7; + GNUNET_assert (1 == GNUNET_DISK_file_write (fds[1], &c, 1)); +} + + +static void +taskNeverRun (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (0); +} + +static void +taskLast (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + + /* t4 should be ready (albeit with lower priority) */ + GNUNET_assert (8 == *ok); + (*ok) = 0; +} + +static void +taskRd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static char c; + int *ok = cls; + + GNUNET_assert (7 == *ok); + GNUNET_assert (GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, fds[0])); + GNUNET_assert (1 == GNUNET_DISK_file_read (fds[0], &c, 1)); + (*ok) = 8; + GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &taskLast, + cls); + GNUNET_SCHEDULER_shutdown (); +} + + +static void +task5 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + + GNUNET_assert (5 == *ok); + (*ok) = 6; + p = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); + GNUNET_assert (NULL != p); + fds[0] = GNUNET_DISK_pipe_handle (p, GNUNET_DISK_PIPE_END_READ); + fds[1] = GNUNET_DISK_pipe_handle (p, GNUNET_DISK_PIPE_END_WRITE); + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, fds[0], &taskRd, + cls); + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, fds[1], + &taskWrt, cls); +} + + +static void +task1 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + GNUNET_SCHEDULER_TaskIdentifier t2; + GNUNET_SCHEDULER_TaskIdentifier t4; + + GNUNET_assert (1 == *ok); + (*ok) = 2; + /* t2 will go first -- prereq for all */ + t2 = GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_NO_TASK, &task2, cls); + /* t4 will go after t2 ('add after') and after t3 (priority) */ + t4 = GNUNET_SCHEDULER_add_after (t2, &task4, cls); + /* t5 will go last (after p4) */ + GNUNET_SCHEDULER_add_after (t4, &task5, cls); +} + + + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check () +{ + int ok; + + ok = 1; + GNUNET_SCHEDULER_run (&task1, &ok); + return ok; +} + + +static void +taskShutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + + GNUNET_assert (1 == *ok); + *ok = 8; + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &taskLast, cls); + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +checkShutdown () +{ + int ok; + + ok = 1; + GNUNET_SCHEDULER_run (&taskShutdown, &ok); + return ok; +} + + +static void +taskSig (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + + GNUNET_assert (1 == *ok); + *ok = 8; + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &taskLast, cls); + GNUNET_break (0 == PLIBC_KILL (getpid (), SIGTERM)); +} + + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +checkSignal () +{ + int ok; + + ok = 1; + GNUNET_SCHEDULER_run (&taskSig, &ok); + return ok; +} + + +static void +taskCancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *ok = cls; + + GNUNET_assert (1 == *ok); + *ok = 0; + GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_add_after + (GNUNET_SCHEDULER_NO_TASK, &taskNeverRun, NULL)); +} + + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +checkCancel () +{ + int ok; + + ok = 1; + GNUNET_SCHEDULER_run (&taskCancel, &ok); + return ok; +} + + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_scheduler", "WARNING", NULL); + ret += check (); +#ifndef MINGW + ret += checkSignal (); +#endif + ret += checkShutdown (); + ret += checkCancel (); + GNUNET_DISK_pipe_close (p); + + return ret; +} + +/* end of test_scheduler.c */ diff --git a/src/util/test_scheduler_delay.c b/src/util/test_scheduler_delay.c new file mode 100644 index 0000000..8ba35f5 --- /dev/null +++ b/src/util/test_scheduler_delay.c @@ -0,0 +1,103 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_scheduler_delay.c + * @brief testcase for delay of scheduler, measures how + * precise the timers are. Expect values between 10 and 20 ms on + * modern machines. + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +static struct GNUNET_TIME_Absolute target; + +static int i; + +static unsigned long long cumDelta; + +#define INCR 47 + +#define MAXV 1500 + +/** + * Signature of the main function of a task. + * + * @param cls closure + * @param tc context + */ +static void +test_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TIME_Absolute now; + + now = GNUNET_TIME_absolute_get (); + if (now.abs_value > target.abs_value) + cumDelta += (now.abs_value - target.abs_value); + else + cumDelta += (target.abs_value - now.abs_value); + target = + GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, i)); + FPRINTF (stderr, "%s", "."); + if (i > MAXV) + { + FPRINTF (stderr, "%s", "\n"); + return; + } + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, i), &test_task, + NULL); + i += INCR; +} + +static int +check () +{ + target = GNUNET_TIME_absolute_get (); + GNUNET_SCHEDULER_run (&test_task, NULL); + FPRINTF (stdout, "Sleep precision: %llu ms. ", + cumDelta / 1000 / (MAXV / INCR)); + if (cumDelta <= 10 * MAXV / INCR) + FPRINTF (stdout, "%s", "Timer precision is excellent.\n"); + else if (cumDelta <= 50 * MAXV / INCR) /* 50 ms average deviation */ + FPRINTF (stdout, "%s", "Timer precision is good.\n"); + else if (cumDelta > 250 * MAXV / INCR) + FPRINTF (stdout, "%s", "Timer precision is awful.\n"); + else + FPRINTF (stdout, "%s", "Timer precision is acceptable.\n"); + return 0; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-scheduler-delay", "WARNING", NULL); + ret = check (); + + return ret; +} + +/* end of test_scheduler_delay.c */ diff --git a/src/util/test_server.c b/src/util/test_server.c new file mode 100644 index 0000000..6718c65 --- /dev/null +++ b/src/util/test_server.c @@ -0,0 +1,222 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_server.c + * @brief tests for server.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_client_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define PORT 12435 + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) + +#define MY_TYPE 128 +#define MY_TYPE2 129 + +static struct GNUNET_SERVER_Handle *server; + +static struct GNUNET_CLIENT_Connection *cc; + +static struct GNUNET_SERVER_Client *argclient; + +static struct GNUNET_CONFIGURATION_Handle *cfg; + +static int ok; + + +static void +finish_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (ok == 6); + ok = 0; + GNUNET_SERVER_destroy (server); + GNUNET_CLIENT_disconnect (cc, GNUNET_NO); + GNUNET_CONFIGURATION_destroy (cfg); +} + + +static void +recv_fin_cb (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + GNUNET_assert (ok == 5); + ok = 6; + GNUNET_SERVER_receive_done (client, GNUNET_OK); + GNUNET_SCHEDULER_add_now (&finish_up, NULL); +} + + +static void +first_reply_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + GNUNET_assert (ok == 4); + ok = 5; + GNUNET_SERVER_receive_done (argclient, GNUNET_OK); + GNUNET_SERVER_client_drop (argclient); + argclient = NULL; +} + + +static size_t +reply_msg (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader msg; + + GNUNET_assert (ok == 3); + ok = 4; + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + msg.type = htons (MY_TYPE); + msg.size = htons (sizeof (struct GNUNET_MessageHeader)); + memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader)); + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +recv_cb (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + GNUNET_assert (ok == 2); + ok = 3; + argclient = client; + GNUNET_SERVER_client_keep (argclient); + GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); + GNUNET_assert (MY_TYPE == ntohs (message->type)); + GNUNET_assert (NULL != + GNUNET_SERVER_notify_transmit_ready (client, + ntohs (message->size), + TIMEOUT, &reply_msg, + NULL)); +} + + +static struct GNUNET_SERVER_MessageHandler handlers[] = { + {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, + {&recv_fin_cb, NULL, MY_TYPE2, sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} +}; + + +static size_t +transmit_second_message (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader msg; + + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + msg.type = htons (MY_TYPE2); + msg.size = htons (sizeof (struct GNUNET_MessageHeader)); + memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader)); + return sizeof (struct GNUNET_MessageHeader); +} + + +static size_t +transmit_initial_message (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader msg; + + GNUNET_assert (ok == 1); + ok = 2; + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + msg.type = htons (MY_TYPE); + msg.size = htons (sizeof (struct GNUNET_MessageHeader)); + memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader)); + GNUNET_assert (NULL != + GNUNET_CLIENT_notify_transmit_ready (cc, + sizeof (struct + GNUNET_MessageHeader), + TIMEOUT, GNUNET_YES, + &transmit_second_message, + NULL)); + GNUNET_CLIENT_receive (cc, &first_reply_handler, NULL, TIMEOUT); + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct sockaddr_in sa; + struct sockaddr *sap[2]; + socklen_t slens[2]; + + sap[0] = (struct sockaddr *) &sa; + slens[0] = sizeof (sa); + sap[1] = NULL; + slens[1] = 0; + memset (&sa, 0, sizeof (sa)); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_family = AF_INET; + sa.sin_port = htons (PORT); + server = GNUNET_SERVER_create (NULL, NULL, sap, slens, TIMEOUT, GNUNET_NO); + GNUNET_assert (server != NULL); + GNUNET_SERVER_add_handlers (server, handlers); + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_number (cfg, "test-server", "PORT", PORT); + GNUNET_CONFIGURATION_set_value_string (cfg, "test-server", "HOSTNAME", + "localhost"); + GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", + "localhost"); + cc = GNUNET_CLIENT_connect ("test-server", cfg); + GNUNET_assert (cc != NULL); + GNUNET_assert (NULL != + GNUNET_CLIENT_notify_transmit_ready (cc, + sizeof (struct + GNUNET_MessageHeader), + TIMEOUT, GNUNET_YES, + &transmit_initial_message, + NULL)); +} + + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check () +{ + ok = 1; + GNUNET_SCHEDULER_run (&task, &ok); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_server", "WARNING", NULL); + ret += check (); + + return ret; +} + +/* end of test_server.c */ diff --git a/src/util/test_server_disconnect.c b/src/util/test_server_disconnect.c new file mode 100644 index 0000000..8010695 --- /dev/null +++ b/src/util/test_server_disconnect.c @@ -0,0 +1,180 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_server_disconnect.c + * @brief tests for server.c, specifically GNUNET_SERVER_client_disconnect + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_client_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define PORT 12435 + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250) + +#define MY_TYPE 128 + +static struct GNUNET_SERVER_Handle *server; + +static struct GNUNET_CLIENT_Connection *cc; + +static struct GNUNET_CONFIGURATION_Handle *cfg; + +static int ok; + + +static void +finish_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_assert (ok == 5); + ok = 0; + GNUNET_SERVER_destroy (server); + GNUNET_CLIENT_disconnect (cc, GNUNET_NO); + GNUNET_CONFIGURATION_destroy (cfg); +} + + +static void +notify_disconnect (void *cls, struct GNUNET_SERVER_Client *clientarg) +{ + if (clientarg == NULL) + return; + GNUNET_assert (ok == 4); + ok = 5; + GNUNET_SCHEDULER_add_now (&finish_up, NULL); +} + + +static void +server_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_SERVER_Client *argclient = cls; + + GNUNET_assert (ok == 3); + ok = 4; + GNUNET_SERVER_client_disconnect (argclient); + GNUNET_SERVER_client_drop (argclient); +} + + +static void +recv_cb (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + GNUNET_assert (ok == 2); + ok = 3; + GNUNET_SERVER_client_keep (client); + GNUNET_SCHEDULER_add_now (&server_disconnect, client); + GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); + GNUNET_assert (MY_TYPE == ntohs (message->type)); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +static struct GNUNET_SERVER_MessageHandler handlers[] = { + {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} +}; + + +static size_t +transmit_initial_message (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader msg; + + GNUNET_assert (ok == 1); + ok = 2; + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + msg.type = htons (MY_TYPE); + msg.size = htons (sizeof (struct GNUNET_MessageHeader)); + memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader)); + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct sockaddr_in sa; + struct sockaddr *sap[2]; + socklen_t slens[2]; + + sap[0] = (struct sockaddr *) &sa; + slens[0] = sizeof (sa); + sap[1] = NULL; + slens[1] = 0; + memset (&sa, 0, sizeof (sa)); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_family = AF_INET; + sa.sin_port = htons (PORT); + server = GNUNET_SERVER_create (NULL, NULL, sap, slens, TIMEOUT, GNUNET_NO); + GNUNET_assert (server != NULL); + GNUNET_SERVER_add_handlers (server, handlers); + GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, NULL); + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_number (cfg, "test-server", "PORT", PORT); + GNUNET_CONFIGURATION_set_value_string (cfg, "test-server", "HOSTNAME", + "localhost"); + GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", + "localhost"); + cc = GNUNET_CLIENT_connect ("test-server", cfg); + GNUNET_assert (cc != NULL); + GNUNET_assert (NULL != + GNUNET_CLIENT_notify_transmit_ready (cc, + sizeof (struct + GNUNET_MessageHeader), + TIMEOUT, GNUNET_YES, + &transmit_initial_message, + NULL)); +} + + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check () +{ + ok = 1; + GNUNET_SCHEDULER_run (&task, &ok); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_server_disconnect", "WARNING", NULL); + ret += check (); + + return ret; +} + +/* end of test_server_disconnect.c */ diff --git a/src/util/test_server_with_client.c b/src/util/test_server_with_client.c new file mode 100644 index 0000000..06a4b71 --- /dev/null +++ b/src/util/test_server_with_client.c @@ -0,0 +1,224 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_server_with_client.c + * @brief tests for server.c and client.c, + * specifically disconnect_notify, + * client_get_address and receive_done (resume processing) + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_client_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define PORT 22335 + +#define MY_TYPE 128 + + +static struct GNUNET_SERVER_Handle *server; + +static struct GNUNET_CLIENT_Connection *client; + +static struct GNUNET_CONFIGURATION_Handle *cfg; + +static int ok; + +static void +send_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_SERVER_Client *argclient = cls; + + GNUNET_assert (ok == 3); + ok++; + GNUNET_SERVER_receive_done (argclient, GNUNET_OK); +} + + +static void +recv_cb (void *cls, struct GNUNET_SERVER_Client *argclient, + const struct GNUNET_MessageHeader *message) +{ + void *addr; + size_t addrlen; + struct sockaddr_in sa; + struct sockaddr_in *have; + + GNUNET_assert (GNUNET_OK == + GNUNET_SERVER_client_get_address (argclient, &addr, &addrlen)); + + GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); + have = addr; + memset (&sa, 0, sizeof (sa)); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_family = AF_INET; + sa.sin_port = have->sin_port; + sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + GNUNET_assert (0 == memcmp (&sa, addr, addrlen)); + GNUNET_free (addr); + switch (ok) + { + case 2: + ok++; + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 50), + &send_done, argclient); + break; + case 4: + ok++; + GNUNET_CLIENT_disconnect (client, GNUNET_YES); + GNUNET_SERVER_receive_done (argclient, GNUNET_OK); + break; + default: + GNUNET_assert (0); + } + +} + + +static void +clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_SERVER_destroy (server); + server = NULL; + GNUNET_CONFIGURATION_destroy (cfg); + cfg = NULL; +} + + +/** + * Functions with this signature are called whenever a client + * is disconnected on the network level. + * + * @param cls closure + * @param client identification of the client + */ +static void +notify_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + if (client == NULL) + return; + GNUNET_assert (ok == 5); + ok = 0; + GNUNET_SCHEDULER_add_now (&clean_up, NULL); +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg; + + GNUNET_assert (size >= 256); + GNUNET_assert (1 == ok); + ok++; + msg = buf; + msg->type = htons (MY_TYPE); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + msg++; + msg->type = htons (MY_TYPE); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + return 2 * sizeof (struct GNUNET_MessageHeader); +} + + +static struct GNUNET_SERVER_MessageHandler handlers[] = { + {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} +}; + + +static void +task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct sockaddr_in sa; + struct sockaddr *sap[2]; + socklen_t slens[2]; + + sap[0] = (struct sockaddr *) &sa; + slens[0] = sizeof (sa); + sap[1] = NULL; + slens[1] = 0; + memset (&sa, 0, sizeof (sa)); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + sa.sin_family = AF_INET; + sa.sin_port = htons (PORT); + server = + GNUNET_SERVER_create (NULL, NULL, sap, slens, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO); + GNUNET_assert (server != NULL); + handlers[0].callback_cls = cls; + GNUNET_SERVER_add_handlers (server, handlers); + GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, cls); + cfg = GNUNET_CONFIGURATION_create (); + GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT); + GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", "localhost"); + GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", + "localhost"); + client = GNUNET_CLIENT_connect ("test", cfg); + GNUNET_assert (client != NULL); + GNUNET_CLIENT_notify_transmit_ready (client, 256, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 250), + GNUNET_NO, ¬ify_ready, NULL); +} + + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check () +{ + + ok = 1; + GNUNET_SCHEDULER_run (&task, NULL); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_server_with_client", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret += check (); + + return ret; +} + +/* end of test_server_with_client.c */ diff --git a/src/util/test_server_with_client_unix.c b/src/util/test_server_with_client_unix.c new file mode 100644 index 0000000..99af4e8 --- /dev/null +++ b/src/util/test_server_with_client_unix.c @@ -0,0 +1,212 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_server_with_client_unix.c + * @brief tests for server.c and client.c, + * specifically disconnect_notify, + * client_get_address and receive_done (resume processing) + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_client_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +#define MY_TYPE 128 + + +static struct GNUNET_SERVER_Handle *server; + +static struct GNUNET_CLIENT_Connection *client; + +static struct GNUNET_CONFIGURATION_Handle *cfg; + +static int ok; + +static void +send_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_SERVER_Client *argclient = cls; + + GNUNET_assert (ok == 3); + ok++; + GNUNET_SERVER_receive_done (argclient, GNUNET_OK); +} + + +static void +recv_cb (void *cls, struct GNUNET_SERVER_Client *argclient, + const struct GNUNET_MessageHeader *message) +{ + switch (ok) + { + case 2: + ok++; + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 50), + &send_done, argclient); + break; + case 4: + ok++; + GNUNET_CLIENT_disconnect (client, GNUNET_YES); + GNUNET_SERVER_receive_done (argclient, GNUNET_OK); + break; + default: + GNUNET_assert (0); + } + +} + + +static void +clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_SERVER_destroy (server); + server = NULL; + GNUNET_CONFIGURATION_destroy (cfg); + cfg = NULL; +} + + +/** + * Functions with this signature are called whenever a client + * is disconnected on the network level. + * + * @param cls closure + * @param client identification of the client + */ +static void +notify_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + if (client == NULL) + return; + GNUNET_assert (ok == 5); + ok = 0; + GNUNET_SCHEDULER_add_now (&clean_up, NULL); +} + + +static size_t +notify_ready (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg; + + GNUNET_assert (size >= 256); + GNUNET_assert (1 == ok); + ok++; + msg = buf; + msg->type = htons (MY_TYPE); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + msg++; + msg->type = htons (MY_TYPE); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + return 2 * sizeof (struct GNUNET_MessageHeader); +} + + +static struct GNUNET_SERVER_MessageHandler handlers[] = { + {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} +}; + + +static void +task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct sockaddr_un un; + const char *unixpath = "/tmp/testsock"; + size_t slen = strlen (unixpath); + struct sockaddr *sap[2]; + socklen_t slens[2]; + + memset (&un, 0, sizeof (un)); + un.sun_family = AF_UNIX; + memcpy (un.sun_path, unixpath, slen); + un.sun_path[slen] = '\0'; +#if HAVE_SOCKADDR_IN_SIN_LEN + un.sun_len = (u_char) sizeof (un); +#endif +#if LINUX + un.sun_path[0] = '\0'; +#endif + + + sap[0] = (struct sockaddr *) &un; + slens[0] = sizeof (un); + sap[1] = NULL; + slens[1] = 0; + server = + GNUNET_SERVER_create (NULL, NULL, sap, slens, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO); + GNUNET_assert (server != NULL); + handlers[0].callback_cls = cls; + GNUNET_SERVER_add_handlers (server, handlers); + GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, cls); + cfg = GNUNET_CONFIGURATION_create (); + + GNUNET_CONFIGURATION_set_value_string (cfg, "test", "UNIXPATH", unixpath); + GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", + "localhost"); + + client = GNUNET_CLIENT_connect ("test", cfg); + GNUNET_assert (client != NULL); + GNUNET_CLIENT_notify_transmit_ready (client, 256, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 250), + GNUNET_NO, ¬ify_ready, NULL); +} + + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check () +{ + + ok = 1; + GNUNET_SCHEDULER_run (&task, NULL); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + + GNUNET_log_setup ("test_server_with_client_unix", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret += check (); + + return ret; +} + +/* end of test_server_with_client_unix.c */ diff --git a/src/util/test_service.c b/src/util/test_service.c new file mode 100644 index 0000000..049282d --- /dev/null +++ b/src/util/test_service.c @@ -0,0 +1,287 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_service.c + * @brief tests for service.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_client_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_service_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + + +#define VERBOSE GNUNET_NO + +#define PORT 12435 + +#define MY_TYPE 256 + +static struct GNUNET_SERVICE_Context *sctx; + +static int ok = 1; + + +static size_t +build_msg (void *cls, size_t size, void *buf) +{ + struct GNUNET_CLIENT_Connection *client = cls; + struct GNUNET_MessageHeader *msg = buf; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected, transmitting\n"); + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + msg->type = htons (MY_TYPE); + msg->size = htons (sizeof (struct GNUNET_MessageHeader)); + GNUNET_CLIENT_disconnect (client, GNUNET_NO); + return sizeof (struct GNUNET_MessageHeader); +} + + +static void +ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + const struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct GNUNET_CLIENT_Connection *client; + + GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service confirmed running\n"); + client = GNUNET_CLIENT_connect ("test_service", cfg); + GNUNET_assert (client != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client connecting, waiting to transmit\n"); + GNUNET_CLIENT_notify_transmit_ready (client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_UNIT_SECONDS, GNUNET_NO, + &build_msg, client); +} + + +static void +do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_SERVICE_stop (sctx); +} + + +static void +recv_cb (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving client message...\n"); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + if (sctx != NULL) + GNUNET_SCHEDULER_add_now (&do_stop, NULL); + else + GNUNET_SCHEDULER_shutdown (); + ok = 0; +} + + +static struct GNUNET_SERVER_MessageHandler myhandlers[] = { + {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, + {NULL, NULL, 0, 0} +}; + + +static void +runner (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service initializing\n"); + GNUNET_SERVER_add_handlers (server, myhandlers); + GNUNET_CLIENT_service_test ("test_service", cfg, GNUNET_TIME_UNIT_SECONDS, + &ready, (void *) cfg); +} + + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check () +{ + ok = 1; + char *const argv[] = { + "test_service", + "-c", + "test_service_data.conf", + "-L", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL + }; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting service\n"); + GNUNET_assert (GNUNET_OK == + GNUNET_SERVICE_run (5, argv, "test_service", + GNUNET_SERVICE_OPTION_NONE, &runner, &ok)); + GNUNET_assert (0 == ok); + return ok; +} + +static void +ready6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + const struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct GNUNET_CLIENT_Connection *client; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "V6 ready\n"); + GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); + client = GNUNET_CLIENT_connect ("test_service6", cfg); + GNUNET_assert (client != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "V6 client connected\n"); + GNUNET_CLIENT_notify_transmit_ready (client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_UNIT_SECONDS, GNUNET_NO, + &build_msg, client); +} + +static void +runner6 (void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initializing v6 service\n"); + GNUNET_SERVER_add_handlers (server, myhandlers); + GNUNET_CLIENT_service_test ("test_service6", cfg, GNUNET_TIME_UNIT_SECONDS, + &ready6, (void *) cfg); +} + +/** + * Main method, starts scheduler with task1, + * checks that "ok" is correct at the end. + */ +static int +check6 () +{ + char *const argv[] = { + "test_service6", + "-c", + "test_service_data.conf", + "-L", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL + }; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting v6 service\n"); + GNUNET_assert (GNUNET_OK == + GNUNET_SERVICE_run (5, argv, "test_service6", + GNUNET_SERVICE_OPTION_NONE, &runner6, + &ok)); + GNUNET_assert (0 == ok); + return ok; +} + + + +static void +start_stop_main (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + int *ret = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting service using start method\n"); + sctx = GNUNET_SERVICE_start ("test_service", cfg); + GNUNET_assert (NULL != sctx); + runner (cls, GNUNET_SERVICE_get_server (sctx), cfg); + *ret = 0; +} + + +static int +check_start_stop () +{ + char *const argv[] = { + "test-service-program", + "-c", + "test_service_data.conf", + "-L", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL + }; + const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + int ret = 1; + + GNUNET_assert (GNUNET_OK == + GNUNET_PROGRAM_run (5, argv, "test-service-program", "no help", + options, &start_stop_main, &ret)); + + GNUNET_break (0 == ret); + return ret; +} + + +int +main (int argc, char *argv[]) +{ + int ret = 0; + struct GNUNET_NETWORK_Handle *s = NULL; + + GNUNET_log_setup ("test-service", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret += check (); + ret += check (); + + // FIXME +#ifndef MINGW + s = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); +#endif + if (NULL == s) + { + if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || + (errno == EACCES)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); + return 1; + } + FPRINTF (stderr, + "IPv6 support seems to not be available (%s), not testing it!\n", + strerror (errno)); + } + else + { + GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s)); + ret += check6 (); + } + ret += check_start_stop (); + + return ret; +} + +/* end of test_service.c */ diff --git a/src/util/test_service_data.conf b/src/util/test_service_data.conf new file mode 100644 index 0000000..7f6baaa --- /dev/null +++ b/src/util/test_service_data.conf @@ -0,0 +1,29 @@ +[test_service] +PORT=12435 +BINDTO=localhost +PIDFILE=/tmp/test-service.pid +TIMEOUT=30 s +MAXBUF=1024 +DISABLEV6=NO +ACCEPT_FROM=127.0.0.1; +REJECT_FROM=1.2.3.0/15;4.5.0.0/8;6.7.8.9/255.255.255.0; +ACCEPT_FROM6=::1; +REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40; +HOSTNAME=localhost + +[test_service6] +PORT=12435 +PIDFILE=/tmp/test-service.pid +TIMEOUT=30 s +MAXBUF=1024 +DISABLEV6=NO +ACCEPT_FROM=127.0.0.1; +REJECT_FROM=1.2.3.0/15;4.5.0.0/8;6.7.8.9/255.255.255.0; +ACCEPT_FROM6=::1; +REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40; +HOSTNAME=::1 + +[resolver] +HOSTNAME=localhost + + diff --git a/src/util/test_strings.c b/src/util/test_strings.c new file mode 100644 index 0000000..570776a --- /dev/null +++ b/src/util/test_strings.c @@ -0,0 +1,117 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_strings.c + * @brief testcase for strings.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_strings_lib.h" + +#define VERBOSE GNUNET_NO + +#define WANT(a,b) if (0 != strcmp(a,b)) { fprintf(stderr, "Got `%s', wanted `%s'\n", b, a); GNUNET_free(b); GNUNET_break(0); return 1;} else { GNUNET_free (b); } +#define WANTB(a,b,l) if (0 != memcmp(a,b,l)) { GNUNET_break(0); return 1;} else { } + +static int +check () +{ + char buf[128]; + char *r; + char *b; + struct GNUNET_TIME_Absolute at; + const char *hdir; + + sprintf (buf, "4 %s", _( /* size unit */ "b")); + b = GNUNET_STRINGS_byte_size_fancy (4); + WANT (buf, b); + sprintf (buf, "10 %s", _( /* size unit */ "KiB")); + b = GNUNET_STRINGS_byte_size_fancy (10240); + WANT (buf, b); + sprintf (buf, "10 %s", _( /* size unit */ "TiB")); + b = GNUNET_STRINGS_byte_size_fancy (10240LL * 1024LL * 1024LL * 1024LL); + WANT (buf, b); + sprintf (buf, "4 %s", _( /* time unit */ "ms")); + b = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, + 4)); + WANT (buf, b); + sprintf (buf, "7 %s", _( /* time unit */ "s")); + b = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, + 7 * 1000)); + WANT (buf, b); + sprintf (buf, "7 %s", _( /* time unit */ "h")); + b = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, + 7 * 60 * 60 * 1000)); + WANT (buf, b); +#ifndef MINGW + hdir = getenv ("HOME"); +#else + hdir = getenv ("USERPROFILE"); +#endif + GNUNET_snprintf (buf, sizeof (buf), "%s%s", hdir, DIR_SEPARATOR_STR); + b = GNUNET_STRINGS_filename_expand ("~"); + GNUNET_assert (b != NULL); + WANT (buf, b); + GNUNET_STRINGS_buffer_fill (buf, sizeof (buf), 3, "a", "btx", "c"); + WANTB ("a\0btx\0c", buf, 8); + if (6 != GNUNET_STRINGS_buffer_tokenize (buf, sizeof (buf), 2, &r, &b)) + return 1; + r = GNUNET_strdup (r); + WANT ("a", r); + b = GNUNET_strdup (b); + WANT ("btx", b); + if (0 != GNUNET_STRINGS_buffer_tokenize (buf, 2, 2, &r, &b)) + return 1; + at.abs_value = 5000; + r = GNUNET_STRINGS_absolute_time_to_string (at); + /* r should be something like "Wed Dec 31 17:00:05 1969" + * where the details of the day and hour depend on the timezone; + * however, the "0:05 19" should always be there; hence: */ + if (NULL == strstr (r, "0:05 19")) + { + FPRINTF (stderr, "Got %s\n", r); + GNUNET_break (0); + GNUNET_free (r); + return 1; + } + GNUNET_free (r); + b = GNUNET_STRINGS_to_utf8 ("TEST", 4, "ASCII"); + WANT ("TEST", b); + GNUNET_log_skip (2, GNUNET_NO); + b = GNUNET_STRINGS_to_utf8 ("TEST", 4, "unknown"); + GNUNET_log_skip (0, GNUNET_YES); + WANT ("TEST", b); + return 0; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test_strings", "ERROR", NULL); + ret = check (); + return ret; +} + +/* end of test_strings.c */ diff --git a/src/util/test_time.c b/src/util/test_time.c new file mode 100644 index 0000000..788884f --- /dev/null +++ b/src/util/test_time.c @@ -0,0 +1,244 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file util/test_time.c + * @brief testcase for time.c + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_time_lib.h" + +#define VERBOSE GNUNET_NO + +static int +check () +{ + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_AbsoluteNBO nown; + struct GNUNET_TIME_Absolute future; + struct GNUNET_TIME_Absolute past; + struct GNUNET_TIME_Absolute last; + struct GNUNET_TIME_Absolute forever; + struct GNUNET_TIME_Absolute zero; + struct GNUNET_TIME_Relative rel; + struct GNUNET_TIME_Relative relForever; + struct GNUNET_TIME_Relative relUnit; + struct GNUNET_TIME_RelativeNBO reln; + unsigned int i; + + forever = GNUNET_TIME_absolute_get_forever (); + relForever = GNUNET_TIME_relative_get_forever (); + relUnit = GNUNET_TIME_relative_get_unit (); + zero.abs_value = 0; + + last = now = GNUNET_TIME_absolute_get (); + while (now.abs_value == last.abs_value) + now = GNUNET_TIME_absolute_get (); + GNUNET_assert (now.abs_value > last.abs_value); + + /* test overflow checking in multiply */ + rel = GNUNET_TIME_UNIT_SECONDS; + GNUNET_log_skip (1, GNUNET_NO); + for (i = 0; i < 55; i++) + rel = GNUNET_TIME_relative_multiply (rel, 2); + GNUNET_log_skip (0, GNUNET_NO); + GNUNET_assert (rel.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value); + /*check zero */ + rel.rel_value = (UINT64_MAX) - 1024; + GNUNET_assert (GNUNET_TIME_relative_get_zero ().rel_value == + GNUNET_TIME_relative_multiply (rel, 0).rel_value); + + /* test infinity-check for relative to absolute */ + GNUNET_log_skip (1, GNUNET_NO); + last = GNUNET_TIME_relative_to_absolute (rel); + GNUNET_assert (last.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value); + GNUNET_log_skip (0, GNUNET_YES); + + /*check relative to absolute */ + rel.rel_value = 0; + GNUNET_assert (GNUNET_TIME_absolute_get ().abs_value == + GNUNET_TIME_relative_to_absolute (rel).abs_value); + /*check forever */ + rel.rel_value = UINT64_MAX; + GNUNET_assert (GNUNET_TIME_absolute_get_forever ().abs_value == + GNUNET_TIME_relative_to_absolute (rel).abs_value); + /* check overflow for r2a */ + rel.rel_value = (UINT64_MAX) - 1024; + GNUNET_log_skip (1, GNUNET_NO); + last = GNUNET_TIME_relative_to_absolute (rel); + GNUNET_log_skip (0, GNUNET_NO); + GNUNET_assert (last.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value); + + /* check overflow for relative add */ + GNUNET_log_skip (1, GNUNET_NO); + rel = GNUNET_TIME_relative_add (rel, rel); + GNUNET_log_skip (0, GNUNET_NO); + GNUNET_assert (rel.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value); + + GNUNET_log_skip (1, GNUNET_NO); + rel = GNUNET_TIME_relative_add (relForever, relForever); + GNUNET_log_skip (0, GNUNET_NO); + GNUNET_assert (rel.rel_value == relForever.rel_value); + + GNUNET_log_skip (1, GNUNET_NO); + rel = GNUNET_TIME_relative_add (relUnit, relUnit); + GNUNET_assert (rel.rel_value == 2 * relUnit.rel_value); + + /* check relation check in get_duration */ + future.abs_value = now.abs_value + 1000000; + GNUNET_assert (GNUNET_TIME_absolute_get_difference (now, future).rel_value == + 1000000); + GNUNET_assert (GNUNET_TIME_absolute_get_difference (future, now).rel_value == + 0); + + GNUNET_assert (GNUNET_TIME_absolute_get_difference (zero, forever).rel_value + == forever.abs_value); + + past.abs_value = now.abs_value - 1000000; + rel = GNUNET_TIME_absolute_get_duration (future); + GNUNET_assert (rel.rel_value == 0); + rel = GNUNET_TIME_absolute_get_duration (past); + GNUNET_assert (rel.rel_value >= 1000000); + + /* check get remaining */ + rel = GNUNET_TIME_absolute_get_remaining (now); + GNUNET_assert (rel.rel_value == 0); + rel = GNUNET_TIME_absolute_get_remaining (past); + GNUNET_assert (rel.rel_value == 0); + rel = GNUNET_TIME_absolute_get_remaining (future); + GNUNET_assert (rel.rel_value > 0); + GNUNET_assert (rel.rel_value <= 1000000); + forever = GNUNET_TIME_absolute_get_forever (); + GNUNET_assert (GNUNET_TIME_relative_get_forever ().rel_value == + GNUNET_TIME_absolute_get_remaining (forever).rel_value); + + /* check endianess */ + reln = GNUNET_TIME_relative_hton (rel); + GNUNET_assert (rel.rel_value == GNUNET_TIME_relative_ntoh (reln).rel_value); + nown = GNUNET_TIME_absolute_hton (now); + GNUNET_assert (now.abs_value == GNUNET_TIME_absolute_ntoh (nown).abs_value); + + /* check absolute addition */ + future = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_SECONDS); + GNUNET_assert (future.abs_value == now.abs_value + 1000); + + future = GNUNET_TIME_absolute_add (forever, GNUNET_TIME_UNIT_ZERO); + GNUNET_assert (future.abs_value == forever.abs_value); + + rel.rel_value = (UINT64_MAX) - 1024; + now.abs_value = rel.rel_value; + future = GNUNET_TIME_absolute_add (now, rel); + GNUNET_assert (future.abs_value == forever.abs_value); + + /* check zero */ + future = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_ZERO); + GNUNET_assert (future.abs_value == now.abs_value); + + GNUNET_assert (forever.abs_value == + GNUNET_TIME_absolute_subtract (forever, + GNUNET_TIME_UNIT_MINUTES).abs_value); + /*check absolute subtract */ + now.abs_value = 50000; + rel.rel_value = 100000; + GNUNET_assert (GNUNET_TIME_UNIT_ZERO_ABS.abs_value == + (GNUNET_TIME_absolute_subtract (now, rel)).abs_value); + rel.rel_value = 10000; + GNUNET_assert (40000 == (GNUNET_TIME_absolute_subtract (now, rel)).abs_value); + + /*check relative divide */ + GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value == + (GNUNET_TIME_relative_divide (rel, 0)).rel_value); + + rel = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value == + (GNUNET_TIME_relative_divide (rel, 2)).rel_value); + + rel = GNUNET_TIME_relative_divide (relUnit, 2); + GNUNET_assert (rel.rel_value == relUnit.rel_value / 2); + + + /* check Return absolute time of 0ms */ + zero = GNUNET_TIME_absolute_get_zero (); + + /* check GNUNET_TIME_calculate_eta */ + last.abs_value = GNUNET_TIME_absolute_get ().abs_value - 1024; + forever = GNUNET_TIME_absolute_get_forever (); + forever.abs_value = forever.abs_value - 1024; + GNUNET_assert (GNUNET_TIME_absolute_get_zero ().abs_value == + GNUNET_TIME_calculate_eta (forever, 50000, 100000).rel_value); + /* check zero */ + GNUNET_log_skip (1, GNUNET_NO); + GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value == + (GNUNET_TIME_calculate_eta (last, 60000, 50000)).rel_value); + GNUNET_log_skip (0, GNUNET_YES); + /*check forever */ + GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value == + (GNUNET_TIME_calculate_eta (last, 0, 50000)).rel_value); + + /*check relative subtract */ + now = GNUNET_TIME_absolute_get (); + rel.rel_value = now.abs_value; + relForever.rel_value = rel.rel_value + 1024; + GNUNET_assert (1024 == + GNUNET_TIME_relative_subtract (relForever, rel).rel_value); + /*check zero */ + GNUNET_assert (GNUNET_TIME_relative_get_zero ().rel_value == + GNUNET_TIME_relative_subtract (rel, relForever).rel_value); + /*check forever */ + rel.rel_value = UINT64_MAX; + GNUNET_assert (GNUNET_TIME_relative_get_forever ().rel_value == + GNUNET_TIME_relative_subtract (rel, relForever).rel_value); + + /*check GNUNET_TIME_relative_min */ + now = GNUNET_TIME_absolute_get (); + rel.rel_value = now.abs_value; + relForever.rel_value = rel.rel_value - 1024; + GNUNET_assert (relForever.rel_value == + GNUNET_TIME_relative_min (rel, relForever).rel_value); + + /*check GNUNET_TIME_relative_max */ + GNUNET_assert (rel.rel_value == + GNUNET_TIME_relative_max (rel, relForever).rel_value); + + /*check GNUNET_TIME_absolute_min */ + now = GNUNET_TIME_absolute_get (); + last.abs_value = now.abs_value - 1024; + GNUNET_assert (last.abs_value == + GNUNET_TIME_absolute_min (now, last).abs_value); + + /*check GNUNET_TIME_absolute_max */ + GNUNET_assert (now.abs_value == + GNUNET_TIME_absolute_max (now, last).abs_value); + + return 0; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-time", "WARNING", NULL); + ret = check (); + + return ret; +} + +/* end of test_time.c */ diff --git a/src/util/time.c b/src/util/time.c new file mode 100644 index 0000000..c57ccd1 --- /dev/null +++ b/src/util/time.c @@ -0,0 +1,521 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2006, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/time.c + * @author Christian Grothoff + * @brief functions for handling time and time arithmetic + */ +#include "platform.h" +#include "gnunet_time_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +/** + * Variable used to simulate clock skew. Used for testing, never in production. + */ +static long long timestamp_offset; + +/** + * Set the timestamp offset for this instance. + * + * @param offset the offset to skew the locale time by + */ +void +GNUNET_TIME_set_offset (long long offset) +{ + timestamp_offset = offset; +} + +/** + * Get the current time (works just as "time", just that we use the + * unit of time that the cron-jobs use (and is 64 bit)). + * + * @return the current time + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_get () +{ + struct GNUNET_TIME_Absolute ret; + struct timeval tv; + + GETTIMEOFDAY (&tv, NULL); + ret.abs_value = + (uint64_t) (((uint64_t) tv.tv_sec * 1000LL) + + ((uint64_t) tv.tv_usec / 1000LL)) + timestamp_offset; + return ret; +} + + +/** + * Return relative time of 0ms. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_get_zero () +{ + static struct GNUNET_TIME_Relative zero; + + return zero; +} + + +/** + * Return absolute time of 0ms. + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_get_zero () +{ + static struct GNUNET_TIME_Absolute zero; + + return zero; +} + +/** + * Return relative time of 1ms. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_get_unit () +{ + static struct GNUNET_TIME_Relative one = { 1 }; + return one; +} + +/** + * Return "forever". + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_get_forever () +{ + static struct GNUNET_TIME_Relative forever = { UINT64_MAX }; + return forever; +} + +/** + * Return "forever". + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_get_forever () +{ + static struct GNUNET_TIME_Absolute forever = { UINT64_MAX }; + return forever; +} + +/** + * Convert relative time to an absolute time in the + * future. + * + * @return timestamp that is "rel" in the future, or FOREVER if rel==FOREVER (or if we would overflow) + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel) +{ + struct GNUNET_TIME_Absolute ret; + + if (rel.rel_value == UINT64_MAX) + return GNUNET_TIME_absolute_get_forever (); + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + + if (rel.rel_value + now.abs_value < rel.rel_value) + { + GNUNET_break (0); /* overflow... */ + return GNUNET_TIME_absolute_get_forever (); + } + ret.abs_value = rel.rel_value + now.abs_value; + return ret; +} + + +/** + * Return the minimum of two relative time values. + * + * @param t1 first timestamp + * @param t2 other timestamp + * @return timestamp that is smaller + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_min (struct GNUNET_TIME_Relative t1, + struct GNUNET_TIME_Relative t2) +{ + return (t1.rel_value < t2.rel_value) ? t1 : t2; +} + + +/** + * Return the maximum of two relative time values. + * + * @param t1 first timestamp + * @param t2 other timestamp + * @return timestamp that is larger + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_max (struct GNUNET_TIME_Relative t1, + struct GNUNET_TIME_Relative t2) +{ + return (t1.rel_value > t2.rel_value) ? t1 : t2; +} + + + +/** + * Return the minimum of two relative time values. + * + * @param t1 first timestamp + * @param t2 other timestamp + * @return timestamp that is smaller + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_min (struct GNUNET_TIME_Absolute t1, + struct GNUNET_TIME_Absolute t2) +{ + return (t1.abs_value < t2.abs_value) ? t1 : t2; +} + + +/** + * Return the maximum of two relative time values. + * + * @param t1 first timestamp + * @param t2 other timestamp + * @return timestamp that is smaller + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_max (struct GNUNET_TIME_Absolute t1, + struct GNUNET_TIME_Absolute t2) +{ + return (t1.abs_value > t2.abs_value) ? t1 : t2; +} + + +/** + * Given a timestamp in the future, how much time + * remains until then? + * + * @return future - now, or 0 if now >= future, or FOREVER if future==FOREVER. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_absolute_get_remaining (struct GNUNET_TIME_Absolute future) +{ + struct GNUNET_TIME_Relative ret; + + if (future.abs_value == UINT64_MAX) + return GNUNET_TIME_relative_get_forever (); + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + + if (now.abs_value > future.abs_value) + return GNUNET_TIME_relative_get_zero (); + ret.rel_value = future.abs_value - now.abs_value; + return ret; +} + +/** + * Compute the time difference between the given start and end times. + * Use this function instead of actual subtraction to ensure that + * "FOREVER" and overflows are handled correctly. + * + * @return 0 if start >= end; FOREVER if end==FOREVER; otherwise end - start + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_absolute_get_difference (struct GNUNET_TIME_Absolute start, + struct GNUNET_TIME_Absolute end) +{ + struct GNUNET_TIME_Relative ret; + + if (end.abs_value == UINT64_MAX) + return GNUNET_TIME_relative_get_forever (); + if (end.abs_value < start.abs_value) + return GNUNET_TIME_relative_get_zero (); + ret.rel_value = end.abs_value - start.abs_value; + return ret; +} + +/** + * Get the duration of an operation as the + * difference of the current time and the given start time "whence". + * + * @return aborts if whence==FOREVER, 0 if whence > now, otherwise now-whence. + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_absolute_get_duration (struct GNUNET_TIME_Absolute whence) +{ + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Relative ret; + + now = GNUNET_TIME_absolute_get (); + GNUNET_assert (whence.abs_value != UINT64_MAX); + if (whence.abs_value > now.abs_value) + return GNUNET_TIME_relative_get_zero (); + ret.rel_value = now.abs_value - whence.abs_value; + return ret; +} + + +/** + * Add a given relative duration to the + * given start time. + * + * @return FOREVER if either argument is FOREVER or on overflow; start+duration otherwise + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_add (struct GNUNET_TIME_Absolute start, + struct GNUNET_TIME_Relative duration) +{ + struct GNUNET_TIME_Absolute ret; + + if ((start.abs_value == UINT64_MAX) || (duration.rel_value == UINT64_MAX)) + return GNUNET_TIME_absolute_get_forever (); + if (start.abs_value + duration.rel_value < start.abs_value) + { + GNUNET_break (0); + return GNUNET_TIME_absolute_get_forever (); + } + ret.abs_value = start.abs_value + duration.rel_value; + return ret; +} + + +/** + * Subtract a given relative duration from the + * given start time. + * + * @param start some absolute time + * @param duration some relative time to subtract + * @return ZERO if start <= duration, or FOREVER if start time is FOREVER; start-duration otherwise + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_subtract (struct GNUNET_TIME_Absolute start, + struct GNUNET_TIME_Relative duration) +{ + struct GNUNET_TIME_Absolute ret; + + if (start.abs_value <= duration.rel_value) + return GNUNET_TIME_UNIT_ZERO_ABS; + if (start.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) + return GNUNET_TIME_UNIT_FOREVER_ABS; + ret.abs_value = start.abs_value - duration.rel_value; + return ret; +} + + +/** + * Multiply relative time by a given factor. + * + * @return FOREVER if rel=FOREVER or on overflow; otherwise rel*factor + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel, + unsigned int factor) +{ + struct GNUNET_TIME_Relative ret; + + if (factor == 0) + return GNUNET_TIME_relative_get_zero (); + ret.rel_value = rel.rel_value * (unsigned long long) factor; + if (ret.rel_value / factor != rel.rel_value) + { + GNUNET_break (0); + return GNUNET_TIME_relative_get_forever (); + } + return ret; +} + + +/** + * Divide relative time by a given factor. + * + * @param rel some duration + * @param factor integer to divide by + * @return FOREVER if rel=FOREVER or factor==0; otherwise rel/factor + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_divide (struct GNUNET_TIME_Relative rel, + unsigned int factor) +{ + struct GNUNET_TIME_Relative ret; + + if ((factor == 0) || + (rel.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)) + return GNUNET_TIME_UNIT_FOREVER_REL; + ret.rel_value = rel.rel_value / (unsigned long long) factor; + return ret; +} + + +/** + * Calculate the estimate time of arrival/completion + * for an operation. + * + * @param start when did the operation start? + * @param finished how much has been done? + * @param total how much must be done overall (same unit as for "finished") + * @return remaining duration for the operation, + * assuming it continues at the same speed + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_calculate_eta (struct GNUNET_TIME_Absolute start, uint64_t finished, + uint64_t total) +{ + struct GNUNET_TIME_Relative dur; + double exp; + struct GNUNET_TIME_Relative ret; + + GNUNET_break (finished <= total); + if (finished >= total) + return GNUNET_TIME_UNIT_ZERO; + if (finished == 0) + return GNUNET_TIME_UNIT_FOREVER_REL; + dur = GNUNET_TIME_absolute_get_duration (start); + exp = ((double) dur.rel_value) * ((double) total) / ((double) finished); + ret.rel_value = ((uint64_t) exp) - dur.rel_value; + return ret; +} + + +/** + * Add relative times together. + * + * @param a1 first timestamp + * @param a2 second timestamp + * @return FOREVER if either argument is FOREVER or on overflow; a1+a2 otherwise + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_add (struct GNUNET_TIME_Relative a1, + struct GNUNET_TIME_Relative a2) +{ + struct GNUNET_TIME_Relative ret; + + if ((a1.rel_value == UINT64_MAX) || (a2.rel_value == UINT64_MAX)) + return GNUNET_TIME_relative_get_forever (); + if (a1.rel_value + a2.rel_value < a1.rel_value) + { + GNUNET_break (0); + return GNUNET_TIME_relative_get_forever (); + } + ret.rel_value = a1.rel_value + a2.rel_value; + return ret; +} + + +/** + * Subtract relative timestamp from the other. + * + * @param a1 first timestamp + * @param a2 second timestamp + * @return ZERO if a2>=a1 (including both FOREVER), FOREVER if a1 is FOREVER, a1-a2 otherwise + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_subtract (struct GNUNET_TIME_Relative a1, + struct GNUNET_TIME_Relative a2) +{ + struct GNUNET_TIME_Relative ret; + + if (a2.rel_value >= a1.rel_value) + return GNUNET_TIME_relative_get_zero (); + if (a1.rel_value == UINT64_MAX) + return GNUNET_TIME_relative_get_forever (); + ret.rel_value = a1.rel_value - a2.rel_value; + return ret; +} + + +/** + * Convert relative time to network byte order. + * + * @param a time to convert + * @return time in network byte order + */ +struct GNUNET_TIME_RelativeNBO +GNUNET_TIME_relative_hton (struct GNUNET_TIME_Relative a) +{ + struct GNUNET_TIME_RelativeNBO ret; + + ret.rel_value__ = GNUNET_htonll (a.rel_value); + return ret; +} + +/** + * Convert relative time from network byte order. + * + * @param a time to convert + * @return time in host byte order + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_ntoh (struct GNUNET_TIME_RelativeNBO a) +{ + struct GNUNET_TIME_Relative ret; + + ret.rel_value = GNUNET_ntohll (a.rel_value__); + return ret; + +} + +/** + * Convert absolute time to network byte order. + * + * @param a time to convert + * @return time in network byte order + */ +struct GNUNET_TIME_AbsoluteNBO +GNUNET_TIME_absolute_hton (struct GNUNET_TIME_Absolute a) +{ + struct GNUNET_TIME_AbsoluteNBO ret; + + ret.abs_value__ = GNUNET_htonll (a.abs_value); + return ret; +} + +/** + * Convert absolute time from network byte order. + * + * @param a time to convert + * @return time in host byte order + */ +struct GNUNET_TIME_Absolute +GNUNET_TIME_absolute_ntoh (struct GNUNET_TIME_AbsoluteNBO a) +{ + struct GNUNET_TIME_Absolute ret; + + ret.abs_value = GNUNET_ntohll (a.abs_value__); + return ret; + +} + +/** + * Convert a relative time to a string. + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param time the time to print + * + * @return string form of the time (as milliseconds) + */ +const char * +GNUNET_TIME_relative_to_string (struct GNUNET_TIME_Relative time) +{ + static char time_string[21]; + + memset (time_string, 0, sizeof (time_string)); + + sprintf (time_string, "%llu", (unsigned long long) time.rel_value); + return (const char *) time_string; +} + + + +/* end of time.c */ diff --git a/src/util/util.conf b/src/util/util.conf new file mode 100644 index 0000000..ba9dfec --- /dev/null +++ b/src/util/util.conf @@ -0,0 +1,16 @@ +[PATHS] +SERVICEHOME = ~/.gnunet/ +# SERVICEHOME = /var/lib/gnunet/ +# DEFAULTCONFIG = /etc/gnunet.conf +# If 'DEFAULTCONFIG' is not defined, the current +# configuration file is assumed to be the default, +# which is what we want by default... + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[client] +HOME = $SERVICEHOME + +[TESTING] +WEAKRANDOM = NO diff --git a/src/util/win.cc b/src/util/win.cc new file mode 100644 index 0000000..1f66072 --- /dev/null +++ b/src/util/win.cc @@ -0,0 +1,1266 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/win.cc + * @brief Helper functions for MS Windows in C++ + * @author Nils Durner + */ + +#ifndef _WIN_CC +#define _WIN_CC + +#include "winproc.h" +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" + +#include +using namespace std; +#include + +#ifndef INHERITED_ACE +#define INHERITED_ACE 0x10 +#endif + +extern "C" { + +int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows); + +#define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \ + union { \ + struct { \ + ULONG Length; \ + DWORD Flags; \ + }; \ + }; \ + +#define _IP_ADAPTER_UNICAST_ADDRESS_BASE \ + SOCKET_ADDRESS Address; \ + IP_PREFIX_ORIGIN PrefixOrigin; \ + IP_SUFFIX_ORIGIN SuffixOrigin; \ + IP_DAD_STATE DadState; \ + ULONG ValidLifetime; \ + ULONG PreferredLifetime; \ + ULONG LeaseLifetime; + +#define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \ + UINT8 OnLinkPrefixLength; + + +#define _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(suffix,addition) \ +typedef struct _IP_ADAPTER_UNICAST_ADDRESS##suffix { \ + _IP_ADAPTER_UNICAST_ADDRESS_HEAD \ + struct _IP_ADAPTER_UNICAST_ADDRESS##suffix *Next; \ + _IP_ADAPTER_UNICAST_ADDRESS_BASE \ + addition \ +} IP_ADAPTER_UNICAST_ADDRESS##suffix, *PIP_ADAPTER_UNICAST_ADDRESS##suffix; + +/* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */ +_IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA,_IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA) + + +typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD Reserved; + }; + }; + struct _IP_ADAPTER_WINS_SERVER_ADDRESS *Next; + SOCKET_ADDRESS Address; +} IP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS_LH; + +typedef struct _IP_ADAPTER_GATEWAY_ADDRESS { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD Reserved; + }; + }; + struct _IP_ADAPTER_GATEWAY_ADDRESS *Next; + SOCKET_ADDRESS Address; +} IP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS_LH; + +typedef UINT32 NET_IF_COMPARTMENT_ID; +typedef GUID NET_IF_NETWORK_GUID; + +typedef enum _NET_IF_CONNECTION_TYPE { + NET_IF_CONNECTION_DEDICATED = 1, + NET_IF_CONNECTION_PASSIVE, + NET_IF_CONNECTION_DEMAND, + NET_IF_CONNECTION_MAXIMUM +} NET_IF_CONNECTION_TYPE, *PNET_IF_CONNECTION_TYPE; + +typedef enum { + TUNNEL_TYPE_NONE = 0, + TUNNEL_TYPE_OTHER, + TUNNEL_TYPE_DIRECT, + TUNNEL_TYPE_6TO4, + TUNNEL_TYPE_ISATAP, + TUNNEL_TYPE_TEREDO, + TUNNEL_TYPE_IPHTTPS +} TUNNEL_TYPE, *PTUNNEL_TYPE; + +/* +A DUID consists of a two-octet type code represented in network byte + order, followed by a variable number of octets that make up the + actual identifier. A DUID can be no more than 128 octets long (not + including the type code). +*/ +#define MAX_DHCPV6_DUID_LENGTH 130 + +typedef union _NET_LUID { + ULONG64 Value; + struct { + ULONG64 Reserved :24; + ULONG64 NetLuidIndex :24; + ULONG64 IfType :16; + } Info; +} NET_LUID, *PNET_LUID, IF_LUID; + +#define MAX_DNS_SUFFIX_STRING_LENGTH 246 + +typedef struct _IP_ADAPTER_DNS_SUFFIX { + struct _IP_ADAPTER_DNS_SUFFIX *Next; + WCHAR String[MAX_DNS_SUFFIX_STRING_LENGTH]; +} IP_ADAPTER_DNS_SUFFIX, *PIP_ADAPTER_DNS_SUFFIX; + + + +#define _IP_ADAPTER_ADDRESSES_HEAD \ + union { \ + ULONGLONG Alignment; \ + struct { \ + ULONG Length; \ + DWORD IfIndex; \ + }; \ + }; + +#define _IP_ADAPTER_ADDRESSES_BASE \ + PCHAR AdapterName; \ + PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress; \ + PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress; \ + PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress; \ + PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress; \ + PWCHAR DnsSuffix; \ + PWCHAR Description; \ + PWCHAR FriendlyName; \ + BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \ + DWORD PhysicalAddressLength; \ + DWORD Flags; \ + DWORD Mtu; \ + DWORD IfType; \ + IF_OPER_STATUS OperStatus; + +#define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \ + DWORD Ipv6IfIndex; \ + DWORD ZoneIndices[16]; \ + PIP_ADAPTER_PREFIX FirstPrefix; \ + + +#define _IP_ADAPTER_ADDRESSES_ADD_VISTA \ + _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \ + ULONG64 TransmitLinkSpeed; \ + ULONG64 ReceiveLinkSpeed; \ + PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; \ + PIP_ADAPTER_GATEWAY_ADDRESS_LH FirstGatewayAddress; \ + ULONG Ipv4Metric; \ + ULONG Ipv6Metric; \ + IF_LUID Luid; \ + SOCKET_ADDRESS Dhcpv4Server; \ + NET_IF_COMPARTMENT_ID CompartmentId; \ + NET_IF_NETWORK_GUID NetworkGuid; \ + NET_IF_CONNECTION_TYPE ConnectionType; \ + TUNNEL_TYPE TunnelType; \ + SOCKET_ADDRESS Dhcpv6Server; \ + BYTE Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; \ + ULONG Dhcpv6ClientDuidLength; \ + ULONG Dhcpv6Iaid; + +#define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \ + _IP_ADAPTER_ADDRESSES_ADD_VISTA \ + PIP_ADAPTER_DNS_SUFFIX FirstDnsSuffix; + +#define _IP_ADAPTER_ADDRESSES_DEFINE(suffix,addition) \ +typedef struct _IP_ADAPTER_ADDRESSES##suffix { \ + _IP_ADAPTER_ADDRESSES_HEAD \ + struct _IP_ADAPTER_ADDRESSES##suffix *Next; \ + _IP_ADAPTER_ADDRESSES_BASE \ + addition \ +} IP_ADAPTER_ADDRESSES##suffix, *PIP_ADAPTER_ADDRESSES##suffix; + + +/* _IP_ADAPTER_ADDRESSES_DEFINE(,) defined in w32api headers */ +_IP_ADAPTER_ADDRESSES_DEFINE(_XPSP1,_IP_ADAPTER_ADDRESSES_ADD_XPSP1) +_IP_ADAPTER_ADDRESSES_DEFINE(_VISTA,_IP_ADAPTER_ADDRESSES_ADD_VISTA) +_IP_ADAPTER_ADDRESSES_DEFINE(_2008_OR_VISTASP1,_IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1) + +static int +EnumNICs_IPv6_get_ifs_count (SOCKET s) +{ + DWORD dwret = 0, err; + int iret; + iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, + &dwret, NULL, NULL); + err = GetLastError (); + if (iret == SOCKET_ERROR && err == WSAEFAULT) + return dwret; + else if (iret == 0) + return 0; + return GNUNET_SYSERR; +} + +static int +EnumNICs_IPv6_get_ifs (SOCKET s, SOCKET_ADDRESS_LIST *inf, int size) +{ + int iret; + DWORD dwret = 0; + iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, inf, size, + &dwret, NULL, NULL); + + if (iret != 0 || dwret != size) + { + /* It's supposed to succeed! And size should be the same */ + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +#undef GNUNET_malloc +#define GNUNET_malloc(a) HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY | \ + HEAP_GENERATE_EXCEPTIONS, a) + +#undef GNUNET_free +#define GNUNET_free(a) HeapFree(GetProcessHeap (), 0, a) + +#undef GNUNET_free_non_null +#define GNUNET_free_non_null(a) do { if ((a) != NULL) GNUNET_free(a); } while (0) + +static int +EnumNICs_IPv4_get_ifs (SOCKET s, INTERFACE_INFO **inf, int *size) +{ + int iret; + DWORD dwret = 0; + DWORD error; + INTERFACE_INFO *ii = NULL; + DWORD ii_size = sizeof (INTERFACE_INFO) * 15; + while (TRUE) + { + if (ii_size >= sizeof (INTERFACE_INFO) * 1000) + return GNUNET_SYSERR; + ii = (INTERFACE_INFO *) GNUNET_malloc (ii_size); + dwret = 0; + iret = WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, ii, ii_size, + &dwret, NULL, NULL); + error = GetLastError (); + if (iret == SOCKET_ERROR) + { + if (error == WSAEFAULT) + { + GNUNET_free (ii); + ii_size *= 2; + continue; + } + GNUNET_free (ii); + return GNUNET_SYSERR; + } + else + { + *inf = ii; + *size = dwret; + return GNUNET_OK; + } + } + return GNUNET_SYSERR; +} + +int +EnumNICs2 (INTERFACE_INFO **ifs4, int *ifs4_len, SOCKET_ADDRESS_LIST **ifs6) +{ + int result = 0; + SOCKET s4 = INVALID_SOCKET, s6 = INVALID_SOCKET; + DWORD dwret1 = 0, dwret2; + DWORD err1, err2; + int ifs4len = 0, ifs6len = 0; + INTERFACE_INFO *interfaces4 = NULL; + SOCKET_ADDRESS_LIST *interfaces6 = NULL; + SetLastError (0); + s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + err1 = GetLastError (); + SetLastError (0); + s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP); + err2 = GetLastError (); + if (s6 != INVALID_SOCKET) + { + ifs6len = EnumNICs_IPv6_get_ifs_count (s6); + if (ifs6len > 0) + { + interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len); + result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result; + } + closesocket (s6); + s6 = INVALID_SOCKET; + } + + if (s4 != INVALID_SOCKET) + { + result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result; + closesocket (s4); + s4 = INVALID_SOCKET; + } + if (ifs6len + ifs4len == 0) + goto error; + + if (!result) + { + *ifs4 = interfaces4; + *ifs4_len = ifs4len; + *ifs6 = interfaces6; + return GNUNET_OK; + } +error: + if (interfaces4 != NULL) + GNUNET_free (interfaces4); + if (interfaces6 != NULL) + GNUNET_free (interfaces6); + if (s4 != INVALID_SOCKET) + closesocket (s4); + if (s6 != INVALID_SOCKET) + closesocket (s6); + return GNUNET_SYSERR; +} + +/** + * Returns GNUNET_OK on OK, GNUNET_SYSERR on error + */ +int +EnumNICs3 (struct EnumNICs3_results **results, int *results_count) +{ + DWORD dwRetVal = 0; + int count = 0; + ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; + struct sockaddr_in6 examplecom6; + IPAddr examplecom; + DWORD best_interface = 0; + DWORD best_interface6 = 0; + + int use_enum2 = 0; + INTERFACE_INFO *interfaces4 = NULL; + int interfaces4_len = 0; + SOCKET_ADDRESS_LIST *interfaces6 = NULL; + + unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES); + IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL; + IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen); + + if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen) + == ERROR_BUFFER_OVERFLOW) + { + GNUNET_free (pAddresses); + pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen); + } + + dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen); + + if (dwRetVal != NO_ERROR) + { + GNUNET_free (pAddresses); + return GNUNET_SYSERR; + } + + if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA)) + { + use_enum2 = 1; + + /* Enumerate NICs using WSAIoctl() */ + if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6)) + { + GNUNET_free (pAddresses); + return GNUNET_SYSERR; + } + } + + examplecom = inet_addr("192.0.34.166"); /* www.example.com */ + if (GetBestInterface (examplecom, &best_interface) != NO_ERROR) + best_interface = 0; + + if (GNGetBestInterfaceEx != NULL) + { + examplecom6.sin6_family = AF_INET6; + examplecom6.sin6_port = 0; + examplecom6.sin6_flowinfo = 0; + examplecom6.sin6_scope_id = 0; + inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10", + (struct sockaddr *) &examplecom6.sin6_addr); + dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6, + &best_interface6); + if (dwRetVal != NO_ERROR) + best_interface6 = 0; + } + + /* Give IPv6 a priority */ + if (best_interface6 != 0) + best_interface = best_interface6; + + count = 0; + for (pCurrentAddress = pAddresses; + pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next) + { + if (pCurrentAddress->OperStatus == IfOperStatusUp) + { + IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL; + for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL; + unicast = unicast->Next) + { + if ((unicast->Address.lpSockaddr->sa_family == AF_INET || + unicast->Address.lpSockaddr->sa_family == AF_INET6) && + (unicast->DadState == IpDadStateDeprecated || + unicast->DadState == IpDadStatePreferred)) + count += 1; + } + } + } + + if (count == 0) + { + *results = NULL; + *results_count = 0; + GNUNET_free (pAddresses); + GNUNET_free_non_null (interfaces4); + GNUNET_free_non_null (interfaces6); + return GNUNET_OK; + } + + *results = (struct EnumNICs3_results *) GNUNET_malloc ( + sizeof (struct EnumNICs3_results) * count); + *results_count = count; + + count = 0; + for (pCurrentAddress = pAddresses; + pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next) + { + struct EnumNICs3_results *r; + IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL; + if (pCurrentAddress->OperStatus != IfOperStatusUp) + continue; + for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL; + unicast = unicast->Next) + { + int i, j; + int mask_length = -1; + char dst[INET6_ADDRSTRLEN + 1]; + + if ((unicast->Address.lpSockaddr->sa_family != AF_INET && + unicast->Address.lpSockaddr->sa_family != AF_INET6) || + (unicast->DadState != IpDadStateDeprecated && + unicast->DadState != IpDadStatePreferred)) + continue; + + r = &(*results)[count]; + r->flags = 0; + if (pCurrentAddress->IfIndex > 0 && + pCurrentAddress->IfIndex == best_interface && + unicast->Address.lpSockaddr->sa_family == AF_INET) + r->is_default = 1; + else if (pCurrentAddress->Ipv6IfIndex > 0 && + pCurrentAddress->Ipv6IfIndex == best_interface6 && + unicast->Address.lpSockaddr->sa_family == AF_INET6) + r->is_default = 1; + else + r->is_default = 0; + + /* Don't choose default interface twice */ + if (r->is_default) + best_interface = best_interface6 = 0; + + if (!use_enum2) + { + memcpy (&r->address, unicast->Address.lpSockaddr, + unicast->Address.iSockaddrLength); + memset (&r->mask, 0, sizeof (struct sockaddr)); + mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)-> + OnLinkPrefixLength; + /* OnLinkPrefixLength is the number of leading 1s in the mask. + * OnLinkPrefixLength is available on Vista and later (hence use_enum2). + */ + if (unicast->Address.lpSockaddr->sa_family == AF_INET) + { + struct sockaddr_in *m = (struct sockaddr_in *) &r->mask; + for (i = 0; i < mask_length; i++) + ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8); + } + else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) + { + struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask; + struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast; + for (i = 0; i < mask_length; i++) + ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8); + memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength); + for (i = mask_length; i < 128; i++) + ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8); + } + r->flags |= ENUMNICS3_MASK_OK; + } + else + { + int found = 0; + if (unicast->Address.lpSockaddr->sa_family == AF_INET) + { + for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++) + { + struct sockaddr_in *m = (struct sockaddr_in *) &r->mask; + if (memcpy (&interfaces4[i].iiAddress.Address, + unicast->Address.lpSockaddr, + unicast->Address.iSockaddrLength) != 0) + continue; + found = 1; + memcpy (&r->address, &interfaces4[i].iiAddress.Address, + sizeof (struct sockaddr_in)); + memcpy (&r->mask, &interfaces4[i].iiNetmask.Address, + sizeof (struct sockaddr_in)); + for (mask_length = 0; + ((unsigned char *) &m->sin_addr)[mask_length / 8] & + 0x80 >> (mask_length % 8); mask_length++) + { + } + r->flags |= ENUMNICS3_MASK_OK; + } + } + else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) + { + for (i = 0; + interfaces6 != NULL && !found && i < interfaces6->iAddressCount; + i++) + { + if (memcpy (interfaces6->Address[i].lpSockaddr, + unicast->Address.lpSockaddr, + unicast->Address.iSockaddrLength) != 0) + continue; + found = 1; + memcpy (&r->address, interfaces6->Address[i].lpSockaddr, + sizeof (struct sockaddr_in6)); + /* TODO: Find a way to reliably get network mask for IPv6 on XP */ + memset (&r->mask, 0, sizeof (struct sockaddr)); + r->flags &= ~ENUMNICS3_MASK_OK; + } + } + if (!found) + { + DebugBreak (); + } + } + if (unicast->Address.lpSockaddr->sa_family == AF_INET) + { + struct sockaddr_in *m = (struct sockaddr_in *) &r->mask; + struct sockaddr_in *a = (struct sockaddr_in *) &r->address; + /* copy address to broadcast, then flip all the trailing bits not + * falling under netmask to 1, + * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24. + */ + memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength); + for (i = mask_length; i < 32; i++) + ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8); + r->flags |= ENUMNICS3_BCAST_OK; + r->addr_size = sizeof (struct sockaddr_in); + inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN); + } + else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) + { + struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address; + /* for IPv6 broadcast is not defined, zero it down */ + memset (&r->broadcast, 0, sizeof (struct sockaddr)); + r->flags &= ~ENUMNICS3_BCAST_OK; + r->addr_size = sizeof (struct sockaddr_in6); + inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN); + } + + i = 0; + i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, + "%S (%s", pCurrentAddress->FriendlyName, dst); + for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++) + i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, + "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]); + i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")"); + r->pretty_name[1000] = '\0'; + count += 1; + } + } + + if (use_enum2) + { + GNUNET_free_non_null (interfaces4); + GNUNET_free_non_null (interfaces6); + } + + GNUNET_free (pAddresses); + return GNUNET_OK; +} + +void +EnumNICs3_free (struct EnumNICs3_results *r) +{ + GNUNET_free_non_null (r); +} + + +/** + * Lists all network interfaces in a combo box + * Used by the basic GTK configurator + * + * @param callback function to call for each NIC + * @param callback_cls closure for callback + */ +int +ListNICs (void (*callback) (void *, const char *, int), void * callback_cls) +{ + int r; + int i; + struct EnumNICs3_results *results = NULL; + int results_count; + + r = EnumNICs3 (&results, &results_count); + if (r != GNUNET_OK) + return GNUNET_NO; + + for (i = 0; i < results_count; i++) + callback (callback_cls, results[i].pretty_name, results[i].is_default); + GNUNET_free_non_null (results); + return GNUNET_YES; +} + +/** + * @brief Installs the Windows service + * @param servicename name of the service as diplayed by the SCM + * @param application path to the application binary + * @param username the name of the service's user account + * @returns 0 on success + * 1 if the Windows version doesn't support services + * 2 if the SCM could not be opened + * 3 if the service could not be created + */ +int InstallAsService(char *servicename, char *application, char *username) +{ + SC_HANDLE hManager, hService; + char szEXE[_MAX_PATH + 17] = "\""; + char *user = NULL; + + if (! GNOpenSCManager) + return 1; + + plibc_conv_to_win_path(application, szEXE + 1); + strcat(szEXE, "\" --win-service"); + hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); + if (! hManager) + return 2; + + if (username) + { + user = (char *) malloc(strlen(username) + 3); + sprintf(user, ".\\%s", username); + } + + hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0, + SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE, + NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username); + + if (user) + free(user); + + if (! hService) + return 3; + + GNCloseServiceHandle(hService); + + return 0; +} + +/** + * @brief Uninstall Windows service + * @param servicename name of the service to delete + * @returns 0 on success + * 1 if the Windows version doesn't support services + * 2 if the SCM could not be openend + * 3 if the service cannot be accessed + * 4 if the service cannot be deleted + */ +int UninstallService(char *servicename) +{ + SC_HANDLE hManager, hService; + + if (! GNOpenSCManager) + return 1; + + hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + if (! hManager) + return 2; + + if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE))) + if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) + return 3; + else + goto closeSCM; + + if (! GNDeleteService(hService)) + if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) + return 4; + +closeSCM: + GNCloseServiceHandle(hService); + + return 0; +} + +/** + * @author Scott Field, Microsoft + * @see http://support.microsoft.com/?scid=kb;en-us;132958 + * @date 12-Jul-95 + */ +void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String) +{ + DWORD StringLength; + + if(String == NULL) + { + LsaString->Buffer = NULL; + LsaString->Length = 0; + LsaString->MaximumLength = 0; + return; + } + + StringLength = wcslen(String); + LsaString->Buffer = String; + LsaString->Length = (USHORT) StringLength *sizeof(WCHAR); + LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR); +} + + +/** + * @author Scott Field, Microsoft + * @see http://support.microsoft.com/?scid=kb;en-us;132958 + * @date 12-Jul-95 + */ +NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle) +{ + LSA_OBJECT_ATTRIBUTES ObjectAttributes; + LSA_UNICODE_STRING ServerString; + PLSA_UNICODE_STRING Server = NULL; + + /* Always initialize the object attributes to all zeroes. */ + ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); + + if(ServerName != NULL) + { + /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */ + _InitLsaString(&ServerString, ServerName); + Server = &ServerString; + } + + /* Attempt to open the policy. */ + return GNLsaOpenPolicy(Server, + &ObjectAttributes, DesiredAccess, PolicyHandle); +} + +/** + * @brief Obtain a SID representing the supplied account on the supplied system + * @return TRUE on success, FALSE on failure + * @author Scott Field, Microsoft + * @date 12-Jul-95 + * @remarks A buffer is allocated which contains the SID representing the + * supplied account. This buffer should be freed when it is no longer + * needed by calling\n + * HeapFree(GetProcessHeap(), 0, buffer) + * @remarks Call GetLastError() to obtain extended error information. + * @see http://support.microsoft.com/?scid=kb;en-us;132958 + */ +BOOL _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid) +{ + LPTSTR ReferencedDomain = NULL; + DWORD cbSid = 128; /* initial allocation attempt */ + DWORD cchReferencedDomain = 16; /* initial allocation size */ + SID_NAME_USE peUse; + BOOL bSuccess = FALSE; /* assume this function will fail */ + + /* initial memory allocations */ + if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL) + return FALSE; + + if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (), + 0, + cchReferencedDomain * + sizeof (TCHAR))) == NULL) + return FALSE; + + /* Obtain the SID of the specified account on the specified system. */ + while (!GNLookupAccountName(SystemName, /* machine to lookup account on */ + AccountName, /* account to lookup */ + *Sid, /* SID of interest */ + &cbSid, /* size of SID */ + ReferencedDomain, /* domain account was found on */ + &cchReferencedDomain, &peUse)) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + /* reallocate memory */ + if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL) + return FALSE; + + if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (), + 0, + ReferencedDomain, + cchReferencedDomain + * sizeof (TCHAR))) == NULL) + return FALSE; + } + else + goto end; + } + + /* Indicate success. */ + bSuccess = TRUE; + +end: + /* Cleanup and indicate failure, if appropriate. */ + HeapFree (GetProcessHeap (), 0, ReferencedDomain); + + if (!bSuccess) + { + if (*Sid != NULL) + { + HeapFree (GetProcessHeap (), 0, *Sid); + *Sid = NULL; + } + } + + return bSuccess; +} + +/** + * @author Scott Field, Microsoft + * @see http://support.microsoft.com/?scid=kb;en-us;132958 + * @date 12-Jul-95 + */ +NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */ + PSID AccountSid, /* SID to grant privilege to */ + LPWSTR PrivilegeName, /* privilege to grant (Unicode) */ + BOOL bEnable /* enable or disable */ + ) +{ + LSA_UNICODE_STRING PrivilegeString; + + /* Create a LSA_UNICODE_STRING for the privilege name. */ + _InitLsaString(&PrivilegeString, PrivilegeName); + + /* grant or revoke the privilege, accordingly */ + if(bEnable) + { + NTSTATUS i; + + i = GNLsaAddAccountRights(PolicyHandle, /* open policy handle */ + AccountSid, /* target SID */ + &PrivilegeString, /* privileges */ + 1 /* privilege count */ + ); + } + else + { + return GNLsaRemoveAccountRights(PolicyHandle, /* open policy handle */ + AccountSid, /* target SID */ + FALSE, /* do not disable all rights */ + &PrivilegeString, /* privileges */ + 1 /* privilege count */ + ); + } +} + +/** + * @brief Create a Windows service account + * @return 0 on success, > 0 otherwise + * @param pszName the name of the account + * @param pszDesc description of the account + */ +int CreateServiceAccount(const char *pszName, const char *pszDesc) +{ + USER_INFO_1 ui; + USER_INFO_1008 ui2; + NET_API_STATUS nStatus; + wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH]; + DWORD dwErr; + LSA_HANDLE hPolicy; + PSID pSID; + + if (! GNNetUserAdd) + return 1; + mbstowcs(wszName, pszName, strlen(pszName) + 1); + mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1); + + memset(&ui, 0, sizeof(ui)); + ui.usri1_name = wszName; + ui.usri1_password = wszName; /* account is locked anyway */ + ui.usri1_priv = USER_PRIV_USER; + ui.usri1_comment = wszDesc; + ui.usri1_flags = UF_SCRIPT; + + nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL); + + if (nStatus != NERR_Success && nStatus != NERR_UserExists) + return 2; + + ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD; + GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL); + + if (_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy) != + STATUS_SUCCESS) + return 3; + + _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID); + + if (_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE) != STATUS_SUCCESS) + return 4; + + _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE); + _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE); + _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE); + + GNLsaClose(hPolicy); + + return 0; +} + +/** + * @brief Grant permission to a file + * @param lpszFileName the name of the file or directory + * @param lpszAccountName the user account + * @param dwAccessMask the desired access (e.g. GENERIC_ALL) + * @return TRUE on success + * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102& + */ +BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName, + DWORD dwAccessMask) +{ + /* SID variables. */ + SID_NAME_USE snuType; + TCHAR * szDomain = NULL; + DWORD cbDomain = 0; + LPVOID pUserSID = NULL; + DWORD cbUserSID = 0; + + /* File SD variables. */ + PSECURITY_DESCRIPTOR pFileSD = NULL; + DWORD cbFileSD = 0; + + /* New SD variables. */ + SECURITY_DESCRIPTOR newSD; + + /* ACL variables. */ + PACL pACL = NULL; + BOOL fDaclPresent; + BOOL fDaclDefaulted; + ACL_SIZE_INFORMATION AclInfo; + + /* New ACL variables. */ + PACL pNewACL = NULL; + DWORD cbNewACL = 0; + + /* Temporary ACE. */ + LPVOID pTempAce = NULL; + UINT CurrentAceIndex = 0; + + UINT newAceIndex = 0; + + /* Assume function will fail. */ + BOOL fResult = FALSE; + BOOL fAPISuccess; + + SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION; + + /** + * STEP 1: Get SID of the account name specified. + */ + fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName, + pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType); + + /* API should have failed with insufficient buffer. */ + if (fAPISuccess) + goto end; + else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + goto end; + } + + pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID); + if (!pUserSID) { + goto end; + } + + szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR)); + if (!szDomain) { + goto end; + } + + fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName, + pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType); + if (!fAPISuccess) { + goto end; + } + + /** + * STEP 2: Get security descriptor (SD) of the file specified. + */ + fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName, + secInfo, pFileSD, 0, &cbFileSD); + + /* API should have failed with insufficient buffer. */ + if (fAPISuccess) + goto end; + else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + goto end; + } + + pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + cbFileSD); + if (!pFileSD) { + goto end; + } + + fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName, + secInfo, pFileSD, cbFileSD, &cbFileSD); + if (!fAPISuccess) { + goto end; + } + + /** + * STEP 3: Initialize new SD. + */ + if (!GNInitializeSecurityDescriptor(&newSD, + SECURITY_DESCRIPTOR_REVISION)) { + goto end; + } + + /** + * STEP 4: Get DACL from the old SD. + */ + if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL, + &fDaclDefaulted)) { + goto end; + } + + /** + * STEP 5: Get size information for DACL. + */ + AclInfo.AceCount = 0; // Assume NULL DACL. + AclInfo.AclBytesFree = 0; + AclInfo.AclBytesInUse = sizeof(ACL); + + if (pACL == NULL) + fDaclPresent = FALSE; + + /* If not NULL DACL, gather size information from DACL. */ + if (fDaclPresent) { + + if (!GNGetAclInformation(pACL, &AclInfo, + sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) { + goto end; + } + } + + /** + * STEP 6: Compute size needed for the new ACL. + */ + cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + + GetLengthSid(pUserSID) - sizeof(DWORD); + + /** + * STEP 7: Allocate memory for new ACL. + */ + pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL); + if (!pNewACL) { + goto end; + } + + /** + * STEP 8: Initialize the new ACL. + */ + if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) { + goto end; + } + + /** + * STEP 9 If DACL is present, copy all the ACEs from the old DACL + * to the new DACL. + * + * The following code assumes that the old DACL is + * already in Windows 2000 preferred order. To conform + * to the new Windows 2000 preferred order, first we will + * copy all non-inherited ACEs from the old DACL to the + * new DACL, irrespective of the ACE type. + */ + + newAceIndex = 0; + + if (fDaclPresent && AclInfo.AceCount) { + + for (CurrentAceIndex = 0; + CurrentAceIndex < AclInfo.AceCount; + CurrentAceIndex++) { + + /** + * TEP 10: Get an ACE. + */ + if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) { + goto end; + } + + /** + * STEP 11: Check if it is a non-inherited ACE. + * If it is an inherited ACE, break from the loop so + * that the new access allowed non-inherited ACE can + * be added in the correct position, immediately after + * all non-inherited ACEs. + */ + if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags + & INHERITED_ACE) + break; + + /** + * STEP 12: Skip adding the ACE, if the SID matches + * with the account specified, as we are going to + * add an access allowed ACE with a different access + * mask. + */ + if (GNEqualSid(pUserSID, + &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart))) + continue; + + /** + * STEP 13: Add the ACE to the new ACL. + */ + if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce, + ((PACE_HEADER) pTempAce)->AceSize)) { + goto end; + } + + newAceIndex++; + } + } + + /** + * STEP 14: Add the access-allowed ACE to the new DACL. + * The new ACE added here will be in the correct position, + * immediately after all existing non-inherited ACEs. + */ + if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask, + pUserSID)) { + goto end; + } + + /** + * STEP 14.5: Make new ACE inheritable + */ + if (!GetAce(pNewACL, newAceIndex, &pTempAce)) + goto end; + ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |= + (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE); + + /** + * STEP 15: To conform to the new Windows 2000 preferred order, + * we will now copy the rest of inherited ACEs from the + * old DACL to the new DACL. + */ + if (fDaclPresent && AclInfo.AceCount) { + + for (; + CurrentAceIndex < AclInfo.AceCount; + CurrentAceIndex++) { + + /** + * STEP 16: Get an ACE. + */ + if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) { + goto end; + } + + /** + * STEP 17: Add the ACE to the new ACL. + */ + if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce, + ((PACE_HEADER) pTempAce)->AceSize)) { + goto end; + } + } + } + + /** + * STEP 18: Set permissions + */ + if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) { + goto end; + } + + fResult = TRUE; + +end: + + /** + * STEP 19: Free allocated memory + */ + if (pUserSID) + HeapFree(GetProcessHeap(), 0, pUserSID); + + if (szDomain) + HeapFree(GetProcessHeap(), 0, szDomain); + + if (pFileSD) + HeapFree(GetProcessHeap(), 0, pFileSD); + + if (pNewACL) + HeapFree(GetProcessHeap(), 0, pNewACL); + + return fResult; +} + +char *winErrorStr(const char *prefix, int dwErr) +{ + char *err, *ret; + int mem; + + if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err, + 0, NULL )) + { + err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1); + } + + mem = strlen(err) + strlen(prefix) + 20; + ret = (char *) malloc(mem); + + snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr); + + LocalFree(err); + + return ret; +} + +} /* extern "C" */ + +#endif diff --git a/src/util/winproc.c b/src/util/winproc.c new file mode 100644 index 0000000..7cd80a9 --- /dev/null +++ b/src/util/winproc.c @@ -0,0 +1,338 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/winproc.c + * @brief Functions for MS Windows + * @author Nils Durner + */ + +#include "platform.h" +#include "gnunet_common.h" + +#define DEBUG_WINPROC 0 + +#ifdef MINGW + +static HINSTANCE hNTDLL, hIphlpapi, hAdvapi, hNetapi; +#ifdef W32_VEH +static void *GNWinVEH_handle = NULL; +#endif + +TNtQuerySystemInformation GNNtQuerySystemInformation; +TGetIfEntry GNGetIfEntry; +TGetIpAddrTable GNGetIpAddrTable; +TGetIfTable GNGetIfTable; +TOpenSCManager GNOpenSCManager; +TCreateService GNCreateService; +TCloseServiceHandle GNCloseServiceHandle; +TDeleteService GNDeleteService; +TRegisterServiceCtrlHandler GNRegisterServiceCtrlHandler; +TSetServiceStatus GNSetServiceStatus; +TStartServiceCtrlDispatcher GNStartServiceCtrlDispatcher; +TControlService GNControlService; +TOpenService GNOpenService; +TGetBestInterfaceEx GNGetBestInterfaceEx; +TGetAdaptersInfo GNGetAdaptersInfo; +TNetUserAdd GNNetUserAdd; +TNetUserSetInfo GNNetUserSetInfo; +TLsaOpenPolicy GNLsaOpenPolicy; +TLsaAddAccountRights GNLsaAddAccountRights; +TLsaRemoveAccountRights GNLsaRemoveAccountRights; +TLsaClose GNLsaClose; +TLookupAccountName GNLookupAccountName; +TGetFileSecurity GNGetFileSecurity; +TInitializeSecurityDescriptor GNInitializeSecurityDescriptor; +TGetSecurityDescriptorDacl GNGetSecurityDescriptorDacl; +TGetAclInformation GNGetAclInformation; +TInitializeAcl GNInitializeAcl; +TGetAce GNGetAce; +TEqualSid GNEqualSid; +TAddAce GNAddAce; +TAddAccessAllowedAce GNAddAccessAllowedAce; +TSetNamedSecurityInfo GNSetNamedSecurityInfo; + +#define LOG(kind,...) GNUNET_log_from (kind, "winproc", __VA_ARGS__) +/** + * Log (panic) messages from PlibC + */ +void +plibc_panic (int err, char *msg) +{ + LOG (((err == INT_MAX) ? GNUNET_ERROR_TYPE_DEBUG : GNUNET_ERROR_TYPE_ERROR), + "%s", msg); +} + +#ifdef W32_VEH +/** + * Handles exceptions (useful for debugging). + * Issues a DebugBreak() call if the process is being debugged (not really + * useful - if the process is being debugged, this handler won't be invoked + * anyway). If it is not, runs a debugger from GNUNET_DEBUGGER env var, + * substituting first %u in it for PID, and the second one for the event, + * that should be set once the debugger attaches itself (otherwise the + * only way out of WaitForSingleObject() is to time out after 1 minute). + */ +LONG __stdcall +GNWinVEH (PEXCEPTION_POINTERS ExceptionInfo) +{ + char debugger[MAX_PATH + 1]; + char *debugger_env = NULL; + if (IsDebuggerPresent ()) + { + DebugBreak (); + return EXCEPTION_CONTINUE_EXECUTION; + } + debugger_env = getenv ("GNUNET_DEBUGGER"); + if (debugger_env != NULL) + { + STARTUPINFO si; + PROCESS_INFORMATION pi; + HANDLE event; + SECURITY_ATTRIBUTES sa; + memset (&si, 0, sizeof (si)); + si.cb = sizeof (si); + memset (&pi, 0, sizeof (pi)); + memset (&sa, 0, sizeof (sa)); + sa.nLength = sizeof (sa); + sa.bInheritHandle = TRUE; + event = CreateEvent (&sa, FALSE, FALSE, NULL); + snprintf (debugger, MAX_PATH + 1, debugger_env, GetCurrentProcessId (), (uintptr_t) event); + debugger[MAX_PATH] = '\0'; + if (0 != CreateProcessA (NULL, debugger, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) + { + CloseHandle (pi.hProcess); + CloseHandle (pi.hThread); + WaitForSingleObject (event, 60000); + CloseHandle (event); + if (IsDebuggerPresent ()) + { + return EXCEPTION_CONTINUE_EXECUTION; + } + } + else + CloseHandle (event); + } + return EXCEPTION_CONTINUE_SEARCH; +} +#endif + +/** + * @brief Initialize PlibC and set up Windows environment + * @param logging context, NULL means stderr + * @return Error code from winerror.h, ERROR_SUCCESS on success +*/ +int +GNInitWinEnv () +{ + int ret; + + plibc_initialized (); + plibc_set_panic_proc (plibc_panic); + ret = plibc_init ("GNU", PACKAGE); + + /* don't load other DLLs twice */ + if (hNTDLL) + return ret; + +#ifdef W32_VEH + if (GNWinVEH_handle == NULL) + { + GNWinVEH_handle = AddVectoredExceptionHandler (1, &GNWinVEH); + if (GNWinVEH_handle == NULL) + { + /* This is bad, but what can we do? */ + printf ("Failed to set up an exception handler!\n"); + } + } +#endif + + hNTDLL = LoadLibrary ("ntdll.dll"); + + /* Function to get CPU usage under Win NT */ + if (hNTDLL) + { + GNNtQuerySystemInformation = + (TNtQuerySystemInformation) GetProcAddress (hNTDLL, + "NtQuerySystemInformation"); + } + else + { + GNNtQuerySystemInformation = NULL; + } + + /* Functions to get information about a network adapter */ + hIphlpapi = LoadLibrary ("iphlpapi.dll"); + if (hIphlpapi) + { + GNGetIfEntry = (TGetIfEntry) GetProcAddress (hIphlpapi, "GetIfEntry"); + GNGetIpAddrTable = + (TGetIpAddrTable) GetProcAddress (hIphlpapi, "GetIpAddrTable"); + GNGetIfTable = (TGetIfTable) GetProcAddress (hIphlpapi, "GetIfTable"); + GNGetBestInterfaceEx = + (TGetBestInterfaceEx) GetProcAddress (hIphlpapi, "GetBestInterfaceEx"); + GNGetAdaptersInfo = + (TGetAdaptersInfo) GetProcAddress (hIphlpapi, "GetAdaptersInfo"); + } + else + { + GNGetIfEntry = NULL; + GNGetIpAddrTable = NULL; + GNGetIfTable = NULL; + GNGetBestInterfaceEx = NULL; + GNGetAdaptersInfo = NULL; + } + + /* Service & Account functions */ + hAdvapi = LoadLibrary ("advapi32.dll"); + if (hAdvapi) + { + GNOpenSCManager = + (TOpenSCManager) GetProcAddress (hAdvapi, "OpenSCManagerA"); + GNCreateService = + (TCreateService) GetProcAddress (hAdvapi, "CreateServiceA"); + GNCloseServiceHandle = + (TCloseServiceHandle) GetProcAddress (hAdvapi, "CloseServiceHandle"); + GNDeleteService = + (TDeleteService) GetProcAddress (hAdvapi, "DeleteService"); + GNRegisterServiceCtrlHandler = + (TRegisterServiceCtrlHandler) GetProcAddress (hAdvapi, + "RegisterServiceCtrlHandlerA"); + GNSetServiceStatus = + (TSetServiceStatus) GetProcAddress (hAdvapi, "SetServiceStatus"); + GNStartServiceCtrlDispatcher = + (TStartServiceCtrlDispatcher) GetProcAddress (hAdvapi, + "StartServiceCtrlDispatcherA"); + GNControlService = + (TControlService) GetProcAddress (hAdvapi, "ControlService"); + GNOpenService = (TOpenService) GetProcAddress (hAdvapi, "OpenServiceA"); + + GNLsaOpenPolicy = + (TLsaOpenPolicy) GetProcAddress (hAdvapi, "LsaOpenPolicy"); + GNLsaAddAccountRights = + (TLsaAddAccountRights) GetProcAddress (hAdvapi, "LsaAddAccountRights"); + GNLsaRemoveAccountRights = + (TLsaRemoveAccountRights) GetProcAddress (hAdvapi, + "LsaRemoveAccountRights"); + GNLsaClose = (TLsaClose) GetProcAddress (hAdvapi, "LsaClose"); + GNLookupAccountName = + (TLookupAccountName) GetProcAddress (hAdvapi, "LookupAccountNameA"); + + GNGetFileSecurity = + (TGetFileSecurity) GetProcAddress (hAdvapi, "GetFileSecurityA"); + GNInitializeSecurityDescriptor = + (TInitializeSecurityDescriptor) GetProcAddress (hAdvapi, + "InitializeSecurityDescriptor"); + GNGetSecurityDescriptorDacl = + (TGetSecurityDescriptorDacl) GetProcAddress (hAdvapi, + "GetSecurityDescriptorDacl"); + GNGetAclInformation = + (TGetAclInformation) GetProcAddress (hAdvapi, "GetAclInformation"); + GNInitializeAcl = + (TInitializeAcl) GetProcAddress (hAdvapi, "InitializeAcl"); + GNGetAce = (TGetAce) GetProcAddress (hAdvapi, "GetAce"); + GNEqualSid = (TEqualSid) GetProcAddress (hAdvapi, "EqualSid"); + GNAddAce = (TAddAce) GetProcAddress (hAdvapi, "AddAce"); + GNAddAccessAllowedAce = + (TAddAccessAllowedAce) GetProcAddress (hAdvapi, "AddAccessAllowedAce"); + GNSetNamedSecurityInfo = + (TSetNamedSecurityInfo) GetProcAddress (hAdvapi, + "SetNamedSecurityInfoA"); + } + else + { + GNOpenSCManager = NULL; + GNCreateService = NULL; + GNCloseServiceHandle = NULL; + GNDeleteService = NULL; + GNRegisterServiceCtrlHandler = NULL; + GNSetServiceStatus = NULL; + GNStartServiceCtrlDispatcher = NULL; + GNControlService = NULL; + GNOpenService = NULL; + + GNLsaOpenPolicy = NULL; + GNLsaAddAccountRights = NULL; + GNLsaRemoveAccountRights = NULL; + GNLsaClose = NULL; + GNLookupAccountName = NULL; + + GNGetFileSecurity = NULL; + GNInitializeSecurityDescriptor = NULL; + GNGetSecurityDescriptorDacl = NULL; + GNGetAclInformation = NULL; + GNInitializeAcl = NULL; + GNGetAce = NULL; + GNEqualSid = NULL; + GNAddAce = NULL; + GNAddAccessAllowedAce = NULL; + GNSetNamedSecurityInfo = NULL; + } + + /* Account function */ + hNetapi = LoadLibrary ("netapi32.dll"); + if (hNetapi) + { + GNNetUserAdd = (TNetUserAdd) GetProcAddress (hNetapi, "NetUserAdd"); + GNNetUserSetInfo = + (TNetUserSetInfo) GetProcAddress (hNetapi, "NetUserSetInfo"); + } + else + { + GNNetUserAdd = NULL; + GNNetUserSetInfo = NULL; + } + + return ret; +} + +/** + * Clean up Windows environment + */ +void +GNShutdownWinEnv () +{ + plibc_shutdown (); + +#ifdef W32_VEH + if (GNWinVEH_handle != NULL) + { + RemoveVectoredExceptionHandler (GNWinVEH_handle); + GNWinVEH_handle = NULL; + } +#endif + + FreeLibrary (hNTDLL); + FreeLibrary (hIphlpapi); + FreeLibrary (hAdvapi); + FreeLibrary (hNetapi); + + CoUninitialize (); +} + +#endif /* MINGW */ + +#if !HAVE_ATOLL +long long +atoll (const char *nptr) +{ + return atol (nptr); +} +#endif diff --git a/src/vpn/Makefile.am b/src/vpn/Makefile.am new file mode 100644 index 0000000..2af34f8 --- /dev/null +++ b/src/vpn/Makefile.am @@ -0,0 +1,110 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +plugindir = $(libdir)/gnunet + +pkgcfg_DATA = \ + vpn.conf + +if LINUX +VPNBIN = gnunet-helper-vpn +install-exec-hook: + $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-vpn || true + $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-vpn || true +if HAVE_MHD + VPN_TEST = \ + test_gnunet_vpn-4_to_6 \ + test_gnunet_vpn-6_to_4 \ + test_gnunet_vpn-6_over \ + test_gnunet_vpn-4_over +endif +else +install-exec-hook: +endif + + +lib_LTLIBRARIES = \ + libgnunetvpn.la + + +bin_PROGRAMS = \ + $(VPNBIN) gnunet-service-vpn gnunet-vpn + + + +check_PROGRAMS = $(VPN_TEST) + +if ENABLE_TEST_RUN +TESTS = $(check_PROGRAMS) +endif + +EXTRA_DIST = \ + test_gnunet_vpn.conf + +gnunet_helper_vpn_SOURCES = \ + gnunet-helper-vpn.c + +gnunet_service_vpn_SOURCES = \ + gnunet-service-vpn.c +gnunet_service_vpn_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(GN_LIBINTL) +gnunet_service_vpn_CFLAGS = \ + -I$(top_srcdir)/src/exit $(CFLAGS) + +gnunet_vpn_SOURCES = \ + gnunet-vpn.c +gnunet_vpn_LDADD = \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_vpn_DEPENDENCIES = \ + libgnunetvpn.la + +libgnunetvpn_la_SOURCES = \ + vpn_api.c vpn.h +libgnunetvpn_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +libgnunetvpn_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) + + +test_gnunet_vpn_4_over_SOURCES = \ + test_gnunet_vpn.c +test_gnunet_vpn_4_over_LDADD = -lmicrohttpd @LIBCURL@ \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_vpn_6_over_SOURCES = \ + test_gnunet_vpn.c +test_gnunet_vpn_6_over_LDADD = -lmicrohttpd @LIBCURL@ \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_vpn_4_to_6_SOURCES = \ + test_gnunet_vpn.c +test_gnunet_vpn_4_to_6_LDADD = -lmicrohttpd @LIBCURL@ \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_vpn_6_to_4_SOURCES = \ + test_gnunet_vpn.c +test_gnunet_vpn_6_to_4_LDADD = -lmicrohttpd @LIBCURL@ \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la diff --git a/src/vpn/Makefile.in b/src/vpn/Makefile.in new file mode 100644 index 0000000..575375b --- /dev/null +++ b/src/vpn/Makefile.in @@ -0,0 +1,1018 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = $(am__EXEEXT_1) gnunet-service-vpn$(EXEEXT) \ + gnunet-vpn$(EXEEXT) +check_PROGRAMS = $(am__EXEEXT_2) +subdir = src/vpn +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/vpn.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = vpn.conf +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgcfgdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libgnunetvpn_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la +am_libgnunetvpn_la_OBJECTS = vpn_api.lo +libgnunetvpn_la_OBJECTS = $(am_libgnunetvpn_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libgnunetvpn_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgnunetvpn_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +@LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-vpn$(EXEEXT) +@HAVE_MHD_TRUE@@LINUX_TRUE@am__EXEEXT_2 = \ +@HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-4_to_6$(EXEEXT) \ +@HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-6_to_4$(EXEEXT) \ +@HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-6_over$(EXEEXT) \ +@HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-4_over$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) +am_gnunet_helper_vpn_OBJECTS = gnunet-helper-vpn.$(OBJEXT) +gnunet_helper_vpn_OBJECTS = $(am_gnunet_helper_vpn_OBJECTS) +gnunet_helper_vpn_LDADD = $(LDADD) +am_gnunet_service_vpn_OBJECTS = \ + gnunet_service_vpn-gnunet-service-vpn.$(OBJEXT) +gnunet_service_vpn_OBJECTS = $(am_gnunet_service_vpn_OBJECTS) +am__DEPENDENCIES_1 = +gnunet_service_vpn_DEPENDENCIES = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(am__DEPENDENCIES_1) +gnunet_service_vpn_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(gnunet_service_vpn_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_gnunet_vpn_OBJECTS = gnunet-vpn.$(OBJEXT) +gnunet_vpn_OBJECTS = $(am_gnunet_vpn_OBJECTS) +am_test_gnunet_vpn_4_over_OBJECTS = test_gnunet_vpn.$(OBJEXT) +test_gnunet_vpn_4_over_OBJECTS = $(am_test_gnunet_vpn_4_over_OBJECTS) +test_gnunet_vpn_4_over_DEPENDENCIES = \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_gnunet_vpn_4_to_6_OBJECTS = test_gnunet_vpn.$(OBJEXT) +test_gnunet_vpn_4_to_6_OBJECTS = $(am_test_gnunet_vpn_4_to_6_OBJECTS) +test_gnunet_vpn_4_to_6_DEPENDENCIES = \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_gnunet_vpn_6_over_OBJECTS = test_gnunet_vpn.$(OBJEXT) +test_gnunet_vpn_6_over_OBJECTS = $(am_test_gnunet_vpn_6_over_OBJECTS) +test_gnunet_vpn_6_over_DEPENDENCIES = \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la +am_test_gnunet_vpn_6_to_4_OBJECTS = test_gnunet_vpn.$(OBJEXT) +test_gnunet_vpn_6_to_4_OBJECTS = $(am_test_gnunet_vpn_6_to_4_OBJECTS) +test_gnunet_vpn_6_to_4_DEPENDENCIES = \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgnunetvpn_la_SOURCES) $(gnunet_helper_vpn_SOURCES) \ + $(gnunet_service_vpn_SOURCES) $(gnunet_vpn_SOURCES) \ + $(test_gnunet_vpn_4_over_SOURCES) \ + $(test_gnunet_vpn_4_to_6_SOURCES) \ + $(test_gnunet_vpn_6_over_SOURCES) \ + $(test_gnunet_vpn_6_to_4_SOURCES) +DIST_SOURCES = $(libgnunetvpn_la_SOURCES) $(gnunet_helper_vpn_SOURCES) \ + $(gnunet_service_vpn_SOURCES) $(gnunet_vpn_SOURCES) \ + $(test_gnunet_vpn_4_over_SOURCES) \ + $(test_gnunet_vpn_4_to_6_SOURCES) \ + $(test_gnunet_vpn_6_over_SOURCES) \ + $(test_gnunet_vpn_6_to_4_SOURCES) +DATA = $(pkgcfg_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/src/include +@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 +pkgcfgdir = $(pkgdatadir)/config.d/ +plugindir = $(libdir)/gnunet +pkgcfg_DATA = \ + vpn.conf + +@LINUX_TRUE@VPNBIN = gnunet-helper-vpn +@HAVE_MHD_TRUE@@LINUX_TRUE@VPN_TEST = \ +@HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-4_to_6 \ +@HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-6_to_4 \ +@HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-6_over \ +@HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-4_over + +lib_LTLIBRARIES = \ + libgnunetvpn.la + +@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) +EXTRA_DIST = \ + test_gnunet_vpn.conf + +gnunet_helper_vpn_SOURCES = \ + gnunet-helper-vpn.c + +gnunet_service_vpn_SOURCES = \ + gnunet-service-vpn.c + +gnunet_service_vpn_LDADD = \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/tun/libgnunettun.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/mesh/libgnunetmesh.la \ + $(GN_LIBINTL) + +gnunet_service_vpn_CFLAGS = \ + -I$(top_srcdir)/src/exit $(CFLAGS) + +gnunet_vpn_SOURCES = \ + gnunet-vpn.c + +gnunet_vpn_LDADD = \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_vpn_DEPENDENCIES = \ + libgnunetvpn.la + +libgnunetvpn_la_SOURCES = \ + vpn_api.c vpn.h + +libgnunetvpn_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) + +libgnunetvpn_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) + +test_gnunet_vpn_4_over_SOURCES = \ + test_gnunet_vpn.c + +test_gnunet_vpn_4_over_LDADD = -lmicrohttpd @LIBCURL@ \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_vpn_6_over_SOURCES = \ + test_gnunet_vpn.c + +test_gnunet_vpn_6_over_LDADD = -lmicrohttpd @LIBCURL@ \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_vpn_4_to_6_SOURCES = \ + test_gnunet_vpn.c + +test_gnunet_vpn_4_to_6_LDADD = -lmicrohttpd @LIBCURL@ \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_gnunet_vpn_6_to_4_SOURCES = \ + test_gnunet_vpn.c + +test_gnunet_vpn_6_to_4_LDADD = -lmicrohttpd @LIBCURL@ \ + $(top_builddir)/src/vpn/libgnunetvpn.la \ + $(top_builddir)/src/arm/libgnunetarm.la \ + $(top_builddir)/src/util/libgnunetutil.la + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/vpn/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/vpn/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +vpn.conf: $(top_builddir)/config.status $(srcdir)/vpn.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgnunetvpn.la: $(libgnunetvpn_la_OBJECTS) $(libgnunetvpn_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgnunetvpn_la_LINK) -rpath $(libdir) $(libgnunetvpn_la_OBJECTS) $(libgnunetvpn_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gnunet-helper-vpn$(EXEEXT): $(gnunet_helper_vpn_OBJECTS) $(gnunet_helper_vpn_DEPENDENCIES) + @rm -f gnunet-helper-vpn$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_helper_vpn_OBJECTS) $(gnunet_helper_vpn_LDADD) $(LIBS) +gnunet-service-vpn$(EXEEXT): $(gnunet_service_vpn_OBJECTS) $(gnunet_service_vpn_DEPENDENCIES) + @rm -f gnunet-service-vpn$(EXEEXT) + $(AM_V_CCLD)$(gnunet_service_vpn_LINK) $(gnunet_service_vpn_OBJECTS) $(gnunet_service_vpn_LDADD) $(LIBS) +gnunet-vpn$(EXEEXT): $(gnunet_vpn_OBJECTS) $(gnunet_vpn_DEPENDENCIES) + @rm -f gnunet-vpn$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_vpn_OBJECTS) $(gnunet_vpn_LDADD) $(LIBS) +test_gnunet_vpn-4_over$(EXEEXT): $(test_gnunet_vpn_4_over_OBJECTS) $(test_gnunet_vpn_4_over_DEPENDENCIES) + @rm -f test_gnunet_vpn-4_over$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_vpn_4_over_OBJECTS) $(test_gnunet_vpn_4_over_LDADD) $(LIBS) +test_gnunet_vpn-4_to_6$(EXEEXT): $(test_gnunet_vpn_4_to_6_OBJECTS) $(test_gnunet_vpn_4_to_6_DEPENDENCIES) + @rm -f test_gnunet_vpn-4_to_6$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_vpn_4_to_6_OBJECTS) $(test_gnunet_vpn_4_to_6_LDADD) $(LIBS) +test_gnunet_vpn-6_over$(EXEEXT): $(test_gnunet_vpn_6_over_OBJECTS) $(test_gnunet_vpn_6_over_DEPENDENCIES) + @rm -f test_gnunet_vpn-6_over$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_vpn_6_over_OBJECTS) $(test_gnunet_vpn_6_over_LDADD) $(LIBS) +test_gnunet_vpn-6_to_4$(EXEEXT): $(test_gnunet_vpn_6_to_4_OBJECTS) $(test_gnunet_vpn_6_to_4_DEPENDENCIES) + @rm -f test_gnunet_vpn-6_to_4$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gnunet_vpn_6_to_4_OBJECTS) $(test_gnunet_vpn_6_to_4_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-vpn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-vpn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_vpn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vpn_api.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +gnunet_service_vpn-gnunet-service-vpn.o: gnunet-service-vpn.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gnunet_service_vpn_CFLAGS) $(CFLAGS) -MT gnunet_service_vpn-gnunet-service-vpn.o -MD -MP -MF $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Tpo -c -o gnunet_service_vpn-gnunet-service-vpn.o `test -f 'gnunet-service-vpn.c' || echo '$(srcdir)/'`gnunet-service-vpn.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Tpo $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gnunet-service-vpn.c' object='gnunet_service_vpn-gnunet-service-vpn.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gnunet_service_vpn_CFLAGS) $(CFLAGS) -c -o gnunet_service_vpn-gnunet-service-vpn.o `test -f 'gnunet-service-vpn.c' || echo '$(srcdir)/'`gnunet-service-vpn.c + +gnunet_service_vpn-gnunet-service-vpn.obj: gnunet-service-vpn.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gnunet_service_vpn_CFLAGS) $(CFLAGS) -MT gnunet_service_vpn-gnunet-service-vpn.obj -MD -MP -MF $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Tpo -c -o gnunet_service_vpn-gnunet-service-vpn.obj `if test -f 'gnunet-service-vpn.c'; then $(CYGPATH_W) 'gnunet-service-vpn.c'; else $(CYGPATH_W) '$(srcdir)/gnunet-service-vpn.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Tpo $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gnunet-service-vpn.c' object='gnunet_service_vpn-gnunet-service-vpn.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gnunet_service_vpn_CFLAGS) $(CFLAGS) -c -o gnunet_service_vpn-gnunet-service-vpn.obj `if test -f 'gnunet-service-vpn.c'; then $(CYGPATH_W) 'gnunet-service-vpn.c'; else $(CYGPATH_W) '$(srcdir)/gnunet-service-vpn.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgcfgDATA: $(pkgcfg_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ + done + +uninstall-pkgcfgDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgcfgDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgcfgDATA + +.MAKE: check-am install-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-exec-hook install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-pkgcfgDATA \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-libLTLIBRARIES uninstall-pkgcfgDATA + +@LINUX_TRUE@install-exec-hook: +@LINUX_TRUE@ $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-vpn || true +@LINUX_TRUE@ $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-vpn || true +@LINUX_FALSE@install-exec-hook: + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/vpn/gnunet-helper-vpn.c b/src/vpn/gnunet-helper-vpn.c new file mode 100644 index 0000000..7c09827 --- /dev/null +++ b/src/vpn/gnunet-helper-vpn.c @@ -0,0 +1,616 @@ +/* + This file is part of GNUnet. + (C) 2010, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file vpn/gnunet-helper-vpn.c + * @brief the helper for the VPN service. Opens a virtual network-interface, + * sends data received on the if to stdout, sends data received on stdin to the + * interface + * @author Philipp Tölke + * @author Christian Grothoff + * + * The following list of people have reviewed this code and considered + * it safe since the last modification (if you reviewed it, please + * have your name added to the list): + * + * - Philipp Tölke + */ +#include "platform.h" +#include + +/** + * Need 'struct GNUNET_MessageHeader'. + */ +#include "gnunet_common.h" + +/** + * Need VPN message types. + */ +#include "gnunet_protocols.h" + +/** + * Should we print (interesting|debug) messages that can happen during + * normal operation? + */ +#define DEBUG GNUNET_NO + +/** + * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) + */ +#define MAX_SIZE 65536 + +#ifndef _LINUX_IN6_H +/** + * This is in linux/include/net/ipv6.h, but not always exported... + */ +struct in6_ifreq +{ + struct in6_addr ifr6_addr; + uint32_t ifr6_prefixlen; + unsigned int ifr6_ifindex; +}; +#endif + + +/** + * Creates a tun-interface called dev; + * + * @param dev is asumed to point to a char[IFNAMSIZ] + * if *dev == '\\0', uses the name supplied by the kernel; + * @return the fd to the tun or -1 on error + */ +static int +init_tun (char *dev) +{ + struct ifreq ifr; + int fd; + + if (NULL == dev) + { + errno = EINVAL; + return -1; + } + + if (-1 == (fd = open ("/dev/net/tun", O_RDWR))) + { + fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun", + strerror (errno)); + return -1; + } + + if (fd >= FD_SETSIZE) + { + fprintf (stderr, "File descriptor to large: %d", fd); + (void) close (fd); + return -1; + } + + memset (&ifr, 0, sizeof (ifr)); + ifr.ifr_flags = IFF_TUN; + + if ('\0' != *dev) + strncpy (ifr.ifr_name, dev, IFNAMSIZ); + + if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr)) + { + fprintf (stderr, "Error with ioctl on `%s': %s\n", "/dev/net/tun", + strerror (errno)); + (void) close (fd); + return -1; + } + strcpy (dev, ifr.ifr_name); + return fd; +} + + +/** + * @brief Sets the IPv6-Address given in address on the interface dev + * + * @param dev the interface to configure + * @param address the IPv6-Address + * @param prefix_len the length of the network-prefix + */ +static void +set_address6 (const char *dev, const char *address, unsigned long prefix_len) +{ + struct ifreq ifr; + struct in6_ifreq ifr6; + struct sockaddr_in6 sa6; + int fd; + + /* + * parse the new address + */ + memset (&sa6, 0, sizeof (struct sockaddr_in6)); + sa6.sin6_family = AF_INET6; + if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr)) + { + fprintf (stderr, "Failed to parse address `%s': %s\n", address, + strerror (errno)); + exit (1); + } + + if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0))) + { + fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); + exit (1); + } + + memset (&ifr, 0, sizeof (struct ifreq)); + /* + * Get the index of the if + */ + strncpy (ifr.ifr_name, dev, IFNAMSIZ); + if (-1 == ioctl (fd, SIOGIFINDEX, &ifr)) + { + fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); + (void) close (fd); + exit (1); + } + + memset (&ifr6, 0, sizeof (struct in6_ifreq)); + ifr6.ifr6_addr = sa6.sin6_addr; + ifr6.ifr6_ifindex = ifr.ifr_ifindex; + ifr6.ifr6_prefixlen = prefix_len; + + /* + * Set the address + */ + if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Get the flags + */ + if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Add the UP and RUNNING flags + */ + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + if (0 != close (fd)) + { + fprintf (stderr, "close failed: %s\n", strerror (errno)); + exit (1); + } +} + + +/** + * @brief Sets the IPv4-Address given in address on the interface dev + * + * @param dev the interface to configure + * @param address the IPv4-Address + * @param mask the netmask + */ +static void +set_address4 (const char *dev, const char *address, const char *mask) +{ + int fd; + struct sockaddr_in *addr; + struct ifreq ifr; + + memset (&ifr, 0, sizeof (struct ifreq)); + addr = (struct sockaddr_in *) &(ifr.ifr_addr); + addr->sin_family = AF_INET; + + /* + * Parse the address + */ + if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr)) + { + fprintf (stderr, "Failed to parse address `%s': %s\n", address, + strerror (errno)); + exit (1); + } + + if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0))) + { + fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); + exit (1); + } + + strncpy (ifr.ifr_name, dev, IFNAMSIZ); + + /* + * Set the address + */ + if (-1 == ioctl (fd, SIOCSIFADDR, &ifr)) + { + fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Parse the netmask + */ + addr = (struct sockaddr_in *) &(ifr.ifr_netmask); + if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr)) + { + fprintf (stderr, "Failed to parse address `%s': %s\n", mask, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Set the netmask + */ + if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Get the flags + */ + if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + /* + * Add the UP and RUNNING flags + */ + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) + { + fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, + strerror (errno)); + (void) close (fd); + exit (1); + } + + if (0 != close (fd)) + { + fprintf (stderr, "close failed: %s\n", strerror (errno)); + (void) close (fd); + exit (1); + } +} + + +/** + * Start forwarding to and from the tunnel. + * + * @param fd_tun tunnel FD + */ +static void +run (int fd_tun) +{ + /* + * The buffer filled by reading from fd_tun + */ + unsigned char buftun[MAX_SIZE]; + ssize_t buftun_size = 0; + unsigned char *buftun_read = NULL; + + /* + * The buffer filled by reading from stdin + */ + unsigned char bufin[MAX_SIZE]; + ssize_t bufin_size = 0; + size_t bufin_rpos = 0; + unsigned char *bufin_read = NULL; + + fd_set fds_w; + fd_set fds_r; + + /* read refers to reading from fd_tun, writing to stdout */ + int read_open = 1; + + /* write refers to reading from stdin, writing to fd_tun */ + int write_open = 1; + + while ((1 == read_open) || (1 == write_open)) + { + FD_ZERO (&fds_w); + FD_ZERO (&fds_r); + + /* + * We are supposed to read and the buffer is empty + * -> select on read from tun + */ + if (read_open && (0 == buftun_size)) + FD_SET (fd_tun, &fds_r); + + /* + * We are supposed to read and the buffer is not empty + * -> select on write to stdout + */ + if (read_open && (0 != buftun_size)) + FD_SET (1, &fds_w); + + /* + * We are supposed to write and the buffer is empty + * -> select on read from stdin + */ + if (write_open && (NULL == bufin_read)) + FD_SET (0, &fds_r); + + /* + * We are supposed to write and the buffer is not empty + * -> select on write to tun + */ + if (write_open && (NULL != bufin_read)) + FD_SET (fd_tun, &fds_w); + + int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL); + + if (-1 == r) + { + if (EINTR == errno) + continue; + fprintf (stderr, "select failed: %s\n", strerror (errno)); + exit (1); + } + + if (r > 0) + { + if (FD_ISSET (fd_tun, &fds_r)) + { + buftun_size = + read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader), + MAX_SIZE - sizeof (struct GNUNET_MessageHeader)); + if (-1 == buftun_size) + { + fprintf (stderr, "read-error: %s\n", strerror (errno)); + shutdown (fd_tun, SHUT_RD); + shutdown (1, SHUT_WR); + read_open = 0; + buftun_size = 0; + } + else if (0 == buftun_size) + { + fprintf (stderr, "EOF on tun\n"); + shutdown (fd_tun, SHUT_RD); + shutdown (1, SHUT_WR); + read_open = 0; + buftun_size = 0; + } + else + { + buftun_read = buftun; + struct GNUNET_MessageHeader *hdr = + (struct GNUNET_MessageHeader *) buftun; + buftun_size += sizeof (struct GNUNET_MessageHeader); + hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + hdr->size = htons (buftun_size); + } + } + else if (FD_ISSET (1, &fds_w)) + { + ssize_t written = write (1, buftun_read, buftun_size); + + if (-1 == written) + { +#if !DEBUG + if (errno != EPIPE) +#endif + fprintf (stderr, "write-error to stdout: %s\n", strerror (errno)); + shutdown (fd_tun, SHUT_RD); + shutdown (1, SHUT_WR); + read_open = 0; + buftun_size = 0; + } + else if (0 == written) + { + fprintf (stderr, "write returned 0!?\n"); + exit (1); + } + else + { + buftun_size -= written; + buftun_read += written; + } + } + + if (FD_ISSET (0, &fds_r)) + { + bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos); + if (-1 == bufin_size) + { + fprintf (stderr, "read-error: %s\n", strerror (errno)); + shutdown (0, SHUT_RD); + shutdown (fd_tun, SHUT_WR); + write_open = 0; + bufin_size = 0; + } + else if (0 == bufin_size) + { +#if DEBUG + fprintf (stderr, "EOF on stdin\n"); +#endif + shutdown (0, SHUT_RD); + shutdown (fd_tun, SHUT_WR); + write_open = 0; + bufin_size = 0; + } + else + { + struct GNUNET_MessageHeader *hdr; + +PROCESS_BUFFER: + bufin_rpos += bufin_size; + if (bufin_rpos < sizeof (struct GNUNET_MessageHeader)) + continue; + hdr = (struct GNUNET_MessageHeader *) bufin; + if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) + { + fprintf (stderr, "protocol violation!\n"); + exit (1); + } + if (ntohs (hdr->size) > bufin_rpos) + continue; + bufin_read = bufin + sizeof (struct GNUNET_MessageHeader); + bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader); + bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader); + } + } + else if (FD_ISSET (fd_tun, &fds_w)) + { + ssize_t written = write (fd_tun, bufin_read, bufin_size); + + if (-1 == written) + { + fprintf (stderr, "write-error to tun: %s\n", strerror (errno)); + shutdown (0, SHUT_RD); + shutdown (fd_tun, SHUT_WR); + write_open = 0; + bufin_size = 0; + } + else if (0 == written) + { + fprintf (stderr, "write returned 0!?\n"); + exit (1); + } + else + { + bufin_size -= written; + bufin_read += written; + if (0 == bufin_size) + { + memmove (bufin, bufin_read, bufin_rpos); + bufin_read = NULL; /* start reading again */ + bufin_size = 0; + goto PROCESS_BUFFER; + } + } + } + } + } +} + + +/** + * Open VPN tunnel interface. + * + * @param argc must be 6 + * @param argv 0: binary name (gnunet-helper-vpn) + * 1: tunnel interface name (gnunet-vpn) + * 2: IPv6 address (::1), "-" to disable + * 3: IPv6 netmask length in bits (64), ignored if #2 is "-" + * 4: IPv4 address (1.2.3.4), "-" to disable + * 5: IPv4 netmask (255.255.0.0), ignored if #4 is "-" + */ +int +main (int argc, char **argv) +{ + char dev[IFNAMSIZ]; + int fd_tun; + int global_ret; + + if (6 != argc) + { + fprintf (stderr, "Fatal: must supply 5 arguments!\n"); + return 1; + } + + strncpy (dev, argv[1], IFNAMSIZ); + dev[IFNAMSIZ - 1] = '\0'; + + if (-1 == (fd_tun = init_tun (dev))) + { + fprintf (stderr, "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n", + dev, + argv[2], + argv[3], + argv[4], + argv[5]); + return 1; + } + + if (0 != strcmp (argv[2], "-")) + { + const char *address = argv[2]; + long prefix_len = atol (argv[3]); + + if ((prefix_len < 1) || (prefix_len > 127)) + { + fprintf (stderr, "Fatal: prefix_len out of range\n"); + return 1; + } + + set_address6 (dev, address, prefix_len); + } + + if (0 != strcmp (argv[4], "-")) + { + const char *address = argv[4]; + const char *mask = argv[5]; + + set_address4 (dev, address, mask); + } + + uid_t uid = getuid (); +#ifdef HAVE_SETRESUID + if (0 != setresuid (uid, uid, uid)) + { + fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); + global_ret = 2; + goto cleanup; + } +#else + if (0 != (setuid (uid) | seteuid (uid))) + { + fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); + global_ret = 2; + goto cleanup; + } +#endif + + if (SIG_ERR == signal (SIGPIPE, SIG_IGN)) + { + fprintf (stderr, "Failed to protect against SIGPIPE: %s\n", + strerror (errno)); + /* no exit, we might as well die with SIGPIPE should it ever happen */ + } + run (fd_tun); + global_ret = 0; + cleanup: + close (fd_tun); + return global_ret; +} diff --git a/src/vpn/gnunet-service-vpn.c b/src/vpn/gnunet-service-vpn.c new file mode 100644 index 0000000..26deeee --- /dev/null +++ b/src/vpn/gnunet-service-vpn.c @@ -0,0 +1,3202 @@ +/* + This file is part of GNUnet. + (C) 2010, 2011, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file vpn/gnunet-service-vpn.c + * @brief service that opens a virtual interface and allows its clients + * to allocate IPs on the virtual interface and to then redirect + * IP traffic received on those IPs via the GNUnet mesh + * @author Philipp Toelke + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_common.h" +#include "gnunet_protocols.h" +#include "gnunet_applications.h" +#include "gnunet_mesh_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_constants.h" +#include "gnunet_tun_lib.h" +#include "vpn.h" +#include "exit.h" + + +/** + * Maximum number of messages we allow in the queue for mesh. + */ +#define MAX_MESSAGE_QUEUE_SIZE 4 + + +/** + * State we keep for each of our tunnels. + */ +struct TunnelState; + + +/** + * Information we track for each IP address to determine which tunnel + * to send the traffic over to the destination. + */ +struct DestinationEntry +{ + + /** + * Key under which this entry is in the 'destination_map' (only valid + * if 'heap_node != NULL'). + */ + GNUNET_HashCode key; + + /** + * Pre-allocated tunnel for this destination, or NULL for none. + */ + struct TunnelState *ts; + + /** + * Entry for this entry in the destination_heap. + */ + struct GNUNET_CONTAINER_HeapNode *heap_node; + + /** + * GNUNET_NO if this is a tunnel to an Internet-exit, + * GNUNET_YES if this tunnel is to a service. + */ + int is_service; + + /** + * Details about the connection (depending on is_service). + */ + union + { + + struct + { + /** + * The description of the service (only used for service tunnels). + */ + GNUNET_HashCode service_descriptor; + + /** + * Peer offering the service. + */ + struct GNUNET_PeerIdentity target; + + } service_destination; + + struct + { + + /** + * Address family used (AF_INET or AF_INET6). + */ + int af; + + /** + * IP address of the ultimate destination (only used for exit tunnels). + */ + union + { + /** + * Address if af is AF_INET. + */ + struct in_addr v4; + + /** + * Address if af is AF_INET6. + */ + struct in6_addr v6; + } ip; + + } exit_destination; + + } details; + +}; + + +/** + * A messages we have in queue for a particular tunnel. + */ +struct TunnelMessageQueueEntry +{ + /** + * This is a doubly-linked list. + */ + struct TunnelMessageQueueEntry *next; + + /** + * This is a doubly-linked list. + */ + struct TunnelMessageQueueEntry *prev; + + /** + * Number of bytes in 'msg'. + */ + size_t len; + + /** + * Message to transmit, allocated at the end of this struct. + */ + const void *msg; +}; + + +/** + * State we keep for each of our tunnels. + */ +struct TunnelState +{ + + /** + * Information about the tunnel to use, NULL if no tunnel + * is available right now. + */ + struct GNUNET_MESH_Tunnel *tunnel; + + /** + * Active transmission handle, NULL for none. + */ + struct GNUNET_MESH_TransmitHandle *th; + + /** + * Entry for this entry in the tunnel_heap, NULL as long as this + * tunnel state is not fully bound. + */ + struct GNUNET_CONTAINER_HeapNode *heap_node; + + /** + * Head of list of messages scheduled for transmission. + */ + struct TunnelMessageQueueEntry *tmq_head; + + /** + * Tail of list of messages scheduled for transmission. + */ + struct TunnelMessageQueueEntry *tmq_tail; + + /** + * Client that needs to be notified about the tunnel being + * up as soon as a peer is connected; NULL for none. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Destination entry that has a pointer to this tunnel state; + * NULL if this tunnel state is in the tunnel map. + */ + struct DestinationEntry *destination_container; + + /** + * ID of the client request that caused us to setup this entry. + */ + uint64_t request_id; + + /** + * Destination to which this tunnel leads. Note that + * this struct is NOT in the destination_map (but a + * local copy) and that the 'heap_node' should always + * be NULL. + */ + struct DestinationEntry destination; + + /** + * Task scheduled to destroy the tunnel (or NO_TASK). + */ + GNUNET_SCHEDULER_TaskIdentifier destroy_task; + + /** + * Addess family used for this tunnel on the local TUN interface. + */ + int af; + + /** + * Length of the doubly linked 'tmq_head/tmq_tail' list. + */ + unsigned int tmq_length; + + /** + * IPPROTO_TCP or IPPROTO_UDP once bound. + */ + uint8_t protocol; + + /** + * IP address of the source on our end, initially uninitialized. + */ + union + { + /** + * Address if af is AF_INET. + */ + struct in_addr v4; + + /** + * Address if af is AF_INET6. + */ + struct in6_addr v6; + + } source_ip; + + /** + * Destination IP address used by the source on our end (this is the IP + * that we pick freely within the VPN's tunnel IP range). + */ + union + { + /** + * Address if af is AF_INET. + */ + struct in_addr v4; + + /** + * Address if af is AF_INET6. + */ + struct in6_addr v6; + + } destination_ip; + + /** + * Source port used by the sender on our end; 0 for uninitialized. + */ + uint16_t source_port; + + /** + * Destination port used by the sender on our end; 0 for uninitialized. + */ + uint16_t destination_port; + +}; + + +/** + * Return value from 'main'. + */ +static int global_ret; + +/** + * Configuration we use. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Handle to the mesh service. + */ +static struct GNUNET_MESH_Handle *mesh_handle; + +/** + * Map from IP address to destination information (possibly with a + * MESH tunnel handle for fast setup). + */ +static struct GNUNET_CONTAINER_MultiHashMap *destination_map; + +/** + * Min-Heap sorted by activity time to expire old mappings. + */ +static struct GNUNET_CONTAINER_Heap *destination_heap; + +/** + * Map from source and destination address (IP+port) to connection + * information (mostly with the respective MESH tunnel handle). + */ +static struct GNUNET_CONTAINER_MultiHashMap *tunnel_map; + +/** + * Min-Heap sorted by activity time to expire old mappings; values are + * of type 'struct TunnelState'. + */ +static struct GNUNET_CONTAINER_Heap *tunnel_heap; + +/** + * Statistics. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * The handle to the VPN helper process "gnunet-helper-vpn". + */ +static struct GNUNET_HELPER_Handle *helper_handle; + +/** + * Arguments to the vpn helper. + */ +static char *vpn_argv[7]; + +/** + * Length of the prefix of the VPN's IPv6 network. + */ +static unsigned long long ipv6prefix; + +/** + * Notification context for sending replies to clients. + */ +static struct GNUNET_SERVER_NotificationContext *nc; + +/** + * If there are more than this number of address-mappings, old ones + * will be removed + */ +static unsigned long long max_destination_mappings; + +/** + * If there are more than this number of open tunnels, old ones + * will be removed + */ +static unsigned long long max_tunnel_mappings; + + +/** + * Compute the key under which we would store an entry in the + * destination_map for the given IP address. + * + * @param af address family (AF_INET or AF_INET6) + * @param address IP address, struct in_addr or struct in6_addr + * @param key where to store the key + */ +static void +get_destination_key_from_ip (int af, + const void *address, + GNUNET_HashCode *key) +{ + switch (af) + { + case AF_INET: + GNUNET_CRYPTO_hash (address, + sizeof (struct in_addr), + key); + break; + case AF_INET6: + GNUNET_CRYPTO_hash (address, + sizeof (struct in6_addr), + key); + break; + default: + GNUNET_assert (0); + break; + } +} + + +/** + * Compute the key under which we would store an entry in the + * tunnel_map for the given socket address pair. + * + * @param af address family (AF_INET or AF_INET6) + * @param protocol IPPROTO_TCP or IPPROTO_UDP + * @param source_ip sender's source IP, struct in_addr or struct in6_addr + * @param source_port sender's source port + * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr + * @param destination_port sender's destination port + * @param key where to store the key + */ +static void +get_tunnel_key_from_ips (int af, + uint8_t protocol, + const void *source_ip, + uint16_t source_port, + const void *destination_ip, + uint16_t destination_port, + GNUNET_HashCode *key) +{ + char *off; + + memset (key, 0, sizeof (GNUNET_HashCode)); + /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash, + so we put the ports in there (and hope for few collisions) */ + off = (char*) key; + memcpy (off, &source_port, sizeof (uint16_t)); + off += sizeof (uint16_t); + memcpy (off, &destination_port, sizeof (uint16_t)); + off += sizeof (uint16_t); + switch (af) + { + case AF_INET: + memcpy (off, source_ip, sizeof (struct in_addr)); + off += sizeof (struct in_addr); + memcpy (off, destination_ip, sizeof (struct in_addr)); + off += sizeof (struct in_addr); + break; + case AF_INET6: + memcpy (off, source_ip, sizeof (struct in6_addr)); + off += sizeof (struct in6_addr); + memcpy (off, destination_ip, sizeof (struct in6_addr)); + off += sizeof (struct in6_addr); + break; + default: + GNUNET_assert (0); + break; + } + memcpy (off, &protocol, sizeof (uint8_t)); + off += sizeof (uint8_t); +} + + +/** + * Notify the client about the result of its request. + * + * @param client client to notify + * @param request_id original request ID to include in response + * @param result_af resulting address family + * @param addr resulting IP address + */ +static void +send_client_reply (struct GNUNET_SERVER_Client *client, + uint64_t request_id, + int result_af, + const void *addr) +{ + char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)]; + struct RedirectToIpResponseMessage *res; + size_t rlen; + + switch (result_af) + { + case AF_INET: + rlen = sizeof (struct in_addr); + break; + case AF_INET6: + rlen = sizeof (struct in6_addr); + break; + case AF_UNSPEC: + rlen = 0; + break; + default: + GNUNET_assert (0); + return; + } + res = (struct RedirectToIpResponseMessage *) buf; + res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen); + res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP); + res->result_af = htonl (result_af); + res->request_id = request_id; + memcpy (&res[1], addr, rlen); + GNUNET_SERVER_notification_context_add (nc, client); + GNUNET_SERVER_notification_context_unicast (nc, + client, + &res->header, + GNUNET_NO); +} + + +/** + * Free resources associated with a tunnel state. + * + * @param ts state to free + */ +static void +free_tunnel_state (struct TunnelState *ts) +{ + GNUNET_HashCode key; + struct TunnelMessageQueueEntry *tnq; + struct GNUNET_MESH_Tunnel *tunnel; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up tunnel state\n"); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Active tunnels"), + -1, GNUNET_NO); + while (NULL != (tnq = ts->tmq_head)) + { + GNUNET_CONTAINER_DLL_remove (ts->tmq_head, + ts->tmq_tail, + tnq); + ts->tmq_length--; + GNUNET_free (tnq); + } + GNUNET_assert (0 == ts->tmq_length); + if (NULL != ts->client) + { + GNUNET_SERVER_client_drop (ts->client); + ts->client = NULL; + } + if (NULL != ts->th) + { + GNUNET_MESH_notify_transmit_ready_cancel (ts->th); + ts->th = NULL; + } + GNUNET_assert (NULL == ts->destination.heap_node); + if (NULL != (tunnel = ts->tunnel)) + { + ts->tunnel = NULL; + GNUNET_MESH_tunnel_destroy (tunnel); + } + if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task) + { + GNUNET_SCHEDULER_cancel (ts->destroy_task); + ts->destroy_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != ts->heap_node) + { + GNUNET_CONTAINER_heap_remove_node (ts->heap_node); + ts->heap_node = NULL; + get_tunnel_key_from_ips (ts->af, + ts->protocol, + &ts->source_ip, + ts->source_port, + &ts->destination_ip, + ts->destination_port, + &key); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (tunnel_map, + &key, + ts)); + } + if (NULL != ts->destination_container) + { + GNUNET_assert (ts == ts->destination_container->ts); + ts->destination_container->ts = NULL; + ts->destination_container = NULL; + } + GNUNET_free (ts); +} + + +/** + * Destroy the mesh tunnel. + * + * @param cls the 'struct TunnelState' with the tunnel to destroy + * @param tc scheduler context + */ +static void +destroy_tunnel_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TunnelState *ts = cls; + struct GNUNET_MESH_Tunnel *tunnel; + + ts->destroy_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (NULL != ts->tunnel); + tunnel = ts->tunnel; + ts->tunnel = NULL; + GNUNET_MESH_tunnel_destroy (tunnel); + free_tunnel_state (ts); +} + + +/** + * Method called whenever a peer has disconnected from the tunnel. + * + * @param cls closure + * @param peer peer identity the tunnel stopped working with + */ +static void +tunnel_peer_disconnect_handler (void *cls, + const struct + GNUNET_PeerIdentity * peer) +{ + struct TunnelState *ts = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %s disconnected from tunnel.\n", + GNUNET_i2s (peer)); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Peers connected to mesh tunnels"), + -1, GNUNET_NO); + if (NULL != ts->th) + { + GNUNET_MESH_notify_transmit_ready_cancel (ts->th); + ts->th = NULL; + } + if (ts->destination.is_service) + return; /* hope for reconnect eventually */ + /* as we are most likely going to change the exit node now, + we should just destroy the tunnel entirely... */ + if (GNUNET_SCHEDULER_NO_TASK == ts->destroy_task) + ts->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_tunnel_task, ts); +} + + +/** + * Method called whenever a peer has connected to the tunnel. Notifies + * the waiting client that the tunnel is now up. + * + * @param cls closure + * @param peer peer identity the tunnel was created to, NULL on timeout + * @param atsi performance data for the connection + */ +static void +tunnel_peer_connect_handler (void *cls, + const struct GNUNET_PeerIdentity + * peer, + const struct + GNUNET_ATS_Information * atsi) +{ + struct TunnelState *ts = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %s connected to tunnel.\n", + GNUNET_i2s (peer)); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Peers connected to mesh tunnels"), + 1, GNUNET_NO); + if (NULL == ts->client) + return; /* nothing to do */ + send_client_reply (ts->client, + ts->request_id, + ts->af, + &ts->destination_ip); + GNUNET_SERVER_client_drop (ts->client); + ts->client = NULL; +} + + +/** + * Send a message from the message queue via mesh. + * + * @param cls the 'struct TunnelState' with the message queue + * @param size number of bytes available in buf + * @param buf where to copy the message + * @return number of bytes copied to buf + */ +static size_t +send_to_peer_notify_callback (void *cls, size_t size, void *buf) +{ + struct TunnelState *ts = cls; + struct TunnelMessageQueueEntry *tnq; + size_t ret; + + ts->th = NULL; + if (NULL == buf) + return 0; + tnq = ts->tmq_head; + GNUNET_assert (NULL != tnq); + GNUNET_assert (size >= tnq->len); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending %u bytes via mesh tunnel\n", + tnq->len); + GNUNET_CONTAINER_DLL_remove (ts->tmq_head, + ts->tmq_tail, + tnq); + ts->tmq_length--; + memcpy (buf, tnq->msg, tnq->len); + ret = tnq->len; + GNUNET_free (tnq); + if (NULL != (tnq = ts->tmq_head)) + ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, + GNUNET_NO /* cork */, + 42 /* priority */, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, + tnq->len, + &send_to_peer_notify_callback, + ts); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes given to mesh for transmission"), + ret, GNUNET_NO); + return ret; +} + + +/** + * Add the given message to the given tunnel and trigger the + * transmission process. + * + * @param tnq message to queue + * @param ts tunnel to queue the message for + */ +static void +send_to_tunnel (struct TunnelMessageQueueEntry *tnq, + struct TunnelState *ts) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Queueing %u bytes for transmission via mesh tunnel\n", + tnq->len); + GNUNET_assert (NULL != ts->tunnel); + GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head, + ts->tmq_tail, + tnq); + ts->tmq_length++; + if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE) + { + struct TunnelMessageQueueEntry *dq; + + dq = ts->tmq_head; + GNUNET_assert (dq != tnq); + GNUNET_CONTAINER_DLL_remove (ts->tmq_head, + ts->tmq_tail, + dq); + ts->tmq_length--; + GNUNET_MESH_notify_transmit_ready_cancel (ts->th); + ts->th = NULL; + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes dropped in mesh queue (overflow)"), + dq->len, + GNUNET_NO); + GNUNET_free (dq); + } + if (NULL == ts->th) + ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, + GNUNET_NO /* cork */, + 42 /* priority */, + GNUNET_TIME_UNIT_FOREVER_REL, + NULL, + tnq->len, + &send_to_peer_notify_callback, + ts); +} + + +/** + * Initialize the given destination entry's mesh tunnel. + * + * @param de destination entry for which we need to setup a tunnel + * @param client client to notify on successful tunnel setup, or NULL for none + * @param client_af address family of the address returned to the client + * @param request_id request ID to send in client notification (unused if client is NULL) + * @return tunnel state of the tunnel that was created + */ +static struct TunnelState * +create_tunnel_to_destination (struct DestinationEntry *de, + struct GNUNET_SERVER_Client *client, + int client_af, + uint64_t request_id) +{ + struct TunnelState *ts; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Mesh tunnels created"), + 1, GNUNET_NO); + GNUNET_assert (NULL == de->ts); + ts = GNUNET_malloc (sizeof (struct TunnelState)); + ts->af = client_af; + if (NULL != client) + { + ts->request_id = request_id; + ts->client = client; + GNUNET_SERVER_client_keep (client); + } + ts->destination = *de; + ts->destination.heap_node = NULL; /* copy is NOT in destination heap */ + de->ts = ts; + ts->destination_container = de; /* we are referenced from de */ + ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle, + ts, + &tunnel_peer_connect_handler, + &tunnel_peer_disconnect_handler, + ts); + if (NULL == ts->tunnel) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to setup mesh tunnel!\n")); + if (NULL != client) + GNUNET_SERVER_client_drop (client); + GNUNET_free (ts); + return NULL; + } + if (de->is_service) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating tunnel to peer %s offering service %s\n", + GNUNET_i2s (&de->details.service_destination.target), + GNUNET_h2s (&de->details.service_destination.service_descriptor)); + GNUNET_MESH_peer_request_connect_add (ts->tunnel, + &de->details.service_destination.target); + } + else + { + switch (de->details.exit_destination.af) + { + case AF_INET: + GNUNET_MESH_peer_request_connect_by_type (ts->tunnel, + GNUNET_APPLICATION_TYPE_IPV4_GATEWAY); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating tunnel to exit peer for %s\n", + "IPv4"); + break; + case AF_INET6: + GNUNET_MESH_peer_request_connect_by_type (ts->tunnel, + GNUNET_APPLICATION_TYPE_IPV6_GATEWAY); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating tunnel to exit peer for %s\n", + "IPv6"); + break; + default: + GNUNET_assert (0); + break; + } + } + return ts; +} + + +/** + * We have too many active tunnels. Clean up the oldest tunnel. + * + * @param except tunnel that must NOT be cleaned up, even if it is the oldest + */ +static void +expire_tunnel (struct TunnelState *except) +{ + struct TunnelState *ts; + + ts = GNUNET_CONTAINER_heap_peek (tunnel_heap); + GNUNET_assert (NULL != ts); + if (except == ts) + return; /* can't do this */ + free_tunnel_state (ts); +} + + +/** + * Route a packet via mesh to the given destination. + * + * @param destination description of the destination + * @param af address family on this end (AF_INET or AF_INET6) + * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6 + * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr) + * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr) + * @param payload payload of the packet after the IP header + * @param payload_length number of bytes in payload + */ +static void +route_packet (struct DestinationEntry *destination, + int af, + uint8_t protocol, + const void *source_ip, + const void *destination_ip, + const void *payload, + size_t payload_length) +{ + GNUNET_HashCode key; + struct TunnelState *ts; + struct TunnelMessageQueueEntry *tnq; + size_t alen; + size_t mlen; + int is_new; + const struct GNUNET_TUN_UdpHeader *udp; + const struct GNUNET_TUN_TcpHeader *tcp; + const struct GNUNET_TUN_IcmpHeader *icmp; + uint16_t source_port; + uint16_t destination_port; + + switch (protocol) + { + case IPPROTO_UDP: + { + if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader)) + { + /* blame kernel? */ + GNUNET_break (0); + return; + } + udp = payload; + if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader)) + { + GNUNET_break_op (0); + return; + } + source_port = ntohs (udp->source_port); + destination_port = ntohs (udp->destination_port); + get_tunnel_key_from_ips (af, + IPPROTO_UDP, + source_ip, + source_port, + destination_ip, + destination_port, + &key); + } + break; + case IPPROTO_TCP: + { + if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader)) + { + /* blame kernel? */ + GNUNET_break (0); + return; + } + tcp = payload; + if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) + { + GNUNET_break_op (0); + return; + } + source_port = ntohs (tcp->source_port); + destination_port = ntohs (tcp->destination_port); + get_tunnel_key_from_ips (af, + IPPROTO_TCP, + source_ip, + source_port, + destination_ip, + destination_port, + &key); + } + break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + { + if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) ) + { + GNUNET_break (0); + return; + } + if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader)) + { + /* blame kernel? */ + GNUNET_break (0); + return; + } + icmp = payload; + source_port = 0; + destination_port = 0; + get_tunnel_key_from_ips (af, + protocol, + source_ip, + 0, + destination_ip, + 0, + &key); + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Protocol %u not supported, dropping\n"), + (unsigned int) protocol); + return; + } + if (! destination->is_service) + { + switch (destination->details.exit_destination.af) + { + case AF_INET: + alen = sizeof (struct in_addr); + break; + case AF_INET6: + alen = sizeof (struct in6_addr); + break; + default: + alen = 0; + GNUNET_assert (0); + } + + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + char xbuf[INET6_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n", + (protocol == IPPROTO_TCP) ? "TCP" : "UDP", + inet_ntop (af, source_ip, sbuf, sizeof (sbuf)), + source_port, + inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)), + destination_port, + inet_ntop (destination->details.exit_destination.af, + &destination->details.exit_destination.ip, + xbuf, sizeof (xbuf)), + destination_port); + } + } + else + { + /* make compiler happy */ + alen = 0; + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n", + (protocol == IPPROTO_TCP) ? "TCP" : "UDP", + inet_ntop (af, source_ip, sbuf, sizeof (sbuf)), + source_port, + inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)), + destination_port, + GNUNET_h2s (&destination->details.service_destination.service_descriptor), + GNUNET_i2s (&destination->details.service_destination.target)); + } + + } + + /* see if we have an existing tunnel for this destination */ + ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map, + &key); + if (NULL == ts) + { + /* need to either use the existing tunnel from the destination (if still + available) or create a fresh one */ + is_new = GNUNET_YES; + if (NULL == destination->ts) + ts = create_tunnel_to_destination (destination, NULL, af, 0); + else + ts = destination->ts; + if (NULL == ts) + return; + destination->ts = NULL; + ts->destination_container = NULL; /* no longer 'contained' */ + /* now bind existing "unbound" tunnel to our IP/port tuple */ + ts->protocol = protocol; + ts->af = af; + if (af == AF_INET) + { + ts->source_ip.v4 = * (const struct in_addr *) source_ip; + ts->destination_ip.v4 = * (const struct in_addr *) destination_ip; + } + else + { + ts->source_ip.v6 = * (const struct in6_addr *) source_ip; + ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip; + } + ts->source_port = source_port; + ts->destination_port = destination_port; + ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap, + ts, + GNUNET_TIME_absolute_get ().abs_value); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_put (tunnel_map, + &key, + ts, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Active tunnels"), + 1, GNUNET_NO); + while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings) + expire_tunnel (ts); + } + else + { + is_new = GNUNET_NO; + GNUNET_CONTAINER_heap_update_cost (tunnel_heap, + ts->heap_node, + GNUNET_TIME_absolute_get ().abs_value); + } + GNUNET_assert (NULL != ts->tunnel); + + /* send via tunnel */ + switch (protocol) + { + case IPPROTO_UDP: + if (destination->is_service) + { + struct GNUNET_EXIT_UdpServiceMessage *usm; + + mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) + + payload_length - sizeof (struct GNUNET_TUN_UdpHeader); + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); + tnq->len = mlen; + tnq->msg = &tnq[1]; + usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1]; + usm->header.size = htons ((uint16_t) mlen); + usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE); + /* if the source port is below 32000, we assume it has a special + meaning; if not, we pick a random port (this is a heuristic) */ + usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0; + usm->destination_port = udp->destination_port; + usm->service_descriptor = destination->details.service_destination.service_descriptor; + memcpy (&usm[1], + &udp[1], + payload_length - sizeof (struct GNUNET_TUN_UdpHeader)); + } + else + { + struct GNUNET_EXIT_UdpInternetMessage *uim; + struct in_addr *ip4dst; + struct in6_addr *ip6dst; + void *payload; + + mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) + + alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader); + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + + mlen); + tnq->len = mlen; + tnq->msg = &tnq[1]; + uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1]; + uim->header.size = htons ((uint16_t) mlen); + uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET); + uim->af = htonl (destination->details.exit_destination.af); + uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0; + uim->destination_port = udp->destination_port; + switch (destination->details.exit_destination.af) + { + case AF_INET: + ip4dst = (struct in_addr *) &uim[1]; + *ip4dst = destination->details.exit_destination.ip.v4; + payload = &ip4dst[1]; + break; + case AF_INET6: + ip6dst = (struct in6_addr *) &uim[1]; + *ip6dst = destination->details.exit_destination.ip.v6; + payload = &ip6dst[1]; + break; + default: + GNUNET_assert (0); + } + memcpy (payload, + &udp[1], + payload_length - sizeof (struct GNUNET_TUN_UdpHeader)); + } + break; + case IPPROTO_TCP: + if (is_new) + { + if (destination->is_service) + { + struct GNUNET_EXIT_TcpServiceStartMessage *tsm; + + mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) + + payload_length - sizeof (struct GNUNET_TUN_TcpHeader); + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); + tnq->len = mlen; + tnq->msg = &tnq[1]; + tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1]; + tsm->header.size = htons ((uint16_t) mlen); + tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START); + tsm->reserved = htonl (0); + tsm->service_descriptor = destination->details.service_destination.service_descriptor; + tsm->tcp_header = *tcp; + memcpy (&tsm[1], + &tcp[1], + payload_length - sizeof (struct GNUNET_TUN_TcpHeader)); + } + else + { + struct GNUNET_EXIT_TcpInternetStartMessage *tim; + struct in_addr *ip4dst; + struct in6_addr *ip6dst; + void *payload; + + mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) + + alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader); + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); + tnq->len = mlen; + tnq->msg = &tnq[1]; + tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1]; + tim->header.size = htons ((uint16_t) mlen); + tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START); + tim->af = htonl (destination->details.exit_destination.af); + tim->tcp_header = *tcp; + switch (destination->details.exit_destination.af) + { + case AF_INET: + ip4dst = (struct in_addr *) &tim[1]; + *ip4dst = destination->details.exit_destination.ip.v4; + payload = &ip4dst[1]; + break; + case AF_INET6: + ip6dst = (struct in6_addr *) &tim[1]; + *ip6dst = destination->details.exit_destination.ip.v6; + payload = &ip6dst[1]; + break; + default: + GNUNET_assert (0); + } + memcpy (payload, + &tcp[1], + payload_length - sizeof (struct GNUNET_TUN_TcpHeader)); + } + } + else + { + struct GNUNET_EXIT_TcpDataMessage *tdm; + + mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + + payload_length - sizeof (struct GNUNET_TUN_TcpHeader); + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); + tnq->len = mlen; + tnq->msg = &tnq[1]; + tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1]; + tdm->header.size = htons ((uint16_t) mlen); + tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT); + tdm->reserved = htonl (0); + tdm->tcp_header = *tcp; + memcpy (&tdm[1], + &tcp[1], + payload_length - sizeof (struct GNUNET_TUN_TcpHeader)); + } + break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + if (destination->is_service) + { + struct GNUNET_EXIT_IcmpServiceMessage *ism; + + mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) + + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); + tnq->msg = &tnq[1]; + ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1]; + ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE); + ism->af = htonl (af); /* need to tell destination ICMP protocol family! */ + ism->service_descriptor = destination->details.service_destination.service_descriptor; + ism->icmp_header = *icmp; + /* ICMP protocol translation will be done by the receiver (as we don't know + the target AF); however, we still need to possibly discard the payload + depending on the ICMP type */ + switch (af) + { + case AF_INET: + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: + case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: + break; + case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: + case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: + case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: + /* throw away ICMP payload, won't be useful for the other side anyway */ + payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + default: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (not allowed)"), + 1, GNUNET_NO); + return; + } + /* end of AF_INET */ + break; + case AF_INET6: + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: + case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: + case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: + case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: + /* throw away ICMP payload, won't be useful for the other side anyway */ + payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: + case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: + break; + default: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (not allowed)"), + 1, GNUNET_NO); + return; + } + /* end of AF_INET6 */ + break; + default: + GNUNET_assert (0); + break; + } + + /* update length calculations, as payload_length may have changed */ + mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) + + alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); + tnq->len = mlen; + ism->header.size = htons ((uint16_t) mlen); + /* finally, copy payload (if there is any left...) */ + memcpy (&ism[1], + &icmp[1], + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader)); + } + else + { + struct GNUNET_EXIT_IcmpInternetMessage *iim; + struct in_addr *ip4dst; + struct in6_addr *ip6dst; + void *payload; + + mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) + + alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + + mlen); + tnq->msg = &tnq[1]; + iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1]; + iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET); + iim->icmp_header = *icmp; + /* Perform ICMP protocol-translation (depending on destination AF and source AF) + and throw away ICMP payload depending on ICMP message type */ + switch (af) + { + case AF_INET: + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: + if (destination->details.exit_destination.af == AF_INET6) + iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY; + break; + case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: + if (destination->details.exit_destination.af == AF_INET6) + iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST; + break; + case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: + if (destination->details.exit_destination.af == AF_INET6) + iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; + /* throw away IP-payload, exit will have to make it up anyway */ + payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: + if (destination->details.exit_destination.af == AF_INET6) + iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED; + /* throw away IP-payload, exit will have to make it up anyway */ + payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: + if (destination->details.exit_destination.af == AF_INET6) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"), + 1, GNUNET_NO); + GNUNET_free (tnq); + return; + } + /* throw away IP-payload, exit will have to make it up anyway */ + payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + default: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), + 1, GNUNET_NO); + GNUNET_free (tnq); + return; + } + /* end of AF_INET */ + break; + case AF_INET6: + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: + if (destination->details.exit_destination.af == AF_INET6) + iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; + /* throw away IP-payload, exit will have to make it up anyway */ + payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: + if (destination->details.exit_destination.af == AF_INET) + iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED; + /* throw away IP-payload, exit will have to make it up anyway */ + payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: + if (destination->details.exit_destination.af == AF_INET) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), + 1, GNUNET_NO); + GNUNET_free (tnq); + return; + } + /* throw away IP-payload, exit will have to make it up anyway */ + payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: + if (destination->details.exit_destination.af == AF_INET) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), + 1, GNUNET_NO); + GNUNET_free (tnq); + return; + } + /* throw away IP-payload, exit will have to make it up anyway */ + payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: + if (destination->details.exit_destination.af == AF_INET) + iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST; + break; + case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: + if (destination->details.exit_destination.af == AF_INET) + iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY; + break; + default: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), + 1, GNUNET_NO); + GNUNET_free (tnq); + return; + } + /* end of AF_INET6 */ + break; + default: + GNUNET_assert (0); + } + /* update length calculations, as payload_length may have changed */ + mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) + + alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); + tnq->len = mlen; + iim->header.size = htons ((uint16_t) mlen); + + /* need to tell destination ICMP protocol family! */ + iim->af = htonl (destination->details.exit_destination.af); + switch (destination->details.exit_destination.af) + { + case AF_INET: + ip4dst = (struct in_addr *) &iim[1]; + *ip4dst = destination->details.exit_destination.ip.v4; + payload = &ip4dst[1]; + break; + case AF_INET6: + ip6dst = (struct in6_addr *) &iim[1]; + *ip6dst = destination->details.exit_destination.ip.v6; + payload = &ip6dst[1]; + break; + default: + GNUNET_assert (0); + } + memcpy (payload, + &icmp[1], + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader)); + } + break; + default: + /* not supported above, how can we get here !? */ + GNUNET_assert (0); + break; + } + send_to_tunnel (tnq, ts); +} + + +/** + * Receive packets from the helper-process (someone send to the local + * virtual tunnel interface). Find the destination mapping, and if it + * exists, identify the correct MESH tunnel (or possibly create it) + * and forward the packet. + * + * @param cls closure, NULL + * @param client NULL + * @param message message we got from the client (VPN tunnel interface) + */ +static void +message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_TUN_Layer2PacketHeader *tun; + size_t mlen; + GNUNET_HashCode key; + struct DestinationEntry *de; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Packets received from TUN interface"), + 1, GNUNET_NO); + mlen = ntohs (message->size); + if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) || + (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) ) + { + GNUNET_break (0); + return; + } + tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1]; + mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)); + switch (ntohs (tun->proto)) + { + case ETH_P_IPV6: + { + const struct GNUNET_TUN_IPv6Header *pkt6; + + if (mlen < sizeof (struct GNUNET_TUN_IPv6Header)) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1]; + get_destination_key_from_ip (AF_INET6, + &pkt6->destination_address, + &key); + de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key); + /* FIXME: do we need to guard against hash collision? + (if so, we need to also store the local destination IP in the + destination entry and then compare here; however, the risk + of collision seems minimal AND the impact is unlikely to be + super-problematic as well... */ + if (NULL == de) + { + char buf[INET6_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Packet received for unmapped destination `%s' (dropping it)\n"), + inet_ntop (AF_INET6, + &pkt6->destination_address, + buf, + sizeof (buf))); + return; + } + route_packet (de, + AF_INET6, + pkt6->next_header, + &pkt6->source_address, + &pkt6->destination_address, + &pkt6[1], + mlen - sizeof (struct GNUNET_TUN_IPv6Header)); + } + break; + case ETH_P_IPV4: + { + struct GNUNET_TUN_IPv4Header *pkt4; + + if (mlen < sizeof (struct GNUNET_TUN_IPv4Header)) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1]; + get_destination_key_from_ip (AF_INET, + &pkt4->destination_address, + &key); + de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key); + /* FIXME: do we need to guard against hash collision? + (if so, we need to also store the local destination IP in the + destination entry and then compare here; however, the risk + of collision seems minimal AND the impact is unlikely to be + super-problematic as well... */ + if (NULL == de) + { + char buf[INET_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Packet received for unmapped destination `%s' (dropping it)\n"), + inet_ntop (AF_INET, + &pkt4->destination_address, + buf, + sizeof (buf))); + return; + } + if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Received IPv4 packet with options (dropping it)\n")); + return; + } + route_packet (de, + AF_INET, + pkt4->protocol, + &pkt4->source_address, + &pkt4->destination_address, + &pkt4[1], + mlen - sizeof (struct GNUNET_TUN_IPv4Header)); + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Received packet of unknown protocol %d from TUN (dropping it)\n"), + (unsigned int) ntohs (tun->proto)); + break; + } +} + + +/** + * Synthesize a plausible ICMP payload for an ICMP error + * response on the given tunnel. + * + * @param ts tunnel information + * @param ipp IPv4 header to fill in (ICMP payload) + * @param udp "UDP" header to fill in (ICMP payload); might actually + * also be the first 8 bytes of the TCP header + */ +static void +make_up_icmpv4_payload (struct TunnelState *ts, + struct GNUNET_TUN_IPv4Header *ipp, + struct GNUNET_TUN_UdpHeader *udp) +{ + GNUNET_TUN_initialize_ipv4_header (ipp, + ts->protocol, + sizeof (struct GNUNET_TUN_TcpHeader), + &ts->source_ip.v4, + &ts->destination_ip.v4); + udp->source_port = htons (ts->source_port); + udp->destination_port = htons (ts->destination_port); + udp->len = htons (0); + udp->crc = htons (0); +} + + +/** + * Synthesize a plausible ICMP payload for an ICMP error + * response on the given tunnel. + * + * @param ts tunnel information + * @param ipp IPv6 header to fill in (ICMP payload) + * @param udp "UDP" header to fill in (ICMP payload); might actually + * also be the first 8 bytes of the TCP header + */ +static void +make_up_icmpv6_payload (struct TunnelState *ts, + struct GNUNET_TUN_IPv6Header *ipp, + struct GNUNET_TUN_UdpHeader *udp) +{ + GNUNET_TUN_initialize_ipv6_header (ipp, + ts->protocol, + sizeof (struct GNUNET_TUN_TcpHeader), + &ts->source_ip.v6, + &ts->destination_ip.v6); + udp->source_port = htons (ts->source_port); + udp->destination_port = htons (ts->destination_port); + udp->len = htons (0); + udp->crc = htons (0); +} + + +/** + * We got an ICMP packet back from the MESH tunnel. Pass it on to the + * local virtual interface via the helper. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *ts = *tunnel_ctx; + const struct GNUNET_EXIT_IcmpToVPNMessage *i2v; + size_t mlen; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMP packets received from mesh"), + 1, GNUNET_NO); + mlen = ntohs (message->size); + if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (NULL == ts->heap_node) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (AF_UNSPEC == ts->af) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message; + mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage); + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n", + (unsigned int) mlen, + inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)), + inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf))); + } + switch (ts->af) + { + case AF_INET: + { + size_t size = sizeof (struct GNUNET_TUN_IPv4Header) + + sizeof (struct GNUNET_TUN_IcmpHeader) + + sizeof (struct GNUNET_MessageHeader) + + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + + mlen; + { + /* reserve some extra space in case we have an ICMP type here where + we will need to make up the payload ourselves */ + char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8]; + struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; + struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; + struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1]; + struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1]; + msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + tun->flags = htons (0); + tun->proto = htons (ETH_P_IPV4); + GNUNET_TUN_initialize_ipv4_header (ipv4, + IPPROTO_ICMP, + sizeof (struct GNUNET_TUN_IcmpHeader) + mlen, + &ts->destination_ip.v4, + &ts->source_ip.v4); + *icmp = i2v->icmp_header; + memcpy (&icmp[1], + &i2v[1], + mlen); + /* For some ICMP types, we need to adjust (make up) the payload here. + Also, depending on the AF used on the other side, we have to + do ICMP PT (translate ICMP types) */ + switch (ntohl (i2v->af)) + { + case AF_INET: + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: + case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: + break; + case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: + case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: + case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: + { + struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1]; + struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; + + if (mlen != 0) + { + /* sender did not strip ICMP payload? */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + size += sizeof (struct GNUNET_TUN_IPv4Header) + 8; + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + make_up_icmpv4_payload (ts, ipp, udp); + } + break; + default: + GNUNET_break_op (0); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + /* end AF_INET */ + break; + case AF_INET6: + /* ICMP PT 6-to-4 and possibly making up payloads */ + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: + icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE; + { + struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1]; + struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; + + if (mlen != 0) + { + /* sender did not strip ICMP payload? */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + size += sizeof (struct GNUNET_TUN_IPv4Header) + 8; + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + make_up_icmpv4_payload (ts, ipp, udp); + } + break; + case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: + icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED; + { + struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1]; + struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; + + if (mlen != 0) + { + /* sender did not strip ICMP payload? */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + size += sizeof (struct GNUNET_TUN_IPv4Header) + 8; + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + make_up_icmpv4_payload (ts, ipp, udp); + } + break; + case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: + case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), + 1, GNUNET_NO); + return GNUNET_OK; + case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: + icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST; + break; + case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: + icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY; + break; + default: + GNUNET_break_op (0); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + /* end AF_INET6 */ + break; + default: + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + msg->size = htons (size); + GNUNET_TUN_calculate_icmp_checksum (icmp, + &i2v[1], + mlen); + (void) GNUNET_HELPER_send (helper_handle, + msg, + GNUNET_YES, + NULL, NULL); + } + } + break; + case AF_INET6: + { + size_t size = sizeof (struct GNUNET_TUN_IPv6Header) + + sizeof (struct GNUNET_TUN_IcmpHeader) + + sizeof (struct GNUNET_MessageHeader) + + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + + mlen; + { + char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8]; + struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; + struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; + struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1]; + struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1]; + msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + tun->flags = htons (0); + tun->proto = htons (ETH_P_IPV6); + GNUNET_TUN_initialize_ipv6_header (ipv6, + IPPROTO_ICMPV6, + sizeof (struct GNUNET_TUN_IcmpHeader) + mlen, + &ts->destination_ip.v6, + &ts->source_ip.v6); + *icmp = i2v->icmp_header; + memcpy (&icmp[1], + &i2v[1], + mlen); + + /* For some ICMP types, we need to adjust (make up) the payload here. + Also, depending on the AF used on the other side, we have to + do ICMP PT (translate ICMP types) */ + switch (ntohl (i2v->af)) + { + case AF_INET: + /* ICMP PT 4-to-6 and possibly making up payloads */ + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: + icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY; + break; + case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: + icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST; + break; + case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: + icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; + { + struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1]; + struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; + + if (mlen != 0) + { + /* sender did not strip ICMP payload? */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + size += sizeof (struct GNUNET_TUN_IPv6Header) + 8; + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + make_up_icmpv6_payload (ts, ipp, udp); + } + break; + case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: + icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED; + { + struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1]; + struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; + + if (mlen != 0) + { + /* sender did not strip ICMP payload? */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + size += sizeof (struct GNUNET_TUN_IPv6Header) + 8; + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + make_up_icmpv6_payload (ts, ipp, udp); + } + break; + case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"), + 1, GNUNET_NO); + return GNUNET_OK; + default: + GNUNET_break_op (0); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + /* end AF_INET */ + break; + case AF_INET6: + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: + case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: + case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: + case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: + { + struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1]; + struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; + + if (mlen != 0) + { + /* sender did not strip ICMP payload? */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + size += sizeof (struct GNUNET_TUN_IPv6Header) + 8; + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + make_up_icmpv6_payload (ts, ipp, udp); + } + break; + case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: + break; + default: + GNUNET_break_op (0); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + /* end AF_INET6 */ + break; + default: + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + msg->size = htons (size); + GNUNET_TUN_calculate_icmp_checksum (icmp, + &i2v[1], mlen); + (void) GNUNET_HELPER_send (helper_handle, + msg, + GNUNET_YES, + NULL, NULL); + } + } + break; + default: + GNUNET_assert (0); + } + GNUNET_CONTAINER_heap_update_cost (tunnel_heap, + ts->heap_node, + GNUNET_TIME_absolute_get ().abs_value); + return GNUNET_OK; +} + + +/** + * We got a UDP packet back from the MESH tunnel. Pass it on to the + * local virtual interface via the helper. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *ts = *tunnel_ctx; + const struct GNUNET_EXIT_UdpReplyMessage *reply; + size_t mlen; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP packets received from mesh"), + 1, GNUNET_NO); + mlen = ntohs (message->size); + if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (NULL == ts->heap_node) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (AF_UNSPEC == ts->af) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message; + mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage); + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n", + (unsigned int) mlen, + inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)), + ts->destination_port, + inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)), + ts->source_port); + } + switch (ts->af) + { + case AF_INET: + { + size_t size = sizeof (struct GNUNET_TUN_IPv4Header) + + sizeof (struct GNUNET_TUN_UdpHeader) + + sizeof (struct GNUNET_MessageHeader) + + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + + mlen; + { + char buf[size]; + struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; + struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; + struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1]; + struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1]; + msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + msg->size = htons (size); + tun->flags = htons (0); + tun->proto = htons (ETH_P_IPV4); + GNUNET_TUN_initialize_ipv4_header (ipv4, + IPPROTO_UDP, + sizeof (struct GNUNET_TUN_UdpHeader) + mlen, + &ts->destination_ip.v4, + &ts->source_ip.v4); + if (0 == ntohs (reply->source_port)) + udp->source_port = htons (ts->destination_port); + else + udp->source_port = reply->source_port; + if (0 == ntohs (reply->destination_port)) + udp->destination_port = htons (ts->source_port); + else + udp->destination_port = reply->destination_port; + udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader)); + GNUNET_TUN_calculate_udp4_checksum (ipv4, + udp, + &reply[1], + mlen); + memcpy (&udp[1], + &reply[1], + mlen); + (void) GNUNET_HELPER_send (helper_handle, + msg, + GNUNET_YES, + NULL, NULL); + } + } + break; + case AF_INET6: + { + size_t size = sizeof (struct GNUNET_TUN_IPv6Header) + + sizeof (struct GNUNET_TUN_UdpHeader) + + sizeof (struct GNUNET_MessageHeader) + + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + + mlen; + { + char buf[size]; + struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; + struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; + struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1]; + struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1]; + msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + msg->size = htons (size); + tun->flags = htons (0); + tun->proto = htons (ETH_P_IPV6); + GNUNET_TUN_initialize_ipv6_header (ipv6, + IPPROTO_UDP, + sizeof (struct GNUNET_TUN_UdpHeader) + mlen, + &ts->destination_ip.v6, + &ts->source_ip.v6); + if (0 == ntohs (reply->source_port)) + udp->source_port = htons (ts->destination_port); + else + udp->source_port = reply->source_port; + if (0 == ntohs (reply->destination_port)) + udp->destination_port = htons (ts->source_port); + else + udp->destination_port = reply->destination_port; + udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader)); + GNUNET_TUN_calculate_udp6_checksum (ipv6, + udp, + &reply[1], mlen); + memcpy (&udp[1], + &reply[1], + mlen); + (void) GNUNET_HELPER_send (helper_handle, + msg, + GNUNET_YES, + NULL, NULL); + } + } + break; + default: + GNUNET_assert (0); + } + GNUNET_CONTAINER_heap_update_cost (tunnel_heap, + ts->heap_node, + GNUNET_TIME_absolute_get ().abs_value); + return GNUNET_OK; +} + + +/** + * We got a TCP packet back from the MESH tunnel. Pass it on to the + * local virtual interface via the helper. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *ts = *tunnel_ctx; + const struct GNUNET_EXIT_TcpDataMessage *data; + size_t mlen; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP packets received from mesh"), + 1, GNUNET_NO); + mlen = ntohs (message->size); + if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (NULL == ts->heap_node) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + data = (const struct GNUNET_EXIT_TcpDataMessage *) message; + mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage); + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n", + (unsigned int) mlen, + inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)), + ts->destination_port, + inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)), + ts->source_port); + } + if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + switch (ts->af) + { + case AF_INET: + { + size_t size = sizeof (struct GNUNET_TUN_IPv4Header) + + sizeof (struct GNUNET_TUN_TcpHeader) + + sizeof (struct GNUNET_MessageHeader) + + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + + mlen; + { + char buf[size]; + struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; + struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; + struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1]; + struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1]; + msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + msg->size = htons (size); + tun->flags = htons (0); + tun->proto = htons (ETH_P_IPV4); + GNUNET_TUN_initialize_ipv4_header (ipv4, + IPPROTO_TCP, + sizeof (struct GNUNET_TUN_TcpHeader) + mlen, + &ts->destination_ip.v4, + &ts->source_ip.v4); + *tcp = data->tcp_header; + tcp->source_port = htons (ts->destination_port); + tcp->destination_port = htons (ts->source_port); + GNUNET_TUN_calculate_tcp4_checksum (ipv4, + tcp, + &data[1], + mlen); + memcpy (&tcp[1], + &data[1], + mlen); + (void) GNUNET_HELPER_send (helper_handle, + msg, + GNUNET_YES, + NULL, NULL); + } + } + break; + case AF_INET6: + { + size_t size = sizeof (struct GNUNET_TUN_IPv6Header) + + sizeof (struct GNUNET_TUN_TcpHeader) + + sizeof (struct GNUNET_MessageHeader) + + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + + mlen; + { + char buf[size]; + struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; + struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; + struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1]; + struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1]; + msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + msg->size = htons (size); + tun->flags = htons (0); + tun->proto = htons (ETH_P_IPV6); + GNUNET_TUN_initialize_ipv6_header (ipv6, + IPPROTO_TCP, + sizeof (struct GNUNET_TUN_TcpHeader) + mlen, + &ts->destination_ip.v6, + &ts->source_ip.v6); + *tcp = data->tcp_header; + tcp->source_port = htons (ts->destination_port); + tcp->destination_port = htons (ts->source_port); + GNUNET_TUN_calculate_tcp6_checksum (ipv6, + tcp, + &data[1], + mlen); + memcpy (&tcp[1], + &data[1], + mlen); + (void) GNUNET_HELPER_send (helper_handle, + msg, + GNUNET_YES, + NULL, NULL); + } + } + break; + } + GNUNET_CONTAINER_heap_update_cost (tunnel_heap, + ts->heap_node, + GNUNET_TIME_absolute_get ().abs_value); + return GNUNET_OK; +} + + +/** + * Allocate an IPv4 address from the range of the tunnel + * for a new redirection. + * + * @param v4 where to store the address + * @return GNUNET_OK on success, + * GNUNET_SYSERR on error + */ +static int +allocate_v4_address (struct in_addr *v4) +{ + const char *ipv4addr = vpn_argv[4]; + const char *ipv4mask = vpn_argv[5]; + struct in_addr addr; + struct in_addr mask; + struct in_addr rnd; + GNUNET_HashCode key; + unsigned int tries; + + GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr)); + GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask)); + /* Given 192.168.0.1/255.255.0.0, we want a mask + of '192.168.255.255', thus: */ + mask.s_addr = addr.s_addr | ~mask.s_addr; + tries = 0; + do + { + tries++; + if (tries > 16) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to find unallocated IPv4 address in VPN's range\n")); + return GNUNET_SYSERR; + } + /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */ + rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT32_MAX); + v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr; + get_destination_key_from_ip (AF_INET, + v4, + &key); + } + while ( (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (destination_map, + &key)) || + (v4->s_addr == addr.s_addr) || + (v4->s_addr == mask.s_addr) ); + return GNUNET_OK; +} + + +/** + * Allocate an IPv6 address from the range of the tunnel + * for a new redirection. + * + * @param v6 where to store the address + * @return GNUNET_OK on success, + * GNUNET_SYSERR on error + */ +static int +allocate_v6_address (struct in6_addr *v6) +{ + const char *ipv6addr = vpn_argv[2]; + struct in6_addr addr; + struct in6_addr mask; + struct in6_addr rnd; + int i; + GNUNET_HashCode key; + unsigned int tries; + + GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr)); + GNUNET_assert (ipv6prefix < 128); + /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF, + thus: */ + mask = addr; + for (i=127;i>=ipv6prefix;i--) + mask.s6_addr[i / 8] |= (1 << (i % 8)); + + /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */ + tries = 0; + do + { + tries++; + if (tries > 16) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to find unallocated IPv6 address in VPN's range\n")); + return GNUNET_SYSERR; + + } + for (i=0;i<16;i++) + { + rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + 256); + v6->s6_addr[i] + = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i]; + } + get_destination_key_from_ip (AF_INET6, + v6, + &key); + } + while ( (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (destination_map, + &key)) || + (0 == memcmp (v6, + &addr, + sizeof (struct in6_addr))) || + (0 == memcmp (v6, + &mask, + sizeof (struct in6_addr))) ); + return GNUNET_OK; +} + + +/** + * Free resources occupied by a destination entry. + * + * @param de entry to free + */ +static void +free_destination_entry (struct DestinationEntry *de) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up destination entry\n"); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Active destinations"), + -1, GNUNET_NO); + if (NULL != de->ts) + { + free_tunnel_state (de->ts); + GNUNET_assert (NULL == de->ts); + } + if (NULL != de->heap_node) + { + GNUNET_CONTAINER_heap_remove_node (de->heap_node); + de->heap_node = NULL; + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (destination_map, + &de->key, + de)); + } + GNUNET_free (de); +} + + +/** + * We have too many active destinations. Clean up the oldest destination. + * + * @param except destination that must NOT be cleaned up, even if it is the oldest + */ +static void +expire_destination (struct DestinationEntry *except) +{ + struct DestinationEntry *de; + + de = GNUNET_CONTAINER_heap_peek (destination_heap); + GNUNET_assert (NULL != de); + if (except == de) + return; /* can't do this */ + free_destination_entry (de); +} + + +/** + * A client asks us to setup a redirection via some exit + * node to a particular IP. Setup the redirection and + * give the client the allocated IP. + * + * @param cls unused + * @param client requesting client + * @param message redirection request (a 'struct RedirectToIpRequestMessage') + */ +static void +service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + size_t mlen; + size_t alen; + const struct RedirectToIpRequestMessage *msg; + int addr_af; + int result_af; + struct in_addr v4; + struct in6_addr v6; + void *addr; + struct DestinationEntry *de; + GNUNET_HashCode key; + struct TunnelState *ts; + + /* validate and parse request */ + mlen = ntohs (message->size); + if (mlen < sizeof (struct RedirectToIpRequestMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + alen = mlen - sizeof (struct RedirectToIpRequestMessage); + msg = (const struct RedirectToIpRequestMessage *) message; + addr_af = (int) htonl (msg->addr_af); + switch (addr_af) + { + case AF_INET: + if (alen != sizeof (struct in_addr)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + break; + case AF_INET6: + if (alen != sizeof (struct in6_addr)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + break; + default: + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* allocate response IP */ + addr = NULL; + result_af = (int) htonl (msg->result_af); + switch (result_af) + { + case AF_INET: + if (GNUNET_OK != + allocate_v4_address (&v4)) + result_af = AF_UNSPEC; + else + addr = &v4; + break; + case AF_INET6: + if (GNUNET_OK != + allocate_v6_address (&v6)) + result_af = AF_UNSPEC; + else + addr = &v6; + break; + case AF_UNSPEC: + if (GNUNET_OK == + allocate_v4_address (&v4)) + { + addr = &v4; + result_af = AF_INET; + } + else if (GNUNET_OK == + allocate_v6_address (&v6)) + { + addr = &v6; + result_af = AF_INET6; + } + break; + default: + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if ( (result_af == AF_UNSPEC) || + (GNUNET_NO == ntohl (msg->nac)) ) + { + /* send reply "instantly" */ + send_client_reply (client, + msg->request_id, + result_af, + addr); + } + if (result_af == AF_UNSPEC) + { + /* failure, we're done */ + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Allocated address %s for redirection via exit to %s\n", + inet_ntop (result_af, addr, sbuf, sizeof (sbuf)), + inet_ntop (addr_af, + &msg[1], dbuf, sizeof (dbuf))); + } + + /* setup destination record */ + de = GNUNET_malloc (sizeof (struct DestinationEntry)); + de->is_service = GNUNET_NO; + de->details.exit_destination.af = addr_af; + memcpy (&de->details.exit_destination.ip, + &msg[1], + alen); + get_destination_key_from_ip (result_af, + addr, + &key); + de->key = key; + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (destination_map, + &key, + de, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap, + de, + GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Active destinations"), + 1, GNUNET_NO); + while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings) + expire_destination (de); + + /* setup tunnel to destination */ + ts = create_tunnel_to_destination (de, + (GNUNET_NO == ntohl (msg->nac)) ? NULL : client, + result_af, + msg->request_id); + switch (result_af) + { + case AF_INET: + ts->destination_ip.v4 = v4; + break; + case AF_INET6: + ts->destination_ip.v6 = v6; + break; + default: + GNUNET_assert (0); + } + /* we're done */ + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * A client asks us to setup a redirection to a particular peer + * offering a service. Setup the redirection and give the client the + * allocated IP. + * + * @param cls unused + * @param client requesting client + * @param message redirection request (a 'struct RedirectToPeerRequestMessage') + */ +static void +service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct RedirectToServiceRequestMessage *msg; + int result_af; + struct in_addr v4; + struct in6_addr v6; + void *addr; + struct DestinationEntry *de; + GNUNET_HashCode key; + struct TunnelState *ts; + + /* parse request */ + msg = (const struct RedirectToServiceRequestMessage *) message; + + /* allocate response IP */ + addr = NULL; + result_af = (int) htonl (msg->result_af); + switch (result_af) + { + case AF_INET: + if (GNUNET_OK != + allocate_v4_address (&v4)) + result_af = AF_UNSPEC; + else + addr = &v4; + break; + case AF_INET6: + if (GNUNET_OK != + allocate_v6_address (&v6)) + result_af = AF_UNSPEC; + else + addr = &v6; + break; + case AF_UNSPEC: + if (GNUNET_OK == + allocate_v4_address (&v4)) + { + addr = &v4; + result_af = AF_INET; + } + else if (GNUNET_OK == + allocate_v6_address (&v6)) + { + addr = &v6; + result_af = AF_INET6; + } + break; + default: + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if ( (result_af == AF_UNSPEC) || + (GNUNET_NO == ntohl (msg->nac)) ) + { + /* send reply "instantly" */ + send_client_reply (client, + msg->request_id, + result_af, + addr); + } + if (result_af == AF_UNSPEC) + { + /* failure, we're done */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to allocate IP address for new destination\n")); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + { + char sbuf[INET6_ADDRSTRLEN]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Allocated address %s for redirection to service %s on peer %s\n", + inet_ntop (result_af, addr, sbuf, sizeof (sbuf)), + GNUNET_h2s (&msg->service_descriptor), + GNUNET_i2s (&msg->target)); + } + + /* setup destination record */ + de = GNUNET_malloc (sizeof (struct DestinationEntry)); + de->is_service = GNUNET_YES; + de->details.service_destination.service_descriptor = msg->service_descriptor; + de->details.service_destination.target = msg->target; + get_destination_key_from_ip (result_af, + addr, + &key); + de->key = key; + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (destination_map, + &key, + de, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap, + de, + GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value); + while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings) + expire_destination (de); + ts = create_tunnel_to_destination (de, + (GNUNET_NO == ntohl (msg->nac)) ? NULL : client, + result_af, + msg->request_id); + switch (result_af) + { + case AF_INET: + ts->destination_ip.v4 = v4; + break; + case AF_INET6: + ts->destination_ip.v6 = v6; + break; + default: + GNUNET_assert (0); + } + /* we're done */ + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + + +/** + * Function called for inbound tunnels. As we don't offer + * any mesh services, this function should never be called. + * + * @param cls closure + * @param tunnel new handle to the tunnel + * @param initiator peer that started the tunnel + * @param atsi performance information for the tunnel + * @return initial tunnel context for the tunnel + * (can be NULL -- that's not an error) + */ +static void * +inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *initiator, + const struct GNUNET_ATS_Information *atsi) +{ + /* How can and why should anyone open an inbound tunnel to vpn? */ + GNUNET_break (0); + return NULL; +} + + +/** + * Function called whenever an inbound tunnel is destroyed. Should clean up + * any associated state. + * + * @param cls closure (set from GNUNET_MESH_connect) + * @param tunnel connection to the other end (henceforth invalid) + * @param tunnel_ctx place where local state associated + * with the tunnel is stored (our 'struct TunnelState') + */ +static void +tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) +{ + /* we don't have inbound tunnels, so this function should never be called */ + GNUNET_break (0); +} + + +/** + * Free memory occupied by an entry in the destination map. + * + * @param cls unused + * @param key unused + * @param value a 'struct DestinationEntry *' + * @return GNUNET_OK (continue to iterate) + */ +static int +cleanup_destination (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct DestinationEntry *de = value; + + free_destination_entry (de); + return GNUNET_OK; +} + + +/** + * Free memory occupied by an entry in the tunnel map. + * + * @param cls unused + * @param key unused + * @param value a 'struct TunnelState *' + * @return GNUNET_OK (continue to iterate) + */ +static int +cleanup_tunnel (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct TunnelState *ts = value; + + free_tunnel_state (ts); + return GNUNET_OK; +} + + +/** + * Function scheduled as very last function, cleans up after us + * + * @param cls unused + * @param tc unused + */ +static void +cleanup (void *cls GNUNET_UNUSED, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "VPN is shutting down\n"); + if (NULL != destination_map) + { + GNUNET_CONTAINER_multihashmap_iterate (destination_map, + &cleanup_destination, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (destination_map); + destination_map = NULL; + } + if (NULL != destination_heap) + { + GNUNET_CONTAINER_heap_destroy (destination_heap); + destination_heap = NULL; + } + if (NULL != tunnel_map) + { + GNUNET_CONTAINER_multihashmap_iterate (tunnel_map, + &cleanup_tunnel, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (tunnel_map); + tunnel_map = NULL; + } + if (NULL != tunnel_heap) + { + GNUNET_CONTAINER_heap_destroy (tunnel_heap); + tunnel_heap = NULL; + } + if (NULL != mesh_handle) + { + GNUNET_MESH_disconnect (mesh_handle); + mesh_handle = NULL; + } + if (NULL != helper_handle) + { + GNUNET_HELPER_stop (helper_handle); + helper_handle = NULL; + } + if (NULL != nc) + { + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; + } + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + stats = NULL; + } + for (i=0;i<5;i++) + GNUNET_free_non_null (vpn_argv[i]); +} + + +/** + * A client disconnected, clean up all references to it. + * + * @param cls the client that disconnected + * @param key unused + * @param value a 'struct TunnelState *' + * @return GNUNET_OK (continue to iterate) + */ +static int +cleanup_tunnel_client (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_SERVER_Client *client = cls; + struct TunnelState *ts = value; + + if (client == ts->client) + { + GNUNET_SERVER_client_drop (ts->client); + ts->client = NULL; + } + return GNUNET_OK; +} + + +/** + * A client disconnected, clean up all references to it. + * + * @param cls the client that disconnected + * @param key unused + * @param value a 'struct DestinationEntry *' + * @return GNUNET_OK (continue to iterate) + */ +static int +cleanup_destination_client (void *cls, + const GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_SERVER_Client *client = cls; + struct DestinationEntry *de = value; + struct TunnelState *ts; + + if (NULL == (ts = de->ts)) + return GNUNET_OK; + if (client == ts->client) + { + GNUNET_SERVER_client_drop (ts->client); + ts->client = NULL; + } + return GNUNET_OK; +} + + +/** + * A client has disconnected from us. If we are currently building + * a tunnel for it, cancel the operation. + * + * @param cls unused + * @param client handle to the client that disconnected + */ +static void +client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + if (NULL != tunnel_map) + GNUNET_CONTAINER_multihashmap_iterate (tunnel_map, + &cleanup_tunnel_client, + client); + if (NULL != destination_map) + GNUNET_CONTAINER_multihashmap_iterate (destination_map, + &cleanup_destination_client, + client); +} + + +/** + * Test if the given AF is supported by this system. + * + * @param af to test + * @return GNUNET_OK if the AF is supported + */ +static int +test_af (int af) +{ + int s; + + s = socket (af, SOCK_STREAM, 0); + if (-1 == s) + { + if (EAFNOSUPPORT == errno) + return GNUNET_NO; + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "socket"); + return GNUNET_SYSERR; + } + close (s); + return GNUNET_OK; +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param server the initialized server + * @param cfg_ configuration + */ +static void +run (void *cls, + struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *cfg_) +{ + static const struct GNUNET_SERVER_MessageHandler service_handlers[] = { + /* callback, cls, type, size */ + { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0}, + { &service_redirect_to_service, NULL, + GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE, + sizeof (struct RedirectToServiceRequestMessage) }, + {NULL, NULL, 0, 0} + }; + static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = { + { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0}, + { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0}, + { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0}, + {NULL, 0, 0} + }; + static const GNUNET_MESH_ApplicationType types[] = { + GNUNET_APPLICATION_TYPE_END + }; + char *ifname; + char *ipv6addr; + char *ipv6prefix_s; + char *ipv4addr; + char *ipv4mask; + struct in_addr v4; + struct in6_addr v6; + + if (GNUNET_YES != + GNUNET_OS_check_helper_binary ("gnunet-helper-vpn")) + { + fprintf (stderr, + "`%s' is not SUID, refusing to run.\n", + "gnunet-helper-vpn"); + global_ret = 1; + return; + } + cfg = cfg_; + stats = GNUNET_STATISTICS_create ("vpn", cfg); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING", + &max_destination_mappings)) + max_destination_mappings = 200; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS", + &max_tunnel_mappings)) + max_tunnel_mappings = 200; + + destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2); + destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2); + tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + + + vpn_argv[0] = GNUNET_strdup ("vpn-gnunet"); + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'IFNAME' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + vpn_argv[1] = ifname; + if (GNUNET_OK == test_af (AF_INET6)) + { + if ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR", + &ipv6addr) || + (1 != inet_pton (AF_INET6, ipv6addr, &v6))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No valid entry 'IPV6ADDR' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + vpn_argv[2] = ipv6addr; + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX", + &ipv6prefix_s)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'IPV6PREFIX' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + vpn_argv[3] = ipv6prefix_s; + if ( (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", + "IPV6PREFIX", + &ipv6prefix)) || + (ipv6prefix >= 127) ) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("IPv6 support disabled as this system does not support IPv6\n")); + vpn_argv[2] = GNUNET_strdup ("-"); + vpn_argv[3] = GNUNET_strdup ("-"); + } + if (GNUNET_OK == test_af (AF_INET)) + { + if ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR", + &ipv4addr) || + (1 != inet_pton (AF_INET, ipv4addr, &v4))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No valid entry for 'IPV4ADDR' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + vpn_argv[4] = ipv4addr; + if ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK", + &ipv4mask) || + (1 != inet_pton (AF_INET, ipv4mask, &v4))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No valid entry 'IPV4MASK' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + vpn_argv[5] = ipv4mask; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("IPv4 support disabled as this system does not support IPv4\n")); + vpn_argv[4] = GNUNET_strdup ("-"); + vpn_argv[5] = GNUNET_strdup ("-"); + } + vpn_argv[6] = NULL; + + mesh_handle = + GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL, + &inbound_tunnel_cb, + &tunnel_cleaner, + mesh_handlers, + types); + helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv, + &message_token, NULL); + nc = GNUNET_SERVER_notification_context_create (server, 1); + GNUNET_SERVER_add_handlers (server, service_handlers); + GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); +} + + +/** + * The main function of the VPN service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, argv, "vpn", + GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? global_ret : 1; +} + +/* end of gnunet-service-vpn.c */ diff --git a/src/vpn/gnunet-vpn.c b/src/vpn/gnunet-vpn.c new file mode 100644 index 0000000..ecc0442 --- /dev/null +++ b/src/vpn/gnunet-vpn.c @@ -0,0 +1,334 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/vpn/gnunet-vpn.c + * @brief Tool to manually request VPN tunnels to be created + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_vpn_service.h" + + +/** + * Handle to vpn service. + */ +static struct GNUNET_VPN_Handle *handle; + +/** + * Opaque redirection request handle. + */ +static struct GNUNET_VPN_RedirectionRequest *request; + +/** + * Option -p: destination peer identity for service + */ +static char *peer_id; + +/** + * Option -s: service name (hash to get service descriptor) + */ +static char *service_name; + +/** + * Option -i: target IP + */ +static char *target_ip; + +/** + * Option -4: IPv4 requested. + */ +static int ipv4; + +/** + * Option -6: IPv6 requested. + */ +static int ipv6; + +/** + * Option -t: TCP requested. + */ +static int tcp; + +/** + * Option -u: UDP requested. + */ +static int udp; + +/** + * Selected level of verbosity. + */ +static int verbosity; + +/** + * Option '-a': Notify only once the tunnel is connected? + */ +static int nac; + +/** + * Global return value. + */ +static int ret; + +/** + * Option '-d': duration of the mapping + */ +static unsigned long long duration = 5 * 60; + + +/** + * Shutdown. + */ +static void +do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != request) + { + GNUNET_VPN_cancel_request (request); + request = NULL; + } + if (NULL != handle) + { + GNUNET_VPN_disconnect (handle); + handle = NULL; + } + GNUNET_free_non_null (peer_id); + GNUNET_free_non_null (service_name); + GNUNET_free_non_null (target_ip); +} + + +/** + * Callback invoked from the VPN service once a redirection is + * available. Provides the IP address that can now be used to + * reach the requested destination. + * + * @param cls closure + * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error; + * will match 'result_af' from the request + * @param address IP address (struct in_addr or struct in_addr6, depending on 'af') + * that the VPN allocated for the redirection; + * traffic to this IP will now be redirected to the + * specified target peer; NULL on error + */ +static void +allocation_cb (void *cls, + int af, + const void *address) +{ + char buf[INET6_ADDRSTRLEN]; + + request = NULL; + switch (af) + { + case AF_INET6: + case AF_INET: + FPRINTF (stdout, + "%s\n", + inet_ntop (af, address, buf, sizeof (buf))); + break; + case AF_UNSPEC: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Error creating tunnel\n")); + ret = 1; + break; + default: + break; + } + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + int dst_af; + int req_af; + struct GNUNET_PeerIdentity peer; + GNUNET_HashCode sd; + const void *addr; + struct in_addr v4; + struct in6_addr v6; + uint8_t protocol; + struct GNUNET_TIME_Absolute etime; + + etime = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, + (unsigned int) duration)); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &do_disconnect, NULL); + handle = GNUNET_VPN_connect (cfg); + if (NULL == handle) + goto error; + req_af = AF_UNSPEC; + if (ipv4) + { + if (ipv6) + { + FPRINTF (stderr, _("Option `%s' makes no sense with option `%s'.\n"), + "-4", "-6"); + goto error; + } + req_af = AF_INET; + } + if (ipv6) + req_af = AF_INET6; + + if (NULL == target_ip) + { + if (NULL == service_name) + { + FPRINTF (stderr, _("Option `%s' or `%s' is required.\n"), + "-i", "-s"); + goto error; + } + if (NULL == peer_id) + { + FPRINTF (stderr, _("Option `%s' is required when using option `%s'.\n"), + "-p", "-s"); + goto error; + } + if (! (tcp | udp) ) + { + FPRINTF (stderr, _("Option `%s' or `%s' is required when using option `%s'.\n"), + "-t", "-u", "-s"); + goto error; + } + if (tcp & udp) + { + FPRINTF (stderr, _("Option `%s' makes no sense with option `%s'.\n"), + "-t", "-u"); + goto error; + } + if (tcp) + protocol = IPPROTO_TCP; + if (udp) + protocol = IPPROTO_UDP; + if (GNUNET_OK != + GNUNET_CRYPTO_hash_from_string (peer_id, + &peer.hashPubKey)) + { + FPRINTF (stderr, _("`%s' is not a valid peer identifier.\n"), + peer_id); + goto error; + } + GNUNET_CRYPTO_hash (service_name, + strlen (service_name), + &sd); + request = GNUNET_VPN_redirect_to_peer (handle, + req_af, + protocol, + &peer, + &sd, + nac, + etime, + &allocation_cb, NULL); + } + else + { + if (1 != inet_pton (AF_INET6, target_ip, &v6)) + { + if (1 != inet_pton (AF_INET, target_ip, &v4)) + { + FPRINTF (stderr, _("`%s' is not a valid IP address.\n"), + target_ip); + goto error; + } + else + { + dst_af = AF_INET; + addr = &v4; + } + } + else + { + dst_af = AF_INET6; + addr = &v6; + } + request = GNUNET_VPN_redirect_to_ip (handle, + req_af, + dst_af, + addr, + nac, + etime, + &allocation_cb, NULL); + } + return; + + error: + GNUNET_SCHEDULER_shutdown (); + ret = 1; +} + + +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'4', "ipv4", NULL, + gettext_noop ("request that result should be an IPv4 address"), + 0, &GNUNET_GETOPT_set_one, &ipv4}, + {'6', "ipv6", NULL, + gettext_noop ("request that result should be an IPv6 address"), + 0, &GNUNET_GETOPT_set_one, &ipv6}, + {'a', "after-connect", NULL, + gettext_noop ("print IP address only after mesh tunnel has been created"), + 0, &GNUNET_GETOPT_set_one, &ipv6}, + {'d', "duration", "SECONDS", + gettext_noop ("how long should the mapping be valid for new tunnels?"), + 1, &GNUNET_GETOPT_set_ulong, &duration}, + {'i', "ip", "IP", + gettext_noop ("destination IP for the tunnel"), + 1, &GNUNET_GETOPT_set_string, &target_ip}, + {'p', "peer", "PEERID", + gettext_noop ("peer offering the service we would like to access"), + 1, &GNUNET_GETOPT_set_string, &peer_id}, + {'s', "service", "NAME", + gettext_noop ("name of the service we would like to access"), + 1, &GNUNET_GETOPT_set_string, &service_name}, + {'t', "tcp", NULL, + gettext_noop ("service is offered via TCP"), + 0, &GNUNET_GETOPT_set_one, &tcp}, + {'u', "udp", NULL, + gettext_noop ("service is offered via UDP"), + 0, &GNUNET_GETOPT_set_one, &udp}, + + GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-vpn", + gettext_noop + ("Setup tunnels via VPN."), options, + &run, NULL)) ? ret : 1; +} + + +/* end of gnunet-vpn.c */ diff --git a/src/vpn/test_gnunet_vpn.c b/src/vpn/test_gnunet_vpn.c new file mode 100644 index 0000000..005c7bd --- /dev/null +++ b/src/vpn/test_gnunet_vpn.c @@ -0,0 +1,605 @@ +/* + This file is part of GNUnet + (C) 2007, 2009, 2011, 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file test_gnunet_vpn.c + * @brief testcase for tunneling HTTP over the GNUnet VPN + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include +#include "gnunet_vpn_service.h" +#include "gnunet_arm_service.h" + +#define PORT 48080 + +#define START_ARM GNUNET_YES + +#define VERBOSE GNUNET_NO + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 45) + +struct PeerContext +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_PeerIdentity id; +#if START_ARM + struct GNUNET_OS_Process *arm_proc; +#endif +}; + +static struct PeerContext p1; + +/** + * Return value for 'main'. + */ +static int global_ret; + +static struct GNUNET_VPN_Handle *vpn; + +static struct MHD_Daemon *mhd; + +static GNUNET_SCHEDULER_TaskIdentifier mhd_task_id; + +static GNUNET_SCHEDULER_TaskIdentifier curl_task_id; + +static GNUNET_SCHEDULER_TaskIdentifier ctrl_c_task_id; + +static struct GNUNET_VPN_RedirectionRequest *rr; + +static CURL *curl; + +static CURLM *multi; + +static char *url; + +/** + * IP address of the ultimate destination. + */ +static const char *dest_ip; + +/** + * Address family of the dest_ip. + */ +static int dest_af; + +/** + * Address family to use by the curl client. + */ +static int src_af; + + +struct CBC +{ + char buf[1024]; + size_t pos; +}; + +static struct CBC cbc; + + + +static size_t +copy_buffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > sizeof(cbc->buf)) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + + +static int +mhd_ahc (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int ptr; + struct MHD_Response *response; + int ret; + + if (0 != strcmp ("GET", method)) + return MHD_NO; /* unexpected method */ + if (&ptr != *unused) + { + *unused = &ptr; + return MHD_YES; + } + *unused = NULL; +#if VERBOSE + fprintf (stderr, "MHD sends respose for request to URL `%s'\n", url); +#endif + response = MHD_create_response_from_buffer (strlen (url), + (void *) url, + MHD_RESPMEM_MUST_COPY); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + if (ret == MHD_NO) + abort (); + return ret; +} + + +static void +do_shutdown () +{ + if (mhd_task_id != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (mhd_task_id); + mhd_task_id = GNUNET_SCHEDULER_NO_TASK; + } + if (curl_task_id != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (curl_task_id); + curl_task_id = GNUNET_SCHEDULER_NO_TASK; + } + if (ctrl_c_task_id != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ctrl_c_task_id); + ctrl_c_task_id = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != mhd) + { + MHD_stop_daemon (mhd); + mhd = NULL; + } + if (NULL != rr) + { + GNUNET_VPN_cancel_request (rr); + rr = NULL; + } + if (NULL != vpn) + { + GNUNET_VPN_disconnect (vpn); + vpn = NULL; + } + GNUNET_free_non_null (url); + url = NULL; +} + + +/** + * Function to run the HTTP client. + */ +static void +curl_main (void); + + +static void +curl_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + curl_task_id = GNUNET_SCHEDULER_NO_TASK; + curl_main (); +} + + +static void +curl_main () +{ + fd_set rs; + fd_set ws; + fd_set es; + int max; + struct GNUNET_NETWORK_FDSet nrs; + struct GNUNET_NETWORK_FDSet nws; + struct GNUNET_TIME_Relative delay; + long timeout; + int running; + struct CURLMsg *msg; + + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + if (running == 0) + { + GNUNET_assert (NULL != (msg = curl_multi_info_read (multi, &running))); + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + { + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + global_ret = 1; + } + } + curl_multi_remove_handle (multi, curl); + curl_multi_cleanup (multi); + curl_easy_cleanup (curl); + curl = NULL; + multi = NULL; + if (cbc.pos != strlen ("/hello_world")) + global_ret = 2; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + global_ret = 3; +#if VERBOSE + fprintf (stderr, "Download complete, shutting down!\n"); +#endif + do_shutdown (); + return; + } + GNUNET_assert (CURLM_OK == curl_multi_fdset (multi, &rs, &ws, &es, &max)); + if ( (CURLM_OK != curl_multi_timeout (multi, &timeout)) || + (-1 == timeout) ) + delay = GNUNET_TIME_UNIT_SECONDS; + else + delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, (unsigned int) timeout); + GNUNET_NETWORK_fdset_copy_native (&nrs, + &rs, + max + 1); + GNUNET_NETWORK_fdset_copy_native (&nws, + &ws, + max + 1); + curl_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + delay, + &nrs, + &nws, + &curl_task, + NULL); +} + + +/** + * Callback invoked from the VPN service once a redirection is + * available. Provides the IP address that can now be used to + * reach the requested destination (in our case, the MHD server) + * + * @param cls closure + * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error; + * will match 'result_af' from the request + * @param address IP address (struct in_addr or struct in_addr6, depending on 'af') + * that the VPN allocated for the redirection; + * traffic to this IP will now be redirected to the + * specified target peer; NULL on error + */ +static void +allocation_cb (void *cls, + int af, + const void *address) +{ + char ips[INET6_ADDRSTRLEN]; + + rr = NULL; + if (src_af != af) + { + fprintf (stderr, + "VPN failed to allocate appropriate address\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_asprintf (&url, + "http://%s:%u/hello_world", + inet_ntop (af, address, ips, sizeof (ips)), + (unsigned int) PORT); + curl = curl_easy_init (); + curl_easy_setopt (curl, CURLOPT_URL, url); + curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ©_buffer); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (curl, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, 15L); + curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1); + + multi = curl_multi_init (); + GNUNET_assert (multi != NULL); + GNUNET_assert (CURLM_OK == curl_multi_add_handle (multi, curl)); +#if VERBOSE + fprintf (stderr, "Beginning HTTP download from `%s'\n", url); +#endif + curl_main (); +} + + +/** + * Function to keep the HTTP server running. + */ +static void +mhd_main (void); + + +static void +mhd_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + mhd_task_id = GNUNET_SCHEDULER_NO_TASK; + MHD_run (mhd); + mhd_main (); +} + + +static void +ctrl_c_shutdown (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + ctrl_c_task_id = GNUNET_SCHEDULER_NO_TASK; + do_shutdown (); + global_ret = 1; +} + + +static void +mhd_main () +{ + struct GNUNET_NETWORK_FDSet nrs; + struct GNUNET_NETWORK_FDSet nws; + fd_set rs; + fd_set ws; + fd_set es; + int max_fd; + unsigned MHD_LONG_LONG timeout; + struct GNUNET_TIME_Relative delay; + + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == mhd_task_id); + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + max_fd = -1; + GNUNET_assert (MHD_YES == + MHD_get_fdset (mhd, &rs, &ws, &es, &max_fd)); + if (MHD_YES == MHD_get_timeout (mhd, &timeout)) + delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + (unsigned int) timeout); + else + delay = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_NETWORK_fdset_copy_native (&nrs, + &rs, + max_fd + 1); + GNUNET_NETWORK_fdset_copy_native (&nws, + &ws, + max_fd + 1); + mhd_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_SCHEDULER_NO_TASK, + delay, + &nrs, + &nws, + &mhd_task, + NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct in_addr v4; + struct in6_addr v6; + void *addr; + enum MHD_FLAG flags; + + vpn = GNUNET_VPN_connect (cfg); + GNUNET_assert (NULL != vpn); + flags = MHD_USE_DEBUG; + if (AF_INET6 == dest_af) + flags |= MHD_USE_IPv6; + mhd = MHD_start_daemon (flags, + PORT, + NULL, NULL, + &mhd_ahc, NULL, + MHD_OPTION_END); + GNUNET_assert (NULL != mhd); + mhd_main (); + addr = NULL; + switch (dest_af) + { + case AF_INET: + GNUNET_assert (1 == inet_pton (dest_af, dest_ip, &v4)); + addr = &v4; + break; + case AF_INET6: + GNUNET_assert (1 == inet_pton (dest_af, dest_ip, &v6)); + addr = &v6; + break; + default: + GNUNET_assert (0); + } + rr = GNUNET_VPN_redirect_to_ip (vpn, + src_af, + dest_af, + addr, + GNUNET_YES, + GNUNET_TIME_UNIT_FOREVER_ABS, + &allocation_cb, NULL); + ctrl_c_task_id = GNUNET_SCHEDULER_add_delayed (TIMEOUT, + &ctrl_c_shutdown, + NULL); +} + + +static void +setup_peer (struct PeerContext *p, const char *cfgname) +{ + p->cfg = GNUNET_CONFIGURATION_create (); +#if START_ARM + p->arm_proc = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", + "gnunet-service-arm", +#if VERBOSE + "-L", "DEBUG", +#endif + "-c", cfgname, NULL); +#endif + GNUNET_assert (NULL != p->arm_proc); + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); +} + + +static void +stop_peer (struct PeerContext *p) +{ +#if START_ARM + if (NULL != p->arm_proc) + { + if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); + if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", + GNUNET_OS_process_get_pid (p->arm_proc)); + GNUNET_OS_process_close (p->arm_proc); + p->arm_proc = NULL; + } +#endif + GNUNET_CONFIGURATION_destroy (p->cfg); +} + + +/** + * Test if the given AF is supported by this system. + * + * @param af to test + * @return GNUNET_OK if the AF is supported + */ +static int +test_af (int af) +{ + int s; + + s = socket (af, SOCK_STREAM, 0); + if (-1 == s) + { + if (EAFNOSUPPORT == errno) + return GNUNET_NO; + fprintf (stderr, "Failed to create test socket: %s\n", STRERROR (errno)); + return GNUNET_SYSERR; + } + close (s); + return GNUNET_OK; +} + + + +int +main (int argc, char *const *argv) +{ + const char *type; + const char *bin; + char *const argvx[] = { + "test_gnunet_vpn", + "-c", + "test_gnunet_vpn.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + if (0 != ACCESS ("/dev/net/tun", R_OK)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "access", + "/dev/net/tun"); + fprintf (stderr, + "WARNING: System unable to run test, skipping.\n"); + return 0; + } + if ( (GNUNET_YES != + GNUNET_OS_check_helper_binary ("gnunet-helper-vpn")) || + (GNUNET_YES != + GNUNET_OS_check_helper_binary ("gnunet-helper-exit")) ) + { + fprintf (stderr, + "WARNING: gnunet-helper-{exit,vpn} binaries in $PATH are not SUID, refusing to run test (as it would have to fail).\n"); + fprintf (stderr, + "Change $PATH ('.' in $PATH before $GNUNET_PREFIX/bin is problematic) or permissions (run 'make install' as root) to fix this!\n"); + return 0; + } + bin = argv[0]; + if (NULL != strstr (bin, "lt-")) + bin = strstr (bin, "lt-") + 4; + type = strstr (bin, "-"); + if (NULL == type) + { + fprintf (stderr, "invalid binary name\n"); + return 1; + } + type++; + if (0 == strcmp (type, "4_to_6")) + { + dest_ip = "FC5A:04E1:C2BA::1"; + dest_af = AF_INET6; + src_af = AF_INET; + } + else if (0 == strcmp (type, "6_to_4")) + { + dest_ip = "169.254.86.1"; + dest_af = AF_INET; + src_af = AF_INET6; + } + else if (0 == strcmp (type, "4_over")) + { + dest_ip = "169.254.86.1"; + dest_af = AF_INET; + src_af = AF_INET; + } + else if (0 == strcmp (type, "6_over")) + { + dest_ip = "FC5A:04E1:C2BA::1"; + dest_af = AF_INET6; + src_af = AF_INET6; + } + else + { + fprintf (stderr, "invalid binary suffix `%s'\n", type); + return 1; + } + if ( (GNUNET_OK != test_af (src_af)) || + (GNUNET_OK != test_af (dest_af)) ) + { + fprintf (stderr, + "Required address families not supported by this system, skipping test.\n"); + return 0; + } + + + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + setup_peer (&p1, "test_gnunet_vpn.conf"); + GNUNET_log_setup ("test_gnunet_vpn", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, + "test_gnunet_vpn", "nohelp", options, &run, NULL); + stop_peer (&p1); + GNUNET_DISK_directory_remove ("/tmp/gnunet-test-vpn"); + return global_ret; +} + +/* end of test_gnunet_vpn.c */ + diff --git a/src/vpn/test_gnunet_vpn.conf b/src/vpn/test_gnunet_vpn.conf new file mode 100644 index 0000000..5aec0c5 --- /dev/null +++ b/src/vpn/test_gnunet_vpn.conf @@ -0,0 +1,37 @@ +[PATHS] +SERVICEHOME = /tmp/gnunet-test-vpn/ +DEFAULTCONFIG = test_gnunet_vpn.conf + + +[arm] +DEFAULTSERVICES = statistics exit vpn +PORT = 0 +ALLOW_SHUTDOWN = YES + +[exit] +EXIT_IPV4 = YES +EXIT_IPV6 = YES + +# FIXME: can we use 'lo'? +EXIT_IFNAME = eth1 + +[testing] +WEAKRANDOM = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat + + + +# repeating some values from the default configurations +# here as the respective network addresses are also +# hard-wired in the tests and the MUST match (!) +[vpn] +IPV6ADDR = FC2D:FDAA:6A26::1 +IPV6PREFIX = 64 +IPV4ADDR = 169.254.20.1 +IPV4MASK = 255.255.255.0 + +[exit] +IPV6ADDR = FC5A:04E1:C2BA::1 +IPV6PREFIX = 96 +IPV4ADDR = 169.254.86.1 +IPV4MASK = 255.255.255.0 diff --git a/src/vpn/vpn.conf.in b/src/vpn/vpn.conf.in new file mode 100644 index 0000000..f5eb224 --- /dev/null +++ b/src/vpn/vpn.conf.in @@ -0,0 +1,21 @@ +[vpn] +AUTOSTART = YES +@UNIXONLY@ PORT = 0 +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-vpn +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = /tmp/gnunet-service-vpn.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + +IPV6ADDR = 1234::1 +IPV6PREFIX = 32 +IPV4ADDR = 10.11.10.1 +IPV4MASK = 255.255.0.0 +VIRTDNS = 10.11.10.2 +VIRTDNS6 = 1234::17 +IFNAME = vpn-gnunet + diff --git a/src/vpn/vpn.h b/src/vpn/vpn.h new file mode 100644 index 0000000..e937f5e --- /dev/null +++ b/src/vpn/vpn.h @@ -0,0 +1,159 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file vpn/vpn.h + * @brief IPC messages between VPN library and VPN service + * @author Christian Grothoff + */ +#ifndef VPN_H +#define VPN_H + +#include "gnunet_util_lib.h" + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message send by the VPN client to the VPN service requesting + * the setup of a redirection from some IP via an exit node to + * some global Internet address. + */ +struct RedirectToIpRequestMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP + */ + struct GNUNET_MessageHeader header; + + /** + * GNUNET_YES to notify only after completion of the mesh-level connection, + * GNUNET_NO to notify as soon as an address was allocated (in nbo). + */ + int32_t nac GNUNET_PACKED; + + /** + * How long should the redirection be maintained at most? + */ + struct GNUNET_TIME_AbsoluteNBO expiration_time; + + /** + * Address family desired for the result (AF_INET or AF_INET6 or AF_UNSPEC, in nbo) + */ + int32_t result_af GNUNET_PACKED; + + /** + * Address family used for the destination address (AF_INET or AF_INET6, in nbo) + */ + int32_t addr_af GNUNET_PACKED; + + /** + * Unique ID to match a future response to this request. + * Picked by the client. + */ + uint64_t request_id GNUNET_PACKED; + + /* followed by destination address ('struct in_addr' or 'struct in6_addr') */ + +}; + + +/** + * Message send by the VPN client to the VPN service requesting + * the setup of a redirection from some IP to a service running + * at a particular peer. + */ +struct RedirectToServiceRequestMessage +{ + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP + */ + struct GNUNET_MessageHeader header; + + /** + * GNUNET_YES to notify only after completion of the mesh-level connection, + * GNUNET_NO to notify as soon as an address was allocated (in nbo). + */ + int32_t nac GNUNET_PACKED; + + /** + * How long should the redirection be maintained at most? + */ + struct GNUNET_TIME_AbsoluteNBO expiration_time; + + /** + * Desired protocol (IPPROTO_UDP or IPPROTO_TCP) + */ + int32_t protocol GNUNET_PACKED; + + /** + * Address family desired for the result (AF_INET or AF_INET6 or AF_UNSPEC, in nbo) + */ + int32_t result_af GNUNET_PACKED; + + /** + * Target peer offering the service. + */ + struct GNUNET_PeerIdentity target; + + /** + * Service descriptor identifying the service. + */ + GNUNET_HashCode service_descriptor GNUNET_PACKED; + + /** + * Unique ID to match a future response to this request. + * Picked by the client. + */ + uint64_t request_id GNUNET_PACKED; + +}; + + +/** + * Response from the VPN service to a VPN client informing about + * the IP that was assigned for the requested redirection. + */ +struct RedirectToIpResponseMessage +{ + + /** + * Type is GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP + */ + struct GNUNET_MessageHeader header; + + /** + * Address family of the allocated address that follows; will match + * "result_af" from the request, of be "AF_UNSPEC" on errors. + */ + int32_t result_af GNUNET_PACKED; + + /** + * Unique ID to match the response to a request. + */ + uint64_t request_id GNUNET_PACKED; + + /* followed by destination address ('struct in_addr' or 'struct in6_addr') */ + +}; + +GNUNET_NETWORK_STRUCT_END + + +#endif diff --git a/src/vpn/vpn_api.c b/src/vpn/vpn_api.c new file mode 100644 index 0000000..31d17f8 --- /dev/null +++ b/src/vpn/vpn_api.c @@ -0,0 +1,605 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file vpn/vpn_api.c + * @brief library to access the VPN service and tell it how to redirect traffic + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_vpn_service.h" +#include "vpn.h" + + +/** + * Opaque VPN handle + */ +struct GNUNET_VPN_Handle +{ + /** + * Configuration we use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Connection to VPN service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Active transmission request. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Head of list of active redirection requests. + */ + struct GNUNET_VPN_RedirectionRequest *rr_head; + + /** + * Tail of list of active redirection requests. + */ + struct GNUNET_VPN_RedirectionRequest *rr_tail; + + /** + * Identifier of a reconnect task. + */ + GNUNET_SCHEDULER_TaskIdentifier rt; + + /** + * How long do we wait until we try to reconnect? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * ID of the last request that was submitted to the service. + */ + uint64_t request_id_gen; + +}; + + +/** + * Opaque redirection request handle. + */ +struct GNUNET_VPN_RedirectionRequest +{ + /** + * Element in DLL. + */ + struct GNUNET_VPN_RedirectionRequest *next; + + /** + * Element in DLL. + */ + struct GNUNET_VPN_RedirectionRequest *prev; + + /** + * Pointer to the VPN struct. + */ + struct GNUNET_VPN_Handle *vh; + + /** + * Target IP address for the redirection, or NULL for + * redirection to service. Allocated after this struct. + */ + const void *addr; + + /** + * Function to call with the designated IP address. + */ + GNUNET_VPN_AllocationCallback cb; + + /** + * Closure for 'cb'. + */ + void *cb_cls; + + /** + * For service redirection, identity of the peer offering the service. + */ + struct GNUNET_PeerIdentity peer; + + /** + * For service redirection, service descriptor. + */ + GNUNET_HashCode serv; + + /** + * At what time should the created service mapping expire? + */ + struct GNUNET_TIME_Absolute expiration_time; + + /** + * non-zero if this request has been sent to the service. + */ + uint64_t request_id; + + /** + * Desired address family for the result. + */ + int result_af; + + /** + * Address family of 'addr'. AF_INET or AF_INET6. + */ + int addr_af; + + /** + * GNUNET_YES if we are to call the callback only after successful + * mesh tunnel creation. + */ + int nac; + + /** + * For service redirection, IPPROT_UDP or IPPROTO_TCP. + */ + uint8_t protocol; + +}; + + +/** + * Disconnect from the service (communication error) and reconnect later. + * + * @param vh handle to reconnect. + */ +static void +reconnect (struct GNUNET_VPN_Handle *vh); + + +/** + * Function called when we receive a message from the VPN service. + * + * @param cls the 'struct GNUNET_VPN_Handle' + * @param msg message received, NULL on timeout or fatal error + */ +static void +receive_response (void *cls, + const struct GNUNET_MessageHeader* msg) +{ + struct GNUNET_VPN_Handle *vh = cls; + const struct RedirectToIpResponseMessage *rm; + struct GNUNET_VPN_RedirectionRequest *rr; + size_t msize; + size_t alen; + int af; + + if (NULL == msg) + { + reconnect (vh); + return; + } + if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP) || + (sizeof (struct RedirectToIpResponseMessage) > (msize = ntohs (msg->size))) ) + { + GNUNET_break (0); + reconnect (vh); + return; + } + rm = (const struct RedirectToIpResponseMessage *) msg; + af = (int) ntohl (rm->result_af); + switch (af) + { + case AF_UNSPEC: + alen = 0; + break; + case AF_INET: + alen = sizeof (struct in_addr); + break; + case AF_INET6: + alen = sizeof (struct in6_addr); + break; + default: + GNUNET_break (0); + reconnect (vh); + return; + } + if ( (msize != alen + sizeof (struct RedirectToIpResponseMessage)) || + (0 == rm->request_id) ) + { + GNUNET_break (0); + reconnect (vh); + return; + } + GNUNET_CLIENT_receive (vh->client, + &receive_response, vh, + GNUNET_TIME_UNIT_FOREVER_REL); + for (rr = vh->rr_head; NULL != rr; rr = rr->next) + { + if (rr->request_id == rm->request_id) + { + GNUNET_CONTAINER_DLL_remove (vh->rr_head, + vh->rr_tail, + rr); + rr->cb (rr->cb_cls, + af, + (af == AF_UNSPEC) ? NULL : &rm[1]); + GNUNET_free (rr); + break; + } + } +} + + +/** + * We're ready to transmit a request to the VPN service. Do it. + * + * @param cls the 'struct GNUNET_VPN_Handle*' + * @param size number of bytes available in buf + * @param buf where to copy the request + * @return number of bytes copied to 'buf' + */ +static size_t +transmit_request (void *cls, + size_t size, + void *buf) +{ + struct GNUNET_VPN_Handle *vh = cls; + struct GNUNET_VPN_RedirectionRequest *rr; + struct RedirectToIpRequestMessage rip; + struct RedirectToServiceRequestMessage rs; + char *cbuf; + size_t alen; + size_t ret; + + vh->th = NULL; + /* find a pending request */ + rr = vh->rr_head; + while ( (NULL != rr) && + (0 != rr->request_id) ) + rr = rr->next; + if (NULL == rr) + return 0; + if (0 == size) + { + reconnect (vh); + return 0; + } + + /* if first request, start receive loop */ + if (0 == vh->request_id_gen) + GNUNET_CLIENT_receive (vh->client, + &receive_response, vh, + GNUNET_TIME_UNIT_FOREVER_REL); + if (NULL == rr->addr) + { + ret = sizeof (struct RedirectToServiceRequestMessage); + GNUNET_assert (ret <= size); + rs.header.size = htons ((uint16_t) ret); + rs.header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE); + rs.nac = htonl (rr->nac); + rs.expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time); + rs.protocol = htonl (rr->protocol); + rs.result_af = htonl (rr->result_af); + rs.target = rr->peer; + rs.service_descriptor = rr->serv; + rs.request_id = rr->request_id = ++vh->request_id_gen; + memcpy (buf, &rs, sizeof (struct RedirectToServiceRequestMessage)); + } + else + { + switch (rr->addr_af) + { + case AF_INET: + alen = sizeof (struct in_addr); + break; + case AF_INET6: + alen = sizeof (struct in6_addr); + break; + default: + GNUNET_assert (0); + return 0; + } + ret = alen + sizeof (struct RedirectToIpRequestMessage); + GNUNET_assert (ret <= size); + rip.header.size = htons ((uint16_t) ret); + rip.header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP); + rip.nac = htonl (rr->nac); + rip.expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time); + rip.result_af = htonl (rr->result_af); + rip.addr_af = htonl (rr->addr_af); + rip.request_id = rr->request_id = ++vh->request_id_gen; + cbuf = buf; + memcpy (cbuf, &rip, sizeof (struct RedirectToIpRequestMessage)); + memcpy (&cbuf[sizeof (struct RedirectToIpRequestMessage)], rr->addr, alen); + } + /* test if there are more pending requests */ + while ( (NULL != rr) && + (0 != rr->request_id) ) + rr = rr->next; + if (NULL != rr) + vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client, + sizeof (struct RedirectToServiceRequestMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, + &transmit_request, + vh); + return ret; +} + + +/** + * Add a request to our request queue and transmit it. + * + * @param rr request to queue and transmit. + */ +static void +queue_request (struct GNUNET_VPN_RedirectionRequest *rr) +{ + struct GNUNET_VPN_Handle *vh; + + vh = rr->vh; + GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head, + vh->rr_tail, + rr); + if ( (NULL == vh->th) && + (NULL != vh->client) ) + vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client, + sizeof (struct RedirectToServiceRequestMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, + &transmit_request, + vh); +} + + +/** + * Connect to the VPN service and start again to transmit our requests. + * + * @param cls the 'struct GNUNET_VPN_Handle *' + * @param tc scheduler context + */ +static void +connect_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_VPN_Handle *vh = cls; + + vh->rt = GNUNET_SCHEDULER_NO_TASK; + vh->client = GNUNET_CLIENT_connect ("vpn", vh->cfg); + GNUNET_assert (NULL != vh->client); + GNUNET_assert (NULL == vh->th); + if (NULL != vh->rr_head) + vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client, + sizeof (struct RedirectToServiceRequestMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_NO, + &transmit_request, + vh); +} + + +/** + * Disconnect from the service (communication error) and reconnect later. + * + * @param vh handle to reconnect. + */ +static void +reconnect (struct GNUNET_VPN_Handle *vh) +{ + struct GNUNET_VPN_RedirectionRequest *rr; + + if (NULL != vh->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (vh->th); + vh->th = NULL; + } + GNUNET_CLIENT_disconnect (vh->client, GNUNET_NO); + vh->client = NULL; + vh->request_id_gen = 0; + for (rr = vh->rr_head; NULL != rr; rr = rr->next) + rr->request_id = 0; + vh->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, + GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (vh->backoff, 2), + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30))); + vh->rt = GNUNET_SCHEDULER_add_delayed (vh->backoff, + &connect_task, + vh); +} + + +/** + * Cancel redirection request with the service. + * + * @param rr request to cancel + */ +void +GNUNET_VPN_cancel_request (struct GNUNET_VPN_RedirectionRequest *rr) +{ + struct GNUNET_VPN_Handle *vh; + + vh = rr->vh; + GNUNET_CONTAINER_DLL_remove (vh->rr_head, + vh->rr_tail, + rr); + GNUNET_free (rr); +} + + +/** + * Tell the VPN that a forwarding to a particular peer offering a + * particular service is requested. The VPN is to reserve a + * particular IP for the redirection and return it. The VPN will + * begin the redirection as soon as possible and maintain it as long + * as it is actively used and keeping it is feasible. Given resource + * limitations, the longest inactive mappings will be destroyed. + * + * @param vh VPN handle + * @param result_af desired address family for the returned allocation + * can also be AF_UNSPEC + * @param protocol protocol, IPPROTO_UDP or IPPROTO_TCP + * @param peer target peer for the redirection + * @param serv service descriptor to give to the peer + * @param nac GNUNET_YES to notify via callback only after completion of + * the MESH-level connection, + * GNUNET_NO to notify as soon as the IP has been reserved + * @param expiration_time at what time should the redirection expire? + * (this should not impact connections that are active at that time) + * @param cb function to call with the IP + * @param cb_cls closure for cb + * @return handle to cancel the request (means the callback won't be + * invoked anymore; the mapping may or may not be established + * anyway) + */ +struct GNUNET_VPN_RedirectionRequest * +GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *vh, + int result_af, + uint8_t protocol, + const struct GNUNET_PeerIdentity *peer, + const GNUNET_HashCode *serv, + int nac, + struct GNUNET_TIME_Absolute expiration_time, + GNUNET_VPN_AllocationCallback cb, + void *cb_cls) +{ + struct GNUNET_VPN_RedirectionRequest *rr; + + rr = GNUNET_malloc (sizeof (struct GNUNET_VPN_RedirectionRequest)); + rr->vh = vh; + rr->cb = cb; + rr->cb_cls = cb_cls; + rr->peer = *peer; + rr->serv = *serv; + rr->expiration_time = expiration_time; + rr->result_af = result_af; + rr->nac = nac; + rr->protocol = protocol; + queue_request (rr); + return rr; +} + + +/** + * Tell the VPN that forwarding to the Internet via some exit node is + * requested. Note that both UDP and TCP traffic will be forwarded, + * but possibly to different exit nodes. The VPN is to reserve a + * particular IP for the redirection and return it. The VPN will + * begin the redirection as soon as possible and maintain it as long + * as it is actively used and keeping it is feasible. Given resource + * limitations, the longest inactive mappings will be destroyed. + * + * @param vh VPN handle + * @param result_af desired address family for the returned allocation + * @param addr_af address family for 'addr', AF_INET or AF_INET6 + * @param addr destination IP address on the Internet; destination + * port is to be taken from the VPN packet itself + * @param nac GNUNET_YES to notify via callback only after completion of + * the MESH-level connection, + * GNUNET_NO to notify as soon as the IP has been reserved + * @param expiration_time at what time should the redirection expire? + * (this should not impact connections that are active at that time) + * @param cb function to call with the IP + * @param cb_cls closure for cb + * @return handle to cancel the request (means the callback won't be + * invoked anymore; the mapping may or may not be established + * anyway) + */ +struct GNUNET_VPN_RedirectionRequest * +GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *vh, + int result_af, + int addr_af, + const void *addr, + int nac, + struct GNUNET_TIME_Absolute expiration_time, + GNUNET_VPN_AllocationCallback cb, + void *cb_cls) +{ + struct GNUNET_VPN_RedirectionRequest *rr; + size_t alen; + + switch (addr_af) + { + case AF_INET: + alen = sizeof (struct in_addr); + break; + case AF_INET6: + alen = sizeof (struct in6_addr); + break; + default: + GNUNET_break (0); + return NULL; + } + rr = GNUNET_malloc (sizeof (struct GNUNET_VPN_RedirectionRequest) + alen); + rr->vh = vh; + rr->addr = &rr[1]; + rr->cb = cb; + rr->cb_cls = cb_cls; + rr->expiration_time = expiration_time; + rr->result_af = result_af; + rr->addr_af = addr_af; + rr->nac = nac; + memcpy (&rr[1], addr, alen); + queue_request (rr); + return rr; +} + + +/** + * Connect to the VPN service + * + * @param cfg configuration to use + * @return VPN handle + */ +struct GNUNET_VPN_Handle * +GNUNET_VPN_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_VPN_Handle *vh; + + vh = GNUNET_malloc (sizeof (struct GNUNET_VPN_Handle)); + vh->cfg = cfg; + vh->client = GNUNET_CLIENT_connect ("vpn", cfg); + if (NULL == vh->client) + { + GNUNET_free (vh); + return NULL; + } + return vh; +} + + +/** + * Disconnect from the VPN service. + * + * @param vh VPN handle + */ +void +GNUNET_VPN_disconnect (struct GNUNET_VPN_Handle *vh) +{ + GNUNET_assert (NULL == vh->rr_head); + if (NULL != vh->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (vh->th); + vh->th = NULL; + } + if (NULL != vh->client) + { + GNUNET_CLIENT_disconnect (vh->client, GNUNET_NO); + vh->client = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != vh->rt) + { + GNUNET_SCHEDULER_cancel (vh->rt); + vh->rt = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (vh); +} + +/* end of vpn_api.c */ -- cgit v1.2.3-18-g5258